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