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