Mercurial > octave
annotate src/oct-stream.cc @ 8902:5d5db7a347c6
erase closed files from file list & cache lookup
author | Jaroslav Hajek <highegg@gmail.com> |
---|---|
date | Tue, 03 Mar 2009 08:01:07 +0100 |
parents | 9e3111d203c0 |
children | eb63fbe60fab |
rev | line source |
---|---|
2117 | 1 /* |
2 | |
7017 | 3 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, |
4 2005, 2006, 2007 John W. Eaton | |
2117 | 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. | |
2117 | 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/>. | |
2117 | 21 |
22 */ | |
23 | |
24 #ifdef HAVE_CONFIG_H | |
25 #include <config.h> | |
26 #endif | |
27 | |
3268 | 28 #include <cassert> |
7709
fa41af732801
octave_scan_1: fix reading of hex numbers
Jaroslav Hajek <highegg@gmail.com>
parents:
7538
diff
changeset
|
29 #include <cctype> |
2215 | 30 #include <cstring> |
31 | |
3503 | 32 #include <iomanip> |
3559 | 33 #include <fstream> |
5765 | 34 #include <sstream> |
3535 | 35 #include <string> |
2117 | 36 |
4944 | 37 #include <Array.h> |
38 #include <Array2.h> | |
39 #include <Array3.h> | |
40 | |
41 #include <Array.cc> | |
42 | |
43 #include "byte-swap.h" | |
2117 | 44 #include "lo-ieee.h" |
45 #include "lo-mappers.h" | |
46 #include "lo-utils.h" | |
47 #include "str-vec.h" | |
4153 | 48 #include "quit.h" |
2117 | 49 |
50 #include "error.h" | |
7352 | 51 #include "gripes.h" |
3342 | 52 #include "input.h" |
3775 | 53 #include "oct-stdstrm.h" |
2117 | 54 #include "oct-stream.h" |
2877 | 55 #include "oct-obj.h" |
2117 | 56 #include "utils.h" |
57 | |
58 // Possible values for conv_err: | |
59 // | |
60 // 1 : not a real scalar | |
2902 | 61 // 2 : value is NaN |
62 // 3 : value is not an integer | |
2117 | 63 |
64 static int | |
65 convert_to_valid_int (const octave_value& tc, int& conv_err) | |
66 { | |
67 int retval = 0; | |
68 | |
69 conv_err = 0; | |
70 | |
2902 | 71 double dval = tc.double_value (); |
72 | |
73 if (! error_state) | |
2117 | 74 { |
5389 | 75 if (! lo_ieee_isnan (dval)) |
2117 | 76 { |
2902 | 77 int ival = NINT (dval); |
78 | |
79 if (ival == dval) | |
80 retval = ival; | |
2117 | 81 else |
82 conv_err = 3; | |
83 } | |
84 else | |
85 conv_err = 2; | |
86 } | |
87 else | |
88 conv_err = 1; | |
89 | |
90 return retval; | |
91 } | |
92 | |
93 static int | |
4468 | 94 get_size (double d, const std::string& who) |
2117 | 95 { |
96 int retval = -1; | |
97 | |
5389 | 98 if (! lo_ieee_isnan (d)) |
2117 | 99 { |
100 if (! xisinf (d)) | |
101 { | |
3268 | 102 if (d >= 0.0) |
2117 | 103 retval = NINT (d); |
104 else | |
105 ::error ("%s: negative value invalid as size specification", | |
4468 | 106 who.c_str ()); |
2117 | 107 } |
108 else | |
109 retval = -1; | |
110 } | |
111 else | |
4468 | 112 ::error ("%s: NaN is invalid as size specification", who.c_str ()); |
2117 | 113 |
114 return retval; | |
115 } | |
116 | |
117 static void | |
5275 | 118 get_size (const Array<double>& size, octave_idx_type& nr, octave_idx_type& nc, bool& one_elt_size_spec, |
4468 | 119 const std::string& who) |
2117 | 120 { |
121 nr = -1; | |
122 nc = -1; | |
123 | |
3268 | 124 one_elt_size_spec = false; |
125 | |
2117 | 126 double dnr = -1.0; |
127 double dnc = -1.0; | |
128 | |
5275 | 129 octave_idx_type sz_len = size.length (); |
3810 | 130 |
131 if (sz_len == 1) | |
2601 | 132 { |
3268 | 133 one_elt_size_spec = true; |
134 | |
3810 | 135 dnr = size (0); |
4293 | 136 |
137 dnc = (dnr == 0.0) ? 0.0 : 1.0; | |
2601 | 138 } |
3810 | 139 else if (sz_len == 2) |
2117 | 140 { |
3810 | 141 dnr = size (0); |
142 | |
143 if (! xisinf (dnr)) | |
144 dnc = size (1); | |
145 else | |
4468 | 146 ::error ("%s: invalid size specification", who.c_str ()); |
2117 | 147 } |
148 else | |
4468 | 149 ::error ("%s: invalid size specification", who.c_str ()); |
2117 | 150 |
151 if (! error_state) | |
152 { | |
4468 | 153 nr = get_size (dnr, who); |
2117 | 154 |
3268 | 155 if (! error_state && dnc >= 0.0) |
4468 | 156 nc = get_size (dnc, who); |
2117 | 157 } |
158 } | |
159 | |
3523 | 160 scanf_format_list::scanf_format_list (const std::string& s) |
2117 | 161 : nconv (0), curr_idx (0), list (16), buf (0) |
162 { | |
163 int num_elts = 0; | |
164 | |
165 int n = s.length (); | |
166 | |
167 int i = 0; | |
168 | |
2215 | 169 int width = 0; |
2117 | 170 bool discard = false; |
171 char modifier = '\0'; | |
172 char type = '\0'; | |
173 | |
174 bool have_more = true; | |
175 | |
176 while (i < n) | |
177 { | |
178 have_more = true; | |
179 | |
180 if (! buf) | |
5765 | 181 buf = new std::ostringstream (); |
2117 | 182 |
183 if (s[i] == '%') | |
184 { | |
3483 | 185 // Process percent-escape conversion type. |
186 | |
2215 | 187 process_conversion (s, i, n, width, discard, type, modifier, |
188 num_elts); | |
2117 | 189 have_more = (buf != 0); |
190 } | |
3483 | 191 else if (isspace (s[i])) |
2117 | 192 { |
3483 | 193 type = scanf_format_elt::whitespace_conversion; |
194 | |
2215 | 195 width = 0; |
2117 | 196 discard = false; |
197 modifier = '\0'; | |
3483 | 198 *buf << " "; |
199 | |
200 while (++i < n && isspace (s[i])) | |
201 /* skip whitespace */; | |
202 | |
203 add_elt_to_list (width, discard, type, modifier, num_elts); | |
204 | |
205 have_more = false; | |
206 } | |
207 else | |
208 { | |
209 type = scanf_format_elt::literal_conversion; | |
210 | |
211 width = 0; | |
212 discard = false; | |
213 modifier = '\0'; | |
214 | |
215 while (i < n && ! isspace (s[i]) && s[i] != '%') | |
216 *buf << s[i++]; | |
217 | |
218 add_elt_to_list (width, discard, type, modifier, num_elts); | |
219 | |
220 have_more = false; | |
2117 | 221 } |
222 | |
223 if (nconv < 0) | |
224 { | |
225 have_more = false; | |
226 break; | |
227 } | |
228 } | |
229 | |
230 if (have_more) | |
2215 | 231 add_elt_to_list (width, discard, type, modifier, num_elts); |
2117 | 232 |
233 list.resize (num_elts); | |
234 | |
235 delete buf; | |
236 } | |
237 | |
238 scanf_format_list::~scanf_format_list (void) | |
239 { | |
5275 | 240 octave_idx_type n = list.length (); |
241 | |
242 for (octave_idx_type i = 0; i < n; i++) | |
2117 | 243 { |
3340 | 244 scanf_format_elt *elt = list(i); |
2117 | 245 delete elt; |
246 } | |
247 } | |
248 | |
249 void | |
2215 | 250 scanf_format_list::add_elt_to_list (int width, bool discard, char type, |
3483 | 251 char modifier, int& num_elts, |
3523 | 252 const std::string& char_class) |
2117 | 253 { |
254 if (buf) | |
255 { | |
5765 | 256 std::string text = buf->str (); |
4051 | 257 |
258 if (! text.empty ()) | |
2117 | 259 { |
4051 | 260 scanf_format_elt *elt |
261 = new scanf_format_elt (text.c_str (), width, discard, type, | |
262 modifier, char_class); | |
263 | |
264 if (num_elts == list.length ()) | |
265 list.resize (2 * num_elts); | |
266 | |
267 list(num_elts++) = elt; | |
2117 | 268 } |
269 | |
270 delete buf; | |
271 buf = 0; | |
272 } | |
273 } | |
274 | |
3535 | 275 static std::string |
3523 | 276 expand_char_class (const std::string& s) |
3483 | 277 { |
3523 | 278 std::string retval; |
3483 | 279 |
280 size_t len = s.length (); | |
281 | |
282 size_t i = 0; | |
283 | |
284 while (i < len) | |
285 { | |
286 unsigned char c = s[i++]; | |
287 | |
288 if (c == '-' && i > 1 && i < len | |
5760 | 289 && static_cast<unsigned char> (s[i-2]) <= static_cast<unsigned char> (s[i])) |
3483 | 290 { |
291 // Add all characters from the range except the first (we | |
292 // already added it below). | |
293 | |
294 for (c = s[i-2]+1; c < s[i]; c++) | |
295 retval += c; | |
296 } | |
297 else | |
298 { | |
299 // Add the character to the class. Only add '-' if it is | |
300 // the last character in the class. | |
301 | |
302 if (c != '-' || i == len) | |
303 retval += c; | |
304 } | |
305 } | |
306 | |
307 return retval; | |
308 } | |
309 | |
2117 | 310 void |
3523 | 311 scanf_format_list::process_conversion (const std::string& s, int& i, int n, |
2215 | 312 int& width, bool& discard, char& type, |
2117 | 313 char& modifier, int& num_elts) |
314 { | |
2215 | 315 width = 0; |
2117 | 316 discard = false; |
317 modifier = '\0'; | |
318 type = '\0'; | |
319 | |
320 *buf << s[i++]; | |
321 | |
322 bool have_width = false; | |
323 | |
324 while (i < n) | |
325 { | |
326 switch (s[i]) | |
327 { | |
328 case '*': | |
329 if (discard) | |
330 nconv = -1; | |
331 else | |
332 { | |
333 discard = true; | |
334 *buf << s[i++]; | |
335 } | |
336 break; | |
337 | |
338 case '0': case '1': case '2': case '3': case '4': | |
339 case '5': case '6': case '7': case '8': case '9': | |
340 if (have_width) | |
341 nconv = -1; | |
342 else | |
343 { | |
2215 | 344 char c = s[i++]; |
345 width = width * 10 + c - '0'; | |
2117 | 346 have_width = true; |
2215 | 347 *buf << c; |
2117 | 348 while (i < n && isdigit (s[i])) |
2215 | 349 { |
350 c = s[i++]; | |
351 width = width * 10 + c - '0'; | |
352 *buf << c; | |
353 } | |
2117 | 354 } |
355 break; | |
356 | |
357 case 'h': case 'l': case 'L': | |
358 if (modifier != '\0') | |
359 nconv = -1; | |
360 else | |
2663 | 361 modifier = s[i++]; |
2117 | 362 break; |
363 | |
364 case 'd': case 'i': case 'o': case 'u': case 'x': | |
365 if (modifier == 'L') | |
366 { | |
367 nconv = -1; | |
368 break; | |
369 } | |
370 goto fini; | |
371 | |
372 case 'e': case 'f': case 'g': | |
373 if (modifier == 'h') | |
374 { | |
375 nconv = -1; | |
376 break; | |
377 } | |
2663 | 378 |
379 // No float or long double conversions, thanks. | |
380 *buf << 'l'; | |
381 | |
2117 | 382 goto fini; |
383 | |
384 case 'c': case 's': case 'p': case '%': case '[': | |
385 if (modifier != '\0') | |
386 { | |
387 nconv = -1; | |
388 break; | |
389 } | |
390 goto fini; | |
391 | |
392 fini: | |
393 { | |
2215 | 394 if (finish_conversion (s, i, n, width, discard, type, |
2117 | 395 modifier, num_elts) == 0) |
396 return; | |
397 } | |
398 break; | |
399 | |
400 default: | |
401 nconv = -1; | |
402 break; | |
403 } | |
404 | |
405 if (nconv < 0) | |
406 break; | |
407 } | |
408 | |
409 nconv = -1; | |
410 } | |
411 | |
412 int | |
3523 | 413 scanf_format_list::finish_conversion (const std::string& s, int& i, int n, |
2215 | 414 int& width, bool discard, char& type, |
2117 | 415 char modifier, int& num_elts) |
416 { | |
417 int retval = 0; | |
418 | |
3523 | 419 std::string char_class; |
3483 | 420 |
3640 | 421 int beg_idx = -1; |
422 int end_idx = -1; | |
423 | |
2117 | 424 if (s[i] == '%') |
3640 | 425 { |
426 type = '%'; | |
427 *buf << s[i++]; | |
428 } | |
2117 | 429 else |
430 { | |
431 type = s[i]; | |
432 | |
433 if (s[i] == '[') | |
434 { | |
435 *buf << s[i++]; | |
436 | |
437 if (i < n) | |
438 { | |
3483 | 439 beg_idx = i; |
440 | |
2117 | 441 if (s[i] == '^') |
442 { | |
443 type = '^'; | |
444 *buf << s[i++]; | |
3483 | 445 |
446 if (i < n) | |
447 { | |
448 beg_idx = i; | |
449 | |
450 if (s[i] == ']') | |
451 *buf << s[i++]; | |
452 } | |
2117 | 453 } |
454 else if (s[i] == ']') | |
455 *buf << s[i++]; | |
456 } | |
457 | |
458 while (i < n && s[i] != ']') | |
459 *buf << s[i++]; | |
460 | |
461 if (i < n && s[i] == ']') | |
3483 | 462 { |
463 end_idx = i-1; | |
464 *buf << s[i++]; | |
465 } | |
2117 | 466 |
467 if (s[i-1] != ']') | |
468 retval = nconv = -1; | |
469 } | |
470 else | |
2215 | 471 *buf << s[i++]; |
3640 | 472 } |
473 | |
474 nconv++; | |
475 | |
476 if (nconv > 0) | |
477 { | |
478 if (beg_idx >= 0 && end_idx >= 0) | |
479 char_class = expand_char_class (s.substr (beg_idx, | |
480 end_idx - beg_idx + 1)); | |
481 | |
482 add_elt_to_list (width, discard, type, modifier, num_elts, char_class); | |
2117 | 483 } |
484 | |
485 return retval; | |
486 } | |
487 | |
488 void | |
489 scanf_format_list::printme (void) const | |
490 { | |
491 int n = list.length (); | |
492 | |
493 for (int i = 0; i < n; i++) | |
494 { | |
3340 | 495 scanf_format_elt *elt = list(i); |
2117 | 496 |
3531 | 497 std::cerr |
498 << "width: " << elt->width << "\n" | |
499 << "discard: " << elt->discard << "\n" | |
500 << "type: "; | |
3483 | 501 |
502 if (elt->type == scanf_format_elt::literal_conversion) | |
3531 | 503 std::cerr << "literal text\n"; |
3483 | 504 else if (elt->type == scanf_format_elt::whitespace_conversion) |
3531 | 505 std::cerr << "whitespace\n"; |
3483 | 506 else |
3531 | 507 std::cerr << elt->type << "\n"; |
508 | |
509 std::cerr | |
510 << "modifier: " << elt->modifier << "\n" | |
511 << "char_class: `" << undo_string_escapes (elt->char_class) << "'\n" | |
512 << "text: `" << undo_string_escapes (elt->text) << "'\n\n"; | |
2117 | 513 } |
514 } | |
515 | |
516 bool | |
517 scanf_format_list::all_character_conversions (void) | |
518 { | |
519 int n = list.length (); | |
520 | |
521 if (n > 0) | |
522 { | |
523 for (int i = 0; i < n; i++) | |
524 { | |
3340 | 525 scanf_format_elt *elt = list(i); |
2117 | 526 |
527 switch (elt->type) | |
528 { | |
3483 | 529 case 'c': case 's': case '%': case '[': case '^': |
530 case scanf_format_elt::literal_conversion: | |
531 case scanf_format_elt::whitespace_conversion: | |
2117 | 532 break; |
533 | |
534 default: | |
535 return false; | |
536 break; | |
537 } | |
538 } | |
539 | |
540 return true; | |
541 } | |
542 else | |
543 return false; | |
544 } | |
545 | |
546 bool | |
547 scanf_format_list::all_numeric_conversions (void) | |
548 { | |
549 int n = list.length (); | |
550 | |
551 if (n > 0) | |
552 { | |
553 for (int i = 0; i < n; i++) | |
554 { | |
3340 | 555 scanf_format_elt *elt = list(i); |
2117 | 556 |
557 switch (elt->type) | |
558 { | |
559 case 'd': case 'i': case 'o': case 'u': case 'x': | |
560 case 'e': case 'f': case 'g': | |
561 break; | |
562 | |
563 default: | |
564 return false; | |
565 break; | |
566 } | |
567 } | |
568 | |
569 return true; | |
570 } | |
571 else | |
572 return false; | |
573 } | |
574 | |
575 // Ugh again. | |
576 | |
3523 | 577 printf_format_list::printf_format_list (const std::string& s) |
2117 | 578 : nconv (0), curr_idx (0), list (16), buf (0) |
579 { | |
580 int num_elts = 0; | |
581 | |
582 int n = s.length (); | |
583 | |
584 int i = 0; | |
585 | |
586 int args = 0; | |
3643 | 587 std::string flags; |
3640 | 588 int fw = 0; |
589 int prec = 0; | |
2117 | 590 char modifier = '\0'; |
591 char type = '\0'; | |
592 | |
593 bool have_more = true; | |
3640 | 594 bool empty_buf = true; |
2117 | 595 |
4223 | 596 if (n == 0) |
2117 | 597 { |
4223 | 598 printf_format_elt *elt |
599 = new printf_format_elt ("", args, fw, prec, flags, type, modifier); | |
600 | |
601 list(num_elts++) = elt; | |
602 | |
603 list.resize (num_elts); | |
604 } | |
605 else | |
606 { | |
607 while (i < n) | |
3640 | 608 { |
4223 | 609 have_more = true; |
610 | |
611 if (! buf) | |
612 { | |
5765 | 613 buf = new std::ostringstream (); |
4223 | 614 empty_buf = true; |
615 } | |
616 | |
617 switch (s[i]) | |
618 { | |
619 case '%': | |
3640 | 620 { |
4223 | 621 if (empty_buf) |
622 { | |
623 process_conversion (s, i, n, args, flags, fw, prec, | |
624 type, modifier, num_elts); | |
625 | |
626 have_more = (buf != 0); | |
627 } | |
628 else | |
629 add_elt_to_list (args, flags, fw, prec, type, modifier, | |
630 num_elts); | |
3640 | 631 } |
4223 | 632 break; |
633 | |
634 default: | |
635 { | |
636 args = 0; | |
637 flags = ""; | |
638 fw = 0; | |
639 prec = 0; | |
640 modifier = '\0'; | |
641 type = '\0'; | |
642 *buf << s[i++]; | |
643 empty_buf = false; | |
644 } | |
645 break; | |
646 } | |
647 | |
648 if (nconv < 0) | |
649 { | |
650 have_more = false; | |
651 break; | |
652 } | |
2117 | 653 } |
654 | |
4223 | 655 if (have_more) |
656 add_elt_to_list (args, flags, fw, prec, type, modifier, num_elts); | |
657 | |
658 list.resize (num_elts); | |
659 | |
660 delete buf; | |
2117 | 661 } |
662 } | |
663 | |
664 printf_format_list::~printf_format_list (void) | |
665 { | |
666 int n = list.length (); | |
667 | |
668 for (int i = 0; i < n; i++) | |
669 { | |
3340 | 670 printf_format_elt *elt = list(i); |
2117 | 671 delete elt; |
672 } | |
673 } | |
674 | |
675 void | |
3640 | 676 printf_format_list::add_elt_to_list (int args, const std::string& flags, |
677 int fw, int prec, char type, | |
678 char modifier, int& num_elts) | |
2117 | 679 { |
680 if (buf) | |
681 { | |
5765 | 682 std::string text = buf->str (); |
4051 | 683 |
684 if (! text.empty ()) | |
2117 | 685 { |
4051 | 686 printf_format_elt *elt |
687 = new printf_format_elt (text.c_str (), args, fw, prec, flags, | |
688 type, modifier); | |
689 | |
690 if (num_elts == list.length ()) | |
691 list.resize (2 * num_elts); | |
692 | |
693 list(num_elts++) = elt; | |
2117 | 694 } |
695 | |
696 delete buf; | |
697 buf = 0; | |
698 } | |
699 } | |
700 | |
701 void | |
3640 | 702 printf_format_list::process_conversion |
703 (const std::string& s, int& i, int n, int& args, std::string& flags, | |
704 int& fw, int& prec, char& modifier, char& type, int& num_elts) | |
2117 | 705 { |
706 args = 0; | |
3640 | 707 flags = ""; |
708 fw = 0; | |
709 prec = 0; | |
2117 | 710 modifier = '\0'; |
711 type = '\0'; | |
712 | |
713 *buf << s[i++]; | |
714 | |
4587 | 715 bool nxt = false; |
2117 | 716 |
717 while (i < n) | |
718 { | |
719 switch (s[i]) | |
720 { | |
721 case '-': case '+': case ' ': case '0': case '#': | |
3640 | 722 flags += s[i]; |
2117 | 723 *buf << s[i++]; |
724 break; | |
725 | |
726 default: | |
4587 | 727 nxt = true; |
2117 | 728 break; |
729 } | |
730 | |
4587 | 731 if (nxt) |
2117 | 732 break; |
733 } | |
734 | |
735 if (i < n) | |
736 { | |
737 if (s[i] == '*') | |
738 { | |
3640 | 739 fw = -1; |
2117 | 740 args++; |
741 *buf << s[i++]; | |
742 } | |
743 else | |
744 { | |
3640 | 745 if (isdigit (s[i])) |
746 { | |
4587 | 747 int nn = 0; |
3643 | 748 std::string tmp = s.substr (i); |
4587 | 749 sscanf (tmp.c_str (), "%d%n", &fw, &nn); |
3640 | 750 } |
751 | |
2117 | 752 while (i < n && isdigit (s[i])) |
753 *buf << s[i++]; | |
754 } | |
755 } | |
756 | |
757 if (i < n && s[i] == '.') | |
758 { | |
759 *buf << s[i++]; | |
760 | |
761 if (i < n) | |
762 { | |
763 if (s[i] == '*') | |
764 { | |
3640 | 765 prec = -1; |
2117 | 766 args++; |
767 *buf << s[i++]; | |
768 } | |
769 else | |
770 { | |
3640 | 771 if (isdigit (s[i])) |
772 { | |
4587 | 773 int nn = 0; |
3643 | 774 std::string tmp = s.substr (i); |
4587 | 775 sscanf (tmp.c_str (), "%d%n", &prec, &nn); |
3640 | 776 } |
777 | |
2117 | 778 while (i < n && isdigit (s[i])) |
779 *buf << s[i++]; | |
780 } | |
781 } | |
782 } | |
783 | |
784 if (i < n) | |
785 { | |
786 switch (s[i]) | |
787 { | |
788 case 'h': case 'l': case 'L': | |
789 modifier = s[i]; | |
790 *buf << s[i++]; | |
791 break; | |
792 | |
793 default: | |
794 break; | |
795 } | |
796 } | |
797 | |
798 if (i < n) | |
3640 | 799 finish_conversion (s, i, args, flags, fw, prec, modifier, type, num_elts); |
2117 | 800 else |
801 nconv = -1; | |
802 } | |
803 | |
804 void | |
3640 | 805 printf_format_list::finish_conversion |
806 (const std::string& s, int& i, int args, const std::string& flags, | |
807 int fw, int prec, char modifier, char& type, int& num_elts) | |
2117 | 808 |
809 { | |
810 switch (s[i]) | |
811 { | |
812 case 'd': case 'i': case 'o': case 'x': case 'X': | |
813 case 'u': case 'c': | |
814 if (modifier == 'L') | |
815 { | |
816 nconv = -1; | |
817 break; | |
818 } | |
819 goto fini; | |
820 | |
821 case 'f': case 'e': case 'E': case 'g': case 'G': | |
822 if (modifier == 'h' || modifier == 'l') | |
823 { | |
824 nconv = -1; | |
825 break; | |
826 } | |
827 goto fini; | |
828 | |
829 case 's': case 'p': case '%': | |
830 if (modifier != '\0') | |
831 { | |
832 nconv = -1; | |
833 break; | |
834 } | |
835 goto fini; | |
836 | |
837 fini: | |
838 | |
3640 | 839 type = s[i]; |
840 | |
841 *buf << s[i++]; | |
842 | |
843 if (type != '%' || args != 0) | |
844 nconv++; | |
845 | |
846 if (type != '%') | |
847 args++; | |
848 | |
849 add_elt_to_list (args, flags, fw, prec, type, modifier, num_elts); | |
850 | |
2117 | 851 break; |
852 | |
853 default: | |
854 nconv = -1; | |
855 break; | |
856 } | |
857 } | |
858 | |
859 void | |
860 printf_format_list::printme (void) const | |
861 { | |
862 int n = list.length (); | |
863 | |
864 for (int i = 0; i < n; i++) | |
865 { | |
3340 | 866 printf_format_elt *elt = list(i); |
2117 | 867 |
3640 | 868 std::cerr |
869 << "args: " << elt->args << "\n" | |
870 << "flags: `" << elt->flags << "'\n" | |
871 << "width: " << elt->fw << "\n" | |
872 << "prec: " << elt->prec << "\n" | |
873 << "type: `" << elt->type << "'\n" | |
874 << "modifier: `" << elt->modifier << "'\n" | |
875 << "text: `" << undo_string_escapes (elt->text) << "'\n\n"; | |
2117 | 876 } |
877 } | |
878 | |
3145 | 879 int |
3148 | 880 octave_base_stream::file_number (void) |
3145 | 881 { |
882 // Kluge alert! | |
883 | |
884 if (name () == "stdin") | |
885 return 0; | |
886 | |
887 if (name () == "stdout") | |
888 return 1; | |
889 | |
890 if (name () == "stderr") | |
891 return 2; | |
892 | |
893 int retval = -1; | |
894 | |
3523 | 895 std::istream *is = input_stream (); |
896 std::ostream *os = output_stream (); | |
3145 | 897 |
3775 | 898 // There is no standard way to get the underlying file descriptor from |
899 // std::filebuf (nor in the GNU libstdc++-v3 implementation). We cache | |
900 // the descriptor in c_file_ptr_buf, and then extract it here. | |
901 | |
6757 | 902 c_file_ptr_buf *ibuf |
903 = is ? dynamic_cast<c_file_ptr_buf *> (is->rdbuf ()) : 0; | |
904 | |
905 c_file_ptr_buf *obuf | |
906 = os ? dynamic_cast<c_file_ptr_buf *> (os->rdbuf ()) : 0; | |
3775 | 907 |
908 int i_fid = ibuf ? ibuf->file_number () : -1; | |
909 int o_fid = obuf ? obuf->file_number () : -1; | |
3145 | 910 |
911 if (i_fid >= 0) | |
912 { | |
913 if (o_fid >= 0) | |
914 retval = (i_fid == o_fid) ? i_fid : -1; | |
915 else | |
916 retval = i_fid; | |
917 } | |
918 else if (o_fid >= 0) | |
919 retval = o_fid; | |
920 | |
921 return retval; | |
922 } | |
923 | |
2117 | 924 void |
3523 | 925 octave_base_stream::error (const std::string& msg) |
2117 | 926 { |
927 fail = true; | |
928 errmsg = msg; | |
929 } | |
930 | |
931 void | |
4468 | 932 octave_base_stream::error (const std::string& who, const std::string& msg) |
933 { | |
934 fail = true; | |
6296 | 935 errmsg = who + ": " + msg; |
4468 | 936 } |
937 | |
938 void | |
2117 | 939 octave_base_stream::clear (void) |
940 { | |
4889 | 941 fail = false; |
942 errmsg = ""; | |
943 } | |
944 | |
945 void | |
946 octave_base_stream::clearerr (void) | |
947 { | |
4888 | 948 std::istream *is = input_stream (); |
949 std::ostream *os = output_stream (); | |
950 | |
951 if (is) | |
952 is->clear (); | |
953 | |
954 if (os) | |
955 os->clear (); | |
2117 | 956 } |
957 | |
958 // Functions that are defined for all input streams (input streams | |
959 // are those that define is). | |
960 | |
3536 | 961 std::string |
5275 | 962 octave_base_stream::do_gets (octave_idx_type max_len, bool& err, |
4468 | 963 bool strip_newline, const std::string& who) |
2117 | 964 { |
3523 | 965 std::string retval; |
2117 | 966 |
8773
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
967 if ((interactive || forced_interactive) && file_number () == 0) |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
968 { |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
969 ::error ("%s: unable to read from stdin while running interactively", |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
970 who.c_str ()); |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
971 |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
972 return retval; |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
973 } |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
974 |
2117 | 975 err = false; |
976 | |
3523 | 977 std::istream *isp = input_stream (); |
2117 | 978 |
979 if (isp) | |
980 { | |
3523 | 981 std::istream& is = *isp; |
2117 | 982 |
5765 | 983 std::ostringstream buf; |
2117 | 984 |
985 int c = 0; | |
3553 | 986 int char_count = 0; |
6345 | 987 |
988 if (max_len != 0) | |
2117 | 989 { |
6345 | 990 while (is && (c = is.get ()) != EOF) |
2117 | 991 { |
6345 | 992 char_count++; |
993 | |
8739
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
994 // Handle CRLF, CR, or LF as line ending. |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
995 |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
996 if (c == '\r') |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
997 { |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
998 if (! strip_newline) |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
999 buf << static_cast<char> (c); |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1000 |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1001 c = is.get (); |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1002 |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1003 if (c != EOF) |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1004 { |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1005 if (c == '\n') |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1006 { |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1007 char_count++; |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1008 |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1009 if (! strip_newline) |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1010 buf << static_cast<char> (c); |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1011 } |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1012 else |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1013 is.putback (c); |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1014 } |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1015 |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1016 break; |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1017 } |
d477e57e811c
handle CRLF and CR in fgetl/fgets
John W. Eaton <jwe@octave.org>
parents:
8021
diff
changeset
|
1018 else if (c == '\n') |
6345 | 1019 { |
1020 if (! strip_newline) | |
1021 buf << static_cast<char> (c); | |
1022 | |
1023 break; | |
1024 } | |
1025 else | |
5760 | 1026 buf << static_cast<char> (c); |
6345 | 1027 |
1028 if (max_len > 0 && char_count == max_len) | |
1029 break; | |
2117 | 1030 } |
6345 | 1031 } |
1032 | |
1033 if (! is.eof () && char_count > 0) | |
1034 { | |
1035 // GAGME. Matlab seems to check for EOF even if the last | |
1036 // character in a file is a newline character. This is NOT | |
1037 // what the corresponding C-library functions do. | |
1038 int disgusting_compatibility_hack = is.get (); | |
1039 if (! is.eof ()) | |
1040 is.putback (disgusting_compatibility_hack); | |
2117 | 1041 } |
1042 | |
4224 | 1043 if (is.good () || (is.eof () && char_count > 0)) |
5765 | 1044 retval = buf.str (); |
4224 | 1045 else |
1046 { | |
1047 err = true; | |
4468 | 1048 |
4224 | 1049 if (is.eof () && char_count == 0) |
4468 | 1050 error (who, "at end of file"); |
4224 | 1051 else |
4468 | 1052 error (who, "read error"); |
4224 | 1053 } |
2117 | 1054 } |
1055 else | |
1056 { | |
1057 err = true; | |
4468 | 1058 invalid_operation (who, "reading"); |
2117 | 1059 } |
1060 | |
1061 return retval; | |
1062 } | |
1063 | |
3536 | 1064 std::string |
5275 | 1065 octave_base_stream::getl (octave_idx_type max_len, bool& err, const std::string& who) |
2117 | 1066 { |
4468 | 1067 return do_gets (max_len, err, true, who); |
2117 | 1068 } |
1069 | |
3536 | 1070 std::string |
5275 | 1071 octave_base_stream::gets (octave_idx_type max_len, bool& err, const std::string& who) |
2117 | 1072 { |
4468 | 1073 return do_gets (max_len, err, false, who); |
2117 | 1074 } |
1075 | |
3640 | 1076 #define OCTAVE_SCAN(is, fmt, arg) octave_scan (is, fmt, arg) |
3636 | 1077 |
1078 template <class T> | |
1079 std::istream& | |
6767 | 1080 octave_scan_1 (std::istream& is, const scanf_format_elt& fmt, T* valptr) |
3636 | 1081 { |
3779 | 1082 T& ref = *valptr; |
1083 | |
1084 switch (fmt.type) | |
1085 { | |
1086 case 'o': | |
4926 | 1087 is >> std::oct >> ref >> std::dec; |
3779 | 1088 break; |
1089 | |
1090 case 'x': | |
4926 | 1091 is >> std::hex >> ref >> std::dec; |
1092 break; | |
1093 | |
1094 case 'i': | |
1095 { | |
1096 int c1 = is.get (); | |
1097 | |
1098 if (! is.eof ()) | |
1099 { | |
1100 if (c1 == '0') | |
1101 { | |
7709
fa41af732801
octave_scan_1: fix reading of hex numbers
Jaroslav Hajek <highegg@gmail.com>
parents:
7538
diff
changeset
|
1102 int c2 = is.peek (); |
4926 | 1103 |
1104 if (c2 == 'x' || c2 == 'X') | |
7709
fa41af732801
octave_scan_1: fix reading of hex numbers
Jaroslav Hajek <highegg@gmail.com>
parents:
7538
diff
changeset
|
1105 { |
fa41af732801
octave_scan_1: fix reading of hex numbers
Jaroslav Hajek <highegg@gmail.com>
parents:
7538
diff
changeset
|
1106 is.ignore (); |
fa41af732801
octave_scan_1: fix reading of hex numbers
Jaroslav Hajek <highegg@gmail.com>
parents:
7538
diff
changeset
|
1107 if (std::isxdigit (is.peek ())) |
fa41af732801
octave_scan_1: fix reading of hex numbers
Jaroslav Hajek <highegg@gmail.com>
parents:
7538
diff
changeset
|
1108 is >> std::hex >> ref >> std::dec; |
fa41af732801
octave_scan_1: fix reading of hex numbers
Jaroslav Hajek <highegg@gmail.com>
parents:
7538
diff
changeset
|
1109 else |
fa41af732801
octave_scan_1: fix reading of hex numbers
Jaroslav Hajek <highegg@gmail.com>
parents:
7538
diff
changeset
|
1110 ref = 0; |
fa41af732801
octave_scan_1: fix reading of hex numbers
Jaroslav Hajek <highegg@gmail.com>
parents:
7538
diff
changeset
|
1111 } |
4926 | 1112 else |
4927 | 1113 { |
1114 if (c2 == '0' || c2 == '1' || c2 == '2' | |
1115 || c2 == '3' || c2 == '4' || c2 == '5' | |
1116 || c2 == '6' || c2 == '7') | |
1117 is >> std::oct >> ref >> std::dec; | |
1118 else | |
1119 ref = 0; | |
1120 } | |
4926 | 1121 } |
1122 else | |
1123 { | |
1124 is.putback (c1); | |
1125 | |
1126 is >> ref; | |
1127 } | |
1128 } | |
1129 } | |
3779 | 1130 break; |
1131 | |
1132 default: | |
1133 is >> ref; | |
1134 break; | |
1135 } | |
3639 | 1136 |
3638 | 1137 return is; |
3636 | 1138 } |
1139 | |
6767 | 1140 template <class T> |
1141 std::istream& | |
1142 octave_scan (std::istream& is, const scanf_format_elt& fmt, T* valptr) | |
1143 { | |
1144 if (fmt.width) | |
1145 { | |
1146 // Limit input to fmt.width characters by reading into a | |
1147 // temporary stringstream buffer. | |
1148 | |
1149 std::string tmp; | |
1150 | |
1151 is.width (fmt.width); | |
1152 is >> tmp; | |
1153 | |
1154 std::istringstream ss (tmp); | |
1155 | |
1156 octave_scan_1 (ss, fmt, valptr); | |
1157 } | |
1158 else | |
1159 octave_scan_1 (is, fmt, valptr); | |
1160 | |
1161 return is; | |
1162 } | |
1163 | |
3779 | 1164 // Note that this specialization is only used for reading characters, not |
1165 // character strings. See BEGIN_S_CONVERSION for details. | |
1166 | |
1167 template<> | |
1168 std::istream& | |
4661 | 1169 octave_scan<> (std::istream& is, const scanf_format_elt& /* fmt */, |
1170 char* valptr) | |
3779 | 1171 { |
1172 return is >> valptr; | |
1173 } | |
3636 | 1174 |
4595 | 1175 template std::istream& |
1176 octave_scan (std::istream&, const scanf_format_elt&, int*); | |
1177 | |
1178 template std::istream& | |
1179 octave_scan (std::istream&, const scanf_format_elt&, long int*); | |
1180 | |
1181 template std::istream& | |
1182 octave_scan (std::istream&, const scanf_format_elt&, short int*); | |
1183 | |
1184 template std::istream& | |
1185 octave_scan (std::istream&, const scanf_format_elt&, unsigned int*); | |
1186 | |
1187 template std::istream& | |
1188 octave_scan (std::istream&, const scanf_format_elt&, unsigned long int*); | |
1189 | |
1190 template std::istream& | |
1191 octave_scan (std::istream&, const scanf_format_elt&, unsigned short int*); | |
1192 | |
1193 #if 0 | |
1194 template std::istream& | |
1195 octave_scan (std::istream&, const scanf_format_elt&, float*); | |
1196 #endif | |
1197 | |
5403 | 1198 template<> |
5176 | 1199 std::istream& |
5403 | 1200 octave_scan<> (std::istream& is, const scanf_format_elt& fmt, double* valptr) |
5176 | 1201 { |
1202 double& ref = *valptr; | |
1203 | |
1204 switch (fmt.type) | |
1205 { | |
1206 case 'e': | |
1207 case 'f': | |
1208 case 'g': | |
1209 { | |
5259 | 1210 int c1 = EOF; |
5176 | 1211 |
1212 while (is && (c1 = is.get ()) != EOF && isspace (c1)) | |
1213 /* skip whitespace */; | |
1214 | |
1215 if (c1 != EOF) | |
1216 { | |
1217 if (c1 == 'N') | |
1218 { | |
1219 int c2 = is.get (); | |
1220 | |
1221 if (c2 != EOF) | |
1222 { | |
1223 if (c2 == 'A') | |
1224 { | |
1225 int c3 = is.get (); | |
1226 | |
1227 if (c3 != EOF) | |
1228 { | |
1229 is.putback (c3); | |
1230 | |
1231 if (isspace (c3) || ispunct (c3)) | |
1232 ref = octave_NA; | |
1233 else | |
1234 { | |
1235 is.putback (c2); | |
1236 is.putback (c1); | |
1237 | |
1238 is >> ref; | |
1239 } | |
1240 } | |
1241 else | |
1242 { | |
1243 is.clear (); | |
1244 | |
1245 ref = octave_NA; | |
1246 } | |
1247 } | |
1248 else if (c2 == 'a') | |
1249 { | |
1250 int c3 = is.get (); | |
1251 | |
1252 if (c3 != EOF) | |
1253 { | |
1254 if (c3 == 'N') | |
1255 { | |
1256 int c4 = is.get (); | |
1257 | |
1258 if (c4 != EOF) | |
1259 { | |
1260 is.putback (c4); | |
1261 | |
1262 if (isspace (c4) || ispunct (c4)) | |
1263 ref = octave_NaN; | |
1264 else | |
1265 { | |
1266 is.putback (c3); | |
1267 is.putback (c2); | |
1268 is.putback (c1); | |
1269 | |
1270 is >> ref; | |
1271 } | |
1272 } | |
1273 else | |
1274 { | |
1275 is.clear (); | |
1276 | |
1277 ref = octave_NaN; | |
1278 } | |
1279 } | |
1280 else | |
1281 { | |
1282 is.putback (c3); | |
1283 is.putback (c2); | |
1284 is.putback (c1); | |
1285 | |
1286 is >> ref; | |
1287 } | |
1288 } | |
1289 } | |
1290 else | |
1291 { | |
1292 is.putback (c2); | |
1293 is.putback (c1); | |
1294 | |
1295 is >> ref; | |
1296 } | |
1297 } | |
1298 } | |
1299 else if (c1 == 'I') | |
1300 { | |
1301 int c2 = is.get (); | |
1302 | |
1303 if (c2 != EOF) | |
1304 { | |
1305 if (c2 == 'n') | |
1306 { | |
1307 int c3 = is.get (); | |
1308 | |
1309 if (c3 != EOF) | |
6483 | 1310 { |
1311 if (c3 == 'f') | |
1312 { | |
1313 int c4 = is.get (); | |
1314 | |
1315 if (c4 != EOF) | |
1316 { | |
1317 is.putback (c4); | |
1318 | |
1319 if (isspace (c4) || ispunct (c4)) | |
1320 ref = octave_Inf; | |
1321 else | |
1322 { | |
1323 is.putback (c3); | |
1324 is.putback (c2); | |
1325 is.putback (c1); | |
1326 | |
1327 is >> ref; | |
1328 } | |
1329 } | |
1330 else | |
1331 { | |
1332 is.clear (); | |
1333 | |
5176 | 1334 ref = octave_Inf; |
6483 | 1335 } |
1336 } | |
1337 else | |
1338 { | |
1339 is.putback (c3); | |
1340 is.putback (c2); | |
1341 is.putback (c1); | |
1342 | |
1343 is >> ref; | |
1344 } | |
1345 } | |
1346 else | |
1347 { | |
1348 is.putback (c2); | |
1349 is.putback (c1); | |
1350 | |
1351 is >> ref; | |
1352 } | |
5176 | 1353 } |
1354 } | |
1355 } | |
1356 else | |
1357 { | |
1358 is.putback (c1); | |
1359 | |
1360 is >> ref; | |
1361 } | |
1362 } | |
1363 } | |
1364 break; | |
1365 | |
1366 default: | |
1367 panic_impossible (); | |
1368 break; | |
1369 } | |
1370 | |
1371 return is; | |
1372 } | |
1373 | |
2572 | 1374 template <class T> |
1375 void | |
3636 | 1376 do_scanf_conv (std::istream& is, const scanf_format_elt& fmt, |
5275 | 1377 T valptr, Matrix& mval, double *data, octave_idx_type& idx, |
1378 octave_idx_type& conversion_count, octave_idx_type nr, octave_idx_type max_size, | |
3636 | 1379 bool discard) |
2572 | 1380 { |
3640 | 1381 OCTAVE_SCAN (is, fmt, valptr); |
2572 | 1382 |
1383 if (is) | |
1384 { | |
1385 if (idx == max_size && ! discard) | |
1386 { | |
1387 max_size *= 2; | |
1388 | |
1389 if (nr > 0) | |
1390 mval.resize (nr, max_size / nr, 0.0); | |
1391 else | |
1392 mval.resize (max_size, 1, 0.0); | |
1393 | |
1394 data = mval.fortran_vec (); | |
1395 } | |
1396 | |
1397 if (! discard) | |
3268 | 1398 { |
3559 | 1399 conversion_count++; |
3268 | 1400 data[idx++] = *(valptr); |
1401 } | |
2572 | 1402 } |
1403 } | |
1404 | |
1405 template void | |
3878 | 1406 do_scanf_conv (std::istream&, const scanf_format_elt&, int*, |
5275 | 1407 Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); |
2572 | 1408 |
3233 | 1409 template void |
3636 | 1410 do_scanf_conv (std::istream&, const scanf_format_elt&, long int*, |
5275 | 1411 Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); |
3233 | 1412 |
1413 template void | |
3636 | 1414 do_scanf_conv (std::istream&, const scanf_format_elt&, short int*, |
5275 | 1415 Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); |
3233 | 1416 |
3878 | 1417 template void |
1418 do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned int*, | |
5275 | 1419 Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); |
3878 | 1420 |
1421 template void | |
1422 do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned long int*, | |
5275 | 1423 Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); |
3878 | 1424 |
1425 template void | |
1426 do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned short int*, | |
5275 | 1427 Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); |
3878 | 1428 |
2600 | 1429 #if 0 |
2572 | 1430 template void |
3636 | 1431 do_scanf_conv (std::istream&, const scanf_format_elt&, float*, |
5275 | 1432 Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); |
2600 | 1433 #endif |
2572 | 1434 |
1435 template void | |
3636 | 1436 do_scanf_conv (std::istream&, const scanf_format_elt&, double*, |
5275 | 1437 Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); |
2572 | 1438 |
3483 | 1439 #define DO_WHITESPACE_CONVERSION() \ |
1440 do \ | |
1441 { \ | |
1442 int c = EOF; \ | |
1443 \ | |
1444 while (is && (c = is.get ()) != EOF && isspace (c)) \ | |
1445 /* skip whitespace */; \ | |
1446 \ | |
1447 if (c != EOF) \ | |
1448 is.putback (c); \ | |
1449 } \ | |
1450 while (0) | |
1451 | |
1452 #define DO_LITERAL_CONVERSION() \ | |
1453 do \ | |
1454 { \ | |
1455 int c = EOF; \ | |
1456 \ | |
1457 int n = strlen (fmt); \ | |
1458 int i = 0; \ | |
1459 \ | |
1460 while (i < n && is && (c = is.get ()) != EOF) \ | |
1461 { \ | |
5326 | 1462 if (c == static_cast<unsigned char> (fmt[i])) \ |
3483 | 1463 { \ |
1464 i++; \ | |
1465 continue; \ | |
1466 } \ | |
1467 else \ | |
1468 { \ | |
1469 is.putback (c); \ | |
1470 break; \ | |
1471 } \ | |
1472 } \ | |
1473 \ | |
1474 if (i != n) \ | |
3538 | 1475 is.setstate (std::ios::failbit); \ |
3483 | 1476 } \ |
1477 while (0) | |
1478 | |
3640 | 1479 #define DO_PCT_CONVERSION() \ |
1480 do \ | |
1481 { \ | |
1482 int c = is.get (); \ | |
1483 \ | |
1484 if (c != EOF) \ | |
1485 { \ | |
1486 if (c != '%') \ | |
1487 { \ | |
1488 is.putback (c); \ | |
1489 is.setstate (std::ios::failbit); \ | |
1490 } \ | |
1491 } \ | |
1492 else \ | |
1493 is.setstate (std::ios::failbit); \ | |
1494 } \ | |
1495 while (0) | |
1496 | |
3483 | 1497 #define BEGIN_C_CONVERSION() \ |
3538 | 1498 is.unsetf (std::ios::skipws); \ |
3483 | 1499 \ |
1500 int width = elt->width ? elt->width : 1; \ | |
1501 \ | |
4051 | 1502 char *tbuf = new char[width + 1]; \ |
3483 | 1503 \ |
1504 int c = EOF; \ | |
1505 int n = 0; \ | |
1506 \ | |
1507 while (is && n < width && (c = is.get ()) != EOF) \ | |
5760 | 1508 tbuf[n++] = static_cast<char> (c); \ |
4051 | 1509 \ |
1510 tbuf[n] = '\0'; \ | |
3483 | 1511 \ |
5266 | 1512 if (n > 0 && c == EOF) \ |
1513 is.clear (); \ | |
1514 \ | |
4051 | 1515 std::string tmp = tbuf; \ |
1516 \ | |
1517 delete [] tbuf | |
3483 | 1518 |
1519 // For a `%s' format, skip initial whitespace and then read until the | |
5338 | 1520 // next whitespace character or until WIDTH characters have been read. |
3483 | 1521 #define BEGIN_S_CONVERSION() \ |
1522 int width = elt->width; \ | |
1523 \ | |
4051 | 1524 std::string tmp; \ |
3483 | 1525 \ |
1526 do \ | |
1527 { \ | |
1528 if (width) \ | |
5338 | 1529 { \ |
1530 char *tbuf = new char [width+1]; \ | |
1531 \ | |
1532 int c = EOF; \ | |
1533 \ | |
1534 int n = 0; \ | |
1535 \ | |
1536 while (is && (c = is.get ()) != EOF) \ | |
1537 { \ | |
1538 if (! isspace (c)) \ | |
1539 { \ | |
1540 tbuf[n++] = static_cast<char> (c); \ | |
1541 break; \ | |
1542 } \ | |
1543 } \ | |
4051 | 1544 \ |
5338 | 1545 while (is && n < width && (c = is.get ()) != EOF) \ |
1546 { \ | |
1547 if (isspace (c)) \ | |
1548 { \ | |
1549 is.putback (c); \ | |
1550 break; \ | |
1551 } \ | |
1552 else \ | |
1553 tbuf[n++] = static_cast<char> (c); \ | |
1554 } \ | |
3483 | 1555 \ |
5338 | 1556 tbuf[n] = '\0'; \ |
1557 \ | |
1558 if (n > 0 && c == EOF) \ | |
1559 is.clear (); \ | |
1560 \ | |
4051 | 1561 tmp = tbuf; \ |
5338 | 1562 \ |
4051 | 1563 delete [] tbuf; \ |
5338 | 1564 } \ |
3483 | 1565 else \ |
5338 | 1566 { \ |
1567 is >> std::ws >> tmp; \ | |
1568 } \ | |
3483 | 1569 } \ |
1570 while (0) | |
1571 | |
1572 // This format must match a nonempty sequence of characters. | |
1573 #define BEGIN_CHAR_CLASS_CONVERSION() \ | |
1574 int width = elt->width; \ | |
1575 \ | |
4051 | 1576 std::string tmp; \ |
3483 | 1577 \ |
1578 do \ | |
1579 { \ | |
7426 | 1580 if (! width) \ |
7427 | 1581 width = INT_MAX; \ |
1582 \ | |
7426 | 1583 std::ostringstream buf; \ |
1584 \ | |
1585 std::string char_class = elt->char_class; \ | |
4051 | 1586 \ |
7426 | 1587 int c = EOF; \ |
3483 | 1588 \ |
7426 | 1589 if (elt->type == '[') \ |
1590 { \ | |
1591 int chars_read = 0; \ | |
1592 while (is && chars_read++ < width && (c = is.get ()) != EOF \ | |
8021 | 1593 && char_class.find (c) != std::string::npos) \ |
7426 | 1594 buf << static_cast<char> (c); \ |
3483 | 1595 } \ |
1596 else \ | |
1597 { \ | |
7426 | 1598 int chars_read = 0; \ |
1599 while (is && chars_read++ < width && (c = is.get ()) != EOF \ | |
8021 | 1600 && char_class.find (c) == std::string::npos) \ |
7426 | 1601 buf << static_cast<char> (c); \ |
1602 } \ | |
3483 | 1603 \ |
7426 | 1604 if (width == INT_MAX && c != EOF) \ |
1605 is.putback (c); \ | |
3483 | 1606 \ |
7426 | 1607 tmp = buf.str (); \ |
3483 | 1608 \ |
7426 | 1609 if (tmp.empty ()) \ |
1610 is.setstate (std::ios::failbit); \ | |
3483 | 1611 } \ |
1612 while (0) | |
1613 | |
3410 | 1614 #define FINISH_CHARACTER_CONVERSION() \ |
1615 do \ | |
1616 { \ | |
4051 | 1617 width = tmp.length (); \ |
3410 | 1618 \ |
1619 if (is) \ | |
1620 { \ | |
1621 int i = 0; \ | |
1622 \ | |
1623 if (! discard) \ | |
1624 { \ | |
1625 conversion_count++; \ | |
1626 \ | |
1627 while (i < width && tmp[i] != '\0') \ | |
1628 { \ | |
1629 if (data_index == max_size) \ | |
1630 { \ | |
1631 max_size *= 2; \ | |
1632 \ | |
4420 | 1633 if (all_char_conv) \ |
3410 | 1634 { \ |
4420 | 1635 if (one_elt_size_spec) \ |
3410 | 1636 mval.resize (1, max_size, 0.0); \ |
4420 | 1637 else if (nr > 0) \ |
1638 mval.resize (nr, max_size / nr, 0.0); \ | |
3410 | 1639 else \ |
4420 | 1640 panic_impossible (); \ |
3410 | 1641 } \ |
4420 | 1642 else if (nr > 0) \ |
6970 | 1643 mval.resize (nr, max_size / nr, 0.0); \ |
4420 | 1644 else \ |
1645 mval.resize (max_size, 1, 0.0); \ | |
3410 | 1646 \ |
1647 data = mval.fortran_vec (); \ | |
1648 } \ | |
1649 \ | |
1650 data[data_index++] = tmp[i++]; \ | |
1651 } \ | |
1652 } \ | |
1653 } \ | |
1654 } \ | |
1655 while (0) | |
2117 | 1656 |
1657 octave_value | |
1658 octave_base_stream::do_scanf (scanf_format_list& fmt_list, | |
5275 | 1659 octave_idx_type nr, octave_idx_type nc, bool one_elt_size_spec, |
1660 octave_idx_type& conversion_count, const std::string& who) | |
2117 | 1661 { |
8773
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
1662 octave_value retval = Matrix (); |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
1663 |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
1664 if ((interactive || forced_interactive) && file_number () == 0) |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
1665 { |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
1666 ::error ("%s: unable to read from stdin while running interactively", |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
1667 who.c_str ()); |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
1668 |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
1669 return retval; |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
1670 } |
9e3111d203c0
disallow reading from stdin while running interactively
John W. Eaton <jwe@octave.org>
parents:
8739
diff
changeset
|
1671 |
3268 | 1672 conversion_count = 0; |
1673 | |
3640 | 1674 int nconv = fmt_list.num_conversions (); |
1675 | |
5275 | 1676 octave_idx_type data_index = 0; |
2121 | 1677 |
3268 | 1678 if (nr == 0 || nc == 0) |
1679 { | |
1680 if (one_elt_size_spec) | |
1681 nc = 0; | |
1682 | |
1683 return Matrix (nr, nc, 0.0); | |
1684 } | |
1685 | |
3523 | 1686 std::istream *isp = input_stream (); |
2117 | 1687 |
1688 bool all_char_conv = fmt_list.all_character_conversions (); | |
1689 | |
1690 Matrix mval; | |
1691 double *data = 0; | |
5275 | 1692 octave_idx_type max_size = 0; |
1693 octave_idx_type max_conv = 0; | |
1694 | |
1695 octave_idx_type final_nr = 0; | |
1696 octave_idx_type final_nc = 0; | |
2117 | 1697 |
3268 | 1698 if (all_char_conv) |
1699 { | |
4420 | 1700 // Any of these could be resized later (if we have %s |
1701 // conversions, we may read more than one element for each | |
1702 // conversion). | |
1703 | |
3268 | 1704 if (one_elt_size_spec) |
1705 { | |
3410 | 1706 max_size = 512; |
1707 mval.resize (1, max_size, 0.0); | |
1708 | |
3268 | 1709 if (nr > 0) |
1710 max_conv = nr; | |
1711 } | |
4420 | 1712 else if (nr > 0) |
3268 | 1713 { |
4420 | 1714 if (nc > 0) |
1715 { | |
1716 mval.resize (nr, nc, 0.0); | |
1717 max_size = max_conv = nr * nc; | |
1718 } | |
1719 else | |
1720 { | |
1721 mval.resize (nr, 32, 0.0); | |
1722 max_size = nr * 32; | |
1723 } | |
3268 | 1724 } |
4420 | 1725 else |
1726 panic_impossible (); | |
3268 | 1727 } |
1728 else if (nr > 0) | |
2117 | 1729 { |
1730 if (nc > 0) | |
1731 { | |
4420 | 1732 // Will not resize later. |
2117 | 1733 mval.resize (nr, nc, 0.0); |
1734 max_size = nr * nc; | |
3268 | 1735 max_conv = max_size; |
2117 | 1736 } |
1737 else | |
1738 { | |
4420 | 1739 // Maybe resize later. |
2117 | 1740 mval.resize (nr, 32, 0.0); |
2121 | 1741 max_size = nr * 32; |
2117 | 1742 } |
1743 } | |
1744 else | |
1745 { | |
4420 | 1746 // Maybe resize later. |
2117 | 1747 mval.resize (32, 1, 0.0); |
1748 max_size = 32; | |
1749 } | |
1750 | |
4420 | 1751 data = mval.fortran_vec (); |
1752 | |
2117 | 1753 if (isp) |
1754 { | |
3523 | 1755 std::istream& is = *isp; |
2117 | 1756 |
1757 const scanf_format_elt *elt = fmt_list.first (); | |
1758 | |
3538 | 1759 std::ios::fmtflags flags = is.flags (); |
2213 | 1760 |
2117 | 1761 for (;;) |
1762 { | |
4153 | 1763 OCTAVE_QUIT; |
1764 | |
2117 | 1765 if (elt) |
1766 { | |
3268 | 1767 if (max_conv > 0 && conversion_count == max_conv) |
1768 { | |
1769 if (all_char_conv && one_elt_size_spec) | |
1770 { | |
1771 final_nr = 1; | |
1772 final_nc = data_index; | |
1773 } | |
1774 else | |
1775 { | |
1776 final_nr = nr; | |
1777 final_nc = (data_index - 1) / nr + 1; | |
1778 } | |
1779 | |
1780 break; | |
1781 } | |
1782 else if (data_index == max_size) | |
2117 | 1783 { |
3410 | 1784 max_size *= 2; |
1785 | |
4420 | 1786 if (all_char_conv) |
2687 | 1787 { |
4420 | 1788 if (one_elt_size_spec) |
3410 | 1789 mval.resize (1, max_size, 0.0); |
4420 | 1790 else if (nr > 0) |
1791 mval.resize (nr, max_size / nr, 0.0); | |
3410 | 1792 else |
4420 | 1793 panic_impossible (); |
2687 | 1794 } |
4420 | 1795 else if (nr > 0) |
6970 | 1796 mval.resize (nr, max_size / nr, 0.0); |
4420 | 1797 else |
1798 mval.resize (max_size, 1, 0.0); | |
3410 | 1799 |
1800 data = mval.fortran_vec (); | |
2117 | 1801 } |
1802 | |
1803 const char *fmt = elt->text; | |
1804 | |
1805 bool discard = elt->discard; | |
1806 | |
1807 switch (elt->type) | |
1808 { | |
3483 | 1809 case scanf_format_elt::whitespace_conversion: |
1810 DO_WHITESPACE_CONVERSION (); | |
1811 break; | |
1812 | |
1813 case scanf_format_elt::literal_conversion: | |
1814 DO_LITERAL_CONVERSION (); | |
1815 break; | |
1816 | |
2117 | 1817 case '%': |
3640 | 1818 DO_PCT_CONVERSION (); |
3483 | 1819 break; |
2117 | 1820 |
3878 | 1821 case 'd': case 'i': |
2117 | 1822 { |
3233 | 1823 switch (elt->modifier) |
1824 { | |
1825 case 'h': | |
1826 { | |
1827 short int tmp; | |
3779 | 1828 do_scanf_conv (is, *elt, &tmp, mval, data, |
3268 | 1829 data_index, conversion_count, |
3233 | 1830 nr, max_size, discard); |
1831 } | |
3483 | 1832 break; |
3233 | 1833 |
1834 case 'l': | |
1835 { | |
1836 long int tmp; | |
3779 | 1837 do_scanf_conv (is, *elt, &tmp, mval, data, |
3268 | 1838 data_index, conversion_count, |
3233 | 1839 nr, max_size, discard); |
1840 } | |
3483 | 1841 break; |
3233 | 1842 |
1843 default: | |
1844 { | |
1845 int tmp; | |
3779 | 1846 do_scanf_conv (is, *elt, &tmp, mval, data, |
3268 | 1847 data_index, conversion_count, |
3233 | 1848 nr, max_size, discard); |
1849 } | |
3483 | 1850 break; |
3233 | 1851 } |
2117 | 1852 } |
3483 | 1853 break; |
2117 | 1854 |
3878 | 1855 case 'o': case 'u': case 'x': |
1856 { | |
1857 switch (elt->modifier) | |
1858 { | |
1859 case 'h': | |
1860 { | |
1861 unsigned short int tmp; | |
1862 do_scanf_conv (is, *elt, &tmp, mval, data, | |
1863 data_index, conversion_count, | |
1864 nr, max_size, discard); | |
1865 } | |
1866 break; | |
1867 | |
1868 case 'l': | |
1869 { | |
1870 unsigned long int tmp; | |
1871 do_scanf_conv (is, *elt, &tmp, mval, data, | |
1872 data_index, conversion_count, | |
1873 nr, max_size, discard); | |
1874 } | |
1875 break; | |
1876 | |
1877 default: | |
1878 { | |
1879 unsigned int tmp; | |
1880 do_scanf_conv (is, *elt, &tmp, mval, data, | |
1881 data_index, conversion_count, | |
1882 nr, max_size, discard); | |
1883 } | |
1884 break; | |
1885 } | |
1886 } | |
1887 break; | |
1888 | |
2117 | 1889 case 'e': case 'f': case 'g': |
1890 { | |
2600 | 1891 double tmp; |
1892 | |
3779 | 1893 do_scanf_conv (is, *elt, &tmp, mval, data, |
3268 | 1894 data_index, conversion_count, |
2600 | 1895 nr, max_size, discard); |
2117 | 1896 } |
3483 | 1897 break; |
2117 | 1898 |
2213 | 1899 case 'c': |
3410 | 1900 { |
3483 | 1901 BEGIN_C_CONVERSION (); |
3410 | 1902 |
1903 FINISH_CHARACTER_CONVERSION (); | |
3483 | 1904 |
1905 is.setf (flags); | |
3410 | 1906 } |
1907 break; | |
2213 | 1908 |
2117 | 1909 case 's': |
1910 { | |
3483 | 1911 BEGIN_S_CONVERSION (); |
3268 | 1912 |
3410 | 1913 FINISH_CHARACTER_CONVERSION (); |
2117 | 1914 } |
3483 | 1915 break; |
1916 | |
1917 case '[': case '^': | |
1918 { | |
1919 BEGIN_CHAR_CLASS_CONVERSION (); | |
1920 | |
1921 FINISH_CHARACTER_CONVERSION (); | |
1922 } | |
1923 break; | |
1924 | |
1925 case 'p': | |
4468 | 1926 error ("%s: unsupported format specifier", who.c_str ()); |
2117 | 1927 break; |
1928 | |
1929 default: | |
4468 | 1930 error ("%s: internal format error", who.c_str ()); |
2117 | 1931 break; |
1932 } | |
1933 | |
1934 if (! ok ()) | |
1935 { | |
1936 break; | |
1937 } | |
1938 else if (! is) | |
1939 { | |
3268 | 1940 if (all_char_conv) |
2117 | 1941 { |
3268 | 1942 if (one_elt_size_spec) |
1943 { | |
1944 final_nr = 1; | |
1945 final_nc = data_index; | |
1946 } | |
1947 else if (data_index > nr) | |
2117 | 1948 { |
2759 | 1949 final_nr = nr; |
3268 | 1950 final_nc = (data_index - 1) / nr + 1; |
2117 | 1951 } |
1952 else | |
1953 { | |
3268 | 1954 final_nr = data_index; |
1955 final_nc = 1; | |
1956 } | |
1957 } | |
1958 else if (nr > 0) | |
1959 { | |
1960 if (data_index > nr) | |
1961 { | |
1962 final_nr = nr; | |
1963 final_nc = (data_index - 1) / nr + 1; | |
1964 } | |
1965 else | |
1966 { | |
1967 final_nr = data_index; | |
2117 | 1968 final_nc = 1; |
1969 } | |
1970 } | |
1971 else | |
1972 { | |
3268 | 1973 final_nr = data_index; |
2759 | 1974 final_nc = 1; |
1975 } | |
1976 | |
3337 | 1977 // If it looks like we have a matching failure, then |
1978 // reset the failbit in the stream state. | |
1979 | |
3538 | 1980 if (is.rdstate () & std::ios::failbit) |
1981 is.clear (is.rdstate () & (~std::ios::failbit)); | |
3337 | 1982 |
5775 | 1983 // FIXME -- is this the right thing to do? |
3342 | 1984 |
1985 if (interactive && name () == "stdin") | |
2759 | 1986 { |
1987 is.clear (); | |
1988 | |
1989 // Skip to end of line. | |
1990 | |
1991 bool err; | |
4468 | 1992 do_gets (-1, err, false, who); |
2117 | 1993 } |
1994 | |
1995 break; | |
1996 } | |
1997 } | |
1998 else | |
1999 { | |
4468 | 2000 error ("%s: internal format error", who.c_str ()); |
2117 | 2001 break; |
2002 } | |
2003 | |
3640 | 2004 elt = fmt_list.next (nconv > 0); |
2117 | 2005 } |
2006 } | |
2007 | |
2008 if (ok ()) | |
2009 { | |
2121 | 2010 mval.resize (final_nr, final_nc, 0.0); |
2117 | 2011 |
3268 | 2012 retval = mval; |
2013 | |
2117 | 2014 if (all_char_conv) |
5279 | 2015 retval = retval.convert_to_str (false, true); |
2117 | 2016 } |
2017 | |
2018 return retval; | |
2019 } | |
2020 | |
2021 octave_value | |
3810 | 2022 octave_base_stream::scanf (const std::string& fmt, const Array<double>& size, |
5275 | 2023 octave_idx_type& conversion_count, const std::string& who) |
2117 | 2024 { |
2025 octave_value retval = Matrix (); | |
2026 | |
3559 | 2027 conversion_count = 0; |
2117 | 2028 |
3523 | 2029 std::istream *isp = input_stream (); |
2117 | 2030 |
2031 if (isp) | |
2032 { | |
2033 scanf_format_list fmt_list (fmt); | |
2034 | |
3640 | 2035 if (fmt_list.num_conversions () == -1) |
4468 | 2036 ::error ("%s: invalid format specified", who.c_str ()); |
3640 | 2037 else |
2117 | 2038 { |
5275 | 2039 octave_idx_type nr = -1; |
2040 octave_idx_type nc = -1; | |
3640 | 2041 |
2042 bool one_elt_size_spec; | |
2043 | |
4468 | 2044 get_size (size, nr, nc, one_elt_size_spec, who); |
3640 | 2045 |
2046 if (! error_state) | |
2047 retval = do_scanf (fmt_list, nr, nc, one_elt_size_spec, | |
4468 | 2048 conversion_count, who); |
2215 | 2049 } |
2050 } | |
2051 else | |
4468 | 2052 invalid_operation (who, "reading"); |
2572 | 2053 |
2054 return retval; | |
2055 } | |
2056 | |
2712 | 2057 bool |
2058 octave_base_stream::do_oscanf (const scanf_format_elt *elt, | |
4468 | 2059 octave_value& retval, const std::string& who) |
2572 | 2060 { |
2712 | 2061 bool quit = false; |
2215 | 2062 |
3523 | 2063 std::istream *isp = input_stream (); |
2215 | 2064 |
2065 if (isp) | |
2066 { | |
3523 | 2067 std::istream& is = *isp; |
2215 | 2068 |
3538 | 2069 std::ios::fmtflags flags = is.flags (); |
2215 | 2070 |
2071 if (elt) | |
2072 { | |
2073 const char *fmt = elt->text; | |
2074 | |
2075 bool discard = elt->discard; | |
2076 | |
2077 switch (elt->type) | |
2078 { | |
3483 | 2079 case scanf_format_elt::whitespace_conversion: |
2080 DO_WHITESPACE_CONVERSION (); | |
2081 break; | |
2082 | |
2083 case scanf_format_elt::literal_conversion: | |
2084 DO_LITERAL_CONVERSION (); | |
2085 break; | |
2086 | |
2215 | 2087 case '%': |
2088 { | |
3640 | 2089 DO_PCT_CONVERSION (); |
2090 | |
2091 if (! is) | |
2712 | 2092 quit = true; |
3640 | 2093 |
2215 | 2094 } |
2095 break; | |
2096 | |
3878 | 2097 case 'd': case 'i': |
2215 | 2098 { |
2099 int tmp; | |
2100 | |
3640 | 2101 if (OCTAVE_SCAN (is, *elt, &tmp)) |
2712 | 2102 { |
2103 if (! discard) | |
4233 | 2104 retval = tmp; |
2712 | 2105 } |
2106 else | |
2107 quit = true; | |
2215 | 2108 } |
2109 break; | |
2110 | |
3878 | 2111 case 'o': case 'u': case 'x': |
2112 { | |
2113 long int tmp; | |
2114 | |
2115 if (OCTAVE_SCAN (is, *elt, &tmp)) | |
2116 { | |
2117 if (! discard) | |
4254 | 2118 retval = tmp; |
3878 | 2119 } |
2120 else | |
2121 quit = true; | |
2122 } | |
2123 break; | |
2124 | |
2215 | 2125 case 'e': case 'f': case 'g': |
2126 { | |
2600 | 2127 double tmp; |
2128 | |
3640 | 2129 if (OCTAVE_SCAN (is, *elt, &tmp)) |
2712 | 2130 { |
2131 if (! discard) | |
2132 retval = tmp; | |
2133 } | |
2134 else | |
2135 quit = true; | |
2215 | 2136 } |
2137 break; | |
2138 | |
2139 case 'c': | |
2140 { | |
3483 | 2141 BEGIN_C_CONVERSION (); |
2142 | |
2143 if (! discard) | |
2144 retval = tmp; | |
2145 | |
2146 if (! is) | |
2712 | 2147 quit = true; |
2215 | 2148 |
2149 is.setf (flags); | |
2150 } | |
2151 break; | |
2152 | |
2153 case 's': | |
2154 { | |
3483 | 2155 BEGIN_S_CONVERSION (); |
2156 | |
2157 if (! discard) | |
2158 retval = tmp; | |
2572 | 2159 |
3268 | 2160 if (! is) |
2161 quit = true; | |
2215 | 2162 } |
2163 break; | |
2164 | |
3483 | 2165 case '[': case '^': |
2166 { | |
2167 BEGIN_CHAR_CLASS_CONVERSION (); | |
2168 | |
2169 if (! discard) | |
2170 retval = tmp; | |
2171 | |
2172 if (! is) | |
2173 quit = true; | |
2174 } | |
2175 break; | |
2176 | |
2177 case 'p': | |
4468 | 2178 error ("%s: unsupported format specifier", who.c_str ()); |
2215 | 2179 break; |
2180 | |
2181 default: | |
4468 | 2182 error ("%s: internal format error", who.c_str ()); |
2215 | 2183 break; |
2184 } | |
2185 } | |
2186 | |
2187 if (ok () && is.fail ()) | |
2188 { | |
4468 | 2189 error ("%s: read error", who.c_str ()); |
3483 | 2190 |
5775 | 2191 // FIXME -- is this the right thing to do? |
3342 | 2192 |
2193 if (interactive && name () == "stdin") | |
2215 | 2194 { |
2195 // Skip to end of line. | |
2196 | |
2197 bool err; | |
4468 | 2198 do_gets (-1, err, false, who); |
2215 | 2199 } |
2200 } | |
2201 } | |
2202 | |
2712 | 2203 return quit; |
2215 | 2204 } |
2205 | |
2206 octave_value_list | |
4468 | 2207 octave_base_stream::oscanf (const std::string& fmt, const std::string& who) |
2215 | 2208 { |
2209 octave_value_list retval; | |
2210 | |
3523 | 2211 std::istream *isp = input_stream (); |
2215 | 2212 |
2213 if (isp) | |
2214 { | |
3523 | 2215 std::istream& is = *isp; |
2215 | 2216 |
2217 scanf_format_list fmt_list (fmt); | |
2218 | |
2219 int nconv = fmt_list.num_conversions (); | |
2220 | |
3640 | 2221 if (nconv == -1) |
4468 | 2222 ::error ("%s: invalid format specified", who.c_str ()); |
3640 | 2223 else |
2215 | 2224 { |
3640 | 2225 is.clear (); |
2226 | |
2227 int len = fmt_list.length (); | |
2228 | |
2229 retval.resize (nconv+1, Matrix ()); | |
2230 | |
2231 const scanf_format_elt *elt = fmt_list.first (); | |
2232 | |
2233 int num_values = 0; | |
2234 | |
2235 bool quit = false; | |
2236 | |
5275 | 2237 for (octave_idx_type i = 0; i < len; i++) |
3640 | 2238 { |
2239 octave_value tmp; | |
2240 | |
4468 | 2241 quit = do_oscanf (elt, tmp, who); |
3640 | 2242 |
2243 if (quit) | |
2244 break; | |
2245 else | |
2246 { | |
2247 if (tmp.is_defined ()) | |
2248 retval (num_values++) = tmp; | |
2249 | |
2250 if (! ok ()) | |
2251 break; | |
2252 | |
2253 elt = fmt_list.next (nconv > 0); | |
2254 } | |
2255 } | |
2256 | |
4233 | 2257 retval(nconv) = num_values; |
3640 | 2258 |
2259 if (! quit) | |
2260 { | |
2261 // Pick up any trailing stuff. | |
2262 if (ok () && len > nconv) | |
2263 { | |
2264 octave_value tmp; | |
3704 | 2265 |
2266 elt = fmt_list.next (); | |
2267 | |
4468 | 2268 do_oscanf (elt, tmp, who); |
3640 | 2269 } |
2270 } | |
2117 | 2271 } |
2272 } | |
2273 else | |
4468 | 2274 invalid_operation (who, "reading"); |
2117 | 2275 |
2276 return retval; | |
2277 } | |
2278 | |
2279 // Functions that are defined for all output streams (output streams | |
2280 // are those that define os). | |
2281 | |
2282 int | |
2283 octave_base_stream::flush (void) | |
2284 { | |
2285 int retval = -1; | |
2286 | |
3523 | 2287 std::ostream *os = output_stream (); |
2117 | 2288 |
2289 if (os) | |
2290 { | |
2291 os->flush (); | |
2292 | |
2293 if (os->good ()) | |
2294 retval = 0; | |
2295 } | |
2296 else | |
2297 invalid_operation ("fflush", "writing"); | |
2298 | |
2299 return retval; | |
2300 } | |
2301 | |
2302 class | |
2303 printf_value_cache | |
2304 { | |
2305 public: | |
2306 | |
3653 | 2307 enum state { ok, conversion_error }; |
2117 | 2308 |
7352 | 2309 printf_value_cache (const octave_value_list& args, const std::string& who) |
2117 | 2310 : values (args), val_idx (0), elt_idx (0), |
2311 n_vals (values.length ()), n_elts (0), data (0), | |
7352 | 2312 curr_state (ok) |
2313 { | |
2314 for (octave_idx_type i = 0; i < values.length (); i++) | |
2315 { | |
2316 octave_value val = values(i); | |
2317 | |
2318 if (val.is_map () || val.is_cell () || val.is_object () | |
2319 || val.is_list ()) | |
2320 { | |
2321 gripe_wrong_type_arg (who, val); | |
2322 break; | |
2323 } | |
2324 } | |
2325 } | |
2117 | 2326 |
2327 ~printf_value_cache (void) { } | |
2328 | |
2329 // Get the current value as a double and advance the internal pointer. | |
2330 double double_value (void); | |
2331 | |
2332 // Get the current value as an int and advance the internal pointer. | |
2333 int int_value (void); | |
2334 | |
2335 // Get the current value as a string and advance the internal pointer. | |
3523 | 2336 std::string string_value (void); |
2117 | 2337 |
3145 | 2338 operator bool () const { return (curr_state == ok); } |
2117 | 2339 |
3653 | 2340 bool exhausted (void) { return (val_idx >= n_vals); } |
2117 | 2341 |
2342 private: | |
2343 | |
2344 const octave_value_list values; | |
2345 int val_idx; | |
2346 int elt_idx; | |
2347 int n_vals; | |
2348 int n_elts; | |
2349 const double *data; | |
4874 | 2350 NDArray curr_val; |
2117 | 2351 state curr_state; |
2352 | |
2353 // Must create value cache with values! | |
2354 | |
2355 printf_value_cache (void); | |
2356 | |
2357 // No copying! | |
2358 | |
2359 printf_value_cache (const printf_value_cache&); | |
2360 | |
2361 printf_value_cache& operator = (const printf_value_cache&); | |
2362 }; | |
2363 | |
2364 double | |
2365 printf_value_cache::double_value (void) | |
2366 { | |
2367 double retval = 0.0; | |
2368 | |
3711 | 2369 if (exhausted ()) |
2370 curr_state = conversion_error; | |
2371 | |
2372 while (! exhausted ()) | |
2117 | 2373 { |
2374 if (! data) | |
2375 { | |
2376 octave_value tmp_val = values (val_idx); | |
2377 | |
5476 | 2378 // Force string conversion here for compatibility. |
2379 | |
2380 curr_val = tmp_val.array_value (true); | |
2117 | 2381 |
2382 if (! error_state) | |
2383 { | |
2384 elt_idx = 0; | |
2385 n_elts = curr_val.length (); | |
2386 data = curr_val.data (); | |
2387 } | |
2388 else | |
2389 { | |
2390 curr_state = conversion_error; | |
2391 break; | |
2392 } | |
2393 } | |
2394 | |
2395 if (elt_idx < n_elts) | |
2396 { | |
3653 | 2397 retval = data[elt_idx++]; |
2398 | |
2399 if (elt_idx >= n_elts) | |
2400 { | |
2401 elt_idx = 0; | |
2402 val_idx++; | |
2403 data = 0; | |
2404 } | |
2405 | |
2117 | 2406 break; |
2407 } | |
2408 else | |
2409 { | |
2410 val_idx++; | |
2411 data = 0; | |
3969 | 2412 |
2413 if (n_elts == 0 && exhausted ()) | |
2414 curr_state = conversion_error; | |
2415 | |
2117 | 2416 continue; |
2417 } | |
2418 } | |
2419 | |
2420 return retval; | |
2421 } | |
2422 | |
2423 int | |
2424 printf_value_cache::int_value (void) | |
2425 { | |
2426 int retval = 0; | |
2427 | |
2428 double dval = double_value (); | |
2429 | |
2430 if (! error_state) | |
2431 { | |
2432 if (D_NINT (dval) == dval) | |
2433 retval = NINT (dval); | |
2434 else | |
2435 curr_state = conversion_error; | |
2436 } | |
2437 | |
2438 return retval; | |
2439 } | |
2440 | |
3536 | 2441 std::string |
2117 | 2442 printf_value_cache::string_value (void) |
2443 { | |
3523 | 2444 std::string retval; |
2117 | 2445 |
4425 | 2446 if (exhausted ()) |
2447 curr_state = conversion_error; | |
4257 | 2448 else |
2117 | 2449 { |
4425 | 2450 octave_value tval = values (val_idx++); |
2451 | |
2452 if (tval.rows () == 1) | |
2453 retval = tval.string_value (); | |
2454 else | |
2455 { | |
2456 // In the name of Matlab compatibility. | |
2457 | |
2458 charMatrix chm = tval.char_matrix_value (); | |
2459 | |
5275 | 2460 octave_idx_type nr = chm.rows (); |
2461 octave_idx_type nc = chm.columns (); | |
4425 | 2462 |
2463 int k = 0; | |
2464 | |
2465 retval.resize (nr * nc, '\0'); | |
2466 | |
5275 | 2467 for (octave_idx_type j = 0; j < nc; j++) |
2468 for (octave_idx_type i = 0; i < nr; i++) | |
4425 | 2469 retval[k++] = chm(i,j); |
2470 } | |
2471 | |
2472 if (error_state) | |
2473 curr_state = conversion_error; | |
2117 | 2474 } |
4257 | 2475 |
2117 | 2476 return retval; |
2477 } | |
2478 | |
2479 // Ugh again and again. | |
2480 | |
2572 | 2481 template <class T> |
3620 | 2482 int |
3523 | 2483 do_printf_conv (std::ostream& os, const char *fmt, int nsa, int sa_1, |
4468 | 2484 int sa_2, T arg, const std::string& who) |
2572 | 2485 { |
3620 | 2486 int retval = 0; |
2487 | |
2572 | 2488 switch (nsa) |
2489 { | |
2490 case 2: | |
3640 | 2491 retval = octave_format (os, fmt, sa_1, sa_2, arg); |
2572 | 2492 break; |
2493 | |
2494 case 1: | |
3640 | 2495 retval = octave_format (os, fmt, sa_1, arg); |
2572 | 2496 break; |
2497 | |
2498 case 0: | |
3640 | 2499 retval = octave_format (os, fmt, arg); |
2572 | 2500 break; |
2501 | |
2502 default: | |
4468 | 2503 ::error ("%s: internal error handling format", who.c_str ()); |
2572 | 2504 break; |
2505 } | |
3620 | 2506 |
2507 return retval; | |
2572 | 2508 } |
2509 | |
3620 | 2510 template int |
4468 | 2511 do_printf_conv (std::ostream&, const char*, int, int, int, int, |
2512 const std::string&); | |
2513 | |
2514 template int | |
2515 do_printf_conv (std::ostream&, const char*, int, int, int, long, | |
2516 const std::string&); | |
2517 | |
3878 | 2518 template int |
4468 | 2519 do_printf_conv (std::ostream&, const char*, int, int, int, unsigned int, |
2520 const std::string&); | |
2521 | |
2522 template int | |
2523 do_printf_conv (std::ostream&, const char*, int, int, int, unsigned long, | |
2524 const std::string&); | |
2525 | |
2526 template int | |
2527 do_printf_conv (std::ostream&, const char*, int, int, int, double, | |
2528 const std::string&); | |
2529 | |
2530 template int | |
2531 do_printf_conv (std::ostream&, const char*, int, int, int, const char*, | |
2532 const std::string&); | |
2117 | 2533 |
6492 | 2534 #define DO_DOUBLE_CONV(TQUAL) \ |
2535 do \ | |
2536 { \ | |
7199 | 2537 if (val > std::numeric_limits<TQUAL long>::max () \ |
2538 || val < std::numeric_limits<TQUAL long>::min ()) \ | |
6492 | 2539 { \ |
7199 | 2540 std::string tfmt = fmt; \ |
6492 | 2541 \ |
7199 | 2542 tfmt.replace (tfmt.rfind (elt->type), 1, ".f"); \ |
6492 | 2543 \ |
7199 | 2544 if (elt->modifier == 'l') \ |
2545 tfmt.replace (tfmt.rfind (elt->modifier), 1, ""); \ | |
2546 \ | |
2547 retval += do_printf_conv (os, tfmt.c_str (), nsa, sa_1, sa_2, \ | |
2548 val, who); \ | |
6492 | 2549 } \ |
2550 else \ | |
7199 | 2551 retval += do_printf_conv (os, fmt, nsa, sa_1, sa_2, \ |
2552 static_cast<TQUAL long> (val), who); \ | |
6492 | 2553 } \ |
2554 while (0) | |
2555 | |
2117 | 2556 int |
2557 octave_base_stream::do_printf (printf_format_list& fmt_list, | |
4468 | 2558 const octave_value_list& args, |
2559 const std::string& who) | |
2117 | 2560 { |
3620 | 2561 int retval = 0; |
2117 | 2562 |
3640 | 2563 int nconv = fmt_list.num_conversions (); |
2564 | |
3523 | 2565 std::ostream *osp = output_stream (); |
2117 | 2566 |
2567 if (osp) | |
2568 { | |
3523 | 2569 std::ostream& os = *osp; |
2117 | 2570 |
2571 const printf_format_elt *elt = fmt_list.first (); | |
2572 | |
7352 | 2573 printf_value_cache val_cache (args, who); |
2574 | |
2575 if (error_state) | |
2576 return retval; | |
2117 | 2577 |
2578 for (;;) | |
2579 { | |
4153 | 2580 OCTAVE_QUIT; |
2581 | |
2117 | 2582 if (elt) |
2583 { | |
3640 | 2584 // NSA is the number of `star' args to convert. |
2585 | |
2586 int nsa = (elt->fw < 0) + (elt->prec < 0); | |
2117 | 2587 |
2588 int sa_1 = 0; | |
2589 int sa_2 = 0; | |
2590 | |
2591 if (nsa > 0) | |
2592 { | |
2593 sa_1 = val_cache.int_value (); | |
2594 | |
2595 if (! val_cache) | |
2596 break; | |
2597 else | |
2598 { | |
2599 if (nsa > 1) | |
2600 { | |
2601 sa_2 = val_cache.int_value (); | |
2602 | |
2603 if (! val_cache) | |
2604 break; | |
2605 } | |
2606 } | |
2607 } | |
2608 | |
2609 const char *fmt = elt->text; | |
2610 | |
3640 | 2611 if (elt->type == '%') |
2612 { | |
2613 os << "%"; | |
2614 retval++; | |
2615 } | |
2616 else if (elt->args == 0 && elt->text) | |
2617 { | |
2618 os << elt->text; | |
2619 retval += strlen (elt->text); | |
2620 } | |
4257 | 2621 else if (elt->type == 's') |
3640 | 2622 { |
2623 std::string val = val_cache.string_value (); | |
2624 | |
2625 if (val_cache) | |
2626 retval += do_printf_conv (os, fmt, nsa, sa_1, | |
4468 | 2627 sa_2, val.c_str (), who); |
3640 | 2628 else |
2629 break; | |
2630 } | |
2117 | 2631 else |
2632 { | |
3640 | 2633 double val = val_cache.double_value (); |
2634 | |
2635 if (val_cache) | |
2117 | 2636 { |
6492 | 2637 if (lo_ieee_isnan (val) || xisinf (val)) |
4303 | 2638 { |
2639 std::string tfmt = fmt; | |
6865 | 2640 std::string::size_type i1, i2; |
2641 | |
2642 tfmt.replace ((i1 = tfmt.rfind (elt->type)), | |
2643 1, 1, 's'); | |
2644 | |
8021 | 2645 if ((i2 = tfmt.rfind ('.')) != std::string::npos && i2 < i1) |
6865 | 2646 { |
2647 tfmt.erase (i2, i1-i2); | |
2648 if (elt->prec < 0) | |
2649 nsa--; | |
2650 } | |
6492 | 2651 |
2652 const char *tval = xisinf (val) | |
2653 ? (val < 0 ? "-Inf" : "Inf") | |
2654 : (lo_ieee_is_NA (val) ? "NA" : "NaN"); | |
2655 | |
2656 retval += do_printf_conv (os, tfmt.c_str (), | |
2657 nsa, sa_1, sa_2, | |
2658 tval, who); | |
4303 | 2659 } |
2660 else | |
3640 | 2661 { |
6492 | 2662 char type = elt->type; |
2663 | |
2664 switch (type) | |
4303 | 2665 { |
2666 case 'd': case 'i': case 'c': | |
7227 | 2667 DO_DOUBLE_CONV (OCTAVE_EMPTY_CPP_ARG); |
4303 | 2668 break; |
2669 | |
2670 case 'o': case 'x': case 'X': case 'u': | |
6492 | 2671 DO_DOUBLE_CONV (unsigned); |
4303 | 2672 break; |
2673 | |
2674 case 'f': case 'e': case 'E': | |
2675 case 'g': case 'G': | |
2676 retval | |
2677 += do_printf_conv (os, fmt, nsa, sa_1, sa_2, | |
4468 | 2678 val, who); |
4303 | 2679 break; |
2680 | |
2681 default: | |
4468 | 2682 error ("%s: invalid format specifier", |
2683 who.c_str ()); | |
4303 | 2684 return -1; |
2685 break; | |
2686 } | |
3640 | 2687 } |
2117 | 2688 } |
2689 else | |
3620 | 2690 break; |
2117 | 2691 } |
2692 | |
3620 | 2693 if (! os) |
2117 | 2694 { |
4468 | 2695 error ("%s: write error", who.c_str ()); |
2117 | 2696 break; |
2697 } | |
2698 } | |
2699 else | |
2700 { | |
4468 | 2701 ::error ("%s: internal error handling format", who.c_str ()); |
2117 | 2702 retval = -1; |
2703 break; | |
2704 } | |
2705 | |
3640 | 2706 elt = fmt_list.next (nconv > 0 && ! val_cache.exhausted ()); |
2707 | |
2708 if (! elt || (val_cache.exhausted () && elt->args > 0)) | |
2709 break; | |
2710 } | |
2117 | 2711 } |
3640 | 2712 else |
4468 | 2713 invalid_operation (who, "writing"); |
2117 | 2714 |
2715 return retval; | |
2716 } | |
2717 | |
2718 int | |
3640 | 2719 octave_base_stream::printf (const std::string& fmt, |
4468 | 2720 const octave_value_list& args, |
2721 const std::string& who) | |
2117 | 2722 { |
3640 | 2723 int retval = 0; |
2724 | |
2725 printf_format_list fmt_list (fmt); | |
2726 | |
2727 if (fmt_list.num_conversions () == -1) | |
4468 | 2728 ::error ("%s: invalid format specified", who.c_str ()); |
2117 | 2729 else |
4468 | 2730 retval = do_printf (fmt_list, args, who); |
2117 | 2731 |
2732 return retval; | |
2733 } | |
2734 | |
2735 int | |
4468 | 2736 octave_base_stream::puts (const std::string& s, const std::string& who) |
2117 | 2737 { |
2738 int retval = -1; | |
2739 | |
3523 | 2740 std::ostream *osp = output_stream (); |
2117 | 2741 |
2742 if (osp) | |
2743 { | |
3523 | 2744 std::ostream& os = *osp; |
2117 | 2745 |
2746 os << s; | |
2747 | |
2748 if (os) | |
2749 { | |
5775 | 2750 // FIXME -- why does this seem to be necessary? |
2117 | 2751 // Without it, output from a loop like |
2752 // | |
2753 // for i = 1:100, fputs (stdout, "foo\n"); endfor | |
2754 // | |
2755 // doesn't seem to go to the pager immediately. | |
2756 | |
2757 os.flush (); | |
2758 | |
2759 if (os) | |
2760 retval = 0; | |
2761 else | |
4468 | 2762 error ("%s: write error", who.c_str ()); |
2117 | 2763 } |
2764 else | |
4468 | 2765 error ("%s: write error", who.c_str ()); |
2117 | 2766 } |
2767 else | |
4468 | 2768 invalid_operation (who, "writing"); |
2117 | 2769 |
2770 return retval; | |
2771 } | |
2772 | |
2773 // Return current error message for this stream. | |
2774 | |
3536 | 2775 std::string |
2435 | 2776 octave_base_stream::error (bool clear_err, int& err_num) |
2117 | 2777 { |
2435 | 2778 err_num = fail ? -1 : 0; |
2117 | 2779 |
3523 | 2780 std::string tmp = errmsg; |
2117 | 2781 |
2782 if (clear_err) | |
2783 clear (); | |
2784 | |
2785 return tmp; | |
2786 } | |
2787 | |
2788 void | |
4468 | 2789 octave_base_stream::invalid_operation (const std::string& who, const char *rw) |
2117 | 2790 { |
4468 | 2791 // Note that this is not ::error () ! |
2792 | |
6297 | 2793 error (who, std::string ("stream not open for ") + rw); |
2117 | 2794 } |
2795 | |
3552 | 2796 octave_stream::octave_stream (octave_base_stream *bs) |
3340 | 2797 : rep (bs) |
2798 { | |
2799 if (rep) | |
2800 rep->count = 1; | |
2801 } | |
2802 | |
2803 octave_stream::~octave_stream (void) | |
2804 { | |
2805 if (rep && --rep->count == 0) | |
2806 delete rep; | |
2807 } | |
2808 | |
2809 octave_stream::octave_stream (const octave_stream& s) | |
2810 : rep (s.rep) | |
2811 { | |
2812 if (rep) | |
2813 rep->count++; | |
2814 } | |
2815 | |
2816 octave_stream& | |
2817 octave_stream::operator = (const octave_stream& s) | |
2818 { | |
2819 if (rep != s.rep) | |
2820 { | |
2821 if (rep && --rep->count == 0) | |
2822 delete rep; | |
2823 | |
2824 rep = s.rep; | |
2825 | |
2826 if (rep) | |
2827 rep->count++; | |
2828 } | |
2829 | |
2830 return *this; | |
2831 } | |
2832 | |
2117 | 2833 int |
2834 octave_stream::flush (void) | |
2835 { | |
2836 int retval = -1; | |
2837 | |
5659 | 2838 if (stream_ok ()) |
2117 | 2839 retval = rep->flush (); |
2840 | |
2841 return retval; | |
2842 } | |
2843 | |
3536 | 2844 std::string |
5275 | 2845 octave_stream::getl (octave_idx_type max_len, bool& err, const std::string& who) |
2117 | 2846 { |
3523 | 2847 std::string retval; |
2117 | 2848 |
5659 | 2849 if (stream_ok ()) |
4468 | 2850 retval = rep->getl (max_len, err, who); |
2117 | 2851 |
2852 return retval; | |
2853 } | |
2854 | |
3536 | 2855 std::string |
4468 | 2856 octave_stream::getl (const octave_value& tc_max_len, bool& err, |
2857 const std::string& who) | |
2117 | 2858 { |
3523 | 2859 std::string retval; |
2117 | 2860 |
2861 err = false; | |
2862 | |
2863 int conv_err = 0; | |
2864 | |
6345 | 2865 int max_len = -1; |
2866 | |
2867 if (tc_max_len.is_defined ()) | |
2117 | 2868 { |
6345 | 2869 max_len = convert_to_valid_int (tc_max_len, conv_err); |
2870 | |
2871 if (conv_err || max_len < 0) | |
2872 { | |
2873 err = true; | |
2874 ::error ("%s: invalid maximum length specified", who.c_str ()); | |
2875 } | |
2117 | 2876 } |
6345 | 2877 |
2878 if (! error_state) | |
4468 | 2879 retval = getl (max_len, err, who); |
2117 | 2880 |
2881 return retval; | |
2882 } | |
2883 | |
3536 | 2884 std::string |
5275 | 2885 octave_stream::gets (octave_idx_type max_len, bool& err, const std::string& who) |
2117 | 2886 { |
3523 | 2887 std::string retval; |
2117 | 2888 |
5659 | 2889 if (stream_ok ()) |
4468 | 2890 retval = rep->gets (max_len, err, who); |
2117 | 2891 |
2892 return retval; | |
2893 } | |
2894 | |
3536 | 2895 std::string |
4468 | 2896 octave_stream::gets (const octave_value& tc_max_len, bool& err, |
2897 const std::string& who) | |
2117 | 2898 { |
3523 | 2899 std::string retval; |
2117 | 2900 |
2901 err = false; | |
2902 | |
2903 int conv_err = 0; | |
2904 | |
6345 | 2905 int max_len = -1; |
2906 | |
2907 if (tc_max_len.is_defined ()) | |
2117 | 2908 { |
6345 | 2909 max_len = convert_to_valid_int (tc_max_len, conv_err); |
2910 | |
2911 if (conv_err || max_len < 0) | |
2912 { | |
2913 err = true; | |
2914 ::error ("%s: invalid maximum length specified", who.c_str ()); | |
2915 } | |
2117 | 2916 } |
6345 | 2917 |
2918 if (! error_state) | |
4468 | 2919 retval = gets (max_len, err, who); |
2117 | 2920 |
2921 return retval; | |
2922 } | |
2923 | |
2924 int | |
4797 | 2925 octave_stream::seek (long offset, int origin) |
2117 | 2926 { |
5065 | 2927 int status = -1; |
2117 | 2928 |
5659 | 2929 if (stream_ok ()) |
4889 | 2930 { |
2931 clearerr (); | |
2932 | |
5065 | 2933 long orig_pos = rep->tell (); |
2934 | |
2935 status = rep->seek (offset, origin); | |
2936 | |
2937 if (status == 0) | |
2938 { | |
2939 long save_pos = rep->tell (); | |
2940 | |
2941 rep->seek (0, SEEK_END); | |
2942 | |
2943 long pos_eof = rep->tell (); | |
2944 | |
2945 // I don't think save_pos can be less than zero, but we'll | |
2946 // check anyway... | |
2947 | |
2948 if (save_pos > pos_eof || save_pos < 0) | |
2949 { | |
2950 // Seek outside bounds of file. Failure should leave | |
2951 // position unchanged. | |
2952 | |
2953 rep->seek (orig_pos, SEEK_SET); | |
2954 | |
2955 status = -1; | |
2956 } | |
2957 else | |
2958 { | |
2959 // Is it possible for this to fail? We are just | |
2960 // returning to a position after the first successful | |
2961 // seek. | |
2962 | |
2963 rep->seek (save_pos, SEEK_SET); | |
2964 } | |
2965 } | |
4889 | 2966 } |
2117 | 2967 |
5065 | 2968 return status; |
2117 | 2969 } |
2970 | |
2971 int | |
2972 octave_stream::seek (const octave_value& tc_offset, | |
2973 const octave_value& tc_origin) | |
2974 { | |
2975 int retval = -1; | |
2976 | |
4797 | 2977 long xoffset = tc_offset.long_value (true); |
4645 | 2978 |
2979 if (! error_state) | |
2117 | 2980 { |
4645 | 2981 int conv_err = 0; |
2982 | |
4797 | 2983 int origin = SEEK_SET; |
2117 | 2984 |
2341 | 2985 if (tc_origin.is_string ()) |
2117 | 2986 { |
3523 | 2987 std::string xorigin = tc_origin.string_value (); |
2341 | 2988 |
2989 if (xorigin == "bof") | |
4797 | 2990 origin = SEEK_SET; |
2341 | 2991 else if (xorigin == "cof") |
4797 | 2992 origin = SEEK_CUR; |
2341 | 2993 else if (xorigin == "eof") |
4797 | 2994 origin = SEEK_END; |
2117 | 2995 else |
2996 conv_err = -1; | |
2997 } | |
2341 | 2998 else |
2999 { | |
3000 int xorigin = convert_to_valid_int (tc_origin, conv_err); | |
3001 | |
3002 if (! conv_err) | |
3003 { | |
3004 if (xorigin == -1) | |
4797 | 3005 origin = SEEK_SET; |
2341 | 3006 else if (xorigin == 0) |
4797 | 3007 origin = SEEK_CUR; |
2341 | 3008 else if (xorigin == 1) |
4797 | 3009 origin = SEEK_END; |
2341 | 3010 else |
3011 conv_err = -1; | |
3012 } | |
3013 } | |
2117 | 3014 |
3015 if (! conv_err) | |
5065 | 3016 { |
3017 retval = seek (xoffset, origin); | |
3018 | |
3019 if (retval != 0) | |
3020 error ("fseek: failed to seek to requested position"); | |
3021 } | |
2117 | 3022 else |
3023 error ("fseek: invalid value for origin"); | |
3024 } | |
3025 else | |
3026 error ("fseek: invalid value for offset"); | |
3027 | |
3028 return retval; | |
3029 } | |
3030 | |
4797 | 3031 long |
3032 octave_stream::tell (void) | |
2117 | 3033 { |
4797 | 3034 long retval = -1; |
2117 | 3035 |
5659 | 3036 if (stream_ok ()) |
2117 | 3037 retval = rep->tell (); |
3038 | |
3039 return retval; | |
3040 } | |
3041 | |
3042 int | |
3043 octave_stream::rewind (void) | |
3044 { | |
6296 | 3045 return seek (0, SEEK_SET); |
2117 | 3046 } |
3047 | |
3340 | 3048 bool |
3049 octave_stream::is_open (void) const | |
3050 { | |
3051 bool retval = false; | |
3052 | |
5659 | 3053 if (stream_ok ()) |
3340 | 3054 retval = rep->is_open (); |
3055 | |
3056 return retval; | |
3057 } | |
3058 | |
3059 void | |
3060 octave_stream::close (void) | |
3061 { | |
5659 | 3062 if (stream_ok ()) |
3340 | 3063 rep->close (); |
3064 } | |
3065 | |
4944 | 3066 template <class RET_T, class READ_T> |
2117 | 3067 octave_value |
5275 | 3068 do_read (octave_stream& strm, octave_idx_type nr, octave_idx_type nc, octave_idx_type block_size, |
7995 | 3069 octave_idx_type skip, bool do_float_fmt_conv, bool do_NA_conv, |
5275 | 3070 oct_mach_info::float_format from_flt_fmt, octave_idx_type& count) |
2117 | 3071 { |
3072 octave_value retval; | |
3073 | |
4944 | 3074 RET_T nda; |
3075 | |
3076 count = 0; | |
3077 | |
3078 typename octave_array_type_traits<RET_T>::element_type elt_zero | |
3079 = typename octave_array_type_traits<RET_T>::element_type (); | |
3080 | |
3081 typename octave_array_type_traits<RET_T>::element_type *dat = 0; | |
3082 | |
5275 | 3083 octave_idx_type max_size = 0; |
3084 | |
3085 octave_idx_type final_nr = 0; | |
3086 octave_idx_type final_nc = 1; | |
4944 | 3087 |
3088 if (nr > 0) | |
3089 { | |
3090 if (nc > 0) | |
3091 { | |
3092 nda.resize (dim_vector (nr, nc), elt_zero); | |
3093 dat = nda.fortran_vec (); | |
3094 max_size = nr * nc; | |
3095 } | |
3096 else | |
3097 { | |
3098 nda.resize (dim_vector (nr, 32), elt_zero); | |
3099 dat = nda.fortran_vec (); | |
3100 max_size = nr * 32; | |
3101 } | |
3102 } | |
3103 else | |
3104 { | |
3105 nda.resize (dim_vector (32, 1), elt_zero); | |
3106 dat = nda.fortran_vec (); | |
3107 max_size = 32; | |
3108 } | |
3109 | |
5775 | 3110 // FIXME -- byte order for Cray? |
4944 | 3111 |
3112 bool swap = false; | |
3113 | |
3114 if (oct_mach_info::words_big_endian ()) | |
3115 swap = (from_flt_fmt == oct_mach_info::flt_fmt_ieee_little_endian | |
3116 || from_flt_fmt == oct_mach_info::flt_fmt_vax_g | |
3117 || from_flt_fmt == oct_mach_info::flt_fmt_vax_g); | |
3118 else | |
3119 swap = (from_flt_fmt == oct_mach_info::flt_fmt_ieee_big_endian); | |
3120 | |
3121 union | |
3122 { | |
3123 char buf[sizeof (typename octave_type_traits<READ_T>::val_type)]; | |
3124 typename octave_type_traits<READ_T>::val_type val; | |
3125 } u; | |
3126 | |
3127 std::istream *isp = strm.input_stream (); | |
3128 | |
3129 if (isp) | |
3130 { | |
3131 std::istream& is = *isp; | |
3132 | |
5275 | 3133 octave_idx_type elts_read = 0; |
4944 | 3134 |
3135 for (;;) | |
3136 { | |
5775 | 3137 // FIXME -- maybe there should be a special case for |
4944 | 3138 // skip == 0. |
3139 | |
3140 if (is) | |
3141 { | |
3142 if (nr > 0 && nc > 0 && count == max_size) | |
3143 { | |
3144 final_nr = nr; | |
3145 final_nc = nc; | |
3146 | |
3147 break; | |
3148 } | |
3149 | |
3150 is.read (u.buf, sizeof (typename octave_type_traits<READ_T>::val_type)); | |
3151 | |
3152 // We only swap bytes for integer types. For float | |
3153 // types, the format conversion will also handle byte | |
3154 // swapping. | |
3155 | |
3156 if (swap) | |
3157 swap_bytes<sizeof (typename octave_type_traits<READ_T>::val_type)> (u.buf); | |
3158 else if (do_float_fmt_conv) | |
3159 do_float_format_conversion | |
3160 (u.buf, | |
3161 sizeof (typename octave_type_traits<READ_T>::val_type), | |
3162 1, from_flt_fmt, oct_mach_info::float_format ()); | |
3163 | |
3164 typename octave_array_type_traits<RET_T>::element_type tmp | |
3165 = static_cast <typename octave_array_type_traits<RET_T>::element_type> (u.val); | |
3166 | |
5030 | 3167 if (is) |
4944 | 3168 { |
5030 | 3169 if (count == max_size) |
4944 | 3170 { |
5030 | 3171 max_size *= 2; |
3172 | |
3173 if (nr > 0) | |
3174 nda.resize (dim_vector (nr, max_size / nr), | |
3175 elt_zero); | |
3176 else | |
3177 nda.resize (dim_vector (max_size, 1), elt_zero); | |
3178 | |
3179 dat = nda.fortran_vec (); | |
4944 | 3180 } |
3181 | |
7995 | 3182 if (do_NA_conv && __lo_ieee_is_old_NA (tmp)) |
3183 tmp = __lo_ieee_replace_old_NA (tmp); | |
3184 | |
5030 | 3185 dat[count++] = tmp; |
3186 | |
3187 elts_read++; | |
3188 } | |
3189 | |
7538
2c4b0cbda85a
oct-stream.cc (do_read): stop reading if seek fails
John W. Eaton <jwe@octave.org>
parents:
7433
diff
changeset
|
3190 int seek_status = 0; |
2c4b0cbda85a
oct-stream.cc (do_read): stop reading if seek fails
John W. Eaton <jwe@octave.org>
parents:
7433
diff
changeset
|
3191 |
5030 | 3192 if (skip != 0 && elts_read == block_size) |
3193 { | |
7538
2c4b0cbda85a
oct-stream.cc (do_read): stop reading if seek fails
John W. Eaton <jwe@octave.org>
parents:
7433
diff
changeset
|
3194 seek_status = strm.seek (skip, SEEK_CUR); |
5030 | 3195 elts_read = 0; |
3196 } | |
3197 | |
7538
2c4b0cbda85a
oct-stream.cc (do_read): stop reading if seek fails
John W. Eaton <jwe@octave.org>
parents:
7433
diff
changeset
|
3198 if (is.eof () || seek_status < 0) |
5030 | 3199 { |
3200 if (nr > 0) | |
4944 | 3201 { |
5030 | 3202 if (count > nr) |
4944 | 3203 { |
5030 | 3204 final_nr = nr; |
3205 final_nc = (count - 1) / nr + 1; | |
4944 | 3206 } |
3207 else | |
3208 { | |
3209 final_nr = count; | |
3210 final_nc = 1; | |
3211 } | |
3212 } | |
5030 | 3213 else |
3214 { | |
3215 final_nr = count; | |
3216 final_nc = 1; | |
3217 } | |
3218 | |
4944 | 3219 break; |
3220 } | |
3221 } | |
5030 | 3222 else if (is.eof ()) |
3223 break; | |
4944 | 3224 } |
3225 } | |
3226 | |
5030 | 3227 nda.resize (dim_vector (final_nr, final_nc), elt_zero); |
3228 | |
3229 retval = nda; | |
4944 | 3230 |
3231 return retval; | |
3232 } | |
3233 | |
3234 #define DO_READ_VAL_TEMPLATE(RET_T, READ_T) \ | |
3235 template octave_value \ | |
7995 | 3236 do_read<RET_T, READ_T> (octave_stream&, octave_idx_type, octave_idx_type, octave_idx_type, octave_idx_type, bool, bool, \ |
5275 | 3237 oct_mach_info::float_format, octave_idx_type&) |
4944 | 3238 |
5775 | 3239 // FIXME -- should we only have float if it is a different |
4944 | 3240 // size from double? |
3241 | |
3242 #define INSTANTIATE_DO_READ(VAL_T) \ | |
3243 DO_READ_VAL_TEMPLATE (VAL_T, octave_int8); \ | |
3244 DO_READ_VAL_TEMPLATE (VAL_T, octave_uint8); \ | |
3245 DO_READ_VAL_TEMPLATE (VAL_T, octave_int16); \ | |
3246 DO_READ_VAL_TEMPLATE (VAL_T, octave_uint16); \ | |
3247 DO_READ_VAL_TEMPLATE (VAL_T, octave_int32); \ | |
3248 DO_READ_VAL_TEMPLATE (VAL_T, octave_uint32); \ | |
3249 DO_READ_VAL_TEMPLATE (VAL_T, octave_int64); \ | |
3250 DO_READ_VAL_TEMPLATE (VAL_T, octave_uint64); \ | |
3251 DO_READ_VAL_TEMPLATE (VAL_T, float); \ | |
3252 DO_READ_VAL_TEMPLATE (VAL_T, double); \ | |
3253 DO_READ_VAL_TEMPLATE (VAL_T, char); \ | |
3254 DO_READ_VAL_TEMPLATE (VAL_T, signed char); \ | |
3255 DO_READ_VAL_TEMPLATE (VAL_T, unsigned char) | |
3256 | |
4970 | 3257 INSTANTIATE_DO_READ (int8NDArray); |
3258 INSTANTIATE_DO_READ (uint8NDArray); | |
3259 INSTANTIATE_DO_READ (int16NDArray); | |
3260 INSTANTIATE_DO_READ (uint16NDArray); | |
3261 INSTANTIATE_DO_READ (int32NDArray); | |
3262 INSTANTIATE_DO_READ (uint32NDArray); | |
3263 INSTANTIATE_DO_READ (int64NDArray); | |
3264 INSTANTIATE_DO_READ (uint64NDArray); | |
7789
82be108cc558
First attempt at single precision tyeps
David Bateman <dbateman@free.fr>
parents:
7724
diff
changeset
|
3265 INSTANTIATE_DO_READ (FloatNDArray); |
4970 | 3266 INSTANTIATE_DO_READ (NDArray); |
3267 INSTANTIATE_DO_READ (charNDArray); | |
5780 | 3268 INSTANTIATE_DO_READ (boolNDArray); |
4944 | 3269 |
7995 | 3270 typedef octave_value (*read_fptr) (octave_stream&, octave_idx_type, octave_idx_type, octave_idx_type, octave_idx_type, bool, bool, |
5275 | 3271 oct_mach_info::float_format ffmt, octave_idx_type&); |
4944 | 3272 |
7433 | 3273 NO_INSTANTIATE_ARRAY_SORT (read_fptr); |
6708 | 3274 INSTANTIATE_ARRAY (read_fptr,); |
4944 | 3275 template class Array2<read_fptr>; |
3276 | |
3277 #define FILL_TABLE_ROW(R, VAL_T) \ | |
3278 read_fptr_table(R,oct_data_conv::dt_int8) = do_read<VAL_T, octave_int8>; \ | |
3279 read_fptr_table(R,oct_data_conv::dt_uint8) = do_read<VAL_T, octave_uint8>; \ | |
3280 read_fptr_table(R,oct_data_conv::dt_int16) = do_read<VAL_T, octave_int16>; \ | |
3281 read_fptr_table(R,oct_data_conv::dt_uint16) = do_read<VAL_T, octave_uint16>; \ | |
3282 read_fptr_table(R,oct_data_conv::dt_int32) = do_read<VAL_T, octave_int32>; \ | |
3283 read_fptr_table(R,oct_data_conv::dt_uint32) = do_read<VAL_T, octave_uint32>; \ | |
3284 read_fptr_table(R,oct_data_conv::dt_int64) = do_read<VAL_T, octave_int64>; \ | |
3285 read_fptr_table(R,oct_data_conv::dt_uint64) = do_read<VAL_T, octave_uint64>; \ | |
3286 read_fptr_table(R,oct_data_conv::dt_single) = do_read<VAL_T, float>; \ | |
3287 read_fptr_table(R,oct_data_conv::dt_double) = do_read<VAL_T, double>; \ | |
3288 read_fptr_table(R,oct_data_conv::dt_char) = do_read<VAL_T, char>; \ | |
3289 read_fptr_table(R,oct_data_conv::dt_schar) = do_read<VAL_T, signed char>; \ | |
4970 | 3290 read_fptr_table(R,oct_data_conv::dt_uchar) = do_read<VAL_T, unsigned char>; \ |
3291 read_fptr_table(R,oct_data_conv::dt_logical) = do_read<VAL_T, unsigned char> | |
4944 | 3292 |
3293 octave_value | |
5275 | 3294 octave_stream::read (const Array<double>& size, octave_idx_type block_size, |
4944 | 3295 oct_data_conv::data_type input_type, |
3296 oct_data_conv::data_type output_type, | |
5275 | 3297 octave_idx_type skip, oct_mach_info::float_format ffmt, |
3298 octave_idx_type& char_count) | |
4944 | 3299 { |
3300 static bool initialized = false; | |
3301 | |
3302 // Table function pointers for return types x read types. | |
3303 | |
4970 | 3304 static Array2<read_fptr> read_fptr_table (oct_data_conv::dt_unknown, 14, 0); |
4944 | 3305 |
3306 if (! initialized) | |
3307 { | |
3308 FILL_TABLE_ROW (oct_data_conv::dt_int8, int8NDArray); | |
3309 FILL_TABLE_ROW (oct_data_conv::dt_uint8, uint8NDArray); | |
3310 FILL_TABLE_ROW (oct_data_conv::dt_int16, int16NDArray); | |
3311 FILL_TABLE_ROW (oct_data_conv::dt_uint16, uint16NDArray); | |
3312 FILL_TABLE_ROW (oct_data_conv::dt_int32, int32NDArray); | |
3313 FILL_TABLE_ROW (oct_data_conv::dt_uint32, uint32NDArray); | |
3314 FILL_TABLE_ROW (oct_data_conv::dt_int64, int64NDArray); | |
3315 FILL_TABLE_ROW (oct_data_conv::dt_uint64, uint64NDArray); | |
7789
82be108cc558
First attempt at single precision tyeps
David Bateman <dbateman@free.fr>
parents:
7724
diff
changeset
|
3316 FILL_TABLE_ROW (oct_data_conv::dt_single, FloatNDArray); |
4944 | 3317 FILL_TABLE_ROW (oct_data_conv::dt_double, NDArray); |
3318 FILL_TABLE_ROW (oct_data_conv::dt_char, charNDArray); | |
3319 FILL_TABLE_ROW (oct_data_conv::dt_schar, charNDArray); | |
3320 FILL_TABLE_ROW (oct_data_conv::dt_uchar, charNDArray); | |
4970 | 3321 FILL_TABLE_ROW (oct_data_conv::dt_logical, boolNDArray); |
4944 | 3322 |
3323 initialized = true; | |
3324 } | |
3325 | |
3326 octave_value retval; | |
3327 | |
5659 | 3328 if (stream_ok ()) |
4944 | 3329 { |
5775 | 3330 // FIXME -- we may eventually want to make this extensible. |
3331 | |
3332 // FIXME -- we need a better way to ensure that this | |
4944 | 3333 // numbering stays consistent with the order of the elements in the |
3334 // data_type enum in the oct_data_conv class. | |
3335 | |
3336 char_count = 0; | |
3337 | |
5275 | 3338 octave_idx_type nr = -1; |
3339 octave_idx_type nc = -1; | |
4944 | 3340 |
3341 bool ignore; | |
3342 | |
3343 get_size (size, nr, nc, ignore, "fread"); | |
3344 | |
3345 if (! error_state) | |
3346 { | |
3347 if (nr == 0 || nc == 0) | |
3348 retval = Matrix (nr, nc); | |
3349 else | |
3350 { | |
3351 if (ffmt == oct_mach_info::flt_fmt_unknown) | |
3352 ffmt = float_format (); | |
3353 | |
3354 read_fptr fcn = read_fptr_table (output_type, input_type); | |
3355 | |
3356 bool do_float_fmt_conv = ((input_type == oct_data_conv::dt_double | |
3357 || input_type == oct_data_conv::dt_single) | |
3358 && ffmt != float_format ()); | |
3359 | |
7995 | 3360 bool do_NA_conv = (output_type == oct_data_conv::dt_double); |
3361 | |
4944 | 3362 if (fcn) |
3363 { | |
3364 retval = (*fcn) (*this, nr, nc, block_size, skip, | |
7995 | 3365 do_float_fmt_conv, do_NA_conv, |
3366 ffmt, char_count); | |
4944 | 3367 |
5775 | 3368 // FIXME -- kluge! |
4944 | 3369 |
3370 if (! error_state | |
3371 && (output_type == oct_data_conv::dt_char | |
3372 || output_type == oct_data_conv::dt_schar | |
3373 || output_type == oct_data_conv::dt_uchar)) | |
3374 retval = octave_value (retval.char_matrix_value (), true); | |
3375 } | |
3376 else | |
3377 error ("fread: unable to read and convert requested types"); | |
3378 } | |
3379 } | |
3380 else | |
3381 invalid_operation ("fread", "reading"); | |
3382 } | |
2117 | 3383 |
3384 return retval; | |
3385 } | |
3386 | |
5275 | 3387 octave_idx_type |
3388 octave_stream::write (const octave_value& data, octave_idx_type block_size, | |
3389 oct_data_conv::data_type output_type, octave_idx_type skip, | |
2317 | 3390 oct_mach_info::float_format flt_fmt) |
2117 | 3391 { |
5275 | 3392 octave_idx_type retval = -1; |
2117 | 3393 |
5659 | 3394 if (stream_ok ()) |
4944 | 3395 { |
3396 if (! error_state) | |
3397 { | |
3398 if (flt_fmt == oct_mach_info::flt_fmt_unknown) | |
3399 flt_fmt = float_format (); | |
3400 | |
5275 | 3401 octave_idx_type status = data.write (*this, block_size, output_type, |
4944 | 3402 skip, flt_fmt); |
3403 | |
3404 if (status < 0) | |
3405 error ("fwrite: write error"); | |
3406 else | |
3407 retval = status; | |
3408 } | |
3409 else | |
3410 invalid_operation ("fwrite", "writing"); | |
3411 } | |
2117 | 3412 |
3413 return retval; | |
3414 } | |
3415 | |
4944 | 3416 template <class T> |
3417 void | |
3418 write_int (std::ostream& os, bool swap, const T& val) | |
3419 { | |
3420 typename octave_type_traits<T>::val_type tmp = val.value (); | |
3421 | |
3422 if (swap) | |
3423 swap_bytes<sizeof (typename octave_type_traits<T>::val_type)> (&tmp); | |
3424 | |
3425 os.write (reinterpret_cast<const char *> (&tmp), | |
3426 sizeof (typename octave_type_traits<T>::val_type)); | |
3427 } | |
3428 | |
3429 template void write_int (std::ostream&, bool, const octave_int8&); | |
3430 template void write_int (std::ostream&, bool, const octave_uint8&); | |
3431 template void write_int (std::ostream&, bool, const octave_int16&); | |
3432 template void write_int (std::ostream&, bool, const octave_uint16&); | |
3433 template void write_int (std::ostream&, bool, const octave_int32&); | |
3434 template void write_int (std::ostream&, bool, const octave_uint32&); | |
3435 template void write_int (std::ostream&, bool, const octave_int64&); | |
3436 template void write_int (std::ostream&, bool, const octave_uint64&); | |
3437 | |
3438 template <class T> | |
3439 static inline bool | |
3440 do_write (std::ostream& os, const T& val, oct_data_conv::data_type output_type, | |
3441 oct_mach_info::float_format flt_fmt, bool swap, | |
3442 bool do_float_conversion) | |
3443 { | |
3444 bool retval = true; | |
3445 | |
3446 // For compatibility, Octave converts to the output type, then | |
3447 // writes. This means that truncation happens on the conversion. | |
3448 // For example, the following program prints 0: | |
3449 // | |
3450 // x = int8 (-1) | |
3451 // f = fopen ("foo.dat", "w"); | |
3452 // fwrite (f, x, "unsigned char"); | |
3453 // fclose (f); | |
3454 // f = fopen ("foo.dat", "r"); | |
3455 // y = fread (f, 1, "unsigned char"); | |
3456 // printf ("%d\n", y); | |
3457 | |
3458 switch (output_type) | |
3459 { | |
3460 case oct_data_conv::dt_char: | |
3461 case oct_data_conv::dt_schar: | |
3462 case oct_data_conv::dt_int8: | |
3463 write_int (os, swap, octave_int8 (val)); | |
3464 break; | |
3465 | |
3466 case oct_data_conv::dt_uchar: | |
3467 case oct_data_conv::dt_uint8: | |
3468 write_int (os, swap, octave_uint8 (val)); | |
3469 break; | |
3470 | |
3471 case oct_data_conv::dt_int16: | |
3472 write_int (os, swap, octave_int16 (val)); | |
3473 break; | |
3474 | |
3475 case oct_data_conv::dt_uint16: | |
3476 write_int (os, swap, octave_uint16 (val)); | |
3477 break; | |
3478 | |
3479 case oct_data_conv::dt_int32: | |
3480 write_int (os, swap, octave_int32 (val)); | |
3481 break; | |
3482 | |
3483 case oct_data_conv::dt_uint32: | |
3484 write_int (os, swap, octave_uint32 (val)); | |
3485 break; | |
3486 | |
3487 case oct_data_conv::dt_int64: | |
3488 write_int (os, swap, octave_int64 (val)); | |
3489 break; | |
3490 | |
3491 case oct_data_conv::dt_uint64: | |
3492 write_int (os, swap, octave_uint64 (val)); | |
3493 break; | |
3494 | |
3495 case oct_data_conv::dt_single: | |
3496 { | |
3497 float f = static_cast<float> (val); | |
3498 | |
3499 if (do_float_conversion) | |
3500 do_float_format_conversion (&f, 1, flt_fmt); | |
3501 | |
3502 os.write (reinterpret_cast<const char *> (&f), sizeof (float)); | |
3503 } | |
3504 break; | |
3505 | |
3506 case oct_data_conv::dt_double: | |
3507 { | |
3508 double d = static_cast<double> (val); | |
3509 if (do_float_conversion) | |
3510 do_double_format_conversion (&d, 1, flt_fmt); | |
3511 | |
3512 os.write (reinterpret_cast<const char *> (&d), sizeof (double)); | |
3513 } | |
3514 break; | |
3515 | |
3516 default: | |
3517 retval = false; | |
3518 (*current_liboctave_error_handler) | |
3519 ("write: invalid type specification"); | |
3520 break; | |
3521 } | |
3522 | |
3523 return retval; | |
3524 } | |
3525 | |
5887 | 3526 template bool |
3527 do_write (std::ostream&, const octave_int8&, oct_data_conv::data_type, | |
3528 oct_mach_info::float_format, bool, bool); | |
3529 | |
3530 template bool | |
3531 do_write (std::ostream&, const octave_uint8&, oct_data_conv::data_type, | |
3532 oct_mach_info::float_format, bool, bool); | |
3533 | |
3534 template bool | |
3535 do_write (std::ostream&, const octave_int16&, oct_data_conv::data_type, | |
3536 oct_mach_info::float_format, bool, bool); | |
3537 | |
3538 template bool | |
3539 do_write (std::ostream&, const octave_uint16&, oct_data_conv::data_type, | |
3540 oct_mach_info::float_format, bool, bool); | |
3541 | |
3542 template bool | |
3543 do_write (std::ostream&, const octave_int32&, oct_data_conv::data_type, | |
3544 oct_mach_info::float_format, bool, bool); | |
3545 | |
3546 template bool | |
3547 do_write (std::ostream&, const octave_uint32&, oct_data_conv::data_type, | |
3548 oct_mach_info::float_format, bool, bool); | |
3549 | |
3550 template bool | |
3551 do_write (std::ostream&, const octave_int64&, oct_data_conv::data_type, | |
3552 oct_mach_info::float_format, bool, bool); | |
3553 | |
3554 template bool | |
3555 do_write (std::ostream&, const octave_uint64&, oct_data_conv::data_type, | |
3556 oct_mach_info::float_format, bool, bool); | |
3557 | |
4944 | 3558 template <class T> |
5275 | 3559 octave_idx_type |
3560 octave_stream::write (const Array<T>& data, octave_idx_type block_size, | |
4944 | 3561 oct_data_conv::data_type output_type, |
5275 | 3562 octave_idx_type skip, oct_mach_info::float_format flt_fmt) |
4944 | 3563 { |
5275 | 3564 octave_idx_type retval = -1; |
4944 | 3565 |
3566 bool status = true; | |
3567 | |
5275 | 3568 octave_idx_type count = 0; |
4944 | 3569 |
3570 const T *d = data.data (); | |
3571 | |
5275 | 3572 octave_idx_type n = data.length (); |
4944 | 3573 |
3574 oct_mach_info::float_format native_flt_fmt | |
3575 = oct_mach_info::float_format (); | |
3576 | |
3577 bool do_float_conversion = (flt_fmt != native_flt_fmt); | |
3578 | |
5775 | 3579 // FIXME -- byte order for Cray? |
4944 | 3580 |
3581 bool swap = false; | |
3582 | |
3583 if (oct_mach_info::words_big_endian ()) | |
3584 swap = (flt_fmt == oct_mach_info::flt_fmt_ieee_little_endian | |
3585 || flt_fmt == oct_mach_info::flt_fmt_vax_g | |
3586 || flt_fmt == oct_mach_info::flt_fmt_vax_g); | |
3587 else | |
3588 swap = (flt_fmt == oct_mach_info::flt_fmt_ieee_big_endian); | |
3589 | |
5275 | 3590 for (octave_idx_type i = 0; i < n; i++) |
4944 | 3591 { |
3592 std::ostream *osp = output_stream (); | |
3593 | |
3594 if (osp) | |
3595 { | |
3596 std::ostream& os = *osp; | |
3597 | |
5254 | 3598 // It seems that Matlab writes zeros instead of actually |
3599 // seeking. Hmm... | |
3600 | |
4944 | 3601 if (skip != 0 && (i % block_size) == 0) |
5254 | 3602 { |
5775 | 3603 // FIXME -- probably should try to write larger |
5254 | 3604 // blocks... |
3605 | |
3606 unsigned char zero = 0; | |
3607 for (int j = 0; j < skip; j++) | |
3608 os.write (reinterpret_cast<const char *> (&zero), 1); | |
3609 } | |
4944 | 3610 |
3611 if (os) | |
3612 { | |
3613 status = do_write (os, d[i], output_type, flt_fmt, swap, | |
3614 do_float_conversion); | |
3615 | |
3616 if (os && status) | |
3617 count++; | |
3618 else | |
3619 break; | |
3620 } | |
3621 else | |
3622 { | |
3623 status = false; | |
3624 break; | |
3625 } | |
3626 } | |
3627 else | |
3628 { | |
3629 status = false; | |
3630 break; | |
3631 } | |
3632 } | |
3633 | |
3634 if (status) | |
3635 retval = count; | |
3636 | |
3637 return retval; | |
3638 } | |
3639 | |
5275 | 3640 template octave_idx_type |
3641 octave_stream::write (const Array<char>&, octave_idx_type, | |
4944 | 3642 oct_data_conv::data_type, |
5275 | 3643 octave_idx_type, oct_mach_info::float_format); |
3644 | |
3645 template octave_idx_type | |
3646 octave_stream::write (const Array<bool>&, octave_idx_type, | |
4970 | 3647 oct_data_conv::data_type, |
5275 | 3648 octave_idx_type, oct_mach_info::float_format); |
3649 | |
3650 template octave_idx_type | |
3651 octave_stream::write (const Array<double>&, octave_idx_type, | |
4944 | 3652 oct_data_conv::data_type, |
5275 | 3653 octave_idx_type, oct_mach_info::float_format); |
3654 | |
3655 template octave_idx_type | |
7789
82be108cc558
First attempt at single precision tyeps
David Bateman <dbateman@free.fr>
parents:
7724
diff
changeset
|
3656 octave_stream::write (const Array<float>&, octave_idx_type, |
82be108cc558
First attempt at single precision tyeps
David Bateman <dbateman@free.fr>
parents:
7724
diff
changeset
|
3657 oct_data_conv::data_type, |
82be108cc558
First attempt at single precision tyeps
David Bateman <dbateman@free.fr>
parents:
7724
diff
changeset
|
3658 octave_idx_type, oct_mach_info::float_format); |
82be108cc558
First attempt at single precision tyeps
David Bateman <dbateman@free.fr>
parents:
7724
diff
changeset
|
3659 |
82be108cc558
First attempt at single precision tyeps
David Bateman <dbateman@free.fr>
parents:
7724
diff
changeset
|
3660 template octave_idx_type |
5275 | 3661 octave_stream::write (const Array<octave_int8>&, octave_idx_type, |
4944 | 3662 oct_data_conv::data_type, |
5275 | 3663 octave_idx_type, oct_mach_info::float_format); |
3664 | |
3665 template octave_idx_type | |
3666 octave_stream::write (const Array<octave_uint8>&, octave_idx_type, | |
4944 | 3667 oct_data_conv::data_type, |
5275 | 3668 octave_idx_type, oct_mach_info::float_format); |
3669 | |
3670 template octave_idx_type | |
3671 octave_stream::write (const Array<octave_int16>&, octave_idx_type, | |
4944 | 3672 oct_data_conv::data_type, |
5275 | 3673 octave_idx_type, oct_mach_info::float_format); |
3674 | |
3675 template octave_idx_type | |
3676 octave_stream::write (const Array<octave_uint16>&, octave_idx_type, | |
4944 | 3677 oct_data_conv::data_type, |
5275 | 3678 octave_idx_type, oct_mach_info::float_format); |
3679 | |
3680 template octave_idx_type | |
3681 octave_stream::write (const Array<octave_int32>&, octave_idx_type, | |
4944 | 3682 oct_data_conv::data_type, |
5275 | 3683 octave_idx_type, oct_mach_info::float_format); |
3684 | |
3685 template octave_idx_type | |
3686 octave_stream::write (const Array<octave_uint32>&, octave_idx_type, | |
4944 | 3687 oct_data_conv::data_type, |
5275 | 3688 octave_idx_type, oct_mach_info::float_format); |
3689 | |
3690 template octave_idx_type | |
3691 octave_stream::write (const Array<octave_int64>&, octave_idx_type, | |
4944 | 3692 oct_data_conv::data_type, |
5275 | 3693 octave_idx_type, oct_mach_info::float_format); |
3694 | |
3695 template octave_idx_type | |
3696 octave_stream::write (const Array<octave_uint64>&, octave_idx_type, | |
4944 | 3697 oct_data_conv::data_type, |
5275 | 3698 octave_idx_type, oct_mach_info::float_format); |
4944 | 3699 |
2117 | 3700 octave_value |
3810 | 3701 octave_stream::scanf (const std::string& fmt, const Array<double>& size, |
5275 | 3702 octave_idx_type& count, const std::string& who) |
2117 | 3703 { |
3704 octave_value retval; | |
3705 | |
5659 | 3706 if (stream_ok ()) |
4468 | 3707 retval = rep->scanf (fmt, size, count, who); |
2117 | 3708 |
3709 return retval; | |
3710 } | |
3711 | |
5279 | 3712 octave_value |
3713 octave_stream::scanf (const octave_value& fmt, const Array<double>& size, | |
5299 | 3714 octave_idx_type& count, const std::string& who) |
5279 | 3715 { |
3716 octave_value retval = Matrix (); | |
3717 | |
3718 if (fmt.is_string ()) | |
3719 { | |
3720 std::string sfmt = fmt.string_value (); | |
3721 | |
3722 if (fmt.is_sq_string ()) | |
3723 sfmt = do_string_escapes (sfmt); | |
3724 | |
3725 retval = scanf (sfmt, size, count, who); | |
3726 } | |
3727 else | |
3728 { | |
3729 // Note that this is not ::error () ! | |
3730 | |
3731 error (who + ": format must be a string"); | |
3732 } | |
3733 | |
3734 return retval; | |
3735 } | |
3736 | |
2215 | 3737 octave_value_list |
4468 | 3738 octave_stream::oscanf (const std::string& fmt, const std::string& who) |
2215 | 3739 { |
3740 octave_value_list retval; | |
3741 | |
5659 | 3742 if (stream_ok ()) |
4468 | 3743 retval = rep->oscanf (fmt, who); |
2215 | 3744 |
3745 return retval; | |
3746 } | |
3747 | |
5279 | 3748 octave_value_list |
3749 octave_stream::oscanf (const octave_value& fmt, const std::string& who) | |
3750 { | |
3751 octave_value_list retval; | |
3752 | |
3753 if (fmt.is_string ()) | |
3754 { | |
3755 std::string sfmt = fmt.string_value (); | |
3756 | |
3757 if (fmt.is_sq_string ()) | |
3758 sfmt = do_string_escapes (sfmt); | |
3759 | |
3760 retval = oscanf (sfmt, who); | |
3761 } | |
3762 else | |
3763 { | |
3764 // Note that this is not ::error () ! | |
3765 | |
3766 error (who + ": format must be a string"); | |
3767 } | |
3768 | |
3769 return retval; | |
3770 } | |
3771 | |
2117 | 3772 int |
4468 | 3773 octave_stream::printf (const std::string& fmt, const octave_value_list& args, |
3774 const std::string& who) | |
2117 | 3775 { |
3776 int retval = -1; | |
3777 | |
5659 | 3778 if (stream_ok ()) |
4468 | 3779 retval = rep->printf (fmt, args, who); |
2117 | 3780 |
3781 return retval; | |
3782 } | |
3783 | |
3784 int | |
5279 | 3785 octave_stream::printf (const octave_value& fmt, const octave_value_list& args, |
3786 const std::string& who) | |
3787 { | |
3788 int retval = 0; | |
3789 | |
3790 if (fmt.is_string ()) | |
3791 { | |
3792 std::string sfmt = fmt.string_value (); | |
3793 | |
3794 if (fmt.is_sq_string ()) | |
3795 sfmt = do_string_escapes (sfmt); | |
3796 | |
3797 retval = printf (sfmt, args, who); | |
3798 } | |
3799 else | |
3800 { | |
3801 // Note that this is not ::error () ! | |
3802 | |
3803 error (who + ": format must be a string"); | |
3804 } | |
3805 | |
3806 return retval; | |
3807 } | |
3808 | |
3809 int | |
4468 | 3810 octave_stream::puts (const std::string& s, const std::string& who) |
2117 | 3811 { |
3812 int retval = -1; | |
3813 | |
5659 | 3814 if (stream_ok ()) |
4468 | 3815 retval = rep->puts (s, who); |
2117 | 3816 |
3817 return retval; | |
3818 } | |
3819 | |
5775 | 3820 // FIXME -- maybe this should work for string arrays too. |
2117 | 3821 |
3822 int | |
4468 | 3823 octave_stream::puts (const octave_value& tc_s, const std::string& who) |
2117 | 3824 { |
3825 int retval = -1; | |
3826 | |
3827 if (tc_s.is_string ()) | |
3828 { | |
3523 | 3829 std::string s = tc_s.string_value (); |
5279 | 3830 retval = puts (s, who); |
2117 | 3831 } |
3832 else | |
4468 | 3833 { |
3834 // Note that this is not ::error () ! | |
3835 | |
3836 error (who + ": argument must be a string"); | |
3837 } | |
2117 | 3838 |
3839 return retval; | |
3840 } | |
3841 | |
3842 bool | |
3843 octave_stream::eof (void) const | |
3844 { | |
3845 int retval = -1; | |
3846 | |
5659 | 3847 if (stream_ok ()) |
2117 | 3848 retval = rep->eof (); |
3849 | |
3850 return retval; | |
3851 } | |
3852 | |
3536 | 3853 std::string |
2435 | 3854 octave_stream::error (bool clear, int& err_num) |
2117 | 3855 { |
5649 | 3856 std::string retval = "invalid stream object"; |
3857 | |
5659 | 3858 if (stream_ok (false)) |
2435 | 3859 retval = rep->error (clear, err_num); |
2117 | 3860 |
3861 return retval; | |
3862 } | |
3863 | |
3536 | 3864 std::string |
3340 | 3865 octave_stream::name (void) const |
2117 | 3866 { |
3523 | 3867 std::string retval; |
2117 | 3868 |
5659 | 3869 if (stream_ok ()) |
2117 | 3870 retval = rep->name (); |
3871 | |
3872 return retval; | |
3873 } | |
3874 | |
3875 int | |
3340 | 3876 octave_stream::mode (void) const |
2117 | 3877 { |
3878 int retval = 0; | |
3879 | |
5659 | 3880 if (stream_ok ()) |
2117 | 3881 retval = rep->mode (); |
3882 | |
3883 return retval; | |
3884 } | |
3885 | |
2317 | 3886 oct_mach_info::float_format |
3340 | 3887 octave_stream::float_format (void) const |
2117 | 3888 { |
4574 | 3889 oct_mach_info::float_format retval = oct_mach_info::flt_fmt_unknown; |
2317 | 3890 |
5659 | 3891 if (stream_ok ()) |
2317 | 3892 retval = rep->float_format (); |
2117 | 3893 |
3894 return retval; | |
3895 } | |
3896 | |
3536 | 3897 std::string |
2117 | 3898 octave_stream::mode_as_string (int mode) |
3899 { | |
3523 | 3900 std::string retval = "???"; |
3775 | 3901 std::ios::openmode in_mode = static_cast<std::ios::openmode> (mode); |
3902 | |
3903 if (in_mode == std::ios::in) | |
3904 retval = "r"; | |
3905 else if (in_mode == std::ios::out | |
4078 | 3906 || in_mode == (std::ios::out | std::ios::trunc)) |
3775 | 3907 retval = "w"; |
4078 | 3908 else if (in_mode == (std::ios::out | std::ios::app)) |
3775 | 3909 retval = "a"; |
4078 | 3910 else if (in_mode == (std::ios::in | std::ios::out)) |
3775 | 3911 retval = "r+"; |
4078 | 3912 else if (in_mode == (std::ios::in | std::ios::out | std::ios::trunc)) |
3775 | 3913 retval = "w+"; |
4078 | 3914 else if (in_mode == (std::ios::in | std::ios::out | std::ios::ate)) |
3775 | 3915 retval = "a+"; |
4078 | 3916 else if (in_mode == (std::ios::in | std::ios::binary)) |
3775 | 3917 retval = "rb"; |
4078 | 3918 else if (in_mode == (std::ios::out | std::ios::binary) |
3919 || in_mode == (std::ios::out | std::ios::trunc | std::ios::binary)) | |
3775 | 3920 retval = "wb"; |
4078 | 3921 else if (in_mode == (std::ios::out | std::ios::app | std::ios::binary)) |
3775 | 3922 retval = "ab"; |
4078 | 3923 else if (in_mode == (std::ios::in | std::ios::out | std::ios::binary)) |
3775 | 3924 retval = "r+b"; |
4078 | 3925 else if (in_mode == (std::ios::in | std::ios::out | std::ios::trunc |
3926 | std::ios::binary)) | |
3775 | 3927 retval = "w+b"; |
4078 | 3928 else if (in_mode == (std::ios::in | std::ios::out | std::ios::ate |
3929 | std::ios::binary)) | |
3775 | 3930 retval = "a+b"; |
2117 | 3931 |
3932 return retval; | |
3933 } | |
3934 | |
3935 octave_stream_list *octave_stream_list::instance = 0; | |
3936 | |
2926 | 3937 bool |
3938 octave_stream_list::instance_ok (void) | |
3939 { | |
3940 bool retval = true; | |
3941 | |
3942 if (! instance) | |
3943 instance = new octave_stream_list (); | |
3944 | |
3945 if (! instance) | |
3946 { | |
3947 ::error ("unable to create stream list object!"); | |
3948 | |
3949 retval = false; | |
3950 } | |
3951 | |
3952 return retval; | |
3953 } | |
3954 | |
5353 | 3955 int |
6757 | 3956 octave_stream_list::insert (octave_stream& os) |
2926 | 3957 { |
5353 | 3958 return (instance_ok ()) ? instance->do_insert (os) : -1; |
2926 | 3959 } |
3960 | |
3340 | 3961 octave_stream |
3523 | 3962 octave_stream_list::lookup (int fid, const std::string& who) |
2926 | 3963 { |
3341 | 3964 return (instance_ok ()) ? instance->do_lookup (fid, who) : octave_stream (); |
2926 | 3965 } |
3966 | |
3340 | 3967 octave_stream |
3523 | 3968 octave_stream_list::lookup (const octave_value& fid, const std::string& who) |
2926 | 3969 { |
3341 | 3970 return (instance_ok ()) ? instance->do_lookup (fid, who) : octave_stream (); |
2926 | 3971 } |
3972 | |
3973 int | |
3523 | 3974 octave_stream_list::remove (int fid, const std::string& who) |
2926 | 3975 { |
3341 | 3976 return (instance_ok ()) ? instance->do_remove (fid, who) : -1; |
2926 | 3977 } |
3978 | |
3979 int | |
3523 | 3980 octave_stream_list::remove (const octave_value& fid, const std::string& who) |
2926 | 3981 { |
3341 | 3982 return (instance_ok ()) ? instance->do_remove (fid, who) : -1; |
2926 | 3983 } |
3984 | |
3985 void | |
8902
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
3986 octave_stream_list::clear (bool flush) |
2926 | 3987 { |
3988 if (instance) | |
8902
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
3989 instance->do_clear (flush); |
2926 | 3990 } |
3991 | |
3992 string_vector | |
3993 octave_stream_list::get_info (int fid) | |
3994 { | |
3995 return (instance_ok ()) ? instance->do_get_info (fid) : string_vector (); | |
3996 } | |
3997 | |
3998 string_vector | |
3999 octave_stream_list::get_info (const octave_value& fid) | |
4000 { | |
4001 return (instance_ok ()) ? instance->do_get_info (fid) : string_vector (); | |
4002 } | |
4003 | |
3536 | 4004 std::string |
2926 | 4005 octave_stream_list::list_open_files (void) |
4006 { | |
3523 | 4007 return (instance_ok ()) ? instance->do_list_open_files () : std::string (); |
2926 | 4008 } |
4009 | |
4010 octave_value | |
4011 octave_stream_list::open_file_numbers (void) | |
4012 { | |
4013 return (instance_ok ()) | |
4014 ? instance->do_open_file_numbers () : octave_value (); | |
4015 } | |
4016 | |
4017 int | |
4018 octave_stream_list::get_file_number (const octave_value& fid) | |
4019 { | |
4020 return (instance_ok ()) ? instance->do_get_file_number (fid) : -1; | |
4021 } | |
4022 | |
5353 | 4023 int |
6757 | 4024 octave_stream_list::do_insert (octave_stream& os) |
2117 | 4025 { |
6757 | 4026 // Insert item with key corresponding to file-descriptor. |
4027 | |
4028 int stream_number; | |
4029 | |
4030 if ((stream_number = os.file_number ()) == -1) | |
4031 return stream_number; | |
4032 | |
4033 // Should we test for "(list.find (stream_number) != list.end ()) && | |
4034 // list[stream_number].is_open ()" and respond with "error | |
4035 // ("internal error: ...")"? It should not happen except for some | |
4036 // bug or if the user has opened a stream with an interpreted | |
4037 // command, but closed it directly with a system call in an | |
4038 // oct-file; then the kernel knows the fd is free, but Octave does | |
4039 // not know. If it happens, it should not do harm here to simply | |
4040 // overwrite this entry, although the wrong entry might have done | |
4041 // harm before. | |
4042 | |
4043 if (list.size () < list.max_size ()) | |
4044 list[stream_number] = os; | |
4045 else | |
2117 | 4046 { |
6757 | 4047 stream_number = -1; |
4048 error ("could not create file id"); | |
3340 | 4049 } |
2117 | 4050 |
5353 | 4051 return stream_number; |
6757 | 4052 |
2117 | 4053 } |
4054 | |
3341 | 4055 static void |
3523 | 4056 gripe_invalid_file_id (int fid, const std::string& who) |
3341 | 4057 { |
4058 if (who.empty ()) | |
4059 ::error ("invalid stream number = %d", fid); | |
4060 else | |
4061 ::error ("%s: invalid stream number = %d", who.c_str (), fid); | |
4062 } | |
4063 | |
3340 | 4064 octave_stream |
3523 | 4065 octave_stream_list::do_lookup (int fid, const std::string& who) const |
2117 | 4066 { |
3340 | 4067 octave_stream retval; |
2117 | 4068 |
6757 | 4069 if (fid >= 0) |
4070 { | |
8902
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4071 if (lookup_cache != list.end () && lookup_cache->first == fid) |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4072 retval = lookup_cache->second; |
6757 | 4073 else |
8902
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4074 { |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4075 ostrl_map::const_iterator iter = list.find (fid); |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4076 |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4077 if (iter != list.end ()) |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4078 { |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4079 retval = iter->second; |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4080 lookup_cache = iter; |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4081 } |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4082 else |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4083 gripe_invalid_file_id (fid, who); |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4084 } |
6757 | 4085 } |
3341 | 4086 else |
4087 gripe_invalid_file_id (fid, who); | |
2117 | 4088 |
4089 return retval; | |
4090 } | |
4091 | |
3340 | 4092 octave_stream |
3341 | 4093 octave_stream_list::do_lookup (const octave_value& fid, |
3523 | 4094 const std::string& who) const |
2117 | 4095 { |
3340 | 4096 octave_stream retval; |
2117 | 4097 |
4098 int i = get_file_number (fid); | |
4099 | |
4100 if (! error_state) | |
3341 | 4101 retval = do_lookup (i, who); |
2117 | 4102 |
4103 return retval; | |
4104 } | |
4105 | |
4106 int | |
3523 | 4107 octave_stream_list::do_remove (int fid, const std::string& who) |
2117 | 4108 { |
4109 int retval = -1; | |
4110 | |
3531 | 4111 // Can't remove stdin (std::cin), stdout (std::cout), or stderr |
4112 // (std::cerr). | |
2117 | 4113 |
6757 | 4114 if (fid > 2) |
2117 | 4115 { |
6757 | 4116 ostrl_map::iterator iter = list.find (fid); |
4117 | |
4118 if (iter != list.end ()) | |
2117 | 4119 { |
6757 | 4120 octave_stream os = iter->second; |
8902
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4121 list.erase (iter); |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4122 lookup_cache = list.end (); |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4123 |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4124 // FIXME: is this check redundant? |
6757 | 4125 if (os.is_valid ()) |
4126 { | |
4127 os.close (); | |
4128 retval = 0; | |
4129 } | |
4130 else | |
4131 gripe_invalid_file_id (fid, who); | |
2117 | 4132 } |
3341 | 4133 else |
4134 gripe_invalid_file_id (fid, who); | |
2117 | 4135 } |
3341 | 4136 else |
4137 gripe_invalid_file_id (fid, who); | |
2117 | 4138 |
4139 return retval; | |
4140 } | |
4141 | |
4142 int | |
3523 | 4143 octave_stream_list::do_remove (const octave_value& fid, const std::string& who) |
2117 | 4144 { |
4145 int retval = -1; | |
4146 | |
6054 | 4147 if (fid.is_string () && fid.string_value () == "all") |
4148 { | |
8902
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4149 do_clear (false); |
6054 | 4150 |
4151 retval = 0; | |
4152 } | |
4153 else | |
4154 { | |
4155 int i = get_file_number (fid); | |
4156 | |
4157 if (! error_state) | |
4158 retval = do_remove (i, who); | |
4159 } | |
2117 | 4160 |
4161 return retval; | |
4162 } | |
4163 | |
4164 void | |
8902
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4165 octave_stream_list::do_clear (bool flush) |
2117 | 4166 { |
8902
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4167 if (flush) |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4168 { |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4169 // Do flush stdout and stderr. |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4170 |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4171 list[0].flush (); |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4172 list[1].flush (); |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4173 } |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4174 |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4175 octave_stream saved_os[3]; |
2117 | 4176 // But don't delete them or stdin. |
8902
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4177 for (ostrl_map::iterator iter = list.begin (); iter != list.end (); iter++) |
6757 | 4178 { |
8902
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4179 int fid = iter->first; |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4180 octave_stream os = iter->second; |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4181 if (fid < 3) |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4182 saved_os[fid] = os; |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4183 else if (os.is_valid ()) |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4184 os.close (); |
6757 | 4185 } |
8902
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4186 list.clear (); |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4187 for (int fid = 0; fid < 3; fid++) list[fid] = saved_os[fid]; |
5d5db7a347c6
erase closed files from file list & cache lookup
Jaroslav Hajek <highegg@gmail.com>
parents:
8773
diff
changeset
|
4188 lookup_cache = list.end (); |
2117 | 4189 } |
4190 | |
4191 string_vector | |
4192 octave_stream_list::do_get_info (int fid) const | |
4193 { | |
4194 string_vector retval; | |
4195 | |
3340 | 4196 octave_stream os = do_lookup (fid); |
2117 | 4197 |
3341 | 4198 if (os.is_valid ()) |
2117 | 4199 { |
4200 retval.resize (3); | |
4201 | |
3340 | 4202 retval(0) = os.name (); |
4203 retval(1) = octave_stream::mode_as_string (os.mode ()); | |
4204 retval(2) = oct_mach_info::float_format_as_string (os.float_format ()); | |
2117 | 4205 } |
4206 else | |
3341 | 4207 ::error ("invalid file id = %d", fid); |
2117 | 4208 |
4209 return retval; | |
4210 } | |
4211 | |
4212 string_vector | |
4213 octave_stream_list::do_get_info (const octave_value& fid) const | |
4214 { | |
4215 string_vector retval; | |
4216 | |
4217 int conv_err = 0; | |
4218 | |
4219 int int_fid = convert_to_valid_int (fid, conv_err); | |
4220 | |
4221 if (! conv_err) | |
4222 retval = do_get_info (int_fid); | |
4223 else | |
2915 | 4224 ::error ("file id must be a file object or integer value"); |
2117 | 4225 |
4226 return retval; | |
4227 } | |
4228 | |
3536 | 4229 std::string |
2117 | 4230 octave_stream_list::do_list_open_files (void) const |
4231 { | |
3523 | 4232 std::string retval; |
2117 | 4233 |
5765 | 4234 std::ostringstream buf; |
2117 | 4235 |
4236 buf << "\n" | |
4237 << " number mode arch name\n" | |
4238 << " ------ ---- ---- ----\n"; | |
4239 | |
6757 | 4240 for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++) |
2117 | 4241 { |
6757 | 4242 octave_stream os = p->second; |
2117 | 4243 |
4326 | 4244 buf << " " |
4245 << std::setiosflags (std::ios::right) | |
6757 | 4246 << std::setw (4) << p->first << " " |
4326 | 4247 << std::setiosflags (std::ios::left) |
4248 << std::setw (3) | |
4249 << octave_stream::mode_as_string (os.mode ()) | |
4250 << " " | |
4251 << std::setw (9) | |
4252 << oct_mach_info::float_format_as_string (os.float_format ()) | |
4253 << " " | |
4254 << os.name () << "\n"; | |
2117 | 4255 } |
4256 | |
5765 | 4257 buf << "\n"; |
4258 | |
4259 retval = buf.str (); | |
2117 | 4260 |
4261 return retval; | |
4262 } | |
4263 | |
4264 octave_value | |
4265 octave_stream_list::do_open_file_numbers (void) const | |
4266 { | |
6757 | 4267 Matrix retval (1, list.size (), 0.0); |
2117 | 4268 |
4269 int num_open = 0; | |
4270 | |
6757 | 4271 for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++) |
2117 | 4272 { |
6757 | 4273 // Skip stdin, stdout, and stderr. |
4274 | |
4275 if (p->first > 2 && p->second) | |
4276 retval(0,num_open++) = p->first; | |
2117 | 4277 } |
4278 | |
4279 retval.resize ((num_open > 0), num_open); | |
4280 | |
4281 return retval; | |
4282 } | |
4283 | |
4284 int | |
2609 | 4285 octave_stream_list::do_get_file_number (const octave_value& fid) const |
2117 | 4286 { |
4287 int retval = -1; | |
4288 | |
4289 if (fid.is_string ()) | |
4290 { | |
3523 | 4291 std::string nm = fid.string_value (); |
2117 | 4292 |
6757 | 4293 for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++) |
2117 | 4294 { |
6757 | 4295 // stdin (std::cin), stdout (std::cout), and stderr (std::cerr) |
4296 // are unnamed. | |
4297 | |
4298 if (p->first > 2) | |
2117 | 4299 { |
6757 | 4300 octave_stream os = p->second; |
4301 | |
4302 if (os && os.name () == nm) | |
4303 { | |
4304 retval = p->first; | |
4305 break; | |
4306 } | |
2117 | 4307 } |
4308 } | |
4309 } | |
4310 else | |
4311 { | |
4312 int conv_err = 0; | |
4313 | |
4314 int int_fid = convert_to_valid_int (fid, conv_err); | |
4315 | |
4316 if (conv_err) | |
3523 | 4317 ::error ("file id must be a file object, std::string, or integer value"); |
2117 | 4318 else |
4319 retval = int_fid; | |
4320 } | |
4321 | |
4322 return retval; | |
4323 } | |
4324 | |
4325 /* | |
4326 ;;; Local Variables: *** | |
4327 ;;; mode: C++ *** | |
4328 ;;; End: *** | |
4329 */ |