load-save.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1994-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 // Author: John W. Eaton.
00024 // HDF5 support by Steven G. Johnson <stevenj@alum.mit.edu>
00025 // Matlab v5 support by James R. Van Zandt <jrv@vanzandt.mv.com>
00026 
00027 #ifdef HAVE_CONFIG_H
00028 #include <config.h>
00029 #endif
00030 
00031 #include <cfloat>
00032 #include <cstring>
00033 #include <cctype>
00034 
00035 #include <fstream>
00036 #include <iomanip>
00037 #include <iostream>
00038 #include <sstream>
00039 #include <string>
00040 
00041 #include "strftime.h"
00042 
00043 #include "byte-swap.h"
00044 #include "data-conv.h"
00045 #include "file-ops.h"
00046 #include "file-stat.h"
00047 #include "glob-match.h"
00048 #include "lo-mappers.h"
00049 #include "mach-info.h"
00050 #include "oct-env.h"
00051 #include "oct-time.h"
00052 #include "quit.h"
00053 #include "str-vec.h"
00054 #include "oct-locbuf.h"
00055 
00056 #include "Cell.h"
00057 #include "defun.h"
00058 #include "error.h"
00059 #include "gripes.h"
00060 #include "load-path.h"
00061 #include "load-save.h"
00062 #include "oct-obj.h"
00063 #include "oct-map.h"
00064 #include "ov-cell.h"
00065 #include "pager.h"
00066 #include "pt-exp.h"
00067 #include "symtab.h"
00068 #include "sysdep.h"
00069 #include "unwind-prot.h"
00070 #include "utils.h"
00071 #include "variables.h"
00072 #include "version.h"
00073 #include "dMatrix.h"
00074 
00075 #include "ls-hdf5.h"
00076 #include "ls-mat-ascii.h"
00077 #include "ls-mat4.h"
00078 #include "ls-mat5.h"
00079 #include "ls-oct-ascii.h"
00080 #include "ls-oct-binary.h"
00081 
00082 // Remove gnulib definitions, if any.
00083 #ifdef close
00084 #undef close
00085 #endif
00086 #ifdef open
00087 #undef open
00088 #endif
00089 
00090 #ifdef HAVE_ZLIB
00091 #include "zfstream.h"
00092 #endif
00093 
00094 // Write octave-core file if Octave crashes or is killed by a signal.
00095 static bool Vcrash_dumps_octave_core = true;
00096 
00097 // The maximum amount of memory (in kilobytes) that we will attempt to
00098 // write to the Octave core file.
00099 static double Voctave_core_file_limit = -1.0;
00100 
00101 // The name of the Octave core file.
00102 static std::string Voctave_core_file_name = "octave-core";
00103 
00104 // The default output format.  May be one of "binary", "text",
00105 // "mat-binary", or "hdf5".
00106 static std::string Vdefault_save_options = "-text";
00107 
00108 // The output format for Octave core files.
00109 static std::string Voctave_core_file_options = "-binary";
00110 
00111 static std::string
00112 default_save_header_format (void)
00113 {
00114   return
00115     std::string ("# Created by Octave " OCTAVE_VERSION
00116                  ", %a %b %d %H:%M:%S %Y %Z <")
00117     + octave_env::get_user_name ()
00118     + std::string ("@")
00119     + octave_env::get_host_name ()
00120     + std::string (">");
00121 }
00122 
00123 // The format string for the comment line at the top of text-format
00124 // save files.  Passed to strftime.  Should begin with '#' and contain
00125 // no newline characters.
00126 static std::string Vsave_header_format_string = default_save_header_format ();
00127 
00128 static void
00129 gripe_file_open (const std::string& fcn, const std::string& file)
00130 {
00131   if (fcn == "load")
00132     error ("%s: unable to open input file '%s'", fcn.c_str (), file.c_str ());
00133   else if (fcn == "save")
00134     error ("%s: unable to open output file '%s'", fcn.c_str (), file.c_str ());
00135   else
00136     error ("%s: unable to open file '%s'", fcn.c_str (), file.c_str ());
00137 }
00138 
00139 // Install a variable with name NAME and the value VAL in the
00140 // symbol table.  If GLOBAL is TRUE, make the variable global.
00141 
00142 static void
00143 install_loaded_variable (const std::string& name,
00144                          const octave_value& val,
00145                          bool global, const std::string& /*doc*/)
00146 {
00147   if (global)
00148     {
00149       symbol_table::symbol_record& sr = symbol_table::insert (name);
00150       sr.clear ();
00151       sr.mark_global ();
00152       sr.varref () = val;
00153     }
00154   else
00155     symbol_table::varref (name) = val;
00156 }
00157 
00158 // Return TRUE if NAME matches one of the given globbing PATTERNS.
00159 
00160 static bool
00161 matches_patterns (const string_vector& patterns, int pat_idx,
00162                   int num_pat, const std::string& name)
00163 {
00164   for (int i = pat_idx; i < num_pat; i++)
00165     {
00166       glob_match pattern (patterns[i]);
00167 
00168       if (pattern.match (name))
00169         return true;
00170     }
00171 
00172   return false;
00173 }
00174 
00175 int
00176 read_binary_file_header (std::istream& is, bool& swap,
00177                          oct_mach_info::float_format& flt_fmt, bool quiet)
00178 {
00179   const int magic_len = 10;
00180   char magic[magic_len+1];
00181   is.read (magic, magic_len);
00182   magic[magic_len] = '\0';
00183 
00184   if (strncmp (magic, "Octave-1-L", magic_len) == 0)
00185     swap = oct_mach_info::words_big_endian ();
00186   else if (strncmp (magic, "Octave-1-B", magic_len) == 0)
00187     swap = ! oct_mach_info::words_big_endian ();
00188   else
00189     {
00190       if (! quiet)
00191         error ("load: unable to read read binary file");
00192       return -1;
00193     }
00194 
00195   char tmp = 0;
00196   is.read (&tmp, 1);
00197 
00198   flt_fmt = mopt_digit_to_float_format (tmp);
00199 
00200   if (flt_fmt == oct_mach_info::flt_fmt_unknown)
00201     {
00202       if (! quiet)
00203         error ("load: unrecognized binary format!");
00204 
00205       return -1;
00206     }
00207 
00208   return 0;
00209 }
00210 
00211 #ifdef HAVE_ZLIB
00212 static bool
00213 check_gzip_magic (const std::string& fname)
00214 {
00215   bool retval = false;
00216   std::ifstream file (fname.c_str ());
00217   OCTAVE_LOCAL_BUFFER (unsigned char, magic, 2);
00218 
00219   if (file.read (reinterpret_cast<char *> (magic), 2) && magic[0] == 0x1f &&
00220       magic[1] == 0x8b)
00221     retval = true;
00222 
00223   file.close ();
00224   return retval;
00225 }
00226 #endif
00227 
00228 static load_save_format
00229 get_file_format (std::istream& file, const std::string& filename)
00230 {
00231   load_save_format retval = LS_UNKNOWN;
00232 
00233   oct_mach_info::float_format flt_fmt = oct_mach_info::flt_fmt_unknown;
00234 
00235   bool swap = false;
00236 
00237   if (read_binary_file_header (file, swap, flt_fmt, true) == 0)
00238     retval = LS_BINARY;
00239   else
00240     {
00241       file.clear ();
00242       file.seekg (0, std::ios::beg);
00243 
00244       int32_t mopt, nr, nc, imag, len;
00245 
00246       int err = read_mat_file_header (file, swap, mopt, nr, nc, imag, len, 1);
00247 
00248       if (! err)
00249         retval = LS_MAT_BINARY;
00250       else
00251         {
00252           file.clear ();
00253           file.seekg (0, std::ios::beg);
00254 
00255           err = read_mat5_binary_file_header (file, swap, true, filename);
00256 
00257           if (! err)
00258             {
00259               file.clear ();
00260               file.seekg (0, std::ios::beg);
00261               retval = LS_MAT5_BINARY;
00262             }
00263           else
00264             {
00265               file.clear ();
00266               file.seekg (0, std::ios::beg);
00267 
00268               std::string tmp = extract_keyword (file, "name");
00269 
00270               if (! tmp.empty ())
00271                 retval = LS_ASCII;
00272             }
00273         }
00274     }
00275 
00276   return retval;
00277 }
00278 
00279 static load_save_format
00280 get_file_format (const std::string& fname, const std::string& orig_fname,
00281                  bool &use_zlib)
00282 {
00283   load_save_format retval = LS_UNKNOWN;
00284 
00285 #ifdef HAVE_HDF5
00286   // check this before we open the file
00287   if (H5Fis_hdf5 (fname.c_str ()) > 0)
00288     return LS_HDF5;
00289 #endif /* HAVE_HDF5 */
00290 
00291   std::ifstream file (fname.c_str ());
00292   use_zlib = false;
00293 
00294   if (file)
00295     {
00296       retval = get_file_format (file, orig_fname);
00297       file.close ();
00298 
00299 #ifdef HAVE_ZLIB
00300       if (retval == LS_UNKNOWN && check_gzip_magic (fname))
00301         {
00302           gzifstream gzfile (fname.c_str ());
00303           use_zlib = true;
00304 
00305           if (gzfile)
00306             {
00307               retval = get_file_format (gzfile, orig_fname);
00308               gzfile.close ();
00309             }
00310         }
00311 #endif
00312 
00313       if (retval == LS_UNKNOWN)
00314         {
00315           // Try reading the file as numbers only, determining the
00316           // number of rows and columns from the data.  We don't
00317           // even bother to check to see if the first item in the
00318           // file is a number, so that get_complete_line() can
00319           // skip any comments that might appear at the top of the
00320           // file.
00321 
00322           retval = LS_MAT_ASCII;
00323         }
00324     }
00325   else
00326     gripe_file_open ("load", orig_fname);
00327 
00328   return retval;
00329 }
00330 
00331 octave_value
00332 do_load (std::istream& stream, const std::string& orig_fname,
00333          load_save_format format, oct_mach_info::float_format flt_fmt,
00334          bool list_only, bool swap, bool verbose,
00335          const string_vector& argv, int argv_idx, int argc, int nargout)
00336 {
00337   octave_value retval;
00338 
00339   octave_scalar_map retstruct;
00340 
00341   std::ostringstream output_buf;
00342   std::list<std::string> symbol_names;
00343 
00344   octave_idx_type count = 0;
00345 
00346   for (;;)
00347     {
00348       bool global = false;
00349       octave_value tc;
00350 
00351       std::string name;
00352       std::string doc;
00353 
00354       switch (format.type)
00355         {
00356         case LS_ASCII:
00357           name = read_ascii_data (stream, orig_fname, global, tc, count);
00358           break;
00359 
00360         case LS_BINARY:
00361           name = read_binary_data (stream, swap, flt_fmt, orig_fname,
00362                                    global, tc, doc);
00363           break;
00364 
00365         case LS_MAT_ASCII:
00366           name = read_mat_ascii_data (stream, orig_fname, tc);
00367           break;
00368 
00369         case LS_MAT_BINARY:
00370           name = read_mat_binary_data (stream, orig_fname, tc);
00371           break;
00372 
00373 #ifdef HAVE_HDF5
00374         case LS_HDF5:
00375           name = read_hdf5_data (stream, orig_fname, global, tc, doc);
00376           break;
00377 #endif /* HAVE_HDF5 */
00378 
00379         case LS_MAT5_BINARY:
00380         case LS_MAT7_BINARY:
00381           name = read_mat5_binary_element (stream, orig_fname, swap,
00382                                            global, tc);
00383           break;
00384 
00385         default:
00386           gripe_unrecognized_data_fmt ("load");
00387           break;
00388         }
00389 
00390       if (error_state || stream.eof () || name.empty ())
00391         break;
00392       else if (! error_state && ! name.empty ())
00393         {
00394           if (tc.is_defined ())
00395             {
00396               if (format == LS_MAT_ASCII && argv_idx < argc)
00397                 warning ("load: loaded ASCII file '%s' -- ignoring extra args",
00398                          orig_fname.c_str ());
00399 
00400               if (format == LS_MAT_ASCII
00401                   || argv_idx == argc
00402                   || matches_patterns (argv, argv_idx, argc, name))
00403                 {
00404                   count++;
00405                   if (list_only)
00406                     {
00407                       if (verbose)
00408                         {
00409                           if (count == 1)
00410                             output_buf
00411                               << "type               rows   cols   name\n"
00412                               << "====               ====   ====   ====\n";
00413 
00414                           output_buf
00415                             << std::setiosflags (std::ios::left)
00416                             << std::setw (16) << tc.type_name () . c_str ()
00417                             << std::setiosflags (std::ios::right)
00418                             << std::setw (7) << tc.rows ()
00419                             << std::setw (7) << tc.columns ()
00420                             << "   " << name << "\n";
00421                         }
00422                       else
00423                         symbol_names.push_back (name);
00424                     }
00425                   else
00426                     {
00427                       if (nargout == 1)
00428                         {
00429                           if (format == LS_MAT_ASCII)
00430                             retval = tc;
00431                           else
00432                             retstruct.assign (name, tc);
00433                         }
00434                       else
00435                         install_loaded_variable (name, tc, global, doc);
00436                     }
00437                 }
00438 
00439               // Only attempt to read one item from a headless text file.
00440 
00441               if (format == LS_MAT_ASCII)
00442                 break;
00443             }
00444           else
00445             error ("load: unable to load variable '%s'", name.c_str ());
00446         }
00447       else
00448         {
00449           if (count == 0)
00450             error ("load: are you sure '%s' is an Octave data file?",
00451                    orig_fname.c_str ());
00452 
00453           break;
00454         }
00455     }
00456 
00457   if (list_only && count)
00458     {
00459       if (verbose)
00460         {
00461           std::string msg = output_buf.str ();
00462 
00463           if (nargout > 0)
00464             retval = msg;
00465           else
00466             octave_stdout << msg;
00467         }
00468       else
00469         {
00470           if (nargout  > 0)
00471             retval = Cell (string_vector (symbol_names));
00472           else
00473             {
00474               string_vector names (symbol_names);
00475 
00476               names.list_in_columns (octave_stdout);
00477 
00478               octave_stdout << "\n";
00479             }
00480         }
00481     }
00482   else if (retstruct.nfields () != 0)
00483     retval = retstruct;
00484 
00485   return retval;
00486 }
00487 
00488 std::string
00489 find_file_to_load (const std::string& name, const std::string& orig_name)
00490 {
00491   std::string fname = name;
00492 
00493   if (! (octave_env::absolute_pathname (fname)
00494          || octave_env::rooted_relative_pathname (fname)))
00495     {
00496       file_stat fs (fname);
00497 
00498       if (! (fs.exists () && fs.is_reg ()))
00499         {
00500           std::string tmp
00501             = octave_env::make_absolute (load_path::find_file (fname));
00502 
00503           if (! tmp.empty ())
00504             {
00505               warning_with_id ("Octave:load-file-in-path",
00506                                "load: file found in load path");
00507               fname = tmp;
00508             }
00509         }
00510     }
00511 
00512   size_t dot_pos = fname.rfind (".");
00513   size_t sep_pos = fname.find_last_of (file_ops::dir_sep_chars ());
00514 
00515   if (dot_pos == std::string::npos
00516       || (sep_pos != std::string::npos && dot_pos < sep_pos))
00517     {
00518       // Either no '.' in name or no '.' appears after last directory
00519       // separator.
00520 
00521       file_stat fs (fname);
00522 
00523       if (! (fs.exists () && fs.is_reg ()))
00524         fname = find_file_to_load (fname + ".mat", orig_name);
00525     }
00526   else
00527     {
00528       file_stat fs (fname);
00529 
00530       if (! (fs.exists () && fs.is_reg ()))
00531         {
00532           fname = "";
00533 
00534           error ("load: unable to find file %s", orig_name.c_str ());
00535         }
00536     }
00537 
00538   return fname;
00539 }
00540 
00541 
00542 DEFUN (load, args, nargout,
00543   "-*- texinfo -*-\n\
00544 @deftypefn  {Command} {} load file\n\
00545 @deftypefnx {Command} {} load options file\n\
00546 @deftypefnx {Command} {} load options file v1 v2 @dots{}\n\
00547 @deftypefnx {Command} {S =} load (\"options\", \"file\", \"v1\", \"v2\", @dots{})\n\
00548 @deftypefnx {Command} {} load file options\n\
00549 @deftypefnx {Command} {} load file options v1 v2 @dots{}\n\
00550 @deftypefnx {Command} {S =} load (\"file\", \"options\", \"v1\", \"v2\", @dots{})\n\
00551 Load the named variables @var{v1}, @var{v2}, @dots{}, from the file\n\
00552 @var{file}.  If no variables are specified then all variables found in the\n\
00553 file will be loaded.  As with @code{save}, the list of variables to extract\n\
00554 can be full names or use a pattern syntax.  The format of the file is\n\
00555 automatically detected but may be overridden by supplying the appropriate\n\
00556 option.\n\
00557 \n\
00558 If load is invoked using the functional form\n\
00559 \n\
00560 @example\n\
00561 load (\"-option1\", @dots{}, \"file\", \"v1\", @dots{})\n\
00562 @end example\n\
00563 \n\
00564 @noindent\n\
00565 then the @var{options}, @var{file}, and variable name arguments\n\
00566 (@var{v1}, @dots{}) must be specified as character strings.\n\
00567 \n\
00568 If a variable that is not marked as global is loaded from a file when a\n\
00569 global symbol with the same name already exists, it is loaded in the\n\
00570 global symbol table.  Also, if a variable is marked as global in a file\n\
00571 and a local symbol exists, the local symbol is moved to the global\n\
00572 symbol table and given the value from the file.\n\
00573 \n\
00574 If invoked with a single output argument, Octave returns data instead\n\
00575 of inserting variables in the symbol table.  If the data file contains\n\
00576 only numbers (TAB- or space-delimited columns), a matrix of values is\n\
00577 returned.  Otherwise, @code{load} returns a structure with members\n\
00578  corresponding to the names of the variables in the file.\n\
00579 \n\
00580 The @code{load} command can read data stored in Octave's text and\n\
00581 binary formats, and @sc{matlab}'s binary format.  If compiled with zlib\n\
00582 support, it can also load gzip-compressed files.  It will automatically\n\
00583 detect the type of file and do conversion from different floating point\n\
00584 formats (currently only IEEE big and little endian, though other formats\n\
00585 may be added in the future).\n\
00586 \n\
00587 Valid options for @code{load} are listed in the following table.\n\
00588 \n\
00589 @table @code\n\
00590 @item -force\n\
00591 This option is accepted for backward compatibility but is ignored.\n\
00592 Octave now overwrites variables currently in memory with\n\
00593 those of the same name found in the file.\n\
00594 \n\
00595 @item -ascii\n\
00596 Force Octave to assume the file contains columns of numbers in text format\n\
00597 without any header or other information.  Data in the file will be loaded\n\
00598 as a single numeric matrix with the name of the variable derived from the\n\
00599 name of the file.\n\
00600 \n\
00601 @item -binary\n\
00602 Force Octave to assume the file is in Octave's binary format.\n\
00603 \n\
00604 @item -hdf5\n\
00605 Force Octave to assume the file is in @sc{hdf5} format.\n\
00606 (@sc{hdf5} is a free, portable binary format developed by the National\n\
00607 Center for Supercomputing Applications at the University of Illinois.)\n\
00608 Note that Octave can read @sc{hdf5} files not created by itself, but may\n\
00609 skip some datasets in formats that it cannot support.  This format is\n\
00610 only available if Octave was built with a link to the @sc{hdf5} libraries.\n\
00611 \n\
00612 @item -import\n\
00613 This option is accepted for backward compatibility but is ignored.\n\
00614 Octave can now support multi-dimensional HDF data and automatically\n\
00615 modifies variable names if they are invalid Octave identifiers.\n\
00616 \n\
00617 @item -mat\n\
00618 @itemx -mat-binary\n\
00619 @itemx -6\n\
00620 @itemx -v6\n\
00621 @itemx -7\n\
00622 @itemx -v7\n\
00623 Force Octave to assume the file is in @sc{matlab}'s version 6 or 7 binary\n\
00624 format.\n\
00625 \n\
00626 @item  -mat4-binary\n\
00627 @itemx -4\n\
00628 @itemx -v4\n\
00629 @itemx -V4\n\
00630 Force Octave to assume the file is in the binary format written by\n\
00631 @sc{matlab} version 4.\n\
00632 \n\
00633 @item -text\n\
00634 Force Octave to assume the file is in Octave's text format.\n\
00635 @end table\n\
00636 @seealso{save, dlmwrite, csvwrite, fwrite}\n\
00637 @end deftypefn")
00638 {
00639   octave_value_list retval;
00640 
00641   int argc = args.length () + 1;
00642 
00643   string_vector argv = args.make_argv ("load");
00644 
00645   if (error_state)
00646     return retval;
00647 
00648   int i = 1;
00649   std::string orig_fname = "";
00650 
00651   // Function called with Matlab-style ["filename", options] syntax
00652   if (argc > 1 && ! argv[1].empty () && argv[1].at(0) != '-')
00653     {
00654       orig_fname = argv[1];
00655       i++;
00656     }
00657 
00658   // It isn't necessary to have the default load format stored in a
00659   // user preference variable since we can determine the type of file
00660   // as we are reading.
00661 
00662   load_save_format format = LS_UNKNOWN;
00663 
00664   bool list_only = false;
00665   bool verbose = false;
00666 
00667   //for (i; i < argc; i++)
00668   for (; i < argc; i++)
00669     {
00670       if (argv[i] == "-force" || argv[i] == "-f")
00671         {
00672           // Silently ignore this
00673           // warning ("load: -force ignored");
00674         }
00675       else if (argv[i] == "-list" || argv[i] == "-l")
00676         {
00677           list_only = true;
00678         }
00679       else if (argv[i] == "-verbose" || argv[i] == "-v")
00680         {
00681           verbose = true;
00682         }
00683       else if (argv[i] == "-ascii" || argv[i] == "-a")
00684         {
00685           format = LS_MAT_ASCII;
00686         }
00687       else if (argv[i] == "-binary" || argv[i] == "-b")
00688         {
00689           format = LS_BINARY;
00690         }
00691       else if (argv[i] == "-mat-binary" || argv[i] == "-mat" || argv[i] == "-m"
00692                || argv[i] == "-6" || argv[i] == "-v6")
00693         {
00694           format = LS_MAT5_BINARY;
00695         }
00696       else if (argv[i] == "-7" || argv[i] == "-v7")
00697         {
00698           format = LS_MAT7_BINARY;
00699         }
00700       else if (argv[i] == "-mat4-binary" || argv[i] == "-V4"
00701                || argv[i] == "-v4" || argv[i] == "-4")
00702         {
00703           format = LS_MAT_BINARY;
00704         }
00705       else if (argv[i] == "-hdf5" || argv[i] == "-h")
00706         {
00707 #ifdef HAVE_HDF5
00708           format = LS_HDF5;
00709 #else /* ! HAVE_HDF5 */
00710           error ("load: octave executable was not linked with HDF5 library");
00711           return retval;
00712 #endif /* ! HAVE_HDF5 */
00713         }
00714       else if (argv[i] == "-import" || argv[i] == "-i")
00715         {
00716           warning ("load: -import ignored");
00717         }
00718       else if (argv[i] == "-text" || argv[i] == "-t")
00719         {
00720           format = LS_ASCII;
00721         }
00722       else
00723         break;
00724     }
00725 
00726   if (orig_fname == "")
00727     {
00728       if (i == argc)
00729         {
00730           print_usage ();
00731           return retval;
00732         }
00733       else
00734         orig_fname = argv[i];
00735     }
00736   else
00737     i--;
00738 
00739   oct_mach_info::float_format flt_fmt = oct_mach_info::flt_fmt_unknown;
00740 
00741   bool swap = false;
00742 
00743   if (orig_fname == "-")
00744     {
00745       i++;
00746 
00747 #ifdef HAVE_HDF5
00748       if (format == LS_HDF5)
00749         error ("load: cannot read HDF5 format from stdin");
00750       else
00751 #endif /* HAVE_HDF5 */
00752       if (format != LS_UNKNOWN)
00753         {
00754           // FIXME -- if we have already seen EOF on a
00755           // previous call, how do we fix up the state of std::cin so
00756           // that we can get additional input?  I'm afraid that we
00757           // can't fix this using std::cin only.
00758 
00759           retval = do_load (std::cin, orig_fname, format, flt_fmt,
00760                             list_only, swap, verbose, argv, i, argc,
00761                             nargout);
00762         }
00763       else
00764         error ("load: must specify file format if reading from stdin");
00765     }
00766   else
00767     {
00768       std::string fname = file_ops::tilde_expand (orig_fname);
00769 
00770       fname = find_file_to_load (fname, orig_fname);
00771 
00772       if (error_state)
00773         return retval;
00774 
00775       bool use_zlib = false;
00776 
00777       if (format == LS_UNKNOWN)
00778         format = get_file_format (fname, orig_fname, use_zlib);
00779 
00780 #ifdef HAVE_HDF5
00781       if (format == LS_HDF5)
00782         {
00783           i++;
00784 
00785           hdf5_ifstream hdf5_file (fname.c_str ());
00786 
00787           if (hdf5_file.file_id >= 0)
00788             {
00789               retval = do_load (hdf5_file, orig_fname, format,
00790                                 flt_fmt, list_only, swap, verbose,
00791                                 argv, i, argc, nargout);
00792 
00793               hdf5_file.close ();
00794             }
00795           else
00796             gripe_file_open ("load", orig_fname);
00797         }
00798       else
00799 #endif /* HAVE_HDF5 */
00800         // don't insert any statements here; the "else" above has to
00801         // go with the "if" below!!!!!
00802       if (format != LS_UNKNOWN)
00803         {
00804           i++;
00805 
00806           // Always open in binary mode and handle various
00807           // line-endings explicitly.
00808           std::ios::openmode mode = std::ios::in | std::ios::binary;
00809 
00810 #ifdef HAVE_ZLIB
00811           if (use_zlib)
00812             {
00813               gzifstream file (fname.c_str (), mode);
00814 
00815               if (file)
00816                 {
00817                   if (format == LS_BINARY)
00818                     {
00819                       if (read_binary_file_header (file, swap, flt_fmt) < 0)
00820                         {
00821                           if (file) file.close ();
00822                           return retval;
00823                         }
00824                     }
00825                   else if (format == LS_MAT5_BINARY
00826                            || format == LS_MAT7_BINARY)
00827                     {
00828                       if (read_mat5_binary_file_header (file, swap, false, orig_fname) < 0)
00829                         {
00830                           if (file) file.close ();
00831                           return retval;
00832                         }
00833                     }
00834 
00835                   retval = do_load (file, orig_fname, format,
00836                                     flt_fmt, list_only, swap, verbose,
00837                                 argv, i, argc, nargout);
00838 
00839                   file.close ();
00840                 }
00841               else
00842                 gripe_file_open ("load", orig_fname);
00843             }
00844           else
00845 #endif
00846             {
00847               std::ifstream file (fname.c_str (), mode);
00848 
00849               if (file)
00850                 {
00851                   if (format == LS_BINARY)
00852                     {
00853                       if (read_binary_file_header (file, swap, flt_fmt) < 0)
00854                         {
00855                           if (file) file.close ();
00856                           return retval;
00857                         }
00858                     }
00859                   else if (format == LS_MAT5_BINARY
00860                            || format == LS_MAT7_BINARY)
00861                     {
00862                       if (read_mat5_binary_file_header (file, swap, false, orig_fname) < 0)
00863                         {
00864                           if (file) file.close ();
00865                           return retval;
00866                         }
00867                     }
00868 
00869                   retval = do_load (file, orig_fname, format,
00870                                     flt_fmt, list_only, swap, verbose,
00871                                     argv, i, argc, nargout);
00872 
00873                   file.close ();
00874                 }
00875               else
00876                 error ("load: unable to open input file '%s'",
00877                        orig_fname.c_str ());
00878             }
00879         }
00880     }
00881 
00882   return retval;
00883 }
00884 
00885 // Return TRUE if PATTERN has any special globbing chars in it.
00886 
00887 static bool
00888 glob_pattern_p (const std::string& pattern)
00889 {
00890   int open = 0;
00891 
00892   int len = pattern.length ();
00893 
00894   for (int i = 0; i < len; i++)
00895     {
00896       char c = pattern[i];
00897 
00898       switch (c)
00899         {
00900         case '?':
00901         case '*':
00902           return true;
00903 
00904         case '[':       // Only accept an open brace if there is a close
00905           open++;       // brace to match it.  Bracket expressions must be
00906           continue;     // complete, according to Posix.2
00907 
00908         case ']':
00909           if (open)
00910             return true;
00911           continue;
00912 
00913         case '\\':
00914           if (i == len - 1)
00915             return false;
00916 
00917         default:
00918           continue;
00919         }
00920     }
00921 
00922   return false;
00923 }
00924 
00925 static void
00926 do_save (std::ostream& os, const octave_value& tc,
00927          const std::string& name, const std::string& help,
00928          bool global, load_save_format fmt, bool save_as_floats)
00929 {
00930   switch (fmt.type)
00931     {
00932     case LS_ASCII:
00933       save_ascii_data (os, tc, name, global, 0);
00934       break;
00935 
00936     case LS_BINARY:
00937       save_binary_data (os, tc, name, help, global, save_as_floats);
00938       break;
00939 
00940     case LS_MAT_ASCII:
00941       if (! save_mat_ascii_data (os, tc, fmt.opts & LS_MAT_ASCII_LONG ? 16 : 8,
00942                                  fmt.opts & LS_MAT_ASCII_TABS))
00943         warning ("save: unable to save %s in ASCII format", name.c_str ());
00944       break;
00945 
00946     case LS_MAT_BINARY:
00947       save_mat_binary_data (os, tc, name);
00948       break;
00949 
00950 #ifdef HAVE_HDF5
00951     case LS_HDF5:
00952       save_hdf5_data (os, tc, name, help, global, save_as_floats);
00953       break;
00954 #endif /* HAVE_HDF5 */
00955 
00956     case LS_MAT5_BINARY:
00957       save_mat5_binary_element (os, tc, name, global, false, save_as_floats);
00958       break;
00959 
00960     case LS_MAT7_BINARY:
00961       save_mat5_binary_element (os, tc, name, global, true, save_as_floats);
00962       break;
00963 
00964     default:
00965       gripe_unrecognized_data_fmt ("save");
00966       break;
00967     }
00968 }
00969 
00970 // Save the info from SR on stream OS in the format specified by FMT.
00971 
00972 void
00973 do_save (std::ostream& os, const symbol_table::symbol_record& sr,
00974          load_save_format fmt, bool save_as_floats)
00975 {
00976   octave_value val = sr.varval ();
00977 
00978   if (val.is_defined ())
00979     {
00980       std::string name = sr.name ();
00981       std::string help;
00982       bool global = sr.is_global ();
00983 
00984       do_save (os, val, name, help, global, fmt, save_as_floats);
00985     }
00986 }
00987 
00988 // save fields of a scalar structure STR matching PATTERN on stream OS
00989 // in the format specified by FMT.
00990 
00991 static size_t
00992 save_fields (std::ostream& os, const octave_scalar_map& m,
00993              const std::string& pattern,
00994              load_save_format fmt, bool save_as_floats)
00995 {
00996   glob_match pat (pattern);
00997 
00998   size_t saved = 0;
00999 
01000   for (octave_scalar_map::const_iterator p = m.begin (); p != m.end (); p++)
01001     {
01002       std::string empty_str;
01003 
01004       if (pat.match(m.key (p)))
01005         {
01006           do_save (os, m.contents (p), m.key (p), empty_str,
01007                    0, fmt, save_as_floats);
01008 
01009           saved++;
01010         }
01011     }
01012 
01013   return saved;
01014 }
01015 
01016 // Save variables with names matching PATTERN on stream OS in the
01017 // format specified by FMT.
01018 
01019 static size_t
01020 save_vars (std::ostream& os, const std::string& pattern,
01021            load_save_format fmt, bool save_as_floats)
01022 {
01023   std::list<symbol_table::symbol_record> vars = symbol_table::glob (pattern);
01024 
01025   size_t saved = 0;
01026 
01027   typedef std::list<symbol_table::symbol_record>::const_iterator const_vars_iterator;
01028 
01029   for (const_vars_iterator p = vars.begin (); p != vars.end (); p++)
01030     {
01031       do_save (os, *p, fmt, save_as_floats);
01032 
01033       if (error_state)
01034         break;
01035 
01036       saved++;
01037     }
01038 
01039   return saved;
01040 }
01041 
01042 static string_vector
01043 parse_save_options (const string_vector &argv,
01044                     load_save_format &format, bool &append,
01045                     bool &save_as_floats, bool &use_zlib)
01046 {
01047   string_vector retval;
01048   int argc = argv.length ();
01049 
01050   bool do_double = false, do_tabs = false;
01051 
01052   for (int i = 0; i < argc; i++)
01053     {
01054       if (argv[i] == "-append")
01055         {
01056           append = true;
01057         }
01058       else if (argv[i] == "-ascii" || argv[i] == "-a")
01059         {
01060           format = LS_MAT_ASCII;
01061         }
01062       else if (argv[i] == "-double")
01063         {
01064           do_double = true;
01065         }
01066       else if (argv[i] == "-tabs")
01067         {
01068           do_tabs = true;
01069         }
01070       else if (argv[i] == "-text" || argv[i] == "-t")
01071         {
01072           format = LS_ASCII;
01073         }
01074       else if (argv[i] == "-binary" || argv[i] == "-b")
01075         {
01076           format = LS_BINARY;
01077         }
01078       else if (argv[i] == "-hdf5" || argv[i] == "-h")
01079         {
01080 #ifdef HAVE_HDF5
01081           format = LS_HDF5;
01082 #else /* ! HAVE_HDF5 */
01083           error ("save: octave executable was not linked with HDF5 library");
01084 #endif /* ! HAVE_HDF5 */
01085         }
01086       else if (argv[i] == "-mat-binary" || argv[i] == "-mat"
01087                || argv[i] == "-m" || argv[i] == "-6" || argv[i] == "-v6"
01088                || argv[i] == "-V6")
01089         {
01090           format = LS_MAT5_BINARY;
01091         }
01092 #ifdef HAVE_ZLIB
01093       else if (argv[i] == "-mat7-binary" || argv[i] == "-7"
01094                || argv[i] == "-v7" || argv[i] == "-V7")
01095         {
01096           format = LS_MAT7_BINARY;
01097         }
01098 #endif
01099       else if (argv[i] == "-mat4-binary" || argv[i] == "-V4"
01100                || argv[i] == "-v4" || argv[i] == "-4")
01101         {
01102           format = LS_MAT_BINARY;
01103         }
01104       else if (argv[i] == "-float-binary" || argv[i] == "-f")
01105         {
01106           format = LS_BINARY;
01107           save_as_floats = true;
01108         }
01109       else if (argv[i] == "-float-hdf5")
01110         {
01111 #ifdef HAVE_HDF5
01112           format = LS_HDF5;
01113           save_as_floats = true;
01114 #else /* ! HAVE_HDF5 */
01115           error ("save: octave executable was not linked with HDF5 library");
01116 #endif /* ! HAVE_HDF5 */
01117         }
01118 #ifdef HAVE_ZLIB
01119       else if (argv[i] == "-zip" || argv[i] == "-z")
01120         {
01121           use_zlib  = true;
01122         }
01123 #endif
01124       else
01125         retval.append (argv[i]);
01126     }
01127 
01128   if (do_double)
01129     {
01130       if (format == LS_MAT_ASCII)
01131         format.opts |= LS_MAT_ASCII_LONG;
01132       else
01133         warning ("save: \"-double\" option only has an effect with \"-ascii\"");
01134     }
01135 
01136   if (do_tabs)
01137     {
01138       if (format == LS_MAT_ASCII)
01139         format.opts |= LS_MAT_ASCII_TABS;
01140       else
01141         warning ("save: \"-tabs\" option only has an effect with \"-ascii\"");
01142     }
01143 
01144   return retval;
01145 }
01146 
01147 static string_vector
01148 parse_save_options (const std::string &arg, load_save_format &format,
01149                     bool &append, bool &save_as_floats,
01150                     bool &use_zlib)
01151 {
01152   std::istringstream is (arg);
01153   std::string str;
01154   string_vector argv;
01155 
01156   while (! is.eof ())
01157     {
01158       is >> str;
01159       argv.append (str);
01160     }
01161 
01162   return parse_save_options (argv, format, append, save_as_floats,
01163                              use_zlib);
01164 }
01165 
01166 void
01167 write_header (std::ostream& os, load_save_format format)
01168 {
01169   switch (format.type)
01170     {
01171     case LS_BINARY:
01172       {
01173         os << (oct_mach_info::words_big_endian ()
01174                ? "Octave-1-B" : "Octave-1-L");
01175 
01176         oct_mach_info::float_format flt_fmt =
01177           oct_mach_info::native_float_format ();
01178 
01179         char tmp = static_cast<char> (float_format_to_mopt_digit (flt_fmt));
01180 
01181         os.write (&tmp, 1);
01182       }
01183       break;
01184 
01185     case LS_MAT5_BINARY:
01186     case LS_MAT7_BINARY:
01187       {
01188         char const * versionmagic;
01189         int16_t number = *(reinterpret_cast<const int16_t *>("\x00\x01"));
01190         struct tm bdt;
01191         time_t now;
01192         char headertext[128];
01193 
01194         time (&now);
01195         bdt = *gmtime (&now);
01196         memset (headertext, ' ', 124);
01197         // ISO 8601 format date
01198         nstrftime (headertext, 124, "MATLAB 5.0 MAT-file, written by Octave "
01199                    OCTAVE_VERSION ", %Y-%m-%d %T UTC", &bdt, 1, 0);
01200 
01201         // The first pair of bytes give the version of the MAT file
01202         // format.  The second pair of bytes form a magic number which
01203         // signals a MAT file.  MAT file data are always written in
01204         // native byte order.  The order of the bytes in the second
01205         // pair indicates whether the file was written by a big- or
01206         // little-endian machine.  However, the version number is
01207         // written in the *opposite* byte order from everything else!
01208         if (number == 1)
01209           versionmagic = "\x01\x00\x4d\x49"; // this machine is big endian
01210         else
01211           versionmagic = "\x00\x01\x49\x4d"; // this machine is little endian
01212 
01213         memcpy (headertext+124, versionmagic, 4);
01214         os.write (headertext, 128);
01215       }
01216 
01217       break;
01218 
01219 #ifdef HAVE_HDF5
01220     case LS_HDF5:
01221 #endif /* HAVE_HDF5 */
01222     case LS_ASCII:
01223       {
01224         octave_localtime now;
01225 
01226         std::string comment_string = now.strftime (Vsave_header_format_string);
01227 
01228         if (! comment_string.empty ())
01229           {
01230 #ifdef HAVE_HDF5
01231             if (format == LS_HDF5)
01232               {
01233                 hdf5_ofstream& hs = dynamic_cast<hdf5_ofstream&> (os);
01234                 H5Gset_comment (hs.file_id, "/", comment_string.c_str ());
01235               }
01236             else
01237 #endif /* HAVE_HDF5 */
01238               os << comment_string << "\n";
01239           }
01240       }
01241     break;
01242 
01243     default:
01244       break;
01245     }
01246 }
01247 
01248 static void
01249 save_vars (const string_vector& argv, int argv_idx, int argc,
01250            std::ostream& os, load_save_format fmt,
01251            bool save_as_floats, bool write_header_info)
01252 {
01253   if (write_header_info)
01254     write_header (os, fmt);
01255 
01256   if (argv_idx == argc)
01257     {
01258       save_vars (os, "*", fmt, save_as_floats);
01259     }
01260   else if (argv[argv_idx] == "-struct")
01261     {
01262       if (++argv_idx >= argc)
01263         {
01264           error ("save: missing struct name");
01265           return;
01266         }
01267 
01268       std::string struct_name = argv[argv_idx];
01269 
01270       if (! symbol_table::is_variable (struct_name))
01271         {
01272           error ("save: no such variable: '%s'", struct_name.c_str ());
01273           return;
01274         }
01275 
01276       octave_value struct_var = symbol_table::varref (struct_name);
01277 
01278       if (! struct_var.is_map () || struct_var.numel () != 1)
01279         {
01280           error ("save: '%s' is not a scalar structure",
01281                  struct_name.c_str ());
01282           return;
01283         }
01284       octave_scalar_map struct_var_map = struct_var.scalar_map_value ();
01285 
01286       ++argv_idx;
01287 
01288       if (argv_idx < argc)
01289         {
01290           for (int i = argv_idx; i < argc; i++)
01291             {
01292               if (! save_fields (os, struct_var_map, argv[i], fmt,
01293                                  save_as_floats))
01294                 {
01295                   warning ("save: no such field '%s.%s'",
01296                            struct_name.c_str (), argv[i].c_str ());
01297                 }
01298             }
01299         }
01300       else
01301         save_fields (os, struct_var_map, "*", fmt, save_as_floats);
01302     }
01303   else
01304     {
01305       for (int i = argv_idx; i < argc; i++)
01306         {
01307           if (! save_vars (os, argv[i], fmt, save_as_floats))
01308             warning ("save: no such variable '%s'", argv[i].c_str ());
01309         }
01310     }
01311 }
01312 
01313 static void
01314 dump_octave_core (std::ostream& os, const char *fname, load_save_format fmt,
01315                   bool save_as_floats)
01316 {
01317   write_header (os, fmt);
01318 
01319   std::list<symbol_table::symbol_record> vars
01320     = symbol_table::all_variables (symbol_table::top_scope (), 0);
01321 
01322   double save_mem_size = 0;
01323 
01324   typedef std::list<symbol_table::symbol_record>::const_iterator const_vars_iterator;
01325 
01326   for (const_vars_iterator p = vars.begin (); p != vars.end (); p++)
01327     {
01328       octave_value val = p->varval ();
01329 
01330       if (val.is_defined ())
01331         {
01332           std::string name = p->name ();
01333           std::string help;
01334           bool global = p->is_global ();
01335 
01336           double val_size = val.byte_size () / 1024;
01337 
01338           // FIXME -- maybe we should try to throw out the largest first...
01339 
01340           if (Voctave_core_file_limit < 0
01341               || save_mem_size + val_size < Voctave_core_file_limit)
01342             {
01343               save_mem_size += val_size;
01344 
01345               do_save (os, val, name, help, global, fmt, save_as_floats);
01346 
01347               if (error_state)
01348                 break;
01349             }
01350         }
01351     }
01352 
01353   message (0, "save to '%s' complete", fname);
01354 }
01355 
01356 void
01357 dump_octave_core (void)
01358 {
01359   if (Vcrash_dumps_octave_core)
01360     {
01361       // FIXME -- should choose better file name?
01362 
01363       const char *fname = Voctave_core_file_name.c_str ();
01364 
01365       message (0, "attempting to save variables to '%s'...", fname);
01366 
01367       load_save_format format = LS_BINARY;
01368 
01369       bool save_as_floats = false;
01370 
01371       bool append = false;
01372 
01373       bool use_zlib = false;
01374 
01375       parse_save_options (Voctave_core_file_options, format, append,
01376                           save_as_floats, use_zlib);
01377 
01378       std::ios::openmode mode = std::ios::out;
01379 
01380       // Matlab v7 files are always compressed
01381       if (format == LS_MAT7_BINARY)
01382         use_zlib = false;
01383 
01384       if (format == LS_BINARY
01385 #ifdef HAVE_HDF5
01386           || format == LS_HDF5
01387 #endif
01388           || format == LS_MAT_BINARY
01389           || format == LS_MAT5_BINARY
01390           || format == LS_MAT7_BINARY)
01391         mode |= std::ios::binary;
01392 
01393       mode |= append ? std::ios::ate : std::ios::trunc;
01394 
01395 #ifdef HAVE_HDF5
01396       if (format == LS_HDF5)
01397         {
01398           hdf5_ofstream file (fname, mode);
01399 
01400           if (file.file_id >= 0)
01401             {
01402               dump_octave_core (file, fname, format, save_as_floats);
01403 
01404               file.close ();
01405             }
01406           else
01407             warning ("unable to open '%s' for writing...", fname);
01408         }
01409       else
01410 #endif /* HAVE_HDF5 */
01411         // don't insert any commands here!  The open brace below must
01412         // go with the else above!
01413         {
01414 #ifdef HAVE_ZLIB
01415           if (use_zlib)
01416             {
01417               gzofstream file (fname, mode);
01418 
01419               if (file)
01420                 {
01421                   dump_octave_core (file, fname, format, save_as_floats);
01422 
01423                   file.close ();
01424                 }
01425               else
01426                 warning ("unable to open '%s' for writing...", fname);
01427             }
01428           else
01429 #endif
01430             {
01431               std::ofstream file (fname, mode);
01432 
01433               if (file)
01434                 {
01435                   dump_octave_core (file, fname, format, save_as_floats);
01436 
01437                   file.close ();
01438                 }
01439               else
01440                 warning ("unable to open '%s' for writing...", fname);
01441             }
01442         }
01443     }
01444 }
01445 
01446 
01447 DEFUN (save, args, ,
01448   "-*- texinfo -*-\n\
01449 @deftypefn  {Command} {} save file\n\
01450 @deftypefnx {Command} {} save options file\n\
01451 @deftypefnx {Command} {} save options file @var{v1} @var{v2} @dots{}\n\
01452 @deftypefnx {Command} {} save options file -struct @var{STRUCT} @var{f1} @var{f2} @dots{}\n\
01453 Save the named variables @var{v1}, @var{v2}, @dots{}, in the file\n\
01454 @var{file}.  The special filename @samp{-} may be used to write\n\
01455 output to the terminal.  If no variable names are listed, Octave saves\n\
01456 all the variables in the current scope.  Otherwise, full variable names or\n\
01457 pattern syntax can be used to specify the variables to save.\n\
01458 If the @option{-struct} modifier is used, fields @var{f1} @var{f2} @dots{}\n\
01459 of the scalar structure @var{STRUCT} are saved as if they were variables\n\
01460 with corresponding names.\n\
01461 Valid options for the @code{save} command are listed in the following table.\n\
01462 Options that modify the output format override the format specified by\n\
01463 @code{default_save_options}.\n\
01464 \n\
01465 If save is invoked using the functional form\n\
01466 \n\
01467 @example\n\
01468 save (\"-option1\", @dots{}, \"file\", \"v1\", @dots{})\n\
01469 @end example\n\
01470 \n\
01471 @noindent\n\
01472 then the @var{options}, @var{file}, and variable name arguments\n\
01473 (@var{v1}, @dots{}) must be specified as character strings.\n\
01474 \n\
01475 @table @code\n\
01476 @item -append\n\
01477 Append to the destination instead of overwriting.\n\
01478 \n\
01479 @item -ascii\n\
01480 Save a single matrix in a text file without header or any other information.\n\
01481 \n\
01482 @item -binary\n\
01483 Save the data in Octave's binary data format.\n\
01484 \n\
01485 @item -float-binary\n\
01486 Save the data in Octave's binary data format but only using single\n\
01487 precision.  Only use this format if you know that all the\n\
01488 values to be saved can be represented in single precision.\n\
01489 \n\
01490 @item -hdf5\n\
01491 Save the data in @sc{hdf5} format.\n\
01492 (HDF5 is a free, portable binary format developed by the National\n\
01493 Center for Supercomputing Applications at the University of Illinois.)\n\
01494 This format is only available if Octave was built with a link to the\n\
01495 @sc{hdf5} libraries.\n\
01496 \n\
01497 @item -float-hdf5\n\
01498 Save the data in @sc{hdf5} format but only using single precision.\n\
01499 Only use this format if you know that all the\n\
01500 values to be saved can be represented in single precision.\n\
01501 \n\
01502 @item -V7\n\
01503 @itemx -v7\n\
01504 @itemx -7\n\
01505 @itemx -mat7-binary\n\
01506 Save the data in @sc{matlab}'s v7 binary data format.\n\
01507 \n\
01508 @item -V6\n\
01509 @itemx -v6\n\
01510 @itemx -6\n\
01511 @itemx -mat\n\
01512 @itemx -mat-binary\n\
01513 Save the data in @sc{matlab}'s v6 binary data format.\n\
01514 \n\
01515 @item -V4\n\
01516 @itemx -v4\n\
01517 @itemx -4\n\
01518 @itemx -mat4-binary\n\
01519 Save the data in the binary format written by @sc{matlab} version 4.\n\
01520 \n\
01521 @item -text\n\
01522 Save the data in Octave's text data format.  (default).\n\
01523 \n\
01524 @item -zip\n\
01525 @itemx -z\n\
01526 Use the gzip algorithm to compress the file.  This works equally on files\n\
01527 that are compressed with gzip outside of octave, and gzip can equally be\n\
01528 used to convert the files for backward compatibility.\n\
01529 This option is only available if Octave was built with a link to the zlib\n\
01530 libraries.\n\
01531 @end table\n\
01532 \n\
01533 The list of variables to save may use wildcard patterns containing\n\
01534 the following special characters:\n\
01535 @table @code\n\
01536 @item ?\n\
01537 Match any single character.\n\
01538 \n\
01539 @item *\n\
01540 Match zero or more characters.\n\
01541 \n\
01542 @item [ @var{list} ]\n\
01543 Match the list of characters specified by @var{list}.  If the first\n\
01544 character is @code{!} or @code{^}, match all characters except those\n\
01545 specified by @var{list}.  For example, the pattern @code{[a-zA-Z]} will\n\
01546 match all lower and uppercase alphabetic characters.\n\
01547 \n\
01548 Wildcards may also be used in the field name specifications when using\n\
01549 the @option{-struct} modifier (but not in the struct name itself).\n\
01550 \n\
01551 @end table\n\
01552 \n\
01553 Except when using the @sc{matlab} binary data file format or the\n\
01554 @samp{-ascii} format, saving global\n\
01555 variables also saves the global status of the variable.  If the variable\n\
01556 is restored at a later time using @samp{load}, it will be restored as a\n\
01557 global variable.\n\
01558 \n\
01559 The command\n\
01560 \n\
01561 @example\n\
01562 save -binary data a b*\n\
01563 @end example\n\
01564 \n\
01565 @noindent\n\
01566 saves the variable @samp{a} and all variables beginning with @samp{b} to\n\
01567 the file @file{data} in Octave's binary format.\n\
01568 @seealso{load, default_save_options, save_header_format_string, dlmread, csvread, fread}\n\
01569 @end deftypefn")
01570 {
01571   octave_value_list retval;
01572 
01573   int argc = args.length ();
01574 
01575   string_vector argv = args.make_argv ();
01576 
01577   if (error_state)
01578     return retval;
01579 
01580   // Here is where we would get the default save format if it were
01581   // stored in a user preference variable.
01582 
01583   bool save_as_floats = false;
01584 
01585   load_save_format format = LS_ASCII;
01586 
01587   bool append = false;
01588 
01589   bool use_zlib = false;
01590 
01591   // get default options
01592   parse_save_options (Vdefault_save_options, format, append, save_as_floats,
01593                       use_zlib);
01594 
01595   // override from command line
01596   argv = parse_save_options (argv, format, append, save_as_floats,
01597                              use_zlib);
01598   argc = argv.length ();
01599   int i = 0;
01600 
01601   if (error_state)
01602     return retval;
01603 
01604   if (i == argc)
01605     {
01606       print_usage ();
01607       return retval;
01608     }
01609 
01610   if (save_as_floats && format == LS_ASCII)
01611     {
01612       error ("save: cannot specify both -ascii and -float-binary");
01613       return retval;
01614     }
01615 
01616   if (argv[i] == "-")
01617     {
01618       i++;
01619 
01620 #ifdef HAVE_HDF5
01621       if (format == LS_HDF5)
01622         error ("save: cannot write HDF5 format to stdout");
01623       else
01624 #endif /* HAVE_HDF5 */
01625         // don't insert any commands here!  the brace below must go
01626         // with the "else" above!
01627         {
01628           if (append)
01629             warning ("save: ignoring -append option for output to stdout");
01630 
01631           // FIXME -- should things intended for the screen end up
01632           // in a octave_value (string)?
01633 
01634           save_vars (argv, i, argc, octave_stdout, format,
01635                      save_as_floats, true);
01636         }
01637     }
01638 
01639   // Guard against things like 'save a*', which are probably mistakes...
01640 
01641   else if (i == argc - 1 && glob_pattern_p (argv[i]))
01642     {
01643       print_usage ();
01644       return retval;
01645     }
01646   else
01647     {
01648       std::string fname = file_ops::tilde_expand (argv[i]);
01649 
01650       i++;
01651 
01652       // Matlab v7 files are always compressed
01653       if (format == LS_MAT7_BINARY)
01654         use_zlib = false;
01655 
01656       std::ios::openmode mode
01657         = append ? (std::ios::app | std::ios::ate) : std::ios::out;
01658 
01659       if (format == LS_BINARY
01660 #ifdef HAVE_HDF5
01661           || format == LS_HDF5
01662 #endif
01663           || format == LS_MAT_BINARY
01664           || format == LS_MAT5_BINARY
01665           || format == LS_MAT7_BINARY)
01666         mode |= std::ios::binary;
01667 
01668 #ifdef HAVE_HDF5
01669       if (format == LS_HDF5)
01670         {
01671           // FIXME. It should be possible to append to HDF5 files.
01672           if (append)
01673             {
01674               error ("save: appending to HDF5 files is not implemented");
01675               return retval;
01676             }
01677 
01678           bool write_header_info = ! (append &&
01679                                       H5Fis_hdf5 (fname.c_str ()) > 0);
01680 
01681           hdf5_ofstream hdf5_file (fname.c_str (), mode);
01682 
01683           if (hdf5_file.file_id != -1)
01684             {
01685               save_vars (argv, i, argc, hdf5_file, format,
01686                          save_as_floats, write_header_info);
01687 
01688               hdf5_file.close ();
01689           }
01690         else
01691           {
01692             gripe_file_open ("save", fname);
01693             return retval;
01694           }
01695         }
01696       else
01697 #endif /* HAVE_HDF5 */
01698         // don't insert any statements here!  The brace below must go
01699         // with the "else" above!
01700         {
01701 #ifdef HAVE_ZLIB
01702           if (use_zlib)
01703             {
01704               gzofstream file (fname.c_str (), mode);
01705 
01706               if (file)
01707                 {
01708                   bool write_header_info = ! file.tellp ();
01709 
01710                   save_vars (argv, i, argc, file, format,
01711                              save_as_floats, write_header_info);
01712 
01713                   file.close ();
01714                 }
01715               else
01716                 {
01717                   gripe_file_open ("save", fname);
01718                   return retval;
01719                 }
01720             }
01721           else
01722 #endif
01723             {
01724               std::ofstream file (fname.c_str (), mode);
01725 
01726               if (file)
01727                 {
01728                   bool write_header_info = ! file.tellp ();
01729 
01730                   save_vars (argv, i, argc, file, format,
01731                              save_as_floats, write_header_info);
01732 
01733                   file.close ();
01734                 }
01735               else
01736                 {
01737                   gripe_file_open ("save", fname);
01738                   return retval;
01739                 }
01740             }
01741         }
01742     }
01743 
01744   return retval;
01745 }
01746 
01747 DEFUN (crash_dumps_octave_core, args, nargout,
01748   "-*- texinfo -*-\n\
01749 @deftypefn  {Built-in Function} {@var{val} =} crash_dumps_octave_core ()\n\
01750 @deftypefnx {Built-in Function} {@var{old_val} =} crash_dumps_octave_core (@var{new_val})\n\
01751 @deftypefnx {Built-in Function} {} crash_dumps_octave_core (@var{new_val}, \"local\")\n\
01752 Query or set the internal variable that controls whether Octave tries\n\
01753 to save all current variables to the file \"octave-core\" if it\n\
01754 crashes or receives a hangup, terminate or similar signal.\n\
01755 \n\
01756 When called from inside a function with the \"local\" option, the variable is\n\
01757 changed locally for the function and any subroutines it calls.  The original\n\
01758 variable value is restored when exiting the function.\n\
01759 @seealso{octave_core_file_limit, octave_core_file_name, octave_core_file_options}\n\
01760 @end deftypefn")
01761 {
01762   return SET_INTERNAL_VARIABLE (crash_dumps_octave_core);
01763 }
01764 
01765 DEFUN (default_save_options, args, nargout,
01766   "-*- texinfo -*-\n\
01767 @deftypefn  {Built-in Function} {@var{val} =} default_save_options ()\n\
01768 @deftypefnx {Built-in Function} {@var{old_val} =} default_save_options (@var{new_val})\n\
01769 @deftypefnx {Built-in Function} {} default_save_options (@var{new_val}, \"local\")\n\
01770 Query or set the internal variable that specifies the default options\n\
01771 for the @code{save} command, and defines the default format.\n\
01772 Typical values include @code{\"-ascii\"}, @code{\"-text -zip\"}.\n\
01773 The default value is @option{-text}.\n\
01774 \n\
01775 When called from inside a function with the \"local\" option, the variable is\n\
01776 changed locally for the function and any subroutines it calls.  The original\n\
01777 variable value is restored when exiting the function.\n\
01778 @seealso{save}\n\
01779 @end deftypefn")
01780 {
01781   return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (default_save_options);
01782 }
01783 
01784 DEFUN (octave_core_file_limit, args, nargout,
01785   "-*- texinfo -*-\n\
01786 @deftypefn  {Built-in Function} {@var{val} =} octave_core_file_limit ()\n\
01787 @deftypefnx {Built-in Function} {@var{old_val} =} octave_core_file_limit (@var{new_val})\n\
01788 @deftypefnx {Built-in Function} {} octave_core_file_limit (@var{new_val}, \"local\")\n\
01789 Query or set the internal variable that specifies the maximum amount\n\
01790 of memory (in kilobytes) of the top-level workspace that Octave will\n\
01791 attempt to save when writing data to the crash dump file (the name of\n\
01792 the file is specified by @var{octave_core_file_name}).  If\n\
01793 @var{octave_core_file_options} flags specify a binary format,\n\
01794 then @var{octave_core_file_limit} will be approximately the maximum\n\
01795 size of the file.  If a text file format is used, then the file could\n\
01796 be much larger than the limit.  The default value is -1 (unlimited)\n\
01797 \n\
01798 When called from inside a function with the \"local\" option, the variable is\n\
01799 changed locally for the function and any subroutines it calls.  The original\n\
01800 variable value is restored when exiting the function.\n\
01801 @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_options}\n\
01802 @end deftypefn")
01803 {
01804   return SET_INTERNAL_VARIABLE (octave_core_file_limit);
01805 }
01806 
01807 DEFUN (octave_core_file_name, args, nargout,
01808   "-*- texinfo -*-\n\
01809 @deftypefn  {Built-in Function} {@var{val} =} octave_core_file_name ()\n\
01810 @deftypefnx {Built-in Function} {@var{old_val} =} octave_core_file_name (@var{new_val})\n\
01811 @deftypefnx {Built-in Function} {} octave_core_file_name (@var{new_val}, \"local\")\n\
01812 Query or set the internal variable that specifies the name of the file\n\
01813 used for saving data from the top-level workspace if Octave aborts.\n\
01814 The default value is @code{\"octave-core\"}\n\
01815 \n\
01816 When called from inside a function with the \"local\" option, the variable is\n\
01817 changed locally for the function and any subroutines it calls.  The original\n\
01818 variable value is restored when exiting the function.\n\
01819 @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_options}\n\
01820 @end deftypefn")
01821 {
01822   return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (octave_core_file_name);
01823 }
01824 
01825 DEFUN (octave_core_file_options, args, nargout,
01826   "-*- texinfo -*-\n\
01827 @deftypefn  {Built-in Function} {@var{val} =} octave_core_file_options ()\n\
01828 @deftypefnx {Built-in Function} {@var{old_val} =} octave_core_file_options (@var{new_val})\n\
01829 @deftypefnx {Built-in Function} {} octave_core_file_options (@var{new_val}, \"local\")\n\
01830 Query or set the internal variable that specifies the options used for\n\
01831 saving the workspace data if Octave aborts.  The value of\n\
01832 @code{octave_core_file_options} should follow the same format as the\n\
01833 options for the @code{save} function.  The default value is Octave's binary\n\
01834 format.\n\
01835 \n\
01836 When called from inside a function with the \"local\" option, the variable is\n\
01837 changed locally for the function and any subroutines it calls.  The original\n\
01838 variable value is restored when exiting the function.\n\
01839 @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_limit}\n\
01840 @end deftypefn")
01841 {
01842   return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (octave_core_file_options);
01843 }
01844 
01845 DEFUN (save_header_format_string, args, nargout,
01846   "-*- texinfo -*-\n\
01847 @deftypefn  {Built-in Function} {@var{val} =} save_header_format_string ()\n\
01848 @deftypefnx {Built-in Function} {@var{old_val} =} save_header_format_string (@var{new_val})\n\
01849 @deftypefnx {Built-in Function} {} save_header_format_string (@var{new_val}, \"local\")\n\
01850 Query or set the internal variable that specifies the format\n\
01851 string used for the comment line written at the beginning of\n\
01852 text-format data files saved by Octave.  The format string is\n\
01853 passed to @code{strftime} and should begin with the character\n\
01854 @samp{#} and contain no newline characters.  If the value of\n\
01855 @code{save_header_format_string} is the empty string,\n\
01856 the header comment is omitted from text-format data files.  The\n\
01857 default value is\n\
01858 @c Set example in small font to prevent overfull line\n\
01859 \n\
01860 @smallexample\n\
01861 \"# Created by Octave VERSION, %a %b %d %H:%M:%S %Y %Z <USER@@HOST>\"\n\
01862 @end smallexample\n\
01863 \n\
01864 When called from inside a function with the \"local\" option, the variable is\n\
01865 changed locally for the function and any subroutines it calls.  The original\n\
01866 variable value is restored when exiting the function.\n\
01867 @seealso{strftime, save}\n\
01868 @end deftypefn")
01869 {
01870   return SET_INTERNAL_VARIABLE (save_header_format_string);
01871 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines