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