GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
load-save.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1994-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <cstring>
31 
32 #include <fstream>
33 #include <iomanip>
34 #include <iostream>
35 #include <list>
36 #include <sstream>
37 #include <string>
38 
39 #include "byte-swap.h"
40 #include "dMatrix.h"
41 #include "data-conv.h"
42 #include "file-ops.h"
43 #include "file-stat.h"
44 #include "glob-match.h"
45 #include "lo-mappers.h"
46 #include "mach-info.h"
47 #include "oct-env.h"
48 #include "oct-locbuf.h"
49 #include "oct-time.h"
50 #include "quit.h"
51 #include "str-vec.h"
52 #include "strftime-wrapper.h"
53 
54 #include "Cell.h"
55 #include "defun.h"
56 #include "error.h"
57 #include "errwarn.h"
58 #include "interpreter.h"
59 #include "interpreter-private.h"
60 #include "load-path.h"
61 #include "load-save.h"
62 #include "oct-hdf5.h"
63 #include "ovl.h"
64 #include "oct-map.h"
65 #include "ov-cell.h"
66 #include "pager.h"
67 #include "syminfo.h"
68 #include "sysdep.h"
69 #include "unwind-prot.h"
70 #include "utils.h"
71 #include "variables.h"
72 #include "version.h"
73 
74 #include "ls-hdf5.h"
75 #include "ls-mat-ascii.h"
76 #include "ls-mat4.h"
77 #include "ls-mat5.h"
78 #include "ls-oct-text.h"
79 #include "ls-oct-binary.h"
80 
81 // Remove gnulib definitions, if any.
82 #if defined (close)
83 # undef close
84 #endif
85 #if defined (open)
86 # undef open
87 #endif
88 
89 #if defined (HAVE_ZLIB)
90 # include "zfstream.h"
91 #endif
92 
93 namespace octave
94 {
95  OCTAVE_NORETURN static
96  void
97  err_file_open (const std::string& fcn, const std::string& file)
98  {
99  if (fcn == "load")
100  error ("%s: unable to open input file '%s'", fcn.c_str (), file.c_str ());
101  else if (fcn == "save")
102  error ("%s: unable to open output file '%s'", fcn.c_str (), file.c_str ());
103  else
104  error ("%s: unable to open file '%s'", fcn.c_str (), file.c_str ());
105  }
106 
107  // Return TRUE if NAME matches one of the given globbing PATTERNS.
108 
109  static bool
110  matches_patterns (const string_vector& patterns, int pat_idx,
111  int num_pat, const std::string& name)
112  {
113  for (int i = pat_idx; i < num_pat; i++)
114  {
115  glob_match pattern (patterns[i]);
116 
117  if (pattern.match (name))
118  return true;
119  }
120 
121  return false;
122  }
123 
124  static int
125  read_binary_file_header (std::istream& is, bool& swap,
126  mach_info::float_format& flt_fmt,
127  bool quiet = false)
128  {
129  const int magic_len = 10;
130  char magic[magic_len+1];
131  is.read (magic, magic_len);
132  magic[magic_len] = '\0';
133 
134  if (strncmp (magic, "Octave-1-L", magic_len) == 0)
135  swap = mach_info::words_big_endian ();
136  else if (strncmp (magic, "Octave-1-B", magic_len) == 0)
137  swap = ! mach_info::words_big_endian ();
138  else
139  {
140  if (! quiet)
141  error ("load: unable to read binary file");
142 
143  return -1;
144  }
145 
146  char tmp = 0;
147  is.read (&tmp, 1);
148 
149  flt_fmt = mopt_digit_to_float_format (tmp);
150 
151  if (flt_fmt == mach_info::flt_fmt_unknown)
152  {
153  if (! quiet)
154  error ("load: unrecognized binary format!");
155 
156  return -1;
157  }
158 
159  return 0;
160  }
161 
162 #if defined (HAVE_ZLIB)
163  static bool
164  check_gzip_magic (const std::string& fname)
165  {
166  bool retval = false;
167 
168  std::string ascii_fname = sys::get_ASCII_filename (fname);
169 
170  std::ifstream file = sys::ifstream (fname.c_str (),
171  std::ios::in | std::ios::binary);
172 
173  unsigned char magic[2];
174  if (file.read (reinterpret_cast<char *> (&magic[0]), 2)
175  && magic[0] == 0x1f && magic[1] == 0x8b)
176  retval = true;
177 
178  file.close ();
179 
180  return retval;
181  }
182 #endif
183 
184  static std::string
185  find_file_to_load (const std::string& name, const std::string& orig_name)
186  {
187  std::string fname = find_data_file_in_load_path ("load", name, true);
188 
189  size_t dot_pos = fname.rfind ('.');
190  size_t sep_pos = fname.find_last_of (sys::file_ops::dir_sep_chars ());
191 
192  if (dot_pos == std::string::npos
193  || (sep_pos != std::string::npos && dot_pos < sep_pos))
194  {
195  // Either no '.' in name or no '.' appears after last directory
196  // separator.
197 
198  sys::file_stat fs (fname);
199 
200  if (! (fs.exists () && fs.is_reg ()))
201  fname = find_file_to_load (fname + ".mat", orig_name);
202  }
203  else
204  {
205  sys::file_stat fs (fname);
206 
207  if (! (fs.exists () && fs.is_reg ()))
208  {
209  fname = "";
210 
211  error ("load: unable to find file %s", orig_name.c_str ());
212  }
213  }
214 
215  return fname;
216  }
217 
218  // Return TRUE if PATTERN has any special globbing chars in it.
219 
220  static bool
221  glob_pattern_p (const std::string& pattern)
222  {
223  int open = 0;
224 
225  int len = pattern.length ();
226 
227  for (int i = 0; i < len; i++)
228  {
229  char c = pattern[i];
230 
231  switch (c)
232  {
233  case '?':
234  case '*':
235  return true;
236 
237  case '[': // Only accept an open brace if there is a close
238  open++; // brace to match it. Bracket expressions must be
239  continue; // complete, according to Posix.2
240 
241  case ']':
242  if (open)
243  return true;
244  continue;
245 
246  case '\\':
247  if (i == len - 1)
248  return false;
249  continue;
250 
251  default:
252  continue;
253  }
254  }
255 
256  return false;
257  }
258 
260  : m_interpreter (interp),
261  m_crash_dumps_octave_core (true),
262  m_octave_core_file_limit (-1.0),
263  m_octave_core_file_name ("octave-workspace"),
264  m_save_default_options ("-text"),
265  m_octave_core_file_options ("-binary"),
266  m_save_header_format_string (init_save_header_format ())
267  {
268 #if defined (HAVE_HDF5)
269  H5dont_atexit ();
270 #endif
271  }
272 
274  {
275 #if defined (HAVE_HDF5)
276  H5close ();
277 #endif
278  }
279 
282  int nargout)
283  {
284  return set_internal_variable (m_crash_dumps_octave_core, args, nargout,
285  "crash_dumps_octave_core");
286  }
287 
290  int nargout)
291  {
292  return set_internal_variable (m_octave_core_file_limit, args, nargout,
293  "octave_core_file_limit");
294  }
295 
298  int nargout)
299  {
300  return set_internal_variable (m_octave_core_file_name, args, nargout,
301  "octave_core_file_name", false);
302  }
303 
306  int nargout)
307  {
308  return set_internal_variable (m_save_default_options, args, nargout,
309  "save_default_options", false);
310  }
311 
314  int nargout)
315  {
316  return set_internal_variable (m_octave_core_file_options, args, nargout,
317  "octave_core_file_options", false);
318  }
319 
322  int nargout)
323  {
324  return set_internal_variable (m_save_header_format_string, args, nargout,
325  "save_header_format_string");
326  }
327 
329  load_save_system::get_file_format (const std::string& fname,
330  const std::string& orig_fname,
331  bool& use_zlib, bool quiet)
332  {
334 
335  std::string ascii_fname = sys::get_ASCII_filename (fname);
336 
337 #if defined (HAVE_HDF5)
338  // check this before we open the file
339  if (H5Fis_hdf5 (ascii_fname.c_str ()) > 0)
340  return HDF5;
341 #endif
342 
343 #if defined (HAVE_ZLIB)
344  use_zlib = check_gzip_magic (fname);
345 #else
346  use_zlib = false;
347 #endif
348 
349  if (! use_zlib)
350  {
351  std::ifstream file = sys::ifstream (fname.c_str (),
352  std::ios::in | std::ios::binary);
353  if (file)
354  {
355  retval = get_file_format (file, orig_fname);
356  file.close ();
357  }
358  else if (! quiet)
359  err_file_open ("load", orig_fname);
360  }
361 #if defined (HAVE_ZLIB)
362  else
363  {
364  gzifstream gzfile (fname.c_str (), std::ios::in | std::ios::binary);
365  if (gzfile)
366  {
367  retval = get_file_format (gzfile, orig_fname);
368  gzfile.close ();
369  }
370  else if (! quiet)
371  err_file_open ("load", orig_fname);
372  }
373 #endif
374 
375  return retval;
376  }
377 
380  const std::string& orig_fname,
381  const load_save_format& fmt,
382  mach_info::float_format flt_fmt,
383  bool list_only, bool swap, bool verbose,
384  const string_vector& argv, int argv_idx,
385  int argc, int nargout)
386  {
388 
389  octave_scalar_map retstruct;
390 
391  std::ostringstream output_buf;
392  std::list<std::string> symbol_names;
393 
394  octave_idx_type count = 0;
395 
396  for (;;)
397  {
398  bool global = false;
399  octave_value tc;
400 
401  std::string name;
402  std::string doc;
403 
404  switch (fmt.type ())
405  {
406  case TEXT:
407  name = read_text_data (stream, orig_fname, global, tc, count);
408  break;
409 
410  case BINARY:
411  name = read_binary_data (stream, swap, flt_fmt, orig_fname,
412  global, tc, doc);
413  break;
414 
415  case MAT_ASCII:
416  name = read_mat_ascii_data (stream, orig_fname, tc);
417  break;
418 
419  case MAT_BINARY:
420  name = read_mat_binary_data (stream, orig_fname, tc);
421  break;
422 
423 #if defined (HAVE_HDF5)
424  case HDF5:
425  name = read_hdf5_data (stream, orig_fname, global, tc, doc,
426  argv, argv_idx, argc);
427  break;
428 #endif
429 
430  case MAT5_BINARY:
431  case MAT7_BINARY:
432  name = read_mat5_binary_element (stream, orig_fname, swap,
433  global, tc);
434  break;
435 
436  default:
437  err_unrecognized_data_fmt ("load");
438  break;
439  }
440 
441  if (stream.eof () || name.empty ())
442  break;
443  else
444  {
445  if (! tc.is_defined ())
446  error ("load: unable to load variable '%s'", name.c_str ());
447 
448  if (fmt.type () == MAT_ASCII && argv_idx < argc)
449  warning ("load: loaded ASCII file '%s' -- ignoring extra args",
450  orig_fname.c_str ());
451 
452  if (fmt.type () == MAT_ASCII
453  || argv_idx == argc
454  || matches_patterns (argv, argv_idx, argc, name))
455  {
456  count++;
457  if (list_only)
458  {
459  if (verbose)
460  {
461  if (count == 1)
462  output_buf
463  << "type rows cols name\n"
464  << "==== ==== ==== ====\n";
465 
466  output_buf
467  << std::setiosflags (std::ios::left)
468  << std::setw (16) << tc.type_name ().c_str ()
469  << std::setiosflags (std::ios::right)
470  << std::setw (7) << tc.rows ()
471  << std::setw (7) << tc.columns ()
472  << " " << name << "\n";
473  }
474  else
475  symbol_names.push_back (name);
476  }
477  else
478  {
479  if (nargout == 1)
480  {
481  if (fmt.type () == MAT_ASCII)
482  retval = tc;
483  else
484  retstruct.assign (name, tc);
485  }
486  else
487  install_loaded_variable (name, tc, global, doc);
488  }
489  }
490 
491  // Only attempt to read one item from a headless text file.
492 
493  if (fmt.type () == MAT_ASCII)
494  break;
495  }
496  }
497 
498  if (list_only && count)
499  {
500  if (verbose)
501  {
502  std::string msg = output_buf.str ();
503 
504  if (nargout > 0)
505  retval = msg;
506  else
507  octave_stdout << msg;
508  }
509  else
510  {
511  if (nargout > 0)
512  retval = Cell (string_vector (symbol_names));
513  else
514  {
515  string_vector names (symbol_names);
516 
518 
519  octave_stdout << "\n";
520  }
521  }
522  }
523  else if (retstruct.nfields () != 0)
524  retval = retstruct;
525 
526  return retval;
527  }
528 
531  load_save_format& fmt, bool& append,
532  bool& save_as_floats, bool& use_zlib)
533  {
534 #if ! defined (HAVE_ZLIB)
535  octave_unused_parameter (use_zlib);
536 #endif
537 
539  int argc = argv.numel ();
540 
541  bool do_double = false;
542  bool do_tabs = false;
543 
544  for (int i = 0; i < argc; i++)
545  {
546  if (argv[i] == "-append")
547  {
548  append = true;
549  }
550  else if (argv[i] == "-ascii" || argv[i] == "-a")
551  {
552  fmt.set_type (MAT_ASCII);
553  }
554  else if (argv[i] == "-double")
555  {
556  do_double = true;
557  }
558  else if (argv[i] == "-tabs")
559  {
560  do_tabs = true;
561  }
562  else if (argv[i] == "-text" || argv[i] == "-t")
563  {
564  fmt.set_type (TEXT);
565  }
566  else if (argv[i] == "-binary" || argv[i] == "-b")
567  {
568  fmt.set_type (BINARY);
569  }
570  else if (argv[i] == "-hdf5" || argv[i] == "-h")
571  {
572 #if defined (HAVE_HDF5)
573  fmt.set_type (HDF5);
574 #else
575  err_disabled_feature ("save", "HDF5");
576 #endif
577  }
578  else if (argv[i] == "-v7.3" || argv[i] == "-V7.3" || argv[i] == "-7.3")
579  {
580  error ("save: Matlab file format -v7.3 is not yet implemented");
581  }
582 #if defined (HAVE_ZLIB)
583  else if (argv[i] == "-v7" || argv[i] == "-V7" || argv[i] == "-7"
584  || argv[i] == "-mat7-binary")
585  {
586  fmt.set_type (MAT7_BINARY);
587  }
588 #endif
589  else if (argv[i] == "-mat" || argv[i] == "-m"
590  || argv[i] == "-v6" || argv[i] == "-V6" || argv[i] == "-6"
591  || argv[i] == "-mat-binary")
592  {
593  fmt.set_type (MAT5_BINARY);
594  }
595  else if (argv[i] == "-v4" || argv[i] == "-V4" || argv[i] == "-4"
596  || argv[i] == "-mat4-binary")
597  {
598  fmt.set_type (MAT_BINARY);
599  }
600  else if (argv[i] == "-float-binary" || argv[i] == "-f")
601  {
602  fmt.set_type (BINARY);
603  save_as_floats = true;
604  }
605  else if (argv[i] == "-float-hdf5")
606  {
607 #if defined (HAVE_HDF5)
608  fmt.set_type (HDF5);
609  save_as_floats = true;
610 #else
611  err_disabled_feature ("save", "HDF5");
612 #endif
613  }
614 #if defined (HAVE_ZLIB)
615  else if (argv[i] == "-zip" || argv[i] == "-z")
616  {
617  use_zlib = true;
618  }
619 #endif
620  else if (argv[i] == "-struct")
621  {
622  retval.append (argv[i]);
623  }
624  else if (argv[i][0] == '-' && argv[i] != "-")
625  {
626  error ("save: Unrecognized option '%s'", argv[i].c_str ());
627  }
628  else
629  retval.append (argv[i]);
630  }
631 
632  if (do_double)
633  {
634  if (fmt.type () == MAT_ASCII)
636  else
637  warning (R"(save: "-double" option only has an effect with "-ascii")");
638  }
639 
640  if (do_tabs)
641  {
642  if (fmt.type () == MAT_ASCII)
644  else
645  warning (R"(save: "-tabs" option only has an effect with "-ascii")");
646  }
647 
648  return retval;
649  }
650 
652  load_save_system::parse_save_options (const std::string& arg,
653  load_save_format& fmt,
654  bool& append, bool& save_as_floats,
655  bool& use_zlib)
656  {
657  std::istringstream is (arg);
658  std::string str;
659  string_vector argv;
660 
661  while (! is.eof ())
662  {
663  is >> str;
664  argv.append (str);
665  }
666 
667  return parse_save_options (argv, fmt, append, save_as_floats, use_zlib);
668  }
669 
670  void load_save_system::save_vars (const string_vector& argv, int argv_idx,
671  int argc, std::ostream& os,
672  const load_save_format& fmt,
673  bool save_as_floats,
674  bool write_header_info)
675  {
676  if (write_header_info)
677  write_header (os, fmt);
678 
679  if (argv_idx == argc)
680  {
681  save_vars (os, "*", fmt, save_as_floats);
682  }
683  else if (argv[argv_idx] == "-struct")
684  {
685  if (++argv_idx >= argc)
686  error ("save: missing struct name");
687 
688  std::string struct_name = argv[argv_idx];
689 
690  if (! m_interpreter.is_variable (struct_name))
691  error ("save: no such variable: '%s'", struct_name.c_str ());
692 
693  octave_value struct_var = m_interpreter.varval (struct_name);
694 
695  if (! struct_var.isstruct () || struct_var.numel () != 1)
696  error ("save: '%s' is not a scalar structure", struct_name.c_str ());
697 
698  octave_scalar_map struct_var_map = struct_var.scalar_map_value ();
699 
700  ++argv_idx;
701 
702  if (argv_idx < argc)
703  {
704  for (int i = argv_idx; i < argc; i++)
705  {
706  if (! save_fields (os, struct_var_map, argv[i], fmt,
707  save_as_floats))
708  {
709  warning ("save: no such field '%s.%s'",
710  struct_name.c_str (), argv[i].c_str ());
711  }
712  }
713  }
714  else
715  save_fields (os, struct_var_map, "*", fmt, save_as_floats);
716  }
717  else
718  {
719  for (int i = argv_idx; i < argc; i++)
720  {
721  if (argv[i] == "")
722  continue; // Skip empty vars for Matlab compatibility
723  if (! save_vars (os, argv[i], fmt, save_as_floats))
724  warning ("save: no such variable '%s'", argv[i].c_str ());
725  }
726  }
727  }
728 
730  {
732  {
733  // FIXME: should choose better filename?
734 
735  const char *fname = m_octave_core_file_name.c_str ();
736 
737  message (nullptr, "attempting to save variables to '%s'...", fname);
738 
739  load_save_format fmt (BINARY);
740 
741  bool save_as_floats = false;
742 
743  bool append = false;
744 
745  bool use_zlib = false;
746 
748  fmt, append, save_as_floats,
749  use_zlib);
750 
751  std::ios::openmode mode = std::ios::out;
752 
753  // Matlab v7 files are always compressed
754  if (fmt.type () == MAT7_BINARY)
755  use_zlib = false;
756 
757  if (fmt.type () == BINARY
758 #if defined (HAVE_HDF5)
759  || fmt.type () == HDF5
760 #endif
761  || fmt.type () == MAT_BINARY
762  || fmt.type () == MAT5_BINARY
763  || fmt.type () == MAT7_BINARY)
764  mode |= std::ios::binary;
765 
766  mode |= append ? std::ios::ate : std::ios::trunc;
767 
768 #if defined (HAVE_HDF5)
769  if (fmt.type () == HDF5)
770  {
771  hdf5_ofstream file (fname, mode);
772 
773  if (file.file_id >= 0)
774  {
775  dump_octave_core (file, fname, fmt, save_as_floats);
776 
777  file.close ();
778  }
779  else
780  warning ("dump_octave_core: unable to open '%s' for writing...",
781  fname);
782  }
783  else
784 #endif
785  // don't insert any commands here! The open brace below must
786  // go with the else above!
787  {
788 #if defined (HAVE_ZLIB)
789  if (use_zlib)
790  {
791  gzofstream file (fname, mode);
792 
793  if (file)
794  {
795  dump_octave_core (file, fname, fmt, save_as_floats);
796 
797  file.close ();
798  }
799  else
800  warning ("dump_octave_core: unable to open '%s' for writing...",
801  fname);
802  }
803  else
804 #endif
805  {
806  std::ofstream file = sys::ofstream (fname, mode);
807 
808  if (file)
809  {
810  dump_octave_core (file, fname, fmt, save_as_floats);
811 
812  file.close ();
813  }
814  else
815  warning ("dump_octave_core: unable to open '%s' for writing...",
816  fname);
817  }
818  }
819  }
820  }
821 
822  void load_save_system::write_header (std::ostream& os,
823  const load_save_format& fmt)
824  {
825  switch (fmt.type ())
826  {
827  case BINARY:
828  {
830  ? "Octave-1-B" : "Octave-1-L");
831 
833 
834  char tmp = static_cast<char> (float_format_to_mopt_digit (flt_fmt));
835 
836  os.write (&tmp, 1);
837  }
838  break;
839 
840  case MAT5_BINARY:
841  case MAT7_BINARY:
842  {
843  char const *versionmagic;
844  char headertext[128];
845  sys::gmtime now;
846 
847  // ISO 8601 format date
848  const char *matlab_format = "MATLAB 5.0 MAT-file, written by Octave "
849  OCTAVE_VERSION ", %Y-%m-%d %T UTC";
850  std::string comment_string = now.strftime (matlab_format);
851 
852  size_t len = std::min (comment_string.length (), static_cast<size_t> (124));
853  memset (headertext, ' ', 124);
854  memcpy (headertext, comment_string.data (), len);
855 
856  // The first pair of bytes give the version of the MAT file
857  // format. The second pair of bytes form a magic number which
858  // signals a MAT file. MAT file data are always written in
859  // native byte order. The order of the bytes in the second
860  // pair indicates whether the file was written by a big- or
861  // little-endian machine. However, the version number is
862  // written in the *opposite* byte order from everything else!
864  versionmagic = "\x01\x00\x4d\x49"; // this machine is big endian
865  else
866  versionmagic = "\x00\x01\x49\x4d"; // this machine is little endian
867 
868  memcpy (headertext+124, versionmagic, 4);
869  os.write (headertext, 128);
870  }
871 
872  break;
873 
874 #if defined (HAVE_HDF5)
875  case HDF5:
876 #endif
877  case TEXT:
878  {
879  sys::localtime now;
880 
881  std::string comment_string = now.strftime (m_save_header_format_string);
882 
883  if (! comment_string.empty ())
884  {
885 #if defined (HAVE_HDF5)
886  if (fmt.type () == HDF5)
887  {
888  hdf5_ofstream& hs = dynamic_cast<hdf5_ofstream&> (os);
889  H5Gset_comment (hs.file_id, "/", comment_string.c_str ());
890  }
891  else
892 #endif
893  os << comment_string << "\n";
894  }
895  }
896  break;
897 
898  default:
899  break;
900  }
901  }
902 
903  // Save variables with names matching PATTERN on stream OS in the
904  // format specified by FMT.
905 
906  size_t load_save_system::save_vars (std::ostream& os,
907  const std::string& pattern,
908  const load_save_format& fmt,
909  bool save_as_floats)
910  {
912 
913  symbol_info_list syminfo_list = tw.glob_symbol_info (pattern);
914 
915  size_t saved = 0;
916 
917  for (const auto& syminfo : syminfo_list)
918  {
919  do_save (os, syminfo, fmt, save_as_floats);
920 
921  saved++;
922  }
923 
924  return saved;
925  }
926 
927  void load_save_system::do_save (std::ostream& os, const octave_value& tc,
928  const std::string& name,
929  const std::string& help,
930  bool global, const load_save_format& fmt,
931  bool save_as_floats)
932  {
933  switch (fmt.type ())
934  {
935  case TEXT:
936  save_text_data (os, tc, name, global, 0);
937  break;
938 
939  case BINARY:
940  save_binary_data (os, tc, name, help, global, save_as_floats);
941  break;
942 
943  case MAT_ASCII:
944  if (! save_mat_ascii_data (os, tc,
945  fmt.options () & MAT_ASCII_LONG ? 16 : 8,
946  fmt.options () & MAT_ASCII_TABS))
947  warning ("save: unable to save %s in ASCII format", name.c_str ());
948  break;
949 
950  case MAT_BINARY:
951  save_mat_binary_data (os, tc, name);
952  break;
953 
954 #if defined (HAVE_HDF5)
955  case HDF5:
956  save_hdf5_data (os, tc, name, help, global, save_as_floats);
957  break;
958 #endif
959 
960  case MAT5_BINARY:
961  save_mat5_binary_element (os, tc, name, global, false, save_as_floats);
962  break;
963 
964  case MAT7_BINARY:
965  save_mat5_binary_element (os, tc, name, global, true, save_as_floats);
966  break;
967 
968  default:
969  err_unrecognized_data_fmt ("save");
970  break;
971  }
972  }
973 
974  // Save the info from SR on stream OS in the format specified by FMT.
975 
976  void load_save_system::do_save (std::ostream& os,
977  const symbol_info& syminfo,
978  const load_save_format& fmt,
979  bool save_as_floats)
980  {
981  octave_value val = syminfo.value ();
982 
983  if (val.is_defined ())
984  {
985  std::string name = syminfo.name ();
986  std::string help;
987  bool global = syminfo.is_global ();
988 
989  do_save (os, val, name, help, global, fmt, save_as_floats);
990  }
991  }
992 
993  // save fields of a scalar structure STR matching PATTERN on stream OS
994  // in the format specified by FMT.
995 
996  size_t load_save_system::save_fields (std::ostream& os,
997  const octave_scalar_map& m,
998  const std::string& pattern,
999  const load_save_format& fmt,
1000  bool save_as_floats)
1001  {
1002  glob_match pat (pattern);
1003 
1004  size_t saved = 0;
1005 
1006  for (auto it = m.begin (); it != m.end (); it++)
1007  {
1008  std::string empty_str;
1009 
1010  if (pat.match (m.key (it)))
1011  {
1012  do_save (os, m.contents (it), m.key (it), empty_str,
1013  0, fmt, save_as_floats);
1014 
1015  saved++;
1016  }
1017  }
1018 
1019  return saved;
1020  }
1021 
1022  void load_save_system::dump_octave_core (std::ostream& os,
1023  const char *fname,
1024  const load_save_format& fmt,
1025  bool save_as_floats)
1026  {
1027  write_header (os, fmt);
1028 
1030 
1031  symbol_info_list syminfo_list = tw.top_scope_symbol_info ();
1032 
1033  double save_mem_size = 0;
1034 
1035  for (const auto& syminfo : syminfo_list)
1036  {
1037  octave_value val = syminfo.value ();
1038 
1039  std::string name = syminfo.name ();
1040  std::string help;
1041  bool global = syminfo.is_global ();
1042 
1043  double val_size = val.byte_size () / 1024;
1044 
1045  // FIXME: maybe we should try to throw out the largest first...
1046 
1047  if (m_octave_core_file_limit < 0
1048  || save_mem_size + val_size < m_octave_core_file_limit)
1049  {
1050  save_mem_size += val_size;
1051 
1052  do_save (os, val, name, help, global, fmt, save_as_floats);
1053  }
1054  }
1055 
1056  message (nullptr, "save to '%s' complete", fname);
1057  }
1058 
1059  // Install a variable with name NAME and the value VAL in the
1060  // symbol table. If GLOBAL is TRUE, make the variable global.
1061 
1063  const octave_value& val,
1064  bool global,
1065  const std::string& /*doc*/)
1066  {
1067  m_interpreter.install_variable (name, val, global);
1068  }
1069 
1071  {
1072  return
1073  (std::string ("# Created by Octave " OCTAVE_VERSION
1074  ", %a %b %d %H:%M:%S %Y %Z <")
1076  + '@'
1078  + '>');
1079  }
1080 
1083  const std::string& filename)
1084  {
1086 
1087  mach_info::float_format flt_fmt
1089 
1090  bool swap = false;
1091 
1092  if (read_binary_file_header (file, swap, flt_fmt, true) == 0)
1093  retval = BINARY;
1094  else
1095  {
1096  file.clear ();
1097  file.seekg (0, std::ios::beg);
1098 
1099  int32_t mopt, nr, nc, imag, len;
1100 
1101  int err = read_mat_file_header (file, swap, mopt, nr, nc, imag, len,
1102  true);
1103 
1104  if (! err)
1105  retval = MAT_BINARY;
1106  else
1107  {
1108  file.clear ();
1109  file.seekg (0, std::ios::beg);
1110 
1111  err = read_mat5_binary_file_header (file, swap, true, filename);
1112 
1113  if (! err)
1114  {
1115  file.clear ();
1116  file.seekg (0, std::ios::beg);
1117  retval = MAT5_BINARY;
1118  }
1119  else
1120  {
1121  file.clear ();
1122  file.seekg (0, std::ios::beg);
1123 
1124  std::string name_val = extract_keyword (file, "name");
1125  std::string type_val = extract_keyword (file, "type");
1126 
1127  if (name_val.empty () != true && type_val.empty () != true)
1128  retval = TEXT;
1129  else
1130  {
1131  file.clear ();
1132  file.seekg (0, std::ios::beg);
1133 
1134  // FIXME: looks_like_mat_ascii_file does not check
1135  // to see whether the file contains numbers. It
1136  // just skips comments and checks for the same
1137  // number of words on each line. We may need a
1138  // better check here. The best way to do that might
1139  // be just to try to read the file and see if it
1140  // works.
1141 
1142  if (looks_like_mat_ascii_file (file, filename))
1143  retval = MAT_ASCII;
1144  }
1145  }
1146  }
1147  }
1148 
1149  return retval;
1150  }
1151 
1153  load_save_system::load (const octave_value_list& args, int nargout)
1154  {
1156 
1157  int argc = args.length () + 1;
1158 
1159  string_vector argv = args.make_argv ("load");
1160 
1161  int i = 1;
1162  std::string orig_fname = "";
1163 
1164  // Function called with Matlab-style ["filename", options] syntax
1165  if (argc > 1 && ! argv[1].empty () && argv[1].at (0) != '-')
1166  {
1167  orig_fname = argv[1];
1168  i++;
1169  }
1170 
1171  // It isn't necessary to have the default load format stored in a
1172  // user preference variable since we can determine the type of file
1173  // as we are reading.
1174 
1176 
1177  bool list_only = false;
1178  bool verbose = false;
1179 
1180  for (; i < argc; i++)
1181  {
1182  if (argv[i] == "-text" || argv[i] == "-t")
1183  {
1184  format = TEXT;
1185  }
1186  else if (argv[i] == "-binary" || argv[i] == "-b")
1187  {
1188  format = BINARY;
1189  }
1190  else if (argv[i] == "-hdf5" || argv[i] == "-h")
1191  {
1192 #if defined (HAVE_HDF5)
1193  format = HDF5;
1194 #else
1195  err_disabled_feature ("load", "HDF5");
1196 #endif
1197  }
1198  else if (argv[i] == "-ascii" || argv[i] == "-a")
1199  {
1200  format = MAT_ASCII;
1201  }
1202  else if (argv[i] == "-v7.3" || argv[i] == "-V7.3" || argv[i] == "-7.3")
1203  {
1204  error ("load: Matlab file format -v7.3 is not yet implemented");
1205  }
1206  else if (argv[i] == "-v7" || argv[i] == "-V7" || argv[i] == "-7"
1207  || argv[i] == "-mat7-binary")
1208  {
1209  format = MAT7_BINARY;
1210  }
1211  else if (argv[i] == "-mat" || argv[i] == "-m"
1212  || argv[i] == "-v6" || argv[i] == "-V6" || argv[i] == "-6"
1213  || argv[i] == "-mat-binary")
1214  {
1215  format = MAT5_BINARY;
1216  }
1217  else if (argv[i] == "-v4" || argv[i] == "-V4" || argv[i] == "-4"
1218  || argv[i] == "-mat4-binary")
1219  {
1220  format = MAT_BINARY;
1221  }
1222  else if (argv[i] == "-force" || argv[i] == "-f")
1223  {
1224  // Silently ignore this
1225  // warning ("load: -force ignored");
1226  }
1227  else if (argv[i] == "-import" || argv[i] == "-i")
1228  {
1229  warning ("load: -import ignored");
1230  }
1231  else if (argv[i] == "-list" || argv[i] == "-l")
1232  {
1233  list_only = true;
1234  }
1235  else if (argv[i] == "-verbose" || argv[i] == "-v")
1236  {
1237  verbose = true;
1238  }
1239  else
1240  break;
1241  }
1242 
1243  if (orig_fname == "")
1244  {
1245  if (i == argc)
1246  print_usage ();
1247 
1248  orig_fname = argv[i];
1249  }
1250  else
1251  i--;
1252 
1254 
1255  bool swap = false;
1256 
1257  if (orig_fname == "-")
1258  {
1259  i++;
1260 
1261 #if defined (HAVE_HDF5)
1262  if (format.type () == HDF5)
1263  error ("load: cannot read HDF5 format from stdin");
1264  else
1265 #endif
1266  if (format.type () != UNKNOWN)
1267  {
1268  // FIXME: if we have already seen EOF on a previous call,
1269  // how do we fix up the state of std::cin so that we can get
1270  // additional input? I'm afraid that we can't fix this
1271  // using std::cin only.
1272 
1273  retval = load_vars (std::cin, orig_fname, format, flt_fmt,
1274  list_only, swap, verbose, argv, i,
1275  argc, nargout);
1276  }
1277  else
1278  error ("load: must specify file format if reading from stdin");
1279  }
1280  else
1281  {
1282  std::string fname = sys::file_ops::tilde_expand (orig_fname);
1283 
1284  fname = find_file_to_load (fname, orig_fname);
1285 
1286  bool use_zlib = false;
1287 
1288  if (format.type () == UNKNOWN)
1289  format = get_file_format (fname, orig_fname, use_zlib);
1290 
1291 #if defined (HAVE_HDF5)
1292  if (format.type () == HDF5)
1293  {
1294  i++;
1295 
1296  hdf5_ifstream hdf5_file (fname.c_str ());
1297 
1298  if (hdf5_file.file_id < 0)
1299  err_file_open ("load", orig_fname);
1300 
1301  retval = load_vars (hdf5_file, orig_fname, format, flt_fmt,
1302  list_only, swap, verbose, argv, i,
1303  argc, nargout);
1304 
1305  hdf5_file.close ();
1306  }
1307  else
1308 #endif
1309  // don't insert any statements here; the "else" above has to
1310  // go with the "if" below!!!!!
1311  if (format.type () != UNKNOWN)
1312  {
1313  i++;
1314 
1315  // Always open in binary mode and handle various
1316  // line-endings explicitly.
1317  std::ios::openmode mode = std::ios::in | std::ios::binary;
1318 
1319 #if defined (HAVE_ZLIB)
1320  if (use_zlib)
1321  {
1322  gzifstream file (fname.c_str (), mode);
1323 
1324  if (! file)
1325  err_file_open ("load", orig_fname);
1326 
1327  if (format.type () == BINARY)
1328  {
1329  if (read_binary_file_header (file, swap, flt_fmt) < 0)
1330  {
1331  if (file) file.close ();
1332  return retval;
1333  }
1334  }
1335  else if (format.type () == MAT5_BINARY
1336  || format.type () == MAT7_BINARY)
1337  {
1338  if (read_mat5_binary_file_header (file, swap, false,
1339  orig_fname) < 0)
1340  {
1341  if (file) file.close ();
1342  return retval;
1343  }
1344  }
1345 
1346  retval = load_vars (file, orig_fname, format, flt_fmt,
1347  list_only, swap, verbose, argv, i,
1348  argc, nargout);
1349 
1350  file.close ();
1351  }
1352  else
1353 #endif
1354  {
1355  std::ifstream file = sys::ifstream (fname.c_str (), mode);
1356 
1357  if (! file)
1358  error ("load: unable to open input file '%s'",
1359  orig_fname.c_str ());
1360 
1361  if (format.type () == BINARY)
1362  {
1363  if (read_binary_file_header (file, swap, flt_fmt) < 0)
1364  {
1365  if (file) file.close ();
1366  return retval;
1367  }
1368  }
1369  else if (format.type () == MAT5_BINARY
1370  || format.type () == MAT7_BINARY)
1371  {
1372  if (read_mat5_binary_file_header (file, swap, false,
1373  orig_fname) < 0)
1374  {
1375  if (file) file.close ();
1376  return retval;
1377  }
1378  }
1379 
1380  retval = load_vars (file, orig_fname, format, flt_fmt,
1381  list_only, swap, verbose, argv, i,
1382  argc, nargout);
1383 
1384  file.close ();
1385  }
1386  }
1387  else
1388  error ("load: unable to determine file format of '%s'",
1389  orig_fname.c_str ());
1390 
1391  }
1392 
1393  return retval;
1394  }
1395 
1397  load_save_system::save (const octave_value_list& args, int nargout)
1398  {
1399  // Here is where we would get the default save format if it were
1400  // stored in a user preference variable.
1402  bool save_as_floats = false;
1403  bool append = false;
1404  bool use_zlib = false;
1405 
1406 
1407  // get default options
1409  save_as_floats, use_zlib);
1410 
1411  // override from command line
1412  string_vector argv = args.make_argv ();
1413 
1414  argv = parse_save_options (argv, format, append, save_as_floats, use_zlib);
1415 
1416  int argc = argv.numel ();
1417  int i = 0;
1418 
1419  if (i == argc)
1420  print_usage ();
1421 
1422  if (save_as_floats && format.type () == TEXT)
1423  error ("save: cannot specify both -text and -float-binary");
1424 
1426 
1427  if (argv[i] == "-")
1428  {
1429  i++;
1430 
1431 #if defined (HAVE_HDF5)
1432  if (format.type () == HDF5)
1433  error ("save: cannot write HDF5 format to stdout");
1434  else
1435 #endif
1436  // don't insert any commands here! the brace below must go
1437  // with the "else" above!
1438  {
1439  if (append)
1440  warning ("save: ignoring -append option for output to stdout");
1441 
1442  if (nargout == 0)
1443  save_vars (argv, i, argc, octave_stdout, format,
1444  save_as_floats, true);
1445  else
1446  {
1447  std::ostringstream output_buf;
1448  save_vars (argv, i, argc, output_buf, format,
1449  save_as_floats, true);
1450  retval = octave_value (output_buf.str());
1451  }
1452  }
1453  }
1454 
1455  // Guard against things like 'save a*', which are probably mistakes...
1456 
1457  else if (i == argc - 1 && glob_pattern_p (argv[i]))
1458  print_usage ();
1459  else
1460  {
1461  std::string fname = sys::file_ops::tilde_expand (argv[i]);
1462 
1463  i++;
1464 
1465  // Matlab v7 files are always compressed
1466  if (format.type () == MAT7_BINARY)
1467  use_zlib = false;
1468 
1469  std::ios::openmode mode
1470  = (append ? (std::ios::app | std::ios::ate) : std::ios::out);
1471 
1472  // Always open in binary mode to save line endings as is.
1473  mode |= std::ios::binary;
1474 
1475 #if defined (HAVE_HDF5)
1476  if (format.type () == HDF5)
1477  {
1478  // FIXME: It should be possible to append to HDF5 files.
1479  if (append)
1480  error ("save: appending to HDF5 files is not implemented");
1481 
1482  std::string ascii_fname = sys::get_ASCII_filename (fname);
1483 
1484  bool write_header_info
1485  = ! (append && H5Fis_hdf5 (ascii_fname.c_str ()) > 0);
1486 
1487  hdf5_ofstream hdf5_file (fname.c_str (), mode);
1488 
1489  if (hdf5_file.file_id == -1)
1490  err_file_open ("save", fname);
1491 
1492  save_vars (argv, i, argc, hdf5_file, format, save_as_floats,
1493  write_header_info);
1494 
1495  hdf5_file.close ();
1496  }
1497  else
1498 #endif
1499  // don't insert any statements here! The brace below must go
1500  // with the "else" above!
1501  {
1502 #if defined (HAVE_ZLIB)
1503  if (use_zlib)
1504  {
1505  gzofstream file (fname.c_str (), mode);
1506 
1507  if (! file)
1508  err_file_open ("save", fname);
1509 
1510  bool write_header_info = ! file.tellp ();
1511 
1512  save_vars (argv, i, argc, file, format, save_as_floats,
1513  write_header_info);
1514 
1515  file.close ();
1516  }
1517  else
1518 #endif
1519  {
1520  std::ofstream file = sys::ofstream (fname.c_str (), mode);
1521 
1522  if (! file)
1523  err_file_open ("save", fname);
1524 
1525  bool write_header_info = ! file.tellp ();
1526 
1527  save_vars (argv, i, argc, file, format, save_as_floats,
1528  write_header_info);
1529 
1530  file.close ();
1531  }
1532  }
1533  }
1534 
1535  return retval;
1536  }
1537 }
1538 
1539 void
1541 {
1542  octave::load_save_system& load_save_sys
1543  = octave::__get_load_save_system__ ("dump_octave_core");
1544 
1545  load_save_sys.dump_octave_core ();
1546 }
1547 
1548 DEFMETHOD (load, interp, args, nargout,
1549  doc: /* -*- texinfo -*-
1550 @deftypefn {} {} load file
1551 @deftypefnx {} {} load options file
1552 @deftypefnx {} {} load options file v1 v2 @dots{}
1553 @deftypefnx {} {S =} load ("options", "file", "v1", "v2", @dots{})
1554 @deftypefnx {} {} load file options
1555 @deftypefnx {} {} load file options v1 v2 @dots{}
1556 @deftypefnx {} {S =} load ("file", "options", "v1", "v2", @dots{})
1557 Load the named variables @var{v1}, @var{v2}, @dots{}, from the file
1558 @var{file}.
1559 
1560 If no variables are specified then all variables found in the
1561 file will be loaded. As with @code{save}, the list of variables to extract
1562 can be full names or use a pattern syntax. The format of the file is
1563 automatically detected but may be overridden by supplying the appropriate
1564 option.
1565 
1566 If load is invoked using the functional form
1567 
1568 @example
1569 load ("-option1", @dots{}, "file", "v1", @dots{})
1570 @end example
1571 
1572 @noindent
1573 then the @var{options}, @var{file}, and variable name arguments
1574 (@var{v1}, @dots{}) must be specified as character strings.
1575 
1576 If a variable that is not marked as global is loaded from a file when a
1577 global symbol with the same name already exists, it is loaded in the
1578 global symbol table. Also, if a variable is marked as global in a file
1579 and a local symbol exists, the local symbol is moved to the global
1580 symbol table and given the value from the file.
1581 
1582 If invoked with a single output argument, Octave returns data instead
1583 of inserting variables in the symbol table. If the data file contains
1584 only numbers (TAB- or space-delimited columns), a matrix of values is
1585 returned. Otherwise, @code{load} returns a structure with members
1586  corresponding to the names of the variables in the file.
1587 
1588 The @code{load} command can read data stored in Octave's text and
1589 binary formats, and @sc{matlab}'s binary format. If compiled with zlib
1590 support, it can also load gzip-compressed files. It will automatically
1591 detect the type of file and do conversion from different floating point
1592 formats (currently only IEEE big and little endian, though other formats
1593 may be added in the future).
1594 
1595 Valid options for @code{load} are listed in the following table.
1596 
1597 @table @code
1598 @item -force
1599 This option is accepted for backward compatibility but is ignored.
1600 Octave now overwrites variables currently in memory with
1601 those of the same name found in the file.
1602 
1603 @item -ascii
1604 Force Octave to assume the file contains columns of numbers in text format
1605 without any header or other information. Data in the file will be loaded
1606 as a single numeric matrix with the name of the variable derived from the
1607 name of the file.
1608 
1609 @item -binary
1610 Force Octave to assume the file is in Octave's binary format.
1611 
1612 @item -hdf5
1613 Force Octave to assume the file is in @sc{hdf5} format.
1614 (@sc{hdf5} is a free, portable binary format developed by the National
1615 Center for Supercomputing Applications at the University of Illinois.)
1616 Note that Octave can only read @sc{hdf5} files that were created by itself with
1617 @code{save}. This format is only available if Octave was built with a link to
1618 the @sc{hdf5} libraries.
1619 
1620 @item -import
1621 This option is accepted for backward compatibility but is ignored.
1622 Octave can now support multi-dimensional HDF data and automatically
1623 modifies variable names if they are invalid Octave identifiers.
1624 
1625 @item -text
1626 Force Octave to assume the file is in Octave's text format.
1627 
1628 @item -v7.3
1629 @itemx -V7.3
1630 @itemx -7.3
1631 Octave does @strong{not} yet implement @sc{matlab}'s v7.3 binary data format.
1632 
1633 @item -v7
1634 @itemx -V7
1635 @itemx -7
1636 @itemx -mat7-binary
1637 Force Octave to assume the file is in @sc{matlab}'s version 7 binary format.
1638 
1639 @item -v6
1640 @itemx -V6
1641 @itemx -6
1642 @itemx -mat
1643 @itemx -mat-binary
1644 Force Octave to assume the file is in @sc{matlab}'s version 6 binary format.
1645 
1646 @item -v4
1647 @itemx -V4
1648 @itemx -4
1649 @itemx -mat4-binary
1650 Force Octave to assume the file is in @sc{matlab}'s version 4 binary format.
1651 
1652 @end table
1653 @seealso{save, dlmwrite, csvwrite, fwrite}
1654 @end deftypefn */)
1655 {
1656  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
1657 
1658  return load_save_sys.load (args, nargout);
1659 }
1660 
1661 DEFMETHOD (save, interp, args, nargout,
1662  doc: /* -*- texinfo -*-
1663 @deftypefn {} {} save file
1664 @deftypefnx {} {} save options file
1665 @deftypefnx {} {} save options file @var{v1} @var{v2} @dots{}
1666 @deftypefnx {} {} save options file -struct @var{STRUCT}
1667 @deftypefnx {} {} save options file -struct @var{STRUCT} @var{f1} @var{f2} @dots{}
1668 @deftypefnx {} {} save - @var{v1} @var{v2} @dots{}
1669 @deftypefnx {} {@var{str} =} save ("-", @qcode{"@var{v1}"}, @qcode{"@var{v2}"}, @dots{})
1670 Save the named variables @var{v1}, @var{v2}, @dots{}, in the file @var{file}.
1671 
1672 The special filename @samp{-} may be used to return the content of the
1673 variables as a string. If no variable names are listed, Octave saves all the
1674 variables in the current scope. Otherwise, full variable names or pattern
1675 syntax can be used to specify the variables to save. If the @option{-struct}
1676 modifier is used then the fields of the @strong{scalar} struct are saved as if
1677 they were variables with the corresponding field names. The @option{-struct}
1678 option can be combined with specific field names @var{f1}, @var{f2}, @dots{} to
1679 write only certain fields to the file.
1680 
1681 Valid options for the @code{save} command are listed in the following table.
1682 Options that modify the output format override the format specified by
1683 @code{save_default_options}.
1684 
1685 If save is invoked using the functional form
1686 
1687 @example
1688 save ("-option1", @dots{}, "file", "v1", @dots{})
1689 @end example
1690 
1691 @noindent
1692 then the @var{options}, @var{file}, and variable name arguments (@var{v1},
1693 @dots{}) must be specified as character strings.
1694 
1695 If called with a filename of @qcode{"-"}, write the output to stdout if nargout
1696 is 0, otherwise return the output in a character string.
1697 
1698 @table @code
1699 @item -append
1700 Append to the destination instead of overwriting.
1701 
1702 @item -ascii
1703 Save a matrix in a text file without a header or any other information. The
1704 matrix must be 2-D and only the real part of any complex value is written to
1705 the file. Numbers are stored in single-precision format and separated by
1706 spaces. Additional options for the @option{-ascii} format are
1707 
1708 @table @code
1709 @item -double
1710 Store numbers in double-precision format.
1711 
1712 @item -tabs
1713 Separate numbers with tabs.
1714 @end table
1715 
1716 @item -binary
1717 Save the data in Octave's binary data format.
1718 
1719 @item -float-binary
1720 Save the data in Octave's binary data format but using only single precision.
1721 Use this format @strong{only} if you know that all the values to be saved can
1722 be represented in single precision.
1723 
1724 @item -hdf5
1725 Save the data in @sc{hdf5} format.
1726 (HDF5 is a free, portable, binary format developed by the National Center for
1727 Supercomputing Applications at the University of Illinois.) This format is only
1728 available if Octave was built with a link to the @sc{hdf5} libraries.
1729 
1730 @item -float-hdf5
1731 Save the data in @sc{hdf5} format but using only single precision. Use this
1732 format @strong{only} if you know that all the values to be saved can be
1733 represented in single precision.
1734 
1735 @item -text
1736 Save the data in Octave's text data format. (default)
1737 
1738 @item -v7.3
1739 @itemx -V7.3
1740 @itemx -7.3
1741 Octave does @strong{not} yet implement @sc{matlab}'s v7.3 binary data format.
1742 
1743 @item -v7
1744 @itemx -V7
1745 @itemx -7
1746 @itemx -mat7-binary
1747 Save the data in @sc{matlab}'s v7 binary data format.
1748 
1749 @item -v6
1750 @itemx -V6
1751 @itemx -6
1752 @itemx -mat
1753 @itemx -mat-binary
1754 Save the data in @sc{matlab}'s v6 binary data format.
1755 
1756 @item -v4
1757 @itemx -V4
1758 @itemx -4
1759 @itemx -mat4-binary
1760 Save the data in @sc{matlab}'s v4 binary data format.
1761 
1762 @item -zip
1763 @itemx -z
1764 Use the gzip algorithm to compress the file. This works on files that are
1765 compressed with gzip outside of Octave, and gzip can also be used to convert
1766 the files for backward compatibility. This option is only available if Octave
1767 was built with a link to the zlib libraries.
1768 @end table
1769 
1770 The list of variables to save may use wildcard patterns containing the
1771 following special characters:
1772 
1773 @table @code
1774 @item ?
1775 Match any single character.
1776 
1777 @item *
1778 Match zero or more characters.
1779 
1780 @item [ @var{list} ]
1781 Match the list of characters specified by @var{list}. If the first character
1782 is @code{!} or @code{^}, match all characters except those specified by
1783 @var{list}. For example, the pattern @code{[a-zA-Z]} will match all lower and
1784 uppercase alphabetic characters.
1785 
1786 Wildcards may also be used in the field name specifications when using the
1787 @option{-struct} modifier (but not in the struct name itself).
1788 
1789 @end table
1790 
1791 Except when using the @sc{matlab} binary data file format or the @samp{-ascii}
1792 format, saving global variables also saves the global status of the variable.
1793 If the variable is restored at a later time using @samp{load}, it will be
1794 restored as a global variable.
1795 
1796 Example:
1797 
1798 The command
1799 
1800 @example
1801 save -binary data a b*
1802 @end example
1803 
1804 @noindent
1805 saves the variable @samp{a} and all variables beginning with @samp{b} to the
1806 file @file{data} in Octave's binary format.
1807 @seealso{load, save_default_options, save_header_format_string, save_precision, dlmread, csvread, fread}
1808 @end deftypefn */)
1809 {
1810  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
1811 
1812  return load_save_sys.save (args, nargout);
1813 }
1814 
1815 DEFMETHOD (crash_dumps_octave_core, interp, args, nargout,
1816  doc: /* -*- texinfo -*-
1817 @deftypefn {} {@var{val} =} crash_dumps_octave_core ()
1818 @deftypefnx {} {@var{old_val} =} crash_dumps_octave_core (@var{new_val})
1819 @deftypefnx {} {} crash_dumps_octave_core (@var{new_val}, "local")
1820 Query or set the internal variable that controls whether Octave tries
1821 to save all current variables to the file @file{octave-workspace} if it
1822 crashes or receives a hangup, terminate or similar signal.
1823 
1824 When called from inside a function with the @qcode{"local"} option, the
1825 variable is changed locally for the function and any subroutines it calls.
1826 The original variable value is restored when exiting the function.
1827 @seealso{octave_core_file_limit, octave_core_file_name, octave_core_file_options}
1828 @end deftypefn */)
1829 {
1830  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
1831 
1832  return load_save_sys.crash_dumps_octave_core (args, nargout);
1833 }
1834 
1835 DEFMETHOD (save_default_options, interp, args, nargout,
1836  doc: /* -*- texinfo -*-
1837 @deftypefn {} {@var{val} =} save_default_options ()
1838 @deftypefnx {} {@var{old_val} =} save_default_options (@var{new_val})
1839 @deftypefnx {} {} save_default_options (@var{new_val}, "local")
1840 Query or set the internal variable that specifies the default options
1841 for the @code{save} command, and defines the default format.
1842 
1843 The default value is @qcode{"-text"} (Octave's own text-based file format).
1844 See the documentation of the @code{save} command for other choices.
1845 
1846 When called from inside a function with the @qcode{"local"} option, the
1847 variable is changed locally for the function and any subroutines it calls.
1848 The original variable value is restored when exiting the function.
1849 @seealso{save, save_header_format_string, save_precision}
1850 @end deftypefn */)
1851 {
1852  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
1853 
1854  return load_save_sys.save_default_options (args, nargout);
1855 }
1856 
1857 DEFMETHOD (octave_core_file_limit, interp, args, nargout,
1858  doc: /* -*- texinfo -*-
1859 @deftypefn {} {@var{val} =} octave_core_file_limit ()
1860 @deftypefnx {} {@var{old_val} =} octave_core_file_limit (@var{new_val})
1861 @deftypefnx {} {} octave_core_file_limit (@var{new_val}, "local")
1862 Query or set the internal variable that specifies the maximum amount of memory
1863 that Octave will save when writing a crash dump file.
1864 
1865 The limit is measured in kilobytes and is applied to the top-level workspace.
1866 The name of the crash dump file is specified by
1867 @var{octave_core_file_name}.
1868 
1869 If @var{octave_core_file_options} flags specify a binary format, then
1870 @var{octave_core_file_limit} will be approximately the maximum size of the
1871 file. If a text file format is used, then the file could be much larger than
1872 the limit. The default value is -1 (unlimited).
1873 
1874 When called from inside a function with the @qcode{"local"} option, the
1875 variable is changed locally for the function and any subroutines it calls.
1876 The original variable value is restored when exiting the function.
1877 @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_options}
1878 @end deftypefn */)
1879 {
1880  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
1881 
1882  return load_save_sys.octave_core_file_limit (args, nargout);
1883 }
1884 
1885 DEFMETHOD (octave_core_file_name, interp, args, nargout,
1886  doc: /* -*- texinfo -*-
1887 @deftypefn {} {@var{val} =} octave_core_file_name ()
1888 @deftypefnx {} {@var{old_val} =} octave_core_file_name (@var{new_val})
1889 @deftypefnx {} {} octave_core_file_name (@var{new_val}, "local")
1890 Query or set the internal variable that specifies the name of the file
1891 used for saving data from the top-level workspace if Octave aborts.
1892 
1893 The default value is @qcode{"octave-workspace"}
1894 
1895 When called from inside a function with the @qcode{"local"} option, the
1896 variable is changed locally for the function and any subroutines it calls.
1897 The original variable value is restored when exiting the function.
1898 @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_options}
1899 @end deftypefn */)
1900 {
1901  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
1902 
1903  return load_save_sys.octave_core_file_name (args, nargout);
1904 }
1905 
1906 DEFMETHOD (octave_core_file_options, interp, args, nargout,
1907  doc: /* -*- texinfo -*-
1908 @deftypefn {} {@var{val} =} octave_core_file_options ()
1909 @deftypefnx {} {@var{old_val} =} octave_core_file_options (@var{new_val})
1910 @deftypefnx {} {} octave_core_file_options (@var{new_val}, "local")
1911 Query or set the internal variable that specifies the options used for
1912 saving the workspace data if Octave aborts.
1913 
1914 The value of @code{octave_core_file_options} should follow the same format
1915 as the options for the @code{save} function. The default value is Octave's
1916 binary format.
1917 
1918 When called from inside a function with the @qcode{"local"} option, the
1919 variable is changed locally for the function and any subroutines it calls.
1920 The original variable value is restored when exiting the function.
1921 @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_limit}
1922 @end deftypefn */)
1923 {
1924  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
1925 
1926  return load_save_sys.octave_core_file_options (args, nargout);
1927 }
1928 
1929 DEFMETHOD (save_header_format_string, interp, args, nargout,
1930  doc: /* -*- texinfo -*-
1931 @deftypefn {} {@var{val} =} save_header_format_string ()
1932 @deftypefnx {} {@var{old_val} =} save_header_format_string (@var{new_val})
1933 @deftypefnx {} {} save_header_format_string (@var{new_val}, "local")
1934 Query or set the internal variable that specifies the format string used for
1935 the comment line written at the beginning of text-format data files saved by
1936 Octave.
1937 
1938 The format string is passed to @code{strftime} and must begin with the
1939 character @samp{#} and contain no newline characters. If the value of
1940 @code{save_header_format_string} is the empty string, the header comment is
1941 omitted from text-format data files. The default value is
1942 @c Set example in small font to prevent overfull line
1943 
1944 @smallexample
1945 "# Created by Octave VERSION, %a %b %d %H:%M:%S %Y %Z <USER@@HOST>"
1946 @end smallexample
1947 
1948 When called from inside a function with the @qcode{"local"} option, the
1949 variable is changed locally for the function and any subroutines it calls.
1950 The original variable value is restored when exiting the function.
1951 @seealso{strftime, save_default_options}
1952 @end deftypefn */)
1953 {
1954  octave::load_save_system& load_save_sys = interp.get_load_save_system ();
1955 
1956  return load_save_sys.save_header_format_string (args, nargout);
1957 }
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
Definition: Cell.h:43
bool match(const std::string &str) const
Definition: glob-match.cc:35
Gzipped file input stream class.
Definition: zfstream.h:282
void close()
Close gzipped file.
Definition: zfstream.cc:565
Gzipped file output stream class.
Definition: zfstream.h:369
void close()
Close gzipped file.
Definition: zfstream.cc:614
octave_hdf5_id file_id
Definition: ls-hdf5.h:47
void close(void)
Definition: ls-hdf5.cc:103
bool is_variable(const std::string &name) const
octave_value varval(const std::string &name) const
void install_variable(const std::string &name, const octave_value &value, bool global)
tree_evaluator & get_evaluator(void)
load_save_system::format_type type(void) const
Definition: load-save.h:277
void set_option(load_save_system::format_options option)
Definition: load-save.h:279
void set_type(load_save_system::format_type type)
Definition: load-save.h:275
int options(void) const
Definition: load-save.h:284
octave_value crash_dumps_octave_core(const octave_value_list &args, int nargout)
Definition: load-save.cc:281
void write_header(std::ostream &os, const load_save_format &fmt)
Definition: load-save.cc:822
std::string m_octave_core_file_name
Definition: load-save.h:214
octave_value_list load(const octave_value_list &args=octave_value_list(), int nargout=0)
Definition: load-save.cc:1153
static load_save_format get_file_format(const std::string &fname, const std::string &orig_fname, bool &use_zlib, bool quiet=false)
Definition: load-save.cc:329
octave_value octave_core_file_limit(const octave_value_list &args, int nargout)
Definition: load-save.cc:289
octave_value octave_core_file_name(const octave_value_list &args, int nargout)
Definition: load-save.cc:297
octave_value save_default_options(const octave_value_list &args, int nargout)
Definition: load-save.cc:305
std::string save_default_options(void) const
Definition: load-save.h:126
std::string octave_core_file_options(void) const
Definition: load-save.h:139
std::string save_header_format_string(void) const
Definition: load-save.h:152
void dump_octave_core(void)
Definition: load-save.cc:729
std::string octave_core_file_name(void) const
Definition: load-save.h:113
octave_value octave_core_file_options(const octave_value_list &args, int nargout)
Definition: load-save.cc:313
void do_save(std::ostream &os, const octave_value &tc, const std::string &name, const std::string &help, bool global, const load_save_format &fmt, bool save_as_floats)
Definition: load-save.cc:927
void install_loaded_variable(const std::string &name, const octave_value &val, bool global, const std::string &)
Definition: load-save.cc:1062
static string_vector parse_save_options(const string_vector &argv, load_save_format &fmt, bool &append, bool &save_as_floats, bool &use_zlib)
Definition: load-save.cc:530
std::string m_save_header_format_string
Definition: load-save.h:226
octave_value save_header_format_string(const octave_value_list &args, int nargout)
Definition: load-save.cc:321
double octave_core_file_limit(void) const
Definition: load-save.h:100
octave_value load_vars(std::istream &stream, const std::string &orig_fname, const load_save_format &fmt, mach_info::float_format flt_fmt, bool list_only, bool swap, bool verbose, const string_vector &argv, int argv_idx, int argc, int nargout)
Definition: load-save.cc:379
static std::string init_save_header_format(void)
Definition: load-save.cc:1070
void save_vars(const string_vector &argv, int argv_idx, int argc, std::ostream &os, const load_save_format &fmt, bool save_as_floats, bool write_header_info)
Definition: load-save.cc:670
interpreter & m_interpreter
Definition: load-save.h:203
size_t save_fields(std::ostream &os, const octave_scalar_map &m, const std::string &pattern, const load_save_format &fmt, bool save_as_floats)
Definition: load-save.cc:996
bool crash_dumps_octave_core(void) const
Definition: load-save.h:87
std::string m_save_default_options
Definition: load-save.h:218
octave_value_list save(const octave_value_list &args=octave_value_list(), int nargout=0)
Definition: load-save.cc:1397
load_save_system(interpreter &interp)
Definition: load-save.cc:259
std::string m_octave_core_file_options
Definition: load-save.h:221
bool eof(void) const
Definition: oct-stream.cc:7267
octave_value value(void) const
Definition: syminfo.h:66
bool is_global(void) const
Definition: syminfo.h:72
std::string name(void) const
Definition: syminfo.h:64
bool is_reg(void) const
Definition: file-stat.cc:83
bool exists(void) const
Definition: file-stat.h:147
std::string strftime(const std::string &fmt) const
Definition: oct-time.cc:164
static std::string get_host_name(void)
Definition: oct-env.cc:196
static std::string get_user_name(void)
Definition: oct-env.cc:189
symbol_info_list glob_symbol_info(const std::string &pattern) const
Definition: pt-eval.cc:3639
symbol_info_list top_scope_symbol_info(void) const
Definition: pt-eval.cc:3657
octave_idx_type nfields(void) const
Definition: oct-map.h:218
void assign(const std::string &k, const octave_value &val)
Definition: oct-map.h:238
octave_idx_type length(void) const
Definition: ovl.h:113
string_vector make_argv(const std::string &="") const
Definition: ovl.cc:227
octave_idx_type rows(void) const
Definition: ov.h:504
octave_idx_type numel(void) const
Definition: ov.h:518
bool is_defined(void) const
Definition: ov.h:551
octave_idx_type columns(void) const
Definition: ov.h:506
bool isstruct(void) const
Definition: ov.h:605
octave_scalar_map scalar_map_value(void) const
size_t byte_size(void) const
Definition: ov.h:521
std::string type_name(void) const
Definition: ov.h:1254
string_vector & append(const std::string &s)
Definition: str-vec.cc:110
std::ostream & list_in_columns(std::ostream &, int width=0, const std::string &prefix="") const
Definition: str-vec.cc:201
octave_idx_type numel(void) const
Definition: str-vec.h:100
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:143
OCTINTERP_API void print_usage(void)
Definition: defun.cc:53
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition: defun.h:138
void warning(const char *fmt,...)
Definition: error.cc:1050
void error(const char *fmt,...)
Definition: error.cc:968
void message(const char *name, const char *fmt,...)
Definition: error.cc:936
void err_unrecognized_data_fmt(const char *name)
Definition: errwarn.cc:134
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:53
QString name
void dump_octave_core(void)
Definition: load-save.cc:1540
bool save_hdf5_data(std::ostream &os, const octave_value &tc, const std::string &name, const std::string &doc, bool mark_global, bool save_as_floats)
Definition: ls-hdf5.cc:1475
std::string read_hdf5_data(std::istream &is, const std::string &, bool &global, octave_value &tc, std::string &doc, const string_vector &argv, int argv_idx, int argc)
Definition: ls-hdf5.cc:1054
bool save_mat_ascii_data(std::ostream &os, const octave_value &val, int precision, bool tabs)
std::string read_mat_ascii_data(std::istream &is, const std::string &filename, octave_value &tc)
bool looks_like_mat_ascii_file(std::istream &is, const std::string &filename)
octave::mach_info::float_format mopt_digit_to_float_format(int mach)
Definition: ls-mat4.cc:174
bool save_mat_binary_data(std::ostream &os, const octave_value &tc, const std::string &name)
Definition: ls-mat4.cc:394
int read_mat_file_header(std::istream &is, bool &swap, int32_t &mopt, int32_t &nr, int32_t &nc, int32_t &imag, int32_t &len, int quiet)
Definition: ls-mat4.cc:107
static void read_mat_binary_data(std::istream &is, double *data, int precision, int len, bool swap, octave::mach_info::float_format flt_fmt)
Definition: ls-mat4.cc:71
int float_format_to_mopt_digit(octave::mach_info::float_format flt_fmt)
Definition: ls-mat4.cc:200
int read_mat5_binary_file_header(std::istream &is, bool &swap, bool quiet, const std::string &filename)
Definition: ls-mat5.cc:1494
bool save_mat5_binary_element(std::ostream &os, const octave_value &tc, const std::string &name, bool mark_global, bool mat7_format, bool save_as_floats, bool compressing)
Definition: ls-mat5.cc:2252
std::string read_mat5_binary_element(std::istream &is, const std::string &filename, bool swap, bool &global, octave_value &tc)
Definition: ls-mat5.cc:477
std::string read_binary_data(std::istream &is, bool swap, octave::mach_info::float_format fmt, const std::string &filename, bool &global, octave_value &tc, std::string &doc)
bool save_binary_data(std::ostream &os, const octave_value &tc, const std::string &name, const std::string &doc, bool mark_global, bool save_as_floats)
std::string read_text_data(std::istream &is, const std::string &filename, bool &global, octave_value &tc, octave_idx_type count, const bool do_name_validation)
Definition: ls-oct-text.cc:287
std::string extract_keyword(std::istream &is, const char *keyword, const bool next_only)
Definition: ls-oct-text.cc:84
bool save_text_data(std::ostream &os, const octave_value &val_arg, const std::string &name, bool mark_global, int precision)
Definition: ls-oct-text.cc:363
#define OCTAVE_VERSION
Definition: main.in.cc:52
T octave_idx_type m
Definition: mx-inlines.cc:773
float_format native_float_format(void)
Definition: mach-info.cc:65
bool words_big_endian(void)
Definition: mach-info.cc:72
std::complex< T > trunc(const std::complex< T > &x)
Definition: lo-mappers.h:111
bool strncmp(const T &str_a, const T &str_b, const typename T::size_type n)
True if the first N characters are the same.
Definition: oct-string.cc:156
std::string tilde_expand(const std::string &name)
Definition: file-ops.cc:286
std::string dir_sep_chars(void)
Definition: file-ops.cc:252
std::string get_ASCII_filename(const std::string &orig_file_name)
Definition: lo-sysdep.cc:551
std::ifstream ifstream(const std::string &filename, const std::ios::openmode mode)
Definition: lo-sysdep.cc:381
std::ofstream ofstream(const std::string &filename, const std::ios::openmode mode)
Definition: lo-sysdep.cc:395
static OCTAVE_NORETURN void err_file_open(const std::string &fcn, const std::string &file)
Definition: load-save.cc:97
static bool check_gzip_magic(const std::string &fname)
Definition: load-save.cc:164
static bool glob_pattern_p(const std::string &pattern)
Definition: load-save.cc:221
load_save_system & __get_load_save_system__(const std::string &who)
static int left
Definition: randmtzig.cc:191
static int read_binary_file_header(std::istream &is, bool &swap, mach_info::float_format &flt_fmt, bool quiet=false)
Definition: load-save.cc:125
static bool matches_patterns(const string_vector &patterns, int pat_idx, int num_pat, const std::string &name)
Definition: load-save.cc:110
std::string find_data_file_in_load_path(const std::string &fcn, const std::string &file, bool require_regular_file)
Definition: utils.cc:553
size_t format(std::ostream &os, const char *fmt,...)
Definition: utils.cc:1329
static std::string find_file_to_load(const std::string &name, const std::string &orig_name)
Definition: load-save.cc:185
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
#define octave_stdout
Definition: pager.h:313
octave_value set_internal_variable(bool &var, const octave_value_list &args, int nargout, const char *nm)
Definition: variables.cc:608
F77_RET_T len
Definition: xerbla.cc:61