3 Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
4 2003, 2004, 2005, 2006, 2007 John W. Eaton
6 This file is part of Octave.
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
24 // Author: John W. Eaton.
25 // HDF5 support by Steven G. Johnson <stevenj@alum.mit.edu>
26 // Matlab v5 support by James R. Van Zandt <jrv@vanzandt.mv.com>
46 #include "byte-swap.h"
47 #include "data-conv.h"
49 #include "file-stat.h"
50 #include "glob-match.h"
51 #include "lo-mappers.h"
52 #include "mach-info.h"
62 #include "load-path.h"
63 #include "load-save.h"
71 #include "unwind-prot.h"
73 #include "variables.h"
80 #include "ls-mat-ascii.h"
83 #include "ls-oct-ascii.h"
84 #include "ls-oct-binary.h"
90 // Write octave-core file if Octave crashes or is killed by a signal.
91 static bool Vcrash_dumps_octave_core = true;
93 // The maximum amount of memory (in kilobytes) that we will attempt to
94 // write to the Octave core file.
95 static double Voctave_core_file_limit = -1.0;
97 // The name of the Octave core file.
98 static std::string Voctave_core_file_name = "octave-core";
100 // The default output format. May be one of "binary", "text",
101 // "mat-binary", or "hdf5".
102 static std::string Vdefault_save_options = "-text";
104 // The output format for Octave core files.
105 static std::string Voctave_core_file_options = "-binary";
108 default_save_header_format (void)
111 std::string ("# Created by Octave " OCTAVE_VERSION
112 ", %a %b %d %H:%M:%S %Y %Z <")
113 + octave_env::get_user_name ()
115 + octave_env::get_host_name ()
119 // The format string for the comment line at the top of text-format
120 // save files. Passed to strftime. Should begin with `#' and contain
121 // no newline characters.
122 static std::string Vsave_header_format_string = default_save_header_format ();
125 gripe_file_open (const std::string& fcn, const std::string& file)
128 error ("%s: unable to open input file `%s'", fcn.c_str (), file.c_str ());
129 else if (fcn == "save")
130 error ("%s: unable to open output file `%s'", fcn.c_str (), file.c_str ());
132 error ("%s: unable to open file `%s'", fcn.c_str (), file.c_str ());
135 // FIXME -- shouldn't this be implemented in terms of other
136 // functions that are already available?
138 // Install a variable with name NAME and the value specified TC in the
139 // symbol table. If FORCE is TRUE, replace any existing definition
140 // for NAME. If GLOBAL is TRUE, make the variable global.
142 // Assumes TC is defined.
145 install_loaded_variable (int force, const std::string& name,
146 const octave_value& val,
147 int global, const std::string& doc)
149 // Is there already a symbol by this name? If so, what is it?
151 symbol_record *lsr = curr_sym_tab->lookup (name);
153 bool is_undefined = true;
154 bool is_variable = false;
155 bool is_function = false;
156 bool is_global = false;
160 is_undefined = ! lsr->is_defined ();
161 is_variable = lsr->is_variable ();
162 is_function = lsr->is_function ();
163 is_global = lsr->is_linked_to_global ();
166 symbol_record *sr = 0;
170 if (is_global || is_undefined)
172 if (force || is_undefined)
174 lsr = curr_sym_tab->lookup (name, true);
175 link_to_global_variable (lsr);
180 warning ("load: global variable name `%s' exists",
182 warning ("use `load -force' to overwrite");
185 else if (is_function)
189 lsr = curr_sym_tab->lookup (name, true);
190 link_to_global_variable (lsr);
195 warning ("load: `%s' is currently a function in this scope",
197 warning ("`load -force' will load variable and hide function");
200 else if (is_variable)
204 lsr = curr_sym_tab->lookup (name, true);
205 link_to_global_variable (lsr);
210 warning ("load: local variable name `%s' exists",
212 warning ("use `load -force' to overwrite");
216 error ("load: unable to load data for unknown symbol type");
222 if (force || is_undefined)
224 lsr = curr_sym_tab->lookup (name, true);
225 link_to_global_variable (lsr);
230 warning ("load: global variable name `%s' exists",
232 warning ("use `load -force' to overwrite");
235 else if (is_function)
239 lsr = curr_sym_tab->lookup (name, true);
240 link_to_global_variable (lsr);
245 warning ("load: `%s' is currently a function in this scope",
247 warning ("`load -force' will load variable and hide function");
250 else if (is_variable || is_undefined)
252 if (force || is_undefined)
254 lsr = curr_sym_tab->lookup (name, true);
259 warning ("load: local variable name `%s' exists",
261 warning ("use `load -force' to overwrite");
265 error ("load: unable to load data for unknown symbol type");
275 error ("load: unable to load variable `%s'", name.c_str ());
280 // Return TRUE if NAME matches one of the given globbing PATTERNS.
283 matches_patterns (const string_vector& patterns, int pat_idx,
284 int num_pat, const std::string& name)
286 for (int i = pat_idx; i < num_pat; i++)
288 glob_match pattern (patterns[i]);
290 if (pattern.match (name))
298 read_binary_file_header (std::istream& is, bool& swap,
299 oct_mach_info::float_format& flt_fmt, bool quiet)
301 const int magic_len = 10;
302 char magic[magic_len+1];
303 is.read (magic, magic_len);
304 magic[magic_len] = '\0';
306 if (strncmp (magic, "Octave-1-L", magic_len) == 0)
307 swap = oct_mach_info::words_big_endian ();
308 else if (strncmp (magic, "Octave-1-B", magic_len) == 0)
309 swap = ! oct_mach_info::words_big_endian ();
313 error ("load: unable to read read binary file");
320 flt_fmt = mopt_digit_to_float_format (tmp);
322 if (flt_fmt == oct_mach_info::flt_fmt_unknown)
325 error ("load: unrecognized binary format!");
335 check_gzip_magic (const std::string& fname)
338 std::ifstream file (fname.c_str ());
339 OCTAVE_LOCAL_BUFFER (unsigned char, magic, 2);
341 if (file.read (reinterpret_cast<char *> (magic), 2) && magic[0] == 0x1f &&
350 static load_save_format
351 get_file_format (std::istream& file, const std::string& filename)
353 load_save_format retval = LS_UNKNOWN;
355 oct_mach_info::float_format flt_fmt = oct_mach_info::flt_fmt_unknown;
359 if (read_binary_file_header (file, swap, flt_fmt, true) == 0)
364 file.seekg (0, std::ios::beg);
366 int32_t mopt, nr, nc, imag, len;
368 int err = read_mat_file_header (file, swap, mopt, nr, nc, imag, len, 1);
371 retval = LS_MAT_BINARY;
375 file.seekg (0, std::ios::beg);
377 err = read_mat5_binary_file_header (file, swap, true, filename);
382 file.seekg (0, std::ios::beg);
383 retval = LS_MAT5_BINARY;
388 file.seekg (0, std::ios::beg);
390 std::string tmp = extract_keyword (file, "name");
401 static load_save_format
402 get_file_format (const std::string& fname, const std::string& orig_fname,
405 load_save_format retval = LS_UNKNOWN;
408 // check this before we open the file
409 if (H5Fis_hdf5 (fname.c_str ()) > 0)
411 #endif /* HAVE_HDF5 */
413 std::ifstream file (fname.c_str ());
418 retval = get_file_format (file, orig_fname);
422 if (retval == LS_UNKNOWN && check_gzip_magic (fname))
424 gzifstream gzfile (fname.c_str ());
429 retval = get_file_format (gzfile, orig_fname);
435 if (retval == LS_UNKNOWN)
437 // Try reading the file as numbers only, determining the
438 // number of rows and columns from the data. We don't
439 // even bother to check to see if the first item in the
440 // file is a number, so that get_complete_line() can
441 // skip any comments that might appear at the top of the
444 retval = LS_MAT_ASCII;
448 gripe_file_open ("load", orig_fname);
454 do_load (std::istream& stream, const std::string& orig_fname, bool force,
455 load_save_format format, oct_mach_info::float_format flt_fmt,
456 bool list_only, bool swap, bool verbose,
457 const string_vector& argv, int argv_idx, int argc, int nargout)
461 Octave_map retstruct;
463 std::ostringstream output_buf;
465 octave_idx_type count = 0;
478 name = read_ascii_data (stream, orig_fname, global, tc, count);
482 name = read_binary_data (stream, swap, flt_fmt, orig_fname,
487 name = read_mat_ascii_data (stream, orig_fname, tc);
491 name = read_mat_binary_data (stream, orig_fname, tc);
496 name = read_hdf5_data (stream, orig_fname, global, tc, doc);
498 #endif /* HAVE_HDF5 */
502 name = read_mat5_binary_element (stream, orig_fname, swap,
507 gripe_unrecognized_data_fmt ("load");
511 if (error_state || stream.eof () || name.empty ())
513 else if (! error_state && ! name.empty ())
515 if (tc.is_defined ())
517 if (format == LS_MAT_ASCII && argv_idx < argc)
518 warning ("load: loaded ASCII file `%s' -- ignoring extra args",
519 orig_fname.c_str ());
521 if (format == LS_MAT_ASCII
523 || matches_patterns (argv, argv_idx, argc, name))
532 << "type rows cols name\n"
533 << "==== ==== ==== ====\n";
536 << std::setiosflags (std::ios::left)
537 << std::setw (16) << tc.type_name () . c_str ()
538 << std::setiosflags (std::ios::right)
539 << std::setw (7) << tc.rows ()
540 << std::setw (7) << tc.columns ()
543 output_buf << name << "\n";
549 if (format == LS_MAT_ASCII)
552 retstruct.assign (name, tc);
555 install_loaded_variable (force, name, tc, global, doc);
559 // Only attempt to read one item from a headless text file.
561 if (format == LS_MAT_ASCII)
565 error ("load: unable to load variable `%s'", name.c_str ());
570 error ("load: are you sure `%s' is an Octave data file?",
571 orig_fname.c_str ());
577 if (list_only && count)
579 std::string msg = output_buf.str ();
584 octave_stdout << msg;
586 else if (retstruct.nfields () != 0)
593 find_file_to_load (const std::string& name, const std::string& orig_name)
595 std::string fname = name;
597 if (! (octave_env::absolute_pathname (fname)
598 || octave_env::rooted_relative_pathname (fname)))
600 file_stat fs (fname);
602 if (! (fs.exists () && fs.is_reg ()))
604 std::string tmp = octave_env::make_absolute
605 (load_path::find_file (fname), octave_env::getcwd ());
609 warning_with_id ("Octave:load-file-in-path",
610 "load: file found in load path");
616 size_t dot_pos = fname.rfind (".");
617 size_t sep_pos = fname.find_last_of (file_ops::dir_sep_chars);
619 if (dot_pos == NPOS || (sep_pos != NPOS && dot_pos < sep_pos))
621 // Either no '.' in name or no '.' appears after last directory
624 file_stat fs (fname);
626 if (! (fs.exists () && fs.is_reg ()))
627 fname = find_file_to_load (fname + ".mat", orig_name);
631 file_stat fs (fname);
633 if (! (fs.exists () && fs.is_reg ()))
637 error ("load: unable to find file %s", orig_name.c_str ());
645 // HDF5 load/save documentation is included in the Octave manual
646 // regardless, but if HDF5 is not linked in we also include a
647 // sentence noting this, so the user understands that the features
648 // aren't available. Define a macro for this sentence:
651 #define HAVE_HDF5_HELP_STRING ""
652 #else /* ! HAVE_HDF5 */
653 #define HAVE_HDF5_HELP_STRING "\n\
654 HDF5 load and save are not available, as this Octave executable was\n\
655 not linked with the HDF5 library."
656 #endif /* ! HAVE HDF5 */
658 DEFCMD (load, args, nargout,
660 @deffn {Command} load options file v1 v2 @dots{}\n\
661 Load the named variables @var{v1}, @var{v2}, @dots{}, from the file\n\
662 @var{file}. As with @code{save}, you may specify a list of variables\n\
663 and @code{load} will only extract those variables with names that\n\
664 match. For example, to restore the variables saved in the file\n\
665 @file{data}, use the command\n\
671 If load is invoked using the functional form\n\
674 load (\"-option1\", @dots{}, \"file\", \"v1\", @dots{})\n\
678 then the @var{options}, @var{file}, and variable name arguments\n\
679 (@var{v1}, @dots{}) must be specified as character strings.\n\
681 If a variable that is not marked as global is loaded from a file when a\n\
682 global symbol with the same name already exists, it is loaded in the\n\
683 global symbol table. Also, if a variable is marked as global in a file\n\
684 and a local symbol exists, the local symbol is moved to the global\n\
685 symbol table and given the value from the file. Since it seems that\n\
686 both of these cases are likely to be the result of some sort of error,\n\
687 they will generate warnings.\n\
689 If invoked with a single output argument, Octave returns data instead\n\
690 of inserting variables in the symbol table. If the data file contains\n\
691 only numbers (TAB- or space-delimited columns), a matrix of values is\n\
692 returned. Otherwise, @code{load} returns a structure with members\n\
693 corresponding to the names of the variables in the file.\n\
695 The @code{load} command can read data stored in Octave's text and\n\
696 binary formats, and @sc{Matlab}'s binary format. It will automatically\n\
697 detect the type of file and do conversion from different floating point\n\
698 formats (currently only IEEE big and little endian, though other formats\n\
699 may added in the future).\n\
701 Valid options for @code{load} are listed in the following table.\n\
705 The @samp{-force} option is accepted but ignored for backward\n\
706 compatibility. Octave now overwrites variables currently in memory with\n\
707 the same name as those found in the file.\n\
710 Force Octave to assume the file contains columns of numbers in text format\n\
711 without any header or other information. Data in the file will be loaded\n\
712 as a single numeric matrix with the name of the variable derived from the\n\
716 Force Octave to assume the file is in Octave's binary format.\n\
719 @itemx -mat-binary\n\
724 Force Octave to assume the file is in @sc{Matlab}'s version 6 or 7 binary\n\
730 @itemx -mat4-binary\n\
731 Force Octave to assume the file is in the binary format written by\n\
732 @sc{Matlab} version 4.\n\
735 Force Octave to assume the file is in HDF5 format.\n\
736 (HDF5 is a free, portable binary format developed by the National\n\
737 Center for Supercomputing Applications at the University of Illinois.)\n\
738 Note that Octave can read HDF5 files not created by itself, but may\n\
739 skip some datasets in formats that it cannot support.\n"
741 HAVE_HDF5_HELP_STRING
745 The @samp{-import} is accepted but ignored for backward compatibility.\n\
746 Octave can now support multi-dimensional HDF data and automatically\n\
747 modifies variable names if they are invalid Octave identifiers.\n\
750 Force Octave to assume the file is in Octave's text format.\n\
754 octave_value_list retval;
756 int argc = args.length () + 1;
758 string_vector argv = args.make_argv ("load");
763 // It isn't necessary to have the default load format stored in a
764 // user preference variable since we can determine the type of file
765 // as we are reading.
767 load_save_format format = LS_UNKNOWN;
770 bool list_only = false;
771 bool verbose = false;
774 for (i = 1; i < argc; i++)
776 if (argv[i] == "-force" || argv[i] == "-f")
778 // Silently ignore this
779 // warning ("load: -force ignored");
781 else if (argv[i] == "-list" || argv[i] == "-l")
785 else if (argv[i] == "-verbose" || argv[i] == "-v")
789 else if (argv[i] == "-ascii" || argv[i] == "-a")
791 format = LS_MAT_ASCII;
793 else if (argv[i] == "-binary" || argv[i] == "-b")
797 else if (argv[i] == "-mat-binary" || argv[i] == "-mat" || argv[i] == "-m"
798 || argv[i] == "-6" || argv[i] == "-v6")
800 format = LS_MAT5_BINARY;
802 else if (argv[i] == "-7" || argv[i] == "-v7")
804 format = LS_MAT7_BINARY;
806 else if (argv[i] == "-mat4-binary" || argv[i] == "-V4"
807 || argv[i] == "-v4" || argv[i] == "-4")
809 format = LS_MAT_BINARY;
811 else if (argv[i] == "-hdf5" || argv[i] == "-h")
815 #else /* ! HAVE_HDF5 */
816 error ("load: octave executable was not linked with HDF5 library");
818 #endif /* ! HAVE_HDF5 */
820 else if (argv[i] == "-import" || argv[i] == "-i")
822 warning ("load: -import ignored");
824 else if (argv[i] == "-text" || argv[i] == "-t")
838 std::string orig_fname = argv[i];
840 oct_mach_info::float_format flt_fmt = oct_mach_info::flt_fmt_unknown;
849 if (format == LS_HDF5)
850 error ("load: cannot read HDF5 format from stdin");
852 #endif /* HAVE_HDF5 */
853 if (format != LS_UNKNOWN)
855 // FIXME -- if we have already seen EOF on a
856 // previous call, how do we fix up the state of std::cin so
857 // that we can get additional input? I'm afraid that we
858 // can't fix this using std::cin only.
860 retval = do_load (std::cin, orig_fname, force, format, flt_fmt,
861 list_only, swap, verbose, argv, i, argc,
865 error ("load: must specify file format if reading from stdin");
869 std::string fname = file_ops::tilde_expand (argv[i]);
871 fname = find_file_to_load (fname, orig_fname);
876 bool use_zlib = false;
878 if (format == LS_UNKNOWN)
879 format = get_file_format (fname, orig_fname, use_zlib);
882 if (format == LS_HDF5)
886 hdf5_ifstream hdf5_file (fname.c_str ());
888 if (hdf5_file.file_id >= 0)
890 retval = do_load (hdf5_file, orig_fname, force, format,
891 flt_fmt, list_only, swap, verbose,
892 argv, i, argc, nargout);
897 gripe_file_open ("load", orig_fname);
900 #endif /* HAVE_HDF5 */
901 // don't insert any statements here; the "else" above has to
902 // go with the "if" below!!!!!
903 if (format != LS_UNKNOWN)
907 std::ios::openmode mode = std::ios::in;
909 // Open in binary mode in any case, to fix annoying bug that
910 // text-mode opened streams cannot be seekg'ed/tellg'ed with
911 // mingw32 (See http://oldwiki.mingw.org/index.php/Known%20Problems )
912 // The CR/LF issues are handled in ls-ascii-helper.cc
913 mode |= std::ios::binary;
918 gzifstream file (fname.c_str (), mode);
922 if (format == LS_BINARY)
924 if (read_binary_file_header (file, swap, flt_fmt) < 0)
926 if (file) file.close ();
930 else if (format == LS_MAT5_BINARY
931 || format == LS_MAT7_BINARY)
933 if (read_mat5_binary_file_header (file, swap, false, orig_fname) < 0)
935 if (file) file.close ();
940 retval = do_load (file, orig_fname, force, format,
941 flt_fmt, list_only, swap, verbose,
942 argv, i, argc, nargout);
947 gripe_file_open ("load", orig_fname);
952 std::ifstream file (fname.c_str (), mode);
956 if (format == LS_BINARY)
958 if (read_binary_file_header (file, swap, flt_fmt) < 0)
960 if (file) file.close ();
964 else if (format == LS_MAT5_BINARY
965 || format == LS_MAT7_BINARY)
967 if (read_mat5_binary_file_header (file, swap, false, orig_fname) < 0)
969 if (file) file.close ();
974 retval = do_load (file, orig_fname, force, format,
975 flt_fmt, list_only, swap, verbose,
976 argv, i, argc, nargout);
981 error ("load: unable open input file `%s'",
982 orig_fname.c_str ());
990 // Return TRUE if PATTERN has any special globbing chars in it.
993 glob_pattern_p (const std::string& pattern)
997 int len = pattern.length ();
999 for (int i = 0; i < len; i++)
1001 char c = pattern[i];
1009 case '[': // Only accept an open brace if there is a close
1010 open++; // brace to match it. Bracket expressions must be
1011 continue; // complete, according to Posix.2
1031 do_save (std::ostream& os, const octave_value& tc,
1032 const std::string& name, const std::string& help,
1033 int global, load_save_format fmt, bool save_as_floats)
1038 save_ascii_data (os, tc, name, global, 0);
1042 save_binary_data (os, tc, name, help, global, save_as_floats);
1046 case LS_MAT_ASCII_LONG:
1047 if (! save_mat_ascii_data (os, tc, fmt == LS_MAT_ASCII ? 8 : 16))
1048 warning ("save: unable to save %s in ASCII format", name.c_str ());
1052 save_mat_binary_data (os, tc, name);
1057 save_hdf5_data (os, tc, name, help, global, save_as_floats);
1059 #endif /* HAVE_HDF5 */
1061 case LS_MAT5_BINARY:
1062 save_mat5_binary_element (os, tc, name, global, false, save_as_floats);
1065 case LS_MAT7_BINARY:
1066 save_mat5_binary_element (os, tc, name, global, true, save_as_floats);
1070 gripe_unrecognized_data_fmt ("save");
1075 // Save the info from SR on stream OS in the format specified by FMT.
1078 do_save (std::ostream& os, symbol_record *sr, load_save_format fmt,
1079 bool save_as_floats)
1081 if (! sr->is_variable ())
1083 error ("save: can only save variables, not functions");
1087 octave_value tc = sr->def ();
1089 if (tc.is_defined ())
1091 std::string name = sr->name ();
1092 std::string help = sr->help ();
1094 int global = sr->is_linked_to_global ();
1096 do_save (os, tc, name, help, global, fmt, save_as_floats);
1100 // Save variables with names matching PATTERN on stream OS in the
1101 // format specified by FMT.
1104 save_vars (std::ostream& os, const std::string& pattern,
1105 load_save_format fmt, bool save_as_floats)
1107 Array<symbol_record *> vars = curr_sym_tab->glob
1108 (pattern, symbol_record::USER_VARIABLE, SYMTAB_ALL_SCOPES);
1110 int saved = vars.length ();
1112 for (int i = 0; i < saved; i++)
1114 do_save (os, vars(i), fmt, save_as_floats);
1123 static string_vector
1124 parse_save_options (const string_vector &argv,
1125 load_save_format &format, bool &append,
1126 bool &save_as_floats, bool &use_zlib)
1128 string_vector retval;
1129 int argc = argv.length ();
1131 for (int i = 0; i < argc; i++)
1133 if (argv[i] == "-append")
1137 else if (argv[i] == "-ascii" || argv[i] == "-a")
1139 format = LS_MAT_ASCII;
1141 else if (argv[i] == "-text" || argv[i] == "-t")
1145 else if (argv[i] == "-binary" || argv[i] == "-b")
1149 else if (argv[i] == "-hdf5" || argv[i] == "-h")
1153 #else /* ! HAVE_HDF5 */
1154 error ("save: octave executable was not linked with HDF5 library");
1155 #endif /* ! HAVE_HDF5 */
1157 else if (argv[i] == "-mat-binary" || argv[i] == "-mat"
1158 || argv[i] == "-m" || argv[i] == "-6" || argv[i] == "-v6"
1159 || argv[i] == "-V6")
1161 format = LS_MAT5_BINARY;
1164 else if (argv[i] == "-mat7-binary" || argv[i] == "-7"
1165 || argv[i] == "-v7" || argv[i] == "-V7")
1167 format = LS_MAT7_BINARY;
1170 else if (argv[i] == "-mat4-binary" || argv[i] == "-V4"
1171 || argv[i] == "-v4" || argv[i] == "-4")
1173 format = LS_MAT_BINARY;
1175 else if (argv[i] == "-float-binary" || argv[i] == "-f")
1178 save_as_floats = true;
1180 else if (argv[i] == "-float-hdf5")
1184 save_as_floats = true;
1185 #else /* ! HAVE_HDF5 */
1186 error ("save: octave executable was not linked with HDF5 library");
1187 #endif /* ! HAVE_HDF5 */
1190 else if (argv[i] == "-zip" || argv[i] == "-z")
1196 retval.append (argv[i]);
1202 static string_vector
1203 parse_save_options (const std::string &arg, load_save_format &format,
1204 bool &append, bool &save_as_floats,
1207 std::istringstream is (arg);
1217 return parse_save_options (argv, format, append, save_as_floats,
1222 write_header (std::ostream& os, load_save_format format)
1228 os << (oct_mach_info::words_big_endian ()
1229 ? "Octave-1-B" : "Octave-1-L");
1231 oct_mach_info::float_format flt_fmt =
1232 oct_mach_info::native_float_format ();
1234 char tmp = static_cast<char> (float_format_to_mopt_digit (flt_fmt));
1240 case LS_MAT5_BINARY:
1241 case LS_MAT7_BINARY:
1243 char const * versionmagic;
1244 int16_t number = *(reinterpret_cast<const int16_t *>("\x00\x01"));
1247 char headertext[128];
1250 bdt = *gmtime (&now);
1251 memset (headertext, ' ', 124);
1252 // ISO 8601 format date
1253 strftime (headertext, 124, "MATLAB 5.0 MAT-file, written by Octave "
1254 OCTAVE_VERSION ", %Y-%m-%d %T UTC", &bdt);
1256 // The first pair of bytes give the version of the MAT file
1257 // format. The second pair of bytes form a magic number which
1258 // signals a MAT file. MAT file data are always written in
1259 // native byte order. The order of the bytes in the second
1260 // pair indicates whether the file was written by a big- or
1261 // little-endian machine. However, the version number is
1262 // written in the *opposite* byte order from everything else!
1264 versionmagic = "\x01\x00\x4d\x49"; // this machine is big endian
1266 versionmagic = "\x00\x01\x49\x4d"; // this machine is little endian
1268 memcpy (headertext+124, versionmagic, 4);
1269 os.write (headertext, 128);
1276 #endif /* HAVE_HDF5 */
1279 octave_localtime now;
1281 std::string comment_string = now.strftime (Vsave_header_format_string);
1283 if (! comment_string.empty ())
1286 if (format == LS_HDF5)
1288 hdf5_ofstream& hs = dynamic_cast<hdf5_ofstream&> (os);
1289 H5Gset_comment (hs.file_id, "/", comment_string.c_str ());
1292 #endif /* HAVE_HDF5 */
1293 os << comment_string << "\n";
1304 save_vars (const string_vector& argv, int argv_idx, int argc,
1305 std::ostream& os, load_save_format fmt,
1306 bool save_as_floats, bool write_header_info)
1308 if (write_header_info)
1309 write_header (os, fmt);
1311 if (argv_idx == argc)
1313 save_vars (os, "*", fmt, save_as_floats);
1317 for (int i = argv_idx; i < argc; i++)
1319 if (! save_vars (os, argv[i], fmt, save_as_floats))
1321 warning ("save: no such variable `%s'", argv[i].c_str ());
1328 dump_octave_core (std::ostream& os, const char *fname, load_save_format fmt,
1329 bool save_as_floats)
1331 write_header (os, fmt);
1333 Array<symbol_record *> vars = curr_sym_tab->glob
1334 ("*", symbol_record::USER_VARIABLE, SYMTAB_ALL_SCOPES);
1336 int num_to_save = vars.length ();
1338 double save_mem_size = 0;
1340 for (int i = 0; i < num_to_save; i++)
1342 symbol_record *sr = vars(i);
1344 if (sr->is_variable ())
1346 octave_value tc = sr->def ();
1348 if (tc.is_defined ())
1350 double tc_size = tc.byte_size () / 1024;
1352 // FIXME -- maybe we should try to throw out the
1355 if (Voctave_core_file_limit < 0
1356 || save_mem_size + tc_size < Voctave_core_file_limit)
1358 save_mem_size += tc_size;
1360 std::string name = sr->name ();
1361 std::string help = sr->help ();
1363 int global = sr->is_linked_to_global ();
1365 do_save (os, tc, name, help, global, fmt, save_as_floats);
1374 message (0, "save to `%s' complete", fname);
1378 dump_octave_core (void)
1380 if (Vcrash_dumps_octave_core)
1382 // FIXME -- should choose better file name?
1384 const char *fname = Voctave_core_file_name.c_str ();
1386 message (0, "attempting to save variables to `%s'...", fname);
1388 load_save_format format = LS_BINARY;
1390 bool save_as_floats = false;
1392 bool append = false;
1394 bool use_zlib = false;
1396 parse_save_options (Voctave_core_file_options, format, append,
1397 save_as_floats, use_zlib);
1399 std::ios::openmode mode = std::ios::out;
1401 // Matlab v7 files are always compressed
1402 if (format == LS_MAT7_BINARY)
1405 if (format == LS_BINARY
1407 || format == LS_HDF5
1409 || format == LS_MAT_BINARY
1410 || format == LS_MAT5_BINARY
1411 || format == LS_MAT7_BINARY)
1412 mode |= std::ios::binary;
1414 mode |= append ? std::ios::ate : std::ios::trunc;
1417 if (format == LS_HDF5)
1419 hdf5_ofstream file (fname, mode);
1421 if (file.file_id >= 0)
1423 dump_octave_core (file, fname, format, save_as_floats);
1428 warning ("unable to open `%s' for writing...", fname);
1431 #endif /* HAVE_HDF5 */
1432 // don't insert any commands here! The open brace below must
1433 // go with the else above!
1438 gzofstream file (fname, mode);
1442 dump_octave_core (file, fname, format, save_as_floats);
1447 warning ("unable to open `%s' for writing...", fname);
1452 std::ofstream file (fname, mode);
1456 dump_octave_core (file, fname, format, save_as_floats);
1461 warning ("unable to open `%s' for writing...", fname);
1468 #define HAVE_ZLIB_HELP_STRING ""
1469 #else /* ! HAVE_ZLIB */
1470 #define HAVE_ZLIB_HELP_STRING "\n\
1471 This option is not available, as this Octave executable was not linked with\n\
1473 #endif /* ! HAVE ZLIB */
1475 DEFCMD (save, args, ,
1477 @deffn {Command} save options file @var{v1} @var{v2} @dots{}\n\
1478 Save the named variables @var{v1}, @var{v2}, @dots{}, in the file\n\
1479 @var{file}. The special filename @samp{-} can be used to write the\n\
1480 output to your terminal. If no variable names are listed, Octave saves\n\
1481 all the variables in the current scope. Valid options for the\n\
1482 @code{save} command are listed in the following table. Options that\n\
1483 modify the output format override the format specified by\n\
1484 @code{default_save_options}.\n\
1486 If save is invoked using the functional form\n\
1489 save (\"-option1\", @dots{}, \"file\", \"v1\", @dots{})\n\
1493 then the @var{options}, @var{file}, and variable name arguments\n\
1494 (@var{v1}, @dots{}) must be specified as character strings.\n\
1498 Save a single matrix in a text file.\n\
1501 Save the data in Octave's binary data format.\n\
1503 @item -float-binary\n\
1504 Save the data in Octave's binary data format but only using single\n\
1505 precision. You should use this format only if you know that all the\n\
1506 values to be saved can be represented in single precision.\n\
1511 @itemx -mat7-binary\n\
1512 Save the data in @sc{Matlab}'s v7 binary data format.\n"
1514 HAVE_ZLIB_HELP_STRING
1521 @itemx -mat-binary\n\
1522 Save the data in @sc{Matlab}'s v6 binary data format.\n\
1527 @itemx -mat4-binary\n\
1528 Save the data in the binary format written by @sc{Matlab} version 4.\n\
1531 Save the data in HDF5 format.\n\
1532 (HDF5 is a free, portable binary format developed by the National\n\
1533 Center for Supercomputing Applications at the University of Illinois.)\n"
1535 HAVE_HDF5_HELP_STRING
1538 @item -float-hdf5\n\
1539 Save the data in HDF5 format but only using single precision.\n\
1540 You should use this format only if you know that all the\n\
1541 values to be saved can be represented in single precision.\n\
1545 Use the gzip algorithm to compress the file. This works equally on files that\n\
1546 are compressed with gzip outside of octave, and gzip can equally be used to\n\
1547 convert the files for backward compatibility.\n"
1549 HAVE_ZLIB_HELP_STRING
1553 The list of variables to save may include wildcard patterns containing\n\
1554 the following special characters:\n\
1557 Match any single character.\n\
1560 Match zero or more characters.\n\
1562 @item [ @var{list} ]\n\
1563 Match the list of characters specified by @var{list}. If the first\n\
1564 character is @code{!} or @code{^}, match all characters except those\n\
1565 specified by @var{list}. For example, the pattern @samp{[a-zA-Z]} will\n\
1566 match all lower and upper case alphabetic characters. \n\
1569 Save the data in Octave's text data format.\n\
1572 Except when using the @sc{Matlab} binary data file format, saving global\n\
1573 variables also saves the global status of the variable, so that if it is\n\
1574 restored at a later time using @samp{load}, it will be restored as a\n\
1580 save -binary data a b*\n\
1584 saves the variable @samp{a} and all variables beginning with @samp{b} to\n\
1585 the file @file{data} in Octave's binary format.\n\
1588 octave_value_list retval;
1590 int argc = args.length ();
1592 string_vector argv = args.make_argv ();
1597 // Here is where we would get the default save format if it were
1598 // stored in a user preference variable.
1600 bool save_as_floats = false;
1602 load_save_format format = LS_ASCII;
1604 bool append = false;
1606 bool use_zlib = false;
1608 // get default options
1609 parse_save_options (Vdefault_save_options, format, append, save_as_floats,
1612 // override from command line
1613 argv = parse_save_options (argv, format, append, save_as_floats,
1615 argc = argv.length ();
1627 if (save_as_floats && format == LS_ASCII)
1629 error ("save: cannot specify both -ascii and -float-binary");
1638 if (format == LS_HDF5)
1639 error ("save: cannot write HDF5 format to stdout");
1641 #endif /* HAVE_HDF5 */
1642 // don't insert any commands here! the brace below must go
1643 // with the "else" above!
1646 warning ("save: ignoring -append option for output to stdout");
1648 // FIXME -- should things intended for the screen end up
1649 // in a octave_value (string)?
1651 save_vars (argv, i, argc, octave_stdout, format,
1652 save_as_floats, true);
1656 // Guard against things like `save a*', which are probably mistakes...
1658 else if (i == argc - 1 && glob_pattern_p (argv[i]))
1665 std::string fname = file_ops::tilde_expand (argv[i]);
1669 // Matlab v7 files are always compressed
1670 if (format == LS_MAT7_BINARY)
1673 std::ios::openmode mode
1674 = append ? (std::ios::app | std::ios::ate) : std::ios::out;
1676 if (format == LS_BINARY
1678 || format == LS_HDF5
1680 || format == LS_MAT_BINARY
1681 || format == LS_MAT5_BINARY
1682 || format == LS_MAT7_BINARY)
1683 mode |= std::ios::binary;
1686 if (format == LS_HDF5)
1688 // FIXME. It should be possible to append to HDF5 files.
1691 error ("save: appending to HDF5 files is not implemented");
1695 bool write_header_info = ! (append &&
1696 H5Fis_hdf5 (fname.c_str ()) > 0);
1698 hdf5_ofstream hdf5_file (fname.c_str (), mode);
1700 if (hdf5_file.file_id != -1)
1702 save_vars (argv, i, argc, hdf5_file, format,
1703 save_as_floats, write_header_info);
1709 gripe_file_open ("save", fname);
1714 #endif /* HAVE_HDF5 */
1715 // don't insert any statements here! The brace below must go
1716 // with the "else" above!
1721 gzofstream file (fname.c_str (), mode);
1725 bool write_header_info = ! file.tellp ();
1727 save_vars (argv, i, argc, file, format,
1728 save_as_floats, write_header_info);
1734 gripe_file_open ("save", fname);
1741 std::ofstream file (fname.c_str (), mode);
1745 bool write_header_info = ! file.tellp ();
1747 save_vars (argv, i, argc, file, format,
1748 save_as_floats, write_header_info);
1754 gripe_file_open ("save", fname);
1764 DEFUN (crash_dumps_octave_core, args, nargout,
1766 @deftypefn {Built-in Function} {@var{val} =} crash_dumps_octave_core ()\n\
1767 @deftypefnx {Built-in Function} {@var{old_val} =} crash_dumps_octave_core (@var{new_val})\n\
1768 Query or set the internal variable that controls whether Octave tries\n\
1769 to save all current variables to the file \"octave-core\" if it\n\
1770 crashes or receives a hangup, terminate or similar signal.\n\
1771 @seealso{octave_core_file_limit, octave_core_file_name, octave_core_file_options}\n\
1774 return SET_INTERNAL_VARIABLE (crash_dumps_octave_core);
1777 DEFUN (default_save_options, args, nargout,
1779 @deftypefn {Built-in Function} {@var{val} =} default_save_options ()\n\
1780 @deftypefnx {Built-in Function} {@var{old_val} =} default_save_options (@var{new_val})\n\
1781 Query or set the internal variable that specifies the default options\n\
1782 for the @code{save} command, and defines the default format.\n\
1783 Typical values include @code{\"-ascii\"}, @code{\"-ascii -zip\"}.\n\
1784 The default value is @code{-ascii}.\n\
1788 return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (default_save_options);
1791 DEFUN (octave_core_file_limit, args, nargout,
1793 @deftypefn {Built-in Function} {@var{val} =} octave_core_file_limit ()\n\
1794 @deftypefnx {Built-in Function} {@var{old_val} =} octave_core_file_limit (@var{new_val})\n\
1795 Query or set the internal variable that specifies the maximum amount\n\
1796 of memory (in kilobytes) of the top-level workspace that Octave will\n\
1797 attempt to save when writing data to the crash dump file (the name of\n\
1798 the file is specified by @var{octave_core_file_name}). If\n\
1799 @var{octave_core_file_options} flags specify a binary format,\n\
1800 then @var{octave_core_file_limit} will be approximately the maximum\n\
1801 size of the file. If a text file format is used, then the file could\n\
1802 be much larger than the limit. The default value is -1 (unlimited)\n\
1803 @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_options}\n\
1806 return SET_INTERNAL_VARIABLE (octave_core_file_limit);
1809 DEFUN (octave_core_file_name, args, nargout,
1811 @deftypefn {Built-in Function} {@var{val} =} octave_core_file_name ()\n\
1812 @deftypefnx {Built-in Function} {@var{old_val} =} octave_core_file_name (@var{new_val})\n\
1813 Query or set the internal variable that specifies the name of the file\n\
1814 used for saving data from the top-level workspace if Octave aborts.\n\
1815 The default value is @code{\"octave-core\"}\n\
1816 @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_options}\n\
1819 return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (octave_core_file_name);
1822 DEFUN (octave_core_file_options, args, nargout,
1824 @deftypefn {Built-in Function} {@var{val} =} octave_core_file_options ()\n\
1825 @deftypefnx {Built-in Function} {@var{old_val} =} octave_core_file_options (@var{new_val})\n\
1826 Query or set the internal variable that specifies the options used for\n\
1827 saving the workspace data if Octave aborts. The value of\n\
1828 @code{octave_core_file_options} should follow the same format as the\n\
1829 options for the @code{save} function. The default value is Octave's binary\n\
1831 @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_limit}\n\
1834 return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (octave_core_file_options);
1837 DEFUN (save_header_format_string, args, nargout,
1839 @deftypefn {Built-in Function} {@var{val} =} save_header_format_string ()\n\
1840 @deftypefnx {Built-in Function} {@var{old_val} =} save_header_format_string (@var{new_val})\n\
1841 Query or set the internal variable that specifies the format\n\
1842 string used for the comment line written at the beginning of\n\
1843 text-format data files saved by Octave. The format string is\n\
1844 passed to @code{strftime} and should begin with the character\n\
1845 @samp{#} and contain no newline characters. If the value of\n\
1846 @code{save_header_format_string} is the empty string,\n\
1847 the header comment is omitted from text-format data files. The\n\
1851 \"# Created by Octave VERSION, %a %b %d %H:%M:%S %Y %Z <USER@@HOST>\"\n\
1852 @end smallexample\n\
1853 @seealso{strftime}\n\
1856 return SET_INTERNAL_VARIABLE (save_header_format_string);
1860 ;;; Local Variables: ***