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