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