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