GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
oct-stream.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2017 John W. Eaton
4 Copyright (C) 2015-2016 Lachlan Andrew, Monash University
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if defined (HAVE_CONFIG_H)
25 # include "config.h"
26 #endif
27 
28 #include <cassert>
29 #include <cctype>
30 #include <cstring>
31 
32 #include <deque>
33 #include <fstream>
34 #include <iomanip>
35 #include <iostream>
36 #include <sstream>
37 #include <string>
38 
39 #include "Array.h"
40 #include "Cell.h"
41 #include "byte-swap.h"
42 #include "lo-ieee.h"
43 #include "lo-mappers.h"
44 #include "lo-utils.h"
45 #include "oct-locbuf.h"
46 #include "quit.h"
47 #include "singleton-cleanup.h"
48 #include "str-vec.h"
49 
50 #include "error.h"
51 #include "errwarn.h"
52 #include "input.h"
53 #include "interpreter.h"
54 #include "octave.h"
55 #include "oct-stdstrm.h"
56 #include "oct-stream.h"
57 #include "ov.h"
58 #include "ovl.h"
59 #include "utils.h"
60 
61 // Programming Note: There are two very different error functions used
62 // in the stream code. When invoked with "error (...)" the member
63 // function from octave_stream or octave_base_stream is called. This
64 // function sets the error state on the stream AND returns control to
65 // the caller. The caller must then return a value at the end of the
66 // function. When invoked with "::error (...)" the exception-based
67 // error function from error.h is used. This function will throw an
68 // exception and not return control to the caller. BE CAREFUL and
69 // invoke the correct error function!
70 
71 // Possible values for conv_err:
72 //
73 // 1 : not a real scalar
74 // 2 : value is NaN
75 // 3 : value is not an integer
76 
77 static int
78 convert_to_valid_int (const octave_value& tc, int& conv_err)
79 {
80  conv_err = 0;
81 
82  int retval = 0;
83 
84  double dval = 0.0;
85 
86  try
87  {
88  dval = tc.double_value ();
89  }
90  catch (const octave::execution_exception&)
91  {
93 
94  conv_err = 1;
95  }
96 
97  if (! conv_err)
98  {
99  if (! lo_ieee_isnan (dval))
100  {
101  int ival = octave::math::nint (dval);
102 
103  if (ival == dval)
104  retval = ival;
105  else
106  conv_err = 3;
107  }
108  else
109  conv_err = 2;
110  }
111 
112  return retval;
113 }
114 
115 static octave_idx_type
116 get_size (double d, const std::string& who)
117 {
118  octave_idx_type retval = -1;
119 
120  if (lo_ieee_isnan (d))
121  ::error ("%s: NaN is invalid as size specification", who.c_str ());
122 
123  if (octave::math::isinf (d))
124  retval = -1;
125  else
126  {
127  if (d < 0.0)
128  ::error ("%s: negative value invalid as size specification",
129  who.c_str ());
130 
132  ::error ("%s: dimension too large for Octave's index type",
133  who.c_str ());
134 
135  retval = octave::math::nint_big (d);
136  }
137 
138  return retval;
139 }
140 
141 static void
143  bool& one_elt_size_spec, const std::string& who)
144 {
145  nr = -1;
146  nc = -1;
147 
148  one_elt_size_spec = false;
149 
150  double dnr = -1.0;
151  double dnc = -1.0;
152 
153  octave_idx_type sz_len = size.numel ();
154 
155  if (sz_len == 1)
156  {
157  one_elt_size_spec = true;
158 
159  dnr = size(0);
160 
161  dnc = (dnr == 0.0) ? 0.0 : 1.0;
162  }
163  else if (sz_len == 2)
164  {
165  dnr = size(0);
166 
167  if (octave::math::isinf (dnr))
168  ::error ("%s: invalid size specification", who.c_str ());
169 
170  dnc = size(1);
171  }
172  else
173  ::error ("%s: invalid size specification", who.c_str ());
174 
175  nr = get_size (dnr, who);
176 
177  if (dnc >= 0.0)
178  nc = get_size (dnc, who);
179 }
180 
181 class
183 {
184 public:
185 
187  {
188  whitespace_conversion = 1,
189  literal_conversion = 2,
190  null = 3
191  };
192 
193  scanf_format_elt (const char *txt = 0, int w = 0, bool d = false,
194  char typ = '\0', char mod = '\0',
195  const std::string& ch_class = "")
196  : text (strsave (txt)), width (w), discard (d), type (typ),
197  modifier (mod), char_class (ch_class)
198  { }
199 
201  : text (strsave (e.text)), width (e.width), discard (e.discard),
202  type (e.type), modifier (e.modifier), char_class (e.char_class)
203  { }
204 
205  scanf_format_elt& operator = (const scanf_format_elt& e)
206  {
207  if (this != &e)
208  {
209  text = strsave (e.text);
210  width = e.width;
211  discard = e.discard;
212  type = e.type;
213  modifier = e.modifier;
214  char_class = e.char_class;
215  }
216 
217  return *this;
218  }
219 
220  ~scanf_format_elt (void) { delete [] text; }
221 
222  // The C-style format string.
223  const char *text;
224 
225  // The maximum field width.
226  int width;
227 
228  // TRUE if we are not storing the result of this conversion.
229  bool discard;
230 
231  // Type of conversion -- 'd', 'i', 'o', 'u', 'x', 'e', 'f', 'g',
232  // 'c', 's', 'p', '%', or '['.
233  char type;
234 
235  // A length modifier -- 'h', 'l', or 'L'.
236  char modifier;
237 
238  // The class of characters in a '[' format.
240 };
241 
242 class
244 {
245 public:
246 
247  scanf_format_list (const std::string& fmt = "");
248 
249  ~scanf_format_list (void);
250 
251  octave_idx_type num_conversions (void) { return nconv; }
252 
253  // The length can be different than the number of conversions.
254  // For example, "x %d y %d z" has 2 conversions but the length of
255  // the list is 3 because of the characters that appear after the
256  // last conversion.
257 
258  size_t length (void) const { return fmt_elts.size (); }
259 
260  const scanf_format_elt *first (void)
261  {
262  curr_idx = 0;
263  return current ();
264  }
265 
266  const scanf_format_elt *current (void) const
267  {
268  return length () > 0 ? fmt_elts[curr_idx] : 0;
269  }
270 
271  const scanf_format_elt *next (bool cycle = true)
272  {
273  static scanf_format_elt dummy
274  (0, 0, false, scanf_format_elt::null, '\0', "");
275 
276  curr_idx++;
277 
278  if (curr_idx >= length ())
279  {
280  if (cycle)
281  curr_idx = 0;
282  else
283  return &dummy;
284  }
285 
286  return current ();
287  }
288 
289  void printme (void) const;
290 
291  bool ok (void) const { return (nconv >= 0); }
292 
293  operator bool () const { return ok (); }
294 
295  bool all_character_conversions (void);
296 
297  bool all_numeric_conversions (void);
298 
299 private:
300 
301  // Number of conversions specified by this format string, or -1 if
302  // invalid conversions have been found.
304 
305  // Index to current element;
306  size_t curr_idx;
307 
308  // List of format elements.
309  std::deque<scanf_format_elt*> fmt_elts;
310 
311  // Temporary buffer.
312  std::ostringstream buf;
313 
314  void add_elt_to_list (int width, bool discard, char type, char modifier,
315  const std::string& char_class = "");
316 
317  void process_conversion (const std::string& s, size_t& i, size_t n,
318  int& width, bool& discard, char& type,
319  char& modifier);
320 
321  int finish_conversion (const std::string& s, size_t& i, size_t n,
322  int& width, bool discard, char& type,
323  char modifier);
324  // No copying!
325 
327 
328  scanf_format_list& operator = (const scanf_format_list&);
329 };
330 
332  : nconv (0), curr_idx (0), fmt_elts (), buf ()
333 {
334  size_t n = s.length ();
335 
336  size_t i = 0;
337 
338  int width = 0;
339  bool discard = false;
340  char modifier = '\0';
341  char type = '\0';
342 
343  bool have_more = true;
344 
345  while (i < n)
346  {
347  have_more = true;
348 
349  if (s[i] == '%')
350  {
351  // Process percent-escape conversion type.
352 
353  process_conversion (s, i, n, width, discard, type, modifier);
354 
355  have_more = (buf.tellp () != 0);
356  }
357  else if (isspace (s[i]))
358  {
360 
361  width = 0;
362  discard = false;
363  modifier = '\0';
364  buf << " ";
365 
366  while (++i < n && isspace (s[i]))
367  ; // skip whitespace
368 
369  add_elt_to_list (width, discard, type, modifier);
370 
371  have_more = false;
372  }
373  else
374  {
376 
377  width = 0;
378  discard = false;
379  modifier = '\0';
380 
381  while (i < n && ! isspace (s[i]) && s[i] != '%')
382  buf << s[i++];
383 
384  add_elt_to_list (width, discard, type, modifier);
385 
386  have_more = false;
387  }
388 
389  if (nconv < 0)
390  {
391  have_more = false;
392  break;
393  }
394  }
395 
396  if (have_more)
397  add_elt_to_list (width, discard, type, modifier);
398 
399  buf.clear ();
400  buf.str ("");
401 }
402 
404 {
405  size_t n = fmt_elts.size ();
406 
407  for (size_t i = 0; i < n; i++)
408  {
409  scanf_format_elt *elt = fmt_elts[i];
410  delete elt;
411  }
412 }
413 
414 void
415 scanf_format_list::add_elt_to_list (int width, bool discard, char type,
416  char modifier,
417  const std::string& char_class)
418 {
419  std::string text = buf.str ();
420 
421  if (! text.empty ())
422  {
423  scanf_format_elt *elt
424  = new scanf_format_elt (text.c_str (), width, discard, type,
425  modifier, char_class);
426 
427  fmt_elts.push_back (elt);
428  }
429 
430  buf.clear ();
431  buf.str ("");
432 }
433 
434 static std::string
436 {
438 
439  size_t len = s.length ();
440 
441  size_t i = 0;
442 
443  while (i < len)
444  {
445  unsigned char c = s[i++];
446 
447  if (c == '-' && i > 1 && i < len
448  && ( static_cast<unsigned char> (s[i-2])
449  <= static_cast<unsigned char> (s[i])))
450  {
451  // Add all characters from the range except the first (we
452  // already added it below).
453 
454  for (c = s[i-2]+1; c < s[i]; c++)
455  retval += c;
456  }
457  else
458  {
459  // Add the character to the class. Only add '-' if it is
460  // the last character in the class.
461 
462  if (c != '-' || i == len)
463  retval += c;
464  }
465  }
466 
467  return retval;
468 }
469 
470 void
472  size_t n, int& width, bool& discard,
473  char& type, char& modifier)
474 {
475  width = 0;
476  discard = false;
477  modifier = '\0';
478  type = '\0';
479 
480  buf << s[i++];
481 
482  bool have_width = false;
483 
484  while (i < n)
485  {
486  switch (s[i])
487  {
488  case '*':
489  if (discard)
490  nconv = -1;
491  else
492  {
493  discard = true;
494  buf << s[i++];
495  }
496  break;
497 
498  case '0': case '1': case '2': case '3': case '4':
499  case '5': case '6': case '7': case '8': case '9':
500  if (have_width)
501  nconv = -1;
502  else
503  {
504  char c = s[i++];
505  width = 10 * width + c - '0';
506  have_width = true;
507  buf << c;
508  while (i < n && isdigit (s[i]))
509  {
510  c = s[i++];
511  width = 10 * width + c - '0';
512  buf << c;
513  }
514  }
515  break;
516 
517  case 'h': case 'l': case 'L':
518  if (modifier != '\0')
519  nconv = -1;
520  else
521  modifier = s[i++];
522  break;
523 
524  case 'd': case 'i': case 'o': case 'u': case 'x':
525  if (modifier == 'L')
526  {
527  nconv = -1;
528  break;
529  }
530  goto fini;
531 
532  case 'e': case 'f': case 'g':
533  if (modifier == 'h')
534  {
535  nconv = -1;
536  break;
537  }
538 
539  // No float or long double conversions, thanks.
540  buf << 'l';
541 
542  goto fini;
543 
544  case 'c': case 's': case 'p': case '%': case '[':
545  if (modifier != '\0')
546  {
547  nconv = -1;
548  break;
549  }
550  goto fini;
551 
552  fini:
553  {
554  if (finish_conversion (s, i, n, width, discard,
555  type, modifier) == 0)
556  return;
557  }
558  break;
559 
560  default:
561  nconv = -1;
562  break;
563  }
564 
565  if (nconv < 0)
566  break;
567  }
568 
569  nconv = -1;
570 }
571 
572 int
574  size_t n, int& width, bool discard,
575  char& type, char modifier)
576 {
577  int retval = 0;
578 
579  std::string char_class;
580 
581  size_t beg_idx = std::string::npos;
582  size_t end_idx = std::string::npos;
583 
584  if (s[i] == '%')
585  {
586  type = '%';
587  buf << s[i++];
588  }
589  else
590  {
591  type = s[i];
592 
593  if (s[i] == '[')
594  {
595  buf << s[i++];
596 
597  if (i < n)
598  {
599  beg_idx = i;
600 
601  if (s[i] == '^')
602  {
603  type = '^';
604  buf << s[i++];
605 
606  if (i < n)
607  {
608  beg_idx = i;
609 
610  if (s[i] == ']')
611  buf << s[i++];
612  }
613  }
614  else if (s[i] == ']')
615  buf << s[i++];
616  }
617 
618  while (i < n && s[i] != ']')
619  buf << s[i++];
620 
621  if (i < n && s[i] == ']')
622  {
623  end_idx = i-1;
624  buf << s[i++];
625  }
626 
627  if (s[i-1] != ']')
628  retval = nconv = -1;
629  }
630  else
631  buf << s[i++];
632 
633  nconv++;
634  }
635 
636  if (nconv >= 0)
637  {
638  if (beg_idx != std::string::npos && end_idx != std::string::npos)
639  char_class = expand_char_class (s.substr (beg_idx,
640  end_idx - beg_idx + 1));
641 
642  add_elt_to_list (width, discard, type, modifier, char_class);
643  }
644 
645  return retval;
646 }
647 
648 void
650 {
651  size_t n = fmt_elts.size ();
652 
653  for (size_t i = 0; i < n; i++)
654  {
655  scanf_format_elt *elt = fmt_elts[i];
656 
657  std::cerr
658  << "width: " << elt->width << "\n"
659  << "discard: " << elt->discard << "\n"
660  << "type: ";
661 
663  std::cerr << "literal text\n";
665  std::cerr << "whitespace\n";
666  else
667  std::cerr << elt->type << "\n";
668 
669  std::cerr
670  << "modifier: " << elt->modifier << "\n"
671  << "char_class: '" << undo_string_escapes (elt->char_class) << "'\n"
672  << "text: '" << undo_string_escapes (elt->text) << "'\n\n";
673  }
674 }
675 
676 bool
678 {
679  size_t n = fmt_elts.size ();
680 
681  if (n > 0)
682  {
683  for (size_t i = 0; i < n; i++)
684  {
685  scanf_format_elt *elt = fmt_elts[i];
686 
687  switch (elt->type)
688  {
689  case 'c': case 's': case '%': case '[': case '^':
692  break;
693 
694  default:
695  return false;
696  break;
697  }
698  }
699 
700  return true;
701  }
702  else
703  return false;
704 }
705 
706 bool
708 {
709  size_t n = fmt_elts.size ();
710 
711  if (n > 0)
712  {
713  for (size_t i = 0; i < n; i++)
714  {
715  scanf_format_elt *elt = fmt_elts[i];
716 
717  switch (elt->type)
718  {
719  case 'd': case 'i': case 'o': case 'u': case 'x':
720  case 'e': case 'f': case 'g':
721  break;
722 
723  default:
724  return false;
725  break;
726  }
727  }
728 
729  return true;
730  }
731  else
732  return false;
733 }
734 
735 class
737 {
738 public:
739 
740  printf_format_elt (const char *txt = 0, int n = 0, int w = -1,
741  int p = -1, const std::string& f = "",
742  char typ = '\0', char mod = '\0')
743  : text (strsave (txt)), args (n), fw (w), prec (p), flags (f),
744  type (typ), modifier (mod)
745  { }
746 
748  : text (strsave (e.text)), args (e.args), fw (e.fw), prec (e.prec),
749  flags (e.flags), type (e.type), modifier (e.modifier)
750  { }
751 
752  printf_format_elt& operator = (const printf_format_elt& e)
753  {
754  if (this != &e)
755  {
756  text = strsave (e.text);
757  args = e.args;
758  fw = e.fw;
759  prec = e.prec;
760  flags = e.flags;
761  type = e.type;
762  modifier = e.modifier;
763  }
764 
765  return *this;
766  }
767 
768  ~printf_format_elt (void) { delete [] text; }
769 
770  // The C-style format string.
771  const char *text;
772 
773  // How many args do we expect to consume?
774  int args;
775 
776  // Field width.
777  int fw;
778 
779  // Precision.
780  int prec;
781 
782  // Flags -- '-', '+', ' ', '0', or '#'.
784 
785  // Type of conversion -- 'd', 'i', 'o', 'x', 'X', 'u', 'c', 's',
786  // 'f', 'e', 'E', 'g', 'G', 'p', or '%'
787  char type;
788 
789  // A length modifier -- 'h', 'l', or 'L'.
790  char modifier;
791 };
792 
793 class
795 {
796 public:
797 
798  printf_format_list (const std::string& fmt = "");
799 
800  ~printf_format_list (void);
801 
802  octave_idx_type num_conversions (void) { return nconv; }
803 
804  const printf_format_elt *first (void)
805  {
806  curr_idx = 0;
807  return current ();
808  }
809 
810  const printf_format_elt *current (void) const
811  {
812  return length () > 0 ? fmt_elts[curr_idx] : 0;
813  }
814 
815  size_t length (void) const { return fmt_elts.size (); }
816 
817  const printf_format_elt *next (bool cycle = true)
818  {
819  curr_idx++;
820 
821  if (curr_idx >= length ())
822  {
823  if (cycle)
824  curr_idx = 0;
825  else
826  return 0;
827  }
828 
829  return current ();
830  }
831 
832  bool last_elt_p (void) { return (curr_idx + 1 == length ()); }
833 
834  void printme (void) const;
835 
836  bool ok (void) const { return (nconv >= 0); }
837 
838  operator bool () const { return ok (); }
839 
840 private:
841 
842  // Number of conversions specified by this format string, or -1 if
843  // invalid conversions have been found.
845 
846  // Index to current element;
847  size_t curr_idx;
848 
849  // List of format elements.
850  std::deque<printf_format_elt*> fmt_elts;
851 
852  // Temporary buffer.
853  std::ostringstream buf;
854 
855  void add_elt_to_list (int args, const std::string& flags, int fw,
856  int prec, char type, char modifier);
857 
858  void process_conversion (const std::string& s, size_t& i, size_t n,
859  int& args, std::string& flags, int& fw,
860  int& prec, char& modifier, char& type);
861 
862  void finish_conversion (const std::string& s, size_t& i, int args,
863  const std::string& flags, int fw, int prec,
864  char modifier, char& type);
865 
866  // No copying!
867 
869 
870  printf_format_list& operator = (const printf_format_list&);
871 };
872 
874  : nconv (0), curr_idx (0), fmt_elts (), buf ()
875 {
876  size_t n = s.length ();
877 
878  size_t i = 0;
879 
880  int args = 0;
881  std::string flags;
882  int fw = -1;
883  int prec = -1;
884  char modifier = '\0';
885  char type = '\0';
886 
887  bool have_more = true;
888  bool empty_buf = true;
889 
890  if (n == 0)
891  {
892  printf_format_elt *elt
893  = new printf_format_elt ("", args, fw, prec, flags, type, modifier);
894 
895  fmt_elts.push_back (elt);
896  }
897  else
898  {
899  while (i < n)
900  {
901  have_more = true;
902 
903  empty_buf = (buf.tellp () == 0);
904 
905  switch (s[i])
906  {
907  case '%':
908  {
909  if (empty_buf)
910  {
911  process_conversion (s, i, n, args, flags, fw, prec,
912  type, modifier);
913 
914  // If there is nothing in the buffer, then
915  // add_elt_to_list must have just been called, so we
916  // are already done with the current element and we
917  // don't need to call add_elt_to_list if this is our
918  // last trip through the loop.
919 
920  have_more = (buf.tellp () != 0);
921  }
922  else
923  add_elt_to_list (args, flags, fw, prec, type, modifier);
924  }
925  break;
926 
927  default:
928  {
929  args = 0;
930  flags = "";
931  fw = -1;
932  prec = -1;
933  modifier = '\0';
934  type = '\0';
935  buf << s[i++];
936  empty_buf = false;
937  }
938  break;
939  }
940 
941  if (nconv < 0)
942  {
943  have_more = false;
944  break;
945  }
946  }
947 
948  if (have_more)
949  add_elt_to_list (args, flags, fw, prec, type, modifier);
950 
951  buf.clear ();
952  buf.str ("");
953  }
954 }
955 
957 {
958  size_t n = fmt_elts.size ();
959 
960  for (size_t i = 0; i < n; i++)
961  {
962  printf_format_elt *elt = fmt_elts[i];
963  delete elt;
964  }
965 }
966 
967 void
969  int fw, int prec, char type,
970  char modifier)
971 {
972  std::string text = buf.str ();
973 
974  if (! text.empty ())
975  {
976  printf_format_elt *elt
977  = new printf_format_elt (text.c_str (), args, fw, prec, flags,
978  type, modifier);
979 
980  fmt_elts.push_back (elt);
981  }
982 
983  buf.clear ();
984  buf.str ("");
985 }
986 
987 void
989  size_t n, int& args,
990  std::string& flags, int& fw,
991  int& prec, char& modifier,
992  char& type)
993 {
994  args = 0;
995  flags = "";
996  fw = -1;
997  prec = -1;
998  modifier = '\0';
999  type = '\0';
1000 
1001  buf << s[i++];
1002 
1003  bool nxt = false;
1004 
1005  while (i < n)
1006  {
1007  switch (s[i])
1008  {
1009  case '-': case '+': case ' ': case '0': case '#':
1010  flags += s[i];
1011  buf << s[i++];
1012  break;
1013 
1014  default:
1015  nxt = true;
1016  break;
1017  }
1018 
1019  if (nxt)
1020  break;
1021  }
1022 
1023  if (i < n)
1024  {
1025  if (s[i] == '*')
1026  {
1027  fw = -2;
1028  args++;
1029  buf << s[i++];
1030  }
1031  else
1032  {
1033  if (isdigit (s[i]))
1034  {
1035  int nn = 0;
1036  std::string tmp = s.substr (i);
1037  sscanf (tmp.c_str (), "%d%n", &fw, &nn);
1038  }
1039 
1040  while (i < n && isdigit (s[i]))
1041  buf << s[i++];
1042  }
1043  }
1044 
1045  if (i < n && s[i] == '.')
1046  {
1047  // nothing before the . means 0.
1048  if (fw == -1)
1049  fw = 0;
1050 
1051  // . followed by nothing is 0.
1052  prec = 0;
1053 
1054  buf << s[i++];
1055 
1056  if (i < n)
1057  {
1058  if (s[i] == '*')
1059  {
1060  prec = -2;
1061  args++;
1062  buf << s[i++];
1063  }
1064  else
1065  {
1066  if (isdigit (s[i]))
1067  {
1068  int nn = 0;
1069  std::string tmp = s.substr (i);
1070  sscanf (tmp.c_str (), "%d%n", &prec, &nn);
1071  }
1072 
1073  while (i < n && isdigit (s[i]))
1074  buf << s[i++];
1075  }
1076  }
1077  }
1078 
1079  if (i < n)
1080  {
1081  // Accept and record modifier, but don't place it in the format
1082  // item text. All integer conversions are handled as 64-bit
1083  // integers.
1084 
1085  switch (s[i])
1086  {
1087  case 'h': case 'l': case 'L':
1088  modifier = s[i++];
1089  break;
1090 
1091  default:
1092  break;
1093  }
1094  }
1095 
1096  if (i < n)
1097  finish_conversion (s, i, args, flags, fw, prec, modifier, type);
1098  else
1099  nconv = -1;
1100 }
1101 
1102 void
1104  int args, const std::string& flags,
1105  int fw, int prec, char modifier,
1106  char& type)
1107 {
1108  switch (s[i])
1109  {
1110  case 'd': case 'i': case 'o': case 'x': case 'X':
1111  case 'u': case 'c':
1112  if (modifier == 'L')
1113  {
1114  nconv = -1;
1115  break;
1116  }
1117  goto fini;
1118 
1119  case 'f': case 'e': case 'E': case 'g': case 'G':
1120  if (modifier == 'h' || modifier == 'l')
1121  {
1122  nconv = -1;
1123  break;
1124  }
1125  goto fini;
1126 
1127  case 's': case 'p': case '%':
1128  if (modifier != '\0')
1129  {
1130  nconv = -1;
1131  break;
1132  }
1133  goto fini;
1134 
1135  fini:
1136 
1137  type = s[i];
1138 
1139  buf << s[i++];
1140 
1141  if (type != '%' || args != 0)
1142  nconv++;
1143 
1144  if (type != '%')
1145  args++;
1146 
1147  add_elt_to_list (args, flags, fw, prec, type, modifier);
1148 
1149  break;
1150 
1151  default:
1152  nconv = -1;
1153  break;
1154  }
1155 }
1156 
1157 void
1159 {
1160  size_t n = fmt_elts.size ();
1161 
1162  for (size_t i = 0; i < n; i++)
1163  {
1164  printf_format_elt *elt = fmt_elts[i];
1165 
1166  std::cerr
1167  << "args: " << elt->args << "\n"
1168  << "flags: '" << elt->flags << "'\n"
1169  << "width: " << elt->fw << "\n"
1170  << "prec: " << elt->prec << "\n"
1171  << "type: '" << elt->type << "'\n"
1172  << "modifier: '" << elt->modifier << "'\n"
1173  << "text: '" << undo_string_escapes (elt->text) << "'\n\n";
1174  }
1175 }
1176 
1177 // Calculate x^n. Used for ...e+nn so that, for example, 1e2 is
1178 // exactly 100 and 5e-1 is 1/2
1179 
1180 static double
1181 pown (double x, unsigned int n)
1182 {
1183  double retval = 1;
1184 
1185  for (unsigned int d = n; d; d >>= 1)
1186  {
1187  if (d & 1)
1188  retval *= x;
1189  x *= x;
1190  }
1191 
1192  return retval;
1193 }
1194 
1195 static Cell
1197 {
1198  Cell retval (dim_vector (1, 2));
1199 
1200  retval(0) = Cell (octave_value ("inf"));
1201  retval(1) = Cell (octave_value ("nan"));
1202 
1203  return retval;
1204 }
1205 
1206 namespace octave
1207 {
1208  // Delimited stream, optimized to read strings of characters separated
1209  // by single-character delimiters.
1210  //
1211  // The reason behind this class is that octstream doesn't provide
1212  // seek/tell, but the opportunity has been taken to optimise for the
1213  // textscan workload.
1214  //
1215  // The function reads chunks into a 4kiB buffer, and marks where the
1216  // last delimiter occurs. Reads up to this delimiter can be fast.
1217  // After that last delimiter, the remaining text is moved to the front
1218  // of the buffer and the buffer is refilled. This also allows cheap
1219  // seek and tell operations within a "fast read" block.
1220 
1221  class
1223  {
1224  public:
1225 
1226  delimited_stream (std::istream& is, const std::string& delimiters,
1227  int longest_lookahead, octave_idx_type bsize = 4096);
1228 
1229  delimited_stream (std::istream& is, const delimited_stream& ds);
1230 
1231  ~delimited_stream (void);
1232 
1233  // Called when optimized sequence of get is finished. Ensures that
1234  // there is a remaining delimiter in buf, or loads more data in.
1235  void field_done (void)
1236  {
1237  if (idx >= last)
1238  refresh_buf ();
1239  }
1240 
1241  // Load new data into buffer, and set eob, last, idx.
1242  // Return EOF at end of file, 0 otherwise.
1243  int refresh_buf (void);
1244 
1245  // Get a character, relying on caller to call field_done if
1246  // a delimiter has been reached.
1247  int get (void)
1248  {
1249  if (delimited)
1250  return eof () ? std::istream::traits_type::eof () : *idx++;
1251  else
1252  return get_undelim ();
1253  }
1254 
1255  // Get a character, checking for underrun of the buffer.
1256  int get_undelim (void);
1257 
1258  // Read character that will be got by the next get.
1259  int peek (void) { return eof () ? std::istream::traits_type::eof () : *idx; }
1260 
1261  // Read character that will be got by the next get.
1262  int peek_undelim (void);
1263 
1264  // Undo a 'get' or 'get_undelim'. It is the caller's responsibility
1265  // to avoid overflow by calling putbacks only for a character got by
1266  // get() or get_undelim(), with no intervening
1267  // get, get_delim, field_done, refresh_buf, getline, read or seekg.
1268  void putback (char /*ch*/ = 0) { if (! eof ()) --idx; }
1269 
1270  int getline (std::string& dest, char delim);
1271 
1272  // int skipline (char delim);
1273 
1274  char *read (char *buffer, int size, char* &new_start);
1275 
1276  // Return a position suitable to "seekg", valid only within this
1277  // block between calls to field_done.
1278  char *tellg (void) { return idx; }
1279 
1280  void seekg (char *old_idx) { idx = old_idx; }
1281 
1282  bool eof (void)
1283  {
1284  return (eob == buf && i_stream.eof ()) || (flags & std::ios_base::eofbit);
1285  }
1286 
1287  operator const void* (void) { return (! eof () && ! flags) ? this : 0; }
1288 
1289  bool fail (void) { return flags & std::ios_base::failbit; }
1290 
1291  std::ios_base::iostate rdstate (void) { return flags; }
1292 
1293  void setstate (std::ios_base::iostate m) { flags = flags | m; }
1294 
1295  void clear (std::ios_base::iostate m
1296  = (std::ios_base::eofbit & ~std::ios_base::eofbit))
1297  {
1298  flags = flags & m;
1299  }
1300 
1301  // Report if any characters have been consumed.
1302  // (get, read, etc. not cancelled by putback or seekg)
1303 
1304  void progress_benchmark (void) { progress_marker = idx; }
1305 
1306  bool no_progress (void) { return progress_marker == idx; }
1307 
1308  private:
1309 
1310  // Number of characters to read from the file at once.
1311  int bufsize;
1312 
1313  // Stream to read from.
1314  std::istream& i_stream;
1315 
1316  // Temporary storage for a "chunk" of data.
1317  char *buf;
1318 
1319  // Current read pointer.
1320  char *idx;
1321 
1322  // Location of last delimiter in the buffer at buf (undefined if
1323  // delimited is false).
1324  char *last;
1325 
1326  // Position after last character in buffer.
1327  char *eob;
1328 
1329  // True if there is delimiter in the bufer after idx.
1331 
1332  // Longest lookahead required.
1333  int longest;
1334 
1335  // Sequence of single-character delimiters.
1337 
1338  // Position of start of buf in original stream.
1339  std::streampos buf_in_file;
1340 
1341  // Marker to see if a read consumes any characters.
1343 
1344  std::ios_base::iostate flags;
1345 
1346  // No copying!
1347 
1349 
1350  delimited_stream& operator = (const delimited_stream&);
1351  };
1352 
1353  // Create a delimited stream, reading from is, with delimiters delims,
1354  // and allowing reading of up to tellg + longest_lookeahead. When is
1355  // is at EOF, lookahead may be padded by ASCII nuls.
1356 
1358  const std::string& delimiters,
1359  int longest_lookahead,
1360  octave_idx_type bsize)
1361  : bufsize (bsize), i_stream (is), longest (longest_lookahead),
1362  delims (delimiters),
1363  flags (std::ios::failbit & ~std::ios::failbit) // can't cast 0
1364  {
1365  buf = new char[bufsize];
1366  eob = buf + bufsize;
1367  idx = eob; // refresh_buf shouldn't try to copy old data
1368  progress_marker = idx;
1369  refresh_buf (); // load the first batch of data
1370  }
1371 
1372  // Used to create a stream from a strstream from data read from a dstr.
1373  // FIXME: Find a more efficient approach. Perhaps derived dstr
1375  const delimited_stream& ds)
1376  : bufsize (ds.bufsize), i_stream (is), longest (ds.longest),
1377  delims (ds.delims),
1378  flags (std::ios::failbit & ~std::ios::failbit) // can't cast 0
1379  {
1380  buf = new char[bufsize];
1381  eob = buf + bufsize;
1382  idx = eob; // refresh_buf shouldn't try to copy old data
1383  progress_marker = idx;
1384  refresh_buf (); // load the first batch of data
1385  }
1386 
1388  {
1389  // Seek to the correct position in i_stream.
1390  if (! eof ())
1391  {
1392  i_stream.clear ();
1393  i_stream.seekg (buf_in_file);
1394  i_stream.read (buf, idx - buf);
1395  }
1396 
1397  delete [] buf;
1398  }
1399 
1400  // Read a character from the buffer, refilling the buffer from the file
1401  // if necessary.
1402 
1403  int
1405  {
1406  int retval;
1407  if (eof ())
1408  {
1409  setstate (std::ios_base::failbit);
1410  return std::istream::traits_type::eof ();
1411  }
1412 
1413  if (idx < eob)
1414  retval = *idx++;
1415  else
1416  {
1417  refresh_buf ();
1418 
1419  if (eof ())
1420  {
1421  setstate (std::ios_base::eofbit);
1422  retval = std::istream::traits_type::eof ();
1423  }
1424  else
1425  retval = *idx++;
1426  }
1427 
1428  if (idx >= last)
1429  delimited = false;
1430 
1431  return retval;
1432  }
1433 
1434  // Return the next character to be read without incrementing the
1435  // pointer, refilling the buffer from the file if necessary.
1436 
1437  int
1439  {
1440  int retval = get_undelim ();
1441  putback ();
1442 
1443  return retval;
1444  }
1445 
1446  // Copy remaining unprocessed data to the start of the buffer and load
1447  // new data to fill it. Return EOF if the file is at EOF before
1448  // reading any data and all of the data that has been read has been
1449  // processed.
1450 
1451  int
1453  {
1454  if (eof ())
1455  return std::istream::traits_type::eof ();
1456 
1457  int retval;
1458 
1459  if (eob < idx)
1460  idx = eob;
1461 
1462  size_t old_remaining = eob - idx;
1463 
1464  octave_quit (); // allow ctrl-C
1465 
1466  if (old_remaining > 0)
1467  {
1468  buf_in_file += (idx - buf);
1469  memmove (buf, idx, old_remaining);
1470  }
1471 
1472  progress_marker -= idx - buf; // where original idx would have been
1473  idx = buf;
1474 
1475  int gcount; // chars read
1476  if (! i_stream.eof ())
1477  {
1478  buf_in_file = i_stream.tellg (); // record for destructor
1479  i_stream.read (buf + old_remaining, bufsize - old_remaining);
1480  gcount = i_stream.gcount ();
1481  }
1482  else
1483  gcount = 0;
1484 
1485  eob = buf + old_remaining + gcount;
1486  last = eob;
1487  if (gcount == 0)
1488  {
1489  delimited = false;
1490 
1491  if (eob != buf) // no more data in file, but still some to go
1492  retval = 0;
1493  else
1494  // file and buffer are both done.
1495  retval = std::istream::traits_type::eof ();
1496  }
1497  else
1498  {
1499  delimited = true;
1500 
1501  for (last = eob - longest; last - buf >= 0; last--)
1502  {
1503  if (delims.find (*last) != std::string::npos)
1504  break;
1505  }
1506 
1507  if (last < buf)
1508  delimited = false;
1509 
1510  retval = 0;
1511  }
1512 
1513  // Ensure fast peek doesn't give valid char
1514  if (retval == std::istream::traits_type::eof ())
1515  *idx = '\0'; // FIXME: check that no TreatAsEmpty etc starts w. \0?
1516 
1517  return retval;
1518  }
1519 
1520  // Return a pointer to a block of data of size size, assuming that a
1521  // sufficiently large buffer is available in buffer, if required.
1522  // If called when delimited == true, and size is no greater than
1523  // longest_lookahead then this will not call refresh_buf, so seekg
1524  // still works. Otherwise, seekg may be invalidated.
1525 
1526  char *
1527  delimited_stream::read (char *buffer, int size, char* &prior_tell)
1528  {
1529  char *retval;
1530 
1531  if (eob - idx > size)
1532  {
1533  retval = idx;
1534  idx += size;
1535  if (idx > last)
1536  delimited = false;
1537  }
1538  else
1539  {
1540  // If there was a tellg pointing to an earlier point than the current
1541  // read position, try to keep it in the active buffer.
1542  // In the current code, prior_tell==idx for each call,
1543  // so this is not necessary, just a precaution.
1544 
1545  if (eob - prior_tell + size < bufsize)
1546  {
1547  octave_idx_type gap = idx - prior_tell;
1548  idx = prior_tell;
1549  refresh_buf ();
1550  idx += gap;
1551  }
1552  else // can't keep the tellg in range. May skip some data.
1553  {
1554  refresh_buf ();
1555  }
1556 
1557  prior_tell = buf;
1558 
1559  if (eob - idx > size)
1560  {
1561  retval = idx;
1562  idx += size;
1563  if (idx > last)
1564  delimited = false;
1565  }
1566  else
1567  {
1568  if (size <= bufsize) // small read, but reached EOF
1569  {
1570  retval = idx;
1571  memset (eob, 0, size + (idx - buf));
1572  idx += size;
1573  }
1574  else // Reading more than the whole buf; return it in buffer
1575  {
1576  retval = buffer;
1577  // FIXME: read bufsize at a time
1578  int i;
1579  for (i = 0; i < size && ! eof (); i++)
1580  *buffer++ = get_undelim ();
1581  if (eof ())
1582  memset (buffer, 0, size - i);
1583  }
1584  }
1585  }
1586 
1587  return retval;
1588  }
1589 
1590  // Return in OUT an entire line, terminated by delim. On input, OUT
1591  // must have length at least 1.
1592 
1593  int
1595  {
1596  int len = out.length (), used = 0;
1597  int ch;
1598  while ((ch = get_undelim ()) != delim
1599  && ch != std::istream::traits_type::eof ())
1600  {
1601  out[used++] = ch;
1602  if (used == len)
1603  {
1604  len <<= 1;
1605  out.resize (len);
1606  }
1607  }
1608  out.resize (used);
1609  field_done ();
1610 
1611  return ch;
1612  }
1613 
1614  // A single conversion specifier, such as %f or %c.
1615 
1616  class
1618  {
1619  public:
1620 
1622  {
1623  whitespace_conversion = 1,
1624  literal_conversion = 2
1625  };
1626 
1627  textscan_format_elt (const std::string& txt, int w = 0, int p = -1,
1628  int bw = 0, bool dis = false, char typ = '\0',
1629  const std::string& ch_class = std::string ())
1630  : text (txt), width (w), prec (p), bitwidth (bw),
1631  char_class (ch_class), type (typ), discard (dis),
1632  numeric (typ == 'd' || typ == 'u' || type == 'f' || type == 'n')
1633  { }
1634 
1636  : text (e.text), width (e.width), prec (e.prec),
1637  bitwidth (e.bitwidth), char_class (e.char_class), type (e.type),
1638  discard (e.discard), numeric (e.numeric)
1639  { }
1640 
1642  {
1643  if (this != &e)
1644  {
1645  text = e.text;
1646  width = e.width;
1647  prec = e.prec;
1648  bitwidth = e.bitwidth;
1649  discard = e.discard;
1650  type = e.type;
1651  numeric = e.numeric;
1652  char_class = e.char_class;
1653  }
1654 
1655  return *this;
1656  }
1657 
1658  // The C-style format string.
1660 
1661  // The maximum field width.
1662  unsigned int width;
1663 
1664  // The maximum number of digits to read after the decimal in a
1665  // floating point conversion.
1666  int prec;
1667 
1668  // The size of the result. For integers, bitwidth may be 8, 16, 34,
1669  // or 64. For floating point values, bitwidth may be 32 or 64.
1671 
1672  // The class of characters in a `[' or `^' format.
1674 
1675  // Type of conversion
1676  // -- `d', `u', `f', `n', `s', `q', `c', `%', `C', `D', `[' or `^'.
1677  char type;
1678 
1679  // TRUE if we are not storing the result of this conversion.
1680  bool discard;
1681 
1682  // TRUE if the type is 'd', 'u', 'f', 'n'
1683  bool numeric;
1684  };
1685 
1686  // The (parsed) sequence of format specifiers.
1687 
1688  class textscan;
1689 
1690  class
1692  {
1693  public:
1694 
1695  textscan_format_list (const std::string& fmt = std::string (),
1696  const std::string& who = "textscan");
1697 
1698  ~textscan_format_list (void);
1699 
1700  octave_idx_type num_conversions (void) const { return nconv; }
1701 
1702  // The length can be different than the number of conversions.
1703  // For example, "x %d y %d z" has 2 conversions but the length of
1704  // the list is 3 because of the characters that appear after the
1705  // last conversion.
1706 
1707  size_t numel (void) const { return fmt_elts.size (); }
1708 
1710  {
1711  curr_idx = 0;
1712  return current ();
1713  }
1714 
1715  const textscan_format_elt *current (void) const
1716  {
1717  return numel () > 0 ? fmt_elts[curr_idx] : 0;
1718  }
1719 
1720  const textscan_format_elt *next (bool cycle = true)
1721  {
1722  curr_idx++;
1723 
1724  if (curr_idx >= numel ())
1725  {
1726  if (cycle)
1727  curr_idx = 0;
1728  else
1729  return 0;
1730  }
1731 
1732  return current ();
1733  }
1734 
1735  void printme (void) const;
1736 
1737  bool ok (void) const { return (nconv >= 0); }
1738 
1739  operator const void* (void) const { return ok () ? this : 0; }
1740 
1741  // What function name should be shown when reporting errors.
1743 
1744  // True if number of %f to be set from data file.
1746 
1747  // At least one conversion specifier is s,q,c, or [...].
1749 
1750  int read_first_row (delimited_stream& is, textscan& ts);
1751 
1752  std::list<octave_value> out_buf (void) const { return (output_container); }
1753 
1754  private:
1755 
1756  // Number of conversions specified by this format string, or -1 if
1757  // invalid conversions have been found.
1759 
1760  // Index to current element;
1761  size_t curr_idx;
1762 
1763  // List of format elements.
1764  std::deque<textscan_format_elt*> fmt_elts;
1765 
1766  // list holding column arrays of types specified by conversions
1767  std::list<octave_value> output_container;
1768 
1769  // Temporary buffer.
1770  std::ostringstream buf;
1771 
1772  void add_elt_to_list (unsigned int width, int prec, int bitwidth,
1773  octave_value val_type, bool discard,
1774  char type,
1775  const std::string& char_class = std::string ());
1776 
1777  void process_conversion (const std::string& s, size_t& i, size_t n);
1778 
1779  std::string parse_char_class (const std::string& pattern) const;
1780 
1781  int finish_conversion (const std::string& s, size_t& i, size_t n,
1782  unsigned int& width, int& prec, int& bitwidth,
1783  octave_value& val_type,
1784  bool discard, char& type);
1785  // No copying!
1786 
1788 
1789  textscan_format_list& operator = (const textscan_format_list&);
1790  };
1791 
1792  // Main class to implement textscan. Read data and parse it
1793  // according to a format.
1794  //
1795  // The calling sequence is
1796  //
1797  // textscan scanner ();
1798  // scanner.scan (...);
1799 
1800  class
1802  textscan
1803  {
1804  public:
1805 
1806  textscan (const std::string& who_arg = "textscan");
1807 
1808  ~textscan (void) { }
1809 
1810  octave_value scan (std::istream& isp, const std::string& fmt,
1811  octave_idx_type ntimes,
1812  const octave_value_list& options,
1813  octave_idx_type& read_count);
1814 
1815  private:
1816 
1817  friend class textscan_format_list;
1818 
1819  // What function name should be shown when reporting errors.
1821 
1823 
1824  // Three cases for delim_table and delim_list
1825  // 1. delim_table empty, delim_list empty: whitespace delimiters
1826  // 2. delim_table = look-up table of delim chars, delim_list empty.
1827  // 3. delim_table non-empty, delim_list = Cell array of delim strings
1828 
1830 
1831  // delim_table[i] == '\0' if i is not a delimiter.
1833 
1834  // String of delimiter characters.
1836 
1838 
1839  // How far ahead to look to detect an open comment.
1841 
1842  // First character of open comment.
1844 
1846 
1848 
1849  // 'inf' and 'nan' for formatted_double.
1851 
1852  // Array of strings of delimiters.
1854 
1855  // Longest delimiter.
1857 
1862 
1863  // Longest string to treat as "N/A".
1865 
1867 
1868  short eol1;
1869  short eol2;
1871 
1876 
1878 
1879  octave_value do_scan (std::istream& isp, textscan_format_list& fmt_list,
1880  octave_idx_type ntimes);
1881 
1882  void parse_options (const octave_value_list& args,
1883  textscan_format_list& fmt_list);
1884 
1885  int read_format_once (delimited_stream& isp, textscan_format_list& fmt_list,
1886  std::list<octave_value>& retval,
1887  Array<octave_idx_type> row, int& done_after);
1888 
1889  void scan_one (delimited_stream& is, const textscan_format_elt& fmt,
1891 
1892  // Methods to process a particular conversion specifier.
1893  double read_double (delimited_stream& is,
1894  const textscan_format_elt& fmt) const;
1895 
1896  void scan_complex (delimited_stream& is, const textscan_format_elt& fmt,
1897  Complex& val) const;
1898 
1899  int scan_bracket (delimited_stream& is, const std::string& pattern,
1900  std::string& val) const;
1901 
1902  int scan_caret (delimited_stream& is, const std::string& pattern,
1903  std::string& val) const;
1904 
1905  void scan_string (delimited_stream& is, const textscan_format_elt& fmt,
1906  std::string& val) const;
1907 
1908  void scan_cstring (delimited_stream& is, const textscan_format_elt& fmt,
1909  std::string& val) const;
1910 
1911  void scan_qstring (delimited_stream& is, const textscan_format_elt& fmt,
1912  std::string& val);
1913 
1914  // Helper methods.
1915  std::string read_until (delimited_stream& is, const Cell& delimiters,
1916  const std::string& ends) const;
1917 
1918  int lookahead (delimited_stream& is, const Cell& targets, int max_len,
1919  bool case_sensitive = true) const;
1920 
1921  bool match_literal (delimited_stream& isp, const textscan_format_elt& elem);
1922 
1923  int skip_whitespace (delimited_stream& is, bool EOLstop = false);
1924 
1925  int skip_delim (delimited_stream& is);
1926 
1927  bool is_delim (unsigned char ch) const
1928  {
1929  return ((delim_table.empty () && (isspace (ch) || ch == eol1 || ch == eol2))
1930  || delim_table[ch] != '\0');
1931  }
1932 
1933  bool isspace (unsigned int ch) const { return whitespace_table[ch & 0xff]; }
1934 
1935  // True if the only delimiter is whitespace.
1936  bool whitespace_delim (void) const { return delim_table.empty (); }
1937 
1938  // No copying!
1939 
1940  textscan (const textscan&);
1941 
1942  textscan& operator = (const textscan&);
1943  };
1944 
1946  const std::string& who_arg)
1947  : who (who_arg), set_from_first (false), has_string (false),
1948  nconv (0), curr_idx (0), fmt_elts (), buf ()
1949  {
1950  size_t n = s.length ();
1951 
1952  size_t i = 0;
1953 
1954  unsigned int width = -1; // Unspecified width = max (except %c)
1955  int prec = -1;
1956  int bitwidth = 0;
1957  bool discard = false;
1958  char type = '\0';
1959 
1960  bool have_more = true;
1961 
1962  if (s.empty ())
1963  {
1964  buf.clear ();
1965  buf.str ("");
1966 
1967  buf << "%f";
1968 
1969  bitwidth = 64;
1970  type = 'f';
1971  add_elt_to_list (width, prec, bitwidth, octave_value (NDArray ()),
1972  discard, type);
1973  have_more = false;
1974  set_from_first = true;
1975  nconv = 1;
1976  }
1977  else
1978  {
1979  set_from_first = false;
1980 
1981  while (i < n)
1982  {
1983  have_more = true;
1984 
1985  if (s[i] == '%' && (i+1 == n || s[i+1] != '%'))
1986  {
1987  // Process percent-escape conversion type.
1988 
1989  process_conversion (s, i, n);
1990 
1991  // If there is nothing in the buffer, then add_elt_to_list
1992  // must have just been called, so we are already done with
1993  // the current element and we don't need to call
1994  // add_elt_to_list if this is our last trip through the
1995  // loop.
1996 
1997  have_more = (buf.tellp () != 0);
1998  }
1999  else if (isspace (s[i]))
2000  {
2001  while (++i < n && isspace (s[i]))
2002  /* skip whitespace */;
2003 
2004  have_more = false;
2005  }
2006  else
2007  {
2009 
2010  width = 0;
2011  prec = -1;
2012  bitwidth = 0;
2013  discard = true;
2014 
2015  while (i < n && ! isspace (s[i])
2016  && (s[i] != '%' || (i+1 < n && s[i+1] == '%')))
2017  {
2018  if (s[i] == '%') // if double %, skip one
2019  i++;
2020  buf << s[i++];
2021  width++;
2022  }
2023 
2024  add_elt_to_list (width, prec, bitwidth, octave_value (),
2025  discard, type);
2026 
2027  have_more = false;
2028  }
2029 
2030  if (nconv < 0)
2031  {
2032  have_more = false;
2033  break;
2034  }
2035  }
2036  }
2037 
2038  if (have_more)
2039  add_elt_to_list (width, prec, bitwidth, octave_value (), discard, type);
2040 
2041  buf.clear ();
2042  buf.str ("");
2043  }
2044 
2046  {
2047  size_t n = numel ();
2048 
2049  for (size_t i = 0; i < n; i++)
2050  {
2051  textscan_format_elt *elt = fmt_elts[i];
2052  delete elt;
2053  }
2054  }
2055 
2056  void
2057  textscan_format_list::add_elt_to_list (unsigned int width, int prec,
2058  int bitwidth, octave_value val_type,
2059  bool discard, char type,
2060  const std::string& char_class)
2061  {
2062  std::string text = buf.str ();
2063 
2064  if (! text.empty ())
2065  {
2066  textscan_format_elt *elt
2067  = new textscan_format_elt (text, width, prec, bitwidth, discard, type,
2068  char_class);
2069 
2070  if (! discard)
2071  output_container.push_back (val_type);
2072 
2073  fmt_elts.push_back (elt);
2074  }
2075 
2076  buf.clear ();
2077  buf.str ("");
2078  }
2079 
2080  void
2082  size_t n)
2083  {
2084  unsigned width = 0;
2085  int prec = -1;
2086  int bitwidth = 0;
2087  bool discard = false;
2088  octave_value val_type;
2089  char type = '\0';
2090 
2091  buf << s[i++];
2092 
2093  bool have_width = false;
2094 
2095  while (i < n)
2096  {
2097  switch (s[i])
2098  {
2099  case '*':
2100  if (discard)
2101  nconv = -1;
2102  else
2103  {
2104  discard = true;
2105  buf << s[i++];
2106  }
2107  break;
2108 
2109  case '0': case '1': case '2': case '3': case '4':
2110  case '5': case '6': case '7': case '8': case '9':
2111  if (have_width)
2112  nconv = -1;
2113  else
2114  {
2115  char c = s[i++];
2116  width = width * 10 + c - '0';
2117  have_width = true;
2118  buf << c;
2119  while (i < n && isdigit (s[i]))
2120  {
2121  c = s[i++];
2122  width = width * 10 + c - '0';
2123  buf << c;
2124  }
2125 
2126  if (i < n && s[i] == '.')
2127  {
2128  buf << s[i++];
2129  prec = 0;
2130  while (i < n && isdigit (s[i]))
2131  {
2132  c = s[i++];
2133  prec = prec * 10 + c - '0';
2134  buf << c;
2135  }
2136  }
2137  }
2138  break;
2139 
2140  case 'd': case 'u':
2141  {
2142  bool done = true;
2143  buf << (type = s[i++]);
2144  if (i < n)
2145  {
2146  if (s[i] == '8')
2147  {
2148  bitwidth = 8;
2149  if (type == 'd')
2150  val_type = octave_value (int8NDArray ());
2151  else
2152  val_type = octave_value (uint8NDArray ());
2153  buf << s[i++];
2154  }
2155  else if (s[i] == '1' && i+1 < n && s[i+1] == '6')
2156  {
2157  bitwidth = 16;
2158  if (type == 'd')
2159  val_type = octave_value (int16NDArray ());
2160  else
2161  val_type = octave_value (uint16NDArray ());
2162  buf << s[i++];
2163  buf << s[i++];
2164  }
2165  else if (s[i] == '3' && i+1 < n && s[i+1] == '2')
2166  {
2167  done = false; // use default size below
2168  buf << s[i++];
2169  buf << s[i++];
2170  }
2171  else if (s[i] == '6' && i+1 < n && s[i+1] == '4')
2172  {
2173  bitwidth = 64;
2174  if (type == 'd')
2175  val_type = octave_value (int64NDArray ());
2176  else
2177  val_type = octave_value (uint64NDArray ());
2178  buf << s[i++];
2179  buf << s[i++];
2180  }
2181  else
2182  done = false;
2183  }
2184  else
2185  done = false;
2186 
2187  if (! done)
2188  {
2189  bitwidth = 32;
2190  if (type == 'd')
2191  val_type = octave_value (int32NDArray ());
2192  else
2193  val_type = octave_value (uint32NDArray ());
2194  }
2195  goto fini;
2196  }
2197 
2198  case 'f':
2199  buf << (type = s[i++]);
2200  bitwidth = 64;
2201  if (i < n)
2202  {
2203  if (s[i] == '3' && i+1 < n && s[i+1] == '2')
2204  {
2205  bitwidth = 32;
2206  val_type = octave_value (FloatNDArray ());
2207  buf << s[i++];
2208  buf << s[i++];
2209  }
2210  else if (s[i] == '6' && i+1 < n && s[i+1] == '4')
2211  {
2212  val_type = octave_value (NDArray ());
2213  buf << s[i++];
2214  buf << s[i++];
2215  }
2216  else
2217  val_type = octave_value (NDArray ());
2218  }
2219  else
2220  val_type = octave_value (NDArray ());
2221  goto fini;
2222 
2223  case 'n':
2224  buf << (type = s[i++]);
2225  bitwidth = 64;
2226  val_type = octave_value (NDArray ());
2227  goto fini;
2228 
2229  case 's': case 'q': case '[': case 'c':
2230  if (! discard)
2231  val_type = octave_value (Cell ());
2232  buf << (type = s[i++]);
2233  has_string = true;
2234  goto fini;
2235 
2236  fini:
2237  {
2238  if (! have_width)
2239  {
2240  if (type == 'c') // %c defaults to one character
2241  width = 1;
2242  else
2243  width = static_cast<unsigned int> (-1); // others: unlimited
2244  }
2245 
2246  if (finish_conversion (s, i, n, width, prec, bitwidth, val_type,
2247  discard, type) == 0)
2248  return;
2249  }
2250  break;
2251 
2252  default:
2253  error ("%s: '%%%c' is not a valid format specifier",
2254  who.c_str (), s[i]);
2255  }
2256 
2257  if (nconv < 0)
2258  break;
2259  }
2260 
2261  nconv = -1;
2262  }
2263 
2264  // Parse [...] and [^...]
2265  //
2266  // Matlab does not expand expressions like A-Z, but they are useful, and
2267  // so we parse them "carefully". We treat '-' as a usual character
2268  // unless both start and end characters are from the same class (upper
2269  // case, lower case, numeric), or this is not the first '-' in the
2270  // pattern.
2271  //
2272  // Keep both a running list of characters and a mask of which chars have
2273  // occurred. The first is efficient for patterns with few characters.
2274  // The latter is efficient for [^...] patterns.
2275 
2276  std::string
2278  {
2279  int len = pattern.length ();
2280  if (len == 0)
2281  return "";
2282 
2283  std::string retval (256, '\0');
2284  std::string mask (256, '\0'); // number of times chr has been seen
2285 
2286  int in = 0, out = 0;
2287  unsigned char ch, prev = 0;
2288  bool flip = false;
2289 
2290  ch = pattern[in];
2291  if (ch == '^')
2292  {
2293  in++;
2294  flip = true;
2295  }
2296  mask[pattern[in]] = '\1';
2297  retval[out++] = pattern[in++]; // even copy ']' if it is first
2298 
2299  bool prev_was_range = false; // disallow "a-m-z" as a pattern
2300  bool prev_prev_was_range = false;
2301  for (; in < len; in++)
2302  {
2303  bool was_range = false;
2304  ch = pattern[in];
2305  if (ch == ']')
2306  break;
2307 
2308  if (prev == '-' && in > 1 && isalnum (ch) && ! prev_prev_was_range)
2309  {
2310  unsigned char start_of_range = pattern[in-2];
2311  if (start_of_range < ch
2312  && ((isupper (ch) && isupper (start_of_range))
2313  || (islower (ch) && islower (start_of_range))
2314  || (isdigit (ch) && isdigit (start_of_range))
2315  || mask['-'] > 1)) // not the first '-'
2316  {
2317  was_range = true;
2318  out--;
2319  mask['-']--;
2320  for (int i = start_of_range; i <= ch; i++)
2321  {
2322  if (mask[i] == '\0')
2323  {
2324  mask[i] = '\1';
2325  retval[out++] = i;
2326  }
2327  }
2328  }
2329  }
2330  if (! was_range)
2331  {
2332  if (mask[ch]++ == 0)
2333  retval[out++] = ch;
2334  else if (ch != '-')
2335  warning_with_id ("octave:textscan-pattern",
2336  "%s: [...] contains two '%c's",
2337  who.c_str (), ch);
2338 
2339  if (prev == '-' && mask['-'] >= 2)
2341  ("octave:textscan-pattern",
2342  "%s: [...] contains two '-'s outside range expressions",
2343  who.c_str ());
2344  }
2345  prev = ch;
2346  prev_prev_was_range = prev_was_range;
2347  prev_was_range = was_range;
2348  }
2349 
2350  if (flip) // [^...]
2351  {
2352  out = 0;
2353  for (int i = 0; i < 256; i++)
2354  if (! mask[i])
2355  retval[out++] = i;
2356  }
2357 
2358  retval.resize (out);
2359 
2360  return retval;
2361  }
2362 
2363  int
2365  size_t n, unsigned int& width,
2366  int& prec, int& bitwidth,
2367  octave_value& val_type, bool discard,
2368  char& type)
2369  {
2370  int retval = 0;
2371 
2372  std::string char_class;
2373 
2374  size_t beg_idx = std::string::npos;
2375  size_t end_idx = std::string::npos;
2376 
2377  if (type != '%')
2378  {
2379  nconv++;
2380  if (type == '[')
2381  {
2382  if (i < n)
2383  {
2384  beg_idx = i;
2385 
2386  if (s[i] == '^')
2387  {
2388  type = '^';
2389  buf << s[i++];
2390 
2391  if (i < n)
2392  {
2393  beg_idx = i;
2394 
2395  if (s[i] == ']')
2396  buf << s[i++];
2397  }
2398  }
2399  else if (s[i] == ']')
2400  buf << s[i++];
2401  }
2402 
2403  while (i < n && s[i] != ']')
2404  buf << s[i++];
2405 
2406  if (i < n && s[i] == ']')
2407  {
2408  end_idx = i-1;
2409  buf << s[i++];
2410  }
2411 
2412  if (s[i-1] != ']')
2413  retval = nconv = -1;
2414  }
2415  }
2416 
2417  if (nconv >= 0)
2418  {
2419  if (beg_idx != std::string::npos && end_idx != std::string::npos)
2420  char_class = parse_char_class (s.substr (beg_idx,
2421  end_idx - beg_idx + 1));
2422 
2423  add_elt_to_list (width, prec, bitwidth, val_type, discard, type,
2424  char_class);
2425  }
2426 
2427  return retval;
2428  }
2429 
2430  void
2432  {
2433  size_t n = numel ();
2434 
2435  for (size_t i = 0; i < n; i++)
2436  {
2437  textscan_format_elt *elt = fmt_elts[i];
2438 
2439  std::cerr
2440  << "width: " << elt->width << "\n"
2441  << "digits " << elt->prec << "\n"
2442  << "bitwidth: " << elt->bitwidth << "\n"
2443  << "discard: " << elt->discard << "\n"
2444  << "type: ";
2445 
2447  std::cerr << "literal text\n";
2449  std::cerr << "whitespace\n";
2450  else
2451  std::cerr << elt->type << "\n";
2452 
2453  std::cerr
2454  << "char_class: `" << undo_string_escapes (elt->char_class) << "'\n"
2455  << "text: `" << undo_string_escapes (elt->text) << "'\n\n";
2456  }
2457  }
2458 
2459  // If FORMAT is explicitly "", it is assumed to be "%f" repeated enough
2460  // times to read the first row of the file. Set it now.
2461 
2462  int
2464  {
2465  // Read first line and strip end-of-line, which may be two characters
2466  std::string first_line (20, ' ');
2467 
2468  is.getline (first_line, static_cast<char> (ts.eol2));
2469 
2470  if (! first_line.empty ()
2471  && first_line[first_line.length () - 1] == ts.eol1)
2472  first_line.resize (first_line.length () - 1);
2473 
2474  std::istringstream strstr (first_line);
2475  delimited_stream ds (strstr, is);
2476 
2477  dim_vector dv (1,1); // initial size of each output_container
2478  Complex val;
2479  octave_value val_type;
2480  nconv = 0;
2481  int max_empty = 1000; // failsafe, if ds fails but not with eof
2482  int retval = 0;
2483 
2484  // read line, creating output_container as we go
2485  while (! ds.eof ())
2486  {
2487  bool already_skipped_delim = false;
2488  ts.skip_whitespace (ds);
2489  ds.progress_benchmark ();
2490  bool progress = false;
2491  ts.scan_complex (ds, *fmt_elts[0], val);
2492  if (ds.fail ())
2493  {
2494  ds.clear (ds.rdstate () & ~std::ios::failbit);
2495 
2496  if (ds.eof ())
2497  break;
2498 
2499  // Unless this was a missing value (i.e., followed by a delimiter),
2500  // return with an error status.
2501  ts.skip_delim (ds);
2502  if (ds.no_progress ())
2503  {
2504  retval = 4;
2505  break;
2506  }
2507  already_skipped_delim = true;
2508 
2509  val = ts.empty_value.scalar_value ();
2510 
2511  if (! --max_empty)
2512  break;
2513  }
2514 
2515  if (val.imag () == 0)
2516  val_type = octave_value (NDArray (dv, val.real ()));
2517  else
2518  val_type = octave_value (ComplexNDArray (dv, val));
2519 
2520  output_container.push_back (val_type);
2521 
2522  if (! already_skipped_delim)
2523  ts.skip_delim (ds);
2524 
2525  if (! progress && ds.no_progress ())
2526  break;
2527 
2528  nconv++;
2529  }
2530 
2531  output_container.pop_front (); // discard empty element from constructor
2532 
2533  // Create fmt_list now that the size is known
2534  for (octave_idx_type i = 1; i < nconv; i++)
2535  fmt_elts.push_back (new textscan_format_elt (*fmt_elts[0]));
2536 
2537  return retval; // May have returned 4 above.
2538  }
2539 
2541  : who (who_arg), buf (), whitespace_table (), delim_table (),
2542  delims (), comment_style (), comment_len (0), comment_char (-2),
2543  buffer_size (0), date_locale (), inf_nan (init_inf_nan ()),
2544  empty_value (octave::numeric_limits<double>::NaN ()), exp_chars ("edED"),
2545  header_lines (0), treat_as_empty (), treat_as_empty_len (0),
2546  whitespace (" \b\t"), eol1 ('\r'), eol2 ('\n'),
2547  return_on_error (1), collect_output (false),
2548  multiple_delims_as_one (false), default_exp (true),
2549  numeric_delim (false), lines (0)
2550  { }
2551 
2552  octave_value
2553  textscan::scan (std::istream& isp, const std::string& fmt,
2554  octave_idx_type ntimes, const octave_value_list& options,
2555  octave_idx_type& count)
2556  {
2557  textscan_format_list fmt_list (fmt);
2558 
2559  parse_options (options, fmt_list);
2560 
2561  octave_value result = do_scan (isp, fmt_list, ntimes);
2562 
2563  // FIXME: this is probably not the best way to get count. The
2564  // position could easily be larger than octave_idx_type when using
2565  // 32-bit indexing.
2566 
2567  std::ios::iostate state = isp.rdstate ();
2568  isp.clear ();
2569  count = static_cast<octave_idx_type> (isp.tellg ());
2570  isp.setstate (state);
2571 
2572  return result;
2573  }
2574 
2575  octave_value
2576  textscan::do_scan (std::istream& isp, textscan_format_list& fmt_list,
2577  octave_idx_type ntimes)
2578  {
2580 
2581  if (fmt_list.num_conversions () == -1)
2582  error ("%s: invalid format specified", who.c_str ());
2583 
2584  if (fmt_list.num_conversions () == 0)
2585  error ("%s: no valid format conversion specifiers", who.c_str ());
2586 
2587  // skip the first header_lines
2588  std::string dummy;
2589  for (int i = 0; i < header_lines && isp; i++)
2590  getline (isp, dummy, static_cast<char> (eol2));
2591 
2592  // Create our own buffered stream, for fast get/putback/tell/seek.
2593 
2594  // First, see how far ahead it should let us look.
2595  int max_lookahead = std::max (std::max (comment_len, treat_as_empty_len),
2596  std::max (delim_len, 3)); // 3 for NaN and Inf
2597 
2598  // Next, choose a buffer size to avoid reading too much, or too often.
2599  octave_idx_type buf_size = 4096;
2600  if (buffer_size)
2601  buf_size = buffer_size;
2602  else if (ntimes > 0)
2603  {
2604  // Avoid overflow of 80*ntimes...
2605  buf_size = std::min (buf_size, std::max (ntimes, 80 * ntimes));
2606  buf_size = std::max (buf_size, ntimes);
2607  }
2608  // Finally, create the stream.
2609  delimited_stream is (isp,
2610  (delim_table.empty () ? whitespace + "\r\n" : delims),
2611  max_lookahead, buf_size);
2612 
2613  // Grow retval dynamically. "size" is half the initial size
2614  // (FIXME: Should we start smaller if ntimes is large?)
2615  octave_idx_type size = ((ntimes < 8 && ntimes >= 0) ? ntimes : 1);
2616  Array<octave_idx_type> row_idx (dim_vector (1,2));
2617  row_idx(1) = 0;
2618 
2619  int err = 0;
2620  octave_idx_type row = 0;
2621 
2622  if (multiple_delims_as_one) // bug #44750?
2623  skip_delim (is);
2624 
2625  int done_after; // Number of columns read when EOF seen.
2626 
2627  // If FORMAT explicitly "", read first line and see how many "%f" match
2628  if (fmt_list.set_from_first)
2629  {
2630  err = fmt_list.read_first_row (is, *this);
2631  lines = 1;
2632 
2633  done_after = fmt_list.numel () + 1;
2634  if (! err)
2635  row = 1; // the above puts the first line into fmt_list.out_buf ()
2636  }
2637  else
2638  done_after = fmt_list.out_buf ().size () + 1;
2639 
2640  std::list<octave_value> out = fmt_list.out_buf ();
2641 
2642  // We will later merge adjacent columns of the same type.
2643  // Check now which columns to merge.
2644  // Reals may become complex, and so we can't trust types
2645  // after reading in data.
2646  // If the format was "", that conversion may already have happened,
2647  // so force all to be merged (as all are %f).
2648  bool merge_with_prev[fmt_list.numel ()];
2649  int conv = 0;
2650  if (collect_output)
2651  {
2652  int prev_type = -1;
2653  for (std::list<octave_value>::iterator col = out.begin ();
2654  col != out.end (); col++)
2655  {
2656  if (col->type_id () == prev_type
2657  || (fmt_list.set_from_first && prev_type != -1))
2658  merge_with_prev [conv++] = true;
2659  else
2660  merge_with_prev [conv++] = false;
2661 
2662  prev_type = col->type_id ();
2663  }
2664  }
2665 
2666  // This should be caught by earlier code, but this avoids a possible
2667  // infinite loop below.
2668  if (fmt_list.num_conversions () == 0)
2669  error ("%s: No conversions specified", who.c_str ());
2670 
2671  // Read the data. This is the main loop.
2672  if (! err)
2673  {
2674  for (/* row set ~30 lines above */; row < ntimes || ntimes == -1; row++)
2675  {
2676  if (row == 0 || row >= size)
2677  {
2678  size += size+1;
2679  for (std::list<octave_value>::iterator col = out.begin ();
2680  col != out.end (); col++)
2681  *col = (*col).resize (dim_vector (size, 1), 0);
2682  }
2683 
2684  row_idx(0) = row;
2685  err = read_format_once (is, fmt_list, out, row_idx, done_after);
2686 
2687  if ((err & ~1) > 0 || ! is || (lines >= ntimes && ntimes > -1))
2688  break;
2689  }
2690  }
2691 
2692  if ((err & 4) && ! return_on_error)
2693  error ("%s: Read error in field %d of row %d", who.c_str (),
2694  done_after + 1, row + 1);
2695 
2696  // If file does not end in EOL, do not pad columns with NaN.
2697  bool uneven_columns = false;
2698  if (err & 4)
2699  uneven_columns = true;
2700  else if (isp.eof ())
2701  {
2702  isp.clear ();
2703  isp.seekg (-1, std::ios_base::end);
2704  int last_char = isp.get ();
2705  isp.setstate (isp.eofbit);
2706  uneven_columns = (last_char != eol1 && last_char != eol2);
2707  }
2708 
2709  // convert return value to Cell array
2711 
2712  // (err & 1) means "error, and no columns read this row
2713  // FIXME: This may redundant now that done_after=0 says the same
2714  if (err & 1)
2715  done_after = out.size () + 1;
2716 
2717  int valid_rows = (row == ntimes) ? ntimes
2718  : (((err & 1) && (err & 8)) ? row : row+1);
2719  dim_vector dv (valid_rows, 1);
2720 
2721  ra_idx(0) = 0;
2722  int i = 0;
2723  if (! collect_output)
2724  {
2725  retval = Cell (dim_vector (1, out.size ()));
2726  for (std::list<octave_value>::iterator col = out.begin ();
2727  col != out.end (); col++, i++)
2728  {
2729  // trim last columns if that was requested
2730  if (i == done_after && uneven_columns)
2731  dv = dim_vector (std::max (valid_rows - 1, 0), 1);
2732 
2733  ra_idx(1) = i;
2734  retval = do_cat_op (retval, octave_value (Cell (col->resize (dv,0))),
2735  ra_idx);
2736  }
2737  }
2738  else // group adjacent cells of the same type into a single cell
2739  {
2740  octave_value cur; // current cell, accumulating columns
2741  octave_idx_type group_size = 0; // columns in this cell
2742  int prev_type = -1;
2743 
2744  conv = 0;
2745  retval = Cell ();
2746  for (std::list<octave_value>::iterator col = out.begin ();
2747  col != out.end (); col++)
2748  {
2749  if (! merge_with_prev [conv++]) // including first time
2750  {
2751  if (prev_type != -1)
2752  {
2753  ra_idx(1) = i++;
2754  retval = do_cat_op (retval, octave_value (Cell (cur)),
2755  ra_idx);
2756  }
2757  cur = octave_value (col->resize (dv,0));
2758  group_size = 1;
2759  prev_type = col->type_id ();
2760  }
2761  else
2762  {
2763  ra_idx(1) = group_size++;
2764  cur = do_cat_op (cur, octave_value (col->resize (dv,0)),
2765  ra_idx);
2766  }
2767  }
2768  ra_idx(1) = i;
2769  retval = do_cat_op (retval, octave_value (Cell (cur)), ra_idx);
2770  }
2771 
2772  return retval;
2773  }
2774 
2775  // Read a double considering the "precision" field of FMT and the
2776  // EXP_CHARS option of OPTIONS.
2777 
2778  double
2780  const textscan_format_elt& fmt) const
2781  {
2782  int sign = 1;
2783  unsigned int width_left = fmt.width;
2784  double retval = 0;
2785  bool valid = false; // syntactically correct double?
2786 
2787  int ch = is.peek ();
2788 
2789  if (ch == '+')
2790  {
2791  is.get ();
2792  ch = is.peek ();
2793  if (width_left)
2794  width_left--;
2795  }
2796  else if (ch == '-')
2797  {
2798  sign = -1;
2799  is.get ();
2800  ch = is.peek ();
2801  if (width_left)
2802  width_left--;
2803  }
2804 
2805  // Read integer part
2806  if (ch != '.')
2807  {
2808  if (ch >= '0' && ch <= '9') // valid if at least one digit
2809  valid = true;
2810  while (width_left-- && is && (ch = is.get ()) >= '0' && ch <= '9')
2811  retval = retval * 10 + (ch - '0');
2812  width_left++;
2813  }
2814 
2815  // Read fractional part, up to specified precision
2816  if (ch == '.' && width_left)
2817  {
2818  double multiplier = 1;
2819  int precision = fmt.prec;
2820  int i;
2821 
2822  if (width_left)
2823  width_left--; // Consider width of '.'
2824 
2825  if (precision == -1)
2826  precision = 1<<30; // FIXME: Should be MAXINT
2827 
2828  if (! valid) // if there was nothing before '.'...
2829  is.get (); // ...ch was a "peek", not "get".
2830 
2831  for (i = 0; i < precision; i++)
2832  {
2833  if (width_left-- && is && (ch = is.get ()) >= '0' && ch <= '9')
2834  retval += (ch - '0') * (multiplier *= 0.1);
2835  else
2836  {
2837  width_left++;
2838  break;
2839  }
2840  }
2841 
2842  // round up if we truncated and the next digit is >= 5
2843  if ((i == precision || ! width_left) && (ch = is.get ()) >= '5'
2844  && ch <= '9')
2845  retval += multiplier;
2846 
2847  if (i > 0)
2848  valid = true; // valid if at least one digit after '.'
2849 
2850  // skip remainder after '.', to field width, to look for exponent
2851  if (i == precision)
2852  while (width_left-- && is && (ch = is.get ()) >= '0' && ch <= '9')
2853  ; // discard
2854 
2855  width_left++;
2856  }
2857 
2858  // look for exponent part in, e.g., 6.023E+23
2859  bool used_exp = false;
2860  if (valid && width_left > 1 && exp_chars.find (ch) != std::string::npos)
2861  {
2862  int ch1 = is.peek ();
2863  if (ch1 == '-' || ch1 == '+' || (ch1 >= '0' && ch1 <= '9'))
2864  {
2865  // if 1.0e+$ or some such, this will set failbit, as we want
2866  width_left--; // count "E"
2867  int exp = 0;
2868  int exp_sign = 1;
2869  if (ch1 == '+')
2870  {
2871  if (width_left)
2872  width_left--;
2873  is.get ();
2874  }
2875  else if (ch1 == '-')
2876  {
2877  exp_sign = -1;
2878  is.get ();
2879  if (width_left)
2880  width_left--;
2881  }
2882  valid = false;
2883  while (width_left-- && is && (ch = is.get ()) >= '0' && ch <= '9')
2884  {
2885  exp = exp*10 + ch - '0';
2886  valid = true;
2887  }
2888  width_left++;
2889  if (ch != std::istream::traits_type::eof () && width_left)
2890  is.putback (ch);
2891 
2892  double multiplier = pown (10, exp);
2893  if (exp_sign > 0)
2894  retval *= multiplier;
2895  else
2896  retval /= multiplier;
2897 
2898  used_exp = true;
2899  }
2900  }
2901  is.clear ();
2902  if (! used_exp && ch != std::istream::traits_type::eof () && width_left)
2903  is.putback (ch);
2904 
2905  // Check for +/- inf and NaN
2906  if (! valid && width_left >= 3)
2907  {
2908  int i = lookahead (is, inf_nan, 3, false); // false -> case insensitive
2909  if (i == 0)
2910  {
2912  valid = true;
2913  }
2914  else if (i == 1)
2915  {
2917  valid = true;
2918  }
2919  }
2920 
2921  // Check for +/- inf and NaN
2922  if (! valid && width_left >= 3)
2923  {
2924  int i = lookahead (is, inf_nan, 3, false); // false -> case insensitive
2925  if (i == 0)
2926  {
2928  valid = true;
2929  }
2930  else if (i == 1)
2931  {
2933  valid = true;
2934  }
2935  }
2936 
2937  if (! valid)
2938  is.setstate (std::ios::failbit);
2939  else
2940  is.setstate (is.rdstate () & ~std::ios::failbit);
2941 
2942  return retval * sign;
2943  }
2944 
2945  // Read a single number: real, complex, inf, NaN, possibly with limited
2946  // precision. Calls to this should be preceded by skip_whitespace.
2947  // Calling that inside scan_complex would violate its const declaration.
2948 
2949  void
2951  Complex& val) const
2952  {
2953  double im = 0;
2954  double re = 0;
2955  bool as_empty = false; // did we fail but match a "treat_as_empty" string?
2956  bool inf = false;
2957 
2958  int ch = is.peek ();
2959  if (ch == '+' || ch == '-') // check for [+-][ij] with no coefficients
2960  {
2961  ch = is.get ();
2962  int ch2 = is.peek ();
2963  if (ch2 == 'i' || ch2 == 'j')
2964  {
2965  double value = 1;
2966  is.get ();
2967  // Check not -inf
2968  if (is.peek () == 'n')
2969  {
2970  char *pos = is.tellg ();
2971  std::ios::iostate state = is.rdstate ();
2972 
2973  is.get ();
2974  ch2 = is.get ();
2975  if (ch2 == 'f')
2976  {
2977  inf = true;
2978  re = (ch == '+') ? octave::numeric_limits<double>::Inf ()
2980  value = 0;
2981  }
2982  else
2983  {
2984  is.clear (state);
2985  is.seekg (pos); // reset to position before look-ahead
2986  }
2987  }
2988 
2989  im = (ch == '+') ? value : -value;
2990  }
2991  else
2992  is.putback (ch);
2993  }
2994 
2995  if (! im && ! inf) // if not [+-][ij] or [+-]inf, read real normally
2996  {
2997  char *pos = is.tellg ();
2998  std::ios::iostate state = is.rdstate ();
2999  //re = octave_read_value<double> (is);
3000  re = read_double (is, fmt);
3001 
3002  // check for "treat as empty" string
3003  if (treat_as_empty.numel ()
3004  && (is.fail () || octave::math::is_NaN_or_NA (Complex (re))
3006  {
3007 
3008  for (int i = 0; i < treat_as_empty.numel (); i++)
3009  {
3010  if (ch == treat_as_empty (i).string_value ()[0])
3011  {
3012  as_empty = true; // first char matches, so read the lot
3013  break;
3014  }
3015  }
3016  if (as_empty) // if first char matched...
3017  {
3018  as_empty = false; // ...look for the whole string
3019 
3020  is.clear (state); // treat_as_empty "-" causes partial read
3021  is.seekg (pos); // reset to position before failed read
3022 
3023  // treat_as_empty strings may be different sizes.
3024  // Read ahead longest, put it all back, then re-read the string
3025  // that matches.
3026  std::string look_buf (treat_as_empty_len, '\0');
3027  char *look = is.read (&look_buf[0], look_buf.size (), pos);
3028 
3029  is.clear (state);
3030  is.seekg (pos); // reset to position before look-ahead
3031  // FIXME: is.read could invalidate pos
3032 
3033  for (int i = 0; i < treat_as_empty.numel (); i++)
3034  {
3035  std::string s = treat_as_empty (i).string_value ();
3036  if (! strncmp (s.c_str (), look, s.size ()))
3037  {
3038  as_empty = true;
3039  // read just the right amount
3040  is.read (&look_buf[0], s.size (), pos);
3041  break;
3042  }
3043  }
3044  }
3045  }
3046 
3047  if (! is.eof () && ! as_empty)
3048  {
3049  state = is.rdstate (); // before tellg, since that fails at EOF
3050  pos = is.tellg ();
3051  ch = is.peek (); // ch == EOF if read failed; no need to chk fail
3052  if (ch == 'i' || ch == 'j') // pure imaginary
3053  {
3054  is.get ();
3055  im = re;
3056  re = 0;
3057  }
3058  else if (ch == '+' || ch == '-') // see if it is real+imag[ij]
3059  {
3060  // save stream state in case we have to restore it
3061  pos = is.tellg ();
3062  state = is.rdstate ();
3063 
3064  //im = octave_read_value<double> (is);
3065  im = read_double (is, fmt);
3066  if (is.fail ())
3067  im = 1;
3068 
3069  if (is.peek () == 'i' || is.peek () == 'j')
3070  is.get ();
3071  else
3072  {
3073  im = 0; // no valid imaginary part. Restore state
3074  is.clear (state); // eof shouldn't cause fail.
3075  is.seekg (pos);
3076  }
3077  }
3078  else if (is.eof ()) // we've read enough to be a "valid" read
3079  is.clear (state); // failed peek shouldn't cause fail
3080  }
3081  }
3082  if (as_empty)
3083  val = empty_value.scalar_value ();
3084  else
3085  val = Complex (re, im);
3086  }
3087 
3088  // Return in VAL the run of characters from IS NOT contained in PATTERN.
3089 
3090  int
3092  std::string& val) const
3093  {
3094  int c1 = std::istream::traits_type::eof ();
3095  std::ostringstream obuf; // Is this optimized for growing?
3096 
3097  while (is && ((c1 = (is && ! is.eof ())
3098  ? is.get_undelim ()
3099  : std::istream::traits_type::eof ())
3100  != std::istream::traits_type::eof ())
3101  && pattern.find (c1) == std::string::npos)
3102  obuf << static_cast<char> (c1);
3103 
3104  val = obuf.str ();
3105 
3106  if (c1 != std::istream::traits_type::eof ())
3107  is.putback (c1);
3108 
3109  return c1;
3110  }
3111 
3112  // Read until one of the strings in DELIMITERS is found. For
3113  // efficiency, ENDS is a list of the last character of each delimiter.
3114 
3115  std::string
3116  textscan::read_until (delimited_stream& is, const Cell& delimiters,
3117  const std::string& ends) const
3118  {
3119  std::string retval ("");
3120  bool done = false;
3121  do
3122  {
3123  // find sequence ending with an ending char
3124  std::string next;
3125  scan_caret (is, ends.c_str (), next);
3126  retval = retval + next; // FIXME: could use repeated doubling of size
3127 
3128  int last = (! is.eof ()
3129  ? is.get_undelim () : std::istream::traits_type::eof ());
3130 
3131  if (last != std::istream::traits_type::eof ())
3132  {
3133  retval = retval + static_cast<char> (last);
3134  for (int i = 0; i < delimiters.numel (); i++)
3135  {
3136  std::string delim = delimiters(i).string_value ();
3137  size_t start = (retval.length () > delim.length ()
3138  ? retval.length () - delim.length ()
3139  : 0);
3140  std::string may_match = retval.substr (start);
3141  if (may_match == delim)
3142  {
3143  done = true;
3144  retval = retval.substr (0, start);
3145  break;
3146  }
3147  }
3148  }
3149  }
3150  while (! done && is && ! is.eof ());
3151 
3152  return retval;
3153  }
3154 
3155  // Read stream until either fmt.width chars have been read, or
3156  // options.delimiter has been found. Does *not* rely on fmt being 's'.
3157  // Used by formats like %6f to limit to 6.
3158 
3159  void
3161  std::string& val) const
3162  {
3163  if (delim_list.is_empty ())
3164  {
3165  unsigned int i = 0;
3166  unsigned int width = fmt.width;
3167 
3168  for (i = 0; i < width; i++)
3169  {
3170  if (i+1 > val.length ())
3171  val = val + val + ' '; // grow even if empty
3172  int ch = is.get ();
3173  if (is_delim (ch) || ch == std::istream::traits_type::eof ())
3174  {
3175  is.putback (ch);
3176  break;
3177  }
3178  else
3179  val[i] = ch;
3180  }
3181  val = val.substr (0, i); // trim pre-allocation
3182  }
3183  else // Cell array of multi-character delimiters
3184  {
3185  std::string ends ("");
3186  for (int i = 0; i < delim_list.numel (); i++)
3187  {
3188  std::string tmp = delim_list(i).string_value ();
3189  ends += tmp.substr (tmp.length () - 1);
3190  }
3191  val = textscan::read_until (is, delim_list, ends);
3192  }
3193  }
3194 
3195  // Return in VAL the run of characters from IS contained in PATTERN.
3196 
3197  int
3199  std::string& val) const
3200  {
3201  int c1 = std::istream::traits_type::eof ();
3202  std::ostringstream obuf; // Is this optimized for growing?
3203 
3204  while (is && pattern.find (c1 = is.get_undelim ()) != std::string::npos)
3205  obuf << static_cast<char> (c1);
3206 
3207  val = obuf.str ();
3208  if (c1 != std::istream::traits_type::eof ())
3209  is.putback (c1);
3210  return c1;
3211  }
3212 
3213  // Return in VAL a string, either delimited by whitespace/delimiters, or
3214  // enclosed in a pair of double quotes ("..."). Enclosing quotes are
3215  // removed. A consecutive pair "" is inserted into VAL as a single ".
3216 
3217  void
3219  std::string& val)
3220  {
3221  skip_whitespace (is);
3222 
3223  if (is.peek () != '\"')
3224  scan_string (is, fmt, val);
3225  else
3226  {
3227  is.get ();
3228  scan_caret (is, "\"", val); // read everything until "
3229  is.get (); // swallow "
3230 
3231  while (is && is.peek () == '\"') // if double ", insert one in stream,
3232  { // and keep looking for single "
3233  is.get ();
3234  std::string val1;
3235  scan_caret (is, "\"", val1);
3236  val = val + "\"" + val1;
3237  is.get_undelim ();
3238  }
3239  }
3240  }
3241 
3242  // Read from IS into VAL a string of the next fmt.width characters,
3243  // including any whitespace or delimiters.
3244 
3245  void
3247  std::string& val) const
3248  {
3249  val.resize (fmt.width);
3250 
3251  for (unsigned int i = 0; is && i < fmt.width; i++)
3252  {
3253  int ch = is.get_undelim ();
3254  if (ch != std::istream::traits_type::eof ())
3255  val[i] = ch;
3256  else
3257  {
3258  val.resize (i);
3259  break;
3260  }
3261  }
3262  }
3263 
3264  // Read a single '%...' conversion and place it in position ROW of OV.
3265 
3266  void
3269  {
3270  skip_whitespace (is);
3271 
3272  is.clear ();
3273 
3274  octave_value val;
3275  if (fmt.numeric)
3276  {
3277  if (fmt.type == 'f' || fmt.type == 'n')
3278  {
3279  Complex v;
3280  skip_whitespace (is);
3281  scan_complex (is, fmt, v);
3282 
3283  if (! fmt.discard && ! is.fail ())
3284  {
3285  if (fmt.bitwidth == 64)
3286  {
3287  if (ov.is_real_type () && v.imag () == 0)
3288  ov.internal_rep ()->fast_elem_insert (row(0), v.real ());
3289  else
3290  {
3291  if (ov.is_real_type ()) // cat does type conversion
3292  ov = do_cat_op (ov, octave_value (v), row);
3293  else
3294  ov.internal_rep ()->fast_elem_insert (row(0), v);
3295  }
3296  }
3297  else
3298  {
3299  if (ov.is_real_type () && v.imag () == 0)
3300  ov.internal_rep ()->fast_elem_insert (row(0),
3301  float (v.real ()));
3302  else
3303  {
3304  if (ov.is_real_type ()) // cat does type conversion
3305  ov = do_cat_op (ov, octave_value (v), row);
3306  else
3307  ov.internal_rep ()->fast_elem_insert (row(0),
3308  FloatComplex (v));
3309  }
3310  }
3311  }
3312  }
3313  else
3314  {
3315  double v; // Matlab docs say 1e30 etc should be valid for %d and
3316  // 1000 as a %d8 should be 127, so read as double.
3317  // Some loss of precision for d64 and u64.
3318  skip_whitespace (is);
3319  v = read_double (is, fmt);
3320  if (! fmt.discard && ! is.fail ())
3321  switch (fmt.bitwidth)
3322  {
3323  case 64:
3324  switch (fmt.type)
3325  {
3326  case 'd':
3327  {
3328  octave_int64 vv = v;
3329  ov.internal_rep ()->fast_elem_insert (row(0), vv);
3330  }
3331  break;
3332 
3333  case 'u':
3334  {
3335  octave_uint64 vv = v;
3336  ov.internal_rep ()->fast_elem_insert (row(0), vv);
3337  }
3338  break;
3339  }
3340  break;
3341 
3342  case 32:
3343  switch (fmt.type)
3344  {
3345  case 'd':
3346  {
3347  octave_int32 vv = v;
3348  ov.internal_rep ()->fast_elem_insert (row(0), vv);
3349  }
3350  break;
3351 
3352  case 'u':
3353  {
3354  octave_uint32 vv = v;
3355  ov.internal_rep ()->fast_elem_insert (row(0), vv);
3356  }
3357  break;
3358  }
3359  break;
3360 
3361  case 16:
3362  if (fmt.type == 'd')
3363  {
3364  octave_int16 vv = v;
3365  ov.internal_rep ()->fast_elem_insert (row(0), vv);
3366  }
3367  else
3368  {
3369  octave_uint16 vv = v;
3370  ov.internal_rep ()->fast_elem_insert (row(0), vv);
3371  }
3372  break;
3373 
3374  case 8:
3375  if (fmt.type == 'd')
3376  {
3377  octave_int8 vv = v;
3378  ov.internal_rep ()->fast_elem_insert (row(0), vv);
3379  }
3380  else
3381  {
3382  octave_uint8 vv = v;
3383  ov.internal_rep ()->fast_elem_insert (row(0), vv);
3384  }
3385  break;
3386  }
3387  }
3388 
3389  if (is.fail () & ! fmt.discard)
3390  ov = do_cat_op (ov, empty_value, row);
3391  }
3392  else
3393  {
3394  std::string vv (" "); // initial buffer. Grows as needed
3395  switch (fmt.type)
3396  {
3397  case 's':
3398  scan_string (is, fmt, vv);
3399  break;
3400 
3401  case 'q':
3402  scan_qstring (is, fmt, vv);
3403  break;
3404 
3405  case 'c':
3406  scan_cstring (is, fmt, vv);
3407  break;
3408 
3409  case '[':
3410  scan_bracket (is, fmt.char_class.c_str (), vv);
3411  break;
3412 
3413  case '^':
3414  scan_caret (is, fmt.char_class.c_str (), vv);
3415  break;
3416  }
3417 
3418  if (! fmt.discard)
3419  ov.internal_rep ()->fast_elem_insert (row (0),
3420  Cell (octave_value (vv)));
3421 
3422  // FIXME: why does failbit get set at EOF, instead of eofbit?
3423  if (! vv.empty ())
3424  is.clear (is.rdstate () & ~std::ios_base::failbit);
3425  }
3426 
3427  is.field_done ();
3428  }
3429 
3430  // Read data corresponding to the entire format string once, placing the
3431  // values in row ROW of retval.
3432 
3433  int
3435  textscan_format_list& fmt_list,
3436  std::list<octave_value>& retval,
3437  Array<octave_idx_type> row, int& done_after)
3438  {
3439  const textscan_format_elt *elem = fmt_list.first ();
3440  std::list<octave_value>::iterator out = retval.begin ();
3441  bool no_conversions = true;
3442  bool done = false;
3443  bool conversion_failed = false; // Record for ReturnOnError
3444  bool nothing_worked = true;
3445 
3446  octave_quit ();
3447 
3448  for (size_t i = 0; i < fmt_list.numel (); i++)
3449  {
3450  bool this_conversion_failed = false;
3451 
3452  // Clear fail of previous numeric conversions.
3453  is.clear ();
3454 
3455  switch (elem->type)
3456  {
3457  case 'C':
3458  case 'D':
3459  warning ("%s: conversion %c not yet implemented",
3460  who.c_str (), elem->type);
3461  break;
3462 
3463  case 'u':
3464  case 'd':
3465  case 'f':
3466  case 'n':
3467  case 's':
3468  case '[':
3469  case '^':
3470  case 'q':
3471  case 'c':
3472  scan_one (is, *elem, *out, row);
3473  break;
3474 
3476  match_literal (is, *elem);
3477  break;
3478 
3479  default:
3480  error ("Unknown format element '%c'", elem->type);
3481  }
3482 
3483  if (! is.fail ())
3484  {
3485  if (! elem->discard)
3486  no_conversions = false;
3487  }
3488  else
3489  {
3490  is.clear (is.rdstate () & ~std::ios::failbit);
3491 
3492  if (!is.eof () && ~is_delim (is.peek ()))
3493  this_conversion_failed = true;
3494  }
3495 
3496  if (! elem->discard)
3497  out++;
3498 
3499  elem = fmt_list.next ();
3500  char *pos = is.tellg ();
3501 
3502  // FIXME: these conversions "ignore delimiters". Should they include
3503  // delimiters at the start of the conversion, or can those be skipped?
3505  // && elem->type != '[' && elem->type != '^' && elem->type != 'c'
3506  )
3507  skip_delim (is);
3508 
3509  if (is.eof ())
3510  {
3511  if (! done)
3512  done_after = i+1;
3513 
3514  // note EOF, but process others to get empty_val.
3515  done = true;
3516  }
3517 
3518  if (this_conversion_failed)
3519  {
3520  if (is.tellg () == pos && ! conversion_failed)
3521  {
3522  // done_after = first failure
3523  done_after = i; // note fail, but parse others to get empty_val
3524  conversion_failed = true;
3525  }
3526  else
3527  this_conversion_failed = false;
3528  }
3529  else if (! done && !conversion_failed)
3530  nothing_worked = false;
3531  }
3532 
3533  if (done)
3534  is.setstate (std::ios::eofbit);
3535 
3536  return no_conversions
3537  + (is.eof () ? 2 : 0)
3538  + (conversion_failed ? 4 : 0)
3539  + (nothing_worked ? 8 : 0);
3540 
3541  }
3542 
3543  void
3545  textscan_format_list& fmt_list)
3546  {
3547  int last = args.length ();
3548  int n = last;
3549 
3550  if (n & 1)
3551  error ("%s: %d parameters given, but only %d values",
3552  who.c_str (), n-n/2, n/2);
3553 
3554  delim_len = 1;
3555  bool have_delims = false;
3556  for (int i = 0; i < last; i += 2)
3557  {
3558  std::string param = args(i).xstring_value ("%s: Invalid parameter type <%s> for parameter %d",
3559  who.c_str (),
3560  args(i).type_name ().c_str (),
3561  i/2 + 1);
3562  std::transform (param.begin (), param.end (), param.begin (), ::tolower);
3563 
3564  if (param == "delimiter")
3565  {
3566  bool invalid = true;
3567  if (args(i+1).is_string ())
3568  {
3569  invalid = false;
3570  have_delims = true;
3571  delims = args(i+1).string_value ();
3572  if (args(i+1).is_sq_string ())
3574  }
3575  else if (args(i+1).is_cell ())
3576  {
3577  invalid = false;
3578  delim_list = args(i+1).cell_value ();
3579  delim_table = " "; // non-empty, to flag non-default delim
3580 
3581  // Check that all elements are strings, and find max length
3582  for (int j = 0; j < delim_list.numel (); j++)
3583  {
3584  if (! delim_list(j).is_string ())
3585  invalid = true;
3586  else
3587  {
3588  if (delim_list(j).is_sq_string ())
3590  .string_value ());
3591  octave_idx_type len = delim_list(j).string_value ()
3592  .length ();
3593  delim_len = std::max (static_cast<int> (len), delim_len);
3594  }
3595  }
3596  }
3597  if (invalid)
3598  error ("%s: Delimiters must be either a string or cell array of strings",
3599  who.c_str ());
3600  }
3601  else if (param == "commentstyle")
3602  {
3603  if (args(i+1).is_string ())
3604  {
3605  // check here for names like "C++", "C", "shell", ...?
3606  comment_style = Cell (args(i+1));
3607  }
3608  else if (args(i+1).is_cell ())
3609  {
3610  comment_style = args(i+1).cell_value ();
3611  int len = comment_style.numel ();
3612  if ((len >= 1 && ! comment_style (0).is_string ())
3613  || (len >= 2 && ! comment_style (1).is_string ())
3614  || (len >= 3))
3615  error ("%s: CommentStyle must be either a string or cell array of one or two strings",
3616  who.c_str ());
3617  }
3618  else
3619  error ("%s: CommentStyle must be either a string or cell array of one or two strings",
3620  who.c_str ());
3621 
3622  // How far ahead do we need to look to detect an open comment
3623  // and which character do we look for?
3624  if (comment_style.numel () >= 1)
3625  {
3626  comment_len = comment_style (0).string_value ().size ();
3627  comment_char = comment_style (0).string_value ()[0];
3628  }
3629  }
3630  else if (param == "treatasempty")
3631  {
3632  bool invalid = false;
3633  if (args(i+1).is_string ())
3634  {
3635  treat_as_empty = Cell (args(i+1));
3636  treat_as_empty_len = args(i+1).string_value ().size ();
3637  }
3638  else if (args(i+1).is_cell ())
3639  {
3640  treat_as_empty = args(i+1).cell_value ();
3641  for (int j = 0; j < treat_as_empty.numel (); j++)
3642  if (! treat_as_empty (j).is_string ())
3643  invalid = true;
3644  else
3645  {
3646  int k = treat_as_empty (j).string_value ().size ();
3647  if (k > treat_as_empty_len)
3649  }
3650  }
3651  if (invalid)
3652  error ("%s: TreatAsEmpty must be either a string or cell array of one or two strings",
3653  who.c_str ());
3654 
3655  // FIXME: Ensure none is a prefix of a later one. Sort by length?
3656  }
3657  else if (param == "collectoutput")
3658  {
3659  collect_output = args(i+1).xbool_value ("%s: CollectOutput must be logical or numeric", who.c_str ());
3660  }
3661  else if (param == "emptyvalue")
3662  {
3663  empty_value = args(i+1).xscalar_value ("%s: EmptyValue must be numeric", who.c_str ());
3664  }
3665  else if (param == "headerlines")
3666  {
3667  header_lines = args(i+1).xscalar_value ("%s: HeaderLines must be numeric", who.c_str ());
3668  }
3669  else if (param == "bufsize")
3670  {
3671  buffer_size = args(i+1).xscalar_value ("%s: BufSize must be numeric", who.c_str ());
3672  }
3673  else if (param == "multipledelimsasone")
3674  {
3675  multiple_delims_as_one = args(i+1).xbool_value ("%s: MultipleDelimsAsOne must be logical or numeric", who.c_str ());
3676  }
3677  else if (param == "returnonerror")
3678  {
3679  return_on_error = args(i+1).xbool_value ("%s: ReturnOnError must be logical or numeric", who.c_str ());
3680  }
3681  else if (param == "whitespace")
3682  {
3683  whitespace = args(i+1).xstring_value ("%s: Whitespace must be a character string", who.c_str ());
3684  }
3685  else if (param == "expchars")
3686  {
3687  exp_chars = args(i+1).xstring_value ("%s: ExpChars must be a character string", who.c_str ());
3688  default_exp = false;
3689  }
3690  else if (param == "endofline")
3691  {
3692  bool valid = true;
3693  std::string s = args(i+1).xstring_value ("%s: EndOfLine must be at most one character or '\\r\\n'", who.c_str ());
3694  if (args(i+1).is_sq_string ())
3695  s = do_string_escapes (s);
3696  int l = s.length ();
3697  if (l == 0)
3698  eol1 = eol2 = -2;
3699  else if (l == 1)
3700  eol1 = eol2 = s.c_str ()[0];
3701  else if (l == 2)
3702  {
3703  eol1 = s.c_str ()[0];
3704  eol2 = s.c_str ()[1];
3705  if (eol1 != '\r' || eol2 != '\n') // Why limit it?
3706  valid = false;
3707  }
3708  else
3709  valid = false;
3710 
3711  if (! valid)
3712  error ("%s: EndOfLine must be at most one character or '\\r\\n'",
3713  who.c_str ());
3714  }
3715  else
3716  error ("%s: unrecognized option '%s'", who.c_str (), param.c_str ());
3717  }
3718 
3719  whitespace_table = std::string (256, '\0');
3720  for (unsigned int i = 0; i < whitespace.length (); i++)
3721  whitespace_table[whitespace[i]] = '1';
3722 
3723  // For Matlab compatibility, add 0x20 to whitespace, unless
3724  // whitespace is explicitly ignored.
3725  if (! (whitespace.empty () && fmt_list.has_string))
3726  whitespace_table[' '] = '1';
3727 
3728  // Create look-up table of delimiters, based on 'delimiter'
3729  delim_table = std::string (256, '\0');
3730  if (eol1 >= 0 && eol1 < 256)
3731  delim_table[eol1] = '1'; // EOL is always a delimiter
3732  if (eol2 >= 0 && eol2 < 256)
3733  delim_table[eol2] = '1'; // EOL is always a delimiter
3734  if (! have_delims)
3735  for (unsigned int i = 0; i < 256; i++)
3736  {
3737  if (isspace (i))
3738  delim_table[i] = '1';
3739  }
3740  else
3741  for (unsigned int i = 0; i < delims.length (); i++)
3742  delim_table[delims[i]] = '1';
3743  }
3744 
3745  // Skip comments, and characters specified by the "Whitespace" option.
3746  // If EOLstop == true, don't skip end of line.
3747 
3748  int
3750  {
3751  int c1 = std::istream::traits_type::eof ();
3752  bool found_comment = false;
3753 
3754  do
3755  {
3756  found_comment = false;
3757  int prev = -1;
3758  while (is && (c1 = is.get_undelim ()) != std::istream::traits_type::eof ()
3759  && ( ( (c1 == eol1 || c1 == eol2) && ++lines && ! EOLstop)
3760  || isspace (c1)))
3761  {
3762  if (prev == eol1 && eol1 != eol2 && c1 == eol2)
3763  lines--;
3764  prev = c1;
3765  }
3766 
3767  if (c1 == comment_char) // see if we match an open comment
3768  {
3769  // save stream state in case we have to restore it
3770  char *pos = is.tellg ();
3771  std::ios::iostate state = is.rdstate ();
3772 
3773  std::string tmp (comment_len, '\0');
3774  char *look = is.read (&tmp[0], comment_len-1, pos); // already read first char
3775  if (is && ! strncmp (comment_style(0).string_value ().substr (1)
3776  .c_str (), look, comment_len-1))
3777  {
3778  found_comment = true;
3779 
3780  std::string dummy;
3781  if (comment_style.numel () == 1) // skip to end of line
3782  {
3783  std::string eol (3, '\0');
3784  eol[0] = eol1;
3785  eol[1] = eol2;
3786 
3787  scan_caret (is, eol, dummy);
3788  c1 = is.get_undelim ();
3789  if (c1 == eol1 && eol1 != eol2 && is.peek_undelim () == eol2)
3790  is.get_undelim ();
3791  lines++;
3792  }
3793  else // matching pair
3794  {
3795  std::string end_c = comment_style(1).string_value ();
3796  // last char of end-comment sequence
3797  std::string last = end_c.substr (end_c.size () - 1);
3798  std::string may_match ("");
3799  do
3800  {
3801  // find sequence ending with last char
3802  scan_caret (is, last, dummy);
3803  is.get_undelim (); // (read LAST itself)
3804 
3805  may_match = may_match + dummy + last;
3806  if (may_match.length () > end_c.length ())
3807  {
3808  size_t start = may_match.length () - end_c.length ();
3809  may_match = may_match.substr (start);
3810  }
3811  }
3812  while (may_match != end_c && is && ! is.eof ());
3813  }
3814  }
3815  else // wasn't really a comment; restore state
3816  {
3817  is.clear (state);
3818  is.seekg (pos);
3819  }
3820  }
3821  }
3822  while (found_comment);
3823 
3824  if (c1 != std::istream::traits_type::eof ())
3825  is.putback (c1);
3826  return c1;
3827  }
3828 
3829  // See if the next few characters match one of the strings in target.
3830  // For efficiency, MAX_LEN is the cached longest length of any target.
3831  // Return -1 if none is found, or the index of the match.
3832 
3833  int
3834  textscan::lookahead (delimited_stream& is, const Cell& targets, int max_len,
3835  bool case_sensitive) const
3836  {
3837  // target strings may be different sizes.
3838  // Read ahead longest, put it all back, then re-read the string
3839  // that matches.
3840 
3841  char *pos = is.tellg ();
3842 
3843  std::string tmp (max_len, '\0');
3844  char *look = is.read (&tmp[0], tmp.size (), pos);
3845 
3846  is.clear ();
3847  is.seekg (pos); // reset to position before look-ahead
3848  // FIXME: pos may be corrupted by is.read
3849 
3850  int i;
3851  int (*compare)(const char *, const char *, size_t);
3852  compare = case_sensitive ? strncmp : strncasecmp;
3853 
3854  for (i = 0; i < targets.numel (); i++)
3855  {
3856  std::string s = targets (i).string_value ();
3857  if (! (*compare) (s.c_str (), look, s.size ()))
3858  {
3859  is.read (&tmp[0], s.size (), pos); // read just the right amount
3860  break;
3861  }
3862  }
3863 
3864  if (i == targets.numel ())
3865  i = -1;
3866 
3867  return i;
3868  }
3869 
3870  // Skip delimiters -- multiple if MultipleDelimsAsOne specified.
3871  int
3873  {
3874  int c1 = skip_whitespace (is, true); // 'true': stop once EOL is read
3875  if (delim_list.numel () == 0) // single character delimiter
3876  {
3877  if (is_delim (c1) || c1 == eol1 || c1 == eol2)
3878  {
3879  is.get ();
3880  if (c1 == eol1 && is.peek_undelim () == eol2)
3881  is.get_undelim (); // if \r\n, skip the \n too.
3882 
3884  {
3885  int prev = -1;
3886  // skip multiple delims.
3887  // Increment lines for each end-of-line seen; for \r\n, decrement
3888  while (is && ((c1 = is.get_undelim ())
3889  != std::istream::traits_type::eof ())
3890  && (((c1 == eol1 || c1 == eol2) && ++lines)
3891  || isspace (c1) || is_delim (c1)))
3892  {
3893  if (prev == eol1 && eol1 != eol2 && c1 == eol2)
3894  lines--;
3895  prev = c1;
3896  }
3897  if (c1 != std::istream::traits_type::eof ())
3898  is.putback (c1);
3899  }
3900  }
3901  }
3902  else // multi-character delimiter
3903  {
3904  int first_match;
3905 
3906  if (c1 == eol1 || c1 == eol2
3907  || (-1 != (first_match = lookahead (is, delim_list, delim_len))))
3908  {
3909  if (c1 == eol1)
3910  {
3911  is.get_undelim ();
3912  if (is.peek_undelim () == eol2)
3913  is.get_undelim ();
3914  }
3915  else if (c1 == eol2)
3916  {
3917  is.get_undelim ();
3918  }
3919 
3921  {
3922  int prev = -1;
3923  // skip multiple delims.
3924  // Increment lines for each end-of-line seen; for \r\n, decrement
3925  while (is && ((c1 = skip_whitespace (is, true))
3926  != std::istream::traits_type::eof ())
3927  && (((c1 == eol1 || c1 == eol2) && ++lines)
3928  || -1 != lookahead (is, delim_list, delim_len)))
3929  {
3930  if (prev == eol1 && eol1 != eol2 && c1 == eol2)
3931  lines--;
3932  prev = c1;
3933  }
3934  }
3935  }
3936  }
3937 
3938  return c1;
3939  }
3940 
3941  // Read in as much of the input as coincides with the literal in the
3942  // format string. Return "true" if the entire literal is matched, else
3943  // false (and set failbit).
3944 
3945  bool
3947  {
3948  // "false" -> treat EOL as normal space
3949  // since a delimiter at the start of a line is a mismatch, not empty field
3950  skip_whitespace (is, false);
3951 
3952  for (unsigned int i = 0; i < fmt.width; i++)
3953  {
3954  int ch = is.get_undelim ();
3955  if (ch != fmt.text[i])
3956  {
3957  if (ch != std::istream::traits_type::eof ())
3958  is.putback (ch);
3959  is.setstate (std::ios::failbit);
3960  return false;
3961  }
3962  }
3963  return true;
3964  }
3965 }
3966 
3967 void
3969 {
3970  fail = true;
3971  errmsg = msg;
3972 }
3973 
3974 void
3976 {
3977  fail = true;
3978  errmsg = who + ": " + msg;
3979 }
3980 
3981 void
3983 {
3984  fail = false;
3985  errmsg = "";
3986 }
3987 
3988 void
3990 {
3991  std::istream *is = input_stream ();
3992  std::ostream *os = output_stream ();
3993 
3994  if (is)
3995  is->clear ();
3996 
3997  if (os)
3998  os->clear ();
3999 }
4000 
4001 // Functions that are defined for all input streams (input streams
4002 // are those that define is).
4003 
4006  bool strip_newline, const std::string& who)
4007 {
4008  if (octave::application::interactive () && file_number () == 0)
4009  ::error ("%s: unable to read from stdin while running interactively",
4010  who.c_str ());
4011 
4013 
4014  err = false;
4015 
4016  std::istream *isp = input_stream ();
4017 
4018  if (! isp)
4019  {
4020  err = true;
4021  invalid_operation (who, "reading");
4022  }
4023  else
4024  {
4025  std::istream& is = *isp;
4026 
4027  std::ostringstream buf;
4028 
4029  int c = 0;
4030  int char_count = 0;
4031 
4032  if (max_len != 0)
4033  {
4034  while (is && (c = is.get ()) != std::istream::traits_type::eof ())
4035  {
4036  char_count++;
4037 
4038  // Handle CRLF, CR, or LF as line ending.
4039  if (c == '\r')
4040  {
4041  if (! strip_newline)
4042  buf << static_cast<char> (c);
4043 
4044  c = is.get ();
4045 
4046  if (c != std::istream::traits_type::eof ())
4047  {
4048  if (c == '\n')
4049  {
4050  char_count++;
4051 
4052  if (! strip_newline)
4053  buf << static_cast<char> (c);
4054  }
4055  else
4056  is.putback (c);
4057  }
4058 
4059  break;
4060  }
4061  else if (c == '\n')
4062  {
4063  if (! strip_newline)
4064  buf << static_cast<char> (c);
4065 
4066  break;
4067  }
4068  else
4069  buf << static_cast<char> (c);
4070 
4071  if (max_len > 0 && char_count == max_len)
4072  break;
4073  }
4074  }
4075 
4076  if (! is.eof () && char_count > 0)
4077  {
4078  // GAGME. Matlab seems to check for EOF even if the last character
4079  // in a file is a newline character. This is NOT what the
4080  // corresponding C-library functions do.
4081  int disgusting_compatibility_hack = is.get ();
4082  if (! is.eof ())
4083  is.putback (disgusting_compatibility_hack);
4084  }
4085 
4086  if (is.good () || (is.eof () && char_count > 0))
4087  retval = buf.str ();
4088  else
4089  {
4090  err = true;
4091 
4092  if (is.eof () && char_count == 0)
4093  error (who, "at end of file");
4094  else
4095  error (who, "read error");
4096  }
4097  }
4098 
4099  return retval;
4100 }
4101 
4104  const std::string& who)
4105 {
4106  return do_gets (max_len, err, true, who);
4107 }
4108 
4111  const std::string& who)
4112 {
4113  return do_gets (max_len, err, false, who);
4114 }
4115 
4116 off_t
4117 octave_base_stream::skipl (off_t num, bool& err, const std::string& who)
4118 {
4119  if (octave::application::interactive () && file_number () == 0)
4120  ::error ("%s: unable to read from stdin while running interactively",
4121  who.c_str ());
4122 
4123  off_t cnt = -1;
4124 
4125  err = false;
4126 
4127  std::istream *isp = input_stream ();
4128 
4129  if (! isp)
4130  {
4131  err = true;
4132  invalid_operation (who, "reading");
4133  }
4134  else
4135  {
4136  std::istream& is = *isp;
4137 
4138  int c = 0;
4139  int lastc = -1;
4140  cnt = 0;
4141 
4142  while (is && (c = is.get ()) != std::istream::traits_type::eof ())
4143  {
4144  // Handle CRLF, CR, or LF as line ending.
4145  if (c == '\r' || (c == '\n' && lastc != '\r'))
4146  {
4147  if (++cnt == num)
4148  break;
4149  }
4150 
4151  lastc = c;
4152  }
4153 
4154  // Maybe eat the following \n if \r was just met.
4155  if (c == '\r' && is.peek () == '\n')
4156  is.get ();
4157 
4158  if (is.bad ())
4159  {
4160  err = true;
4161  error (who, "read error");
4162  }
4163 
4164  if (err)
4165  cnt = -1;
4166  }
4167 
4168  return cnt;
4169 }
4170 
4171 template <typename T>
4172 std::istream&
4173 octave_scan_1 (std::istream& is, const scanf_format_elt& fmt, T* valptr)
4174 {
4175  T value = T ();
4176 
4177  switch (fmt.type)
4178  {
4179  case 'o':
4180  is >> std::oct >> value >> std::dec;
4181  break;
4182 
4183  case 'x':
4184  is >> std::hex >> value >> std::dec;
4185  break;
4186 
4187  case 'i':
4188  {
4189  int c1 = std::istream::traits_type::eof ();
4190 
4191  while (is && (c1 = is.get ()) != std::istream::traits_type::eof ()
4192  && isspace (c1))
4193  ; // skip whitespace
4194 
4195  if (c1 != std::istream::traits_type::eof ())
4196  {
4197  if (c1 == '0')
4198  {
4199  int c2 = is.peek ();
4200 
4201  if (c2 == 'x' || c2 == 'X')
4202  {
4203  is.ignore ();
4204  if (std::isxdigit (is.peek ()))
4205  is >> std::hex >> value >> std::dec;
4206  else
4207  value = 0;
4208  }
4209  else
4210  {
4211  if (c2 == '0' || c2 == '1' || c2 == '2'
4212  || c2 == '3' || c2 == '4' || c2 == '5'
4213  || c2 == '6' || c2 == '7')
4214  is >> std::oct >> value >> std::dec;
4215  else if (c2 == '8' || c2 == '9')
4216  {
4217  // FIXME: Would like to set error state on octave
4218  // stream. See bug #46493. But only std::istream is
4219  // input to fcn.
4220  // error ("internal failure to match octal format");
4221  value = 0;
4222  }
4223  else
4224  value = 0;
4225  }
4226  }
4227  else
4228  {
4229  is.putback (c1);
4230 
4231  is >> value;
4232  }
4233  }
4234  }
4235  break;
4236 
4237  default:
4238  is >> value;
4239  break;
4240  }
4241 
4242  // If conversion produces an integer that overflows, failbit is set but
4243  // value is non-zero. We want to treat this case as success, so clear
4244  // failbit from the stream state to keep going.
4245  // FIXME: Maybe set error state on octave stream as above? Matlab does
4246  // *not* indicate an error message on overflow.
4247  if ((is.rdstate () & std::ios::failbit) && value != T ())
4248  is.clear (is.rdstate () & ~std::ios::failbit);
4249 
4250  // Only copy the converted value if the stream is in a state where we
4251  // want to continue reading.
4252  if (! (is.rdstate () & std::ios::failbit))
4253  *valptr = value;
4254 
4255  return is;
4256 }
4257 
4258 template <typename T>
4259 std::istream&
4260 octave_scan (std::istream& is, const scanf_format_elt& fmt, T* valptr)
4261 {
4262  if (fmt.width)
4263  {
4264  // Limit input to fmt.width characters by reading into a
4265  // temporary stringstream buffer.
4266  std::string tmp;
4267 
4268  is.width (fmt.width);
4269  is >> tmp;
4270 
4271  std::istringstream ss (tmp);
4272 
4273  octave_scan_1 (ss, fmt, valptr);
4274  }
4275  else
4276  octave_scan_1 (is, fmt, valptr);
4277 
4278  return is;
4279 }
4280 
4281 // Note that this specialization is only used for reading characters, not
4282 // character strings. See BEGIN_S_CONVERSION for details.
4283 
4284 template <>
4285 std::istream&
4286 octave_scan<> (std::istream& is, const scanf_format_elt& /* fmt */,
4287  char* valptr)
4288 {
4289  return is >> valptr;
4290 }
4291 
4292 template <>
4293 std::istream&
4294 octave_scan<> (std::istream& is, const scanf_format_elt& fmt, double* valptr)
4295 {
4296  double& ref = *valptr;
4297 
4298  switch (fmt.type)
4299  {
4300  case 'e':
4301  case 'f':
4302  case 'g':
4303  {
4304  int c1 = std::istream::traits_type::eof ();
4305 
4306  while (is && (c1 = is.get ()) != std::istream::traits_type::eof ()
4307  && isspace (c1))
4308  ; // skip whitespace
4309 
4310  if (c1 != std::istream::traits_type::eof ())
4311  {
4312  is.putback (c1);
4313 
4314  ref = octave_read_value<double> (is);
4315  }
4316  }
4317  break;
4318 
4319  default:
4320  panic_impossible ();
4321  break;
4322  }
4323 
4324  return is;
4325 }
4326 
4327 template <typename T>
4328 void
4329 do_scanf_conv (std::istream& is, const scanf_format_elt& fmt,
4330  T valptr, Matrix& mval, double *data, octave_idx_type& idx,
4331  octave_idx_type& conversion_count, octave_idx_type nr,
4332  octave_idx_type max_size, bool discard)
4333 {
4334  octave_scan (is, fmt, valptr);
4335 
4336  if (! is)
4337  return;
4338 
4339  if (idx == max_size && ! discard)
4340  {
4341  max_size *= 2;
4342 
4343  if (nr > 0)
4344  mval.resize (nr, max_size / nr, 0.0);
4345  else
4346  mval.resize (max_size, 1, 0.0);
4347 
4348  data = mval.fortran_vec ();
4349  }
4350 
4351  if (! discard)
4352  {
4353  conversion_count++;
4354  data[idx++] = *(valptr);
4355  }
4356 }
4357 
4358 template void
4359 do_scanf_conv (std::istream&, const scanf_format_elt&, double*,
4360  Matrix&, double*, octave_idx_type&, octave_idx_type&,
4362 
4363 #define DO_WHITESPACE_CONVERSION() \
4364  do \
4365  { \
4366  int c = std::istream::traits_type::eof (); \
4367  \
4368  while (is && (c = is.get ()) != std::istream::traits_type::eof () \
4369  && isspace (c)) \
4370  { /* skip whitespace */ } \
4371  \
4372  if (c != std::istream::traits_type::eof ()) \
4373  is.putback (c); \
4374  } \
4375  while (0)
4376 
4377 #define DO_LITERAL_CONVERSION() \
4378  do \
4379  { \
4380  int c = std::istream::traits_type::eof (); \
4381  \
4382  int n = strlen (fmt); \
4383  int i = 0; \
4384  \
4385  while (i < n && is && (c = is.get ()) != std::istream::traits_type::eof ()) \
4386  { \
4387  if (c == static_cast<unsigned char> (fmt[i])) \
4388  { \
4389  i++; \
4390  continue; \
4391  } \
4392  else \
4393  { \
4394  is.putback (c); \
4395  break; \
4396  } \
4397  } \
4398  \
4399  if (i != n) \
4400  is.setstate (std::ios::failbit); \
4401  } \
4402  while (0)
4403 
4404 #define DO_PCT_CONVERSION() \
4405  do \
4406  { \
4407  int c = is.get (); \
4408  \
4409  if (c != std::istream::traits_type::eof ()) \
4410  { \
4411  if (c != '%') \
4412  { \
4413  is.putback (c); \
4414  is.setstate (std::ios::failbit); \
4415  } \
4416  } \
4417  else \
4418  is.setstate (std::ios::failbit); \
4419  } \
4420  while (0)
4421 
4422 #define BEGIN_C_CONVERSION() \
4423  is.unsetf (std::ios::skipws); \
4424  \
4425  int width = elt->width ? elt->width : 1; \
4426  \
4427  std::string tmp (width, '\0'); \
4428  \
4429  int c = std::istream::traits_type::eof (); \
4430  int n = 0; \
4431  \
4432  while (is && n < width \
4433  && (c = is.get ()) != std::istream::traits_type::eof ()) \
4434  tmp[n++] = static_cast<char> (c); \
4435  \
4436  if (n > 0 && c == std::istream::traits_type::eof ()) \
4437  is.clear (); \
4438  \
4439  tmp.resize (n)
4440 
4441 // For a '%s' format, skip initial whitespace and then read until the
4442 // next whitespace character or until WIDTH characters have been read.
4443 #define BEGIN_S_CONVERSION() \
4444  int width = elt->width; \
4445  \
4446  std::string tmp; \
4447  \
4448  do \
4449  { \
4450  if (width) \
4451  { \
4452  tmp = std::string (width, '\0'); \
4453  \
4454  int c = std::istream::traits_type::eof (); \
4455  \
4456  int n = 0; \
4457  \
4458  while (is && (c = is.get ()) != std::istream::traits_type::eof ()) \
4459  { \
4460  if (! isspace (c)) \
4461  { \
4462  tmp[n++] = static_cast<char> (c); \
4463  break; \
4464  } \
4465  } \
4466  \
4467  while (is && n < width \
4468  && (c = is.get ()) != std::istream::traits_type::eof ()) \
4469  { \
4470  if (isspace (c)) \
4471  { \
4472  is.putback (c); \
4473  break; \
4474  } \
4475  else \
4476  tmp[n++] = static_cast<char> (c); \
4477  } \
4478  \
4479  if (n > 0 && c == std::istream::traits_type::eof ()) \
4480  is.clear (); \
4481  \
4482  tmp.resize (n); \
4483  } \
4484  else \
4485  { \
4486  is >> std::ws >> tmp; \
4487  } \
4488  } \
4489  while (0)
4490 
4491 // This format must match a nonempty sequence of characters.
4492 #define BEGIN_CHAR_CLASS_CONVERSION() \
4493  int width = elt->width; \
4494  \
4495  std::string tmp; \
4496  \
4497  do \
4498  { \
4499  if (! width) \
4500  width = std::numeric_limits<int>::max (); \
4501  \
4502  std::ostringstream buf; \
4503  \
4504  std::string char_class = elt->char_class; \
4505  \
4506  int c = std::istream::traits_type::eof (); \
4507  \
4508  if (elt->type == '[') \
4509  { \
4510  int chars_read = 0; \
4511  while (is && chars_read++ < width \
4512  && (c = is.get ()) != std::istream::traits_type::eof () \
4513  && char_class.find (c) != std::string::npos) \
4514  buf << static_cast<char> (c); \
4515  } \
4516  else \
4517  { \
4518  int chars_read = 0; \
4519  while (is && chars_read++ < width \
4520  && (c = is.get ()) != std::istream::traits_type::eof () \
4521  && char_class.find (c) == std::string::npos) \
4522  buf << static_cast<char> (c); \
4523  } \
4524  \
4525  if (width == std::numeric_limits<int>::max () \
4526  && c != std::istream::traits_type::eof ()) \
4527  is.putback (c); \
4528  \
4529  tmp = buf.str (); \
4530  \
4531  if (tmp.empty ()) \
4532  is.setstate (std::ios::failbit); \
4533  else if (c == std::istream::traits_type::eof ()) \
4534  is.clear (); \
4535  \
4536  } \
4537  while (0)
4538 
4539 #define FINISH_CHARACTER_CONVERSION() \
4540  do \
4541  { \
4542  width = tmp.length (); \
4543  \
4544  if (is) \
4545  { \
4546  int i = 0; \
4547  \
4548  if (! discard) \
4549  { \
4550  conversion_count++; \
4551  \
4552  while (i < width) \
4553  { \
4554  if (data_index == max_size) \
4555  { \
4556  max_size *= 2; \
4557  \
4558  if (all_char_conv) \
4559  { \
4560  if (one_elt_size_spec) \
4561  mval.resize (1, max_size, 0.0); \
4562  else if (nr > 0) \
4563  mval.resize (nr, max_size / nr, 0.0); \
4564  else \
4565  panic_impossible (); \
4566  } \
4567  else if (nr > 0) \
4568  mval.resize (nr, max_size / nr, 0.0); \
4569  else \
4570  mval.resize (max_size, 1, 0.0); \
4571  \
4572  data = mval.fortran_vec (); \
4573  } \
4574  \
4575  data[data_index++] = tmp[i++]; \
4576  } \
4577  } \
4578  } \
4579  } \
4580  while (0)
4581 
4585  bool one_elt_size_spec,
4586  octave_idx_type& conversion_count,
4587  const std::string& who)
4588 {
4589  if (octave::application::interactive () && file_number () == 0)
4590  ::error ("%s: unable to read from stdin while running interactively",
4591  who.c_str ());
4592 
4593  octave_value retval = Matrix ();
4594 
4595  conversion_count = 0;
4596 
4597  octave_idx_type nconv = fmt_list.num_conversions ();
4598 
4599  octave_idx_type data_index = 0;
4600 
4601  if (nr == 0 || nc == 0)
4602  {
4603  if (one_elt_size_spec)
4604  nc = 0;
4605 
4606  return Matrix (nr, nc, 0.0);
4607  }
4608 
4609  std::istream *isp = input_stream ();
4610 
4611  bool all_char_conv = fmt_list.all_character_conversions ();
4612 
4613  Matrix mval;
4614  double *data = 0;
4615  octave_idx_type max_size = 0;
4616  octave_idx_type max_conv = 0;
4617 
4618  octave_idx_type final_nr = 0;
4619  octave_idx_type final_nc = 0;
4620 
4621  if (all_char_conv)
4622  {
4623  // Any of these could be resized later (if we have %s conversions,
4624  // we may read more than one element for each conversion).
4625  if (one_elt_size_spec)
4626  {
4627  max_size = 512;
4628  mval.resize (1, max_size, 0.0);
4629 
4630  if (nr > 0)
4631  max_conv = nr;
4632  }
4633  else if (nr > 0)
4634  {
4635  if (nc > 0)
4636  {
4637  mval.resize (nr, nc, 0.0);
4638  max_size = max_conv = nr * nc;
4639  }
4640  else
4641  {
4642  mval.resize (nr, 32, 0.0);
4643  max_size = nr * 32;
4644  }
4645  }
4646  else
4647  panic_impossible ();
4648  }
4649  else if (nr > 0)
4650  {
4651  if (nc > 0)
4652  {
4653  // Will not resize later.
4654  mval.resize (nr, nc, 0.0);
4655  max_size = nr * nc;
4656  max_conv = max_size;
4657  }
4658  else
4659  {
4660  // Maybe resize later.
4661  mval.resize (nr, 32, 0.0);
4662  max_size = nr * 32;
4663  }
4664  }
4665  else
4666  {
4667  // Maybe resize later.
4668  mval.resize (32, 1, 0.0);
4669  max_size = 32;
4670  }
4671 
4672  data = mval.fortran_vec ();
4673 
4674  if (isp)
4675  {
4676  std::istream& is = *isp;
4677 
4678  const scanf_format_elt *elt = fmt_list.first ();
4679 
4680  std::ios::fmtflags flags = is.flags ();
4681 
4682  octave_idx_type trips = 0;
4683 
4684  octave_idx_type num_fmt_elts = fmt_list.length ();
4685 
4686  for (;;)
4687  {
4688  octave_quit ();
4689 
4690  if (elt)
4691  {
4692  if (elt->type == scanf_format_elt::null
4695  || elt->type == '%')
4696  && max_conv > 0 && conversion_count == max_conv))
4697  {
4698  // We are done, either because we have reached the end of the
4699  // format string and are not cycling through the format again
4700  // or because we've converted all the values that have been
4701  // requested and the next format element is a conversion.
4702  // Determine final array size and exit.
4703  if (all_char_conv && one_elt_size_spec)
4704  {
4705  final_nr = 1;
4706  final_nc = data_index;
4707  }
4708  else
4709  {
4710  final_nr = nr;
4711  final_nc = (data_index - 1) / nr + 1;
4712  }
4713 
4714  break;
4715  }
4716  else if (data_index == max_size)
4717  {
4718  max_size *= 2;
4719 
4720  if (all_char_conv)
4721  {
4722  if (one_elt_size_spec)
4723  mval.resize (1, max_size, 0.0);
4724  else if (nr > 0)
4725  mval.resize (nr, max_size / nr, 0.0);
4726  else
4727  panic_impossible ();
4728  }
4729  else if (nr > 0)
4730  mval.resize (nr, max_size / nr, 0.0);
4731  else
4732  mval.resize (max_size, 1, 0.0);
4733 
4734  data = mval.fortran_vec ();
4735  }
4736 
4737  const char *fmt = elt->text;
4738 
4739  bool discard = elt->discard;
4740 
4741  switch (elt->type)
4742  {
4745  break;
4746 
4749  break;
4750 
4751  case '%':
4752  DO_PCT_CONVERSION ();
4753  break;
4754 
4755  case 'd': case 'i':
4756  {
4757  switch (elt->modifier)
4758  {
4759  case 'h':
4760  {
4761  int16_t tmp;
4762  do_scanf_conv (is, *elt, &tmp, mval, data,
4763  data_index, conversion_count,
4764  nr, max_size, discard);
4765  }
4766  break;
4767 
4768  case 'l':
4769  {
4770  int64_t tmp;
4771  do_scanf_conv (is, *elt, &tmp, mval, data,
4772  data_index, conversion_count,
4773  nr, max_size, discard);
4774  }
4775  break;
4776 
4777  default:
4778  {
4779  int32_t tmp;
4780  do_scanf_conv (is, *elt, &tmp, mval, data,
4781  data_index, conversion_count,
4782  nr, max_size, discard);
4783  }
4784  break;
4785  }
4786  }
4787  break;
4788 
4789  case 'o': case 'u': case 'x':
4790  {
4791  switch (elt->modifier)
4792  {
4793  case 'h':
4794  {
4795  uint16_t tmp;
4796  do_scanf_conv (is, *elt, &tmp, mval, data,
4797  data_index, conversion_count,
4798  nr, max_size, discard);
4799  }
4800  break;
4801 
4802  case 'l':
4803  {
4804  uint64_t tmp;
4805  do_scanf_conv (is, *elt, &tmp, mval, data,
4806  data_index, conversion_count,
4807  nr, max_size, discard);
4808  }
4809  break;
4810 
4811  default:
4812  {
4813  uint32_t tmp;
4814  do_scanf_conv (is, *elt, &tmp, mval, data,
4815  data_index, conversion_count,
4816  nr, max_size, discard);
4817  }
4818  break;
4819  }
4820  }
4821  break;
4822 
4823  case 'e': case 'f': case 'g':
4824  {
4825  double tmp;
4826 
4827  do_scanf_conv (is, *elt, &tmp, mval, data,
4828  data_index, conversion_count,
4829  nr, max_size, discard);
4830  }
4831  break;
4832 
4833  case 'c':
4834  {
4835  BEGIN_C_CONVERSION ();
4836 
4838 
4839  is.setf (flags);
4840  }
4841  break;
4842 
4843  case 's':
4844  {
4845  BEGIN_S_CONVERSION ();
4846 
4848  }
4849  break;
4850 
4851  case '[': case '^':
4852  {
4854 
4856  }
4857  break;
4858 
4859  case 'p':
4860  error ("%s: unsupported format specifier", who.c_str ());
4861  break;
4862 
4863  default:
4864  error ("%s: internal format error", who.c_str ());
4865  break;
4866  }
4867 
4868  if (! ok ())
4869  {
4870  break;
4871  }
4872  else if (! is)
4873  {
4874  if (all_char_conv)
4875  {
4876  if (one_elt_size_spec)
4877  {
4878  final_nr = 1;
4879  final_nc = data_index;
4880  }
4881  else if (data_index > nr)
4882  {
4883  final_nr = nr;
4884  final_nc = (data_index - 1) / nr + 1;
4885  }
4886  else
4887  {
4888  final_nr = data_index;
4889  final_nc = 1;
4890  }
4891  }
4892  else if (nr > 0)
4893  {
4894  if (data_index > nr)
4895  {
4896  final_nr = nr;
4897  final_nc = (data_index - 1) / nr + 1;
4898  }
4899  else
4900  {
4901  final_nr = data_index;
4902  final_nc = 1;
4903  }
4904  }
4905  else
4906  {
4907  final_nr = data_index;
4908  final_nc = 1;
4909  }
4910 
4911  // If it looks like we have a matching failure, then
4912  // reset the failbit in the stream state.
4913  if (is.rdstate () & std::ios::failbit)
4914  is.clear (is.rdstate () & (~std::ios::failbit));
4915 
4916  // FIXME: is this the right thing to do?
4917  if (octave::application::interactive ()
4918  && ! octave::application::forced_interactive ()
4919  && name () == "stdin")
4920  {
4921  is.clear ();
4922 
4923  // Skip to end of line.
4924  bool err;
4925  do_gets (-1, err, false, who);
4926  }
4927 
4928  break;
4929  }
4930  }
4931  else
4932  {
4933  error ("%s: internal format error", who.c_str ());
4934  break;
4935  }
4936 
4937  if (nconv == 0 && ++trips == num_fmt_elts)
4938  {
4939  if (all_char_conv && one_elt_size_spec)
4940  {
4941  final_nr = 1;
4942  final_nc = data_index;
4943  }
4944  else
4945  {
4946  final_nr = nr;
4947  final_nc = (data_index - 1) / nr + 1;
4948  }
4949 
4950  break;
4951  }
4952  else
4953  {
4954  // Cycle through the format list more than once if we have some
4955  // conversions to make and we haven't reached the limit on the
4956  // number of values to convert (possibly because there is no
4957  // specified limit).
4958  elt = fmt_list.next (nconv > 0
4959  && (max_conv == 0
4960  || conversion_count < max_conv));
4961  }
4962  }
4963  }
4964 
4965  if (ok ())
4966  {
4967  mval.resize (final_nr, final_nc, 0.0);
4968 
4969  retval = mval;
4970 
4971  if (all_char_conv)
4972  retval = retval.convert_to_str (false, true);
4973  }
4974 
4975  return retval;
4976 }
4977 
4980  octave_idx_type& conversion_count,
4981  const std::string& who)
4982 {
4983  octave_value retval = Matrix ();
4984 
4985  conversion_count = 0;
4986 
4987  std::istream *isp = input_stream ();
4988 
4989  if (! isp)
4990  invalid_operation (who, "reading");
4991  else
4992  {
4993  scanf_format_list fmt_list (fmt);
4994 
4995  if (fmt_list.num_conversions () == -1)
4996  ::error ("%s: invalid format specified", who.c_str ());
4997 
4998  octave_idx_type nr = -1;
4999  octave_idx_type nc = -1;
5000 
5001  bool one_elt_size_spec;
5002 
5003  get_size (size, nr, nc, one_elt_size_spec, who);
5004 
5005  retval = do_scanf (fmt_list, nr, nc, one_elt_size_spec,
5006  conversion_count, who);
5007  }
5008 
5009  return retval;
5010 }
5011 
5012 bool
5013 octave_base_stream::do_oscanf (const scanf_format_elt *elt,
5014  octave_value& retval, const std::string& who)
5015 {
5016  std::istream *isp = input_stream ();
5017 
5018  if (! isp)
5019  return false;
5020 
5021  bool quit = false;
5022 
5023  std::istream& is = *isp;
5024 
5025  std::ios::fmtflags flags = is.flags ();
5026 
5027  if (elt)
5028  {
5029  const char *fmt = elt->text;
5030 
5031  bool discard = elt->discard;
5032 
5033  switch (elt->type)
5034  {
5037  break;
5038 
5041  break;
5042 
5043  case '%':
5044  {
5045  DO_PCT_CONVERSION ();
5046 
5047  if (! is)
5048  quit = true;
5049  }
5050  break;
5051 
5052  case 'd': case 'i':
5053  {
5054  int tmp;
5055 
5056  if (octave_scan (is, *elt, &tmp))
5057  {
5058  if (! discard)
5059  retval = tmp;
5060  }
5061  else
5062  quit = true;
5063  }
5064  break;
5065 
5066  case 'o': case 'u': case 'x':
5067  {
5068  long int tmp;
5069 
5070  if (octave_scan (is, *elt, &tmp))
5071  {
5072  if (! discard)
5073  retval = tmp;
5074  }
5075  else
5076  quit = true;
5077  }
5078  break;
5079 
5080  case 'e': case 'f': case 'g':
5081  {
5082  double tmp;
5083 
5084  if (octave_scan (is, *elt, &tmp))
5085  {
5086  if (! discard)
5087  retval = tmp;
5088  }
5089  else
5090  quit = true;
5091  }
5092  break;
5093 
5094  case 'c':
5095  {
5096  BEGIN_C_CONVERSION ();
5097 
5098  if (! discard)
5099  retval = tmp;
5100 
5101  if (! is)
5102  quit = true;
5103 
5104  is.setf (flags);
5105  }
5106  break;
5107 
5108  case 's':
5109  {
5110  BEGIN_S_CONVERSION ();
5111 
5112  if (! discard)
5113  retval = tmp;
5114 
5115  if (! is)
5116  quit = true;
5117  }
5118  break;
5119 
5120  case '[':
5121  case '^':
5122  {
5124 
5125  if (! discard)
5126  retval = tmp;
5127 
5128  if (! is)
5129  quit = true;
5130  }
5131  break;
5132 
5133  case 'p':
5134  error ("%s: unsupported format specifier", who.c_str ());
5135  break;
5136 
5137  default:
5138  error ("%s: internal format error", who.c_str ());
5139  break;
5140  }
5141  }
5142 
5143  if (ok () && is.fail ())
5144  {
5145  error ("%s: read error", who.c_str ());
5146 
5147  // FIXME: is this the right thing to do?
5148 
5149  if (octave::application::interactive ()
5150  && ! octave::application::forced_interactive ()
5151  && name () == "stdin")
5152  {
5153  // Skip to end of line.
5154  bool err;
5155  do_gets (-1, err, false, who);
5156  }
5157  }
5158 
5159  return quit;
5160 }
5161 
5164 {
5166 
5167  std::istream *isp = input_stream ();
5168 
5169  if (! isp)
5170  invalid_operation (who, "reading");
5171  else
5172  {
5173  std::istream& is = *isp;
5174 
5175  scanf_format_list fmt_list (fmt);
5176 
5177  octave_idx_type nconv = fmt_list.num_conversions ();
5178 
5179  if (nconv == -1)
5180  ::error ("%s: invalid format specified", who.c_str ());
5181 
5182  is.clear ();
5183 
5184  octave_idx_type len = fmt_list.length ();
5185 
5186  retval.resize (nconv+2, Matrix ());
5187 
5188  const scanf_format_elt *elt = fmt_list.first ();
5189 
5190  int num_values = 0;
5191 
5192  bool quit = false;
5193 
5194  for (octave_idx_type i = 0; i < len; i++)
5195  {
5196  octave_value tmp;
5197 
5198  quit = do_oscanf (elt, tmp, who);
5199 
5200  if (quit)
5201  break;
5202  else
5203  {
5204  if (tmp.is_defined ())
5205  retval(num_values++) = tmp;
5206 
5207  if (! ok ())
5208  break;
5209 
5210  elt = fmt_list.next (nconv > 0);
5211  }
5212  }
5213 
5214  retval(nconv) = num_values;
5215 
5216  int err_num;
5217  retval(nconv+1) = error (false, err_num);
5218 
5219  if (! quit)
5220  {
5221  // Pick up any trailing stuff.
5222  if (ok () && len > nconv)
5223  {
5224  octave_value tmp;
5225 
5226  elt = fmt_list.next ();
5227 
5228  do_oscanf (elt, tmp, who);
5229  }
5230  }
5231  }
5232 
5233  return retval;
5234 }
5235 
5238  octave_idx_type ntimes,
5239  const octave_value_list& options,
5240  const std::string& who,
5241  octave_idx_type& read_count)
5242 {
5243  if (octave::application::interactive () && file_number () == 0)
5244  ::error ("%s: unable to read from stdin while running interactively",
5245  who.c_str ());
5246 
5247  octave_value retval = Cell (dim_vector (1, 1), Matrix (0, 1));
5248 
5249  std::istream *isp = input_stream ();
5250 
5251  if (! isp)
5252  invalid_operation (who, "reading");
5253  else
5254  {
5255  octave::textscan scanner (who);
5256 
5257  retval = scanner.scan (*isp, fmt, ntimes, options, read_count);
5258  }
5259 
5260  return retval;
5261 }
5262 
5263 // Functions that are defined for all output streams
5264 // (output streams are those that define os).
5265 
5266 int
5268 {
5269  int retval = -1;
5270 
5271  std::ostream *os = output_stream ();
5272 
5273  if (! os)
5274  invalid_operation ("fflush", "writing");
5275  else
5276  {
5277  os->flush ();
5278 
5279  if (os->good ())
5280  retval = 0;
5281  }
5282 
5283  return retval;
5284 }
5285 
5286 class
5288 {
5289 public:
5290 
5291  enum state { ok, conversion_error };
5292 
5294  : values (args), val_idx (0), elt_idx (0),
5295  n_vals (values.length ()), n_elts (0), have_data (false),
5296  curr_state (ok)
5297  {
5298  for (octave_idx_type i = 0; i < values.length (); i++)
5299  {
5300  octave_value val = values(i);
5301 
5302  if (val.is_map () || val.is_cell () || val.is_object ())
5303  err_wrong_type_arg (who, val);
5304  }
5305  }
5306 
5308 
5309  // Get the current value as a double and advance the internal pointer.
5310  octave_value get_next_value (char type = 0);
5311 
5312  // Get the current value as an int and advance the internal pointer.
5313  int int_value (void);
5314 
5315  operator bool () const { return (curr_state == ok); }
5316 
5317  bool exhausted (void) { return (val_idx >= n_vals); }
5318 
5319 private:
5320 
5322  int val_idx;
5323  int elt_idx;
5324  int n_vals;
5325  int n_elts;
5329 
5330  // Must create value cache with values!
5331 
5332  printf_value_cache (void);
5333 
5334  // No copying!
5335 
5337 
5338  printf_value_cache& operator = (const printf_value_cache&);
5339 };
5340 
5343 {
5345 
5346  if (exhausted ())
5348 
5349  while (! exhausted ())
5350  {
5351  if (! have_data)
5352  {
5353  curr_val = values (val_idx);
5354 
5355  elt_idx = 0;
5356  n_elts = curr_val.numel ();
5357  have_data = true;
5358  }
5359 
5360  if (elt_idx < n_elts)
5361  {
5362  if (type == 's')
5363  {
5364  if (curr_val.is_string ())
5365  {
5366  dim_vector dv (1, curr_val.numel ());
5368 
5369  std::string sval = tmp.string_value ();
5370 
5371  retval = sval.substr (elt_idx);
5372 
5373  // We've consumed the rest of the value.
5374  elt_idx = n_elts;
5375  }
5376  else
5377  {
5378  // Convert to character string while values are
5379  // integers in the range [0 : char max]
5380  const NDArray val = curr_val.array_value ();
5381 
5382  octave_idx_type idx = elt_idx;
5383 
5384  for (; idx < n_elts; idx++)
5385  {
5386  double dval = val(idx);
5387 
5388  if (octave::math::x_nint (dval) != dval || dval < 0 || dval > 255)
5389  break;
5390  }
5391 
5392  octave_idx_type n = idx - elt_idx;
5393 
5394  if (n > 0)
5395  {
5396  std::string sval (n, '\0');
5397 
5398  for (octave_idx_type i = 0; i < n; i++)
5399  sval[i] = val(elt_idx++);
5400 
5401  retval = sval;
5402  }
5403  else
5404  retval = curr_val.fast_elem_extract (elt_idx++);
5405  }
5406  }
5407  else
5408  {
5409  retval = curr_val.fast_elem_extract (elt_idx++);
5410 
5411  if (type == 'c' && ! retval.is_string ())
5412  {
5413  double dval = retval.double_value ();
5414 
5415  if (octave::math::x_nint (dval) == dval && dval >= 0 && dval < 256)
5416  retval = static_cast<char> (dval);
5417  }
5418  }
5419 
5420  if (elt_idx >= n_elts)
5421  {
5422  elt_idx = 0;
5423  val_idx++;
5424  have_data = false;
5425  }
5426 
5427  break;
5428  }
5429  else
5430  {
5431  val_idx++;
5432  have_data = false;
5433 
5434  if (n_elts == 0)
5435  {
5436  if (elt_idx == 0 && (type == 's' || type == 'c'))
5437  {
5438  retval = "";
5439  break;
5440  }
5441 
5442  if (exhausted ())
5444  }
5445  }
5446  }
5447 
5448  return retval;
5449 }
5450 
5451 int
5453 {
5454  int retval = 0;
5455 
5457 
5458  double dval = val.double_value (true);
5459 
5460  if (octave::math::x_nint (dval) == dval)
5461  retval = octave::math::nint (dval);
5462  else
5464 
5465  return retval;
5466 }
5467 
5468 // Ugh again and again.
5469 
5470 template <typename T>
5471 int
5472 do_printf_conv (std::ostream& os, const char *fmt, int nsa, int sa_1,
5473  int sa_2, T arg, const std::string& who)
5474 {
5475  int retval = 0;
5476 
5477  switch (nsa)
5478  {
5479  case 2:
5480  retval = octave_format (os, fmt, sa_1, sa_2, arg);
5481  break;
5482 
5483  case 1:
5484  retval = octave_format (os, fmt, sa_1, arg);
5485  break;
5486 
5487  case 0:
5488  retval = octave_format (os, fmt, arg);
5489  break;
5490 
5491  default:
5492  ::error ("%s: internal error handling format", who.c_str ());
5493  break;
5494  }
5495 
5496  return retval;
5497 }
5498 
5499 static size_t
5500 do_printf_string (std::ostream& os, const printf_format_elt *elt,
5501  int nsa, int sa_1, int sa_2, const std::string& arg,
5502  const std::string& who)
5503 {
5504  if (nsa > 2)
5505  ::error ("%s: internal error handling format", who.c_str ());
5506 
5507  std::string flags = elt->flags;
5508 
5509  bool left = flags.find ('-') != std::string::npos;
5510 
5511  size_t len = arg.length ();
5512 
5513  size_t fw = nsa > 0 ? sa_1 : (elt->fw == -1 ? len : elt->fw);
5514  size_t prec = nsa > 1 ? sa_2 : (elt->prec == -1 ? len : elt->prec);
5515 
5516  os << std::setw (fw)
5517  << (left ? std::left : std::right)
5518  << (prec < len ? arg.substr (0, prec) : arg);
5519 
5520  return len > fw ? len : fw;
5521 }
5522 
5523 static bool
5525 {
5526  octave_value ov_isnan = val.isnan ();
5527  octave_value ov_isinf = val.isinf ();
5528 
5529  return (ov_isnan.is_true () || ov_isinf.is_true ());
5530 }
5531 
5532 static bool
5534 {
5535  uint64_t limit = std::numeric_limits<int64_t>::max ();
5536 
5537  if (val.is_string ())
5538  return true;
5539  else if (val.is_integer_type ())
5540  {
5541  if (val.is_uint64_type ())
5542  {
5543  octave_uint64 ival = val.uint64_scalar_value ();
5544 
5545  if (ival.value () <= limit)
5546  return true;
5547  }
5548  else
5549  return true;
5550  }
5551  else
5552  {
5553  double dval = val.double_value (true);
5554 
5555  if (dval == octave::math::round (dval) && dval <= limit)
5556  return true;
5557  }
5558 
5559  return false;
5560 }
5561 
5562 static bool
5564 {
5565  if (val.is_string ())
5566  return true;
5567  else if (val.is_integer_type ())
5568  {
5569  // Easier than dispatching here...
5570 
5571  octave_value ov_is_ge_zero
5573 
5574  return ov_is_ge_zero.is_true ();
5575  }
5576  else
5577  {
5578  double dval = val.double_value (true);
5579 
5580  uint64_t limit = std::numeric_limits<uint64_t>::max ();
5581 
5582  if (dval == octave::math::round (dval) && dval >= 0 && dval <= limit)
5583  return true;
5584  }
5585 
5586  return false;
5587 }
5588 
5589 static std::string
5591 {
5592  std::string tfmt = elt->text;
5593 
5594  tfmt.replace (tfmt.rfind (elt->type), 1, "g");
5595 
5596  return tfmt;
5597 }
5598 
5599 int
5601  const printf_format_elt *elt,
5602  int nsa, int sa_1, int sa_2,
5603  const octave_value& val,
5604  const std::string& who)
5605 {
5606  int retval = 0;
5607 
5608  const char *fmt = elt->text;
5609 
5610  if (is_nan_or_inf (val))
5611  {
5612  double dval = val.double_value ();
5613 
5614  std::string tfmt = fmt;
5615  std::string::size_type i1, i2;
5616 
5617  tfmt.replace ((i1 = tfmt.rfind (elt->type)), 1, 1, 's');
5618 
5619  if ((i2 = tfmt.rfind ('.')) != std::string::npos && i2 < i1)
5620  {
5621  tfmt.erase (i2, i1-i2);
5622  if (elt->prec == -2)
5623  nsa--;
5624  }
5625 
5626  const char *tval;
5627  if (lo_ieee_isinf (dval))
5628  {
5629  if (elt->flags.find ('+') != std::string::npos)
5630  tval = (dval < 0 ? "-Inf" : "+Inf");
5631  else
5632  tval = (dval < 0 ? "-Inf" : "Inf");
5633  }
5634  else
5635  {
5636  if (elt->flags.find ('+') != std::string::npos)
5637  tval = (lo_ieee_is_NA (dval) ? "+NA" : "+NaN");
5638  else
5639  tval = (lo_ieee_is_NA (dval) ? "NA" : "NaN");
5640  }
5641 
5642  retval += do_printf_conv (os, tfmt.c_str (), nsa, sa_1, sa_2, tval, who);
5643  }
5644  else
5645  {
5646  static std::string llmod
5647  = sizeof (long) == sizeof (int64_t) ? "l" : "ll";
5648 
5649  char type = elt->type;
5650 
5651  switch (type)
5652  {
5653  case 'd': case 'i': case 'c':
5654  if (ok_for_signed_int_conv (val))
5655  {
5656  octave_int64 tval = val.int64_scalar_value ();
5657 
5658  // Insert "long" modifier.
5659  std::string tfmt = fmt;
5660  tfmt.replace (tfmt.rfind (type), 1, llmod + type);
5661 
5662  retval += do_printf_conv (os, tfmt.c_str (), nsa, sa_1, sa_2,
5663  tval.value (), who);
5664  }
5665  else
5666  {
5667  std::string tfmt = switch_to_g_format (elt);
5668 
5669  double dval = val.double_value (true);
5670 
5671  retval += do_printf_conv (os, tfmt.c_str (), nsa,
5672  sa_1, sa_2, dval, who);
5673  }
5674  break;
5675 
5676  case 'o': case 'x': case 'X': case 'u':
5677  if (ok_for_unsigned_int_conv (val))
5678  {
5679  octave_uint64 tval = val.uint64_scalar_value ();
5680 
5681  // Insert "long" modifier.
5682  std::string tfmt = fmt;
5683  tfmt.replace (tfmt.rfind (type), 1, llmod + type);
5684 
5685  retval += do_printf_conv (os, tfmt.c_str (), nsa, sa_1, sa_2,
5686  tval.value (), who);
5687  }
5688  else
5689  {
5690  std::string tfmt = switch_to_g_format (elt);
5691 
5692  double dval = val.double_value (true);
5693 
5694  retval += do_printf_conv (os, tfmt.c_str (), nsa,
5695  sa_1, sa_2, dval, who);
5696  }
5697  break;
5698 
5699  case 'f': case 'e': case 'E':
5700  case 'g': case 'G':
5701  {
5702  double dval = val.double_value (true);
5703 
5704  retval += do_printf_conv (os, fmt, nsa, sa_1, sa_2, dval, who);
5705  }
5706  break;
5707 
5708  default:
5709  // Note: error is member fcn from octave_base_stream, not ::error.
5710  // This error does not halt execution so "return ..." must exist.
5711  error ("%s: invalid format specifier", who.c_str ());
5712  return -1;
5713  break;
5714  }
5715  }
5716 
5717  return retval;
5718 }
5719 
5720 int
5722  const octave_value_list& args,
5723  const std::string& who)
5724 {
5725  int retval = 0;
5726 
5727  octave_idx_type nconv = fmt_list.num_conversions ();
5728 
5729  std::ostream *osp = output_stream ();
5730 
5731  if (! osp)
5732  invalid_operation (who, "writing");
5733  else
5734  {
5735  std::ostream& os = *osp;
5736 
5737  const printf_format_elt *elt = fmt_list.first ();
5738 
5739  printf_value_cache val_cache (args, who);
5740 
5741  for (;;)
5742  {
5743  octave_quit ();
5744 
5745  if (! elt)
5746  ::error ("%s: internal error handling format", who.c_str ());
5747 
5748  // NSA is the number of 'star' args to convert.
5749  int nsa = (elt->fw == -2) + (elt->prec == -2);
5750 
5751  int sa_1 = 0;
5752  int sa_2 = 0;
5753 
5754  if (nsa > 0)
5755  {
5756  sa_1 = val_cache.int_value ();
5757 
5758  if (! val_cache)
5759  break;
5760  else
5761  {
5762  if (nsa > 1)
5763  {
5764  sa_2 = val_cache.int_value ();
5765 
5766  if (! val_cache)
5767  break;
5768  }
5769  }
5770  }
5771 
5772  if (elt->type == '%')
5773  {
5774  os << "%";
5775  retval++;
5776  }
5777  else if (elt->args == 0 && elt->text)
5778  {
5779  os << elt->text;
5780  retval += strlen (elt->text);
5781  }
5782  else if (elt->type == 's' || elt->type == 'c')
5783  {
5784  octave_value val = val_cache.get_next_value (elt->type);
5785 
5786  if (val_cache)
5787  {
5788  if (val.is_string ())
5789  {
5790  std::string sval = val.string_value ();
5791 
5792  retval += do_printf_string (os, elt, nsa, sa_1,
5793  sa_2, sval, who);
5794  }
5795  else
5796  retval += do_numeric_printf_conv (os, elt, nsa, sa_1,
5797  sa_2, val, who);
5798  }
5799  else
5800  break;
5801  }
5802  else
5803  {
5804  octave_value val = val_cache.get_next_value ();
5805 
5806  if (val_cache)
5807  retval += do_numeric_printf_conv (os, elt, nsa, sa_1,
5808  sa_2, val, who);
5809  else
5810  break;
5811  }
5812 
5813  if (! os)
5814  {
5815  error ("%s: write error", who.c_str ());
5816  break;
5817  }
5818 
5819  elt = fmt_list.next (nconv > 0 && ! val_cache.exhausted ());
5820 
5821  if (! elt || (val_cache.exhausted () && elt->args > 0))
5822  break;
5823  }
5824  }
5825 
5826  return retval;
5827 }
5828 
5829 int
5831  const octave_value_list& args,
5832  const std::string& who)
5833 {
5834  printf_format_list fmt_list (fmt);
5835 
5836  if (fmt_list.num_conversions () == -1)
5837  ::error ("%s: invalid format specified", who.c_str ());
5838 
5839  return do_printf (fmt_list, args, who);
5840 }
5841 
5842 int
5844 {
5845  int retval = -1;
5846 
5847  std::ostream *osp = output_stream ();
5848 
5849  if (! osp)
5850  invalid_operation (who, "writing");
5851  else
5852  {
5853  std::ostream& os = *osp;
5854 
5855  os << s;
5856 
5857  if (! os)
5858  error ("%s: write error", who.c_str ());
5859  else
5860  {
5861  // FIXME: why does this seem to be necessary?
5862  // Without it, output from a loop like
5863  //
5864  // for i = 1:100, fputs (stdout, "foo\n"); endfor
5865  //
5866  // doesn't seem to go to the pager immediately.
5867  os.flush ();
5868 
5869  if (os)
5870  retval = 0;
5871  else
5872  error ("%s: write error", who.c_str ());
5873  }
5874  }
5875 
5876  return retval;
5877 }
5878 
5879 // Return current error message for this stream.
5880 
5882 octave_base_stream::error (bool clear_err, int& err_num)
5883 {
5884  err_num = fail ? -1 : 0;
5885 
5887 
5888  if (clear_err)
5889  clear ();
5890 
5891  return tmp;
5892 }
5893 
5894 void
5896 {
5897  // Note: This calls the member fcn error, not ::error from error.h.
5898  error (who, std::string ("stream not open for ") + rw);
5899 }
5900 
5902  : rep (bs)
5903 {
5904  if (rep)
5905  rep->count = 1;
5906 }
5907 
5909 {
5910  if (rep && --rep->count == 0)
5911  delete rep;
5912 }
5913 
5915  : rep (s.rep)
5916 {
5917  if (rep)
5918  rep->count++;
5919 }
5920 
5923 {
5924  if (rep != s.rep)
5925  {
5926  if (rep && --rep->count == 0)
5927  delete rep;
5928 
5929  rep = s.rep;
5930 
5931  if (rep)
5932  rep->count++;
5933  }
5934 
5935  return *this;
5936 }
5937 
5938 int
5940 {
5941  int retval = -1;
5942 
5943  if (stream_ok ())
5944  retval = rep->flush ();
5945 
5946  return retval;
5947 }
5948 
5951 {
5953 
5954  if (stream_ok ())
5955  retval = rep->getl (max_len, err, who);
5956 
5957  return retval;
5958 }
5959 
5961 octave_stream::getl (const octave_value& tc_max_len, bool& err,
5962  const std::string& who)
5963 {
5964  err = false;
5965 
5966  int conv_err = 0;
5967 
5968  int max_len = -1;
5969 
5970  if (tc_max_len.is_defined ())
5971  {
5972  max_len = convert_to_valid_int (tc_max_len, conv_err);
5973 
5974  if (conv_err || max_len < 0)
5975  {
5976  err = true;
5977  ::error ("%s: invalid maximum length specified", who.c_str ());
5978  }
5979  }
5980 
5981  return getl (max_len, err, who);
5982 }
5983 
5986 {
5988 
5989  if (stream_ok ())
5990  retval = rep->gets (max_len, err, who);
5991 
5992  return retval;
5993 }
5994 
5996 octave_stream::gets (const octave_value& tc_max_len, bool& err,
5997  const std::string& who)
5998 {
5999  err = false;
6000 
6001  int conv_err = 0;
6002 
6003  int max_len = -1;
6004 
6005  if (tc_max_len.is_defined ())
6006  {
6007  max_len = convert_to_valid_int (tc_max_len, conv_err);
6008 
6009  if (conv_err || max_len < 0)
6010  {
6011  err = true;
6012  ::error ("%s: invalid maximum length specified", who.c_str ());
6013  }
6014  }
6015 
6016  return gets (max_len, err, who);
6017 }
6018 
6019 off_t
6020 octave_stream::skipl (off_t count, bool& err, const std::string& who)
6021 {
6022  off_t retval = -1;
6023 
6024  if (stream_ok ())
6025  retval = rep->skipl (count, err, who);
6026 
6027  return retval;
6028 }
6029 
6030 off_t
6031 octave_stream::skipl (const octave_value& tc_count, bool& err,
6032  const std::string& who)
6033 {
6034  err = false;
6035 
6036  int conv_err = 0;
6037 
6038  int count = 1;
6039 
6040  if (tc_count.is_defined ())
6041  {
6042  if (tc_count.is_scalar_type ()
6043  && octave::math::isinf (tc_count.scalar_value ()))
6044  count = -1;
6045  else
6046  {
6047  count = convert_to_valid_int (tc_count, conv_err);
6048 
6049  if (conv_err || count < 0)
6050  {
6051  err = true;
6052  ::error ("%s: invalid number of lines specified", who.c_str ());
6053  }
6054  }
6055  }
6056 
6057  return skipl (count, err, who);
6058 }
6059 
6060 int
6061 octave_stream::seek (off_t offset, int origin)
6062 {
6063  int status = -1;
6064 
6065  if (stream_ok ())
6066  {
6067  clearerr ();
6068 
6069  // Find current position so we can return to it if needed.
6070  off_t orig_pos = rep->tell ();
6071 
6072  // Move to end of file. If successful, find the offset of the end.
6073  status = rep->seek (0, SEEK_END);
6074 
6075  if (status == 0)
6076  {
6077  off_t eof_pos = rep->tell ();
6078 
6079  if (origin == SEEK_CUR)
6080  {
6081  // Move back to original position, otherwise we will be seeking
6082  // from the end of file which is probably not the original
6083  // location.
6084  rep->seek (orig_pos, SEEK_SET);
6085  }
6086 
6087  // Attempt to move to desired position; may be outside bounds of
6088  // existing file.
6089  status = rep->seek (offset, origin);
6090 
6091  if (status == 0)
6092  {
6093  // Where are we after moving to desired position?
6094  off_t desired_pos = rep->tell ();
6095 
6096  // I don't think save_pos can be less than zero,
6097  // but we'll check anyway...
6098  if (desired_pos > eof_pos || desired_pos < 0)
6099  {
6100  // Seek outside bounds of file.
6101  // Failure should leave position unchanged.
6102  rep->seek (orig_pos, SEEK_SET);
6103 
6104  status = -1;
6105  }
6106  }
6107  else
6108  {
6109  // Seeking to the desired position failed.
6110  // Move back to original position and return failure status.
6111  rep->seek (orig_pos, SEEK_SET);
6112 
6113  status = -1;
6114  }
6115  }
6116  }
6117 
6118  return status;
6119 }
6120 
6121 int
6123  const octave_value& tc_origin)
6124 {
6125  int retval = -1;
6126 
6127  // FIXME: should we have octave_value methods that handle off_t explicitly?
6128  octave_int64 val = tc_offset.xint64_scalar_value ("fseek: invalid value for offset");
6129  off_t xoffset = val.value ();
6130 
6131  int conv_err = 0;
6132 
6133  int origin = SEEK_SET;
6134 
6135  if (tc_origin.is_string ())
6136  {
6137  std::string xorigin = tc_origin.string_value ("fseek: invalid value for origin");
6138 
6139  if (xorigin == "bof")
6140  origin = SEEK_SET;
6141  else if (xorigin == "cof")
6142  origin = SEEK_CUR;
6143  else if (xorigin == "eof")
6144  origin = SEEK_END;
6145  else
6146  conv_err = -1;
6147  }
6148  else
6149  {
6150  int xorigin = convert_to_valid_int (tc_origin, conv_err);
6151 
6152  if (! conv_err)
6153  {
6154  if (xorigin == -1)
6155  origin = SEEK_SET;
6156  else if (xorigin == 0)
6157  origin = SEEK_CUR;
6158  else if (xorigin == 1)
6159  origin = SEEK_END;
6160  else
6161  conv_err = -1;
6162  }
6163  }
6164 
6165  if (conv_err)
6166  ::error ("fseek: invalid value for origin");
6167 
6168  retval = seek (xoffset, origin);
6169 
6170  if (retval != 0)
6171  // Note: error is member fcn from octave_stream, not ::error.
6172  error ("fseek: failed to seek to requested position");
6173 
6174  return retval;
6175 }
6176 
6177 off_t
6179 {
6180  off_t retval = -1;
6181 
6182  if (stream_ok ())
6183  retval = rep->tell ();
6184 
6185  return retval;
6186 }
6187 
6188 int
6190 {
6191  return seek (0, SEEK_SET);
6192 }
6193 
6194 bool
6196 {
6197  bool retval = false;
6198 
6199  if (stream_ok ())
6200  retval = rep->is_open ();
6201 
6202  return retval;
6203 }
6204 
6205 void
6207 {
6208  if (stream_ok ())
6209  rep->close ();
6210 }
6211 
6212 // FIXME: maybe these should be defined in lo-ieee.h?
6213 
6214 template <typename T>
6215 static inline bool
6217 {
6218  return false;
6219 }
6220 
6221 template <>
6222 inline bool
6224 {
6225  return __lo_ieee_is_old_NA (val);
6226 }
6227 
6228 template <typename T>
6229 static inline T
6231 {
6232  return val;
6233 }
6234 
6235 template <>
6236 inline double
6238 {
6239  return __lo_ieee_replace_old_NA (val);
6240 }
6241 
6242 template <typename SRC_T, typename DST_T>
6243 static octave_value
6244 convert_and_copy (std::list<void *>& input_buf_list,
6245  octave_idx_type input_buf_elts,
6246  octave_idx_type elts_read,
6247  octave_idx_type nr, octave_idx_type nc, bool swap,
6248  bool do_float_fmt_conv, bool do_NA_conv,
6249  octave::mach_info::float_format from_flt_fmt)
6250 {
6251  typedef typename DST_T::element_type dst_elt_type;
6252 
6253  DST_T conv (dim_vector (nr, nc));
6254 
6255  dst_elt_type *conv_data = conv.fortran_vec ();
6256 
6257  octave_idx_type j = 0;
6258 
6259  for (std::list<void *>::const_iterator it = input_buf_list.begin ();
6260  it != input_buf_list.end (); it++)
6261  {
6262  SRC_T *data = static_cast<SRC_T *> (*it);
6263 
6264  if (swap || do_float_fmt_conv)
6265  {
6266  if (do_NA_conv)
6267  {
6268  for (octave_idx_type i = 0; i < input_buf_elts && j < elts_read;
6269  i++, j++)
6270  {
6271  if (swap)
6272  swap_bytes<sizeof (SRC_T)> (&data[i]);
6273  else if (do_float_fmt_conv)
6274  do_float_format_conversion (&data[i], sizeof (SRC_T),
6275  1, from_flt_fmt,
6277 
6278  dst_elt_type tmp (data[i]);
6279 
6280  if (is_old_NA (tmp))
6281  tmp = replace_old_NA (tmp);
6282 
6283  conv_data[j] = tmp;
6284  }
6285  }
6286  else
6287  {
6288  for (octave_idx_type i = 0; i < input_buf_elts && j < elts_read;
6289  i++, j++)
6290  {
6291  if (swap)
6292  swap_bytes<sizeof (SRC_T)> (&data[i]);
6293  else if (do_float_fmt_conv)
6294  do_float_format_conversion (&data[i], sizeof (SRC_T),
6295  1, from_flt_fmt,
6297 
6298  conv_data[j] = data[i];
6299  }
6300  }
6301  }
6302  else
6303  {
6304  if (do_NA_conv)
6305  {
6306  for (octave_idx_type i = 0; i < input_buf_elts && j < elts_read;
6307  i++, j++)
6308  {
6309  dst_elt_type tmp (data[i]);
6310 
6311  if (is_old_NA (tmp))
6312  tmp = replace_old_NA (tmp);
6313 
6314  conv_data[j] = tmp;
6315  }
6316  }
6317  else
6318  {
6319  for (octave_idx_type i = 0; i < input_buf_elts && j < elts_read;
6320  i++, j++)
6321  conv_data[j] = data[i];
6322  }
6323  }
6324 
6325  delete [] data;
6326  }
6327 
6328  input_buf_list.clear ();
6329 
6330  for (octave_idx_type i = elts_read; i < nr * nc; i++)
6331  conv_data[i] = dst_elt_type (0);
6332 
6333  return conv;
6334 }
6335 
6336 typedef octave_value (*conv_fptr)
6337  (std::list<void *>& input_buf_list, octave_idx_type input_buf_elts,
6339  bool swap, bool do_float_fmt_conv, bool do_NA_conv,
6340  octave::mach_info::float_format from_flt_fmt);
6341 
6342 #define TABLE_ELT(T, U, V, W) \
6343  conv_fptr_table[oct_data_conv::T][oct_data_conv::U] = convert_and_copy<V, W>
6344 
6345 #define FILL_TABLE_ROW(T, V) \
6346  TABLE_ELT (T, dt_int8, V, int8NDArray); \
6347  TABLE_ELT (T, dt_uint8, V, uint8NDArray); \
6348  TABLE_ELT (T, dt_int16, V, int16NDArray); \
6349  TABLE_ELT (T, dt_uint16, V, uint16NDArray); \
6350  TABLE_ELT (T, dt_int32, V, int32NDArray); \
6351  TABLE_ELT (T, dt_uint32, V, uint32NDArray); \
6352  TABLE_ELT (T, dt_int64, V, int64NDArray); \
6353  TABLE_ELT (T, dt_uint64, V, uint64NDArray); \
6354  TABLE_ELT (T, dt_single, V, FloatNDArray); \
6355  TABLE_ELT (T, dt_double, V, NDArray); \
6356  TABLE_ELT (T, dt_char, V, charNDArray); \
6357  TABLE_ELT (T, dt_schar, V, charNDArray); \
6358  TABLE_ELT (T, dt_uchar, V, charNDArray); \
6359  TABLE_ELT (T, dt_logical, V, boolNDArray);
6360 
6362 octave_stream::finalize_read (std::list<void *>& input_buf_list,
6363  octave_idx_type input_buf_elts,
6364  octave_idx_type elts_read,
6366  oct_data_conv::data_type input_type,
6367  oct_data_conv::data_type output_type,
6369 {
6371 
6372  static bool initialized = false;
6373 
6374  // Table function pointers for return types x read types.
6375 
6376  static conv_fptr conv_fptr_table[oct_data_conv::dt_unknown][14];
6377 
6378  if (! initialized)
6379  {
6380  for (int i = 0; i < oct_data_conv::dt_unknown; i++)
6381  for (int j = 0; j < 14; j++)
6382  conv_fptr_table[i][j] = 0;
6383 
6384  FILL_TABLE_ROW (dt_int8, int8_t);
6385  FILL_TABLE_ROW (dt_uint8, uint8_t);
6386  FILL_TABLE_ROW (dt_int16, int16_t);
6387  FILL_TABLE_ROW (dt_uint16, uint16_t);
6388  FILL_TABLE_ROW (dt_int32, int32_t);
6389  FILL_TABLE_ROW (dt_uint32, uint32_t);
6390  FILL_TABLE_ROW (dt_int64, int64_t);
6391  FILL_TABLE_ROW (dt_uint64, uint64_t);
6392  FILL_TABLE_ROW (dt_single, float);
6393  FILL_TABLE_ROW (dt_double, double);
6394  FILL_TABLE_ROW (dt_char, char);
6395  FILL_TABLE_ROW (dt_schar, signed char);
6396  FILL_TABLE_ROW (dt_uchar, unsigned char);
6397  FILL_TABLE_ROW (dt_logical, bool);
6398 
6399  initialized = true;
6400  }
6401 
6402  bool swap = false;
6403 
6405  ffmt = float_format ();
6406 
6409  else
6411 
6412  bool do_float_fmt_conv = ((input_type == oct_data_conv::dt_double
6413  || input_type == oct_data_conv::dt_single)
6414  && ffmt != float_format ());
6415 
6416  bool do_NA_conv = (output_type == oct_data_conv::dt_double);
6417 
6418  switch (output_type)
6419  {
6434  {
6435  conv_fptr fptr = conv_fptr_table[input_type][output_type];
6436 
6437  retval = fptr (input_buf_list, input_buf_elts, elts_read,
6438  nr, nc, swap, do_float_fmt_conv, do_NA_conv, ffmt);
6439  }
6440  break;
6441 
6442  default:
6443  ::error ("read: invalid type specification");
6444  }
6445 
6446  return retval;
6447 }
6448 
6451  oct_data_conv::data_type input_type,
6452  oct_data_conv::data_type output_type,
6454  octave_idx_type& count)
6455 {
6457 
6458  octave_idx_type nr = -1;
6459  octave_idx_type nc = -1;
6460 
6461  bool one_elt_size_spec = false;
6462 
6463  if (! stream_ok ())
6464  return retval;
6465 
6466  // FIXME: we may eventually want to make this extensible.
6467 
6468  // FIXME: we need a better way to ensure that this
6469  // numbering stays consistent with the order of the elements in the
6470  // data_type enum in the oct_data_conv class.
6471 
6472  // Expose this in a future version?
6473  size_t char_count = 0;
6474 
6475  ptrdiff_t tmp_count = 0;
6476 
6477  try
6478  {
6479  get_size (size, nr, nc, one_elt_size_spec, "fread");
6480  }
6481  catch (const octave::execution_exception&)
6482  {
6483  invalid_operation ("fread", "reading");
6484 
6485  return retval;
6486  }
6487 
6488  if (one_elt_size_spec)
6489  {
6490  // If NR == 0, Matlab returns [](0x0).
6491 
6492  // If NR > 0, the result will be a column vector with the given
6493  // number of rows.
6494 
6495  // If NR < 0, then we have Inf and the result will be a column
6496  // vector but we have to wait to see how big NR will be.
6497 
6498  if (nr == 0)
6499  nr = nc = 0;
6500  else
6501  nc = 1;
6502  }
6503  else
6504  {
6505  // Matlab returns [] even if there are two elements in the size
6506  // specification and one is nonzero.
6507 
6508  // If NC < 0 we have [NR, Inf] and we'll wait to decide how big NC
6509  // should be.
6510 
6511  if (nr == 0 || nc == 0)
6512  nr = nc = 0;
6513  }
6514 
6515  // FIXME: Ensure that this does not overflow.
6516  // Maybe try comparing nr * nc computed in double with
6517  // std::numeric_limits<octave_idx_type>::max ();
6518  octave_idx_type elts_to_read = nr * nc;
6519 
6520  bool read_to_eof = elts_to_read < 0;
6521 
6522  octave_idx_type input_buf_elts = -1;
6523 
6524  if (skip == 0)
6525  {
6526  if (read_to_eof)
6527  input_buf_elts = 1024 * 1024;
6528  else
6529  input_buf_elts = elts_to_read;
6530  }
6531  else
6532  input_buf_elts = block_size;
6533 
6534  octave_idx_type input_elt_size
6535  = oct_data_conv::data_type_size (input_type);
6536 
6537  ptrdiff_t input_buf_size
6538  = static_cast<ptrdiff_t> (input_buf_elts) * input_elt_size;
6539 
6540  assert (input_buf_size >= 0);
6541 
6542  // Must also work and return correct type object
6543  // for 0 elements to read.
6544  std::istream *isp = input_stream ();
6545 
6546  if (! isp)
6547  error ("fread: invalid input stream");
6548  else
6549  {
6550  std::istream& is = *isp;
6551 
6552  std::list <void *> input_buf_list;
6553 
6554  while (is && ! is.eof ()
6555  && (read_to_eof || tmp_count < elts_to_read))
6556  {
6557  if (! read_to_eof)
6558  {
6559  octave_idx_type remaining_elts = elts_to_read - tmp_count;
6560 
6561  if (remaining_elts < input_buf_elts)
6562  input_buf_size = remaining_elts * input_elt_size;
6563  }
6564 
6565  char *input_buf = new char [input_buf_size];
6566 
6567  is.read (input_buf, input_buf_size);
6568 
6569  size_t gcount = is.gcount ();
6570 
6571  char_count += gcount;
6572 
6573  octave_idx_type nel = gcount / input_elt_size;
6574 
6575  tmp_count += nel;
6576 
6577  input_buf_list.push_back (input_buf);
6578 
6579  if (is && skip != 0 && nel == block_size)
6580  {
6581  // Seek to skip.
6582  // If skip would move past EOF, position at EOF.
6583 
6584  off_t orig_pos = tell ();
6585 
6586  seek (0, SEEK_END);
6587 
6588  off_t eof_pos = tell ();
6589 
6590  // Is it possible for this to fail to return us to
6591  // the original position?
6592  seek (orig_pos, SEEK_SET);
6593 
6594  off_t remaining = eof_pos - orig_pos;
6595 
6596  if (remaining < skip)
6597  seek (0, SEEK_END);
6598  else
6599  seek (skip, SEEK_CUR);
6600 
6601  if (! is)
6602  break;
6603  }
6604  }
6605 
6606  if (read_to_eof)
6607  {
6608  if (nc < 0)
6609  {
6610  nc = tmp_count / nr;
6611 
6612  if (tmp_count % nr != 0)
6613  nc++;
6614  }
6615  else
6616  nr = tmp_count;
6617  }
6618  else if (tmp_count == 0)
6619  {
6620  nr = 0;
6621  nc = 0;
6622  }
6623  else if (tmp_count != nr * nc)
6624  {
6625  if (tmp_count % nr != 0)
6626  nc = tmp_count / nr + 1;
6627  else
6628  nc = tmp_count / nr;
6629 
6630  if (tmp_count < nr)
6631  nr = tmp_count;
6632  }
6633 
6634  if (tmp_count > std::numeric_limits<octave_idx_type>::max ())
6635  error ("fread: number of elements read exceeds max index size");
6636  else
6637  count = static_cast<octave_idx_type> (tmp_count);
6638 
6639  retval = finalize_read (input_buf_list, input_buf_elts, count,
6640  nr, nc, input_type, output_type, ffmt);
6641  }
6642 
6643  return retval;
6644 }
6645 
6648  oct_data_conv::data_type output_type,
6650 {
6651  octave_idx_type retval = -1;
6652 
6653  if (! stream_ok ())
6654  invalid_operation ("fwrite", "writing");
6655  else
6656  {
6657  if (flt_fmt == octave::mach_info::flt_fmt_unknown)
6658  flt_fmt = float_format ();
6659 
6660  octave_idx_type status = data.write (*this, block_size, output_type,
6661  skip, flt_fmt);
6662 
6663  if (status < 0)
6664  error ("fwrite: write error");
6665  else
6666  retval = status;
6667  }
6668 
6669  return retval;
6670 }
6671 
6672 template <typename T, typename V>
6673 static void
6674 convert_chars (const void *data, void *conv_data, octave_idx_type n_elts)
6675 {
6676  const T *tt_data = static_cast<const T *> (data);
6677 
6678  V *vt_data = static_cast<V *> (conv_data);
6679 
6680  for (octave_idx_type i = 0; i < n_elts; i++)
6681  vt_data[i] = tt_data[i];
6682 }
6683 
6684 template <typename T, typename V>
6685 static void
6686 convert_ints (const T *data, void *conv_data, octave_idx_type n_elts,
6687  bool swap)
6688 {
6689  typedef typename V::val_type val_type;
6690 
6691  val_type *vt_data = static_cast<val_type *> (conv_data);
6692 
6693  for (octave_idx_type i = 0; i < n_elts; i++)
6694  {
6695  // Yes, we want saturation semantics when converting to an integer type.
6696  V val (data[i]);
6697 
6698  vt_data[i] = val.value ();
6699 
6700  if (swap)
6701  swap_bytes<sizeof (val_type)> (&vt_data[i]);
6702  }
6703 }
6704 
6705 template <typename T>
6707 {
6708 public:
6709  typedef T type;
6710 };
6711 
6712 template <typename T>
6714 {
6715 public:
6716  typedef T type;
6717 };
6718 
6719 template <typename T>
6720 static bool
6721 convert_data (const T *data, void *conv_data, octave_idx_type n_elts,
6722  oct_data_conv::data_type output_type,
6724 {
6725  bool retval = true;
6726 
6727  bool swap = false;
6728 
6731  else
6732  swap = (flt_fmt == octave::mach_info::flt_fmt_ieee_big_endian);
6733 
6734  bool do_float_conversion = flt_fmt != octave::mach_info::float_format ();
6735 
6736  typedef typename ultimate_element_type<T>::type ult_elt_type;
6737 
6738  switch (output_type)
6739  {
6741  convert_chars<ult_elt_type, char> (data, conv_data, n_elts);
6742  break;
6743 
6745  convert_chars<ult_elt_type, signed char> (data, conv_data, n_elts);
6746  break;
6747 
6749  convert_chars<ult_elt_type, unsigned char> (data, conv_data, n_elts);
6750  break;
6751 
6753  convert_ints<T, octave_int8> (data, conv_data, n_elts, swap);
6754  break;
6755 
6757  convert_ints<T, octave_uint8> (data, conv_data, n_elts, swap);
6758  break;
6759 
6761  convert_ints<T, octave_int16> (data, conv_data, n_elts, swap);
6762  break;
6763 
6765  convert_ints<T, octave_uint16> (data, conv_data, n_elts, swap);
6766  break;
6767 
6769  convert_ints<T, octave_int32> (data, conv_data, n_elts, swap);
6770  break;
6771 
6773  convert_ints<T, octave_uint32> (data, conv_data, n_elts, swap);
6774  break;
6775 
6777  convert_ints<T, octave_int64> (data, conv_data, n_elts, swap);
6778  break;
6779 
6781  convert_ints<T, octave_uint64> (data, conv_data, n_elts, swap);
6782  break;
6783 
6785  {
6786  float *vt_data = static_cast<float *> (conv_data);
6787 
6788  for (octave_idx_type i = 0; i < n_elts; i++)
6789  {
6790  vt_data[i] = data[i];
6791 
6792  if (do_float_conversion)
6793  do_float_format_conversion (&vt_data[i], 1, flt_fmt);
6794  }
6795  }
6796  break;
6797 
6799  {
6800  double *vt_data = static_cast<double *> (conv_data);
6801 
6802  for (octave_idx_type i = 0; i < n_elts; i++)
6803  {
6804  vt_data[i] = data[i];
6805 
6806  if (do_float_conversion)
6807  do_double_format_conversion (&vt_data[i], 1, flt_fmt);
6808  }
6809  }
6810  break;
6811 
6812  default:
6813  ::error ("write: invalid type specification");
6814  }
6815 
6816  return retval;
6817 }
6818 
6819 bool
6820 octave_stream::write_bytes (const void *data, size_t nbytes)
6821 {
6822  bool status = false;
6823 
6824  std::ostream *osp = output_stream ();
6825 
6826  if (osp)
6827  {
6828  std::ostream& os = *osp;
6829 
6830  if (os)
6831  {
6832  os.write (static_cast<const char *> (data), nbytes);
6833 
6834  if (os)
6835  status = true;
6836  }
6837  }
6838 
6839  return status;
6840 }
6841 
6842 bool
6844 {
6845  bool status = false;
6846 
6847  std::ostream *osp = output_stream ();
6848 
6849  if (! osp)
6850  return false;
6851 
6852  std::ostream& os = *osp;
6853 
6854  // Seek to skip when inside bounds of existing file.
6855  // Otherwise, write NUL to skip.
6856  off_t orig_pos = tell ();
6857 
6858  seek (0, SEEK_END);
6859 
6860  off_t eof_pos = tell ();
6861 
6862  // Is it possible for this to fail to return us to the original position?
6863  seek (orig_pos, SEEK_SET);
6864 
6865  size_t remaining = eof_pos - orig_pos;
6866 
6867  if (remaining < skip)
6868  {
6869  seek (0, SEEK_END);
6870 
6871  // FIXME: probably should try to write larger blocks...
6872  unsigned char zero = 0;
6873  for (size_t j = 0; j < skip - remaining; j++)
6874  os.write (reinterpret_cast<const char *> (&zero), 1);
6875  }
6876  else
6877  seek (skip, SEEK_CUR);
6878 
6879  if (os)
6880  status = true;
6881 
6882  return status;
6883 }
6884 
6885 template <typename T>
6888  oct_data_conv::data_type output_type,
6889  octave_idx_type skip,
6891 {
6892  bool swap = false;
6893 
6896  else
6897  swap = (flt_fmt == octave::mach_info::flt_fmt_ieee_big_endian);
6898 
6899  bool do_data_conversion = (swap || ! is_equivalent_type<T> (output_type)
6900  || flt_fmt != octave::mach_info::float_format ());
6901 
6902  octave_idx_type nel = data.numel ();
6903 
6904  octave_idx_type chunk_size;
6905 
6906  if (skip != 0)
6907  chunk_size = block_size;
6908  else if (do_data_conversion)
6909  chunk_size = 1024 * 1024;
6910  else
6911  chunk_size = nel;
6912 
6913  octave_idx_type i = 0;
6914 
6915  const T *pdata = data.data ();
6916 
6917  while (i < nel)
6918  {
6919  if (skip != 0)
6920  {
6921  if (! skip_bytes (skip))
6922  return -1;
6923  }
6924 
6925  octave_idx_type remaining_nel = nel - i;
6926 
6927  if (chunk_size > remaining_nel)
6928  chunk_size = remaining_nel;
6929 
6930  bool status = false;
6931 
6932  if (do_data_conversion)
6933  {
6934  size_t output_size
6935  = chunk_size * oct_data_conv::data_type_size (output_type);
6936 
6937  OCTAVE_LOCAL_BUFFER (unsigned char, conv_data, output_size);
6938 
6939  status = convert_data (&pdata[i], conv_data, chunk_size,
6940  output_type, flt_fmt);
6941 
6942  if (status)
6943  status = write_bytes (conv_data, output_size);
6944  }
6945  else
6946  status = write_bytes (pdata, sizeof (T) * chunk_size);
6947 
6948  if (! status)
6949  return -1;
6950 
6951  i += chunk_size;
6952  }
6953 
6954  return nel;
6955 }
6956 
6957 #define INSTANTIATE_WRITE(T) \
6958  template \
6959  octave_idx_type \
6960  octave_stream::write (const Array<T>& data, octave_idx_type block_size, \
6961  oct_data_conv::data_type output_type, \
6962  octave_idx_type skip, \
6963  octave::mach_info::float_format flt_fmt)
6964 
6973 INSTANTIATE_WRITE (int8_t);
6974 INSTANTIATE_WRITE (uint8_t);
6975 INSTANTIATE_WRITE (int16_t);
6976 INSTANTIATE_WRITE (uint16_t);
6977 INSTANTIATE_WRITE (int32_t);
6978 INSTANTIATE_WRITE (uint32_t);
6979 INSTANTIATE_WRITE (int64_t);
6980 INSTANTIATE_WRITE (uint64_t);
6981 INSTANTIATE_WRITE (bool);
6982 #if defined (OCTAVE_HAVE_OVERLOAD_CHAR_INT8_TYPES)
6983 INSTANTIATE_WRITE (char);
6984 #endif
6985 INSTANTIATE_WRITE (float);
6986 INSTANTIATE_WRITE (double);
6987 
6990  octave_idx_type& count, const std::string& who)
6991 {
6993 
6994  if (stream_ok ())
6995  retval = rep->scanf (fmt, size, count, who);
6996 
6997  return retval;
6998 }
6999 
7002  octave_idx_type& count, const std::string& who)
7003 {
7004  octave_value retval = Matrix ();
7005 
7006  if (fmt.is_string ())
7007  {
7008  std::string sfmt = fmt.string_value ();
7009 
7010  if (fmt.is_sq_string ())
7011  sfmt = do_string_escapes (sfmt);
7012 
7013  retval = scanf (sfmt, size, count, who);
7014  }
7015  else
7016  {
7017  // Note: error is member fcn from octave_stream, not ::error.
7018  error (who + ": format must be a string");
7019  }
7020 
7021  return retval;
7022 }
7023 
7026 {
7028 
7029  if (stream_ok ())
7030  retval = rep->oscanf (fmt, who);
7031 
7032  return retval;
7033 }
7034 
7037 {
7039 
7040  if (fmt.is_string ())
7041  {
7042  std::string sfmt = fmt.string_value ();
7043 
7044  if (fmt.is_sq_string ())
7045  sfmt = do_string_escapes (sfmt);
7046 
7047  retval = oscanf (sfmt, who);
7048  }
7049  else
7050  {
7051  // Note: error is member fcn from octave_stream, not ::error.
7052  error (who + ": format must be a string");
7053  }
7054 
7055  return retval;
7056 }
7057 
7060  const octave_value_list& options,
7061  const std::string& who, octave_idx_type& count)
7062 {
7063  return (stream_ok ()
7064  ? rep->do_textscan (fmt, ntimes, options, who, count)
7065  : octave_value ());
7066 }
7067 
7068 int
7070  const std::string& who)
7071 {
7072  int retval = -1;
7073 
7074  if (stream_ok ())
7075  retval = rep->printf (fmt, args, who);
7076 
7077  return retval;
7078 }
7079 
7080 int
7082  const std::string& who)
7083 {
7084  int retval = 0;
7085 
7086  if (fmt.is_string ())
7087  {
7088  std::string sfmt = fmt.string_value ();
7089 
7090  if (fmt.is_sq_string ())
7091  sfmt = do_string_escapes (sfmt);
7092 
7093  retval = printf (sfmt, args, who);
7094  }
7095  else
7096  {
7097  // Note: error is member fcn from octave_stream, not ::error.
7098  error (who + ": format must be a string");
7099  }
7100 
7101  return retval;
7102 }
7103 
7104 int
7106 {
7107  int retval = -1;
7108 
7109  if (stream_ok ())
7110  retval = rep->puts (s, who);
7111 
7112  return retval;
7113 }
7114 
7115 // FIXME: maybe this should work for string arrays too.
7116 
7117 int
7119 {
7120  int retval = -1;
7121 
7122  if (tc_s.is_string ())
7123  {
7124  std::string s = tc_s.string_value ();
7125  retval = puts (s, who);
7126  }
7127  else
7128  {
7129  // Note: error is member fcn from octave_stream, not ::error.
7130  error (who + ": argument must be a string");
7131  }
7132 
7133  return retval;
7134 }
7135 
7136 bool
7138 {
7139  int retval = -1;
7140 
7141  if (stream_ok ())
7142  retval = rep->eof ();
7143 
7144  return retval;
7145 }
7146 
7148 octave_stream::error (bool clear, int& err_num)
7149 {
7150  std::string retval = "invalid stream object";
7151 
7152  if (stream_ok (false))
7153  retval = rep->error (clear, err_num);
7154 
7155  return retval;
7156 }
7157 
7160 {
7162 
7163  if (stream_ok ())
7164  retval = rep->name ();
7165 
7166  return retval;
7167 }
7168 
7169 int
7171 {
7172  int retval = 0;
7173 
7174  if (stream_ok ())
7175  retval = rep->mode ();
7176 
7177  return retval;
7178 }
7179 
7182 {
7184 
7185  if (stream_ok ())
7186  retval = rep->float_format ();
7187 
7188  return retval;
7189 }
7190 
7193 {
7194  std::string retval = "???";
7195  std::ios::openmode in_mode = static_cast<std::ios::openmode> (mode);
7196 
7197  if (in_mode == std::ios::in)
7198  retval = "r";
7199  else if (in_mode == std::ios::out
7200  || in_mode == (std::ios::out | std::ios::trunc))
7201  retval = "w";
7202  else if (in_mode == (std::ios::out | std::ios::app))
7203  retval = "a";
7204  else if (in_mode == (std::ios::in | std::ios::out))
7205  retval = "r+";
7206  else if (in_mode == (std::ios::in | std::ios::out | std::ios::trunc))
7207  retval = "w+";
7208  else if (in_mode == (std::ios::in | std::ios::out | std::ios::ate))
7209  retval = "a+";
7210  else if (in_mode == (std::ios::in | std::ios::binary))
7211  retval = "rb";
7212  else if (in_mode == (std::ios::out | std::ios::binary)
7213  || in_mode == (std::ios::out | std::ios::trunc | std::ios::binary))
7214  retval = "wb";
7215  else if (in_mode == (std::ios::out | std::ios::app | std::ios::binary))
7216  retval = "ab";
7217  else if (in_mode == (std::ios::in | std::ios::out | std::ios::binary))
7218  retval = "r+b";
7219  else if (in_mode == (std::ios::in | std::ios::out | std::ios::trunc
7220  | std::ios::binary))
7221  retval = "w+b";
7222  else if (in_mode == (std::ios::in | std::ios::out | std::ios::ate
7223  | std::ios::binary))
7224  retval = "a+b";
7225 
7226  return retval;
7227 }
7228 
7230 
7231 bool
7233 {
7234  bool retval = true;
7235 
7236  if (! instance)
7237  {
7238  instance = new octave_stream_list ();
7239 
7240  if (instance)
7242  }
7243 
7244  if (! instance)
7245  ::error ("unable to create stream list object!");
7246 
7247  return retval;
7248 }
7249 
7250 int
7252 {
7253  return (instance_ok ()) ? instance->do_insert (os) : -1;
7254 }
7255 
7258 {
7259  return (instance_ok ()) ? instance->do_lookup (fid, who) : octave_stream ();
7260 }
7261 
7264 {
7265  return (instance_ok ()) ? instance->do_lookup (fid, who) : octave_stream ();
7266 }
7267 
7268 int
7270 {
7271  return (instance_ok ()) ? instance->do_remove (fid, who) : -1;
7272 }
7273 
7274 int
7276 {
7277  return (instance_ok ()) ? instance->do_remove (fid, who) : -1;
7278 }
7279 
7280 void
7282 {
7283  if (instance)
7284  instance->do_clear (flush);
7285 }
7286 
7289 {
7290  return (instance_ok ()) ? instance->do_get_info (fid) : string_vector ();
7291 }
7292 
7295 {
7296  return (instance_ok ()) ? instance->do_get_info (fid) : string_vector ();
7297 }
7298 
7301 {
7302  return (instance_ok ()) ? instance->do_list_open_files () : "";
7303 }
7304 
7307 {
7308  return (instance_ok ())
7310 }
7311 
7312 int
7314 {
7315  return (instance_ok ()) ? instance->do_get_file_number (fid) : -1;
7316 }
7317 
7318 int
7320 {
7321  // Insert item with key corresponding to file-descriptor.
7322 
7323  int stream_number = os.file_number ();
7324 
7325  if (stream_number == -1)
7326  return stream_number;
7327 
7328  // Should we test for
7329  //
7330  // (list.find (stream_number) != list.end ()
7331  // && list[stream_number].is_open ())
7332  //
7333  // and respond with "error ("internal error: ...")"? It should not
7334  // happen except for some bug or if the user has opened a stream with
7335  // an interpreted command, but closed it directly with a system call
7336  // in an oct-file; then the kernel knows the fd is free, but Octave
7337  // does not know. If it happens, it should not do harm here to simply
7338  // overwrite this entry, although the wrong entry might have done harm
7339  // before.
7340 
7341  if (list.size () >= list.max_size ())
7342  ::error ("could not create file id");
7343 
7344  list[stream_number] = os;
7345 
7346  return stream_number;
7347 }
7348 
7349 OCTAVE_NORETURN static
7350 void
7351 err_invalid_file_id (int fid, const std::string& who)
7352 {
7353  if (who.empty ())
7354  ::error ("invalid stream number = %d", fid);
7355  else
7356  ::error ("%s: invalid stream number = %d", who.c_str (), fid);
7357 }
7358 
7360 octave_stream_list::do_lookup (int fid, const std::string& who) const
7361 {
7363 
7364  if (fid < 0)
7365  err_invalid_file_id (fid, who);
7366 
7367  if (lookup_cache != list.end () && lookup_cache->first == fid)
7368  retval = lookup_cache->second;
7369  else
7370  {
7371  ostrl_map::const_iterator iter = list.find (fid);
7372 
7373  if (iter == list.end ())
7374  err_invalid_file_id (fid, who);
7375 
7376  retval = iter->second;
7377  lookup_cache = iter;
7378  }
7379 
7380  return retval;
7381 }
7382 
7385  const std::string& who) const
7386 {
7387  int i = get_file_number (fid);
7388 
7389  return do_lookup (i, who);
7390 }
7391 
7392 int
7394 {
7395  // Can't remove stdin (std::cin), stdout (std::cout), or stderr (std::cerr).
7396  if (fid < 3)
7397  err_invalid_file_id (fid, who);
7398 
7399  ostrl_map::iterator iter = list.find (fid);
7400 
7401  if (iter == list.end ())
7402  err_invalid_file_id (fid, who);
7403 
7404  octave_stream os = iter->second;
7405  list.erase (iter);
7406  lookup_cache = list.end ();
7407 
7408  // FIXME: is this check redundant?
7409  if (! os.is_valid ())
7410  err_invalid_file_id (fid, who);
7411 
7412  os.close ();
7413 
7414  return 0;
7415 }
7416 
7417 int
7419 {
7420  int retval = -1;
7421 
7422  if (fid.is_string () && fid.string_value () == "all")
7423  {
7424  do_clear (false);
7425 
7426  retval = 0;
7427  }
7428  else
7429  {
7430  int i = get_file_number (fid);
7431 
7432  retval = do_remove (i, who);
7433  }
7434 
7435  return retval;
7436 }
7437 
7438 void
7440 {
7441  if (flush)
7442  {
7443  // Flush stdout and stderr.
7444  list[1].flush ();
7445  list[2].flush ();
7446  }
7447 
7448  for (ostrl_map::iterator iter = list.begin (); iter != list.end (); )
7449  {
7450  int fid = iter->first;
7451  if (fid < 3) // Don't delete stdin, stdout, stderr
7452  {
7453  iter++;
7454  continue;
7455  }
7456 
7457  octave_stream os = iter->second;
7458 
7459  std::string name = os.name ();
7460  std::transform (name.begin (), name.end (), name.begin (), tolower);
7461 
7462  // FIXME: This test for gnuplot is hardly foolproof.
7463  if (name.find ("gnuplot") != std::string::npos)
7464  {
7465  // Don't close down pipes to gnuplot
7466  iter++;
7467  continue;
7468  }
7469 
7470  // Normal file handle. Close and delete from list.
7471  if (os.is_valid ())
7472  os.close ();
7473 
7474  list.erase (iter++);
7475  }
7476 
7477  lookup_cache = list.end ();
7478 }
7479 
7482 {
7483  octave_stream os = do_lookup (fid);
7484 
7485  if (! os.is_valid ())
7486  ::error ("invalid file id = %d", fid);
7487 
7488  string_vector retval (3);
7489 
7490  retval(0) = os.name ();
7493 
7494  return retval;
7495 }
7496 
7499 {
7500  int conv_err = 0;
7501 
7502  int int_fid = convert_to_valid_int (fid, conv_err);
7503 
7504  if (conv_err)
7505  ::error ("file id must be a file object or integer value");
7506 
7507  return do_get_info (int_fid);
7508 }
7509 
7512 {
7513  std::ostringstream buf;
7514 
7515  buf << "\n"
7516  << " number mode arch name\n"
7517  << " ------ ---- ---- ----\n";
7518 
7519  for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++)
7520  {
7521  octave_stream os = p->second;
7522 
7523  buf << " "
7524  << std::setiosflags (std::ios::right)
7525  << std::setw (4) << p->first << " "
7526  // reset necessary in addition to setiosflags since this is one stmt.
7527  << std::resetiosflags (std::ios::adjustfield)
7528  << std::setiosflags (std::ios::left)
7529  << std::setw (3)
7531  << " "
7532  << std::setw (9)
7534  << " "
7535  << os.name () << "\n";
7536  }
7537 
7538  buf << "\n";
7539 
7540  return buf.str ();
7541 }
7542 
7545 {
7546  Matrix retval (1, list.size (), 0.0);
7547 
7548  int num_open = 0;
7549 
7550  for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++)
7551  {
7552  // Skip stdin, stdout, and stderr.
7553  if (p->first > 2 && p->second)
7554  retval(0,num_open++) = p->first;
7555  }
7556 
7557  retval.resize ((num_open > 0), num_open);
7558 
7559  return retval;
7560 }
7561 
7562 int
7564 {
7565  int retval = -1;
7566 
7567  if (fid.is_string ())
7568  {
7569  std::string nm = fid.string_value ();
7570 
7571  for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++)
7572  {
7573  // stdin, stdout, and stderr are unnamed.
7574  if (p->first > 2)
7575  {
7576  octave_stream os = p->second;
7577 
7578  if (os && os.name () == nm)
7579  {
7580  retval = p->first;
7581  break;
7582  }
7583  }
7584  }
7585  }
7586  else
7587  {
7588  int conv_err = 0;
7589 
7590  int int_fid = convert_to_valid_int (fid, conv_err);
7591 
7592  if (conv_err)
7593  ::error ("file id must be a file object, std::string, or integer value");
7594 
7595  retval = int_fid;
7596  }
7597 
7598  return retval;
7599 }
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:803
int scan_caret(delimited_stream &is, const std::string &pattern, std::string &val) const
Definition: oct-stream.cc:3091
octave_value(* conv_fptr)(std::list< void * > &input_buf_list, octave_idx_type input_buf_elts, octave_idx_type elts_read, octave_idx_type nr, octave_idx_type nc, bool swap, bool do_float_fmt_conv, bool do_NA_conv, octave::mach_info::float_format from_flt_fmt)
Definition: oct-stream.cc:6337
bool is_object(void) const
Definition: ov.h:593
void invalid_operation(const std::string &who, const char *rw)
Definition: oct-stream.h:395
std::list< octave_value > out_buf(void) const
Definition: oct-stream.cc:1752
~scanf_format_elt(void)
Definition: oct-stream.cc:220
octave_int64 xint64_scalar_value(const char *fmt,...) const
Definition: ov.cc:2105
bool multiple_delims_as_one
Definition: oct-stream.cc:1873
bool skip_bytes(size_t n_elts)
Definition: oct-stream.cc:6843
bool is_empty(void) const
Definition: Array.h:575
static int left
Definition: randmtzig.cc:185
static OCTAVE_NORETURN void err_invalid_file_id(int fid, const std::string &who)
Definition: oct-stream.cc:7351
#define DO_LITERAL_CONVERSION()
Definition: oct-stream.cc:4377
F77_RET_T const F77_INT const F77_INT const F77_INT const F77_DBLE const F77_DBLE F77_INT F77_DBLE * V
#define DO_PCT_CONVERSION()
Definition: oct-stream.cc:4404
octave_value empty_value
Definition: oct-stream.cc:1858
#define lo_ieee_is_NA(x)
Definition: lo-ieee.h:115
Octave interface to the compression and uncompression libraries.
Definition: aepbalance.cc:47
Definition: Cell.h:37
size_t numel(void) const
Definition: oct-stream.cc:1707
void scan_cstring(delimited_stream &is, const textscan_format_elt &fmt, std::string &val) const
Definition: oct-stream.cc:3246
static std::string expand_char_class(const std::string &s)
Definition: oct-stream.cc:435
const printf_format_elt * first(void)
Definition: oct-stream.cc:804
std::ostringstream buf
Definition: oct-stream.cc:1770
void clear(void)
Definition: ovl.h:152
bool is_real_type(void) const
Definition: ov.h:667
std::list< octave_value > output_container
Definition: oct-stream.cc:1767
bool isspace(unsigned int ch) const
Definition: oct-stream.cc:1933
void scan_one(delimited_stream &is, const textscan_format_elt &fmt, octave_value &ov, Array< octave_idx_type > row)
Definition: oct-stream.cc:3267
void printme(void) const
Definition: oct-stream.cc:649
bool last_elt_p(void)
Definition: oct-stream.cc:832
bool is_open(void) const
Definition: oct-stream.h:107
double __lo_ieee_replace_old_NA(double x)
Definition: lo-ieee.cc:101
void scan_string(delimited_stream &is, const textscan_format_elt &fmt, std::string &val) const
Definition: oct-stream.cc:3160
const octave_base_value const Array< octave_idx_type > & ra_idx
octave_value reshape(const dim_vector &dv) const
Definition: ov.h:515
void parse_options(const octave_value_list &args, textscan_format_list &fmt_list)
Definition: oct-stream.cc:3544
octave_value do_cat_op(const octave_value &v1, const octave_value &v2, const Array< octave_idx_type > &ra_idx)
Definition: ov.cc:2456
int rewind(void)
Definition: oct-stream.cc:6189
std::string delims
Definition: oct-stream.cc:1835
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:145
virtual off_t tell(void)=0
void setstate(std::ios_base::iostate m)
Definition: oct-stream.cc:1293
octave_idx_type buffer_size
Definition: oct-stream.cc:1845
octave_idx_type write(const octave_value &data, octave_idx_type block_size, oct_data_conv::data_type output_type, octave_idx_type skip, octave::mach_info::float_format flt_fmt)
Definition: oct-stream.cc:6647
octave::mach_info::float_format float_format(void) const
Definition: oct-stream.cc:7181
int do_remove(int fid, const std::string &who="")
Definition: oct-stream.cc:7393
std::string delim_table
Definition: oct-stream.cc:1832
static string_vector get_info(int fid)
Definition: oct-stream.cc:7288
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
void seekg(char *old_idx)
Definition: oct-stream.cc:1280
static bool is_old_NA(T)
Definition: oct-stream.cc:6216
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:5068
static octave_idx_type nn
Definition: DASPK.cc:71
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE const F77_DBLE * f
printf_format_elt(const printf_format_elt &e)
Definition: oct-stream.cc:747
std::string read_until(delimited_stream &is, const Cell &delimiters, const std::string &ends) const
Definition: oct-stream.cc:3116
octave_idx_type length(void) const
Definition: ovl.h:96
OCTINTERP_API std::string undo_string_escapes(const std::string &s)
std::ostringstream buf
Definition: oct-stream.cc:312
static octave_stream_list * instance
Definition: oct-stream.h:456
Return the CPU time used by your Octave session The first output is the total time spent executing your process and is equal to the sum of second and third which are the number of CPU seconds spent executing in user mode and the number of CPU seconds spent executing in system mode
Definition: data.cc:6386
std::string gets(octave_idx_type max_len, bool &err, const std::string &who)
Definition: oct-stream.cc:5985
bool is_scalar_type(void) const
Definition: ov.h:673
bool is_open(void) const
Definition: oct-stream.cc:6195
int seek(off_t offset, int origin)
Definition: oct-stream.cc:6061
void process_conversion(const std::string &s, size_t &i, size_t n, int &width, bool &discard, char &type, char &modifier)
Definition: oct-stream.cc:471
void do_clear(bool flush=true)
Definition: oct-stream.cc:7439
bool is_defined(void) const
Definition: ov.h:536
textscan(const std::string &who_arg="textscan")
Definition: oct-stream.cc:2540
double trunc(double x)
Definition: lo-mappers.cc:327
static double pown(double x, unsigned int n)
Definition: oct-stream.cc:1181
virtual std::istream * input_stream(void)
Definition: oct-stream.h:97
static std::string switch_to_g_format(const printf_format_elt *elt)
Definition: oct-stream.cc:5590
octave_base_stream * rep
Definition: oct-stream.h:378
void clear(std::ios_base::iostate m=(std::ios_base::eofbit &~std::ios_base::eofbit))
Definition: oct-stream.cc:1295
octave_int< T > mod(const octave_int< T > &x, const octave_int< T > &y)
Definition: oct-inttypes.h:977
static char * strsave(const char *s)
Definition: main.cc:183
for large enough k
Definition: lu.cc:606
int finish_conversion(const std::string &s, size_t &i, size_t n, unsigned int &width, int &prec, int &bitwidth, octave_value &val_type, bool discard, char &type)
Definition: oct-stream.cc:2364
void add_elt_to_list(unsigned int width, int prec, int bitwidth, octave_value val_type, bool discard, char type, const std::string &char_class=std::string())
Definition: oct-stream.cc:2057
octave_stream_list(void)
Definition: oct-stream.h:417
~scanf_format_list(void)
Definition: oct-stream.cc:403
void finish_conversion(const std::string &s, size_t &i, int args, const std::string &flags, int fw, int prec, char modifier, char &type)
Definition: oct-stream.cc:1103
void error(const char *fmt,...)
Definition: error.cc:570
textscan_format_list(const std::string &fmt=std::string(), const std::string &who="textscan")
Definition: oct-stream.cc:1945
octave_value get_next_value(char type=0)
Definition: oct-stream.cc:5342
octave_idx_type nconv
Definition: oct-stream.cc:303
is greater than zero
Definition: load-path.cc:2339
static bool instance_ok(void)
Definition: oct-stream.cc:7232
bool exhausted(void)
Definition: oct-stream.cc:5317
STL namespace.
virtual std::string name(void) const =0
octave_value scanf(const std::string &fmt, const Array< double > &size, octave_idx_type &count, const std::string &who)
Definition: oct-stream.cc:4979
const char * text
Definition: oct-stream.cc:223
textscan_format_elt(const textscan_format_elt &e)
Definition: oct-stream.cc:1635
size_type size(const size_type d) const
Size of the specified dimension.
Definition: Array.h:428
off_t skipl(off_t count, bool &err, const std::string &who)
Definition: oct-stream.cc:6020
printf_value_cache(const octave_value_list &args, const std::string &who)
Definition: oct-stream.cc:5293
bool ok(void) const
Definition: oct-stream.h:134
octave::mach_info::float_format flt_fmt
Definition: load-save.cc:723
virtual bool fast_elem_insert(octave_idx_type n, const octave_value &x)
Definition: ov-base.cc:1404
octave_value do_scanf(scanf_format_list &fmt_list, octave_idx_type nr, octave_idx_type nc, bool one_elt_size_spec, octave_idx_type &count, const std::string &who)
Definition: oct-stream.cc:4583
octave_value isinf(void) const
Definition: ov.h:1374
bool is_cell(void) const
Definition: ov.h:545
bool whitespace_delim(void) const
Definition: oct-stream.cc:1936
~printf_format_elt(void)
Definition: oct-stream.cc:768
#define lo_ieee_isinf(x)
Definition: lo-ieee.h:111
int mode(void) const
Definition: oct-stream.cc:7170
bool ok(void) const
Definition: oct-stream.cc:836
bool is_delim(unsigned char ch) const
Definition: oct-stream.cc:1927
int finish_conversion(const std::string &s, size_t &i, size_t n, int &width, bool discard, char &type, char modifier)
Definition: oct-stream.cc:573
double scalar_value(bool frc_str_conv=false) const
Definition: ov.h:781
std::string char_class
Definition: oct-stream.cc:239
#define BEGIN_S_CONVERSION()
Definition: oct-stream.cc:4443
s
Definition: file-io.cc:2682
#define DO_WHITESPACE_CONVERSION()
Definition: oct-stream.cc:4363
int do_get_file_number(const octave_value &fid) const
Definition: oct-stream.cc:7563
const octave_value_list values
Definition: oct-stream.cc:5321
std::string flags
Definition: oct-stream.cc:783
in this the arguments are accumulated from left to right
Definition: data.cc:393
std::istream * input_stream(void)
Definition: oct-stream.h:363
std::string who
Definition: oct-stream.cc:1820
i e
Definition: data.cc:2724
when function syntax is used
Definition: debug.cc:1099
#define SEEK_CUR
octave_idx_type nconv
Definition: oct-stream.cc:844
bool all_numeric_conversions(void)
Definition: oct-stream.cc:707
static size_t do_printf_string(std::ostream &os, const printf_format_elt *elt, int nsa, int sa_1, int sa_2, const std::string &arg, const std::string &who)
Definition: oct-stream.cc:5500
static bool ok_for_signed_int_conv(const octave_value &val)
Definition: oct-stream.cc:5533
octave_value arg
Definition: pr-output.cc:3440
double round(double x)
Definition: lo-mappers.cc:333
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
#define lo_ieee_isnan(x)
Definition: lo-ieee.h:103
std::streampos buf_in_file
Definition: oct-stream.cc:1339
printf_format_elt(const char *txt=0, int n=0, int w=-1, int p=-1, const std::string &f="", char typ= '\0', char mod= '\0')
Definition: oct-stream.cc:740
virtual std::ostream * output_stream(void)
Definition: oct-stream.h:103
cell array If invoked with two or more scalar integer or a vector of integer values
Definition: ov-cell.cc:1205
int printf(const std::string &fmt, const octave_value_list &args, const std::string &who)
Definition: oct-stream.cc:7069
std::deque< textscan_format_elt * > fmt_elts
Definition: oct-stream.cc:1764
const textscan_format_elt * current(void) const
Definition: oct-stream.cc:1715
bool swap
Definition: load-save.cc:725
void scan_qstring(delimited_stream &is, const textscan_format_elt &fmt, std::string &val)
Definition: oct-stream.cc:3218
void do_double_format_conversion(void *data, octave_idx_type len, octave::mach_info::float_format from_fmt, octave::mach_info::float_format to_fmt)
Definition: data-conv.cc:654
JNIEnv void * args
Definition: ov-java.cc:67
void process_conversion(const std::string &s, size_t &i, size_t n, int &args, std::string &flags, int &fw, int &prec, char &modifier, char &type)
Definition: oct-stream.cc:988
static int insert(octave_stream &os)
Definition: oct-stream.cc:7251
static Matrix null(const Matrix &A, octave_idx_type &rank)
Definition: __qp__.cc:42
std::istream & octave_scan_1(std::istream &is, const scanf_format_elt &fmt, T *valptr)
Definition: oct-stream.cc:4173
std::string parse_char_class(const std::string &pattern) const
Definition: oct-stream.cc:2277
std::istream & octave_scan(std::istream &is, const scanf_format_elt &fmt, T *valptr)
Definition: oct-stream.cc:4260
int skip_delim(delimited_stream &is)
Definition: oct-stream.cc:3872
int scan_bracket(delimited_stream &is, const std::string &pattern, std::string &val) const
Definition: oct-stream.cc:3198
done
Definition: syscalls.cc:248
const scanf_format_elt * next(bool cycle=true)
Definition: oct-stream.cc:271
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable name
Definition: input.cc:871
OCTAVE_EXPORT octave_value_list isdir nd deftypefn *std::string nm
Definition: utils.cc:941
std::deque< scanf_format_elt * > fmt_elts
Definition: oct-stream.cc:309
int write(octave_stream &os, int block_size, oct_data_conv::data_type output_type, int skip, octave::mach_info::float_format flt_fmt) const
Definition: ov.cc:2192
int read_format_once(delimited_stream &isp, textscan_format_list &fmt_list, std::list< octave_value > &retval, Array< octave_idx_type > row, int &done_after)
Definition: oct-stream.cc:3434
#define OCTINTERP_API
Definition: mexproto.h:69
static bool words_big_endian(void)
Definition: mach-info.cc:169
void printme(void) const
Definition: oct-stream.cc:2431
void add_elt_to_list(int width, bool discard, char type, char modifier, const std::string &char_class="")
Definition: oct-stream.cc:415
std::deque< printf_format_elt * > fmt_elts
Definition: oct-stream.cc:850
octave_idx_type numel(const octave_value_list &idx)
Definition: ov.h:411
static uint32_t * next
Definition: randmtzig.cc:183
static int convert_to_valid_int(const octave_value &tc, int &conv_err)
Definition: oct-stream.cc:78
octave::mach_info::float_format float_format(void) const
Definition: oct-stream.h:144
std::string string_value(bool force=false) const
Definition: ov.h:908
int skip_whitespace(delimited_stream &is, bool EOLstop=false)
Definition: oct-stream.cc:3749
int do_numeric_printf_conv(std::ostream &os, const printf_format_elt *elt, int nsa, int sa_1, int sa_2, const octave_value &val, const std::string &who)
Definition: oct-stream.cc:5600
nd deftypefn *octave_map m
Definition: ov-struct.cc:2058
bool all_character_conversions(void)
Definition: oct-stream.cc:677
static void add(fptr f)
std::string errmsg
Definition: oct-stream.h:178
bool write_bytes(const void *data, size_t n_elts)
Definition: oct-stream.cc:6820
std::complex< double > w(std::complex< double > z, double relerr=0)
octave_value finalize_read(std::list< void * > &input_buf_list, octave_idx_type input_buf_elts, octave_idx_type elts_read, octave_idx_type nr, octave_idx_type nc, oct_data_conv::data_type input_type, oct_data_conv::data_type output_type, octave::mach_info::float_format ffmt)
Definition: oct-stream.cc:6362
const printf_format_elt * current(void) const
Definition: oct-stream.cc:810
static void convert_chars(const void *data, void *conv_data, octave_idx_type n_elts)
Definition: oct-stream.cc:6674
std::ostringstream buf
Definition: oct-stream.cc:853
bool is_string(void) const
Definition: ov.h:578
std::string do_gets(octave_idx_type max_len, bool &err, bool strip_newline, const std::string &who)
Definition: oct-stream.cc:4005
const T * data(void) const
Definition: Array.h:582
int do_printf_conv(std::ostream &os, const char *fmt, int nsa, int sa_1, int sa_2, T arg, const std::string &who)
Definition: oct-stream.cc:5472
octave_value do_scan(std::istream &isp, textscan_format_list &fmt_list, octave_idx_type ntimes)
Definition: oct-stream.cc:2576
octave_value do_textscan(const std::string &fmt, octave_idx_type ntimes, const octave_value_list &options, const std::string &who, octave_idx_type &count)
Definition: oct-stream.cc:5237
int mode(void) const
Definition: oct-stream.h:142
bool do_oscanf(const scanf_format_elt *elt, octave_value &, const std::string &who)
Definition: oct-stream.cc:5013
static int elem
Definition: __contourc__.cc:50
#define SEEK_END
double tmp
Definition: data.cc:6300
is false
Definition: cellfun.cc:398
int puts(const std::string &s, const std::string &who)
Definition: oct-stream.cc:7105
static void clear(bool flush=true)
Definition: oct-stream.cc:7281
octave_value retval
Definition: data.cc:6294
void scan_complex(delimited_stream &is, const textscan_format_elt &fmt, Complex &val) const
Definition: oct-stream.cc:2950
static int remove(int fid, const std::string &who="")
Definition: oct-stream.cc:7269
#define panic_impossible()
Definition: error.h:40
int do_printf(printf_format_list &fmt_list, const octave_value_list &args, const std::string &who)
Definition: oct-stream.cc:5721
int flush(void)
Definition: oct-stream.cc:5939
int puts(const std::string &s, const std::string &who)
Definition: oct-stream.cc:5843
const textscan_format_elt * first(void)
Definition: oct-stream.cc:1709
scanf_format_elt(const scanf_format_elt &e)
Definition: oct-stream.cc:200
std::string error(bool clear, int &err_num)
Definition: oct-stream.cc:7148
std::string date_locale
Definition: oct-stream.cc:1847
static void parse_options(octave::regexp::opts &options, const octave_value_list &args, const std::string &who, int skip, bool &extra_args)
Definition: regexp.cc:284
void process_conversion(const std::string &s, size_t &i, size_t n)
Definition: oct-stream.cc:2081
static octave_stream lookup(int fid, const std::string &who="")
Definition: oct-stream.cc:7257
std::ostream * output_stream(void)
Definition: oct-stream.h:368
virtual int file_number(void) const
Definition: oct-stream.h:120
textscan_format_elt(const std::string &txt, int w=0, int p=-1, int bw=0, bool dis=false, char typ= '\0', const std::string &ch_class=std::string())
Definition: oct-stream.cc:1627
static void cleanup_instance(void)
Definition: oct-stream.h:458
octave_value_list oscanf(const std::string &fmt, const std::string &who)
Definition: oct-stream.cc:7025
octave_idx_type length(void) const
Definition: ov.cc:1623
static bool ok_for_unsigned_int_conv(const octave_value &val)
Definition: oct-stream.cc:5563
idx type
Definition: ov.cc:3129
Array< std::string > param
Definition: urlwrite.cc:343
Definition: dMatrix.h:37
static std::string float_format_as_string(float_format)
Definition: mach-info.cc:202
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the c
Definition: lu.cc:138
OCTINTERP_API size_t octave_format(std::ostream &os, const char *fmt,...)
octave_value textscan(const std::string &fmt, octave_idx_type ntimes, const octave_value_list &options, const std::string &who, octave_idx_type &count)
Definition: oct-stream.cc:7059
octave_value scanf(const std::string &fmt, const Array< double > &size, octave_idx_type &count, const std::string &who)
Definition: oct-stream.cc:6989
T::size_type strlen(const typename T::value_type *str)
Definition: oct-string.cc:75
const scanf_format_elt * first(void)
Definition: oct-stream.cc:260
off_t tell(void)
Definition: oct-stream.cc:6178
std::ios_base::iostate rdstate(void)
Definition: oct-stream.cc:1291
octave_idx_type num_conversions(void)
Definition: oct-stream.cc:251
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:156
With real return the complex result
Definition: data.cc:3375
std::string error(bool clear, int &err_num)
Definition: oct-stream.cc:5882
bool isinf(double x)
Definition: lo-mappers.cc:387
const textscan_format_elt * next(bool cycle=true)
Definition: oct-stream.cc:1720
std::istream & i_stream
Definition: oct-stream.cc:1314
bool stream_ok(bool clear=true) const
Definition: oct-stream.h:380
static uint32_t state[624]
Definition: randmtzig.cc:184
bool is_old_NA< double >(double val)
Definition: oct-stream.cc:6223
bool ok(void) const
Definition: oct-stream.cc:291
static bool is_nan_or_inf(const octave_value &val)
Definition: oct-stream.cc:5524
size_t length(void) const
Definition: oct-stream.cc:258
int read_first_row(delimited_stream &is, textscan &ts)
Definition: oct-stream.cc:2463
~octave_stream(void)
Definition: oct-stream.cc:5908
bool is_map(void) const
Definition: ov.h:590
static float_format native_float_format(void)
Definition: mach-info.cc:162
std::string exp_chars
Definition: oct-stream.cc:1859
void warning(const char *fmt,...)
Definition: error.cc:788
void recover_from_exception(void)
Definition: interpreter.cc:200
octave_value read(const Array< double > &size, octave_idx_type block_size, oct_data_conv::data_type input_type, oct_data_conv::data_type output_type, octave_idx_type skip, octave::mach_info::float_format flt_fmt, octave_idx_type &count)
Definition: oct-stream.cc:6450
bool is_true(void) const
Definition: ov.h:687
scanf_format_elt(const char *txt=0, int w=0, bool d=false, char typ= '\0', char mod= '\0', const std::string &ch_class="")
Definition: oct-stream.cc:193
int do_insert(octave_stream &os)
Definition: oct-stream.cc:7319
void add_elt_to_list(int args, const std::string &flags, int fw, int prec, char type, char modifier)
Definition: oct-stream.cc:968
octave_value curr_val
Definition: oct-stream.cc:5327
octave_idx_type num_conversions(void) const
Definition: oct-stream.cc:1700
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:228
octave_stream(octave_base_stream *bs=0)
Definition: oct-stream.cc:5901
octave_idx_type length(void) const
Number of elements in the array.
Definition: Array.h:354
OCTAVE_EXPORT octave_value_list the first data row corresponds to an index of zero The a spreadsheet style form such as the file is read until end of file is reached The such as text
Definition: dlmread.cc:191
#define Inf
Definition: Faddeeva.cc:247
T::size_type numel(const T &str)
Definition: oct-string.cc:61
scanf_format_list(const std::string &fmt="")
Definition: oct-stream.cc:331
bool is_NaN_or_NA(const Complex &x)
Definition: lo-mappers.cc:78
bool is_sq_string(void) const
Definition: ov.h:581
static octave_value convert_and_copy(std::list< void * > &input_buf_list, octave_idx_type input_buf_elts, octave_idx_type elts_read, octave_idx_type nr, octave_idx_type nc, bool swap, bool do_float_fmt_conv, bool do_NA_conv, octave::mach_info::float_format from_flt_fmt)
Definition: oct-stream.cc:6244
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:793
const char * text
Definition: oct-stream.cc:771
octave::sys::time start
Definition: graphics.cc:11731
octave_idx_type lines
Definition: oct-stream.cc:1877
const printf_format_elt * next(bool cycle=true)
Definition: oct-stream.cc:817
octave_value_list oscanf(const std::string &fmt, const std::string &who)
Definition: oct-stream.cc:5163
octave_value scan(std::istream &isp, const std::string &fmt, octave_idx_type ntimes, const octave_value_list &options, octave_idx_type &read_count)
Definition: oct-stream.cc:2553
bool is_valid(void) const
Definition: oct-stream.h:349
octave_stream do_lookup(int fid, const std::string &who="") const
Definition: oct-stream.cc:7360
std::string whitespace
Definition: oct-stream.cc:1866
octave_stream & operator=(const octave_stream &)
Definition: oct-stream.cc:5922
OCTINTERP_API std::string do_string_escapes(const std::string &s)
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
bool eof(void) const
Definition: oct-stream.cc:7137
octave_idx_type nint_big(double x)
Definition: lo-mappers.cc:409
delimited_stream(std::istream &is, const std::string &delimiters, int longest_lookahead, octave_idx_type bsize=4096)
Definition: oct-stream.cc:1357
is longer than or if then or only for unique occurrences of the complete pattern(false).The default is true.If a cell array of strings ar
Definition: strfind.cc:192
static octave_idx_type get_size(double d, const std::string &who)
Definition: oct-stream.cc:116
std::string getl(octave_idx_type max_len, bool &err, const std::string &who)
Definition: oct-stream.cc:4103
p
Definition: lu.cc:138
OCTAVE_EXPORT octave_value_list or N dimensional array whose elements are all equal to the IEEE symbol zero divided by nd tex zero divided by nd ifnottex and any operation involving another NaN value(5+NaN).Note that NaN always compares not equal to NaN(NaN!
octave_idx_type num_conversions(void)
Definition: oct-stream.cc:802
static std::string list_open_files(void)
Definition: oct-stream.cc:7300
static octave_value open_file_numbers(void)
Definition: oct-stream.cc:7306
issues an error eealso double
Definition: ov-bool-mat.cc:594
#define scanner
OCTAVE_EXPORT octave_value_list only variables visible in the local scope are displayed The following are valid options
Definition: variables.cc:1859
int __lo_ieee_is_old_NA(double x)
Definition: lo-ieee.cc:92
double replace_old_NA< double >(double val)
Definition: oct-stream.cc:6237
octave_refcount< octave_idx_type > count
Definition: oct-stream.h:162
printf_format_list(const std::string &fmt="")
Definition: oct-stream.cc:873
#define BEGIN_C_CONVERSION()
Definition: oct-stream.cc:4422
octave_int64 int64_scalar_value(void) const
Definition: ov.h:869
OCTAVE_EXPORT octave_value_list or N dimensional array whose elements are all equal to the IEEE symbol NaN(Not a Number).NaN is the result of operations which do not produce a well defined 0 result.Common operations which produce a NaN are arithmetic with infinity ex($\infty-\infty $)
#define SEEK_SET
string_vector do_get_info(int fid) const
Definition: oct-stream.cc:7481
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:200
const scanf_format_elt * current(void) const
Definition: oct-stream.cc:266
int lookahead(delimited_stream &is, const Cell &targets, int max_len, bool case_sensitive=true) const
Definition: oct-stream.cc:3834
bool is_uint64_type(void) const
Definition: ov.h:656
ostrl_map::const_iterator lookup_cache
Definition: oct-stream.h:454
void resize(octave_idx_type n, const octave_value &rfv=octave_value())
Definition: ovl.h:100
#define FILL_TABLE_ROW(T, V)
Definition: oct-stream.cc:6345
ColumnVector transform(const Matrix &m, double x, double y, double z)
Definition: graphics.cc:5118
void do_float_format_conversion(void *data, octave_idx_type len, octave::mach_info::float_format from_fmt, octave::mach_info::float_format to_fmt)
Definition: data-conv.cc:701
void close(void)
Definition: oct-stream.cc:6206
octave_uint64 uint64_scalar_value(void) const
Definition: ov.h:881
octave_value fast_elem_extract(octave_idx_type n) const
Definition: ov.h:1420
int getline(std::string &dest, char delim)
Definition: oct-stream.cc:1594
int file_number(void)
Definition: oct-stream.h:347
std::complex< float > FloatComplex
Definition: oct-cmplx.h:32
std::string buf
Definition: oct-stream.cc:1822
void clearerr(void)
Definition: oct-stream.cc:3989
OCTAVE_EXPORT octave_value_list error nd deftypefn *const octave_scalar_map err
Definition: error.cc:1036
void do_scanf_conv(std::istream &is, const scanf_format_elt &fmt, T valptr, Matrix &mval, double *data, octave_idx_type &idx, octave_idx_type &conversion_count, octave_idx_type nr, octave_idx_type max_size, bool discard)
Definition: oct-stream.cc:4329
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable or any other valid Octave code The number of return their size
Definition: input.cc:871
#define FINISH_CHARACTER_CONVERSION()
Definition: oct-stream.cc:4539
FloatComplex(* fptr)(const FloatComplex &, float, int, octave_idx_type &)
Definition: lo-specfun.cc:1724
T value(void) const
Definition: oct-inttypes.h:888
std::complex< double > Complex
Definition: oct-cmplx.h:31
static T replace_old_NA(T val)
Definition: oct-stream.cc:6230
const T * fortran_vec(void) const
Definition: Array.h:584
void printme(void) const
Definition: oct-stream.cc:1158
bool strncmp(const T &str_a, const T &str_b, const typename T::size_type n)
True if the first N characters are the same.
Definition: oct-string.cc:146
std::string name(void) const
Definition: oct-stream.cc:7159
std::string gets(octave_idx_type max_len, bool &err, const std::string &who)
Definition: oct-stream.cc:4110
static bool convert_data(const T *data, void *conv_data, octave_idx_type n_elts, oct_data_conv::data_type output_type, octave::mach_info::float_format flt_fmt)
Definition: oct-stream.cc:6721
virtual bool eof(void) const =0
void invalid_operation(const std::string &who, const char *rw)
Definition: oct-stream.cc:5895
int printf(const std::string &fmt, const octave_value_list &args, const std::string &who)
Definition: oct-stream.cc:5830
octave_base_value * internal_rep(void) const
Definition: ov.h:1299
double double_value(bool frc_str_conv=false) const
Definition: ov.h:775
write the output to stdout if nargout is
Definition: load-save.cc:1576
static Cell init_inf_nan(void)
Definition: oct-stream.cc:1196
bool match_literal(delimited_stream &isp, const textscan_format_elt &elem)
Definition: oct-stream.cc:3946
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
virtual int seek(off_t offset, int origin)=0
std::string getl(octave_idx_type max_len, bool &err, const std::string &who)
Definition: oct-stream.cc:5950
static int get_file_number(const octave_value &fid)
Definition: oct-stream.cc:7313
static size_t data_type_size(data_type dt)
Definition: data-conv.cc:178
octave_value isnan(void) const
Definition: ov.h:1376
void close(void)
Definition: oct-stream.h:111
std::ios_base::iostate flags
Definition: oct-stream.cc:1344
static void clear(octave::dynamic_library &oct_file)
Definition: dynamic-ld.cc:230
static std::string mode_as_string(int mode)
Definition: oct-stream.cc:7192
std::string do_list_open_files(void) const
Definition: oct-stream.cc:7511
#define BEGIN_CHAR_CLASS_CONVERSION()
Definition: oct-stream.cc:4492
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
size_t length(void) const
Definition: oct-stream.cc:815
char * read(char *buffer, int size, char *&new_start)
Definition: oct-stream.cc:1527
std::string whitespace_table
Definition: oct-stream.cc:1829
#define INSTANTIATE_WRITE(T)
Definition: oct-stream.cc:6957
dim_vector dv
Definition: sub2ind.cc:263
const std::string delims
Definition: oct-stream.cc:1336
T x_nint(T x)
Definition: lo-mappers.h:299
where the brackets indicate optional arguments and and character or cell array For character arrays the conversion is repeated for every row
Definition: str2double.cc:342
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE * x
return octave_value(v1.char_array_value().concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string())? '\'': '"'))
static void convert_ints(const T *data, void *conv_data, octave_idx_type n_elts, bool swap)
Definition: oct-stream.cc:6686
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:205
octave_value do_binary_op(octave_value::binary_op op, const octave_value &v1, const octave_value &v2)
Definition: ov.cc:2214
octave_value do_open_file_numbers(void) const
Definition: oct-stream.cc:7544
void clearerr(void)
Definition: oct-stream.h:373
off_t skipl(off_t count, bool &err, const std::string &who)
Definition: oct-stream.cc:4117
int nint(double x)
Definition: lo-mappers.cc:433
double read_double(delimited_stream &is, const textscan_format_elt &fmt) const
Definition: oct-stream.cc:2779
bool is_integer_type(void) const
Definition: ov.h:664