GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
oct-stream.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2013 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <cassert>
28 #include <cctype>
29 #include <cstring>
30 
31 #include <iomanip>
32 #include <iostream>
33 #include <fstream>
34 #include <sstream>
35 #include <string>
36 
37 #include <Array.h>
38 
39 #include "byte-swap.h"
40 #include "lo-ieee.h"
41 #include "lo-mappers.h"
42 #include "lo-utils.h"
43 #include "quit.h"
44 #include "singleton-cleanup.h"
45 #include "str-vec.h"
46 
47 #include "error.h"
48 #include "gripes.h"
49 #include "input.h"
50 #include "oct-stdstrm.h"
51 #include "oct-stream.h"
52 #include "oct-obj.h"
53 #include "utils.h"
54 
55 // Possible values for conv_err:
56 //
57 // 1 : not a real scalar
58 // 2 : value is NaN
59 // 3 : value is not an integer
60 
61 static int
62 convert_to_valid_int (const octave_value& tc, int& conv_err)
63 {
64  int retval = 0;
65 
66  conv_err = 0;
67 
68  double dval = tc.double_value ();
69 
70  if (! error_state)
71  {
72  if (! lo_ieee_isnan (dval))
73  {
74  int ival = NINT (dval);
75 
76  if (ival == dval)
77  retval = ival;
78  else
79  conv_err = 3;
80  }
81  else
82  conv_err = 2;
83  }
84  else
85  conv_err = 1;
86 
87  return retval;
88 }
89 
90 static int
91 get_size (double d, const std::string& who)
92 {
93  int retval = -1;
94 
95  if (! lo_ieee_isnan (d))
96  {
97  if (! xisinf (d))
98  {
99  if (d >= 0.0)
100  retval = NINT (d);
101  else
102  ::error ("%s: negative value invalid as size specification",
103  who.c_str ());
104  }
105  else
106  retval = -1;
107  }
108  else
109  ::error ("%s: NaN is invalid as size specification", who.c_str ());
110 
111  return retval;
112 }
113 
114 static void
116  bool& one_elt_size_spec, const std::string& who)
117 {
118  nr = -1;
119  nc = -1;
120 
121  one_elt_size_spec = false;
122 
123  double dnr = -1.0;
124  double dnc = -1.0;
125 
126  octave_idx_type sz_len = size.length ();
127 
128  if (sz_len == 1)
129  {
130  one_elt_size_spec = true;
131 
132  dnr = size (0);
133 
134  dnc = (dnr == 0.0) ? 0.0 : 1.0;
135  }
136  else if (sz_len == 2)
137  {
138  dnr = size (0);
139 
140  if (! xisinf (dnr))
141  dnc = size (1);
142  else
143  ::error ("%s: invalid size specification", who.c_str ());
144  }
145  else
146  ::error ("%s: invalid size specification", who.c_str ());
147 
148  if (! error_state)
149  {
150  nr = get_size (dnr, who);
151 
152  if (! error_state && dnc >= 0.0)
153  nc = get_size (dnc, who);
154  }
155 }
156 
158  : nconv (0), curr_idx (0), list (dim_vector (16, 1)), buf (0)
159 {
160  octave_idx_type num_elts = 0;
161 
162  size_t n = s.length ();
163 
164  size_t i = 0;
165 
166  int width = 0;
167  bool discard = false;
168  char modifier = '\0';
169  char type = '\0';
170 
171  bool have_more = true;
172 
173  while (i < n)
174  {
175  have_more = true;
176 
177  if (! buf)
178  buf = new std::ostringstream ();
179 
180  if (s[i] == '%')
181  {
182  // Process percent-escape conversion type.
183 
184  process_conversion (s, i, n, width, discard, type, modifier,
185  num_elts);
186 
187  have_more = (buf != 0);
188  }
189  else if (isspace (s[i]))
190  {
192 
193  width = 0;
194  discard = false;
195  modifier = '\0';
196  *buf << " ";
197 
198  while (++i < n && isspace (s[i]))
199  /* skip whitespace */;
200 
201  add_elt_to_list (width, discard, type, modifier, num_elts);
202 
203  have_more = false;
204  }
205  else
206  {
208 
209  width = 0;
210  discard = false;
211  modifier = '\0';
212 
213  while (i < n && ! isspace (s[i]) && s[i] != '%')
214  *buf << s[i++];
215 
216  add_elt_to_list (width, discard, type, modifier, num_elts);
217 
218  have_more = false;
219  }
220 
221  if (nconv < 0)
222  {
223  have_more = false;
224  break;
225  }
226  }
227 
228  if (have_more)
229  add_elt_to_list (width, discard, type, modifier, num_elts);
230 
231  list.resize (dim_vector (num_elts, 1));
232 
233  delete buf;
234 }
235 
237 {
238  octave_idx_type n = list.length ();
239 
240  for (octave_idx_type i = 0; i < n; i++)
241  {
242  scanf_format_elt *elt = list(i);
243  delete elt;
244  }
245 }
246 
247 void
248 scanf_format_list::add_elt_to_list (int width, bool discard, char type,
249  char modifier, octave_idx_type& num_elts,
250  const std::string& char_class)
251 {
252  if (buf)
253  {
254  std::string text = buf->str ();
255 
256  if (! text.empty ())
257  {
258  scanf_format_elt *elt
259  = new scanf_format_elt (text.c_str (), width, discard, type,
260  modifier, char_class);
261 
262  if (num_elts == list.length ())
263  list.resize (dim_vector (2 * num_elts, 1));
264 
265  list(num_elts++) = elt;
266  }
267 
268  delete buf;
269  buf = 0;
270  }
271 }
272 
273 static std::string
274 expand_char_class (const std::string& s)
275 {
276  std::string retval;
277 
278  size_t len = s.length ();
279 
280  size_t i = 0;
281 
282  while (i < len)
283  {
284  unsigned char c = s[i++];
285 
286  if (c == '-' && i > 1 && i < len
287  && ( static_cast<unsigned char> (s[i-2])
288  <= static_cast<unsigned char> (s[i])))
289  {
290  // Add all characters from the range except the first (we
291  // already added it below).
292 
293  for (c = s[i-2]+1; c < s[i]; c++)
294  retval += c;
295  }
296  else
297  {
298  // Add the character to the class. Only add '-' if it is
299  // the last character in the class.
300 
301  if (c != '-' || i == len)
302  retval += c;
303  }
304  }
305 
306  return retval;
307 }
308 
309 void
310 scanf_format_list::process_conversion (const std::string& s, size_t& i,
311  size_t n, int& width, bool& discard,
312  char& type, char& modifier,
313  octave_idx_type& num_elts)
314 {
315  width = 0;
316  discard = false;
317  modifier = '\0';
318  type = '\0';
319 
320  *buf << s[i++];
321 
322  bool have_width = false;
323 
324  while (i < n)
325  {
326  switch (s[i])
327  {
328  case '*':
329  if (discard)
330  nconv = -1;
331  else
332  {
333  discard = true;
334  *buf << s[i++];
335  }
336  break;
337 
338  case '0': case '1': case '2': case '3': case '4':
339  case '5': case '6': case '7': case '8': case '9':
340  if (have_width)
341  nconv = -1;
342  else
343  {
344  char c = s[i++];
345  width = width * 10 + c - '0';
346  have_width = true;
347  *buf << c;
348  while (i < n && isdigit (s[i]))
349  {
350  c = s[i++];
351  width = width * 10 + c - '0';
352  *buf << c;
353  }
354  }
355  break;
356 
357  case 'h': case 'l': case 'L':
358  if (modifier != '\0')
359  nconv = -1;
360  else
361  modifier = s[i++];
362  break;
363 
364  case 'd': case 'i': case 'o': case 'u': case 'x':
365  if (modifier == 'L')
366  {
367  nconv = -1;
368  break;
369  }
370  goto fini;
371 
372  case 'e': case 'f': case 'g':
373  if (modifier == 'h')
374  {
375  nconv = -1;
376  break;
377  }
378 
379  // No float or long double conversions, thanks.
380  *buf << 'l';
381 
382  goto fini;
383 
384  case 'c': case 's': case 'p': case '%': case '[':
385  if (modifier != '\0')
386  {
387  nconv = -1;
388  break;
389  }
390  goto fini;
391 
392  fini:
393  {
394  if (finish_conversion (s, i, n, width, discard, type,
395  modifier, num_elts) == 0)
396  return;
397  }
398  break;
399 
400  default:
401  nconv = -1;
402  break;
403  }
404 
405  if (nconv < 0)
406  break;
407  }
408 
409  nconv = -1;
410 }
411 
412 int
413 scanf_format_list::finish_conversion (const std::string& s, size_t& i,
414  size_t n, int& width, bool discard,
415  char& type, char modifier,
416  octave_idx_type& num_elts)
417 {
418  int retval = 0;
419 
420  std::string char_class;
421 
422  size_t beg_idx = std::string::npos;
423  size_t end_idx = std::string::npos;
424 
425  if (s[i] == '%')
426  {
427  type = '%';
428  *buf << s[i++];
429  }
430  else
431  {
432  type = s[i];
433 
434  if (s[i] == '[')
435  {
436  *buf << s[i++];
437 
438  if (i < n)
439  {
440  beg_idx = i;
441 
442  if (s[i] == '^')
443  {
444  type = '^';
445  *buf << s[i++];
446 
447  if (i < n)
448  {
449  beg_idx = i;
450 
451  if (s[i] == ']')
452  *buf << s[i++];
453  }
454  }
455  else if (s[i] == ']')
456  *buf << s[i++];
457  }
458 
459  while (i < n && s[i] != ']')
460  *buf << s[i++];
461 
462  if (i < n && s[i] == ']')
463  {
464  end_idx = i-1;
465  *buf << s[i++];
466  }
467 
468  if (s[i-1] != ']')
469  retval = nconv = -1;
470  }
471  else
472  *buf << s[i++];
473 
474  nconv++;
475  }
476 
477  if (nconv >= 0)
478  {
479  if (beg_idx != std::string::npos && end_idx != std::string::npos)
480  char_class = expand_char_class (s.substr (beg_idx,
481  end_idx - beg_idx + 1));
482 
483  add_elt_to_list (width, discard, type, modifier, num_elts, char_class);
484  }
485 
486  return retval;
487 }
488 
489 void
491 {
492  octave_idx_type n = list.length ();
493 
494  for (octave_idx_type i = 0; i < n; i++)
495  {
496  scanf_format_elt *elt = list(i);
497 
498  std::cerr
499  << "width: " << elt->width << "\n"
500  << "discard: " << elt->discard << "\n"
501  << "type: ";
502 
504  std::cerr << "literal text\n";
506  std::cerr << "whitespace\n";
507  else
508  std::cerr << elt->type << "\n";
509 
510  std::cerr
511  << "modifier: " << elt->modifier << "\n"
512  << "char_class: '" << undo_string_escapes (elt->char_class) << "'\n"
513  << "text: '" << undo_string_escapes (elt->text) << "'\n\n";
514  }
515 }
516 
517 bool
519 {
520  octave_idx_type n = list.length ();
521 
522  if (n > 0)
523  {
524  for (octave_idx_type i = 0; i < n; i++)
525  {
526  scanf_format_elt *elt = list(i);
527 
528  switch (elt->type)
529  {
530  case 'c': case 's': case '%': case '[': case '^':
533  break;
534 
535  default:
536  return false;
537  break;
538  }
539  }
540 
541  return true;
542  }
543  else
544  return false;
545 }
546 
547 bool
549 {
550  octave_idx_type n = list.length ();
551 
552  if (n > 0)
553  {
554  for (octave_idx_type i = 0; i < n; i++)
555  {
556  scanf_format_elt *elt = list(i);
557 
558  switch (elt->type)
559  {
560  case 'd': case 'i': case 'o': case 'u': case 'x':
561  case 'e': case 'f': case 'g':
562  break;
563 
564  default:
565  return false;
566  break;
567  }
568  }
569 
570  return true;
571  }
572  else
573  return false;
574 }
575 
576 // Ugh again.
577 
579  : nconv (0), curr_idx (0), list (dim_vector (16, 1)), buf (0)
580 {
581  octave_idx_type num_elts = 0;
582 
583  size_t n = s.length ();
584 
585  size_t i = 0;
586 
587  int args = 0;
588  std::string flags;
589  int fw = 0;
590  int prec = 0;
591  char modifier = '\0';
592  char type = '\0';
593 
594  bool have_more = true;
595  bool empty_buf = true;
596 
597  if (n == 0)
598  {
599  printf_format_elt *elt
600  = new printf_format_elt ("", args, fw, prec, flags, type, modifier);
601 
602  list(num_elts++) = elt;
603 
604  list.resize (dim_vector (num_elts, 1));
605  }
606  else
607  {
608  while (i < n)
609  {
610  have_more = true;
611 
612  if (! buf)
613  {
614  buf = new std::ostringstream ();
615  empty_buf = true;
616  }
617 
618  switch (s[i])
619  {
620  case '%':
621  {
622  if (empty_buf)
623  {
624  process_conversion (s, i, n, args, flags, fw, prec,
625  type, modifier, num_elts);
626 
627  have_more = (buf != 0);
628  }
629  else
630  add_elt_to_list (args, flags, fw, prec, type, modifier,
631  num_elts);
632  }
633  break;
634 
635  default:
636  {
637  args = 0;
638  flags = "";
639  fw = 0;
640  prec = 0;
641  modifier = '\0';
642  type = '\0';
643  *buf << s[i++];
644  empty_buf = false;
645  }
646  break;
647  }
648 
649  if (nconv < 0)
650  {
651  have_more = false;
652  break;
653  }
654  }
655 
656  if (have_more)
657  add_elt_to_list (args, flags, fw, prec, type, modifier, num_elts);
658 
659  list.resize (dim_vector (num_elts, 1));
660 
661  delete buf;
662  }
663 }
664 
666 {
667  octave_idx_type n = list.length ();
668 
669  for (octave_idx_type i = 0; i < n; i++)
670  {
671  printf_format_elt *elt = list(i);
672  delete elt;
673  }
674 }
675 
676 void
677 printf_format_list::add_elt_to_list (int args, const std::string& flags,
678  int fw, int prec, char type,
679  char modifier, octave_idx_type& num_elts)
680 {
681  if (buf)
682  {
683  std::string text = buf->str ();
684 
685  if (! text.empty ())
686  {
687  printf_format_elt *elt
688  = new printf_format_elt (text.c_str (), args, fw, prec, flags,
689  type, modifier);
690 
691  if (num_elts == list.length ())
692  list.resize (dim_vector (2 * num_elts, 1));
693 
694  list(num_elts++) = elt;
695  }
696 
697  delete buf;
698  buf = 0;
699  }
700 }
701 
702 void
703 printf_format_list::process_conversion (const std::string& s, size_t& i,
704  size_t n, int& args, std::string& flags,
705  int& fw, int& prec, char& modifier,
706  char& type, octave_idx_type& num_elts)
707 {
708  args = 0;
709  flags = "";
710  fw = 0;
711  prec = 0;
712  modifier = '\0';
713  type = '\0';
714 
715  *buf << s[i++];
716 
717  bool nxt = false;
718 
719  while (i < n)
720  {
721  switch (s[i])
722  {
723  case '-': case '+': case ' ': case '0': case '#':
724  flags += s[i];
725  *buf << s[i++];
726  break;
727 
728  default:
729  nxt = true;
730  break;
731  }
732 
733  if (nxt)
734  break;
735  }
736 
737  if (i < n)
738  {
739  if (s[i] == '*')
740  {
741  fw = -1;
742  args++;
743  *buf << s[i++];
744  }
745  else
746  {
747  if (isdigit (s[i]))
748  {
749  int nn = 0;
750  std::string tmp = s.substr (i);
751  sscanf (tmp.c_str (), "%d%n", &fw, &nn);
752  }
753 
754  while (i < n && isdigit (s[i]))
755  *buf << s[i++];
756  }
757  }
758 
759  if (i < n && s[i] == '.')
760  {
761  *buf << s[i++];
762 
763  if (i < n)
764  {
765  if (s[i] == '*')
766  {
767  prec = -1;
768  args++;
769  *buf << s[i++];
770  }
771  else
772  {
773  if (isdigit (s[i]))
774  {
775  int nn = 0;
776  std::string tmp = s.substr (i);
777  sscanf (tmp.c_str (), "%d%n", &prec, &nn);
778  }
779 
780  while (i < n && isdigit (s[i]))
781  *buf << s[i++];
782  }
783  }
784  }
785 
786  if (i < n)
787  {
788  switch (s[i])
789  {
790  case 'h': case 'l': case 'L':
791  modifier = s[i];
792  *buf << s[i++];
793  break;
794 
795  default:
796  break;
797  }
798  }
799 
800  if (i < n)
801  finish_conversion (s, i, args, flags, fw, prec, modifier, type, num_elts);
802  else
803  nconv = -1;
804 }
805 
806 void
807 printf_format_list::finish_conversion (const std::string& s, size_t& i,
808  int args, const std::string& flags,
809  int fw, int prec, char modifier,
810  char& type, octave_idx_type& num_elts)
811 {
812  switch (s[i])
813  {
814  case 'd': case 'i': case 'o': case 'x': case 'X':
815  case 'u': case 'c':
816  if (modifier == 'L')
817  {
818  nconv = -1;
819  break;
820  }
821  goto fini;
822 
823  case 'f': case 'e': case 'E': case 'g': case 'G':
824  if (modifier == 'h' || modifier == 'l')
825  {
826  nconv = -1;
827  break;
828  }
829  goto fini;
830 
831  case 's': case 'p': case '%':
832  if (modifier != '\0')
833  {
834  nconv = -1;
835  break;
836  }
837  goto fini;
838 
839  fini:
840 
841  type = s[i];
842 
843  *buf << s[i++];
844 
845  if (type != '%' || args != 0)
846  nconv++;
847 
848  if (type != '%')
849  args++;
850 
851  add_elt_to_list (args, flags, fw, prec, type, modifier, num_elts);
852 
853  break;
854 
855  default:
856  nconv = -1;
857  break;
858  }
859 }
860 
861 void
863 {
864  int n = list.length ();
865 
866  for (int i = 0; i < n; i++)
867  {
868  printf_format_elt *elt = list(i);
869 
870  std::cerr
871  << "args: " << elt->args << "\n"
872  << "flags: '" << elt->flags << "'\n"
873  << "width: " << elt->fw << "\n"
874  << "prec: " << elt->prec << "\n"
875  << "type: '" << elt->type << "'\n"
876  << "modifier: '" << elt->modifier << "'\n"
877  << "text: '" << undo_string_escapes (elt->text) << "'\n\n";
878  }
879 }
880 
881 void
882 octave_base_stream::error (const std::string& msg)
883 {
884  fail = true;
885  errmsg = msg;
886 }
887 
888 void
889 octave_base_stream::error (const std::string& who, const std::string& msg)
890 {
891  fail = true;
892  errmsg = who + ": " + msg;
893 }
894 
895 void
897 {
898  fail = false;
899  errmsg = "";
900 }
901 
902 void
904 {
905  std::istream *is = input_stream ();
906  std::ostream *os = output_stream ();
907 
908  if (is)
909  is->clear ();
910 
911  if (os)
912  os->clear ();
913 }
914 
915 // Functions that are defined for all input streams (input streams
916 // are those that define is).
917 
918 std::string
920  bool strip_newline, const std::string& who)
921 {
922  std::string retval;
923 
924  if ((interactive || forced_interactive) && file_number () == 0)
925  {
926  ::error ("%s: unable to read from stdin while running interactively",
927  who.c_str ());
928 
929  return retval;
930  }
931 
932  err = false;
933 
934  std::istream *isp = input_stream ();
935 
936  if (isp)
937  {
938  std::istream& is = *isp;
939 
940  std::ostringstream buf;
941 
942  int c = 0;
943  int char_count = 0;
944 
945  if (max_len != 0)
946  {
947  while (is && (c = is.get ()) != EOF)
948  {
949  char_count++;
950 
951  // Handle CRLF, CR, or LF as line ending.
952 
953  if (c == '\r')
954  {
955  if (! strip_newline)
956  buf << static_cast<char> (c);
957 
958  c = is.get ();
959 
960  if (c != EOF)
961  {
962  if (c == '\n')
963  {
964  char_count++;
965 
966  if (! strip_newline)
967  buf << static_cast<char> (c);
968  }
969  else
970  is.putback (c);
971  }
972 
973  break;
974  }
975  else if (c == '\n')
976  {
977  if (! strip_newline)
978  buf << static_cast<char> (c);
979 
980  break;
981  }
982  else
983  buf << static_cast<char> (c);
984 
985  if (max_len > 0 && char_count == max_len)
986  break;
987  }
988  }
989 
990  if (! is.eof () && char_count > 0)
991  {
992  // GAGME. Matlab seems to check for EOF even if the last
993  // character in a file is a newline character. This is NOT
994  // what the corresponding C-library functions do.
995  int disgusting_compatibility_hack = is.get ();
996  if (! is.eof ())
997  is.putback (disgusting_compatibility_hack);
998  }
999 
1000  if (is.good () || (is.eof () && char_count > 0))
1001  retval = buf.str ();
1002  else
1003  {
1004  err = true;
1005 
1006  if (is.eof () && char_count == 0)
1007  error (who, "at end of file");
1008  else
1009  error (who, "read error");
1010  }
1011  }
1012  else
1013  {
1014  err = true;
1015  invalid_operation (who, "reading");
1016  }
1017 
1018  return retval;
1019 }
1020 
1021 std::string
1023  const std::string& who)
1024 {
1025  return do_gets (max_len, err, true, who);
1026 }
1027 
1028 std::string
1030  const std::string& who)
1031 {
1032  return do_gets (max_len, err, false, who);
1033 }
1034 
1035 off_t
1036 octave_base_stream::skipl (off_t num, bool& err, const std::string& who)
1037 {
1038  off_t cnt = -1;
1039 
1040  if ((interactive || forced_interactive) && file_number () == 0)
1041  {
1042  ::error ("%s: unable to read from stdin while running interactively",
1043  who.c_str ());
1044 
1045  return count;
1046  }
1047 
1048  err = false;
1049 
1050  std::istream *isp = input_stream ();
1051 
1052  if (isp)
1053  {
1054  std::istream& is = *isp;
1055 
1056  int c = 0, lastc = -1;
1057  cnt = 0;
1058 
1059  while (is && (c = is.get ()) != EOF)
1060  {
1061  // Handle CRLF, CR, or LF as line ending.
1062 
1063  if (c == '\r' || (c == '\n' && lastc != '\r'))
1064  {
1065  if (++cnt == num)
1066  break;
1067  }
1068 
1069  lastc = c;
1070  }
1071 
1072  // Maybe eat the following \n if \r was just met.
1073  if (c == '\r' && is.peek () == '\n')
1074  is.get ();
1075 
1076  if (is.bad ())
1077  {
1078  err = true;
1079  error (who, "read error");
1080  }
1081 
1082  if (err)
1083  cnt = -1;
1084  }
1085  else
1086  {
1087  err = true;
1088  invalid_operation (who, "reading");
1089  }
1090 
1091  return cnt;
1092 }
1093 
1094 #define OCTAVE_SCAN(is, fmt, arg) octave_scan (is, fmt, arg)
1095 
1096 template <class T>
1097 std::istream&
1098 octave_scan_1 (std::istream& is, const scanf_format_elt& fmt, T* valptr)
1099 {
1100  T& ref = *valptr;
1101 
1102  switch (fmt.type)
1103  {
1104  case 'o':
1105  is >> std::oct >> ref >> std::dec;
1106  break;
1107 
1108  case 'x':
1109  is >> std::hex >> ref >> std::dec;
1110  break;
1111 
1112  case 'i':
1113  {
1114  int c1 = EOF;
1115 
1116  while (is && (c1 = is.get ()) != EOF && isspace (c1))
1117  /* skip whitespace */;
1118 
1119  if (c1 != EOF)
1120  {
1121  if (c1 == '0')
1122  {
1123  int c2 = is.peek ();
1124 
1125  if (c2 == 'x' || c2 == 'X')
1126  {
1127  is.ignore ();
1128  if (std::isxdigit (is.peek ()))
1129  is >> std::hex >> ref >> std::dec;
1130  else
1131  ref = 0;
1132  }
1133  else
1134  {
1135  if (c2 == '0' || c2 == '1' || c2 == '2'
1136  || c2 == '3' || c2 == '4' || c2 == '5'
1137  || c2 == '6' || c2 == '7')
1138  is >> std::oct >> ref >> std::dec;
1139  else
1140  ref = 0;
1141  }
1142  }
1143  else
1144  {
1145  is.putback (c1);
1146 
1147  is >> ref;
1148  }
1149  }
1150  }
1151  break;
1152 
1153  default:
1154  is >> ref;
1155  break;
1156  }
1157 
1158  return is;
1159 }
1160 
1161 template <class T>
1162 std::istream&
1163 octave_scan (std::istream& is, const scanf_format_elt& fmt, T* valptr)
1164 {
1165  if (fmt.width)
1166  {
1167  // Limit input to fmt.width characters by reading into a
1168  // temporary stringstream buffer.
1169 
1170  std::string tmp;
1171 
1172  is.width (fmt.width);
1173  is >> tmp;
1174 
1175  std::istringstream ss (tmp);
1176 
1177  octave_scan_1 (ss, fmt, valptr);
1178  }
1179  else
1180  octave_scan_1 (is, fmt, valptr);
1181 
1182  return is;
1183 }
1184 
1185 // Note that this specialization is only used for reading characters, not
1186 // character strings. See BEGIN_S_CONVERSION for details.
1187 
1188 template<>
1189 std::istream&
1190 octave_scan<> (std::istream& is, const scanf_format_elt& /* fmt */,
1191  char* valptr)
1192 {
1193  return is >> valptr;
1194 }
1195 
1196 template<>
1197 std::istream&
1198 octave_scan<> (std::istream& is, const scanf_format_elt& fmt, double* valptr)
1199 {
1200  double& ref = *valptr;
1201 
1202  switch (fmt.type)
1203  {
1204  case 'e':
1205  case 'f':
1206  case 'g':
1207  {
1208  int c1 = EOF;
1209 
1210  while (is && (c1 = is.get ()) != EOF && isspace (c1))
1211  /* skip whitespace */;
1212 
1213  if (c1 != EOF)
1214  {
1215  is.putback (c1);
1216 
1217  ref = octave_read_value<double> (is);
1218  }
1219  }
1220  break;
1221 
1222  default:
1223  panic_impossible ();
1224  break;
1225  }
1226 
1227  return is;
1228 }
1229 
1230 template <class T>
1231 void
1232 do_scanf_conv (std::istream& is, const scanf_format_elt& fmt,
1233  T valptr, Matrix& mval, double *data, octave_idx_type& idx,
1234  octave_idx_type& conversion_count, octave_idx_type nr,
1235  octave_idx_type max_size, bool discard)
1236 {
1237  OCTAVE_SCAN (is, fmt, valptr);
1238 
1239  if (is)
1240  {
1241  if (idx == max_size && ! discard)
1242  {
1243  max_size *= 2;
1244 
1245  if (nr > 0)
1246  mval.resize (nr, max_size / nr, 0.0);
1247  else
1248  mval.resize (max_size, 1, 0.0);
1249 
1250  data = mval.fortran_vec ();
1251  }
1252 
1253  if (! discard)
1254  {
1255  conversion_count++;
1256  data[idx++] = *(valptr);
1257  }
1258  }
1259 }
1260 
1261 template void
1262 do_scanf_conv (std::istream&, const scanf_format_elt&, double*,
1263  Matrix&, double*, octave_idx_type&, octave_idx_type&,
1265 
1266 #define DO_WHITESPACE_CONVERSION() \
1267  do \
1268  { \
1269  int c = EOF; \
1270  \
1271  while (is && (c = is.get ()) != EOF && isspace (c)) \
1272  /* skip whitespace */; \
1273  \
1274  if (c != EOF) \
1275  is.putback (c); \
1276  } \
1277  while (0)
1278 
1279 #define DO_LITERAL_CONVERSION() \
1280  do \
1281  { \
1282  int c = EOF; \
1283  \
1284  int n = strlen (fmt); \
1285  int i = 0; \
1286  \
1287  while (i < n && is && (c = is.get ()) != EOF) \
1288  { \
1289  if (c == static_cast<unsigned char> (fmt[i])) \
1290  { \
1291  i++; \
1292  continue; \
1293  } \
1294  else \
1295  { \
1296  is.putback (c); \
1297  break; \
1298  } \
1299  } \
1300  \
1301  if (i != n) \
1302  is.setstate (std::ios::failbit); \
1303  } \
1304  while (0)
1305 
1306 #define DO_PCT_CONVERSION() \
1307  do \
1308  { \
1309  int c = is.get (); \
1310  \
1311  if (c != EOF) \
1312  { \
1313  if (c != '%') \
1314  { \
1315  is.putback (c); \
1316  is.setstate (std::ios::failbit); \
1317  } \
1318  } \
1319  else \
1320  is.setstate (std::ios::failbit); \
1321  } \
1322  while (0)
1323 
1324 #define BEGIN_C_CONVERSION() \
1325  is.unsetf (std::ios::skipws); \
1326  \
1327  int width = elt->width ? elt->width : 1; \
1328  \
1329  std::string tmp (width, '\0'); \
1330  \
1331  int c = EOF; \
1332  int n = 0; \
1333  \
1334  while (is && n < width && (c = is.get ()) != EOF) \
1335  tmp[n++] = static_cast<char> (c); \
1336  \
1337  if (n > 0 && c == EOF) \
1338  is.clear (); \
1339  \
1340  tmp.resize (n)
1341 
1342 // For a '%s' format, skip initial whitespace and then read until the
1343 // next whitespace character or until WIDTH characters have been read.
1344 #define BEGIN_S_CONVERSION() \
1345  int width = elt->width; \
1346  \
1347  std::string tmp; \
1348  \
1349  do \
1350  { \
1351  if (width) \
1352  { \
1353  tmp = std::string (width, '\0'); \
1354  \
1355  int c = EOF; \
1356  \
1357  int n = 0; \
1358  \
1359  while (is && (c = is.get ()) != EOF) \
1360  { \
1361  if (! isspace (c)) \
1362  { \
1363  tmp[n++] = static_cast<char> (c); \
1364  break; \
1365  } \
1366  } \
1367  \
1368  while (is && n < width && (c = is.get ()) != EOF) \
1369  { \
1370  if (isspace (c)) \
1371  { \
1372  is.putback (c); \
1373  break; \
1374  } \
1375  else \
1376  tmp[n++] = static_cast<char> (c); \
1377  } \
1378  \
1379  if (n > 0 && c == EOF) \
1380  is.clear (); \
1381  \
1382  tmp.resize (n); \
1383  } \
1384  else \
1385  { \
1386  is >> std::ws >> tmp; \
1387  } \
1388  } \
1389  while (0)
1390 
1391 // This format must match a nonempty sequence of characters.
1392 #define BEGIN_CHAR_CLASS_CONVERSION() \
1393  int width = elt->width; \
1394  \
1395  std::string tmp; \
1396  \
1397  do \
1398  { \
1399  if (! width) \
1400  width = std::numeric_limits<int>::max (); \
1401  \
1402  std::ostringstream buf; \
1403  \
1404  std::string char_class = elt->char_class; \
1405  \
1406  int c = EOF; \
1407  \
1408  if (elt->type == '[') \
1409  { \
1410  int chars_read = 0; \
1411  while (is && chars_read++ < width && (c = is.get ()) != EOF \
1412  && char_class.find (c) != std::string::npos) \
1413  buf << static_cast<char> (c); \
1414  } \
1415  else \
1416  { \
1417  int chars_read = 0; \
1418  while (is && chars_read++ < width && (c = is.get ()) != EOF \
1419  && char_class.find (c) == std::string::npos) \
1420  buf << static_cast<char> (c); \
1421  } \
1422  \
1423  if (width == std::numeric_limits<int>::max () && c != EOF) \
1424  is.putback (c); \
1425  \
1426  tmp = buf.str (); \
1427  \
1428  if (tmp.empty ()) \
1429  is.setstate (std::ios::failbit); \
1430  else if (c == EOF) \
1431  is.clear (); \
1432  \
1433  } \
1434  while (0)
1435 
1436 #define FINISH_CHARACTER_CONVERSION() \
1437  do \
1438  { \
1439  width = tmp.length (); \
1440  \
1441  if (is) \
1442  { \
1443  int i = 0; \
1444  \
1445  if (! discard) \
1446  { \
1447  conversion_count++; \
1448  \
1449  while (i < width) \
1450  { \
1451  if (data_index == max_size) \
1452  { \
1453  max_size *= 2; \
1454  \
1455  if (all_char_conv) \
1456  { \
1457  if (one_elt_size_spec) \
1458  mval.resize (1, max_size, 0.0); \
1459  else if (nr > 0) \
1460  mval.resize (nr, max_size / nr, 0.0); \
1461  else \
1462  panic_impossible (); \
1463  } \
1464  else if (nr > 0) \
1465  mval.resize (nr, max_size / nr, 0.0); \
1466  else \
1467  mval.resize (max_size, 1, 0.0); \
1468  \
1469  data = mval.fortran_vec (); \
1470  } \
1471  \
1472  data[data_index++] = tmp[i++]; \
1473  } \
1474  } \
1475  } \
1476  } \
1477  while (0)
1478 
1482  bool one_elt_size_spec,
1483  octave_idx_type& conversion_count,
1484  const std::string& who)
1485 {
1486  octave_value retval = Matrix ();
1487 
1488  if ((interactive || forced_interactive) && file_number () == 0)
1489  {
1490  ::error ("%s: unable to read from stdin while running interactively",
1491  who.c_str ());
1492 
1493  return retval;
1494  }
1495 
1496  conversion_count = 0;
1497 
1498  octave_idx_type nconv = fmt_list.num_conversions ();
1499 
1500  octave_idx_type data_index = 0;
1501 
1502  if (nr == 0 || nc == 0)
1503  {
1504  if (one_elt_size_spec)
1505  nc = 0;
1506 
1507  return Matrix (nr, nc, 0.0);
1508  }
1509 
1510  std::istream *isp = input_stream ();
1511 
1512  bool all_char_conv = fmt_list.all_character_conversions ();
1513 
1514  Matrix mval;
1515  double *data = 0;
1516  octave_idx_type max_size = 0;
1517  octave_idx_type max_conv = 0;
1518 
1519  octave_idx_type final_nr = 0;
1520  octave_idx_type final_nc = 0;
1521 
1522  if (all_char_conv)
1523  {
1524  // Any of these could be resized later (if we have %s
1525  // conversions, we may read more than one element for each
1526  // conversion).
1527 
1528  if (one_elt_size_spec)
1529  {
1530  max_size = 512;
1531  mval.resize (1, max_size, 0.0);
1532 
1533  if (nr > 0)
1534  max_conv = nr;
1535  }
1536  else if (nr > 0)
1537  {
1538  if (nc > 0)
1539  {
1540  mval.resize (nr, nc, 0.0);
1541  max_size = max_conv = nr * nc;
1542  }
1543  else
1544  {
1545  mval.resize (nr, 32, 0.0);
1546  max_size = nr * 32;
1547  }
1548  }
1549  else
1550  panic_impossible ();
1551  }
1552  else if (nr > 0)
1553  {
1554  if (nc > 0)
1555  {
1556  // Will not resize later.
1557  mval.resize (nr, nc, 0.0);
1558  max_size = nr * nc;
1559  max_conv = max_size;
1560  }
1561  else
1562  {
1563  // Maybe resize later.
1564  mval.resize (nr, 32, 0.0);
1565  max_size = nr * 32;
1566  }
1567  }
1568  else
1569  {
1570  // Maybe resize later.
1571  mval.resize (32, 1, 0.0);
1572  max_size = 32;
1573  }
1574 
1575  data = mval.fortran_vec ();
1576 
1577  if (isp)
1578  {
1579  std::istream& is = *isp;
1580 
1581  const scanf_format_elt *elt = fmt_list.first ();
1582 
1583  std::ios::fmtflags flags = is.flags ();
1584 
1585  octave_idx_type trips = 0;
1586 
1587  octave_idx_type num_fmt_elts = fmt_list.length ();
1588 
1589  for (;;)
1590  {
1591  octave_quit ();
1592 
1593  if (elt)
1594  {
1597  || elt->type == '%')
1598  && max_conv > 0 && conversion_count == max_conv)
1599  {
1600  if (all_char_conv && one_elt_size_spec)
1601  {
1602  final_nr = 1;
1603  final_nc = data_index;
1604  }
1605  else
1606  {
1607  final_nr = nr;
1608  final_nc = (data_index - 1) / nr + 1;
1609  }
1610 
1611  break;
1612  }
1613  else if (data_index == max_size)
1614  {
1615  max_size *= 2;
1616 
1617  if (all_char_conv)
1618  {
1619  if (one_elt_size_spec)
1620  mval.resize (1, max_size, 0.0);
1621  else if (nr > 0)
1622  mval.resize (nr, max_size / nr, 0.0);
1623  else
1624  panic_impossible ();
1625  }
1626  else if (nr > 0)
1627  mval.resize (nr, max_size / nr, 0.0);
1628  else
1629  mval.resize (max_size, 1, 0.0);
1630 
1631  data = mval.fortran_vec ();
1632  }
1633 
1634  const char *fmt = elt->text;
1635 
1636  bool discard = elt->discard;
1637 
1638  switch (elt->type)
1639  {
1642  break;
1643 
1646  break;
1647 
1648  case '%':
1649  DO_PCT_CONVERSION ();
1650  break;
1651 
1652  case 'd': case 'i':
1653  {
1654  switch (elt->modifier)
1655  {
1656  case 'h':
1657  {
1658  short int tmp;
1659  do_scanf_conv (is, *elt, &tmp, mval, data,
1660  data_index, conversion_count,
1661  nr, max_size, discard);
1662  }
1663  break;
1664 
1665  case 'l':
1666  {
1667  long int tmp;
1668  do_scanf_conv (is, *elt, &tmp, mval, data,
1669  data_index, conversion_count,
1670  nr, max_size, discard);
1671  }
1672  break;
1673 
1674  default:
1675  {
1676  int tmp;
1677  do_scanf_conv (is, *elt, &tmp, mval, data,
1678  data_index, conversion_count,
1679  nr, max_size, discard);
1680  }
1681  break;
1682  }
1683  }
1684  break;
1685 
1686  case 'o': case 'u': case 'x':
1687  {
1688  switch (elt->modifier)
1689  {
1690  case 'h':
1691  {
1692  unsigned short int tmp;
1693  do_scanf_conv (is, *elt, &tmp, mval, data,
1694  data_index, conversion_count,
1695  nr, max_size, discard);
1696  }
1697  break;
1698 
1699  case 'l':
1700  {
1701  unsigned long int tmp;
1702  do_scanf_conv (is, *elt, &tmp, mval, data,
1703  data_index, conversion_count,
1704  nr, max_size, discard);
1705  }
1706  break;
1707 
1708  default:
1709  {
1710  unsigned int tmp;
1711  do_scanf_conv (is, *elt, &tmp, mval, data,
1712  data_index, conversion_count,
1713  nr, max_size, discard);
1714  }
1715  break;
1716  }
1717  }
1718  break;
1719 
1720  case 'e': case 'f': case 'g':
1721  {
1722  double tmp;
1723 
1724  do_scanf_conv (is, *elt, &tmp, mval, data,
1725  data_index, conversion_count,
1726  nr, max_size, discard);
1727  }
1728  break;
1729 
1730  case 'c':
1731  {
1732  BEGIN_C_CONVERSION ();
1733 
1735 
1736  is.setf (flags);
1737  }
1738  break;
1739 
1740  case 's':
1741  {
1742  BEGIN_S_CONVERSION ();
1743 
1745  }
1746  break;
1747 
1748  case '[': case '^':
1749  {
1751 
1753  }
1754  break;
1755 
1756  case 'p':
1757  error ("%s: unsupported format specifier", who.c_str ());
1758  break;
1759 
1760  default:
1761  error ("%s: internal format error", who.c_str ());
1762  break;
1763  }
1764 
1765  if (! ok ())
1766  {
1767  break;
1768  }
1769  else if (! is)
1770  {
1771  if (all_char_conv)
1772  {
1773  if (one_elt_size_spec)
1774  {
1775  final_nr = 1;
1776  final_nc = data_index;
1777  }
1778  else if (data_index > nr)
1779  {
1780  final_nr = nr;
1781  final_nc = (data_index - 1) / nr + 1;
1782  }
1783  else
1784  {
1785  final_nr = data_index;
1786  final_nc = 1;
1787  }
1788  }
1789  else if (nr > 0)
1790  {
1791  if (data_index > nr)
1792  {
1793  final_nr = nr;
1794  final_nc = (data_index - 1) / nr + 1;
1795  }
1796  else
1797  {
1798  final_nr = data_index;
1799  final_nc = 1;
1800  }
1801  }
1802  else
1803  {
1804  final_nr = data_index;
1805  final_nc = 1;
1806  }
1807 
1808  // If it looks like we have a matching failure, then
1809  // reset the failbit in the stream state.
1810 
1811  if (is.rdstate () & std::ios::failbit)
1812  is.clear (is.rdstate () & (~std::ios::failbit));
1813 
1814  // FIXME: is this the right thing to do?
1815 
1816  if (interactive && name () == "stdin")
1817  {
1818  is.clear ();
1819 
1820  // Skip to end of line.
1821 
1822  bool err;
1823  do_gets (-1, err, false, who);
1824  }
1825 
1826  break;
1827  }
1828  }
1829  else
1830  {
1831  error ("%s: internal format error", who.c_str ());
1832  break;
1833  }
1834 
1835  if (nconv == 0 && ++trips == num_fmt_elts)
1836  {
1837  if (all_char_conv && one_elt_size_spec)
1838  {
1839  final_nr = 1;
1840  final_nc = data_index;
1841  }
1842  else
1843  {
1844  final_nr = nr;
1845  final_nc = (data_index - 1) / nr + 1;
1846  }
1847 
1848  break;
1849  }
1850  else
1851  elt = fmt_list.next (nconv > 0);
1852  }
1853  }
1854 
1855  if (ok ())
1856  {
1857  mval.resize (final_nr, final_nc, 0.0);
1858 
1859  retval = mval;
1860 
1861  if (all_char_conv)
1862  retval = retval.convert_to_str (false, true);
1863  }
1864 
1865  return retval;
1866 }
1867 
1869 octave_base_stream::scanf (const std::string& fmt, const Array<double>& size,
1870  octave_idx_type& conversion_count,
1871  const std::string& who)
1872 {
1873  octave_value retval = Matrix ();
1874 
1875  conversion_count = 0;
1876 
1877  std::istream *isp = input_stream ();
1878 
1879  if (isp)
1880  {
1881  scanf_format_list fmt_list (fmt);
1882 
1883  if (fmt_list.num_conversions () == -1)
1884  ::error ("%s: invalid format specified", who.c_str ());
1885  else
1886  {
1887  octave_idx_type nr = -1;
1888  octave_idx_type nc = -1;
1889 
1890  bool one_elt_size_spec;
1891 
1892  get_size (size, nr, nc, one_elt_size_spec, who);
1893 
1894  if (! error_state)
1895  retval = do_scanf (fmt_list, nr, nc, one_elt_size_spec,
1896  conversion_count, who);
1897  }
1898  }
1899  else
1900  invalid_operation (who, "reading");
1901 
1902  return retval;
1903 }
1904 
1905 bool
1907  octave_value& retval, const std::string& who)
1908 {
1909  bool quit = false;
1910 
1911  std::istream *isp = input_stream ();
1912 
1913  if (isp)
1914  {
1915  std::istream& is = *isp;
1916 
1917  std::ios::fmtflags flags = is.flags ();
1918 
1919  if (elt)
1920  {
1921  const char *fmt = elt->text;
1922 
1923  bool discard = elt->discard;
1924 
1925  switch (elt->type)
1926  {
1929  break;
1930 
1933  break;
1934 
1935  case '%':
1936  {
1937  DO_PCT_CONVERSION ();
1938 
1939  if (! is)
1940  quit = true;
1941 
1942  }
1943  break;
1944 
1945  case 'd': case 'i':
1946  {
1947  int tmp;
1948 
1949  if (OCTAVE_SCAN (is, *elt, &tmp))
1950  {
1951  if (! discard)
1952  retval = tmp;
1953  }
1954  else
1955  quit = true;
1956  }
1957  break;
1958 
1959  case 'o': case 'u': case 'x':
1960  {
1961  long int tmp;
1962 
1963  if (OCTAVE_SCAN (is, *elt, &tmp))
1964  {
1965  if (! discard)
1966  retval = tmp;
1967  }
1968  else
1969  quit = true;
1970  }
1971  break;
1972 
1973  case 'e': case 'f': case 'g':
1974  {
1975  double tmp;
1976 
1977  if (OCTAVE_SCAN (is, *elt, &tmp))
1978  {
1979  if (! discard)
1980  retval = tmp;
1981  }
1982  else
1983  quit = true;
1984  }
1985  break;
1986 
1987  case 'c':
1988  {
1989  BEGIN_C_CONVERSION ();
1990 
1991  if (! discard)
1992  retval = tmp;
1993 
1994  if (! is)
1995  quit = true;
1996 
1997  is.setf (flags);
1998  }
1999  break;
2000 
2001  case 's':
2002  {
2003  BEGIN_S_CONVERSION ();
2004 
2005  if (! discard)
2006  retval = tmp;
2007 
2008  if (! is)
2009  quit = true;
2010  }
2011  break;
2012 
2013  case '[': case '^':
2014  {
2016 
2017  if (! discard)
2018  retval = tmp;
2019 
2020  if (! is)
2021  quit = true;
2022  }
2023  break;
2024 
2025  case 'p':
2026  error ("%s: unsupported format specifier", who.c_str ());
2027  break;
2028 
2029  default:
2030  error ("%s: internal format error", who.c_str ());
2031  break;
2032  }
2033  }
2034 
2035  if (ok () && is.fail ())
2036  {
2037  error ("%s: read error", who.c_str ());
2038 
2039  // FIXME: is this the right thing to do?
2040 
2041  if (interactive && name () == "stdin")
2042  {
2043  // Skip to end of line.
2044 
2045  bool err;
2046  do_gets (-1, err, false, who);
2047  }
2048  }
2049  }
2050 
2051  return quit;
2052 }
2053 
2055 octave_base_stream::oscanf (const std::string& fmt, const std::string& who)
2056 {
2057  octave_value_list retval;
2058 
2059  std::istream *isp = input_stream ();
2060 
2061  if (isp)
2062  {
2063  std::istream& is = *isp;
2064 
2065  scanf_format_list fmt_list (fmt);
2066 
2067  octave_idx_type nconv = fmt_list.num_conversions ();
2068 
2069  if (nconv == -1)
2070  ::error ("%s: invalid format specified", who.c_str ());
2071  else
2072  {
2073  is.clear ();
2074 
2075  octave_idx_type len = fmt_list.length ();
2076 
2077  retval.resize (nconv+2, Matrix ());
2078 
2079  const scanf_format_elt *elt = fmt_list.first ();
2080 
2081  int num_values = 0;
2082 
2083  bool quit = false;
2084 
2085  for (octave_idx_type i = 0; i < len; i++)
2086  {
2087  octave_value tmp;
2088 
2089  quit = do_oscanf (elt, tmp, who);
2090 
2091  if (quit)
2092  break;
2093  else
2094  {
2095  if (tmp.is_defined ())
2096  retval(num_values++) = tmp;
2097 
2098  if (! ok ())
2099  break;
2100 
2101  elt = fmt_list.next (nconv > 0);
2102  }
2103  }
2104 
2105  retval(nconv) = num_values;
2106 
2107  int err_num;
2108  retval(nconv+1) = error (false, err_num);
2109 
2110  if (! quit)
2111  {
2112  // Pick up any trailing stuff.
2113  if (ok () && len > nconv)
2114  {
2115  octave_value tmp;
2116 
2117  elt = fmt_list.next ();
2118 
2119  do_oscanf (elt, tmp, who);
2120  }
2121  }
2122  }
2123  }
2124  else
2125  invalid_operation (who, "reading");
2126 
2127  return retval;
2128 }
2129 
2130 // Functions that are defined for all output streams (output streams
2131 // are those that define os).
2132 
2133 int
2135 {
2136  int retval = -1;
2137 
2138  std::ostream *os = output_stream ();
2139 
2140  if (os)
2141  {
2142  os->flush ();
2143 
2144  if (os->good ())
2145  retval = 0;
2146  }
2147  else
2148  invalid_operation ("fflush", "writing");
2149 
2150  return retval;
2151 }
2152 
2153 class
2155 {
2156 public:
2157 
2158  enum state { ok, conversion_error };
2159 
2160  printf_value_cache (const octave_value_list& args, const std::string& who)
2161  : values (args), val_idx (0), elt_idx (0),
2162  n_vals (values.length ()), n_elts (0), data (0),
2163  curr_state (ok)
2164  {
2165  for (octave_idx_type i = 0; i < values.length (); i++)
2166  {
2167  octave_value val = values(i);
2168 
2169  if (val.is_map () || val.is_cell () || val.is_object ())
2170  {
2171  gripe_wrong_type_arg (who, val);
2172  break;
2173  }
2174  }
2175  }
2176 
2178 
2179  // Get the current value as a double and advance the internal pointer.
2180  double double_value (void);
2181 
2182  // Get the current value as an int and advance the internal pointer.
2183  int int_value (void);
2184 
2185  // Get the current value as a string and advance the internal pointer.
2186  std::string string_value (void);
2187 
2188  operator bool () const { return (curr_state == ok); }
2189 
2190  bool exhausted (void) { return (val_idx >= n_vals); }
2191 
2192 private:
2193 
2195  int val_idx;
2196  int elt_idx;
2197  int n_vals;
2198  int n_elts;
2199  const double *data;
2202 
2203  // Must create value cache with values!
2204 
2205  printf_value_cache (void);
2206 
2207  // No copying!
2208 
2210 
2211  printf_value_cache& operator = (const printf_value_cache&);
2212 };
2213 
2214 double
2216 {
2217  double retval = 0.0;
2218 
2219  if (exhausted ())
2221 
2222  while (! exhausted ())
2223  {
2224  if (! data)
2225  {
2226  octave_value tmp_val = values (val_idx);
2227 
2228  // Force string conversion here for compatibility.
2229 
2230  curr_val = tmp_val.array_value (true);
2231 
2232  if (! error_state)
2233  {
2234  elt_idx = 0;
2235  n_elts = curr_val.length ();
2236  data = curr_val.data ();
2237  }
2238  else
2239  {
2241  break;
2242  }
2243  }
2244 
2245  if (elt_idx < n_elts)
2246  {
2247  retval = data[elt_idx++];
2248 
2249  if (elt_idx >= n_elts)
2250  {
2251  elt_idx = 0;
2252  val_idx++;
2253  data = 0;
2254  }
2255 
2256  break;
2257  }
2258  else
2259  {
2260  val_idx++;
2261  data = 0;
2262 
2263  if (n_elts == 0 && exhausted ())
2265 
2266  continue;
2267  }
2268  }
2269 
2270  return retval;
2271 }
2272 
2273 int
2275 {
2276  int retval = 0;
2277 
2278  double dval = double_value ();
2279 
2280  if (! error_state)
2281  {
2282  if (D_NINT (dval) == dval)
2283  retval = NINT (dval);
2284  else
2286  }
2287 
2288  return retval;
2289 }
2290 
2291 std::string
2293 {
2294  std::string retval;
2295 
2296  if (exhausted ())
2298  else
2299  {
2300  octave_value tval = values (val_idx++);
2301 
2302  if (tval.rows () == 1)
2303  retval = tval.string_value ();
2304  else
2305  {
2306  // In the name of Matlab compatibility.
2307 
2308  charMatrix chm = tval.char_matrix_value ();
2309 
2310  octave_idx_type nr = chm.rows ();
2311  octave_idx_type nc = chm.columns ();
2312 
2313  int k = 0;
2314 
2315  retval.resize (nr * nc, '\0');
2316 
2317  for (octave_idx_type j = 0; j < nc; j++)
2318  for (octave_idx_type i = 0; i < nr; i++)
2319  retval[k++] = chm(i,j);
2320  }
2321 
2322  if (error_state)
2324  }
2325 
2326  return retval;
2327 }
2328 
2329 // Ugh again and again.
2330 
2331 template <class T>
2332 int
2333 do_printf_conv (std::ostream& os, const char *fmt, int nsa, int sa_1,
2334  int sa_2, T arg, const std::string& who)
2335 {
2336  int retval = 0;
2337 
2338  switch (nsa)
2339  {
2340  case 2:
2341  retval = octave_format (os, fmt, sa_1, sa_2, arg);
2342  break;
2343 
2344  case 1:
2345  retval = octave_format (os, fmt, sa_1, arg);
2346  break;
2347 
2348  case 0:
2349  retval = octave_format (os, fmt, arg);
2350  break;
2351 
2352  default:
2353  ::error ("%s: internal error handling format", who.c_str ());
2354  break;
2355  }
2356 
2357  return retval;
2358 }
2359 
2360 #define DO_DOUBLE_CONV(TQUAL) \
2361  do \
2362  { \
2363  if (val > std::numeric_limits<TQUAL long>::max () \
2364  || val < std::numeric_limits<TQUAL long>::min ()) \
2365  { \
2366  std::string tfmt = fmt; \
2367  \
2368  tfmt.replace (tfmt.rfind (elt->type), 1, ".f"); \
2369  \
2370  if (elt->modifier == 'l') \
2371  tfmt.replace (tfmt.rfind (elt->modifier), 1, ""); \
2372  \
2373  retval += do_printf_conv (os, tfmt.c_str (), nsa, sa_1, sa_2, \
2374  val, who); \
2375  } \
2376  else \
2377  retval += do_printf_conv (os, fmt, nsa, sa_1, sa_2, \
2378  static_cast<TQUAL long> (val), who); \
2379  } \
2380  while (0)
2381 
2382 int
2384  const octave_value_list& args,
2385  const std::string& who)
2386 {
2387  int retval = 0;
2388 
2389  octave_idx_type nconv = fmt_list.num_conversions ();
2390 
2391  std::ostream *osp = output_stream ();
2392 
2393  if (osp)
2394  {
2395  std::ostream& os = *osp;
2396 
2397  const printf_format_elt *elt = fmt_list.first ();
2398 
2399  printf_value_cache val_cache (args, who);
2400 
2401  if (error_state)
2402  return retval;
2403 
2404  for (;;)
2405  {
2406  octave_quit ();
2407 
2408  if (elt)
2409  {
2410  // NSA is the number of 'star' args to convert.
2411 
2412  int nsa = (elt->fw < 0) + (elt->prec < 0);
2413 
2414  int sa_1 = 0;
2415  int sa_2 = 0;
2416 
2417  if (nsa > 0)
2418  {
2419  sa_1 = val_cache.int_value ();
2420 
2421  if (! val_cache)
2422  break;
2423  else
2424  {
2425  if (nsa > 1)
2426  {
2427  sa_2 = val_cache.int_value ();
2428 
2429  if (! val_cache)
2430  break;
2431  }
2432  }
2433  }
2434 
2435  const char *fmt = elt->text;
2436 
2437  if (elt->type == '%')
2438  {
2439  os << "%";
2440  retval++;
2441  }
2442  else if (elt->args == 0 && elt->text)
2443  {
2444  os << elt->text;
2445  retval += strlen (elt->text);
2446  }
2447  else if (elt->type == 's')
2448  {
2449  std::string val = val_cache.string_value ();
2450 
2451  if (val_cache)
2452  retval += do_printf_conv (os, fmt, nsa, sa_1,
2453  sa_2, val.c_str (), who);
2454  else
2455  break;
2456  }
2457  else
2458  {
2459  double val = val_cache.double_value ();
2460 
2461  if (val_cache)
2462  {
2463  if (lo_ieee_isnan (val) || xisinf (val))
2464  {
2465  std::string tfmt = fmt;
2466  std::string::size_type i1, i2;
2467 
2468  tfmt.replace ((i1 = tfmt.rfind (elt->type)),
2469  1, 1, 's');
2470 
2471  if ((i2 = tfmt.rfind ('.')) != std::string::npos
2472  && i2 < i1)
2473  {
2474  tfmt.erase (i2, i1-i2);
2475  if (elt->prec < 0)
2476  nsa--;
2477  }
2478 
2479  const char *tval;
2480  if (xisinf (val))
2481  if (elt->flags.find ('+') != std::string::npos)
2482  tval = (val < 0 ? "-Inf" : "+Inf");
2483  else
2484  tval = (val < 0 ? "-Inf" : "Inf");
2485  else
2486  if (elt->flags.find ('+') != std::string::npos)
2487  tval = (lo_ieee_is_NA (val) ? "+NA" : "+NaN");
2488  else
2489  tval = (lo_ieee_is_NA (val) ? "NA" : "NaN");
2490 
2491  retval += do_printf_conv (os, tfmt.c_str (),
2492  nsa, sa_1, sa_2,
2493  tval, who);
2494  }
2495  else
2496  {
2497  char type = elt->type;
2498 
2499  switch (type)
2500  {
2501  case 'd': case 'i': case 'c':
2502  DO_DOUBLE_CONV (OCTAVE_EMPTY_CPP_ARG);
2503  break;
2504 
2505  case 'o': case 'x': case 'X': case 'u':
2506  DO_DOUBLE_CONV (unsigned);
2507  break;
2508 
2509  case 'f': case 'e': case 'E':
2510  case 'g': case 'G':
2511  retval += do_printf_conv (os, fmt, nsa,
2512  sa_1, sa_2, val, who);
2513  break;
2514 
2515  default:
2516  error ("%s: invalid format specifier",
2517  who.c_str ());
2518  return -1;
2519  break;
2520  }
2521  }
2522  }
2523  else
2524  break;
2525  }
2526 
2527  if (! os)
2528  {
2529  error ("%s: write error", who.c_str ());
2530  break;
2531  }
2532  }
2533  else
2534  {
2535  ::error ("%s: internal error handling format", who.c_str ());
2536  retval = -1;
2537  break;
2538  }
2539 
2540  elt = fmt_list.next (nconv > 0 && ! val_cache.exhausted ());
2541 
2542  if (! elt || (val_cache.exhausted () && elt->args > 0))
2543  break;
2544  }
2545  }
2546  else
2547  invalid_operation (who, "writing");
2548 
2549  return retval;
2550 }
2551 
2552 int
2553 octave_base_stream::printf (const std::string& fmt,
2554  const octave_value_list& args,
2555  const std::string& who)
2556 {
2557  int retval = 0;
2558 
2559  printf_format_list fmt_list (fmt);
2560 
2561  if (fmt_list.num_conversions () == -1)
2562  ::error ("%s: invalid format specified", who.c_str ());
2563  else
2564  retval = do_printf (fmt_list, args, who);
2565 
2566  return retval;
2567 }
2568 
2569 int
2570 octave_base_stream::puts (const std::string& s, const std::string& who)
2571 {
2572  int retval = -1;
2573 
2574  std::ostream *osp = output_stream ();
2575 
2576  if (osp)
2577  {
2578  std::ostream& os = *osp;
2579 
2580  os << s;
2581 
2582  if (os)
2583  {
2584  // FIXME: why does this seem to be necessary?
2585  // Without it, output from a loop like
2586  //
2587  // for i = 1:100, fputs (stdout, "foo\n"); endfor
2588  //
2589  // doesn't seem to go to the pager immediately.
2590 
2591  os.flush ();
2592 
2593  if (os)
2594  retval = 0;
2595  else
2596  error ("%s: write error", who.c_str ());
2597  }
2598  else
2599  error ("%s: write error", who.c_str ());
2600  }
2601  else
2602  invalid_operation (who, "writing");
2603 
2604  return retval;
2605 }
2606 
2607 // Return current error message for this stream.
2608 
2609 std::string
2610 octave_base_stream::error (bool clear_err, int& err_num)
2611 {
2612  err_num = fail ? -1 : 0;
2613 
2614  std::string tmp = errmsg;
2615 
2616  if (clear_err)
2617  clear ();
2618 
2619  return tmp;
2620 }
2621 
2622 void
2623 octave_base_stream::invalid_operation (const std::string& who, const char *rw)
2624 {
2625  // Note that this is not ::error () !
2626 
2627  error (who, std::string ("stream not open for ") + rw);
2628 }
2629 
2631  : rep (bs)
2632 {
2633  if (rep)
2634  rep->count = 1;
2635 }
2636 
2638 {
2639  if (rep && --rep->count == 0)
2640  delete rep;
2641 }
2642 
2644  : rep (s.rep)
2645 {
2646  if (rep)
2647  rep->count++;
2648 }
2649 
2652 {
2653  if (rep != s.rep)
2654  {
2655  if (rep && --rep->count == 0)
2656  delete rep;
2657 
2658  rep = s.rep;
2659 
2660  if (rep)
2661  rep->count++;
2662  }
2663 
2664  return *this;
2665 }
2666 
2667 int
2669 {
2670  int retval = -1;
2671 
2672  if (stream_ok ())
2673  retval = rep->flush ();
2674 
2675  return retval;
2676 }
2677 
2678 std::string
2679 octave_stream::getl (octave_idx_type max_len, bool& err, const std::string& who)
2680 {
2681  std::string retval;
2682 
2683  if (stream_ok ())
2684  retval = rep->getl (max_len, err, who);
2685 
2686  return retval;
2687 }
2688 
2689 std::string
2690 octave_stream::getl (const octave_value& tc_max_len, bool& err,
2691  const std::string& who)
2692 {
2693  std::string retval;
2694 
2695  err = false;
2696 
2697  int conv_err = 0;
2698 
2699  int max_len = -1;
2700 
2701  if (tc_max_len.is_defined ())
2702  {
2703  max_len = convert_to_valid_int (tc_max_len, conv_err);
2704 
2705  if (conv_err || max_len < 0)
2706  {
2707  err = true;
2708  ::error ("%s: invalid maximum length specified", who.c_str ());
2709  }
2710  }
2711 
2712  if (! error_state)
2713  retval = getl (max_len, err, who);
2714 
2715  return retval;
2716 }
2717 
2718 std::string
2719 octave_stream::gets (octave_idx_type max_len, bool& err, const std::string& who)
2720 {
2721  std::string retval;
2722 
2723  if (stream_ok ())
2724  retval = rep->gets (max_len, err, who);
2725 
2726  return retval;
2727 }
2728 
2729 std::string
2730 octave_stream::gets (const octave_value& tc_max_len, bool& err,
2731  const std::string& who)
2732 {
2733  std::string retval;
2734 
2735  err = false;
2736 
2737  int conv_err = 0;
2738 
2739  int max_len = -1;
2740 
2741  if (tc_max_len.is_defined ())
2742  {
2743  max_len = convert_to_valid_int (tc_max_len, conv_err);
2744 
2745  if (conv_err || max_len < 0)
2746  {
2747  err = true;
2748  ::error ("%s: invalid maximum length specified", who.c_str ());
2749  }
2750  }
2751 
2752  if (! error_state)
2753  retval = gets (max_len, err, who);
2754 
2755  return retval;
2756 }
2757 
2758 off_t
2759 octave_stream::skipl (off_t count, bool& err, const std::string& who)
2760 {
2761  off_t retval = -1;
2762 
2763  if (stream_ok ())
2764  retval = rep->skipl (count, err, who);
2765 
2766  return retval;
2767 }
2768 
2769 off_t
2770 octave_stream::skipl (const octave_value& tc_count, bool& err,
2771  const std::string& who)
2772 {
2773  off_t retval = -1;
2774 
2775  err = false;
2776 
2777  int conv_err = 0;
2778 
2779  int count = 1;
2780 
2781  if (tc_count.is_defined ())
2782  {
2783  if (tc_count.is_scalar_type () && xisinf (tc_count.scalar_value ()))
2784  count = -1;
2785  else
2786  {
2787  count = convert_to_valid_int (tc_count, conv_err);
2788 
2789  if (conv_err || count < 0)
2790  {
2791  err = true;
2792  ::error ("%s: invalid number of lines specified", who.c_str ());
2793  }
2794  }
2795  }
2796 
2797  if (! error_state)
2798  retval = skipl (count, err, who);
2799 
2800  return retval;
2801 }
2802 
2803 int
2804 octave_stream::seek (off_t offset, int origin)
2805 {
2806  int status = -1;
2807 
2808  if (stream_ok ())
2809  {
2810  clearerr ();
2811 
2812  // Find current position so we can return to it if needed.
2813 
2814  off_t orig_pos = rep->tell ();
2815 
2816  // Move to end of file. If successful, find the offset of the end.
2817 
2818  status = rep->seek (0, SEEK_END);
2819 
2820  if (status == 0)
2821  {
2822  off_t eof_pos = rep->tell ();
2823 
2824  if (origin == SEEK_CUR)
2825  {
2826  // Move back to original position, otherwise we will be
2827  // seeking from the end of file which is probably not the
2828  // original location.
2829 
2830  rep->seek (orig_pos, SEEK_SET);
2831  }
2832 
2833  // Attempt to move to desired position; may be outside bounds
2834  // of existing file.
2835 
2836  status = rep->seek (offset, origin);
2837 
2838  if (status == 0)
2839  {
2840  // Where are we after moving to desired position?
2841 
2842  off_t desired_pos = rep->tell ();
2843 
2844  // I don't think save_pos can be less than zero, but we'll
2845  // check anyway...
2846 
2847  if (desired_pos > eof_pos || desired_pos < 0)
2848  {
2849  // Seek outside bounds of file. Failure should leave
2850  // position unchanged.
2851 
2852  rep->seek (orig_pos, SEEK_SET);
2853 
2854  status = -1;
2855  }
2856  }
2857  else
2858  {
2859  // Seeking to the desired position failed. Move back to
2860  // original position and return failure status.
2861 
2862  rep->seek (orig_pos, SEEK_SET);
2863 
2864  status = -1;
2865  }
2866  }
2867  }
2868 
2869  return status;
2870 }
2871 
2872 int
2874  const octave_value& tc_origin)
2875 {
2876  int retval = -1;
2877 
2878  // FIXME: should we have octave_value methods that handle off_t explicitly?
2879  octave_int64 val = tc_offset.int64_scalar_value ();
2880  off_t xoffset = val.value ();
2881 
2882  if (! error_state)
2883  {
2884  int conv_err = 0;
2885 
2886  int origin = SEEK_SET;
2887 
2888  if (tc_origin.is_string ())
2889  {
2890  std::string xorigin = tc_origin.string_value ();
2891 
2892  if (xorigin == "bof")
2893  origin = SEEK_SET;
2894  else if (xorigin == "cof")
2895  origin = SEEK_CUR;
2896  else if (xorigin == "eof")
2897  origin = SEEK_END;
2898  else
2899  conv_err = -1;
2900  }
2901  else
2902  {
2903  int xorigin = convert_to_valid_int (tc_origin, conv_err);
2904 
2905  if (! conv_err)
2906  {
2907  if (xorigin == -1)
2908  origin = SEEK_SET;
2909  else if (xorigin == 0)
2910  origin = SEEK_CUR;
2911  else if (xorigin == 1)
2912  origin = SEEK_END;
2913  else
2914  conv_err = -1;
2915  }
2916  }
2917 
2918  if (! conv_err)
2919  {
2920  retval = seek (xoffset, origin);
2921 
2922  if (retval != 0)
2923  error ("fseek: failed to seek to requested position");
2924  }
2925  else
2926  error ("fseek: invalid value for origin");
2927  }
2928  else
2929  error ("fseek: invalid value for offset");
2930 
2931  return retval;
2932 }
2933 
2934 off_t
2936 {
2937  off_t retval = -1;
2938 
2939  if (stream_ok ())
2940  retval = rep->tell ();
2941 
2942  return retval;
2943 }
2944 
2945 int
2947 {
2948  return seek (0, SEEK_SET);
2949 }
2950 
2951 bool
2953 {
2954  bool retval = false;
2955 
2956  if (stream_ok ())
2957  retval = rep->is_open ();
2958 
2959  return retval;
2960 }
2961 
2962 void
2964 {
2965  if (stream_ok ())
2966  rep->close ();
2967 }
2968 
2969 template <class SRC_T, class DST_T>
2970 static octave_value
2971 convert_and_copy (std::list<void *>& input_buf_list,
2972  octave_idx_type input_buf_elts,
2973  octave_idx_type elts_read,
2974  octave_idx_type nr, octave_idx_type nc, bool swap,
2975  bool do_float_fmt_conv, bool do_NA_conv,
2976  oct_mach_info::float_format from_flt_fmt)
2977 {
2978  typedef typename DST_T::element_type dst_elt_type;
2979 
2980  DST_T conv (dim_vector (nr, nc));
2981 
2982  dst_elt_type *conv_data = conv.fortran_vec ();
2983 
2984  octave_idx_type j = 0;
2985 
2986  for (std::list<void *>::const_iterator it = input_buf_list.begin ();
2987  it != input_buf_list.end (); it++)
2988  {
2989  SRC_T *data = static_cast<SRC_T *> (*it);
2990 
2991  if (swap || do_float_fmt_conv)
2992  {
2993  for (octave_idx_type i = 0; i < input_buf_elts && j < elts_read;
2994  i++, j++)
2995  {
2996  if (swap)
2997  swap_bytes<sizeof (SRC_T)> (&data[i]);
2998  else if (do_float_fmt_conv)
2999  do_float_format_conversion (&data[i], sizeof (SRC_T),
3000  1, from_flt_fmt,
3002 
3003  dst_elt_type tmp (data[i]);
3004 
3005  if (do_NA_conv && __lo_ieee_is_old_NA (tmp))
3006  tmp = __lo_ieee_replace_old_NA (tmp);
3007 
3008  conv_data[j] = tmp;
3009  }
3010  }
3011  else
3012  {
3013  if (do_NA_conv)
3014  {
3015  for (octave_idx_type i = 0; i < input_buf_elts && j < elts_read;
3016  i++, j++)
3017  {
3018  dst_elt_type tmp (data[i]);
3019 
3020  if (__lo_ieee_is_old_NA (tmp))
3021  tmp = __lo_ieee_replace_old_NA (tmp);
3022 
3023  conv_data[j] = tmp;
3024  }
3025  }
3026  else
3027  {
3028  for (octave_idx_type i = 0; i < input_buf_elts && j < elts_read;
3029  i++, j++)
3030  conv_data[j] = data[i];
3031  }
3032  }
3033 
3034  delete [] data;
3035  }
3036 
3037  input_buf_list.clear ();
3038 
3039  for (octave_idx_type i = elts_read; i < nr * nc; i++)
3040  conv_data[i] = dst_elt_type (0);
3041 
3042  return conv;
3043 }
3044 
3045 typedef octave_value (*conv_fptr)
3046  (std::list<void *>& input_buf_list, octave_idx_type input_buf_elts,
3048  bool swap, bool do_float_fmt_conv, bool do_NA_conv,
3049  oct_mach_info::float_format from_flt_fmt);
3050 
3051 #define TABLE_ELT(T, U, V, W) \
3052  conv_fptr_table[oct_data_conv::T][oct_data_conv::U] = convert_and_copy<V, W>
3053 
3054 #define FILL_TABLE_ROW(T, V) \
3055  TABLE_ELT (T, dt_int8, V, int8NDArray); \
3056  TABLE_ELT (T, dt_uint8, V, uint8NDArray); \
3057  TABLE_ELT (T, dt_int16, V, int16NDArray); \
3058  TABLE_ELT (T, dt_uint16, V, uint16NDArray); \
3059  TABLE_ELT (T, dt_int32, V, int32NDArray); \
3060  TABLE_ELT (T, dt_uint32, V, uint32NDArray); \
3061  TABLE_ELT (T, dt_int64, V, int64NDArray); \
3062  TABLE_ELT (T, dt_uint64, V, uint64NDArray); \
3063  TABLE_ELT (T, dt_single, V, FloatNDArray); \
3064  TABLE_ELT (T, dt_double, V, NDArray); \
3065  TABLE_ELT (T, dt_char, V, charNDArray); \
3066  TABLE_ELT (T, dt_schar, V, charNDArray); \
3067  TABLE_ELT (T, dt_uchar, V, charNDArray); \
3068  TABLE_ELT (T, dt_logical, V, boolNDArray);
3069 
3071 octave_stream::finalize_read (std::list<void *>& input_buf_list,
3072  octave_idx_type input_buf_elts,
3073  octave_idx_type elts_read,
3075  oct_data_conv::data_type input_type,
3076  oct_data_conv::data_type output_type,
3078 {
3079  octave_value retval;
3080 
3081  static bool initialized = false;
3082 
3083  // Table function pointers for return types x read types.
3084 
3085  static conv_fptr conv_fptr_table[oct_data_conv::dt_unknown][14];
3086 
3087  if (! initialized)
3088  {
3089  for (int i = 0; i < oct_data_conv::dt_unknown; i++)
3090  for (int j = 0; j < 14; j++)
3091  conv_fptr_table[i][j] = 0;
3092 
3093  FILL_TABLE_ROW (dt_int8, int8_t);
3094  FILL_TABLE_ROW (dt_uint8, uint8_t);
3095  FILL_TABLE_ROW (dt_int16, int16_t);
3096  FILL_TABLE_ROW (dt_uint16, uint16_t);
3097  FILL_TABLE_ROW (dt_int32, int32_t);
3098  FILL_TABLE_ROW (dt_uint32, uint32_t);
3099  FILL_TABLE_ROW (dt_int64, int64_t);
3100  FILL_TABLE_ROW (dt_uint64, uint64_t);
3101  FILL_TABLE_ROW (dt_single, float);
3102  FILL_TABLE_ROW (dt_double, double);
3103  FILL_TABLE_ROW (dt_char, char);
3104  FILL_TABLE_ROW (dt_schar, signed char);
3105  FILL_TABLE_ROW (dt_uchar, unsigned char);
3106  FILL_TABLE_ROW (dt_logical, bool);
3107 
3108  initialized = true;
3109  }
3110 
3111  bool swap = false;
3112 
3113  if (ffmt == oct_mach_info::flt_fmt_unknown)
3114  ffmt = float_format ();
3115 
3118  else
3119  swap = (ffmt == oct_mach_info::flt_fmt_ieee_big_endian);
3120 
3121  bool do_float_fmt_conv = ((input_type == oct_data_conv::dt_double
3122  || input_type == oct_data_conv::dt_single)
3123  && ffmt != float_format ());
3124 
3125  bool do_NA_conv = (output_type == oct_data_conv::dt_double);
3126 
3127  switch (output_type)
3128  {
3143  {
3144  conv_fptr fptr = conv_fptr_table[input_type][output_type];
3145 
3146  retval = fptr (input_buf_list, input_buf_elts, elts_read,
3147  nr, nc, swap, do_float_fmt_conv, do_NA_conv, ffmt);
3148  }
3149  break;
3150 
3151  default:
3152  retval = false;
3153  (*current_liboctave_error_handler)
3154  ("read: invalid type specification");
3155  break;
3156  }
3157 
3158 
3159  return retval;
3160 }
3161 
3164  oct_data_conv::data_type input_type,
3165  oct_data_conv::data_type output_type,
3167  octave_idx_type& char_count)
3168 {
3169  octave_value retval;
3170 
3171  octave_idx_type nr = -1;
3172  octave_idx_type nc = -1;
3173 
3174  bool one_elt_size_spec = false;
3175 
3176  if (stream_ok ())
3177  {
3178  // FIXME: we may eventually want to make this extensible.
3179 
3180  // FIXME: we need a better way to ensure that this
3181  // numbering stays consistent with the order of the elements in the
3182  // data_type enum in the oct_data_conv class.
3183 
3184  char_count = 0;
3185 
3186  get_size (size, nr, nc, one_elt_size_spec, "fread");
3187 
3188  if (! error_state)
3189  {
3190 
3191  octave_idx_type elts_to_read
3193 
3194  if (one_elt_size_spec)
3195  {
3196  // If NR == 0, Matlab returns [](0x0).
3197 
3198  // If NR > 0, the result will be a column vector with the given
3199  // number of rows.
3200 
3201  // If NR < 0, then we have Inf and the result will be a column
3202  // vector but we have to wait to see how big NR will be.
3203 
3204  if (nr == 0)
3205  nr = nc = 0;
3206  else
3207  nc = 1;
3208  }
3209  else
3210  {
3211  // Matlab returns [] even if there are two elements in the size
3212  // specification and one is nonzero.
3213 
3214  // If NC < 0 we have [NR, Inf] and we'll wait to decide how big NC
3215  // should be.
3216 
3217  if (nr == 0 || nc == 0)
3218  nr = nc = 0;
3219  }
3220 
3221  // FIXME: ensure that this does not overflow.
3222 
3223  elts_to_read = nr * nc;
3224 
3225  bool read_to_eof = elts_to_read < 0;
3226 
3227  octave_idx_type input_buf_elts = -1;
3228 
3229  if (skip == 0)
3230  {
3231  if (read_to_eof)
3232  input_buf_elts = 1024 * 1024;
3233  else
3234  input_buf_elts = elts_to_read;
3235  }
3236  else
3237  input_buf_elts = block_size;
3238 
3239  octave_idx_type input_elt_size
3240  = oct_data_conv::data_type_size (input_type);
3241 
3242  octave_idx_type input_buf_size = input_buf_elts * input_elt_size;
3243 
3244  assert (input_buf_size >= 0);
3245 
3246  // Must also work and return correct type object
3247  // for 0 elements to read.
3248 
3249  std::istream *isp = input_stream ();
3250 
3251  if (isp)
3252  {
3253  std::istream& is = *isp;
3254 
3255  std::list <void *> input_buf_list;
3256 
3257  octave_idx_type elts_read = 0;
3258 
3259  while (is && ! is.eof ()
3260  && (read_to_eof || elts_read < elts_to_read))
3261  {
3262  char *input_buf = new char [input_buf_size];
3263 
3264  is.read (input_buf, input_buf_size);
3265 
3266  size_t count = is.gcount ();
3267 
3268  char_count += count;
3269 
3270  elts_read += count / input_elt_size;
3271 
3272  input_buf_list.push_back (input_buf);
3273 
3274  if (is && skip != 0 && elts_read == block_size)
3275  {
3276  int seek_status = seek (skip, SEEK_CUR);
3277 
3278  if (seek_status < 0)
3279  break;
3280  }
3281  }
3282 
3283  if (read_to_eof)
3284  {
3285  if (nc < 0)
3286  nc = elts_read / nr + 1;
3287  else
3288  nr = elts_read;
3289  }
3290 
3291  retval = finalize_read (input_buf_list, input_buf_elts, elts_read,
3292  nr, nc, input_type, output_type, ffmt);
3293  }
3294  else
3295  error ("fread: invalid input stream");
3296  }
3297  else
3298  invalid_operation ("fread", "reading");
3299  }
3300 
3301  return retval;
3302 }
3303 
3306  oct_data_conv::data_type output_type,
3308 {
3309  octave_idx_type retval = -1;
3310 
3311  if (stream_ok ())
3312  {
3313  if (! error_state)
3314  {
3315  if (flt_fmt == oct_mach_info::flt_fmt_unknown)
3316  flt_fmt = float_format ();
3317 
3318  octave_idx_type status = data.write (*this, block_size, output_type,
3319  skip, flt_fmt);
3320 
3321  if (status < 0)
3322  error ("fwrite: write error");
3323  else
3324  retval = status;
3325  }
3326  else
3327  invalid_operation ("fwrite", "writing");
3328  }
3329 
3330  return retval;
3331 }
3332 
3333 template <class T, class V>
3334 static void
3335 convert_ints (const T *data, void *conv_data, octave_idx_type n_elts,
3336  bool swap)
3337 {
3338  typedef typename V::val_type val_type;
3339 
3340  val_type *vt_data = static_cast <val_type *> (conv_data);
3341 
3342  for (octave_idx_type i = 0; i < n_elts; i++)
3343  {
3344  V val (data[i]);
3345 
3346  vt_data[i] = val.value ();
3347 
3348  if (swap)
3349  swap_bytes<sizeof (val_type)> (&vt_data[i]);
3350  }
3351 }
3352 
3353 template <class T>
3354 static bool
3355 convert_data (const T *data, void *conv_data, octave_idx_type n_elts,
3356  oct_data_conv::data_type output_type,
3358 {
3359  bool retval = true;
3360 
3361  bool swap
3365 
3366  bool do_float_conversion = flt_fmt != oct_mach_info::float_format ();
3367 
3368  // We use octave_intN classes here instead of converting directly to
3369  // intN_t so that we get integer saturation semantics.
3370 
3371  switch (output_type)
3372  {
3376  convert_ints<T, octave_int8> (data, conv_data, n_elts, swap);
3377  break;
3378 
3381  convert_ints<T, octave_uint8> (data, conv_data, n_elts, swap);
3382  break;
3383 
3385  convert_ints<T, octave_int16> (data, conv_data, n_elts, swap);
3386  break;
3387 
3389  convert_ints<T, octave_uint16> (data, conv_data, n_elts, swap);
3390  break;
3391 
3393  convert_ints<T, octave_int32> (data, conv_data, n_elts, swap);
3394  break;
3395 
3397  convert_ints<T, octave_uint32> (data, conv_data, n_elts, swap);
3398  break;
3399 
3401  convert_ints<T, octave_int64> (data, conv_data, n_elts, swap);
3402  break;
3403 
3405  convert_ints<T, octave_uint64> (data, conv_data, n_elts, swap);
3406  break;
3407 
3409  {
3410  float *vt_data = static_cast <float *> (conv_data);
3411 
3412  for (octave_idx_type i = 0; i < n_elts; i++)
3413  {
3414  vt_data[i] = data[i];
3415 
3416  if (do_float_conversion)
3417  do_float_format_conversion (&vt_data[i], 1, flt_fmt);
3418  }
3419  }
3420  break;
3421 
3423  {
3424  double *vt_data = static_cast <double *> (conv_data);
3425 
3426  for (octave_idx_type i = 0; i < n_elts; i++)
3427  {
3428  vt_data[i] = data[i];
3429 
3430  if (do_float_conversion)
3431  do_double_format_conversion (&vt_data[i], 1, flt_fmt);
3432  }
3433  }
3434  break;
3435 
3436  default:
3437  retval = false;
3438  (*current_liboctave_error_handler)
3439  ("write: invalid type specification");
3440  break;
3441  }
3442 
3443  return retval;
3444 }
3445 
3446 bool
3447 octave_stream::write_bytes (const void *data, size_t nbytes)
3448 {
3449  bool status = false;
3450 
3451  std::ostream *osp = output_stream ();
3452 
3453  if (osp)
3454  {
3455  std::ostream& os = *osp;
3456 
3457  if (os)
3458  {
3459  os.write (static_cast<const char *> (data), nbytes);
3460 
3461  if (os)
3462  status = true;
3463  }
3464  }
3465 
3466  return status;
3467 }
3468 
3469 bool
3471 {
3472  bool status = false;
3473 
3474  std::ostream *osp = output_stream ();
3475 
3476  if (osp)
3477  {
3478  std::ostream& os = *osp;
3479 
3480  // Seek to skip when inside bounds of existing file.
3481  // Otherwise, write NUL to skip.
3482 
3483  off_t orig_pos = tell ();
3484 
3485  seek (0, SEEK_END);
3486 
3487  off_t eof_pos = tell ();
3488 
3489  // Is it possible for this to fail to return us to the
3490  // original position?
3491  seek (orig_pos, SEEK_SET);
3492 
3493  size_t remaining = eof_pos - orig_pos;
3494 
3495  if (remaining < skip)
3496  {
3497  seek (0, SEEK_END);
3498 
3499  // FIXME: probably should try to write larger blocks...
3500 
3501  unsigned char zero = 0;
3502  for (size_t j = 0; j < skip - remaining; j++)
3503  os.write (reinterpret_cast<const char *> (&zero), 1);
3504  }
3505  else
3506  seek (skip, SEEK_CUR);
3507 
3508  if (os)
3509  status = true;
3510  }
3511 
3512  return status;
3513 }
3514 
3515 template <class T>
3518  oct_data_conv::data_type output_type,
3519  octave_idx_type skip,
3521 {
3522  bool swap = ((oct_mach_info::words_big_endian ()
3525 
3526  bool do_data_conversion = (swap || ! is_equivalent_type<T> (output_type)
3527  || flt_fmt != oct_mach_info::float_format ());
3528 
3529  octave_idx_type nel = data.numel ();
3530 
3531  octave_idx_type chunk_size;
3532 
3533  if (skip != 0)
3534  chunk_size = block_size;
3535  else if (do_data_conversion)
3536  chunk_size = 1024 * 1024;
3537  else
3538  chunk_size = nel;
3539 
3540  octave_idx_type i = 0;
3541 
3542  const T *pdata = data.data ();
3543 
3544  while (i < nel)
3545  {
3546  if (skip != 0)
3547  {
3548  if (! skip_bytes (skip))
3549  return -1;
3550  }
3551 
3552  octave_idx_type remaining_nel = nel - i;
3553 
3554  if (chunk_size > remaining_nel)
3555  chunk_size = remaining_nel;
3556 
3557  bool status = false;
3558 
3559  if (do_data_conversion)
3560  {
3561  size_t output_size
3562  = chunk_size * oct_data_conv::data_type_size (output_type);
3563 
3564  OCTAVE_LOCAL_BUFFER (unsigned char, conv_data, output_size);
3565 
3566  status = convert_data (&pdata[i], conv_data, chunk_size,
3567  output_type, flt_fmt);
3568 
3569  if (status)
3570  status = write_bytes (conv_data, output_size);
3571  }
3572  else
3573  status = write_bytes (pdata, sizeof (T) * chunk_size);
3574 
3575  if (! status)
3576  return -1;
3577 
3578  i += chunk_size;
3579  }
3580 
3581  return nel;
3582 }
3583 
3584 #define INSTANTIATE_WRITE(T) \
3585  template \
3586  octave_idx_type \
3587  octave_stream::write (const Array<T>& data, octave_idx_type block_size, \
3588  oct_data_conv::data_type output_type, \
3589  octave_idx_type skip, \
3590  oct_mach_info::float_format flt_fmt)
3591 
3600 INSTANTIATE_WRITE (int8_t);
3601 INSTANTIATE_WRITE (uint8_t);
3602 INSTANTIATE_WRITE (int16_t);
3603 INSTANTIATE_WRITE (uint16_t);
3604 INSTANTIATE_WRITE (int32_t);
3605 INSTANTIATE_WRITE (uint32_t);
3606 INSTANTIATE_WRITE (int64_t);
3607 INSTANTIATE_WRITE (uint64_t);
3608 INSTANTIATE_WRITE (bool);
3609 INSTANTIATE_WRITE (char);
3610 INSTANTIATE_WRITE (float);
3611 INSTANTIATE_WRITE (double);
3612 
3614 octave_stream::scanf (const std::string& fmt, const Array<double>& size,
3615  octave_idx_type& count, const std::string& who)
3616 {
3617  octave_value retval;
3618 
3619  if (stream_ok ())
3620  retval = rep->scanf (fmt, size, count, who);
3621 
3622  return retval;
3623 }
3624 
3627  octave_idx_type& count, const std::string& who)
3628 {
3629  octave_value retval = Matrix ();
3630 
3631  if (fmt.is_string ())
3632  {
3633  std::string sfmt = fmt.string_value ();
3634 
3635  if (fmt.is_sq_string ())
3636  sfmt = do_string_escapes (sfmt);
3637 
3638  retval = scanf (sfmt, size, count, who);
3639  }
3640  else
3641  {
3642  // Note that this is not ::error () !
3643 
3644  error (who + ": format must be a string");
3645  }
3646 
3647  return retval;
3648 }
3649 
3651 octave_stream::oscanf (const std::string& fmt, const std::string& who)
3652 {
3653  octave_value_list retval;
3654 
3655  if (stream_ok ())
3656  retval = rep->oscanf (fmt, who);
3657 
3658  return retval;
3659 }
3660 
3662 octave_stream::oscanf (const octave_value& fmt, const std::string& who)
3663 {
3664  octave_value_list retval;
3665 
3666  if (fmt.is_string ())
3667  {
3668  std::string sfmt = fmt.string_value ();
3669 
3670  if (fmt.is_sq_string ())
3671  sfmt = do_string_escapes (sfmt);
3672 
3673  retval = oscanf (sfmt, who);
3674  }
3675  else
3676  {
3677  // Note that this is not ::error () !
3678 
3679  error (who + ": format must be a string");
3680  }
3681 
3682  return retval;
3683 }
3684 
3685 int
3686 octave_stream::printf (const std::string& fmt, const octave_value_list& args,
3687  const std::string& who)
3688 {
3689  int retval = -1;
3690 
3691  if (stream_ok ())
3692  retval = rep->printf (fmt, args, who);
3693 
3694  return retval;
3695 }
3696 
3697 int
3699  const std::string& who)
3700 {
3701  int retval = 0;
3702 
3703  if (fmt.is_string ())
3704  {
3705  std::string sfmt = fmt.string_value ();
3706 
3707  if (fmt.is_sq_string ())
3708  sfmt = do_string_escapes (sfmt);
3709 
3710  retval = printf (sfmt, args, who);
3711  }
3712  else
3713  {
3714  // Note that this is not ::error () !
3715 
3716  error (who + ": format must be a string");
3717  }
3718 
3719  return retval;
3720 }
3721 
3722 int
3723 octave_stream::puts (const std::string& s, const std::string& who)
3724 {
3725  int retval = -1;
3726 
3727  if (stream_ok ())
3728  retval = rep->puts (s, who);
3729 
3730  return retval;
3731 }
3732 
3733 // FIXME: maybe this should work for string arrays too.
3734 
3735 int
3736 octave_stream::puts (const octave_value& tc_s, const std::string& who)
3737 {
3738  int retval = -1;
3739 
3740  if (tc_s.is_string ())
3741  {
3742  std::string s = tc_s.string_value ();
3743  retval = puts (s, who);
3744  }
3745  else
3746  {
3747  // Note that this is not ::error () !
3748 
3749  error (who + ": argument must be a string");
3750  }
3751 
3752  return retval;
3753 }
3754 
3755 bool
3757 {
3758  int retval = -1;
3759 
3760  if (stream_ok ())
3761  retval = rep->eof ();
3762 
3763  return retval;
3764 }
3765 
3766 std::string
3767 octave_stream::error (bool clear, int& err_num)
3768 {
3769  std::string retval = "invalid stream object";
3770 
3771  if (stream_ok (false))
3772  retval = rep->error (clear, err_num);
3773 
3774  return retval;
3775 }
3776 
3777 std::string
3779 {
3780  std::string retval;
3781 
3782  if (stream_ok ())
3783  retval = rep->name ();
3784 
3785  return retval;
3786 }
3787 
3788 int
3790 {
3791  int retval = 0;
3792 
3793  if (stream_ok ())
3794  retval = rep->mode ();
3795 
3796  return retval;
3797 }
3798 
3801 {
3803 
3804  if (stream_ok ())
3805  retval = rep->float_format ();
3806 
3807  return retval;
3808 }
3809 
3810 std::string
3812 {
3813  std::string retval = "???";
3814  std::ios::openmode in_mode = static_cast<std::ios::openmode> (mode);
3815 
3816  if (in_mode == std::ios::in)
3817  retval = "r";
3818  else if (in_mode == std::ios::out
3819  || in_mode == (std::ios::out | std::ios::trunc))
3820  retval = "w";
3821  else if (in_mode == (std::ios::out | std::ios::app))
3822  retval = "a";
3823  else if (in_mode == (std::ios::in | std::ios::out))
3824  retval = "r+";
3825  else if (in_mode == (std::ios::in | std::ios::out | std::ios::trunc))
3826  retval = "w+";
3827  else if (in_mode == (std::ios::in | std::ios::out | std::ios::ate))
3828  retval = "a+";
3829  else if (in_mode == (std::ios::in | std::ios::binary))
3830  retval = "rb";
3831  else if (in_mode == (std::ios::out | std::ios::binary)
3832  || in_mode == (std::ios::out | std::ios::trunc | std::ios::binary))
3833  retval = "wb";
3834  else if (in_mode == (std::ios::out | std::ios::app | std::ios::binary))
3835  retval = "ab";
3836  else if (in_mode == (std::ios::in | std::ios::out | std::ios::binary))
3837  retval = "r+b";
3838  else if (in_mode == (std::ios::in | std::ios::out | std::ios::trunc
3839  | std::ios::binary))
3840  retval = "w+b";
3841  else if (in_mode == (std::ios::in | std::ios::out | std::ios::ate
3842  | std::ios::binary))
3843  retval = "a+b";
3844 
3845  return retval;
3846 }
3847 
3849 
3850 bool
3852 {
3853  bool retval = true;
3854 
3855  if (! instance)
3856  {
3857  instance = new octave_stream_list ();
3858 
3859  if (instance)
3861  }
3862 
3863  if (! instance)
3864  {
3865  ::error ("unable to create stream list object!");
3866 
3867  retval = false;
3868  }
3869 
3870  return retval;
3871 }
3872 
3873 int
3875 {
3876  return (instance_ok ()) ? instance->do_insert (os) : -1;
3877 }
3878 
3880 octave_stream_list::lookup (int fid, const std::string& who)
3881 {
3882  return (instance_ok ()) ? instance->do_lookup (fid, who) : octave_stream ();
3883 }
3884 
3886 octave_stream_list::lookup (const octave_value& fid, const std::string& who)
3887 {
3888  return (instance_ok ()) ? instance->do_lookup (fid, who) : octave_stream ();
3889 }
3890 
3891 int
3892 octave_stream_list::remove (int fid, const std::string& who)
3893 {
3894  return (instance_ok ()) ? instance->do_remove (fid, who) : -1;
3895 }
3896 
3897 int
3898 octave_stream_list::remove (const octave_value& fid, const std::string& who)
3899 {
3900  return (instance_ok ()) ? instance->do_remove (fid, who) : -1;
3901 }
3902 
3903 void
3905 {
3906  if (instance)
3907  instance->do_clear (flush);
3908 }
3909 
3912 {
3913  return (instance_ok ()) ? instance->do_get_info (fid) : string_vector ();
3914 }
3915 
3918 {
3919  return (instance_ok ()) ? instance->do_get_info (fid) : string_vector ();
3920 }
3921 
3922 std::string
3924 {
3925  return (instance_ok ()) ? instance->do_list_open_files () : std::string ();
3926 }
3927 
3930 {
3931  return (instance_ok ())
3933 }
3934 
3935 int
3937 {
3938  return (instance_ok ()) ? instance->do_get_file_number (fid) : -1;
3939 }
3940 
3941 int
3943 {
3944  // Insert item with key corresponding to file-descriptor.
3945 
3946  int stream_number;
3947 
3948  if ((stream_number = os.file_number ()) == -1)
3949  return stream_number;
3950 
3951  // Should we test for "(list.find (stream_number) != list.end ()) &&
3952  // list[stream_number].is_open ()" and respond with "error
3953  // ("internal error: ...")"? It should not happen except for some
3954  // bug or if the user has opened a stream with an interpreted
3955  // command, but closed it directly with a system call in an
3956  // oct-file; then the kernel knows the fd is free, but Octave does
3957  // not know. If it happens, it should not do harm here to simply
3958  // overwrite this entry, although the wrong entry might have done
3959  // harm before.
3960 
3961  if (list.size () < list.max_size ())
3962  list[stream_number] = os;
3963  else
3964  {
3965  stream_number = -1;
3966  error ("could not create file id");
3967  }
3968 
3969  return stream_number;
3970 
3971 }
3972 
3973 static void
3974 gripe_invalid_file_id (int fid, const std::string& who)
3975 {
3976  if (who.empty ())
3977  ::error ("invalid stream number = %d", fid);
3978  else
3979  ::error ("%s: invalid stream number = %d", who.c_str (), fid);
3980 }
3981 
3983 octave_stream_list::do_lookup (int fid, const std::string& who) const
3984 {
3985  octave_stream retval;
3986 
3987  if (fid >= 0)
3988  {
3989  if (lookup_cache != list.end () && lookup_cache->first == fid)
3990  retval = lookup_cache->second;
3991  else
3992  {
3993  ostrl_map::const_iterator iter = list.find (fid);
3994 
3995  if (iter != list.end ())
3996  {
3997  retval = iter->second;
3998  lookup_cache = iter;
3999  }
4000  else
4001  gripe_invalid_file_id (fid, who);
4002  }
4003  }
4004  else
4005  gripe_invalid_file_id (fid, who);
4006 
4007  return retval;
4008 }
4009 
4012  const std::string& who) const
4013 {
4014  octave_stream retval;
4015 
4016  int i = get_file_number (fid);
4017 
4018  if (! error_state)
4019  retval = do_lookup (i, who);
4020 
4021  return retval;
4022 }
4023 
4024 int
4025 octave_stream_list::do_remove (int fid, const std::string& who)
4026 {
4027  int retval = -1;
4028 
4029  // Can't remove stdin (std::cin), stdout (std::cout), or stderr
4030  // (std::cerr).
4031 
4032  if (fid > 2)
4033  {
4034  ostrl_map::iterator iter = list.find (fid);
4035 
4036  if (iter != list.end ())
4037  {
4038  octave_stream os = iter->second;
4039  list.erase (iter);
4040  lookup_cache = list.end ();
4041 
4042  // FIXME: is this check redundant?
4043  if (os.is_valid ())
4044  {
4045  os.close ();
4046  retval = 0;
4047  }
4048  else
4049  gripe_invalid_file_id (fid, who);
4050  }
4051  else
4052  gripe_invalid_file_id (fid, who);
4053  }
4054  else
4055  gripe_invalid_file_id (fid, who);
4056 
4057  return retval;
4058 }
4059 
4060 int
4061 octave_stream_list::do_remove (const octave_value& fid, const std::string& who)
4062 {
4063  int retval = -1;
4064 
4065  if (fid.is_string () && fid.string_value () == "all")
4066  {
4067  do_clear (false);
4068 
4069  retval = 0;
4070  }
4071  else
4072  {
4073  int i = get_file_number (fid);
4074 
4075  if (! error_state)
4076  retval = do_remove (i, who);
4077  }
4078 
4079  return retval;
4080 }
4081 
4082 void
4084 {
4085  if (flush)
4086  {
4087  // Do flush stdout and stderr.
4088 
4089  list[0].flush ();
4090  list[1].flush ();
4091  }
4092 
4093  octave_stream saved_os[3];
4094  // But don't delete them or stdin.
4095  for (ostrl_map::iterator iter = list.begin (); iter != list.end (); iter++)
4096  {
4097  int fid = iter->first;
4098  octave_stream os = iter->second;
4099  if (fid < 3)
4100  saved_os[fid] = os;
4101  else if (os.is_valid ())
4102  os.close ();
4103  }
4104  list.clear ();
4105  for (int fid = 0; fid < 3; fid++) list[fid] = saved_os[fid];
4106  lookup_cache = list.end ();
4107 }
4108 
4111 {
4112  string_vector retval;
4113 
4114  octave_stream os = do_lookup (fid);
4115 
4116  if (os.is_valid ())
4117  {
4118  retval.resize (3);
4119 
4121  retval(1) = octave_stream::mode_as_string (os.mode ());
4122  retval(0) = os.name ();
4123  }
4124  else
4125  ::error ("invalid file id = %d", fid);
4126 
4127  return retval;
4128 }
4129 
4132 {
4133  string_vector retval;
4134 
4135  int conv_err = 0;
4136 
4137  int int_fid = convert_to_valid_int (fid, conv_err);
4138 
4139  if (! conv_err)
4140  retval = do_get_info (int_fid);
4141  else
4142  ::error ("file id must be a file object or integer value");
4143 
4144  return retval;
4145 }
4146 
4147 std::string
4149 {
4150  std::string retval;
4151 
4152  std::ostringstream buf;
4153 
4154  buf << "\n"
4155  << " number mode arch name\n"
4156  << " ------ ---- ---- ----\n";
4157 
4158  for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++)
4159  {
4160  octave_stream os = p->second;
4161 
4162  buf << " "
4163  << std::setiosflags (std::ios::right)
4164  << std::setw (4) << p->first << " "
4165  << std::setiosflags (std::ios::left)
4166  << std::setw (3)
4168  << " "
4169  << std::setw (9)
4171  << " "
4172  << os.name () << "\n";
4173  }
4174 
4175  buf << "\n";
4176 
4177  retval = buf.str ();
4178 
4179  return retval;
4180 }
4181 
4184 {
4185  Matrix retval (1, list.size (), 0.0);
4186 
4187  int num_open = 0;
4188 
4189  for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++)
4190  {
4191  // Skip stdin, stdout, and stderr.
4192 
4193  if (p->first > 2 && p->second)
4194  retval(0,num_open++) = p->first;
4195  }
4196 
4197  retval.resize ((num_open > 0), num_open);
4198 
4199  return retval;
4200 }
4201 
4202 int
4204 {
4205  int retval = -1;
4206 
4207  if (fid.is_string ())
4208  {
4209  std::string nm = fid.string_value ();
4210 
4211  for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++)
4212  {
4213  // stdin (std::cin), stdout (std::cout), and stderr (std::cerr)
4214  // are unnamed.
4215 
4216  if (p->first > 2)
4217  {
4218  octave_stream os = p->second;
4219 
4220  if (os && os.name () == nm)
4221  {
4222  retval = p->first;
4223  break;
4224  }
4225  }
4226  }
4227  }
4228  else
4229  {
4230  int conv_err = 0;
4231 
4232  int int_fid = convert_to_valid_int (fid, conv_err);
4233 
4234  if (conv_err)
4235  ::error ("file id must be a file object, std::string, or integer value");
4236  else
4237  retval = int_fid;
4238  }
4239 
4240  return retval;
4241 }