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