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