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