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