604
|
1 // load-save.cc -*- C++ -*- |
|
2 /* |
|
3 |
|
4 Copyright (C) 1992, 1993, 1994 John W. Eaton |
|
5 |
|
6 This file is part of Octave. |
|
7 |
|
8 Octave is free software; you can redistribute it and/or modify it |
|
9 under the terms of the GNU General Public License as published by the |
|
10 Free Software Foundation; either version 2, or (at your option) any |
|
11 later version. |
|
12 |
|
13 Octave is distributed in the hope that it will be useful, but WITHOUT |
|
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
16 for more details. |
|
17 |
|
18 You should have received a copy of the GNU General Public License |
|
19 along with Octave; see the file COPYING. If not, write to the Free |
|
20 Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
21 |
|
22 */ |
|
23 |
|
24 #ifdef HAVE_CONFIG_H |
|
25 #include "config.h" |
|
26 #endif |
|
27 |
|
28 #include <limits.h> |
|
29 #include <string.h> |
|
30 #include <iostream.h> |
|
31 #include <fstream.h> |
|
32 #include <strstream.h> |
|
33 #include <ctype.h> |
|
34 |
|
35 #include "tree-base.h" |
|
36 #include "tree-expr.h" |
|
37 #include "tree-const.h" |
|
38 #include "user-prefs.h" |
|
39 #include "load-save.h" |
|
40 #include "symtab.h" |
|
41 #include "error.h" |
|
42 #include "defun.h" |
|
43 #include "utils.h" |
|
44 #include "help.h" |
|
45 |
|
46 extern "C" |
|
47 { |
|
48 #include <readline/tilde.h> |
|
49 |
|
50 #include "fnmatch.h" |
|
51 } |
|
52 |
|
53 #if CHAR_BIT != 8 |
|
54 LOSE! LOSE! |
|
55 #endif |
|
56 |
|
57 #if SIZEOF_SHORT == 2 |
|
58 #define TWO_BYTE_INT short |
|
59 #elif SIZEOF_INT == 2 |
|
60 #define TWO_BYTE_INT int |
|
61 #else |
|
62 LOSE! LOSE! |
|
63 #endif |
|
64 |
|
65 #if SIZEOF_INT == 4 |
|
66 #define FOUR_BYTE_INT int |
|
67 #elif SIZEOF_LONG == 4 |
|
68 #define FOUR_BYTE_INT long |
|
69 #else |
|
70 LOSE! LOSE! |
|
71 #endif |
|
72 |
|
73 enum load_save_format |
|
74 { |
|
75 LS_ASCII, |
|
76 LS_BINARY, |
|
77 LS_MAT_BINARY, |
|
78 LS_UNKNOWN, |
|
79 }; |
|
80 |
|
81 enum floating_point_format |
|
82 { |
|
83 LS_IEEE_LITTLE, |
|
84 LS_IEEE_BIG, |
|
85 LS_VAX_D, |
|
86 LS_VAX_G, |
|
87 LS_CRAY, |
|
88 LS_UNKNOWN_FLT_FMT, |
|
89 }; |
|
90 |
617
|
91 // Not all of the following are currently used. |
|
92 |
604
|
93 enum save_type |
|
94 { |
|
95 LS_U_CHAR, |
|
96 LS_U_SHORT, |
617
|
97 LS_U_INT, |
|
98 LS_CHAR, |
604
|
99 LS_SHORT, |
|
100 LS_INT, |
617
|
101 LS_FLOAT, |
604
|
102 LS_DOUBLE, |
|
103 }; |
|
104 |
|
105 #if defined (IEEE_LITTLE_ENDIAN) |
|
106 #define NATIVE_FLOAT_FORMAT LS_IEEE_LITTLE |
|
107 #elif defined (IEEE_BIG_ENDIAN) |
|
108 #define NATIVE_FLOAT_FORMAT LS_IEEE_BIG |
|
109 #elif defined (VAX_D_FLOAT) |
|
110 #define NATIVE_FLOAT_FORMAT LS_VAX_D |
|
111 #elif defined (VAX_G_FLOAT) |
|
112 #define NATIVE_FLOAT_FORMAT LS_VAX_G |
|
113 #else |
|
114 LOSE! LOSE! |
|
115 #endif |
|
116 |
|
117 #define swap_1_bytes(x,y) |
|
118 |
|
119 #define LS_DO_READ(TYPE,data,size,len,stream) \ |
|
120 do \ |
|
121 { \ |
|
122 volatile TYPE *ptr = (TYPE *) data; \ |
|
123 stream.read ((TYPE *) ptr, size * len); \ |
|
124 swap_ ## size ## _bytes ((char *) ptr, len); \ |
|
125 TYPE tmp = ptr[0]; \ |
|
126 for (int i = len - 1; i > 0; i--) \ |
|
127 data[i] = ptr[i]; \ |
|
128 data[0] = tmp; \ |
|
129 } \ |
|
130 while (0) |
|
131 |
|
132 #define LS_DO_WRITE(TYPE,data,size,len,stream) \ |
|
133 do \ |
|
134 { \ |
|
135 char tmp_type = (char) type; \ |
|
136 stream.write (&tmp_type, 1); \ |
|
137 volatile TYPE *ptr = (TYPE *) data; \ |
|
138 TYPE tmp = (TYPE) data[0]; \ |
|
139 for (int i = 1; i < len; i++) \ |
|
140 ptr[i] = (TYPE) data[i]; \ |
|
141 ptr[0] = tmp; \ |
|
142 stream.write ((TYPE *) ptr, size * len); \ |
|
143 } \ |
|
144 while (0) |
|
145 |
|
146 // Loading variables from files. |
|
147 |
|
148 // But first, some data conversion routines. |
|
149 |
|
150 // Currently, we only handle conversions for the IEEE types. To fix |
|
151 // that, make more of the following routines work. |
|
152 |
|
153 #define LS_SWAP_BYTES(i,j) \ |
|
154 tmp = t[i]; \ |
|
155 t[i] = t[j]; \ |
|
156 t[j] = tmp; \ |
|
157 |
|
158 static inline void |
|
159 swap_2_bytes (char *t) |
|
160 { |
|
161 char tmp; |
|
162 LS_SWAP_BYTES (0, 1); |
|
163 } |
|
164 |
|
165 static inline void |
|
166 swap_4_bytes (char *t) |
|
167 { |
|
168 char tmp; |
|
169 LS_SWAP_BYTES (0, 3); |
|
170 LS_SWAP_BYTES (1, 2); |
|
171 } |
|
172 |
|
173 static inline void |
|
174 swap_8_bytes (char *t) |
|
175 { |
|
176 char tmp; |
|
177 LS_SWAP_BYTES (0, 7); |
|
178 LS_SWAP_BYTES (1, 6); |
|
179 LS_SWAP_BYTES (2, 5); |
|
180 LS_SWAP_BYTES (3, 4); |
|
181 } |
|
182 |
|
183 static inline void |
|
184 swap_2_bytes (char *t, int len) |
|
185 { |
|
186 char *ptr = t; |
|
187 for (int i = 0; i < len; i++) |
|
188 { |
|
189 swap_2_bytes (ptr); |
|
190 ptr += 2; |
|
191 } |
|
192 } |
|
193 |
|
194 static inline void |
|
195 swap_4_bytes (char *t, int len) |
|
196 { |
|
197 char *ptr = t; |
|
198 for (int i = 0; i < len; i++) |
|
199 { |
|
200 swap_4_bytes (ptr); |
|
201 ptr += 4; |
|
202 } |
|
203 } |
|
204 |
|
205 static inline void |
|
206 swap_8_bytes (char *t, int len) |
|
207 { |
|
208 char *ptr = t; |
|
209 for (int i = 0; i < len; i++) |
|
210 { |
|
211 swap_8_bytes (ptr); |
|
212 ptr += 8; |
|
213 } |
|
214 } |
|
215 |
|
216 // XXX FIXME XXX -- assumes sizeof (Complex) == 8 |
|
217 // XXX FIXME XXX -- assumes sizeof (double) == 8 |
|
218 // XXX FIXME XXX -- assumes sizeof (float) == 4 |
|
219 |
|
220 #if defined (IEEE_LITTLE_ENDIAN) |
|
221 |
|
222 static void |
|
223 IEEE_big_to_IEEE_little (double *d, int len) |
|
224 { |
|
225 swap_8_bytes ((char *) d, len); |
|
226 } |
|
227 |
|
228 static void |
|
229 VAX_D_to_IEEE_little (double *d, int len) |
|
230 { |
|
231 error ("unable to convert from VAX D float to IEEE little endian format"); |
|
232 } |
|
233 |
|
234 static void |
|
235 VAX_G_to_IEEE_little (double *d, int len) |
|
236 { |
|
237 error ("unable to convert from VAX G float to IEEE little endian format"); |
|
238 } |
|
239 |
|
240 static void |
|
241 Cray_to_IEEE_little (double *d, int len) |
|
242 { |
|
243 error ("unable to convert from Cray to IEEE little endian format"); |
|
244 } |
|
245 |
|
246 #elif defined (IEEE_BIG_ENDIAN) |
|
247 |
|
248 static void |
|
249 IEEE_little_to_IEEE_big (double *d, int len) |
|
250 { |
|
251 swap_8_bytes ((char *) d, len); |
|
252 } |
|
253 |
|
254 static void |
|
255 VAX_D_to_IEEE_big (double *d, int len) |
|
256 { |
|
257 error ("unable to convert from VAX D float to IEEE big endian format"); |
|
258 } |
|
259 |
|
260 static void |
|
261 VAX_G_to_IEEE_big (double *d, int len) |
|
262 { |
|
263 error ("unable to convert from VAX G float to IEEE big endian format"); |
|
264 } |
|
265 |
|
266 static void |
|
267 Cray_to_IEEE_big (double *d, int len) |
|
268 { |
|
269 error ("unable to convert from Cray to IEEE big endian format"); |
|
270 } |
|
271 |
|
272 #elif defined (VAX_D_FLOAT) |
|
273 |
|
274 static void |
|
275 IEEE_little_to_VAX_D (double *d, int len) |
|
276 { |
|
277 error ("unable to convert from IEEE little endian to VAX D float format"); |
|
278 } |
|
279 |
|
280 static void |
|
281 IEEE_big_to_VAX_D (double *d, int len) |
|
282 { |
|
283 error ("unable to convert from IEEE big endian to VAX D float format"); |
|
284 } |
|
285 |
|
286 static void |
|
287 VAX_G_to_VAX_D (double *d, int len) |
|
288 { |
|
289 error ("unable to convert from VAX G float to VAX D float format"); |
|
290 } |
|
291 |
|
292 static void |
|
293 Cray_to_VAX_D (double *d, int len) |
|
294 { |
|
295 error ("unable to convert from Cray to VAX D float format"); |
|
296 } |
|
297 |
|
298 #elif defined (VAX_G_FLOAT) |
|
299 |
|
300 static void |
|
301 IEEE_little_to_VAX_G (double *d, int len) |
|
302 { |
|
303 error ("unable to convert from IEEE little endian to VAX G float format"); |
|
304 } |
|
305 |
|
306 static void |
|
307 IEEE_big_to_VAX_G (double *d, int len) |
|
308 { |
|
309 error ("unable to convert from IEEE big endian to VAX G float format"); |
|
310 } |
|
311 |
|
312 static void |
|
313 VAX_D_to_VAX_G (double *d, int len) |
|
314 { |
|
315 error ("unable to convert from VAX D float to VAX G float format"); |
|
316 } |
|
317 |
|
318 static void |
|
319 Cray_to_VAX_G (double *d, int len) |
|
320 { |
|
321 error ("unable to convert from VAX G float to VAX G float format"); |
|
322 } |
|
323 |
|
324 #endif |
|
325 |
|
326 static void |
|
327 do_float_format_conversion (double *data, int len, |
|
328 floating_point_format fmt) |
|
329 { |
|
330 switch (fmt) |
|
331 { |
|
332 #if defined (IEEE_LITTLE_ENDIAN) |
|
333 |
|
334 case LS_IEEE_LITTLE: |
|
335 break; |
|
336 |
|
337 case LS_IEEE_BIG: |
|
338 IEEE_big_to_IEEE_little (data, len); |
|
339 break; |
|
340 |
|
341 case LS_VAX_D: |
|
342 VAX_D_to_IEEE_little (data, len); |
|
343 break; |
|
344 |
|
345 case LS_VAX_G: |
|
346 VAX_G_to_IEEE_little (data, len); |
|
347 break; |
|
348 |
|
349 case LS_CRAY: |
|
350 Cray_to_IEEE_little (data, len); |
|
351 break; |
|
352 |
|
353 #elif defined (IEEE_BIG_ENDIAN) |
|
354 |
|
355 case LS_IEEE_LITTLE: |
|
356 IEEE_little_to_IEEE_big (data, len); |
|
357 break; |
|
358 |
|
359 case LS_IEEE_BIG: |
|
360 break; |
|
361 |
|
362 case LS_VAX_D: |
|
363 VAX_D_to_IEEE_big (data, len); |
|
364 break; |
|
365 |
|
366 case LS_VAX_G: |
|
367 VAX_G_to_IEEE_big (data, len); |
|
368 break; |
|
369 |
|
370 case LS_CRAY: |
|
371 Cray_to_IEEE_big (data, len); |
|
372 break; |
|
373 |
|
374 #elif defined (VAX_D_FLOAT) |
|
375 |
|
376 case LS_IEEE_LITTLE: |
|
377 IEEE_little_to_VAX_D (data, len); |
|
378 break; |
|
379 |
|
380 case LS_IEEE_BIG: |
|
381 IEEE_big_to_VAX_D (data, len); |
|
382 break; |
|
383 |
|
384 case LS_VAX_D: |
|
385 break; |
|
386 |
|
387 case LS_VAX_G: |
|
388 VAX_G_to_VAX_D (data, len); |
|
389 break; |
|
390 |
|
391 case LS_CRAY: |
|
392 Cray_to_VAX_D (data, len); |
|
393 break; |
|
394 |
|
395 #elif defined (VAX_G_FLOAT) |
|
396 |
|
397 case LS_IEEE_LITTLE: |
|
398 IEEE_little_to_VAX_G (data, len); |
|
399 break; |
|
400 |
|
401 case LS_IEEE_BIG: |
|
402 IEEE_big_to_VAX_G (data, len); |
|
403 break; |
|
404 |
|
405 case LS_VAX_D: |
|
406 VAX_D_to_VAX_G (data, len); |
|
407 break; |
|
408 |
|
409 case LS_VAX_G: |
|
410 break; |
|
411 |
|
412 case LS_CRAY: |
|
413 Cray_to_VAX_G (data, len); |
|
414 break; |
|
415 |
|
416 #else |
|
417 LOSE! LOSE! |
|
418 #endif |
|
419 |
|
420 default: |
|
421 panic_impossible (); |
|
422 break; |
|
423 } |
|
424 } |
|
425 |
|
426 static void |
|
427 read_doubles (istream& is, double *data, save_type type, int len, |
|
428 int swap, floating_point_format fmt) |
|
429 { |
|
430 switch (type) |
|
431 { |
|
432 case LS_U_CHAR: |
|
433 LS_DO_READ (unsigned char, data, 1, len, is); |
|
434 break; |
|
435 |
|
436 case LS_U_SHORT: |
|
437 LS_DO_READ (unsigned TWO_BYTE_INT, data, 2, len, is); |
|
438 break; |
|
439 |
618
|
440 case LS_U_INT: |
|
441 LS_DO_READ (unsigned FOUR_BYTE_INT, data, 4, len, is); |
|
442 break; |
|
443 |
|
444 case LS_CHAR: |
|
445 LS_DO_READ (signed char, data, 1, len, is); |
|
446 break; |
|
447 |
604
|
448 case LS_SHORT: |
|
449 LS_DO_READ (TWO_BYTE_INT, data, 2, len, is); |
|
450 break; |
|
451 |
|
452 case LS_INT: |
|
453 LS_DO_READ (FOUR_BYTE_INT, data, 4, len, is); |
|
454 break; |
|
455 |
|
456 case LS_DOUBLE: |
|
457 is.read (data, 8 * len); |
|
458 do_float_format_conversion (data, len, fmt); |
|
459 break; |
|
460 |
|
461 default: |
|
462 is.clear (ios::failbit|is.rdstate ()); |
|
463 break; |
|
464 } |
|
465 } |
|
466 |
|
467 static void |
|
468 write_doubles (ostream& os, double *data, save_type type, int len) |
|
469 { |
|
470 switch (type) |
|
471 { |
|
472 case LS_U_CHAR: |
|
473 LS_DO_WRITE (unsigned char, data, 1, len, os); |
|
474 break; |
|
475 |
|
476 case LS_U_SHORT: |
|
477 LS_DO_WRITE (unsigned TWO_BYTE_INT, data, 2, len, os); |
|
478 break; |
|
479 |
617
|
480 case LS_U_INT: |
|
481 LS_DO_WRITE (unsigned FOUR_BYTE_INT, data, 4, len, os); |
|
482 break; |
|
483 |
|
484 case LS_CHAR: |
|
485 LS_DO_WRITE (signed char, data, 1, len, os); |
|
486 break; |
|
487 |
604
|
488 case LS_SHORT: |
|
489 LS_DO_WRITE (TWO_BYTE_INT, data, 2, len, os); |
|
490 break; |
|
491 |
|
492 case LS_INT: |
|
493 LS_DO_WRITE (FOUR_BYTE_INT, data, 4, len, os); |
|
494 break; |
|
495 |
|
496 case LS_DOUBLE: |
|
497 { |
|
498 char tmp_type = (char) type; |
|
499 os.write (&tmp_type, 1); |
|
500 os.write (data, 8 * len); |
|
501 } |
|
502 break; |
|
503 |
|
504 default: |
|
505 panic_impossible (); |
|
506 break; |
|
507 } |
|
508 } |
|
509 |
|
510 // Return nonzero if S is a valid identifier. |
|
511 |
|
512 static int |
|
513 valid_identifier (char *s) |
|
514 { |
|
515 if (! s || ! (isalnum (*s) || *s == '_')) |
|
516 return 0; |
|
517 |
|
518 while (*++s != '\0') |
|
519 if (! (isalnum (*s) || *s == '_')) |
|
520 return 0; |
|
521 |
|
522 return 1; |
|
523 } |
|
524 |
|
525 // Return nonzero if any element of M is not an integer. Also extract |
|
526 // the largest and smallest values and return them in MAX_VAL and MIN_VAL. |
|
527 |
|
528 static int |
|
529 all_parts_int (const Matrix& m, double& max_val, double& min_val) |
|
530 { |
|
531 int nr = m.rows (); |
|
532 int nc = m.columns (); |
|
533 |
|
534 if (nr > 0 && nc > 0) |
|
535 { |
|
536 max_val = m.elem (0, 0); |
|
537 min_val = m.elem (0, 0); |
|
538 } |
|
539 else |
|
540 return 0; |
|
541 |
|
542 for (int j = 0; j < nc; j++) |
|
543 for (int i = 0; i < nr; i++) |
|
544 { |
|
545 double val = m.elem (i, j); |
|
546 |
|
547 if (val > max_val) |
|
548 max_val = val; |
|
549 |
|
550 if (val < min_val) |
|
551 min_val = val; |
|
552 |
|
553 if (D_NINT (val) != val) |
|
554 return 0; |
|
555 } |
|
556 return 1; |
|
557 } |
|
558 |
|
559 // Return nonzero if any element of CM has a non-integer real or |
|
560 // imaginary part. Also extract the largest and smallest (real or |
|
561 // imaginary) values and return them in MAX_VAL and MIN_VAL. |
|
562 |
|
563 static int |
|
564 all_parts_int (const ComplexMatrix& m, double& max_val, double& min_val) |
|
565 { |
|
566 int nr = m.rows (); |
|
567 int nc = m.columns (); |
|
568 |
|
569 if (nr > 0 && nc > 0) |
|
570 { |
|
571 Complex val = m.elem (0, 0); |
|
572 |
|
573 double r_val = real (val); |
|
574 double i_val = imag (val); |
|
575 |
|
576 max_val = r_val; |
|
577 min_val = r_val; |
|
578 |
|
579 if (i_val > max_val) |
|
580 max_val = i_val; |
|
581 |
|
582 if (i_val < max_val) |
|
583 min_val = i_val; |
|
584 } |
|
585 else |
|
586 return 0; |
|
587 |
|
588 for (int j = 0; j < nc; j++) |
|
589 for (int i = 0; i < nr; i++) |
|
590 { |
|
591 Complex val = m.elem (i, j); |
|
592 |
|
593 double r_val = real (val); |
|
594 double i_val = imag (val); |
|
595 |
|
596 if (r_val > max_val) |
|
597 max_val = r_val; |
|
598 |
|
599 if (i_val > max_val) |
|
600 max_val = i_val; |
|
601 |
|
602 if (r_val < min_val) |
|
603 min_val = r_val; |
|
604 |
|
605 if (i_val < min_val) |
|
606 min_val = i_val; |
|
607 |
|
608 if (D_NINT (r_val) != r_val || D_NINT (i_val) != i_val) |
|
609 return 0; |
|
610 } |
|
611 return 1; |
|
612 } |
|
613 |
|
614 // Shouldn't this be implemented in terms of other functions that are |
|
615 // already available? |
|
616 |
|
617 // Install a variable with name NAME and the value specified TC in the |
|
618 // symbol table. If FORCE is nonzero, replace any existing definition |
|
619 // for NAME. If GLOBAL is nonzero, make the variable global. |
|
620 // |
|
621 // Assumes TC is defined. |
|
622 |
|
623 static void |
|
624 install_loaded_variable (int force, char *name, const tree_constant& tc, |
|
625 int global, char *doc) |
|
626 { |
|
627 // Is there already a symbol by this name? If so, what is it? |
|
628 |
|
629 symbol_record *lsr = curr_sym_tab->lookup (name, 0, 0); |
|
630 |
|
631 int is_undefined = 1; |
|
632 int is_variable = 0; |
|
633 int is_function = 0; |
|
634 int is_global = 0; |
|
635 |
|
636 if (lsr) |
|
637 { |
|
638 is_undefined = ! lsr->is_defined (); |
|
639 is_variable = lsr->is_variable (); |
|
640 is_function = lsr->is_function (); |
|
641 is_global = lsr->is_linked_to_global (); |
|
642 } |
|
643 |
|
644 symbol_record *sr = 0; |
|
645 |
|
646 if (global) |
|
647 { |
|
648 if (is_global || is_undefined) |
|
649 { |
|
650 if (force || is_undefined) |
|
651 { |
|
652 lsr = curr_sym_tab->lookup (name, 1, 0); |
|
653 link_to_global_variable (lsr); |
|
654 sr = lsr; |
|
655 } |
|
656 else |
|
657 { |
|
658 warning ("load: global variable name `%s' exists.", name); |
|
659 warning ("use `load -force' to overwrite"); |
|
660 } |
|
661 } |
|
662 else if (is_function) |
|
663 { |
|
664 if (force) |
|
665 { |
|
666 lsr = curr_sym_tab->lookup (name, 1, 0); |
|
667 link_to_global_variable (lsr); |
|
668 sr = lsr; |
|
669 } |
|
670 else |
|
671 { |
|
672 warning ("load: `%s' is currently a function in this scope", name); |
|
673 warning ("`load -force' will load variable and hide function"); |
|
674 } |
|
675 } |
|
676 else if (is_variable) |
|
677 { |
|
678 if (force) |
|
679 { |
|
680 lsr = curr_sym_tab->lookup (name, 1, 0); |
|
681 link_to_global_variable (lsr); |
|
682 sr = lsr; |
|
683 } |
|
684 else |
|
685 { |
|
686 warning ("load: local variable name `%s' exists.", name); |
|
687 warning ("use `load -force' to overwrite"); |
|
688 } |
|
689 } |
|
690 else |
|
691 panic_impossible (); |
|
692 } |
|
693 else |
|
694 { |
|
695 if (is_global) |
|
696 { |
|
697 if (force || is_undefined) |
|
698 { |
|
699 lsr = curr_sym_tab->lookup (name, 1, 0); |
|
700 link_to_global_variable (lsr); |
|
701 sr = lsr; |
|
702 } |
|
703 else |
|
704 { |
|
705 warning ("load: global variable name `%s' exists.", name); |
|
706 warning ("use `load -force' to overwrite"); |
|
707 } |
|
708 } |
|
709 else if (is_function) |
|
710 { |
|
711 if (force) |
|
712 { |
|
713 lsr = curr_sym_tab->lookup (name, 1, 0); |
|
714 link_to_global_variable (lsr); |
|
715 sr = lsr; |
|
716 } |
|
717 else |
|
718 { |
|
719 warning ("load: `%s' is currently a function in this scope", name); |
|
720 warning ("`load -force' will load variable and hide function"); |
|
721 } |
|
722 } |
|
723 else if (is_variable || is_undefined) |
|
724 { |
|
725 if (force || is_undefined) |
|
726 { |
|
727 lsr = curr_sym_tab->lookup (name, 1, 0); |
|
728 sr = lsr; |
|
729 } |
|
730 else |
|
731 { |
|
732 warning ("load: local variable name `%s' exists.", name); |
|
733 warning ("use `load -force' to overwrite"); |
|
734 } |
|
735 } |
|
736 else |
|
737 panic_impossible (); |
|
738 } |
|
739 |
|
740 if (sr) |
|
741 { |
|
742 tree_constant *tmp_tc = new tree_constant (tc); |
|
743 sr->define (tmp_tc); |
|
744 if (doc) |
|
745 sr->document (doc); |
|
746 return; |
|
747 } |
|
748 else |
|
749 error ("load: unable to load variable `%s'", name); |
|
750 |
|
751 return; |
|
752 } |
|
753 |
|
754 // Functions for reading ascii data. |
|
755 |
|
756 // Skip white space and comments on stream IS. |
|
757 |
|
758 static void |
|
759 skip_comments (istream& is) |
|
760 { |
|
761 char c = '\0'; |
|
762 while (is.get (c)) |
|
763 { |
|
764 if (c == ' ' || c == '\t' || c == '\n') |
|
765 ; // Skip whitespace on way to beginning of next line. |
|
766 else |
|
767 break; |
|
768 } |
|
769 |
|
770 for (;;) |
|
771 { |
|
772 if (is && c == '#') |
|
773 while (is.get (c) && c != '\n') |
|
774 ; // Skip to beginning of next line, ignoring everything. |
|
775 else |
|
776 break; |
|
777 } |
|
778 } |
|
779 |
|
780 // Extract a KEYWORD and its value from stream IS, returning the |
|
781 // associated value in a new string. |
|
782 // |
|
783 // Input should look something like: |
|
784 // |
|
785 // #[ \t]*keyword[ \t]*:[ \t]*string-value\n |
|
786 |
|
787 static char * |
|
788 extract_keyword (istream& is, char *keyword) |
|
789 { |
|
790 ostrstream buf; |
|
791 |
|
792 char *retval = 0; |
|
793 |
|
794 char c; |
|
795 while (is.get (c)) |
|
796 { |
|
797 if (c == '#') |
|
798 { |
|
799 while (is.get (c) && (c == ' ' || c == '\t' || c == '#')) |
|
800 ; // Skip whitespace and comment characters. |
|
801 |
|
802 if (isalpha (c)) |
|
803 buf << c; |
|
804 |
|
805 while (is.get (c) && isalpha (c)) |
|
806 buf << c; |
|
807 |
|
808 buf << ends; |
|
809 char *tmp = buf.str (); |
|
810 int match = (strncmp (tmp, keyword, strlen (keyword)) == 0); |
|
811 delete [] tmp; |
|
812 |
|
813 if (match) |
|
814 { |
|
815 ostrstream value; |
|
816 while (is.get (c) && (c == ' ' || c == '\t' || c == ':')) |
|
817 ; // Skip whitespace and the colon. |
|
818 |
|
819 if (c != '\n') |
|
820 { |
|
821 value << c; |
|
822 while (is.get (c) && c != '\n') |
|
823 value << c; |
|
824 } |
|
825 value << ends; |
|
826 retval = value.str (); |
|
827 break; |
|
828 } |
|
829 } |
|
830 } |
|
831 return retval; |
|
832 } |
|
833 |
|
834 // Match KEYWORD on stream IS, placing the associated value in VALUE, |
|
835 // returning 1 if successful and 0 otherwise. |
|
836 // |
|
837 // Input should look something like: |
|
838 // |
|
839 // [ \t]*keyword[ \t]*int-value\n |
|
840 |
|
841 static int |
|
842 extract_keyword (istream& is, char *keyword, int& value) |
|
843 { |
|
844 ostrstream buf; |
|
845 |
|
846 int status = 0; |
|
847 value = 0; |
|
848 |
|
849 char c; |
|
850 while (is.get (c)) |
|
851 { |
|
852 if (c == '#') |
|
853 { |
|
854 while (is.get (c) && (c == ' ' || c == '\t' || c == '#')) |
|
855 ; // Skip whitespace and comment characters. |
|
856 |
|
857 if (isalpha (c)) |
|
858 buf << c; |
|
859 |
|
860 while (is.get (c) && isalpha (c)) |
|
861 buf << c; |
|
862 |
|
863 buf << ends; |
|
864 char *tmp = buf.str (); |
|
865 int match = (strncmp (tmp, keyword, strlen (keyword)) == 0); |
|
866 delete [] tmp; |
|
867 |
|
868 if (match) |
|
869 { |
|
870 while (is.get (c) && (c == ' ' || c == '\t' || c == ':')) |
|
871 ; // Skip whitespace and the colon. |
|
872 |
|
873 is.putback (c); |
|
874 if (c != '\n') |
|
875 is >> value; |
|
876 if (is) |
|
877 status = 1; |
|
878 while (is.get (c) && c != '\n') |
|
879 ; // Skip to beginning of next line; |
|
880 break; |
|
881 } |
|
882 } |
|
883 } |
|
884 return status; |
|
885 } |
|
886 |
|
887 // Extract one value (scalar, matrix, string, etc.) from stream IS and |
|
888 // place it in TC, returning the name of the variable. If the value |
|
889 // is tagged as global in the file, return nonzero in GLOBAL. |
|
890 // |
|
891 // FILENAME is used for error messages. |
|
892 // |
|
893 // The data is expected to be in the following format: |
|
894 // |
|
895 // The input file must have a header followed by some data. |
|
896 // |
|
897 // All lines in the header must begin with a `#' character. |
|
898 // |
|
899 // The header must contain a list of keyword and value pairs with the |
|
900 // keyword and value separated by a colon. |
|
901 // |
|
902 // Keywords must appear in the following order: |
|
903 // |
|
904 // # name: <name> |
|
905 // # type: <type> |
|
906 // # <info> |
|
907 // |
|
908 // Where: |
|
909 // |
|
910 // <name> : a valid identifier |
|
911 // |
|
912 // <type> : <typename> |
|
913 // | global <typename> |
|
914 // |
|
915 // <typename> : scalar |
|
916 // | complex scalar |
|
917 // | matrix |
|
918 // | complex matrix |
|
919 // | string |
|
920 // | range |
|
921 // |
|
922 // <info> : <matrix info> |
|
923 // | <string info> |
|
924 // |
|
925 // <matrix info> : # rows: <integer> |
|
926 // | # columns: <integer> |
|
927 // |
|
928 // <string info> : # len: <integer> |
|
929 // |
|
930 // Formatted ASCII data follows the header. |
|
931 // |
|
932 // Example: |
|
933 // |
|
934 // # name: foo |
|
935 // # type: matrix |
|
936 // # rows: 2 |
|
937 // # columns: 2 |
|
938 // 2 4 |
|
939 // 1 3 |
|
940 // |
|
941 // XXX FIXME XXX -- this format is fairly rigid, and doesn't allow for |
|
942 // arbitrary comments, etc. Someone should fix that. |
|
943 |
|
944 static char * |
|
945 read_ascii_data (istream& is, const char *filename, int& global, |
|
946 tree_constant& tc) |
|
947 { |
|
948 // Read name for this entry or break on EOF. |
|
949 |
|
950 char *name = extract_keyword (is, "name"); |
|
951 |
|
952 if (! name) |
|
953 return 0; |
|
954 |
|
955 if (! *name) |
|
956 { |
|
957 error ("load: empty name keyword found in file `%s'", filename); |
|
958 delete [] name; |
|
959 return 0; |
|
960 } |
|
961 |
|
962 |
|
963 if (! valid_identifier (name)) |
|
964 { |
|
965 error ("load: bogus identifier `%s' found in file `%s'", name, filename); |
|
966 delete [] name; |
|
967 return 0; |
|
968 } |
|
969 |
|
970 // Look for type keyword |
|
971 |
|
972 char *tag = extract_keyword (is, "type"); |
|
973 |
|
974 if (tag && *tag) |
|
975 { |
|
976 char *ptr = strchr (tag, ' '); |
|
977 if (ptr) |
|
978 { |
|
979 *ptr = '\0'; |
|
980 global = (strncmp (tag, "global", 6) == 0); |
|
981 *ptr = ' '; |
|
982 if (global) |
|
983 ptr++; |
|
984 else |
|
985 ptr = tag; |
|
986 } |
|
987 else |
|
988 ptr = tag; |
|
989 |
|
990 if (strncmp (ptr, "scalar", 6) == 0) |
|
991 { |
|
992 double tmp; |
|
993 is >> tmp; |
|
994 if (is) |
|
995 tc = tmp; |
|
996 else |
|
997 error ("load: failed to load scalar constant"); |
|
998 } |
|
999 else if (strncmp (ptr, "matrix", 6) == 0) |
|
1000 { |
|
1001 int nr = 0, nc = 0; |
|
1002 |
|
1003 if (extract_keyword (is, "rows", nr) && nr > 0 |
|
1004 && extract_keyword (is, "columns", nc) && nc > 0) |
|
1005 { |
|
1006 Matrix tmp (nr, nc); |
|
1007 is >> tmp; |
|
1008 if (is) |
|
1009 tc = tmp; |
|
1010 else |
|
1011 error ("load: failed to load matrix constant"); |
|
1012 } |
|
1013 else |
|
1014 error ("load: failed to extract number of rows and columns"); |
|
1015 } |
|
1016 else if (strncmp (ptr, "complex scalar", 14) == 0) |
|
1017 { |
|
1018 Complex tmp; |
|
1019 is >> tmp; |
|
1020 if (is) |
|
1021 tc = tmp; |
|
1022 else |
|
1023 error ("load: failed to load complex scalar constant"); |
|
1024 } |
|
1025 else if (strncmp (ptr, "complex matrix", 14) == 0) |
|
1026 { |
|
1027 int nr = 0, nc = 0; |
|
1028 |
|
1029 if (extract_keyword (is, "rows", nr) && nr > 0 |
|
1030 && extract_keyword (is, "columns", nc) && nc > 0) |
|
1031 { |
|
1032 ComplexMatrix tmp (nr, nc); |
|
1033 is >> tmp; |
|
1034 if (is) |
|
1035 tc = tmp; |
|
1036 else |
|
1037 error ("load: failed to load complex matrix constant"); |
|
1038 } |
|
1039 else |
|
1040 error ("load: failed to extract number of rows and columns"); |
|
1041 } |
|
1042 else if (strncmp (ptr, "string", 6) == 0) |
|
1043 { |
|
1044 int len; |
|
1045 if (extract_keyword (is, "length", len) && len > 0) |
|
1046 { |
|
1047 char *tmp = new char [len+1]; |
|
1048 is.get (tmp, len+1, EOF); |
|
1049 if (is) |
|
1050 tc = tmp; |
|
1051 else |
|
1052 error ("load: failed to load string constant"); |
|
1053 } |
|
1054 else |
|
1055 error ("load: failed to extract string length"); |
|
1056 } |
|
1057 else if (strncmp (ptr, "range", 5) == 0) |
|
1058 { |
|
1059 // # base, limit, range comment added by save(). |
|
1060 skip_comments (is); |
|
1061 Range tmp; |
|
1062 is >> tmp; |
|
1063 if (is) |
|
1064 tc = tmp; |
|
1065 else |
|
1066 error ("load: failed to load range constant"); |
|
1067 } |
|
1068 else |
|
1069 error ("load: unknown constant type `%s'", tag); |
|
1070 } |
|
1071 else |
|
1072 error ("load: failed to extract keyword specifying value type"); |
|
1073 |
|
1074 delete [] tag; |
|
1075 |
|
1076 if (error_state) |
|
1077 { |
|
1078 error ("load: reading file %s", filename); |
|
1079 return 0; |
|
1080 } |
|
1081 |
|
1082 return name; |
|
1083 } |
|
1084 |
|
1085 // Extract one value (scalar, matrix, string, etc.) from stream IS and |
|
1086 // place it in TC, returning the name of the variable. If the value |
|
1087 // is tagged as global in the file, return nonzero in GLOBAL. If SWAP |
|
1088 // is nonzero, swap bytes after reading. |
|
1089 // |
|
1090 // The data is expected to be in the following format: |
|
1091 // |
|
1092 // object type bytes |
|
1093 // ------ ---- ----- |
|
1094 // magic number string 10 |
|
1095 // |
|
1096 // float format integer 1 |
|
1097 // |
|
1098 // name_length integer 4 |
|
1099 // |
|
1100 // name string name_length |
|
1101 // |
|
1102 // doc_length integer 4 |
|
1103 // |
|
1104 // doc string doc_length |
|
1105 // |
|
1106 // global flag integer 1 |
|
1107 // |
|
1108 // data type integer 1 |
|
1109 // |
|
1110 // data: |
|
1111 // scalar real 8 |
|
1112 // |
|
1113 // complex scalar complex 16 |
|
1114 // |
|
1115 // matrix: |
|
1116 // rows integer 4 |
|
1117 // columns integer 4 |
|
1118 // data real r*c*8 |
|
1119 // |
|
1120 // complex matrix: |
|
1121 // rows integer 4 |
|
1122 // columns integer 4 |
|
1123 // data complex r*c*16 |
|
1124 // |
|
1125 // string: |
|
1126 // length int 4 |
|
1127 // data string length |
|
1128 // |
|
1129 // range: |
|
1130 // base real 8 |
|
1131 // limit real 8 |
|
1132 // increment real 8 |
|
1133 // |
|
1134 // FILENAME is used for error messages. |
|
1135 |
|
1136 static char * |
|
1137 read_binary_data (istream& is, int swap, floating_point_format fmt, |
|
1138 const char *filename, int& global, |
|
1139 tree_constant& tc, char *&doc) |
|
1140 { |
|
1141 char tmp = 0; |
|
1142 |
|
1143 FOUR_BYTE_INT name_len = 0, doc_len = 0; |
|
1144 char *name = 0; |
|
1145 |
|
1146 doc = 0; |
|
1147 |
|
1148 is.read (&name_len, 4); |
|
1149 if (! is) |
|
1150 { |
|
1151 if (! is.eof ()) |
|
1152 goto data_read_error; |
|
1153 return 0; |
|
1154 } |
|
1155 if (swap) |
|
1156 swap_4_bytes ((char *) &name_len); |
|
1157 |
|
1158 name = new char [name_len+1]; |
|
1159 name[name_len] = '\0'; |
|
1160 if (! is.read (name, name_len)) |
|
1161 goto data_read_error; |
|
1162 |
|
1163 is.read (&doc_len, 4); |
|
1164 if (! is) |
|
1165 goto data_read_error; |
|
1166 if (swap) |
|
1167 swap_4_bytes ((char *) &doc_len); |
|
1168 |
|
1169 doc = new char [doc_len+1]; |
|
1170 doc[doc_len] = '\0'; |
|
1171 if (! is.read (doc, doc_len)) |
|
1172 goto data_read_error; |
|
1173 |
|
1174 if (! is.read (&tmp, 1)) |
|
1175 goto data_read_error; |
|
1176 global = tmp ? 1 : 0; |
|
1177 |
|
1178 tmp = 0; |
|
1179 if (! is.read (&tmp, 1)) |
|
1180 goto data_read_error; |
|
1181 |
|
1182 switch (tmp) |
|
1183 { |
|
1184 case 1: |
|
1185 { |
|
1186 double dtmp; |
|
1187 if (! is.read (&dtmp, 8)) |
|
1188 goto data_read_error; |
|
1189 if (swap) |
|
1190 swap_8_bytes ((char *) &dtmp); |
|
1191 tc = dtmp; |
|
1192 } |
|
1193 break; |
|
1194 |
|
1195 case 2: |
|
1196 { |
|
1197 FOUR_BYTE_INT nr, nc; |
|
1198 if (! is.read (&nr, 4)) |
|
1199 goto data_read_error; |
|
1200 if (swap) |
|
1201 swap_4_bytes ((char *) &nr); |
|
1202 if (! is.read (&nc, 4)) |
|
1203 goto data_read_error; |
|
1204 if (swap) |
|
1205 swap_4_bytes ((char *) &nc); |
|
1206 if (! is.read (&tmp, 1)) |
|
1207 goto data_read_error; |
|
1208 Matrix m (nr, nc); |
|
1209 double *re = m.fortran_vec (); |
|
1210 int len = nr * nc; |
|
1211 read_doubles (is, re, (save_type) tmp, len, swap, fmt); |
|
1212 if (! is) |
|
1213 goto data_read_error; |
|
1214 tc = m; |
|
1215 } |
|
1216 break; |
|
1217 |
|
1218 case 3: |
|
1219 { |
|
1220 Complex ctmp; |
|
1221 if (! is.read (&ctmp, 16)) |
|
1222 goto data_read_error; |
|
1223 if (swap) |
|
1224 swap_8_bytes ((char *) &ctmp, 2); |
|
1225 tc = ctmp; |
|
1226 } |
|
1227 break; |
|
1228 |
|
1229 case 4: |
|
1230 { |
|
1231 FOUR_BYTE_INT nr, nc; |
|
1232 if (! is.read (&nr, 4)) |
|
1233 goto data_read_error; |
|
1234 if (swap) |
|
1235 swap_4_bytes ((char *) &nr); |
|
1236 if (! is.read (&nc, 4)) |
|
1237 goto data_read_error; |
|
1238 if (swap) |
|
1239 swap_4_bytes ((char *) &nc); |
|
1240 if (! is.read (&tmp, 1)) |
|
1241 goto data_read_error; |
|
1242 ComplexMatrix m (nr, nc); |
|
1243 Complex *im = m.fortran_vec (); |
|
1244 int len = nr * nc; |
|
1245 read_doubles (is, (double *) im, (save_type) tmp, 2*len, swap, fmt); |
|
1246 if (! is) |
|
1247 goto data_read_error; |
|
1248 tc = m; |
|
1249 } |
|
1250 break; |
|
1251 |
|
1252 case 5: |
|
1253 { |
|
1254 int nr = tc.rows (); |
|
1255 int nc = tc.columns (); |
|
1256 FOUR_BYTE_INT len = nr * nc; |
|
1257 if (! is.read (&len, 4)) |
|
1258 goto data_read_error; |
|
1259 if (swap) |
|
1260 swap_4_bytes ((char *) &len); |
|
1261 char *s = new char [len+1]; |
|
1262 if (! is.read (s, len)) |
|
1263 { |
|
1264 delete [] s; |
|
1265 goto data_read_error; |
|
1266 } |
|
1267 s[len] = '\0'; |
|
1268 tc = s; |
|
1269 } |
|
1270 break; |
|
1271 |
|
1272 case 6: |
|
1273 { |
|
1274 double bas, lim, inc; |
|
1275 if (! is.read (&bas, 8)) |
|
1276 goto data_read_error; |
|
1277 if (swap) |
|
1278 swap_8_bytes ((char *) &bas); |
|
1279 if (! is.read (&lim, 8)) |
|
1280 goto data_read_error; |
|
1281 if (swap) |
|
1282 swap_8_bytes ((char *) &lim); |
|
1283 if (! is.read (&inc, 8)) |
|
1284 goto data_read_error; |
|
1285 if (swap) |
|
1286 swap_8_bytes ((char *) &inc); |
|
1287 Range r (bas, lim, inc); |
|
1288 tc = r; |
|
1289 } |
|
1290 break; |
|
1291 |
|
1292 default: |
|
1293 data_read_error: |
|
1294 error ("load: trouble reading binary file `%s'", filename); |
|
1295 delete [] name; |
|
1296 name = 0; |
|
1297 break; |
|
1298 } |
|
1299 |
|
1300 return name; |
|
1301 } |
|
1302 |
|
1303 // Read LEN elements of data from IS in the format specified by |
|
1304 // PRECISION, placing the result in DATA. If SWAP is nonzero, swap |
|
1305 // the bytes of each element before copying to DATA. FLT_FMT |
|
1306 // specifies the format of the data if we are reading floating point |
|
1307 // numbers. |
|
1308 |
|
1309 static void |
|
1310 read_mat_binary_data (istream& is, double *data, int precision, |
|
1311 int len, int swap, floating_point_format flt_fmt) |
|
1312 { |
|
1313 switch (precision) |
|
1314 { |
|
1315 case 0: |
|
1316 { |
|
1317 if (! is.read (data, 8*len)) |
|
1318 return; |
|
1319 |
|
1320 do_float_format_conversion (data, len, flt_fmt); |
|
1321 } |
|
1322 break; |
|
1323 |
|
1324 case 1: |
|
1325 error ("load: reading 32 bit floating point data unsupported"); |
|
1326 break; |
|
1327 |
|
1328 case 2: |
|
1329 read_doubles (is, data, LS_INT, len, swap, flt_fmt); |
|
1330 break; |
|
1331 |
|
1332 case 3: |
|
1333 read_doubles (is, data, LS_SHORT, len, swap, flt_fmt); |
|
1334 break; |
|
1335 |
|
1336 case 4: |
|
1337 read_doubles (is, data, LS_U_SHORT, len, swap, flt_fmt); |
|
1338 break; |
|
1339 |
|
1340 case 5: |
|
1341 read_doubles (is, data, LS_U_CHAR, len, swap, flt_fmt); |
|
1342 break; |
|
1343 |
|
1344 default: |
|
1345 break; |
|
1346 } |
|
1347 } |
|
1348 |
|
1349 static int |
|
1350 read_mat_file_header (istream& is, int& swap, FOUR_BYTE_INT& mopt, |
|
1351 FOUR_BYTE_INT& nr, FOUR_BYTE_INT& nc, |
|
1352 FOUR_BYTE_INT& imag, FOUR_BYTE_INT& len, |
|
1353 int quiet = 0) |
|
1354 { |
|
1355 is.read (&mopt, 4); |
|
1356 if (! is) |
|
1357 { |
|
1358 if (! is.eof ()) |
|
1359 goto data_read_error; |
|
1360 return 1; |
|
1361 } |
|
1362 |
|
1363 if (! is.read (&nr, 4)) |
|
1364 goto data_read_error; |
|
1365 |
|
1366 if (! is.read (&nc, 4)) |
|
1367 goto data_read_error; |
|
1368 |
|
1369 if (! is.read (&imag, 4)) |
|
1370 goto data_read_error; |
|
1371 |
|
1372 if (! is.read (&len, 4)) |
|
1373 goto data_read_error; |
|
1374 |
|
1375 // If mopt is nonzero and the byte order is swapped, mopt will be |
|
1376 // bigger than we expect, so we swap bytes. |
|
1377 // |
|
1378 // If mopt is zero, it means the file was written on a little endian |
|
1379 // machine, and we only need to swap if we are running on a big endian |
|
1380 // machine. |
|
1381 // |
|
1382 // Gag me. |
|
1383 |
|
1384 #if defined (WORDS_BIGENDIAN) |
|
1385 if (mopt == 0) |
|
1386 swap = 1; |
|
1387 #endif |
|
1388 |
|
1389 if (mopt > 9999) |
|
1390 swap = 1; |
|
1391 |
|
1392 if (swap) |
|
1393 { |
|
1394 swap_4_bytes ((char *) &mopt); |
|
1395 swap_4_bytes ((char *) &nr); |
|
1396 swap_4_bytes ((char *) &nc); |
|
1397 swap_4_bytes ((char *) &imag); |
|
1398 swap_4_bytes ((char *) &len); |
|
1399 } |
|
1400 |
|
1401 if (mopt > 9999 || imag > 1 || imag < 0 || len > 8192) |
|
1402 { |
|
1403 if (! quiet) |
|
1404 error ("load: can't read binary file"); |
|
1405 return -1; |
|
1406 } |
|
1407 |
|
1408 return 0; |
|
1409 |
|
1410 data_read_error: |
|
1411 return -1; |
|
1412 } |
|
1413 |
617
|
1414 // We don't just use a cast here, because we need to be able to detect |
|
1415 // possible errors. |
|
1416 |
|
1417 static floating_point_format |
|
1418 get_floating_point_format (int mach) |
|
1419 { |
619
|
1420 floating_point_format flt_fmt = LS_UNKNOWN_FLT_FMT; |
|
1421 |
617
|
1422 switch (mach) |
|
1423 { |
|
1424 case 0: |
|
1425 flt_fmt = LS_IEEE_LITTLE; |
|
1426 break; |
|
1427 |
|
1428 case 1: |
|
1429 flt_fmt = LS_IEEE_BIG; |
|
1430 break; |
|
1431 |
|
1432 case 2: |
|
1433 flt_fmt = LS_VAX_D; |
|
1434 break; |
|
1435 |
|
1436 case 3: |
|
1437 flt_fmt = LS_VAX_G; |
|
1438 break; |
|
1439 |
|
1440 case 4: |
|
1441 flt_fmt = LS_CRAY; |
|
1442 break; |
|
1443 |
|
1444 default: |
619
|
1445 flt_fmt = LS_UNKNOWN_FLT_FMT; |
617
|
1446 break; |
|
1447 } |
619
|
1448 |
|
1449 return flt_fmt; |
617
|
1450 } |
619
|
1451 |
604
|
1452 // Extract one value (scalar, matrix, string, etc.) from stream IS and |
|
1453 // place it in TC, returning the name of the variable. |
|
1454 // |
|
1455 // The data is expected to be in Matlab's .mat format, though not all |
|
1456 // the features of that format are supported. |
|
1457 // |
|
1458 // FILENAME is used for error messages. |
|
1459 // |
|
1460 // This format provides no way to tag the data as global. |
|
1461 |
|
1462 static char * |
|
1463 read_mat_binary_data (istream& is, const char *filename, |
|
1464 tree_constant& tc) |
|
1465 { |
|
1466 // These are initialized here instead of closer to where they are |
|
1467 // first used to avoid errors from gcc about goto crossing |
|
1468 // initialization of variable. |
|
1469 |
|
1470 Matrix re; |
|
1471 floating_point_format flt_fmt = LS_UNKNOWN_FLT_FMT; |
|
1472 char *name = 0; |
|
1473 int swap = 0, type = 0, prec = 0, mach = 0, dlen = 0; |
|
1474 |
|
1475 FOUR_BYTE_INT mopt, nr, nc, imag, len; |
|
1476 |
|
1477 int err = read_mat_file_header (is, swap, mopt, nr, nc, imag, len); |
|
1478 if (err) |
|
1479 { |
|
1480 if (err < 0) |
|
1481 goto data_read_error; |
|
1482 else |
|
1483 return 0; |
|
1484 } |
|
1485 |
|
1486 type = mopt % 10; // Full, sparse, etc. |
|
1487 mopt /= 10; // Eliminate first digit. |
|
1488 prec = mopt % 10; // double, float, int, etc. |
|
1489 mopt /= 100; // Skip unused third digit too. |
|
1490 mach = mopt % 10; // IEEE, VAX, etc. |
|
1491 |
617
|
1492 flt_fmt = get_floating_point_format (mach); |
|
1493 if (flt_fmt == LS_UNKNOWN_FLT_FMT) |
604
|
1494 { |
|
1495 error ("load: unrecognized binary format!"); |
|
1496 return 0; |
|
1497 } |
|
1498 |
|
1499 if (type != 0 && type != 1) |
|
1500 { |
|
1501 error ("load: can't read sparse matrices"); |
|
1502 return 0; |
|
1503 } |
|
1504 |
|
1505 if (imag && type == 1) |
|
1506 { |
|
1507 error ("load: encountered complex matrix with string flag set!"); |
|
1508 return 0; |
|
1509 } |
|
1510 |
|
1511 name = new char [len]; |
|
1512 if (! is.read (name, len)) |
|
1513 goto data_read_error; |
|
1514 |
|
1515 dlen = nr * nc; |
|
1516 if (dlen < 0) |
|
1517 goto data_read_error; |
|
1518 |
|
1519 re.resize (nr, nc); |
|
1520 |
|
1521 read_mat_binary_data (is, re.fortran_vec (), prec, dlen, swap, flt_fmt); |
|
1522 |
|
1523 if (! is || error_state) |
|
1524 { |
|
1525 error ("load: reading matrix data for `%s'", name); |
|
1526 goto data_read_error; |
|
1527 } |
|
1528 |
|
1529 if (imag) |
|
1530 { |
|
1531 Matrix im (nr, nc); |
|
1532 |
|
1533 read_mat_binary_data (is, im.fortran_vec (), prec, dlen, swap, flt_fmt); |
|
1534 |
|
1535 if (! is || error_state) |
|
1536 { |
|
1537 error ("load: reading imaginary matrix data for `%s'", name); |
|
1538 goto data_read_error; |
|
1539 } |
|
1540 |
|
1541 ComplexMatrix ctmp (nr, nc); |
|
1542 |
|
1543 for (int j = 0; j < nc; j++) |
|
1544 for (int i = 0; i < nr; i++) |
|
1545 ctmp.elem (i, j) = Complex (re.elem (i, j), im.elem (i, j)); |
|
1546 |
|
1547 tc = ctmp; |
|
1548 } |
|
1549 else |
|
1550 tc = re; |
|
1551 |
|
1552 if (type == 1) |
|
1553 tc = tc.convert_to_str (); |
|
1554 |
|
1555 return name; |
|
1556 |
|
1557 data_read_error: |
|
1558 error ("load: trouble reading binary file `%s'", filename); |
|
1559 delete [] name; |
|
1560 return 0; |
|
1561 } |
|
1562 |
|
1563 // Return nonzero if NAME matches one of the given globbing PATTERNS. |
|
1564 |
|
1565 static int |
|
1566 matches_patterns (char **patterns, int num_pat, char *name) |
|
1567 { |
|
1568 while (num_pat-- > 0) |
|
1569 { |
|
1570 if (fnmatch (*patterns++, name, __FNM_FLAGS) == 0) |
|
1571 return 1; |
|
1572 } |
|
1573 return 0; |
|
1574 } |
|
1575 |
|
1576 static int |
|
1577 read_binary_file_header (istream& is, int& swap, |
|
1578 floating_point_format flt_fmt, int quiet = 0) |
|
1579 { |
|
1580 int magic_len = 10; |
|
1581 char magic [magic_len+1]; |
|
1582 is.read (magic, magic_len); |
|
1583 magic[magic_len] = '\0'; |
|
1584 if (strncmp (magic, "Octave-1-L", magic_len) == 0) |
|
1585 { |
|
1586 #if defined (WORDS_BIGENDIAN) |
|
1587 swap = 1; |
|
1588 #else |
|
1589 swap = 0; |
|
1590 #endif |
|
1591 } |
|
1592 else if (strncmp (magic, "Octave-1-B", magic_len) == 0) |
|
1593 { |
|
1594 #if defined (WORDS_BIGENDIAN) |
|
1595 swap = 0; |
|
1596 #else |
|
1597 swap = 1; |
|
1598 #endif |
|
1599 } |
|
1600 else |
|
1601 { |
|
1602 if (! quiet) |
|
1603 error ("load: can't read binary file"); |
|
1604 return -1; |
|
1605 } |
|
1606 |
|
1607 char tmp = 0; |
|
1608 is.read (&tmp, 1); |
|
1609 |
617
|
1610 flt_fmt = get_floating_point_format (tmp); |
|
1611 if (flt_fmt == LS_UNKNOWN_FLT_FMT) |
604
|
1612 { |
|
1613 if (! quiet) |
|
1614 error ("load: unrecognized binary format!"); |
|
1615 return -1; |
|
1616 } |
|
1617 |
|
1618 return 0; |
|
1619 } |
|
1620 |
|
1621 static load_save_format |
|
1622 get_file_format (const char *fname, const char *orig_fname) |
|
1623 { |
|
1624 load_save_format retval = LS_UNKNOWN; |
|
1625 |
|
1626 ifstream file; |
|
1627 |
|
1628 file.open (fname); |
|
1629 |
|
1630 if (! file) |
|
1631 { |
|
1632 error ("load: couldn't open input file `%s'", orig_fname); |
|
1633 return retval; |
|
1634 } |
|
1635 |
|
1636 int swap; |
|
1637 floating_point_format flt_fmt = LS_UNKNOWN_FLT_FMT; |
|
1638 |
|
1639 if (read_binary_file_header (file, swap, flt_fmt, 1) == 0) |
|
1640 retval = LS_BINARY; |
|
1641 else |
|
1642 { |
|
1643 file.seekg (0, ios::beg); |
|
1644 |
|
1645 FOUR_BYTE_INT mopt, nr, nc, imag, len; |
|
1646 int swap; |
|
1647 |
|
1648 if (read_mat_file_header (file, swap, mopt, nr, nc, imag, len, 1) == 0) |
|
1649 retval = LS_MAT_BINARY; |
|
1650 else |
|
1651 { |
|
1652 file.seekg (0, ios::beg); |
|
1653 |
|
1654 char *tmp = extract_keyword (file, "name"); |
|
1655 if (tmp) |
|
1656 retval = LS_ASCII; |
|
1657 |
|
1658 delete [] tmp; |
|
1659 } |
|
1660 } |
|
1661 |
|
1662 file.close (); |
|
1663 |
|
1664 if (retval == LS_UNKNOWN) |
|
1665 error ("load: unable to determine file format for `%s'", orig_fname); |
|
1666 |
|
1667 return retval; |
|
1668 } |
|
1669 |
|
1670 DEFUN_TEXT ("load", Fload, Sload, -1, 1, |
|
1671 "load [-force] [-ascii] [-binary] [-mat-binary] file [pattern ...]\n |
|
1672 \n\ |
|
1673 Load variables from a file.\n\ |
|
1674 \n\ |
|
1675 If no argument is supplied to select a format, load tries to read the |
|
1676 named file as an Octave binary, then as a .mat file, and then as an |
|
1677 Octave text file.\n\ |
|
1678 \n\ |
|
1679 If the option -force is given, variables with the same names as those |
|
1680 found in the file will be replaced with the values read from the file.") |
|
1681 { |
|
1682 Octave_object retval; |
|
1683 |
|
1684 DEFINE_ARGV("load"); |
|
1685 |
|
1686 argc--; |
|
1687 argv++; |
|
1688 |
|
1689 int force = 0; |
|
1690 |
|
1691 // Here is where we would get the default load format if it were |
|
1692 // stored in a user preference variable. |
|
1693 |
|
1694 load_save_format format = LS_UNKNOWN; |
|
1695 |
|
1696 while (argc > 0) |
|
1697 { |
|
1698 if (strcmp (*argv, "-force") == 0 || strcmp (*argv, "-f") == 0) |
|
1699 { |
|
1700 force++; |
|
1701 argc--; |
|
1702 argv++; |
|
1703 } |
|
1704 else if (strcmp (*argv, "-ascii") == 0 || strcmp (*argv, "-a") == 0) |
|
1705 { |
|
1706 format = LS_ASCII; |
|
1707 argc--; |
|
1708 argv++; |
|
1709 } |
|
1710 else if (strcmp (*argv, "-binary") == 0 || strcmp (*argv, "-b") == 0) |
|
1711 { |
|
1712 format = LS_BINARY; |
|
1713 argc--; |
|
1714 argv++; |
|
1715 } |
|
1716 else if (strcmp (*argv, "-mat-binary") == 0 || strcmp (*argv, "-m") == 0) |
|
1717 { |
|
1718 format = LS_MAT_BINARY; |
|
1719 argc--; |
|
1720 argv++; |
|
1721 } |
|
1722 else |
|
1723 break; |
|
1724 } |
|
1725 |
|
1726 if (argc < 1) |
|
1727 { |
|
1728 error ("load: you must specify a single file to read"); |
|
1729 DELETE_ARGV; |
|
1730 return retval; |
|
1731 } |
|
1732 |
|
1733 char *orig_fname = *argv; |
|
1734 static istream stream; |
|
1735 static ifstream file; |
|
1736 if (strcmp (*argv, "-") == 0) |
|
1737 { |
|
1738 if (format == LS_UNKNOWN) |
|
1739 { |
|
1740 error ("load: must specify file format if reading from stdin"); |
|
1741 DELETE_ARGV; |
|
1742 return retval; |
|
1743 } |
|
1744 stream = cin; |
|
1745 } |
|
1746 else |
|
1747 { |
|
1748 char *fname = tilde_expand (*argv); |
|
1749 |
|
1750 if (format == LS_UNKNOWN) |
|
1751 format = get_file_format (fname, orig_fname); |
|
1752 |
|
1753 if (format == LS_UNKNOWN) |
|
1754 { |
|
1755 DELETE_ARGV; |
|
1756 return retval; |
|
1757 } |
|
1758 |
|
1759 argv++; |
|
1760 argc--; |
|
1761 |
|
1762 unsigned mode = ios::in; |
|
1763 if (format == LS_BINARY || format == LS_MAT_BINARY) |
|
1764 mode |= ios::bin; |
|
1765 |
|
1766 file.open (fname, mode); |
|
1767 |
|
1768 if (! file) |
|
1769 { |
|
1770 error ("load: couldn't open input file `%s'", orig_fname); |
|
1771 DELETE_ARGV; |
|
1772 return retval; |
|
1773 } |
|
1774 stream = file; |
|
1775 } |
|
1776 |
|
1777 int swap = 0; |
|
1778 floating_point_format flt_fmt = LS_UNKNOWN_FLT_FMT; |
|
1779 |
|
1780 if (format == LS_BINARY) |
|
1781 { |
|
1782 if (read_binary_file_header (file, swap, flt_fmt) < 0) |
|
1783 { |
|
1784 file.close (); |
|
1785 DELETE_ARGV; |
|
1786 return retval; |
|
1787 } |
|
1788 } |
|
1789 |
|
1790 int count = 0; |
|
1791 for (;;) |
|
1792 { |
|
1793 int global = 0; |
|
1794 tree_constant tc; |
|
1795 |
|
1796 char *name = 0; |
|
1797 char *doc = 0; |
|
1798 |
|
1799 switch (format) |
|
1800 { |
|
1801 case LS_ASCII: |
|
1802 name = read_ascii_data (stream, orig_fname, global, tc); |
|
1803 break; |
|
1804 |
|
1805 case LS_BINARY: |
|
1806 name = read_binary_data (stream, swap, flt_fmt, orig_fname, |
|
1807 global, tc, doc); |
|
1808 break; |
|
1809 |
|
1810 case LS_MAT_BINARY: |
|
1811 name = read_mat_binary_data (stream, orig_fname, tc); |
|
1812 break; |
|
1813 |
|
1814 default: |
|
1815 panic_impossible (); |
|
1816 break; |
|
1817 } |
|
1818 |
|
1819 if (stream.eof ()) |
|
1820 { |
|
1821 break; |
|
1822 } |
|
1823 else if (! error_state && name) |
|
1824 { |
|
1825 if (tc.is_defined ()) |
|
1826 { |
|
1827 if (argc == 0 || matches_patterns (argv, argc, name)) |
|
1828 { |
|
1829 count++; |
|
1830 install_loaded_variable (force, name, tc, global, doc); |
|
1831 } |
|
1832 } |
|
1833 else |
|
1834 error ("load: unable to load variable `%s'", name); |
|
1835 } |
|
1836 else |
|
1837 { |
|
1838 if (count == 0) |
|
1839 error ("load: are you sure `%s' is an Octave data file?", |
|
1840 orig_fname); |
|
1841 |
|
1842 break; |
|
1843 } |
|
1844 |
|
1845 delete [] name; |
|
1846 delete [] doc; |
|
1847 } |
|
1848 |
|
1849 if (file); |
|
1850 file.close (); |
|
1851 |
|
1852 DELETE_ARGV; |
|
1853 |
|
1854 return retval; |
|
1855 } |
|
1856 |
|
1857 // Return nonzero if PATTERN has any special globbing chars in it. |
|
1858 |
|
1859 static int |
|
1860 glob_pattern_p (char *pattern) |
|
1861 { |
|
1862 char *p = pattern; |
|
1863 char c; |
|
1864 int open = 0; |
|
1865 |
|
1866 while ((c = *p++) != '\0') |
|
1867 { |
|
1868 switch (c) |
|
1869 { |
|
1870 case '?': |
|
1871 case '*': |
|
1872 return 1; |
|
1873 |
|
1874 case '[': // Only accept an open brace if there is a close |
|
1875 open++; // brace to match it. Bracket expressions must be |
|
1876 continue; // complete, according to Posix.2 |
|
1877 |
|
1878 case ']': |
|
1879 if (open) |
|
1880 return 1; |
|
1881 continue; |
|
1882 |
|
1883 case '\\': |
|
1884 if (*p++ == '\0') |
|
1885 return 0; |
|
1886 |
|
1887 default: |
|
1888 continue; |
|
1889 } |
|
1890 } |
|
1891 |
|
1892 return 0; |
|
1893 } |
|
1894 |
618
|
1895 // MAX_VAL and MIN_VAL are assumed to have integral values even though |
|
1896 // they are stored in doubles. |
|
1897 |
604
|
1898 static save_type |
|
1899 get_save_type (double max_val, double min_val) |
|
1900 { |
|
1901 save_type st = LS_DOUBLE; |
|
1902 |
|
1903 if (max_val < 256 && min_val > -1) |
|
1904 st = LS_U_CHAR; |
|
1905 else if (max_val < 65536 && min_val > -1) |
|
1906 st = LS_U_SHORT; |
618
|
1907 else if (max_val < 4294967295 && min_val > -1) |
|
1908 st = LS_U_INT; |
|
1909 else if (max_val < 128 && min_val >= -128) |
|
1910 st = LS_CHAR; |
604
|
1911 else if (max_val < 32768 && min_val >= -32768) |
|
1912 st = LS_SHORT; |
|
1913 else if (max_val < 2147483648 && min_val > -2147483648) |
|
1914 st = LS_INT; |
|
1915 |
|
1916 return st; |
|
1917 } |
|
1918 |
|
1919 // Save the data from TC along with the corresponding NAME, help |
|
1920 // string DOC, and global flag MARK_AS_GLOBAL on stream OS in the |
|
1921 // binary format described above for load_binary_data. |
|
1922 |
|
1923 static int |
|
1924 save_binary_data (ostream& os, const tree_constant& tc, char *name, |
|
1925 char *doc, int mark_as_global) |
|
1926 { |
620
|
1927 int fail = 0; |
|
1928 |
604
|
1929 FOUR_BYTE_INT name_len = 0; |
|
1930 if (name) |
|
1931 name_len = strlen (name); |
|
1932 |
|
1933 os.write (&name_len, 4); |
|
1934 os.write (name, name_len); |
|
1935 |
|
1936 FOUR_BYTE_INT doc_len = 0; |
|
1937 if (doc) |
|
1938 doc_len = strlen (doc); |
|
1939 |
|
1940 os.write (&doc_len, 4); |
|
1941 os.write (doc, doc_len); |
|
1942 |
|
1943 char tmp; |
|
1944 |
|
1945 tmp = mark_as_global; |
|
1946 os.write (&tmp, 1); |
|
1947 |
620
|
1948 if (tc.is_real_scalar ()) |
604
|
1949 { |
|
1950 tmp = 1; |
|
1951 os.write (&tmp, 1); |
|
1952 double tmp = tc.double_value (); |
|
1953 os.write (&tmp, 8); |
|
1954 } |
620
|
1955 else if (tc.is_real_matrix ()) |
604
|
1956 { |
|
1957 tmp = 2; |
|
1958 os.write (&tmp, 1); |
|
1959 Matrix m = tc.matrix_value (); |
|
1960 FOUR_BYTE_INT nr = m.rows (); |
|
1961 FOUR_BYTE_INT nc = m.columns (); |
|
1962 os.write (&nr, 4); |
|
1963 os.write (&nc, 4); |
|
1964 int len = nr * nc; |
|
1965 save_type st = LS_DOUBLE; |
|
1966 if (len > 8192) |
|
1967 { |
|
1968 double max_val, min_val; |
|
1969 if (all_parts_int (m, max_val, min_val)) |
|
1970 st = get_save_type (max_val, min_val); |
|
1971 } |
|
1972 double *mtmp = m.fortran_vec (); |
|
1973 write_doubles (os, mtmp, st, len); |
|
1974 } |
|
1975 else if (tc.is_complex_scalar ()) |
|
1976 { |
|
1977 tmp = 3; |
|
1978 os.write (&tmp, 1); |
|
1979 Complex tmp = tc.complex_value (); |
|
1980 os.write (&tmp, 16); |
|
1981 } |
|
1982 else if (tc.is_complex_matrix ()) |
|
1983 { |
|
1984 tmp = 4; |
|
1985 os.write (&tmp, 1); |
|
1986 ComplexMatrix m = tc.complex_matrix_value (); |
|
1987 FOUR_BYTE_INT nr = m.rows (); |
|
1988 FOUR_BYTE_INT nc = m.columns (); |
|
1989 os.write (&nr, 4); |
|
1990 os.write (&nc, 4); |
|
1991 int len = nr * nc; |
|
1992 save_type st = LS_DOUBLE; |
|
1993 if (len > 4096) |
|
1994 { |
|
1995 double max_val, min_val; |
|
1996 if (all_parts_int (m, max_val, min_val)) |
|
1997 st = get_save_type (max_val, min_val); |
|
1998 } |
|
1999 Complex *mtmp = m.fortran_vec (); |
|
2000 write_doubles (os, (double *) mtmp, st, 2*len); |
|
2001 } |
|
2002 else if (tc.is_string ()) |
|
2003 { |
|
2004 tmp = 5; |
|
2005 os.write (&tmp, 1); |
|
2006 int nr = tc.rows (); |
|
2007 int nc = tc.columns (); |
|
2008 FOUR_BYTE_INT len = nr * nc; |
|
2009 os.write (&len, 4); |
|
2010 char *s = tc.string_value (); |
|
2011 os.write (s, len); |
|
2012 } |
|
2013 else if (tc.is_range ()) |
|
2014 { |
|
2015 tmp = 6; |
|
2016 os.write (&tmp, 1); |
|
2017 Range r = tc.range_value (); |
|
2018 double bas = r.base (); |
|
2019 double lim = r.limit (); |
|
2020 double inc = r.inc (); |
|
2021 os.write (&bas, 8); |
|
2022 os.write (&lim, 8); |
|
2023 os.write (&inc, 8); |
|
2024 } |
|
2025 else |
620
|
2026 { |
|
2027 gripe_wrong_type_arg ("save", tc); |
|
2028 fail = 1; |
|
2029 } |
604
|
2030 |
620
|
2031 return (os && ! fail); |
604
|
2032 } |
|
2033 |
620
|
2034 static void |
|
2035 ascii_save_type (ostream& os, char *type, int mark_as_global) |
|
2036 { |
|
2037 if (mark_as_global) |
|
2038 os << "# type: global "; |
|
2039 else |
|
2040 os << "# type: "; |
|
2041 |
|
2042 os << type << "\n"; |
|
2043 } |
|
2044 |
|
2045 // Save the data from TC along with the corresponding NAME, and global |
604
|
2046 // flag MARK_AS_GLOBAL on stream OS in the plain text format described |
|
2047 // above for load_ascii_data. If NAME is null, the name: line is not |
|
2048 // generated. PRECISION specifies the number of decimal digits to print. |
|
2049 |
|
2050 // XXX FIXME XXX -- should probably write the help string here too. |
|
2051 |
|
2052 int |
620
|
2053 save_ascii_data (ostream& os, const tree_constant& tc, |
604
|
2054 char *name, int mark_as_global, int precision) |
|
2055 { |
620
|
2056 int fail = 0; |
|
2057 |
604
|
2058 if (! precision) |
|
2059 precision = user_pref.save_precision; |
|
2060 |
|
2061 if (name) |
|
2062 os << "# name: " << name << "\n"; |
|
2063 |
|
2064 long old_precision = os.precision (); |
|
2065 os.precision (precision); |
|
2066 |
620
|
2067 if (tc.is_real_scalar ()) |
|
2068 { |
|
2069 ascii_save_type (os, "scalar", mark_as_global); |
|
2070 os << tc.double_value () << "\n"; |
|
2071 } |
|
2072 else if (tc.is_real_matrix ()) |
|
2073 { |
|
2074 ascii_save_type (os, "matrix", mark_as_global); |
|
2075 os << "# rows: " << tc.rows () << "\n" |
|
2076 << "# columns: " << tc.columns () << "\n" |
|
2077 << tc.matrix_value () ; |
|
2078 } |
|
2079 else if (tc.is_complex_scalar ()) |
|
2080 { |
|
2081 ascii_save_type (os, "complex scalar", mark_as_global); |
|
2082 os << tc.complex_value () << "\n"; |
|
2083 } |
|
2084 else if (tc.is_complex_matrix ()) |
604
|
2085 { |
620
|
2086 ascii_save_type (os, "complex matrix", mark_as_global); |
|
2087 os << "# rows: " << tc.rows () << "\n" |
|
2088 << "# columns: " << tc.columns () << "\n" |
|
2089 << tc.complex_matrix_value () ; |
|
2090 } |
|
2091 else if (tc.is_string ()) |
|
2092 { |
|
2093 ascii_save_type (os, "string", mark_as_global); |
|
2094 char *tmp = tc.string_value (); |
|
2095 os << "# length: " << strlen (tmp) << "\n" |
|
2096 << tmp << "\n"; |
|
2097 } |
|
2098 else if (tc.is_string ()) |
|
2099 { |
|
2100 ascii_save_type (os, "range", mark_as_global); |
|
2101 Range tmp = tc.range_value (); |
|
2102 os << "# base, limit, increment\n" |
|
2103 << tmp.base () << " " |
|
2104 << tmp.limit () << " " |
|
2105 << tmp.inc () << "\n"; |
|
2106 } |
|
2107 else |
|
2108 { |
|
2109 gripe_wrong_type_arg ("save", tc); |
|
2110 fail = 1; |
604
|
2111 } |
|
2112 |
|
2113 os.precision (old_precision); |
|
2114 |
620
|
2115 return (os && ! fail); |
604
|
2116 } |
|
2117 |
|
2118 // Save the info from sr on stream os in the format specified by fmt. |
|
2119 |
|
2120 static void |
|
2121 do_save (ostream& os, symbol_record *sr, load_save_format fmt) |
|
2122 { |
|
2123 if (! sr->is_variable ()) |
|
2124 { |
|
2125 error ("save: can only save variables, not functions"); |
|
2126 return; |
|
2127 } |
|
2128 |
|
2129 char *name = sr->name (); |
|
2130 char *help = sr->help (); |
|
2131 int global = sr->is_linked_to_global (); |
|
2132 tree_constant tc = *((tree_constant *) sr->def ()); |
|
2133 |
|
2134 if (! name || ! tc.is_defined ()) |
|
2135 return; |
|
2136 |
|
2137 switch (fmt) |
|
2138 { |
|
2139 case LS_ASCII: |
|
2140 save_ascii_data (os, tc, name, global); |
|
2141 break; |
|
2142 |
|
2143 case LS_BINARY: |
|
2144 save_binary_data (os, tc, name, help, global); |
|
2145 break; |
|
2146 |
|
2147 default: |
|
2148 panic_impossible (); |
|
2149 break; |
|
2150 } |
|
2151 } |
|
2152 |
|
2153 // Save variables with names matching PATTERN on stream OS in the |
|
2154 // format specified by FMT. If SAVE_BUILTINS is nonzero, also save |
|
2155 // builtin variables with names that match PATTERN. |
|
2156 |
|
2157 static int |
|
2158 save_vars (ostream& os, char *pattern, int save_builtins, |
|
2159 load_save_format fmt) |
|
2160 { |
|
2161 int count; |
|
2162 |
|
2163 symbol_record **vars = curr_sym_tab->glob |
|
2164 (count, pattern, symbol_def::USER_VARIABLE, SYMTAB_ALL_SCOPES); |
|
2165 |
|
2166 int saved = count; |
|
2167 |
|
2168 int i; |
|
2169 |
|
2170 for (i = 0; i < count; i++) |
620
|
2171 { |
|
2172 do_save (os, vars[i], fmt); |
|
2173 |
|
2174 if (error_state) |
|
2175 break; |
|
2176 } |
604
|
2177 |
|
2178 delete [] vars; |
|
2179 |
620
|
2180 if (! error_state && save_builtins) |
604
|
2181 { |
|
2182 symbol_record **vars = global_sym_tab->glob |
|
2183 (count, pattern, symbol_def::BUILTIN_VARIABLE, SYMTAB_ALL_SCOPES); |
|
2184 |
|
2185 saved += count; |
|
2186 |
|
2187 for (i = 0; i < count; i++) |
620
|
2188 { |
|
2189 do_save (os, vars[i], fmt); |
|
2190 |
|
2191 if (error_state) |
|
2192 break; |
|
2193 } |
604
|
2194 |
|
2195 delete [] vars; |
|
2196 } |
|
2197 |
|
2198 return saved; |
|
2199 } |
|
2200 |
|
2201 static load_save_format |
|
2202 get_default_save_format (void) |
|
2203 { |
|
2204 load_save_format retval = LS_ASCII; |
|
2205 |
|
2206 char *fmt = user_pref.default_save_format; |
|
2207 |
|
2208 if (strcasecmp (fmt, "binary") == 0) |
|
2209 retval = LS_BINARY; |
|
2210 |
|
2211 return retval; |
|
2212 } |
|
2213 |
|
2214 DEFUN_TEXT ("save", Fsave, Ssave, -1, 1, |
|
2215 "save [-ascii] [-binary] [-save-builtins] file [pattern ...]\n\ |
|
2216 \n\ |
|
2217 save variables in a file") |
|
2218 { |
|
2219 Octave_object retval; |
|
2220 |
|
2221 DEFINE_ARGV("save"); |
|
2222 |
|
2223 argc--; |
|
2224 argv++; |
|
2225 |
|
2226 // Here is where we would get the default save format if it were |
|
2227 // stored in a user preference variable. |
|
2228 |
|
2229 int save_builtins = 0; |
|
2230 |
|
2231 load_save_format format = get_default_save_format (); |
|
2232 |
|
2233 while (argc > 0) |
|
2234 { |
|
2235 if (strcmp (*argv, "-ascii") == 0 || strcmp (*argv, "-a") == 0) |
|
2236 { |
|
2237 format = LS_ASCII; |
|
2238 argc--; |
|
2239 argv++; |
|
2240 } |
|
2241 else if (strcmp (*argv, "-binary") == 0 || strcmp (*argv, "-b") == 0) |
|
2242 { |
|
2243 format = LS_BINARY; |
|
2244 argc--; |
|
2245 argv++; |
|
2246 } |
|
2247 else if (strcmp (*argv, "-save-builtins") == 0) |
|
2248 { |
|
2249 save_builtins = 1; |
|
2250 argc--; |
|
2251 argv++; |
|
2252 } |
|
2253 else |
|
2254 break; |
|
2255 } |
|
2256 |
|
2257 if (argc < 1) |
|
2258 { |
|
2259 print_usage ("save"); |
|
2260 DELETE_ARGV; |
|
2261 return retval; |
|
2262 } |
|
2263 |
|
2264 static ostream stream; |
|
2265 static ofstream file; |
|
2266 if (strcmp (*argv, "-") == 0) |
|
2267 { |
|
2268 // XXX FIXME XXX -- should things intended for the screen end up in a |
|
2269 // tree_constant (string)? |
|
2270 stream = cout; |
|
2271 } |
|
2272 else if (argc == 1 && glob_pattern_p (*argv)) // Guard against things |
|
2273 { // like `save a*', |
|
2274 print_usage ("save"); // which are probably |
|
2275 DELETE_ARGV; // mistakes... |
|
2276 return retval; |
|
2277 } |
|
2278 else |
|
2279 { |
|
2280 char *fname = tilde_expand (*argv); |
|
2281 |
|
2282 argc--; |
|
2283 argv++; |
|
2284 |
|
2285 unsigned mode = ios::in; |
|
2286 if (format == LS_BINARY || format == LS_MAT_BINARY) |
|
2287 mode |= ios::bin; |
|
2288 |
|
2289 file.open (fname); |
|
2290 |
|
2291 if (! file) |
|
2292 { |
|
2293 error ("save: couldn't open output file `%s'", *argv); |
|
2294 DELETE_ARGV; |
|
2295 return retval; |
|
2296 } |
|
2297 stream = file; |
|
2298 |
|
2299 } |
|
2300 |
|
2301 if (format == LS_BINARY) |
|
2302 { |
|
2303 #if defined (WORDS_BIGENDIAN) |
|
2304 stream << "Octave-1-B"; |
|
2305 #else |
|
2306 stream << "Octave-1-L"; |
|
2307 #endif |
|
2308 } |
|
2309 |
|
2310 char tmp = (char) NATIVE_FLOAT_FORMAT; |
|
2311 stream.write (&tmp, 1); |
|
2312 |
|
2313 if (argc == 0) |
|
2314 { |
|
2315 save_vars (stream, "*", save_builtins, format); |
|
2316 } |
|
2317 else |
|
2318 { |
|
2319 while (argc-- > 0) |
|
2320 { |
|
2321 if (! save_vars (stream, *argv, save_builtins, format)) |
|
2322 warning ("save: no such variable `%s'", *argv); |
|
2323 |
|
2324 argv++; |
|
2325 } |
|
2326 } |
|
2327 |
|
2328 if (file); |
|
2329 file.close (); |
|
2330 |
|
2331 DELETE_ARGV; |
|
2332 |
|
2333 return retval; |
|
2334 } |
|
2335 |
|
2336 // Maybe this should be a static function in tree-plot.cc? |
|
2337 |
620
|
2338 // If TC is matrix, save it on stream OS in a format useful for |
604
|
2339 // making a 3-dimensional plot with gnuplot. If PARAMETRIC is |
|
2340 // nonzero, assume a parametric 3-dimensional plot will be generated. |
|
2341 |
|
2342 int |
620
|
2343 save_three_d (ostream& os, const tree_constant& tc, int parametric) |
604
|
2344 { |
620
|
2345 int fail = 0; |
604
|
2346 |
620
|
2347 int nr = tc.rows (); |
|
2348 int nc = tc.columns (); |
|
2349 |
|
2350 if (tc.is_real_matrix ()) |
604
|
2351 { |
|
2352 os << "# 3D data...\n" |
|
2353 << "# type: matrix\n" |
|
2354 << "# total rows: " << nr << "\n" |
|
2355 << "# total columns: " << nc << "\n"; |
|
2356 |
|
2357 if (parametric) |
|
2358 { |
|
2359 int extras = nc % 3; |
|
2360 if (extras) |
|
2361 warning ("ignoring last %d columns", extras); |
|
2362 |
620
|
2363 Matrix tmp = tc.matrix_value (); |
604
|
2364 for (int i = 0; i < nc-extras; i += 3) |
|
2365 { |
|
2366 os << tmp.extract (0, i, nr-1, i+2); |
|
2367 if (i+3 < nc-extras) |
|
2368 os << "\n"; |
|
2369 } |
|
2370 } |
|
2371 else |
|
2372 { |
620
|
2373 Matrix tmp = tc.matrix_value (); |
604
|
2374 for (int i = 0; i < nc; i++) |
|
2375 { |
|
2376 os << tmp.extract (0, i, nr-1, i); |
|
2377 if (i+1 < nc) |
|
2378 os << "\n"; |
|
2379 } |
|
2380 } |
620
|
2381 } |
|
2382 else |
|
2383 { |
604
|
2384 ::error ("for now, I can only save real matrices in 3D format"); |
620
|
2385 fail = 1; |
604
|
2386 } |
620
|
2387 |
|
2388 return (os && ! fail); |
604
|
2389 } |
|
2390 |
|
2391 /* |
|
2392 ;;; Local Variables: *** |
|
2393 ;;; mode: C++ *** |
|
2394 ;;; page-delimiter: "^/\\*" *** |
|
2395 ;;; End: *** |
|
2396 */ |