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