oct-stream.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <cassert>
00028 #include <cctype>
00029 #include <cstring>
00030 
00031 #include <iomanip>
00032 #include <iostream>
00033 #include <fstream>
00034 #include <sstream>
00035 #include <string>
00036 
00037 #include <Array.h>
00038 
00039 #include "byte-swap.h"
00040 #include "lo-ieee.h"
00041 #include "lo-mappers.h"
00042 #include "lo-utils.h"
00043 #include "quit.h"
00044 #include "singleton-cleanup.h"
00045 #include "str-vec.h"
00046 
00047 #include "error.h"
00048 #include "gripes.h"
00049 #include "input.h"
00050 #include "oct-stdstrm.h"
00051 #include "oct-stream.h"
00052 #include "oct-obj.h"
00053 #include "utils.h"
00054 
00055 // Possible values for conv_err:
00056 //
00057 //   1 : not a real scalar
00058 //   2 : value is NaN
00059 //   3 : value is not an integer
00060 
00061 static int
00062 convert_to_valid_int (const octave_value& tc, int& conv_err)
00063 {
00064   int retval = 0;
00065 
00066   conv_err = 0;
00067 
00068   double dval = tc.double_value ();
00069 
00070   if (! error_state)
00071     {
00072       if (! lo_ieee_isnan (dval))
00073         {
00074           int ival = NINT (dval);
00075 
00076           if (ival == dval)
00077             retval = ival;
00078           else
00079             conv_err = 3;
00080         }
00081       else
00082         conv_err = 2;
00083     }
00084   else
00085     conv_err = 1;
00086 
00087   return retval;
00088 }
00089 
00090 static int
00091 get_size (double d, const std::string& who)
00092 {
00093   int retval = -1;
00094 
00095   if (! lo_ieee_isnan (d))
00096     {
00097       if (! xisinf (d))
00098         {
00099           if (d >= 0.0)
00100             retval = NINT (d);
00101           else
00102             ::error ("%s: negative value invalid as size specification",
00103                      who.c_str ());
00104         }
00105       else
00106         retval = -1;
00107     }
00108   else
00109     ::error ("%s: NaN is invalid as size specification", who.c_str ());
00110 
00111   return retval;
00112 }
00113 
00114 static void
00115 get_size (const Array<double>& size, octave_idx_type& nr, octave_idx_type& nc, bool& one_elt_size_spec,
00116           const std::string& who)
00117 {
00118   nr = -1;
00119   nc = -1;
00120 
00121   one_elt_size_spec = false;
00122 
00123   double dnr = -1.0;
00124   double dnc = -1.0;
00125 
00126   octave_idx_type sz_len = size.length ();
00127 
00128   if (sz_len == 1)
00129     {
00130       one_elt_size_spec = true;
00131 
00132       dnr = size (0);
00133 
00134       dnc = (dnr == 0.0) ? 0.0 : 1.0;
00135     }
00136   else if (sz_len == 2)
00137     {
00138       dnr = size (0);
00139 
00140       if (! xisinf (dnr))
00141         dnc = size (1);
00142       else
00143         ::error ("%s: invalid size specification", who.c_str ());
00144     }
00145   else
00146     ::error ("%s: invalid size specification", who.c_str ());
00147 
00148   if (! error_state)
00149     {
00150       nr = get_size (dnr, who);
00151 
00152       if (! error_state && dnc >= 0.0)
00153         nc = get_size (dnc, who);
00154     }
00155 }
00156 
00157 scanf_format_list::scanf_format_list (const std::string& s)
00158   : nconv (0), curr_idx (0), list (dim_vector (16, 1)), buf (0)
00159 {
00160   octave_idx_type num_elts = 0;
00161 
00162   size_t n = s.length ();
00163 
00164   size_t i = 0;
00165 
00166   int width = 0;
00167   bool discard = false;
00168   char modifier = '\0';
00169   char type = '\0';
00170 
00171   bool have_more = true;
00172 
00173   while (i < n)
00174     {
00175       have_more = true;
00176 
00177       if (! buf)
00178         buf = new std::ostringstream ();
00179 
00180       if (s[i] == '%')
00181         {
00182           // Process percent-escape conversion type.
00183 
00184           process_conversion (s, i, n, width, discard, type, modifier,
00185                               num_elts);
00186 
00187           have_more = (buf != 0);
00188         }
00189       else if (isspace (s[i]))
00190         {
00191           type = scanf_format_elt::whitespace_conversion;
00192 
00193           width = 0;
00194           discard = false;
00195           modifier = '\0';
00196           *buf << " ";
00197 
00198           while (++i < n && isspace (s[i]))
00199             /* skip whitespace */;
00200 
00201           add_elt_to_list (width, discard, type, modifier, num_elts);
00202 
00203           have_more = false;
00204         }
00205       else
00206         {
00207           type = scanf_format_elt::literal_conversion;
00208 
00209           width = 0;
00210           discard = false;
00211           modifier = '\0';
00212 
00213           while (i < n && ! isspace (s[i]) && s[i] != '%')
00214             *buf << s[i++];
00215 
00216           add_elt_to_list (width, discard, type, modifier, num_elts);
00217 
00218           have_more = false;
00219         }
00220 
00221       if (nconv < 0)
00222         {
00223           have_more = false;
00224           break;
00225         }
00226     }
00227 
00228   if (have_more)
00229     add_elt_to_list (width, discard, type, modifier, num_elts);
00230 
00231   list.resize (dim_vector (num_elts, 1));
00232 
00233   delete buf;
00234 }
00235 
00236 scanf_format_list::~scanf_format_list (void)
00237 {
00238   octave_idx_type n = list.length ();
00239 
00240   for (octave_idx_type i = 0; i < n; i++)
00241     {
00242       scanf_format_elt *elt = list(i);
00243       delete elt;
00244     }
00245 }
00246 
00247 void
00248 scanf_format_list::add_elt_to_list (int width, bool discard, char type,
00249                                     char modifier, octave_idx_type& num_elts,
00250                                     const std::string& char_class)
00251 {
00252   if (buf)
00253     {
00254       std::string text = buf->str ();
00255 
00256       if (! text.empty ())
00257         {
00258           scanf_format_elt *elt
00259             = new scanf_format_elt (text.c_str (), width, discard, type,
00260                                     modifier, char_class);
00261 
00262           if (num_elts == list.length ())
00263             list.resize (dim_vector (2 * num_elts, 1));
00264 
00265           list(num_elts++) = elt;
00266         }
00267 
00268       delete buf;
00269       buf = 0;
00270     }
00271 }
00272 
00273 static std::string
00274 expand_char_class (const std::string& s)
00275 {
00276   std::string retval;
00277 
00278   size_t len = s.length ();
00279 
00280   size_t i = 0;
00281 
00282   while (i < len)
00283     {
00284       unsigned char c = s[i++];
00285 
00286       if (c == '-' && i > 1 && i < len
00287           && static_cast<unsigned char> (s[i-2]) <= static_cast<unsigned char> (s[i]))
00288         {
00289           // Add all characters from the range except the first (we
00290           // already added it below).
00291 
00292           for (c = s[i-2]+1; c < s[i]; c++)
00293             retval += c;
00294         }
00295       else
00296         {
00297           // Add the character to the class.  Only add '-' if it is
00298           // the last character in the class.
00299 
00300           if (c != '-' || i == len)
00301             retval += c;
00302         }
00303     }
00304 
00305   return retval;
00306 }
00307 
00308 void
00309 scanf_format_list::process_conversion (const std::string& s, size_t& i,
00310                                        size_t n, int& width, bool& discard,
00311                                        char& type, char& modifier,
00312                                        octave_idx_type& num_elts)
00313 {
00314   width = 0;
00315   discard = false;
00316   modifier = '\0';
00317   type = '\0';
00318 
00319   *buf << s[i++];
00320 
00321   bool have_width = false;
00322 
00323   while (i < n)
00324     {
00325       switch (s[i])
00326         {
00327         case '*':
00328           if (discard)
00329             nconv = -1;
00330           else
00331             {
00332               discard = true;
00333               *buf << s[i++];
00334             }
00335           break;
00336 
00337         case '0': case '1': case '2': case '3': case '4':
00338         case '5': case '6': case '7': case '8': case '9':
00339           if (have_width)
00340             nconv = -1;
00341           else
00342             {
00343               char c = s[i++];
00344               width = width * 10 + c - '0';
00345               have_width = true;
00346               *buf << c;
00347               while (i < n && isdigit (s[i]))
00348                 {
00349                   c = s[i++];
00350                   width = width * 10 + c - '0';
00351                   *buf << c;
00352                 }
00353             }
00354           break;
00355 
00356         case 'h': case 'l': case 'L':
00357           if (modifier != '\0')
00358             nconv = -1;
00359           else
00360             modifier = s[i++];
00361           break;
00362 
00363         case 'd': case 'i': case 'o': case 'u': case 'x':
00364           if (modifier == 'L')
00365             {
00366               nconv = -1;
00367               break;
00368             }
00369           goto fini;
00370 
00371         case 'e': case 'f': case 'g':
00372           if (modifier == 'h')
00373             {
00374               nconv = -1;
00375               break;
00376             }
00377 
00378           // No float or long double conversions, thanks.
00379           *buf << 'l';
00380 
00381           goto fini;
00382 
00383         case 'c': case 's': case 'p': case '%': case '[':
00384           if (modifier != '\0')
00385             {
00386               nconv = -1;
00387               break;
00388             }
00389           goto fini;
00390 
00391         fini:
00392           {
00393             if (finish_conversion (s, i, n, width, discard, type,
00394                                    modifier, num_elts) == 0)
00395               return;
00396           }
00397           break;
00398 
00399         default:
00400           nconv = -1;
00401           break;
00402         }
00403 
00404       if (nconv < 0)
00405         break;
00406     }
00407 
00408   nconv = -1;
00409 }
00410 
00411 int
00412 scanf_format_list::finish_conversion (const std::string& s, size_t& i,
00413                                       size_t n, int& width, bool discard,
00414                                       char& type, char modifier,
00415                                       octave_idx_type& num_elts)
00416 {
00417   int retval = 0;
00418 
00419   std::string char_class;
00420 
00421   size_t beg_idx = std::string::npos;
00422   size_t end_idx = std::string::npos;
00423 
00424   if (s[i] == '%')
00425     {
00426       type = '%';
00427       *buf << s[i++];
00428     }
00429   else
00430     {
00431       type = s[i];
00432 
00433       if (s[i] == '[')
00434         {
00435           *buf << s[i++];
00436 
00437           if (i < n)
00438             {
00439               beg_idx = i;
00440 
00441               if (s[i] == '^')
00442                 {
00443                   type = '^';
00444                   *buf << s[i++];
00445 
00446                   if (i < n)
00447                     {
00448                       beg_idx = i;
00449 
00450                       if (s[i] == ']')
00451                         *buf << s[i++];
00452                     }
00453                 }
00454               else if (s[i] == ']')
00455                 *buf << s[i++];
00456             }
00457 
00458           while (i < n && s[i] != ']')
00459             *buf << s[i++];
00460 
00461           if (i < n && s[i] == ']')
00462             {
00463               end_idx = i-1;
00464               *buf << s[i++];
00465             }
00466 
00467           if (s[i-1] != ']')
00468             retval = nconv = -1;
00469         }
00470       else
00471         *buf << s[i++];
00472 
00473       nconv++;
00474     }
00475 
00476   if (nconv >= 0)
00477     {
00478       if (beg_idx != std::string::npos && end_idx != std::string::npos)
00479         char_class = expand_char_class (s.substr (beg_idx,
00480                                                   end_idx - beg_idx + 1));
00481 
00482       add_elt_to_list (width, discard, type, modifier, num_elts, char_class);
00483     }
00484 
00485   return retval;
00486 }
00487 
00488 void
00489 scanf_format_list::printme (void) const
00490 {
00491   octave_idx_type n = list.length ();
00492 
00493   for (octave_idx_type i = 0; i < n; i++)
00494     {
00495       scanf_format_elt *elt = list(i);
00496 
00497       std::cerr
00498         << "width:      " << elt->width << "\n"
00499         << "discard:    " << elt->discard << "\n"
00500         << "type:       ";
00501 
00502       if (elt->type == scanf_format_elt::literal_conversion)
00503         std::cerr << "literal text\n";
00504       else if (elt->type == scanf_format_elt::whitespace_conversion)
00505         std::cerr << "whitespace\n";
00506       else
00507         std::cerr << elt->type << "\n";
00508 
00509       std::cerr
00510         << "modifier:   " << elt->modifier << "\n"
00511         << "char_class: '" << undo_string_escapes (elt->char_class) << "'\n"
00512         << "text:       '" << undo_string_escapes (elt->text) << "'\n\n";
00513     }
00514 }
00515 
00516 bool
00517 scanf_format_list::all_character_conversions (void)
00518 {
00519   octave_idx_type n = list.length ();
00520 
00521   if (n > 0)
00522     {
00523       for (octave_idx_type i = 0; i < n; i++)
00524         {
00525           scanf_format_elt *elt = list(i);
00526 
00527           switch (elt->type)
00528             {
00529             case 'c': case 's': case '%': case '[': case '^':
00530             case scanf_format_elt::literal_conversion:
00531             case scanf_format_elt::whitespace_conversion:
00532               break;
00533 
00534             default:
00535               return false;
00536               break;
00537             }
00538         }
00539 
00540       return true;
00541     }
00542   else
00543     return false;
00544 }
00545 
00546 bool
00547 scanf_format_list::all_numeric_conversions (void)
00548 {
00549   octave_idx_type n = list.length ();
00550 
00551   if (n > 0)
00552     {
00553       for (octave_idx_type i = 0; i < n; i++)
00554         {
00555           scanf_format_elt *elt = list(i);
00556 
00557           switch (elt->type)
00558             {
00559             case 'd': case 'i': case 'o': case 'u': case 'x':
00560             case 'e': case 'f': case 'g':
00561               break;
00562 
00563             default:
00564               return false;
00565               break;
00566             }
00567         }
00568 
00569       return true;
00570     }
00571   else
00572     return false;
00573 }
00574 
00575 // Ugh again.
00576 
00577 printf_format_list::printf_format_list (const std::string& s)
00578   : nconv (0), curr_idx (0), list (dim_vector (16, 1)), buf (0)
00579 {
00580   octave_idx_type num_elts = 0;
00581 
00582   size_t n = s.length ();
00583 
00584   size_t i = 0;
00585 
00586   int args = 0;
00587   std::string flags;
00588   int fw = 0;
00589   int prec = 0;
00590   char modifier = '\0';
00591   char type = '\0';
00592 
00593   bool have_more = true;
00594   bool empty_buf = true;
00595 
00596   if (n == 0)
00597     {
00598       printf_format_elt *elt
00599         = new printf_format_elt ("", args, fw, prec, flags, type, modifier);
00600 
00601       list(num_elts++) = elt;
00602 
00603       list.resize (dim_vector (num_elts, 1));
00604     }
00605   else
00606     {
00607       while (i < n)
00608         {
00609           have_more = true;
00610 
00611           if (! buf)
00612             {
00613               buf = new std::ostringstream ();
00614               empty_buf = true;
00615             }
00616 
00617           switch (s[i])
00618             {
00619             case '%':
00620               {
00621                 if (empty_buf)
00622                   {
00623                     process_conversion (s, i, n, args, flags, fw, prec,
00624                                         type, modifier, num_elts);
00625 
00626                     have_more = (buf != 0);
00627                   }
00628                 else
00629                   add_elt_to_list (args, flags, fw, prec, type, modifier,
00630                                    num_elts);
00631               }
00632               break;
00633 
00634             default:
00635               {
00636                 args = 0;
00637                 flags = "";
00638                 fw = 0;
00639                 prec = 0;
00640                 modifier = '\0';
00641                 type = '\0';
00642                 *buf << s[i++];
00643                 empty_buf = false;
00644               }
00645               break;
00646             }
00647 
00648           if (nconv < 0)
00649             {
00650               have_more = false;
00651               break;
00652             }
00653         }
00654 
00655       if (have_more)
00656         add_elt_to_list (args, flags, fw, prec, type, modifier, num_elts);
00657 
00658       list.resize (dim_vector (num_elts, 1));
00659 
00660       delete buf;
00661     }
00662 }
00663 
00664 printf_format_list::~printf_format_list (void)
00665 {
00666   octave_idx_type n = list.length ();
00667 
00668   for (octave_idx_type i = 0; i < n; i++)
00669     {
00670       printf_format_elt *elt = list(i);
00671       delete elt;
00672     }
00673 }
00674 
00675 void
00676 printf_format_list::add_elt_to_list (int args, const std::string& flags,
00677                                      int fw, int prec, char type,
00678                                      char modifier, octave_idx_type& num_elts)
00679 {
00680   if (buf)
00681     {
00682       std::string text = buf->str ();
00683 
00684       if (! text.empty ())
00685         {
00686           printf_format_elt *elt
00687             = new printf_format_elt (text.c_str (), args, fw, prec, flags,
00688                                      type, modifier);
00689 
00690           if (num_elts == list.length ())
00691             list.resize (dim_vector (2 * num_elts, 1));
00692 
00693           list(num_elts++) = elt;
00694         }
00695 
00696       delete buf;
00697       buf = 0;
00698     }
00699 }
00700 
00701 void
00702 printf_format_list::process_conversion
00703   (const std::string& s, size_t& i, size_t n, int& args, std::string& flags,
00704    int& fw, int& prec, char& modifier, char& type, octave_idx_type& num_elts)
00705 {
00706   args = 0;
00707   flags = "";
00708   fw = 0;
00709   prec = 0;
00710   modifier = '\0';
00711   type = '\0';
00712 
00713   *buf << s[i++];
00714 
00715   bool nxt = false;
00716 
00717   while (i < n)
00718     {
00719       switch (s[i])
00720         {
00721         case '-': case '+': case ' ': case '0': case '#':
00722           flags += s[i];
00723           *buf << s[i++];
00724           break;
00725 
00726         default:
00727           nxt = true;
00728           break;
00729         }
00730 
00731       if (nxt)
00732         break;
00733     }
00734 
00735   if (i < n)
00736     {
00737       if (s[i] == '*')
00738         {
00739           fw = -1;
00740           args++;
00741           *buf << s[i++];
00742         }
00743       else
00744         {
00745           if (isdigit (s[i]))
00746             {
00747               int nn = 0;
00748               std::string tmp = s.substr (i);
00749               sscanf (tmp.c_str (), "%d%n", &fw, &nn);
00750             }
00751 
00752           while (i < n && isdigit (s[i]))
00753             *buf << s[i++];
00754         }
00755     }
00756 
00757   if (i < n && s[i] == '.')
00758     {
00759       *buf << s[i++];
00760 
00761       if (i < n)
00762         {
00763           if (s[i] == '*')
00764             {
00765               prec = -1;
00766               args++;
00767               *buf << s[i++];
00768             }
00769           else
00770             {
00771               if (isdigit (s[i]))
00772                 {
00773                   int nn = 0;
00774                   std::string tmp = s.substr (i);
00775                   sscanf (tmp.c_str (), "%d%n", &prec, &nn);
00776                 }
00777 
00778               while (i < n && isdigit (s[i]))
00779                 *buf << s[i++];
00780             }
00781         }
00782     }
00783 
00784   if (i < n)
00785     {
00786       switch (s[i])
00787         {
00788         case 'h': case 'l': case 'L':
00789           modifier = s[i];
00790           *buf << s[i++];
00791           break;
00792 
00793         default:
00794           break;
00795         }
00796     }
00797 
00798   if (i < n)
00799     finish_conversion (s, i, args, flags, fw, prec, modifier, type, num_elts);
00800   else
00801     nconv = -1;
00802 }
00803 
00804 void
00805 printf_format_list::finish_conversion
00806   (const std::string& s, size_t& i, int args, const std::string& flags,
00807    int fw, int prec, char modifier, char& type, octave_idx_type& num_elts)
00808 
00809 {
00810   switch (s[i])
00811     {
00812     case 'd': case 'i': case 'o': case 'x': case 'X':
00813     case 'u': case 'c':
00814       if (modifier == 'L')
00815         {
00816           nconv = -1;
00817           break;
00818         }
00819       goto fini;
00820 
00821     case 'f': case 'e': case 'E': case 'g': case 'G':
00822       if (modifier == 'h' || modifier == 'l')
00823         {
00824           nconv = -1;
00825           break;
00826         }
00827       goto fini;
00828 
00829     case 's': case 'p': case '%':
00830       if (modifier != '\0')
00831         {
00832           nconv = -1;
00833           break;
00834         }
00835       goto fini;
00836 
00837     fini:
00838 
00839       type = s[i];
00840 
00841       *buf << s[i++];
00842 
00843       if (type != '%' || args != 0)
00844         nconv++;
00845 
00846       if (type != '%')
00847         args++;
00848 
00849       add_elt_to_list (args, flags, fw, prec, type, modifier, num_elts);
00850 
00851       break;
00852 
00853     default:
00854       nconv = -1;
00855       break;
00856     }
00857 }
00858 
00859 void
00860 printf_format_list::printme (void) const
00861 {
00862   int n = list.length ();
00863 
00864   for (int i = 0; i < n; i++)
00865     {
00866       printf_format_elt *elt = list(i);
00867 
00868       std::cerr
00869         << "args:     " << elt->args << "\n"
00870         << "flags:    '" << elt->flags << "'\n"
00871         << "width:    " << elt->fw << "\n"
00872         << "prec:     " << elt->prec << "\n"
00873         << "type:     '" << elt->type << "'\n"
00874         << "modifier: '" << elt->modifier << "'\n"
00875         << "text:     '" << undo_string_escapes (elt->text) << "'\n\n";
00876     }
00877 }
00878 
00879 void
00880 octave_base_stream::error (const std::string& msg)
00881 {
00882   fail = true;
00883   errmsg = msg;
00884 }
00885 
00886 void
00887 octave_base_stream::error (const std::string& who, const std::string& msg)
00888 {
00889   fail = true;
00890   errmsg = who + ": " + msg;
00891 }
00892 
00893 void
00894 octave_base_stream::clear (void)
00895 {
00896   fail = false;
00897   errmsg = "";
00898 }
00899 
00900 void
00901 octave_base_stream::clearerr (void)
00902 {
00903   std::istream *is = input_stream ();
00904   std::ostream *os = output_stream ();
00905 
00906   if (is)
00907     is->clear ();
00908 
00909   if (os)
00910     os->clear ();
00911 }
00912 
00913 // Functions that are defined for all input streams (input streams
00914 // are those that define is).
00915 
00916 std::string
00917 octave_base_stream::do_gets (octave_idx_type max_len, bool& err,
00918                              bool strip_newline, const std::string& who)
00919 {
00920   std::string retval;
00921 
00922   if ((interactive || forced_interactive) && file_number () == 0)
00923     {
00924       ::error ("%s: unable to read from stdin while running interactively",
00925                who.c_str ());
00926 
00927       return retval;
00928     }
00929 
00930   err = false;
00931 
00932   std::istream *isp = input_stream ();
00933 
00934   if (isp)
00935     {
00936       std::istream& is = *isp;
00937 
00938       std::ostringstream buf;
00939 
00940       int c = 0;
00941       int char_count = 0;
00942 
00943       if (max_len != 0)
00944         {
00945           while (is && (c = is.get ()) != EOF)
00946             {
00947               char_count++;
00948 
00949               // Handle CRLF, CR, or LF as line ending.
00950 
00951               if (c == '\r')
00952                 {
00953                   if (! strip_newline)
00954                     buf << static_cast<char> (c);
00955 
00956                   c = is.get ();
00957 
00958                   if (c != EOF)
00959                     {
00960                       if (c == '\n')
00961                         {
00962                           char_count++;
00963 
00964                           if (! strip_newline)
00965                             buf << static_cast<char> (c);
00966                         }
00967                       else
00968                         is.putback (c);
00969                     }
00970 
00971                   break;
00972                 }
00973               else if (c == '\n')
00974                 {
00975                   if (! strip_newline)
00976                     buf << static_cast<char> (c);
00977 
00978                   break;
00979                 }
00980               else
00981                 buf << static_cast<char> (c);
00982 
00983               if (max_len > 0 && char_count == max_len)
00984                 break;
00985             }
00986         }
00987 
00988       if (! is.eof () && char_count > 0)
00989         {
00990           // GAGME.  Matlab seems to check for EOF even if the last
00991           // character in a file is a newline character.  This is NOT
00992           // what the corresponding C-library functions do.
00993           int disgusting_compatibility_hack = is.get ();
00994           if (! is.eof ())
00995             is.putback (disgusting_compatibility_hack);
00996         }
00997 
00998       if (is.good () || (is.eof () && char_count > 0))
00999         retval = buf.str ();
01000       else
01001         {
01002           err = true;
01003 
01004           if (is.eof () && char_count == 0)
01005             error (who, "at end of file");
01006           else
01007             error (who, "read error");
01008         }
01009     }
01010   else
01011     {
01012       err = true;
01013       invalid_operation (who, "reading");
01014     }
01015 
01016   return retval;
01017 }
01018 
01019 std::string
01020 octave_base_stream::getl (octave_idx_type max_len, bool& err, const std::string& who)
01021 {
01022   return do_gets (max_len, err, true, who);
01023 }
01024 
01025 std::string
01026 octave_base_stream::gets (octave_idx_type max_len, bool& err, const std::string& who)
01027 {
01028   return do_gets (max_len, err, false, who);
01029 }
01030 
01031 long
01032 octave_base_stream::skipl (long num, bool& err, const std::string& who)
01033 {
01034   long cnt = -1;
01035 
01036   if ((interactive || forced_interactive) && file_number () == 0)
01037     {
01038       ::error ("%s: unable to read from stdin while running interactively",
01039                who.c_str ());
01040 
01041       return count;
01042     }
01043 
01044   err = false;
01045 
01046   std::istream *isp = input_stream ();
01047 
01048   if (isp)
01049     {
01050       std::istream& is = *isp;
01051 
01052       int c = 0, lastc = -1;
01053       cnt = 0;
01054 
01055       while (is && (c = is.get ()) != EOF)
01056         {
01057           // Handle CRLF, CR, or LF as line ending.
01058 
01059           if (c == '\r' || (c == '\n' && lastc != '\r'))
01060             {
01061               if (++cnt == num)
01062                 break;
01063             }
01064 
01065           lastc = c;
01066         }
01067 
01068       // Maybe eat the following \n if \r was just met.
01069       if (c == '\r' && is.peek () == '\n')
01070        is.get ();
01071 
01072       if (is.bad ())
01073         {
01074           err = true;
01075           error (who, "read error");
01076         }
01077 
01078       if (err)
01079         cnt = -1;
01080     }
01081   else
01082     {
01083       err = true;
01084       invalid_operation (who, "reading");
01085     }
01086 
01087   return cnt;
01088 }
01089 
01090 #define OCTAVE_SCAN(is, fmt, arg) octave_scan (is, fmt, arg)
01091 
01092 template <class T>
01093 std::istream&
01094 octave_scan_1 (std::istream& is, const scanf_format_elt& fmt, T* valptr)
01095 {
01096   T& ref = *valptr;
01097 
01098   switch (fmt.type)
01099     {
01100     case 'o':
01101       is >> std::oct >> ref >> std::dec;
01102       break;
01103 
01104     case 'x':
01105       is >> std::hex >> ref >> std::dec;
01106       break;
01107 
01108     case 'i':
01109       {
01110         int c1 = is.get ();
01111 
01112         if (! is.eof ())
01113           {
01114             if (c1 == '0')
01115               {
01116                 int c2 = is.peek ();
01117 
01118                 if (c2 == 'x' || c2 == 'X')
01119                   {
01120                     is.ignore ();
01121                     if (std::isxdigit (is.peek ()))
01122                       is >> std::hex >> ref >> std::dec;
01123                     else
01124                       ref = 0;
01125                   }
01126                 else
01127                   {
01128                     if (c2 == '0' || c2 == '1' || c2 == '2'
01129                         || c2 == '3' || c2 == '4' || c2 == '5'
01130                         || c2 == '6' || c2 == '7')
01131                       is >> std::oct >> ref >> std::dec;
01132                     else
01133                       ref = 0;
01134                   }
01135               }
01136             else
01137               {
01138                 is.putback (c1);
01139 
01140                 is >> ref;
01141               }
01142           }
01143       }
01144       break;
01145 
01146     default:
01147       is >> ref;
01148       break;
01149     }
01150 
01151   return is;
01152 }
01153 
01154 template <class T>
01155 std::istream&
01156 octave_scan (std::istream& is, const scanf_format_elt& fmt, T* valptr)
01157 {
01158   if (fmt.width)
01159     {
01160       // Limit input to fmt.width characters by reading into a
01161       // temporary stringstream buffer.
01162 
01163       std::string tmp;
01164 
01165       is.width (fmt.width);
01166       is >> tmp;
01167 
01168       std::istringstream ss (tmp);
01169 
01170       octave_scan_1 (ss, fmt, valptr);
01171     }
01172   else
01173     octave_scan_1 (is, fmt, valptr);
01174 
01175   return is;
01176 }
01177 
01178 // Note that this specialization is only used for reading characters, not
01179 // character strings. See BEGIN_S_CONVERSION for details.
01180 
01181 template<>
01182 std::istream&
01183 octave_scan<> (std::istream& is, const scanf_format_elt& /* fmt */,
01184                char* valptr)
01185 {
01186   return is >> valptr;
01187 }
01188 
01189 template std::istream&
01190 octave_scan (std::istream&, const scanf_format_elt&, int*);
01191 
01192 template std::istream&
01193 octave_scan (std::istream&, const scanf_format_elt&, long int*);
01194 
01195 template std::istream&
01196 octave_scan (std::istream&, const scanf_format_elt&, short int*);
01197 
01198 template std::istream&
01199 octave_scan (std::istream&, const scanf_format_elt&, unsigned int*);
01200 
01201 template std::istream&
01202 octave_scan (std::istream&, const scanf_format_elt&, unsigned long int*);
01203 
01204 template std::istream&
01205 octave_scan (std::istream&, const scanf_format_elt&, unsigned short int*);
01206 
01207 #if 0
01208 template std::istream&
01209 octave_scan (std::istream&, const scanf_format_elt&, float*);
01210 #endif
01211 
01212 template<>
01213 std::istream&
01214 octave_scan<> (std::istream& is, const scanf_format_elt& fmt, double* valptr)
01215 {
01216   double& ref = *valptr;
01217 
01218   switch (fmt.type)
01219     {
01220     case 'e':
01221     case 'f':
01222     case 'g':
01223       {
01224         int c1 = EOF;
01225 
01226         while (is && (c1 = is.get ()) != EOF && isspace (c1))
01227           /* skip whitespace */;
01228 
01229         if (c1 != EOF)
01230           {
01231             is.putback (c1);
01232 
01233             ref = octave_read_value<double> (is);
01234           }
01235       }
01236       break;
01237 
01238     default:
01239       panic_impossible ();
01240       break;
01241     }
01242 
01243   return is;
01244 }
01245 
01246 template <class T>
01247 void
01248 do_scanf_conv (std::istream& is, const scanf_format_elt& fmt,
01249                T valptr, Matrix& mval, double *data, octave_idx_type& idx,
01250                octave_idx_type& conversion_count, octave_idx_type nr, octave_idx_type max_size,
01251                bool discard)
01252 {
01253   OCTAVE_SCAN (is, fmt, valptr);
01254 
01255   if (is)
01256     {
01257       if (idx == max_size && ! discard)
01258         {
01259           max_size *= 2;
01260 
01261           if (nr > 0)
01262             mval.resize (nr, max_size / nr, 0.0);
01263           else
01264             mval.resize (max_size, 1, 0.0);
01265 
01266           data = mval.fortran_vec ();
01267         }
01268 
01269       if (! discard)
01270         {
01271           conversion_count++;
01272           data[idx++] = *(valptr);
01273         }
01274     }
01275 }
01276 
01277 template void
01278 do_scanf_conv (std::istream&, const scanf_format_elt&, int*,
01279                Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
01280 
01281 template void
01282 do_scanf_conv (std::istream&, const scanf_format_elt&, long int*,
01283                Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
01284 
01285 template void
01286 do_scanf_conv (std::istream&, const scanf_format_elt&, short int*,
01287                Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
01288 
01289 template void
01290 do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned int*,
01291                Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
01292 
01293 template void
01294 do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned long int*,
01295                Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
01296 
01297 template void
01298 do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned short int*,
01299                Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
01300 
01301 #if 0
01302 template void
01303 do_scanf_conv (std::istream&, const scanf_format_elt&, float*,
01304                Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
01305 #endif
01306 
01307 template void
01308 do_scanf_conv (std::istream&, const scanf_format_elt&, double*,
01309                Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool);
01310 
01311 #define DO_WHITESPACE_CONVERSION() \
01312   do \
01313     { \
01314       int c = EOF; \
01315  \
01316       while (is && (c = is.get ()) != EOF && isspace (c)) \
01317         /* skip whitespace */; \
01318  \
01319       if (c != EOF) \
01320         is.putback (c); \
01321     } \
01322   while (0)
01323 
01324 #define DO_LITERAL_CONVERSION() \
01325   do \
01326     { \
01327       int c = EOF; \
01328  \
01329       int n = strlen (fmt); \
01330       int i = 0; \
01331  \
01332       while (i < n && is && (c = is.get ()) != EOF) \
01333         { \
01334           if (c == static_cast<unsigned char> (fmt[i])) \
01335             { \
01336               i++; \
01337               continue; \
01338             } \
01339           else \
01340             { \
01341               is.putback (c); \
01342               break; \
01343             } \
01344         } \
01345  \
01346       if (i != n) \
01347         is.setstate (std::ios::failbit); \
01348     } \
01349   while (0)
01350 
01351 #define DO_PCT_CONVERSION() \
01352   do \
01353     { \
01354       int c = is.get (); \
01355  \
01356       if (c != EOF) \
01357         { \
01358           if (c != '%') \
01359             { \
01360               is.putback (c); \
01361               is.setstate (std::ios::failbit); \
01362             } \
01363         } \
01364       else \
01365         is.setstate (std::ios::failbit); \
01366     } \
01367   while (0)
01368 
01369 #define BEGIN_C_CONVERSION() \
01370   is.unsetf (std::ios::skipws); \
01371  \
01372   int width = elt->width ? elt->width : 1; \
01373  \
01374   std::string tmp (width, '\0'); \
01375  \
01376   int c = EOF; \
01377   int n = 0; \
01378  \
01379   while (is && n < width && (c = is.get ()) != EOF) \
01380     tmp[n++] = static_cast<char> (c); \
01381  \
01382   if (n > 0 && c == EOF) \
01383     is.clear (); \
01384  \
01385   tmp.resize (n)
01386 
01387 // For a '%s' format, skip initial whitespace and then read until the
01388 // next whitespace character or until WIDTH characters have been read.
01389 #define BEGIN_S_CONVERSION() \
01390   int width = elt->width; \
01391  \
01392   std::string tmp; \
01393  \
01394   do \
01395     { \
01396       if (width) \
01397         { \
01398           tmp = std::string (width, '\0'); \
01399  \
01400           int c = EOF; \
01401  \
01402           int n = 0; \
01403  \
01404           while (is && (c = is.get ()) != EOF) \
01405             { \
01406               if (! isspace (c)) \
01407                 { \
01408                   tmp[n++] = static_cast<char> (c); \
01409                   break; \
01410                 } \
01411             } \
01412  \
01413           while (is && n < width && (c = is.get ()) != EOF) \
01414             { \
01415               if (isspace (c)) \
01416                 { \
01417                   is.putback (c); \
01418                   break; \
01419                 } \
01420               else \
01421                 tmp[n++] = static_cast<char> (c); \
01422             } \
01423  \
01424           if (n > 0 && c == EOF) \
01425             is.clear (); \
01426  \
01427           tmp.resize (n); \
01428         } \
01429       else \
01430         { \
01431           is >> std::ws >> tmp; \
01432         } \
01433     } \
01434   while (0)
01435 
01436 // This format must match a nonempty sequence of characters.
01437 #define BEGIN_CHAR_CLASS_CONVERSION() \
01438   int width = elt->width; \
01439  \
01440   std::string tmp; \
01441  \
01442   do \
01443     { \
01444       if (! width) \
01445         width = INT_MAX; \
01446  \
01447       std::ostringstream buf; \
01448  \
01449       std::string char_class = elt->char_class; \
01450  \
01451       int c = EOF; \
01452  \
01453       if (elt->type == '[') \
01454         { \
01455           int chars_read = 0; \
01456           while (is && chars_read++ < width && (c = is.get ()) != EOF \
01457                  && char_class.find (c) != std::string::npos) \
01458             buf << static_cast<char> (c); \
01459         } \
01460       else \
01461         { \
01462           int chars_read = 0; \
01463           while (is && chars_read++ < width && (c = is.get ()) != EOF \
01464                  && char_class.find (c) == std::string::npos) \
01465             buf << static_cast<char> (c); \
01466         } \
01467  \
01468       if (width == INT_MAX && c != EOF) \
01469         is.putback (c); \
01470  \
01471       tmp = buf.str (); \
01472  \
01473       if (tmp.empty ()) \
01474         is.setstate (std::ios::failbit); \
01475       else if (c == EOF) \
01476         is.clear (); \
01477  \
01478     } \
01479   while (0)
01480 
01481 #define FINISH_CHARACTER_CONVERSION() \
01482   do \
01483     { \
01484       width = tmp.length (); \
01485  \
01486       if (is) \
01487         { \
01488           int i = 0; \
01489  \
01490           if (! discard) \
01491             { \
01492               conversion_count++; \
01493  \
01494               while (i < width) \
01495                 { \
01496                   if (data_index == max_size) \
01497                     { \
01498                       max_size *= 2; \
01499  \
01500                       if (all_char_conv) \
01501                         { \
01502                           if (one_elt_size_spec) \
01503                             mval.resize (1, max_size, 0.0); \
01504                           else if (nr > 0) \
01505                             mval.resize (nr, max_size / nr, 0.0); \
01506                           else \
01507                             panic_impossible (); \
01508                         } \
01509                       else if (nr > 0) \
01510                         mval.resize (nr, max_size / nr, 0.0); \
01511                       else \
01512                         mval.resize (max_size, 1, 0.0); \
01513  \
01514                       data = mval.fortran_vec (); \
01515                     } \
01516  \
01517                   data[data_index++] = tmp[i++]; \
01518                 } \
01519             } \
01520         } \
01521     } \
01522   while (0)
01523 
01524 octave_value
01525 octave_base_stream::do_scanf (scanf_format_list& fmt_list,
01526                               octave_idx_type nr, octave_idx_type nc, bool one_elt_size_spec,
01527                               octave_idx_type& conversion_count, const std::string& who)
01528 {
01529   octave_value retval = Matrix ();
01530 
01531   if ((interactive || forced_interactive) && file_number () == 0)
01532     {
01533       ::error ("%s: unable to read from stdin while running interactively",
01534                who.c_str ());
01535 
01536       return retval;
01537     }
01538 
01539   conversion_count = 0;
01540 
01541   octave_idx_type nconv = fmt_list.num_conversions ();
01542 
01543   octave_idx_type data_index = 0;
01544 
01545   if (nr == 0 || nc == 0)
01546     {
01547       if (one_elt_size_spec)
01548         nc = 0;
01549 
01550       return Matrix (nr, nc, 0.0);
01551     }
01552 
01553   std::istream *isp = input_stream ();
01554 
01555   bool all_char_conv = fmt_list.all_character_conversions ();
01556 
01557   Matrix mval;
01558   double *data = 0;
01559   octave_idx_type max_size = 0;
01560   octave_idx_type max_conv = 0;
01561 
01562   octave_idx_type final_nr = 0;
01563   octave_idx_type final_nc = 0;
01564 
01565   if (all_char_conv)
01566     {
01567       // Any of these could be resized later (if we have %s
01568       // conversions, we may read more than one element for each
01569       // conversion).
01570 
01571       if (one_elt_size_spec)
01572         {
01573           max_size = 512;
01574           mval.resize (1, max_size, 0.0);
01575 
01576           if (nr > 0)
01577             max_conv = nr;
01578         }
01579       else if (nr > 0)
01580         {
01581           if (nc > 0)
01582             {
01583               mval.resize (nr, nc, 0.0);
01584               max_size = max_conv = nr * nc;
01585             }
01586           else
01587             {
01588               mval.resize (nr, 32, 0.0);
01589               max_size = nr * 32;
01590             }
01591         }
01592       else
01593         panic_impossible ();
01594     }
01595   else if (nr > 0)
01596     {
01597       if (nc > 0)
01598         {
01599           // Will not resize later.
01600           mval.resize (nr, nc, 0.0);
01601           max_size = nr * nc;
01602           max_conv = max_size;
01603         }
01604       else
01605         {
01606           // Maybe resize later.
01607           mval.resize (nr, 32, 0.0);
01608           max_size = nr * 32;
01609         }
01610     }
01611   else
01612     {
01613       // Maybe resize later.
01614       mval.resize (32, 1, 0.0);
01615       max_size = 32;
01616     }
01617 
01618   data = mval.fortran_vec ();
01619 
01620   if (isp)
01621     {
01622       std::istream& is = *isp;
01623 
01624       const scanf_format_elt *elt = fmt_list.first ();
01625 
01626       std::ios::fmtflags flags = is.flags ();
01627 
01628       octave_idx_type trips = 0;
01629 
01630       octave_idx_type num_fmt_elts = fmt_list.length ();
01631 
01632       for (;;)
01633         {
01634           octave_quit ();
01635 
01636           if (elt)
01637             {
01638               if (! (elt->type == scanf_format_elt::whitespace_conversion
01639                      || elt->type == scanf_format_elt::literal_conversion
01640                      || elt->type == '%')
01641                   && max_conv > 0 && conversion_count == max_conv)
01642                 {
01643                   if (all_char_conv && one_elt_size_spec)
01644                     {
01645                       final_nr = 1;
01646                       final_nc = data_index;
01647                     }
01648                   else
01649                     {
01650                       final_nr = nr;
01651                       final_nc = (data_index - 1) / nr + 1;
01652                     }
01653 
01654                   break;
01655                 }
01656               else if (data_index == max_size)
01657                 {
01658                   max_size *= 2;
01659 
01660                   if (all_char_conv)
01661                     {
01662                       if (one_elt_size_spec)
01663                         mval.resize (1, max_size, 0.0);
01664                       else if (nr > 0)
01665                         mval.resize (nr, max_size / nr, 0.0);
01666                       else
01667                         panic_impossible ();
01668                     }
01669                   else if (nr > 0)
01670                     mval.resize (nr, max_size / nr, 0.0);
01671                   else
01672                     mval.resize (max_size, 1, 0.0);
01673 
01674                   data = mval.fortran_vec ();
01675                 }
01676 
01677               const char *fmt = elt->text;
01678 
01679               bool discard = elt->discard;
01680 
01681               switch (elt->type)
01682                 {
01683                 case scanf_format_elt::whitespace_conversion:
01684                   DO_WHITESPACE_CONVERSION ();
01685                   break;
01686 
01687                 case scanf_format_elt::literal_conversion:
01688                   DO_LITERAL_CONVERSION ();
01689                   break;
01690 
01691                 case '%':
01692                   DO_PCT_CONVERSION ();
01693                   break;
01694 
01695                 case 'd': case 'i':
01696                   {
01697                     switch (elt->modifier)
01698                       {
01699                       case 'h':
01700                         {
01701                           short int tmp;
01702                           do_scanf_conv (is, *elt, &tmp, mval, data,
01703                                          data_index, conversion_count,
01704                                          nr, max_size, discard);
01705                         }
01706                         break;
01707 
01708                       case 'l':
01709                         {
01710                           long int tmp;
01711                           do_scanf_conv (is, *elt, &tmp, mval, data,
01712                                          data_index, conversion_count,
01713                                          nr, max_size, discard);
01714                         }
01715                         break;
01716 
01717                       default:
01718                         {
01719                           int tmp;
01720                           do_scanf_conv (is, *elt, &tmp, mval, data,
01721                                          data_index, conversion_count,
01722                                          nr, max_size, discard);
01723                         }
01724                         break;
01725                       }
01726                   }
01727                   break;
01728 
01729                 case 'o': case 'u': case 'x':
01730                   {
01731                     switch (elt->modifier)
01732                       {
01733                       case 'h':
01734                         {
01735                           unsigned short int tmp;
01736                           do_scanf_conv (is, *elt, &tmp, mval, data,
01737                                          data_index, conversion_count,
01738                                          nr, max_size, discard);
01739                         }
01740                         break;
01741 
01742                       case 'l':
01743                         {
01744                           unsigned long int tmp;
01745                           do_scanf_conv (is, *elt, &tmp, mval, data,
01746                                          data_index, conversion_count,
01747                                          nr, max_size, discard);
01748                         }
01749                         break;
01750 
01751                       default:
01752                         {
01753                           unsigned int tmp;
01754                           do_scanf_conv (is, *elt, &tmp, mval, data,
01755                                          data_index, conversion_count,
01756                                          nr, max_size, discard);
01757                         }
01758                         break;
01759                       }
01760                   }
01761                   break;
01762 
01763                 case 'e': case 'f': case 'g':
01764                   {
01765                     double tmp;
01766 
01767                     do_scanf_conv (is, *elt, &tmp, mval, data,
01768                                    data_index, conversion_count,
01769                                    nr, max_size, discard);
01770                   }
01771                   break;
01772 
01773                 case 'c':
01774                   {
01775                     BEGIN_C_CONVERSION ();
01776 
01777                     FINISH_CHARACTER_CONVERSION ();
01778 
01779                     is.setf (flags);
01780                   }
01781                   break;
01782 
01783                 case 's':
01784                   {
01785                     BEGIN_S_CONVERSION ();
01786 
01787                     FINISH_CHARACTER_CONVERSION ();
01788                   }
01789                   break;
01790 
01791                 case '[': case '^':
01792                   {
01793                     BEGIN_CHAR_CLASS_CONVERSION ();
01794 
01795                     FINISH_CHARACTER_CONVERSION ();
01796                   }
01797                   break;
01798 
01799                 case 'p':
01800                   error ("%s: unsupported format specifier", who.c_str ());
01801                   break;
01802 
01803                 default:
01804                   error ("%s: internal format error", who.c_str ());
01805                   break;
01806                 }
01807 
01808               if (! ok ())
01809                 {
01810                   break;
01811                 }
01812               else if (! is)
01813                 {
01814                   if (all_char_conv)
01815                     {
01816                       if (one_elt_size_spec)
01817                         {
01818                           final_nr = 1;
01819                           final_nc = data_index;
01820                         }
01821                       else if (data_index > nr)
01822                         {
01823                           final_nr = nr;
01824                           final_nc = (data_index - 1) / nr + 1;
01825                         }
01826                       else
01827                         {
01828                           final_nr = data_index;
01829                           final_nc = 1;
01830                         }
01831                     }
01832                   else if (nr > 0)
01833                     {
01834                       if (data_index > nr)
01835                         {
01836                           final_nr = nr;
01837                           final_nc = (data_index - 1) / nr + 1;
01838                         }
01839                       else
01840                         {
01841                           final_nr = data_index;
01842                           final_nc = 1;
01843                         }
01844                     }
01845                   else
01846                     {
01847                       final_nr = data_index;
01848                       final_nc = 1;
01849                     }
01850 
01851                   // If it looks like we have a matching failure, then
01852                   // reset the failbit in the stream state.
01853 
01854                   if (is.rdstate () & std::ios::failbit)
01855                     is.clear (is.rdstate () & (~std::ios::failbit));
01856 
01857                   // FIXME -- is this the right thing to do?
01858 
01859                   if (interactive && name () == "stdin")
01860                     {
01861                       is.clear ();
01862 
01863                       // Skip to end of line.
01864 
01865                       bool err;
01866                       do_gets (-1, err, false, who);
01867                     }
01868 
01869                   break;
01870                 }
01871             }
01872           else
01873             {
01874               error ("%s: internal format error", who.c_str ());
01875               break;
01876             }
01877 
01878           if (nconv == 0 && ++trips == num_fmt_elts)
01879             {
01880               if (all_char_conv && one_elt_size_spec)
01881                 {
01882                   final_nr = 1;
01883                   final_nc = data_index;
01884                 }
01885               else
01886                 {
01887                   final_nr = nr;
01888                   final_nc = (data_index - 1) / nr + 1;
01889                 }
01890 
01891               break;
01892             }
01893           else
01894             elt = fmt_list.next (nconv > 0);
01895         }
01896     }
01897 
01898   if (ok ())
01899     {
01900       mval.resize (final_nr, final_nc, 0.0);
01901 
01902       retval = mval;
01903 
01904       if (all_char_conv)
01905         retval = retval.convert_to_str (false, true);
01906     }
01907 
01908   return retval;
01909 }
01910 
01911 octave_value
01912 octave_base_stream::scanf (const std::string& fmt, const Array<double>& size,
01913                            octave_idx_type& conversion_count, const std::string& who)
01914 {
01915   octave_value retval = Matrix ();
01916 
01917   conversion_count = 0;
01918 
01919   std::istream *isp = input_stream ();
01920 
01921   if (isp)
01922     {
01923       scanf_format_list fmt_list (fmt);
01924 
01925       if (fmt_list.num_conversions () == -1)
01926         ::error ("%s: invalid format specified", who.c_str ());
01927       else
01928         {
01929         octave_idx_type nr = -1;
01930         octave_idx_type nc = -1;
01931 
01932         bool one_elt_size_spec;
01933 
01934         get_size (size, nr, nc, one_elt_size_spec, who);
01935 
01936         if (! error_state)
01937           retval = do_scanf (fmt_list, nr, nc, one_elt_size_spec,
01938                              conversion_count, who);
01939         }
01940     }
01941   else
01942     invalid_operation (who, "reading");
01943 
01944   return retval;
01945 }
01946 
01947 bool
01948 octave_base_stream::do_oscanf (const scanf_format_elt *elt,
01949                                octave_value& retval, const std::string& who)
01950 {
01951   bool quit = false;
01952 
01953   std::istream *isp = input_stream ();
01954 
01955   if (isp)
01956     {
01957       std::istream& is = *isp;
01958 
01959       std::ios::fmtflags flags = is.flags ();
01960 
01961       if (elt)
01962         {
01963           const char *fmt = elt->text;
01964 
01965           bool discard = elt->discard;
01966 
01967           switch (elt->type)
01968             {
01969             case scanf_format_elt::whitespace_conversion:
01970               DO_WHITESPACE_CONVERSION ();
01971               break;
01972 
01973             case scanf_format_elt::literal_conversion:
01974               DO_LITERAL_CONVERSION ();
01975               break;
01976 
01977             case '%':
01978               {
01979                 DO_PCT_CONVERSION ();
01980 
01981                 if (! is)
01982                   quit = true;
01983 
01984               }
01985               break;
01986 
01987             case 'd': case 'i':
01988               {
01989                 int tmp;
01990 
01991                 if (OCTAVE_SCAN (is, *elt, &tmp))
01992                   {
01993                     if (! discard)
01994                       retval = tmp;
01995                   }
01996                 else
01997                   quit = true;
01998               }
01999               break;
02000 
02001             case 'o': case 'u': case 'x':
02002               {
02003                 long int tmp;
02004 
02005                 if (OCTAVE_SCAN (is, *elt, &tmp))
02006                   {
02007                     if (! discard)
02008                       retval = tmp;
02009                   }
02010                 else
02011                   quit = true;
02012               }
02013               break;
02014 
02015             case 'e': case 'f': case 'g':
02016               {
02017                 double tmp;
02018 
02019                 if (OCTAVE_SCAN (is, *elt, &tmp))
02020                   {
02021                     if (! discard)
02022                       retval = tmp;
02023                   }
02024                 else
02025                   quit = true;
02026               }
02027               break;
02028 
02029             case 'c':
02030               {
02031                 BEGIN_C_CONVERSION ();
02032 
02033                 if (! discard)
02034                   retval = tmp;
02035 
02036                 if (! is)
02037                   quit = true;
02038 
02039                 is.setf (flags);
02040               }
02041               break;
02042 
02043             case 's':
02044               {
02045                 BEGIN_S_CONVERSION ();
02046 
02047                 if (! discard)
02048                   retval = tmp;
02049 
02050                 if (! is)
02051                   quit = true;
02052               }
02053               break;
02054 
02055             case '[': case '^':
02056               {
02057                 BEGIN_CHAR_CLASS_CONVERSION ();
02058 
02059                 if (! discard)
02060                   retval = tmp;
02061 
02062                 if (! is)
02063                   quit = true;
02064               }
02065               break;
02066 
02067             case 'p':
02068               error ("%s: unsupported format specifier", who.c_str ());
02069               break;
02070 
02071             default:
02072               error ("%s: internal format error", who.c_str ());
02073               break;
02074             }
02075         }
02076 
02077       if (ok () && is.fail ())
02078         {
02079           error ("%s: read error", who.c_str ());
02080 
02081           // FIXME -- is this the right thing to do?
02082 
02083           if (interactive && name () == "stdin")
02084             {
02085               // Skip to end of line.
02086 
02087               bool err;
02088               do_gets (-1, err, false, who);
02089             }
02090         }
02091     }
02092 
02093   return quit;
02094 }
02095 
02096 octave_value_list
02097 octave_base_stream::oscanf (const std::string& fmt, const std::string& who)
02098 {
02099   octave_value_list retval;
02100 
02101   std::istream *isp = input_stream ();
02102 
02103   if (isp)
02104     {
02105       std::istream& is = *isp;
02106 
02107       scanf_format_list fmt_list (fmt);
02108 
02109       octave_idx_type nconv = fmt_list.num_conversions ();
02110 
02111       if (nconv == -1)
02112         ::error ("%s: invalid format specified", who.c_str ());
02113       else
02114         {
02115           is.clear ();
02116 
02117           octave_idx_type len = fmt_list.length ();
02118 
02119           retval.resize (nconv+2, Matrix ());
02120 
02121           const scanf_format_elt *elt = fmt_list.first ();
02122 
02123           int num_values = 0;
02124 
02125           bool quit = false;
02126 
02127           for (octave_idx_type i = 0; i < len; i++)
02128             {
02129               octave_value tmp;
02130 
02131               quit = do_oscanf (elt, tmp, who);
02132 
02133               if (quit)
02134                 break;
02135               else
02136                 {
02137                   if (tmp.is_defined ())
02138                     retval (num_values++) = tmp;
02139 
02140                   if (! ok ())
02141                     break;
02142 
02143                   elt = fmt_list.next (nconv > 0);
02144                 }
02145             }
02146 
02147           retval(nconv) = num_values;
02148 
02149           int err_num;
02150           retval(nconv+1) = error (false, err_num);
02151 
02152           if (! quit)
02153             {
02154               // Pick up any trailing stuff.
02155               if (ok () && len > nconv)
02156                 {
02157                   octave_value tmp;
02158 
02159                   elt = fmt_list.next ();
02160 
02161                   do_oscanf (elt, tmp, who);
02162                 }
02163             }
02164         }
02165     }
02166   else
02167     invalid_operation (who, "reading");
02168 
02169   return retval;
02170 }
02171 
02172 // Functions that are defined for all output streams (output streams
02173 // are those that define os).
02174 
02175 int
02176 octave_base_stream::flush (void)
02177 {
02178   int retval = -1;
02179 
02180   std::ostream *os = output_stream ();
02181 
02182   if (os)
02183     {
02184       os->flush ();
02185 
02186       if (os->good ())
02187         retval = 0;
02188     }
02189   else
02190     invalid_operation ("fflush", "writing");
02191 
02192   return retval;
02193 }
02194 
02195 class
02196 printf_value_cache
02197 {
02198 public:
02199 
02200   enum state { ok, conversion_error };
02201 
02202   printf_value_cache (const octave_value_list& args, const std::string& who)
02203     : values (args), val_idx (0), elt_idx (0),
02204       n_vals (values.length ()), n_elts (0), data (0),
02205       curr_state (ok)
02206   {
02207     for (octave_idx_type i = 0; i < values.length (); i++)
02208       {
02209         octave_value val = values(i);
02210 
02211         if (val.is_map () || val.is_cell () || val.is_object ())
02212           {
02213             gripe_wrong_type_arg (who, val);
02214             break;
02215           }
02216       }
02217   }
02218 
02219   ~printf_value_cache (void) { }
02220 
02221   // Get the current value as a double and advance the internal pointer.
02222   double double_value (void);
02223 
02224   // Get the current value as an int and advance the internal pointer.
02225   int int_value (void);
02226 
02227   // Get the current value as a string and advance the internal pointer.
02228   std::string string_value (void);
02229 
02230   operator bool () const { return (curr_state == ok); }
02231 
02232   bool exhausted (void) { return (val_idx >= n_vals); }
02233 
02234 private:
02235 
02236   const octave_value_list values;
02237   int val_idx;
02238   int elt_idx;
02239   int n_vals;
02240   int n_elts;
02241   const double *data;
02242   NDArray curr_val;
02243   state curr_state;
02244 
02245   // Must create value cache with values!
02246 
02247   printf_value_cache (void);
02248 
02249   // No copying!
02250 
02251   printf_value_cache (const printf_value_cache&);
02252 
02253   printf_value_cache& operator = (const printf_value_cache&);
02254 };
02255 
02256 double
02257 printf_value_cache::double_value (void)
02258 {
02259   double retval = 0.0;
02260 
02261   if (exhausted ())
02262     curr_state = conversion_error;
02263 
02264   while (! exhausted ())
02265     {
02266       if (! data)
02267         {
02268           octave_value tmp_val = values (val_idx);
02269 
02270           // Force string conversion here for compatibility.
02271 
02272           curr_val = tmp_val.array_value (true);
02273 
02274           if (! error_state)
02275             {
02276               elt_idx = 0;
02277               n_elts = curr_val.length ();
02278               data = curr_val.data ();
02279             }
02280           else
02281             {
02282               curr_state = conversion_error;
02283               break;
02284             }
02285         }
02286 
02287       if (elt_idx < n_elts)
02288         {
02289           retval = data[elt_idx++];
02290 
02291           if (elt_idx >= n_elts)
02292             {
02293               elt_idx = 0;
02294               val_idx++;
02295               data = 0;
02296             }
02297 
02298           break;
02299         }
02300       else
02301         {
02302           val_idx++;
02303           data = 0;
02304 
02305           if (n_elts == 0 && exhausted ())
02306             curr_state = conversion_error;
02307 
02308           continue;
02309         }
02310     }
02311 
02312   return retval;
02313 }
02314 
02315 int
02316 printf_value_cache::int_value (void)
02317 {
02318   int retval = 0;
02319 
02320   double dval = double_value ();
02321 
02322   if (! error_state)
02323     {
02324       if (D_NINT (dval) == dval)
02325         retval = NINT (dval);
02326       else
02327         curr_state = conversion_error;
02328     }
02329 
02330   return retval;
02331 }
02332 
02333 std::string
02334 printf_value_cache::string_value (void)
02335 {
02336   std::string retval;
02337 
02338   if (exhausted ())
02339     curr_state = conversion_error;
02340   else
02341     {
02342       octave_value tval = values (val_idx++);
02343 
02344       if (tval.rows () == 1)
02345         retval = tval.string_value ();
02346       else
02347         {
02348           // In the name of Matlab compatibility.
02349 
02350           charMatrix chm = tval.char_matrix_value ();
02351 
02352           octave_idx_type nr = chm.rows ();
02353           octave_idx_type nc = chm.columns ();
02354 
02355           int k = 0;
02356 
02357           retval.resize (nr * nc, '\0');
02358 
02359           for (octave_idx_type j = 0; j < nc; j++)
02360             for (octave_idx_type i = 0; i < nr; i++)
02361               retval[k++] = chm(i,j);
02362         }
02363 
02364       if (error_state)
02365         curr_state = conversion_error;
02366     }
02367 
02368   return retval;
02369 }
02370 
02371 // Ugh again and again.
02372 
02373 template <class T>
02374 int
02375 do_printf_conv (std::ostream& os, const char *fmt, int nsa, int sa_1,
02376                 int sa_2, T arg, const std::string& who)
02377 {
02378   int retval = 0;
02379 
02380   switch (nsa)
02381     {
02382     case 2:
02383       retval = octave_format (os, fmt, sa_1, sa_2, arg);
02384       break;
02385 
02386     case 1:
02387       retval = octave_format (os, fmt, sa_1, arg);
02388       break;
02389 
02390     case 0:
02391       retval = octave_format (os, fmt, arg);
02392       break;
02393 
02394     default:
02395       ::error ("%s: internal error handling format", who.c_str ());
02396       break;
02397     }
02398 
02399   return retval;
02400 }
02401 
02402 template int
02403 do_printf_conv (std::ostream&, const char*, int, int, int, int,
02404                 const std::string&);
02405 
02406 template int
02407 do_printf_conv (std::ostream&, const char*, int, int, int, long,
02408                 const std::string&);
02409 
02410 template int
02411 do_printf_conv (std::ostream&, const char*, int, int, int, unsigned int,
02412                 const std::string&);
02413 
02414 template int
02415 do_printf_conv (std::ostream&, const char*, int, int, int, unsigned long,
02416                 const std::string&);
02417 
02418 template int
02419 do_printf_conv (std::ostream&, const char*, int, int, int, double,
02420                 const std::string&);
02421 
02422 template int
02423 do_printf_conv (std::ostream&, const char*, int, int, int, const char*,
02424                 const std::string&);
02425 
02426 #define DO_DOUBLE_CONV(TQUAL) \
02427   do \
02428     { \
02429       if (val > std::numeric_limits<TQUAL long>::max () \
02430           || val < std::numeric_limits<TQUAL long>::min ()) \
02431         { \
02432           std::string tfmt = fmt; \
02433  \
02434           tfmt.replace (tfmt.rfind (elt->type), 1, ".f"); \
02435  \
02436           if (elt->modifier == 'l') \
02437             tfmt.replace (tfmt.rfind (elt->modifier), 1, ""); \
02438  \
02439           retval += do_printf_conv (os, tfmt.c_str (), nsa, sa_1, sa_2, \
02440                                     val, who); \
02441         } \
02442       else \
02443         retval += do_printf_conv (os, fmt, nsa, sa_1, sa_2, \
02444                                   static_cast<TQUAL long> (val), who); \
02445     } \
02446   while (0)
02447 
02448 int
02449 octave_base_stream::do_printf (printf_format_list& fmt_list,
02450                                const octave_value_list& args,
02451                                const std::string& who)
02452 {
02453   int retval = 0;
02454 
02455   octave_idx_type nconv = fmt_list.num_conversions ();
02456 
02457   std::ostream *osp = output_stream ();
02458 
02459   if (osp)
02460     {
02461       std::ostream& os = *osp;
02462 
02463       const printf_format_elt *elt = fmt_list.first ();
02464 
02465       printf_value_cache val_cache (args, who);
02466 
02467       if (error_state)
02468         return retval;
02469 
02470       for (;;)
02471         {
02472           octave_quit ();
02473 
02474           if (elt)
02475             {
02476               // NSA is the number of 'star' args to convert.
02477 
02478               int nsa = (elt->fw < 0) + (elt->prec < 0);
02479 
02480               int sa_1 = 0;
02481               int sa_2 = 0;
02482 
02483               if (nsa > 0)
02484                 {
02485                   sa_1 = val_cache.int_value ();
02486 
02487                   if (! val_cache)
02488                     break;
02489                   else
02490                     {
02491                       if (nsa > 1)
02492                         {
02493                           sa_2 = val_cache.int_value ();
02494 
02495                           if (! val_cache)
02496                             break;
02497                         }
02498                     }
02499                 }
02500 
02501               const char *fmt = elt->text;
02502 
02503               if (elt->type == '%')
02504                 {
02505                   os << "%";
02506                   retval++;
02507                 }
02508               else if (elt->args == 0 && elt->text)
02509                 {
02510                   os << elt->text;
02511                   retval += strlen (elt->text);
02512                 }
02513               else if (elt->type == 's')
02514                 {
02515                   std::string val = val_cache.string_value ();
02516 
02517                   if (val_cache)
02518                     retval += do_printf_conv (os, fmt, nsa, sa_1,
02519                                               sa_2, val.c_str (), who);
02520                   else
02521                     break;
02522                 }
02523               else
02524                 {
02525                   double val = val_cache.double_value ();
02526 
02527                   if (val_cache)
02528                     {
02529                       if (lo_ieee_isnan (val) || xisinf (val))
02530                         {
02531                           std::string tfmt = fmt;
02532                           std::string::size_type i1, i2;
02533 
02534                           tfmt.replace ((i1 = tfmt.rfind (elt->type)),
02535                                         1, 1, 's');
02536 
02537                           if ((i2 = tfmt.rfind ('.')) != std::string::npos && i2 < i1)
02538                             {
02539                               tfmt.erase (i2, i1-i2);
02540                               if (elt->prec < 0)
02541                                 nsa--;
02542                             }
02543 
02544                           const char *tval = xisinf (val)
02545                             ? (val < 0 ? "-Inf" : "Inf")
02546                             : (lo_ieee_is_NA (val) ? "NA" : "NaN");
02547 
02548                           retval += do_printf_conv (os, tfmt.c_str (),
02549                                                     nsa, sa_1, sa_2,
02550                                                     tval, who);
02551                         }
02552                       else
02553                         {
02554                           char type = elt->type;
02555 
02556                           switch (type)
02557                             {
02558                             case 'd': case 'i': case 'c':
02559                               DO_DOUBLE_CONV (OCTAVE_EMPTY_CPP_ARG);
02560                               break;
02561 
02562                             case 'o': case 'x': case 'X': case 'u':
02563                               DO_DOUBLE_CONV (unsigned);
02564                               break;
02565 
02566                             case 'f': case 'e': case 'E':
02567                             case 'g': case 'G':
02568                               retval
02569                                 += do_printf_conv (os, fmt, nsa, sa_1, sa_2,
02570                                                    val, who);
02571                               break;
02572 
02573                             default:
02574                               error ("%s: invalid format specifier",
02575                                      who.c_str ());
02576                               return -1;
02577                               break;
02578                             }
02579                         }
02580                     }
02581                   else
02582                     break;
02583                 }
02584 
02585               if (! os)
02586                 {
02587                   error ("%s: write error", who.c_str ());
02588                   break;
02589                 }
02590             }
02591           else
02592             {
02593               ::error ("%s: internal error handling format", who.c_str ());
02594               retval = -1;
02595               break;
02596             }
02597 
02598           elt = fmt_list.next (nconv > 0 && ! val_cache.exhausted ());
02599 
02600           if (! elt || (val_cache.exhausted () && elt->args > 0))
02601             break;
02602         }
02603     }
02604   else
02605     invalid_operation (who, "writing");
02606 
02607   return retval;
02608 }
02609 
02610 int
02611 octave_base_stream::printf (const std::string& fmt,
02612                             const octave_value_list& args,
02613                             const std::string& who)
02614 {
02615   int retval = 0;
02616 
02617   printf_format_list fmt_list (fmt);
02618 
02619   if (fmt_list.num_conversions () == -1)
02620     ::error ("%s: invalid format specified", who.c_str ());
02621   else
02622     retval = do_printf (fmt_list, args, who);
02623 
02624   return retval;
02625 }
02626 
02627 int
02628 octave_base_stream::puts (const std::string& s, const std::string& who)
02629 {
02630   int retval = -1;
02631 
02632   std::ostream *osp = output_stream ();
02633 
02634   if (osp)
02635     {
02636       std::ostream& os = *osp;
02637 
02638       os << s;
02639 
02640       if (os)
02641         {
02642           // FIXME -- why does this seem to be necessary?
02643           // Without it, output from a loop like
02644           //
02645           //   for i = 1:100, fputs (stdout, "foo\n"); endfor
02646           //
02647           // doesn't seem to go to the pager immediately.
02648 
02649           os.flush ();
02650 
02651           if (os)
02652             retval = 0;
02653           else
02654             error ("%s: write error", who.c_str ());
02655         }
02656       else
02657         error ("%s: write error", who.c_str ());
02658     }
02659   else
02660     invalid_operation (who, "writing");
02661 
02662   return retval;
02663 }
02664 
02665 // Return current error message for this stream.
02666 
02667 std::string
02668 octave_base_stream::error (bool clear_err, int& err_num)
02669 {
02670   err_num = fail ? -1 : 0;
02671 
02672   std::string tmp = errmsg;
02673 
02674   if (clear_err)
02675     clear ();
02676 
02677   return tmp;
02678 }
02679 
02680 void
02681 octave_base_stream::invalid_operation (const std::string& who, const char *rw)
02682 {
02683   // Note that this is not ::error () !
02684 
02685   error (who, std::string ("stream not open for ") + rw);
02686 }
02687 
02688 octave_stream::octave_stream (octave_base_stream *bs)
02689   : rep (bs)
02690 {
02691   if (rep)
02692     rep->count = 1;
02693 }
02694 
02695 octave_stream::~octave_stream (void)
02696 {
02697   if (rep && --rep->count == 0)
02698     delete rep;
02699 }
02700 
02701 octave_stream::octave_stream (const octave_stream& s)
02702   : rep (s.rep)
02703 {
02704   if (rep)
02705     rep->count++;
02706 }
02707 
02708 octave_stream&
02709 octave_stream::operator = (const octave_stream& s)
02710 {
02711   if (rep != s.rep)
02712     {
02713       if (rep && --rep->count == 0)
02714         delete rep;
02715 
02716       rep = s.rep;
02717 
02718       if (rep)
02719         rep->count++;
02720     }
02721 
02722   return *this;
02723 }
02724 
02725 int
02726 octave_stream::flush (void)
02727 {
02728   int retval = -1;
02729 
02730   if (stream_ok ())
02731     retval = rep->flush ();
02732 
02733   return retval;
02734 }
02735 
02736 std::string
02737 octave_stream::getl (octave_idx_type max_len, bool& err, const std::string& who)
02738 {
02739   std::string retval;
02740 
02741   if (stream_ok ())
02742     retval = rep->getl (max_len, err, who);
02743 
02744   return retval;
02745 }
02746 
02747 std::string
02748 octave_stream::getl (const octave_value& tc_max_len, bool& err,
02749                      const std::string& who)
02750 {
02751   std::string retval;
02752 
02753   err = false;
02754 
02755   int conv_err = 0;
02756 
02757   int max_len = -1;
02758 
02759   if (tc_max_len.is_defined ())
02760     {
02761       max_len = convert_to_valid_int (tc_max_len, conv_err);
02762 
02763       if (conv_err || max_len < 0)
02764         {
02765           err = true;
02766           ::error ("%s: invalid maximum length specified", who.c_str ());
02767         }
02768     }
02769 
02770   if (! error_state)
02771     retval = getl (max_len, err, who);
02772 
02773   return retval;
02774 }
02775 
02776 std::string
02777 octave_stream::gets (octave_idx_type max_len, bool& err, const std::string& who)
02778 {
02779   std::string retval;
02780 
02781   if (stream_ok ())
02782     retval = rep->gets (max_len, err, who);
02783 
02784   return retval;
02785 }
02786 
02787 std::string
02788 octave_stream::gets (const octave_value& tc_max_len, bool& err,
02789                      const std::string& who)
02790 {
02791   std::string retval;
02792 
02793   err = false;
02794 
02795   int conv_err = 0;
02796 
02797   int max_len = -1;
02798 
02799   if (tc_max_len.is_defined ())
02800     {
02801       max_len = convert_to_valid_int (tc_max_len, conv_err);
02802 
02803       if (conv_err || max_len < 0)
02804         {
02805           err = true;
02806           ::error ("%s: invalid maximum length specified", who.c_str ());
02807         }
02808     }
02809 
02810   if (! error_state)
02811     retval = gets (max_len, err, who);
02812 
02813   return retval;
02814 }
02815 
02816 long
02817 octave_stream::skipl (long count, bool& err, const std::string& who)
02818 {
02819   long retval = -1;
02820 
02821   if (stream_ok ())
02822     retval = rep->skipl (count, err, who);
02823 
02824   return retval;
02825 }
02826 
02827 long
02828 octave_stream::skipl (const octave_value& tc_count, bool& err, const std::string& who)
02829 {
02830   long retval = -1;
02831 
02832   err = false;
02833 
02834   int conv_err = 0;
02835 
02836   int count = 1;
02837 
02838   if (tc_count.is_defined ())
02839     {
02840       if (tc_count.is_scalar_type () && xisinf (tc_count.scalar_value ()))
02841         count = -1;
02842       else
02843         {
02844           count = convert_to_valid_int (tc_count, conv_err);
02845 
02846           if (conv_err || count < 0)
02847             {
02848               err = true;
02849               ::error ("%s: invalid number of lines specified", who.c_str ());
02850             }
02851         }
02852     }
02853 
02854   if (! error_state)
02855     retval = skipl (count, err, who);
02856 
02857   return retval;
02858 }
02859 
02860 int
02861 octave_stream::seek (long offset, int origin)
02862 {
02863   int status = -1;
02864 
02865   if (stream_ok ())
02866     {
02867       clearerr ();
02868 
02869       // Find current position so we can return to it if needed.
02870 
02871       long orig_pos = rep->tell ();
02872 
02873       // Move to end of file.  If successful, find the offset of the end.
02874 
02875       status = rep->seek (0, SEEK_END);
02876 
02877       if (status == 0)
02878         {
02879           long eof_pos = rep->tell ();
02880 
02881           if (origin == SEEK_CUR)
02882             {
02883               // Move back to original position, otherwise we will be
02884               // seeking from the end of file which is probably not the
02885               // original location.
02886 
02887               rep->seek (orig_pos, SEEK_SET);
02888             }
02889 
02890           // Attempt to move to desired position; may be outside bounds
02891           // of existing file.
02892 
02893           status = rep->seek (offset, origin);
02894 
02895           if (status == 0)
02896             {
02897               // Where are we after moving to desired position?
02898 
02899               long desired_pos = rep->tell ();
02900 
02901               // I don't think save_pos can be less than zero, but we'll
02902               // check anyway...
02903 
02904               if (desired_pos > eof_pos || desired_pos < 0)
02905                 {
02906                   // Seek outside bounds of file.  Failure should leave
02907                   // position unchanged.
02908 
02909                   rep->seek (orig_pos, SEEK_SET);
02910 
02911                   status = -1;
02912                 }
02913             }
02914           else
02915             {
02916               // Seeking to the desired position failed.  Move back to
02917               // original position and return failure status.
02918 
02919               rep->seek (orig_pos, SEEK_SET);
02920 
02921               status = -1;
02922             }
02923         }
02924     }
02925 
02926   return status;
02927 }
02928 
02929 int
02930 octave_stream::seek (const octave_value& tc_offset,
02931                      const octave_value& tc_origin)
02932 {
02933   int retval = -1;
02934 
02935   long xoffset = tc_offset.long_value (true);
02936 
02937   if (! error_state)
02938     {
02939       int conv_err = 0;
02940 
02941       int origin = SEEK_SET;
02942 
02943       if (tc_origin.is_string ())
02944         {
02945           std::string xorigin = tc_origin.string_value ();
02946 
02947           if (xorigin == "bof")
02948             origin = SEEK_SET;
02949           else if (xorigin == "cof")
02950             origin = SEEK_CUR;
02951           else if (xorigin == "eof")
02952             origin = SEEK_END;
02953           else
02954             conv_err = -1;
02955         }
02956       else
02957         {
02958           int xorigin = convert_to_valid_int (tc_origin, conv_err);
02959 
02960           if (! conv_err)
02961             {
02962               if (xorigin == -1)
02963                 origin = SEEK_SET;
02964               else if (xorigin == 0)
02965                 origin = SEEK_CUR;
02966               else if (xorigin == 1)
02967                 origin = SEEK_END;
02968               else
02969                 conv_err = -1;
02970             }
02971         }
02972 
02973       if (! conv_err)
02974         {
02975           retval = seek (xoffset, origin);
02976 
02977           if (retval != 0)
02978             error ("fseek: failed to seek to requested position");
02979         }
02980       else
02981         error ("fseek: invalid value for origin");
02982     }
02983   else
02984     error ("fseek: invalid value for offset");
02985 
02986   return retval;
02987 }
02988 
02989 long
02990 octave_stream::tell (void)
02991 {
02992   long retval = -1;
02993 
02994   if (stream_ok ())
02995     retval = rep->tell ();
02996 
02997   return retval;
02998 }
02999 
03000 int
03001 octave_stream::rewind (void)
03002 {
03003   return seek (0, SEEK_SET);
03004 }
03005 
03006 bool
03007 octave_stream::is_open (void) const
03008 {
03009   bool retval = false;
03010 
03011   if (stream_ok ())
03012     retval = rep->is_open ();
03013 
03014   return retval;
03015 }
03016 
03017 void
03018 octave_stream::close (void)
03019 {
03020   if (stream_ok ())
03021     rep->close ();
03022 }
03023 
03024 template <class RET_T, class READ_T>
03025 octave_value
03026 do_read (octave_stream& strm, octave_idx_type nr, octave_idx_type nc, octave_idx_type block_size,
03027          octave_idx_type skip, bool do_float_fmt_conv, bool do_NA_conv,
03028          oct_mach_info::float_format from_flt_fmt, octave_idx_type& count)
03029 {
03030   octave_value retval;
03031 
03032   RET_T nda;
03033 
03034   count = 0;
03035 
03036   typedef typename RET_T::element_type ELMT;
03037   ELMT elt_zero = ELMT ();
03038 
03039   ELMT *dat = 0;
03040 
03041   octave_idx_type max_size = 0;
03042 
03043   octave_idx_type final_nr = 0;
03044   octave_idx_type final_nc = 1;
03045 
03046   if (nr > 0)
03047     {
03048       if (nc > 0)
03049         {
03050           nda.resize (dim_vector (nr, nc), elt_zero);
03051           dat = nda.fortran_vec ();
03052           max_size = nr * nc;
03053         }
03054       else
03055         {
03056           nda.resize (dim_vector (nr, 32), elt_zero);
03057           dat = nda.fortran_vec ();
03058           max_size = nr * 32;
03059         }
03060     }
03061   else
03062     {
03063       nda.resize (dim_vector (32, 1), elt_zero);
03064       dat = nda.fortran_vec ();
03065       max_size = 32;
03066     }
03067 
03068   // FIXME -- byte order for Cray?
03069 
03070   bool swap = false;
03071 
03072   if (oct_mach_info::words_big_endian ())
03073     swap = (from_flt_fmt == oct_mach_info::flt_fmt_ieee_little_endian
03074             || from_flt_fmt == oct_mach_info::flt_fmt_vax_g
03075             || from_flt_fmt == oct_mach_info::flt_fmt_vax_g);
03076   else
03077     swap = (from_flt_fmt == oct_mach_info::flt_fmt_ieee_big_endian);
03078 
03079   union
03080   {
03081     char buf[sizeof (typename strip_template_param<octave_int, READ_T>::type)];
03082     typename strip_template_param<octave_int, READ_T>::type val;
03083   } u;
03084 
03085   std::istream *isp = strm.input_stream ();
03086 
03087   if (isp)
03088     {
03089       std::istream& is = *isp;
03090 
03091       octave_idx_type elts_read = 0;
03092 
03093       for (;;)
03094         {
03095           // FIXME -- maybe there should be a special case for
03096           // skip == 0.
03097 
03098           if (is)
03099             {
03100               if (nr > 0 && nc > 0 && count == max_size)
03101                 {
03102                   final_nr = nr;
03103                   final_nc = nc;
03104 
03105                   break;
03106                 }
03107 
03108               is.read (u.buf, sizeof (typename strip_template_param<octave_int, READ_T>::type));
03109 
03110               // We only swap bytes for integer types.  For float
03111               // types, the format conversion will also handle byte
03112               // swapping.
03113 
03114               if (swap)
03115                 swap_bytes<sizeof (typename strip_template_param<octave_int, READ_T>::type)> (u.buf);
03116               else if (do_float_fmt_conv)
03117                 do_float_format_conversion
03118                   (u.buf,
03119                    sizeof (typename strip_template_param<octave_int, READ_T>::type),
03120                    1, from_flt_fmt, oct_mach_info::float_format ());
03121 
03122               typename RET_T::element_type tmp
03123                 = static_cast <typename RET_T::element_type> (u.val);
03124 
03125               if (is)
03126                 {
03127                   if (count == max_size)
03128                     {
03129                       max_size *= 2;
03130 
03131                       if (nr > 0)
03132                         nda.resize (dim_vector (nr, max_size / nr),
03133                                     elt_zero);
03134                       else
03135                         nda.resize (dim_vector (max_size, 1), elt_zero);
03136 
03137                       dat = nda.fortran_vec ();
03138                     }
03139 
03140                   if (do_NA_conv && __lo_ieee_is_old_NA (tmp))
03141                     tmp = __lo_ieee_replace_old_NA (tmp);
03142 
03143                   dat[count++] = tmp;
03144 
03145                   elts_read++;
03146                 }
03147 
03148               int seek_status = 0;
03149 
03150               if (skip != 0 && elts_read == block_size)
03151                 {
03152                   seek_status = strm.seek (skip, SEEK_CUR);
03153                   elts_read = 0;
03154                 }
03155 
03156               if (is.eof () || seek_status < 0)
03157                 {
03158                   if (nr > 0)
03159                     {
03160                       if (count > nr)
03161                         {
03162                           final_nr = nr;
03163                           final_nc = (count - 1) / nr + 1;
03164                         }
03165                       else
03166                         {
03167                           final_nr = count;
03168                           final_nc = 1;
03169                         }
03170                     }
03171                   else
03172                     {
03173                       final_nr = count;
03174                       final_nc = 1;
03175                     }
03176 
03177                   break;
03178                 }
03179             }
03180           else if (is.eof ())
03181             break;
03182         }
03183     }
03184 
03185   nda.resize (dim_vector (final_nr, final_nc), elt_zero);
03186 
03187   retval = nda;
03188 
03189   return retval;
03190 }
03191 
03192 #define DO_READ_VAL_TEMPLATE(RET_T, READ_T) \
03193   template octave_value \
03194   do_read<RET_T, READ_T> (octave_stream&, octave_idx_type, octave_idx_type, octave_idx_type, octave_idx_type, bool, bool, \
03195                           oct_mach_info::float_format, octave_idx_type&)
03196 
03197 // FIXME -- should we only have float if it is a different
03198 // size from double?
03199 
03200 #define INSTANTIATE_DO_READ(VAL_T) \
03201   DO_READ_VAL_TEMPLATE (VAL_T, octave_int8); \
03202   DO_READ_VAL_TEMPLATE (VAL_T, octave_uint8); \
03203   DO_READ_VAL_TEMPLATE (VAL_T, octave_int16); \
03204   DO_READ_VAL_TEMPLATE (VAL_T, octave_uint16); \
03205   DO_READ_VAL_TEMPLATE (VAL_T, octave_int32); \
03206   DO_READ_VAL_TEMPLATE (VAL_T, octave_uint32); \
03207   DO_READ_VAL_TEMPLATE (VAL_T, octave_int64); \
03208   DO_READ_VAL_TEMPLATE (VAL_T, octave_uint64); \
03209   DO_READ_VAL_TEMPLATE (VAL_T, float); \
03210   DO_READ_VAL_TEMPLATE (VAL_T, double); \
03211   DO_READ_VAL_TEMPLATE (VAL_T, char); \
03212   DO_READ_VAL_TEMPLATE (VAL_T, signed char); \
03213   DO_READ_VAL_TEMPLATE (VAL_T, unsigned char)
03214 
03215 INSTANTIATE_DO_READ (int8NDArray);
03216 INSTANTIATE_DO_READ (uint8NDArray);
03217 INSTANTIATE_DO_READ (int16NDArray);
03218 INSTANTIATE_DO_READ (uint16NDArray);
03219 INSTANTIATE_DO_READ (int32NDArray);
03220 INSTANTIATE_DO_READ (uint32NDArray);
03221 INSTANTIATE_DO_READ (int64NDArray);
03222 INSTANTIATE_DO_READ (uint64NDArray);
03223 INSTANTIATE_DO_READ (FloatNDArray);
03224 INSTANTIATE_DO_READ (NDArray);
03225 INSTANTIATE_DO_READ (charNDArray);
03226 INSTANTIATE_DO_READ (boolNDArray);
03227 
03228 typedef octave_value (*read_fptr) (octave_stream&, octave_idx_type, octave_idx_type, octave_idx_type, octave_idx_type, bool, bool,
03229                                    oct_mach_info::float_format ffmt, octave_idx_type&);
03230 
03231 #define FILL_TABLE_ROW(R, VAL_T) \
03232   read_fptr_table[R][oct_data_conv::dt_int8] = do_read<VAL_T, octave_int8>; \
03233   read_fptr_table[R][oct_data_conv::dt_uint8] = do_read<VAL_T, octave_uint8>; \
03234   read_fptr_table[R][oct_data_conv::dt_int16] = do_read<VAL_T, octave_int16>; \
03235   read_fptr_table[R][oct_data_conv::dt_uint16] = do_read<VAL_T, octave_uint16>; \
03236   read_fptr_table[R][oct_data_conv::dt_int32] = do_read<VAL_T, octave_int32>; \
03237   read_fptr_table[R][oct_data_conv::dt_uint32] = do_read<VAL_T, octave_uint32>; \
03238   read_fptr_table[R][oct_data_conv::dt_int64] = do_read<VAL_T, octave_int64>; \
03239   read_fptr_table[R][oct_data_conv::dt_uint64] = do_read<VAL_T, octave_uint64>; \
03240   read_fptr_table[R][oct_data_conv::dt_single] = do_read<VAL_T, float>; \
03241   read_fptr_table[R][oct_data_conv::dt_double] = do_read<VAL_T, double>; \
03242   read_fptr_table[R][oct_data_conv::dt_char] = do_read<VAL_T, char>; \
03243   read_fptr_table[R][oct_data_conv::dt_schar] = do_read<VAL_T, signed char>; \
03244   read_fptr_table[R][oct_data_conv::dt_uchar] = do_read<VAL_T, unsigned char>; \
03245   read_fptr_table[R][oct_data_conv::dt_logical] = do_read<VAL_T, unsigned char>
03246 
03247 octave_value
03248 octave_stream::read (const Array<double>& size, octave_idx_type block_size,
03249                      oct_data_conv::data_type input_type,
03250                      oct_data_conv::data_type output_type,
03251                      octave_idx_type skip, oct_mach_info::float_format ffmt,
03252                      octave_idx_type& char_count)
03253 {
03254   static bool initialized = false;
03255 
03256   // Table function pointers for return types x read types.
03257 
03258   static read_fptr read_fptr_table[oct_data_conv::dt_unknown][14];
03259 
03260   if (! initialized)
03261     {
03262       for (int i = 0; i < oct_data_conv::dt_unknown; i++)
03263         for (int j = 0; j < 14; j++)
03264           read_fptr_table[i][j] = 0;
03265 
03266       FILL_TABLE_ROW (oct_data_conv::dt_int8, int8NDArray);
03267       FILL_TABLE_ROW (oct_data_conv::dt_uint8, uint8NDArray);
03268       FILL_TABLE_ROW (oct_data_conv::dt_int16, int16NDArray);
03269       FILL_TABLE_ROW (oct_data_conv::dt_uint16, uint16NDArray);
03270       FILL_TABLE_ROW (oct_data_conv::dt_int32, int32NDArray);
03271       FILL_TABLE_ROW (oct_data_conv::dt_uint32, uint32NDArray);
03272       FILL_TABLE_ROW (oct_data_conv::dt_int64, int64NDArray);
03273       FILL_TABLE_ROW (oct_data_conv::dt_uint64, uint64NDArray);
03274       FILL_TABLE_ROW (oct_data_conv::dt_single, FloatNDArray);
03275       FILL_TABLE_ROW (oct_data_conv::dt_double, NDArray);
03276       FILL_TABLE_ROW (oct_data_conv::dt_char, charNDArray);
03277       FILL_TABLE_ROW (oct_data_conv::dt_schar, charNDArray);
03278       FILL_TABLE_ROW (oct_data_conv::dt_uchar, charNDArray);
03279       FILL_TABLE_ROW (oct_data_conv::dt_logical, boolNDArray);
03280 
03281       initialized = true;
03282     }
03283 
03284   octave_value retval;
03285 
03286   if (stream_ok ())
03287     {
03288       // FIXME -- we may eventually want to make this extensible.
03289 
03290       // FIXME -- we need a better way to ensure that this
03291       // numbering stays consistent with the order of the elements in the
03292       // data_type enum in the oct_data_conv class.
03293 
03294       char_count = 0;
03295 
03296       octave_idx_type nr = -1;
03297       octave_idx_type nc = -1;
03298 
03299       bool ignore;
03300 
03301       get_size (size, nr, nc, ignore, "fread");
03302 
03303       if (! error_state)
03304         {
03305           if (nr == 0 || nc == 0)
03306             retval = Matrix (nr, nc);
03307           else
03308             {
03309               if (ffmt == oct_mach_info::flt_fmt_unknown)
03310                 ffmt = float_format ();
03311 
03312               read_fptr fcn = read_fptr_table[output_type][input_type];
03313 
03314               bool do_float_fmt_conv = ((input_type == oct_data_conv::dt_double
03315                                          || input_type == oct_data_conv::dt_single)
03316                                         && ffmt != float_format ());
03317 
03318               bool do_NA_conv = (output_type == oct_data_conv::dt_double);
03319 
03320               if (fcn)
03321                 {
03322                   retval = (*fcn) (*this, nr, nc, block_size, skip,
03323                                    do_float_fmt_conv, do_NA_conv,
03324                                    ffmt, char_count);
03325 
03326                   // FIXME -- kluge!
03327 
03328                   if (! error_state
03329                       && (output_type == oct_data_conv::dt_char
03330                           || output_type == oct_data_conv::dt_schar
03331                           || output_type == oct_data_conv::dt_uchar))
03332                     retval = retval.char_matrix_value ();
03333                 }
03334               else
03335                 error ("fread: unable to read and convert requested types");
03336             }
03337         }
03338       else
03339         invalid_operation ("fread", "reading");
03340     }
03341 
03342   return retval;
03343 }
03344 
03345 octave_idx_type
03346 octave_stream::write (const octave_value& data, octave_idx_type block_size,
03347                       oct_data_conv::data_type output_type, octave_idx_type skip,
03348                       oct_mach_info::float_format flt_fmt)
03349 {
03350   octave_idx_type retval = -1;
03351 
03352   if (stream_ok ())
03353     {
03354       if (! error_state)
03355         {
03356           if (flt_fmt == oct_mach_info::flt_fmt_unknown)
03357             flt_fmt = float_format ();
03358 
03359           octave_idx_type status = data.write (*this, block_size, output_type,
03360                                    skip, flt_fmt);
03361 
03362           if (status < 0)
03363             error ("fwrite: write error");
03364           else
03365             retval = status;
03366         }
03367       else
03368         invalid_operation ("fwrite", "writing");
03369     }
03370 
03371   return retval;
03372 }
03373 
03374 template <class T>
03375 void
03376 write_int (std::ostream& os, bool swap, const T& val)
03377 {
03378   typename T::val_type tmp = val.value ();
03379 
03380   if (swap)
03381     swap_bytes<sizeof (typename T::val_type)> (&tmp);
03382 
03383   os.write (reinterpret_cast<const char *> (&tmp),
03384             sizeof (typename T::val_type));
03385 }
03386 
03387 template void write_int (std::ostream&, bool, const octave_int8&);
03388 template void write_int (std::ostream&, bool, const octave_uint8&);
03389 template void write_int (std::ostream&, bool, const octave_int16&);
03390 template void write_int (std::ostream&, bool, const octave_uint16&);
03391 template void write_int (std::ostream&, bool, const octave_int32&);
03392 template void write_int (std::ostream&, bool, const octave_uint32&);
03393 template void write_int (std::ostream&, bool, const octave_int64&);
03394 template void write_int (std::ostream&, bool, const octave_uint64&);
03395 
03396 template <class T>
03397 static inline bool
03398 do_write (std::ostream& os, const T& val, oct_data_conv::data_type output_type,
03399           oct_mach_info::float_format flt_fmt, bool swap,
03400           bool do_float_conversion)
03401 {
03402   bool retval = true;
03403 
03404   // For compatibility, Octave converts to the output type, then
03405   // writes.  This means that truncation happens on the conversion.
03406   // For example, the following program prints 0:
03407   //
03408   //   x = int8 (-1)
03409   //   f = fopen ("foo.dat", "w");
03410   //   fwrite (f, x, "unsigned char");
03411   //   fclose (f);
03412   //   f = fopen ("foo.dat", "r");
03413   //   y = fread (f, 1, "unsigned char");
03414   //   printf ("%d\n", y);
03415 
03416   switch (output_type)
03417     {
03418     case oct_data_conv::dt_char:
03419     case oct_data_conv::dt_schar:
03420     case oct_data_conv::dt_int8:
03421       write_int (os, swap, octave_int8 (val));
03422       break;
03423 
03424     case oct_data_conv::dt_uchar:
03425     case oct_data_conv::dt_uint8:
03426       write_int (os, swap, octave_uint8 (val));
03427       break;
03428 
03429     case oct_data_conv::dt_int16:
03430       write_int (os, swap, octave_int16 (val));
03431       break;
03432 
03433     case oct_data_conv::dt_uint16:
03434       write_int (os, swap, octave_uint16 (val));
03435       break;
03436 
03437     case oct_data_conv::dt_int32:
03438       write_int (os, swap, octave_int32 (val));
03439       break;
03440 
03441     case oct_data_conv::dt_uint32:
03442       write_int (os, swap, octave_uint32 (val));
03443       break;
03444 
03445     case oct_data_conv::dt_int64:
03446       write_int (os, swap, octave_int64 (val));
03447       break;
03448 
03449     case oct_data_conv::dt_uint64:
03450       write_int (os, swap, octave_uint64 (val));
03451       break;
03452 
03453     case oct_data_conv::dt_single:
03454       {
03455         float f = static_cast<float> (val);
03456 
03457         if (do_float_conversion)
03458           do_float_format_conversion (&f, 1, flt_fmt);
03459 
03460         os.write (reinterpret_cast<const char *> (&f), sizeof (float));
03461       }
03462       break;
03463 
03464     case oct_data_conv::dt_double:
03465       {
03466         double d = static_cast<double> (val);
03467         if (do_float_conversion)
03468           do_double_format_conversion (&d, 1, flt_fmt);
03469 
03470         os.write (reinterpret_cast<const char *> (&d), sizeof (double));
03471       }
03472       break;
03473 
03474     default:
03475       retval = false;
03476       (*current_liboctave_error_handler)
03477         ("write: invalid type specification");
03478       break;
03479     }
03480 
03481   return retval;
03482 }
03483 
03484 template bool
03485 do_write (std::ostream&, const octave_int8&, oct_data_conv::data_type,
03486           oct_mach_info::float_format, bool, bool);
03487 
03488 template bool
03489 do_write (std::ostream&, const octave_uint8&, oct_data_conv::data_type,
03490           oct_mach_info::float_format, bool, bool);
03491 
03492 template bool
03493 do_write (std::ostream&, const octave_int16&, oct_data_conv::data_type,
03494           oct_mach_info::float_format, bool, bool);
03495 
03496 template bool
03497 do_write (std::ostream&, const octave_uint16&, oct_data_conv::data_type,
03498           oct_mach_info::float_format, bool, bool);
03499 
03500 template bool
03501 do_write (std::ostream&, const octave_int32&, oct_data_conv::data_type,
03502           oct_mach_info::float_format, bool, bool);
03503 
03504 template bool
03505 do_write (std::ostream&, const octave_uint32&, oct_data_conv::data_type,
03506           oct_mach_info::float_format, bool, bool);
03507 
03508 template bool
03509 do_write (std::ostream&, const octave_int64&, oct_data_conv::data_type,
03510           oct_mach_info::float_format, bool, bool);
03511 
03512 template bool
03513 do_write (std::ostream&, const octave_uint64&, oct_data_conv::data_type,
03514           oct_mach_info::float_format, bool, bool);
03515 
03516 template <class T>
03517 octave_idx_type
03518 octave_stream::write (const Array<T>& data, octave_idx_type block_size,
03519                       oct_data_conv::data_type output_type,
03520                       octave_idx_type skip, oct_mach_info::float_format flt_fmt)
03521 {
03522   octave_idx_type retval = -1;
03523 
03524   bool status = true;
03525 
03526   octave_idx_type count = 0;
03527 
03528   const T *d = data.data ();
03529 
03530   octave_idx_type n = data.length ();
03531 
03532   oct_mach_info::float_format native_flt_fmt
03533     = oct_mach_info::float_format ();
03534 
03535   bool do_float_conversion = (flt_fmt != native_flt_fmt);
03536 
03537   // FIXME -- byte order for Cray?
03538 
03539   bool swap = false;
03540 
03541   if (oct_mach_info::words_big_endian ())
03542     swap = (flt_fmt == oct_mach_info::flt_fmt_ieee_little_endian
03543             || flt_fmt == oct_mach_info::flt_fmt_vax_g
03544             || flt_fmt == oct_mach_info::flt_fmt_vax_g);
03545   else
03546     swap = (flt_fmt == oct_mach_info::flt_fmt_ieee_big_endian);
03547 
03548   for (octave_idx_type i = 0; i < n; i++)
03549     {
03550       std::ostream *osp = output_stream ();
03551 
03552       if (osp)
03553         {
03554           std::ostream& os = *osp;
03555 
03556           if (skip != 0 && (i % block_size) == 0)
03557             {
03558               // Seek to skip when inside bounds of existing file.
03559               // Otherwise, write NUL to skip.
03560 
03561               long orig_pos = tell ();
03562 
03563               seek (0, SEEK_END);
03564 
03565               long eof_pos = tell ();
03566 
03567               // Is it possible for this to fail to return us to the
03568               // original position?
03569               seek (orig_pos, SEEK_SET);
03570 
03571               long remaining = eof_pos - orig_pos;
03572 
03573               if (remaining < skip)
03574                 {
03575                   seek (0, SEEK_END);
03576 
03577                   // FIXME -- probably should try to write larger
03578                   // blocks...
03579 
03580                   unsigned char zero = 0;
03581                   for (octave_idx_type j = 0; j < skip - remaining; j++)
03582                     os.write (reinterpret_cast<const char *> (&zero), 1);
03583                 }
03584               else
03585                 seek (skip, SEEK_CUR);
03586             }
03587 
03588           if (os)
03589             {
03590               status = do_write (os, d[i], output_type, flt_fmt, swap,
03591                                  do_float_conversion);
03592 
03593               if (os && status)
03594                 count++;
03595               else
03596                 break;
03597             }
03598           else
03599             {
03600               status = false;
03601               break;
03602             }
03603         }
03604       else
03605         {
03606           status = false;
03607           break;
03608         }
03609     }
03610 
03611   if (status)
03612     retval = count;
03613 
03614   return retval;
03615 }
03616 
03617 template octave_idx_type
03618 octave_stream::write (const Array<char>&, octave_idx_type,
03619                       oct_data_conv::data_type,
03620                       octave_idx_type, oct_mach_info::float_format);
03621 
03622 template octave_idx_type
03623 octave_stream::write (const Array<bool>&, octave_idx_type,
03624                       oct_data_conv::data_type,
03625                       octave_idx_type, oct_mach_info::float_format);
03626 
03627 template octave_idx_type
03628 octave_stream::write (const Array<double>&, octave_idx_type,
03629                       oct_data_conv::data_type,
03630                       octave_idx_type, oct_mach_info::float_format);
03631 
03632 template octave_idx_type
03633 octave_stream::write (const Array<float>&, octave_idx_type,
03634                       oct_data_conv::data_type,
03635                       octave_idx_type, oct_mach_info::float_format);
03636 
03637 template octave_idx_type
03638 octave_stream::write (const Array<octave_int8>&, octave_idx_type,
03639                       oct_data_conv::data_type,
03640                       octave_idx_type, oct_mach_info::float_format);
03641 
03642 template octave_idx_type
03643 octave_stream::write (const Array<octave_uint8>&, octave_idx_type,
03644                       oct_data_conv::data_type,
03645                       octave_idx_type, oct_mach_info::float_format);
03646 
03647 template octave_idx_type
03648 octave_stream::write (const Array<octave_int16>&, octave_idx_type,
03649                       oct_data_conv::data_type,
03650                       octave_idx_type, oct_mach_info::float_format);
03651 
03652 template octave_idx_type
03653 octave_stream::write (const Array<octave_uint16>&, octave_idx_type,
03654                       oct_data_conv::data_type,
03655                       octave_idx_type, oct_mach_info::float_format);
03656 
03657 template octave_idx_type
03658 octave_stream::write (const Array<octave_int32>&, octave_idx_type,
03659                       oct_data_conv::data_type,
03660                       octave_idx_type, oct_mach_info::float_format);
03661 
03662 template octave_idx_type
03663 octave_stream::write (const Array<octave_uint32>&, octave_idx_type,
03664                       oct_data_conv::data_type,
03665                       octave_idx_type, oct_mach_info::float_format);
03666 
03667 template octave_idx_type
03668 octave_stream::write (const Array<octave_int64>&, octave_idx_type,
03669                       oct_data_conv::data_type,
03670                       octave_idx_type, oct_mach_info::float_format);
03671 
03672 template octave_idx_type
03673 octave_stream::write (const Array<octave_uint64>&, octave_idx_type,
03674                       oct_data_conv::data_type,
03675                       octave_idx_type, oct_mach_info::float_format);
03676 
03677 octave_value
03678 octave_stream::scanf (const std::string& fmt, const Array<double>& size,
03679                       octave_idx_type& count, const std::string& who)
03680 {
03681   octave_value retval;
03682 
03683   if (stream_ok ())
03684     retval = rep->scanf (fmt, size, count, who);
03685 
03686   return retval;
03687 }
03688 
03689 octave_value
03690 octave_stream::scanf (const octave_value& fmt, const Array<double>& size,
03691                       octave_idx_type& count, const std::string& who)
03692 {
03693   octave_value retval = Matrix ();
03694 
03695   if (fmt.is_string ())
03696     {
03697       std::string sfmt = fmt.string_value ();
03698 
03699       if (fmt.is_sq_string ())
03700         sfmt = do_string_escapes (sfmt);
03701 
03702       retval = scanf (sfmt, size, count, who);
03703     }
03704   else
03705     {
03706       // Note that this is not ::error () !
03707 
03708       error (who + ": format must be a string");
03709     }
03710 
03711   return retval;
03712 }
03713 
03714 octave_value_list
03715 octave_stream::oscanf (const std::string& fmt, const std::string& who)
03716 {
03717   octave_value_list retval;
03718 
03719   if (stream_ok ())
03720     retval = rep->oscanf (fmt, who);
03721 
03722   return retval;
03723 }
03724 
03725 octave_value_list
03726 octave_stream::oscanf (const octave_value& fmt, const std::string& who)
03727 {
03728   octave_value_list retval;
03729 
03730   if (fmt.is_string ())
03731     {
03732       std::string sfmt = fmt.string_value ();
03733 
03734       if (fmt.is_sq_string ())
03735         sfmt = do_string_escapes (sfmt);
03736 
03737       retval = oscanf (sfmt, who);
03738     }
03739   else
03740     {
03741       // Note that this is not ::error () !
03742 
03743       error (who + ": format must be a string");
03744     }
03745 
03746   return retval;
03747 }
03748 
03749 int
03750 octave_stream::printf (const std::string& fmt, const octave_value_list& args,
03751                        const std::string& who)
03752 {
03753   int retval = -1;
03754 
03755   if (stream_ok ())
03756     retval = rep->printf (fmt, args, who);
03757 
03758   return retval;
03759 }
03760 
03761 int
03762 octave_stream::printf (const octave_value& fmt, const octave_value_list& args,
03763                        const std::string& who)
03764 {
03765   int retval = 0;
03766 
03767   if (fmt.is_string ())
03768     {
03769       std::string sfmt = fmt.string_value ();
03770 
03771       if (fmt.is_sq_string ())
03772         sfmt = do_string_escapes (sfmt);
03773 
03774       retval = printf (sfmt, args, who);
03775     }
03776   else
03777     {
03778       // Note that this is not ::error () !
03779 
03780       error (who + ": format must be a string");
03781     }
03782 
03783   return retval;
03784 }
03785 
03786 int
03787 octave_stream::puts (const std::string& s, const std::string& who)
03788 {
03789   int retval = -1;
03790 
03791   if (stream_ok ())
03792     retval = rep->puts (s, who);
03793 
03794   return retval;
03795 }
03796 
03797 // FIXME -- maybe this should work for string arrays too.
03798 
03799 int
03800 octave_stream::puts (const octave_value& tc_s, const std::string& who)
03801 {
03802   int retval = -1;
03803 
03804   if (tc_s.is_string ())
03805     {
03806       std::string s = tc_s.string_value ();
03807       retval = puts (s, who);
03808     }
03809   else
03810     {
03811       // Note that this is not ::error () !
03812 
03813       error (who + ": argument must be a string");
03814     }
03815 
03816   return retval;
03817 }
03818 
03819 bool
03820 octave_stream::eof (void) const
03821 {
03822   int retval = -1;
03823 
03824   if (stream_ok ())
03825     retval = rep->eof ();
03826 
03827   return retval;
03828 }
03829 
03830 std::string
03831 octave_stream::error (bool clear, int& err_num)
03832 {
03833   std::string retval = "invalid stream object";
03834 
03835   if (stream_ok (false))
03836     retval = rep->error (clear, err_num);
03837 
03838   return retval;
03839 }
03840 
03841 std::string
03842 octave_stream::name (void) const
03843 {
03844   std::string retval;
03845 
03846   if (stream_ok ())
03847     retval = rep->name ();
03848 
03849   return retval;
03850 }
03851 
03852 int
03853 octave_stream::mode (void) const
03854 {
03855   int retval = 0;
03856 
03857   if (stream_ok ())
03858     retval = rep->mode ();
03859 
03860   return retval;
03861 }
03862 
03863 oct_mach_info::float_format
03864 octave_stream::float_format (void) const
03865 {
03866   oct_mach_info::float_format retval = oct_mach_info::flt_fmt_unknown;
03867 
03868   if (stream_ok ())
03869     retval = rep->float_format ();
03870 
03871   return retval;
03872 }
03873 
03874 std::string
03875 octave_stream::mode_as_string (int mode)
03876 {
03877   std::string retval = "???";
03878   std::ios::openmode in_mode = static_cast<std::ios::openmode> (mode);
03879 
03880   if (in_mode == std::ios::in)
03881     retval = "r";
03882   else if (in_mode == std::ios::out
03883            || in_mode == (std::ios::out | std::ios::trunc))
03884     retval = "w";
03885   else if (in_mode == (std::ios::out | std::ios::app))
03886     retval = "a";
03887   else if (in_mode == (std::ios::in | std::ios::out))
03888     retval = "r+";
03889   else if (in_mode == (std::ios::in | std::ios::out | std::ios::trunc))
03890     retval = "w+";
03891   else if (in_mode == (std::ios::in | std::ios::out | std::ios::ate))
03892     retval = "a+";
03893   else if (in_mode == (std::ios::in | std::ios::binary))
03894     retval = "rb";
03895   else if (in_mode == (std::ios::out | std::ios::binary)
03896            || in_mode == (std::ios::out | std::ios::trunc | std::ios::binary))
03897     retval = "wb";
03898   else if (in_mode == (std::ios::out | std::ios::app | std::ios::binary))
03899     retval = "ab";
03900   else if (in_mode == (std::ios::in | std::ios::out | std::ios::binary))
03901     retval = "r+b";
03902   else if (in_mode == (std::ios::in | std::ios::out | std::ios::trunc
03903                        | std::ios::binary))
03904     retval = "w+b";
03905   else if (in_mode == (std::ios::in | std::ios::out | std::ios::ate
03906                        | std::ios::binary))
03907     retval = "a+b";
03908 
03909   return retval;
03910 }
03911 
03912 octave_stream_list *octave_stream_list::instance = 0;
03913 
03914 bool
03915 octave_stream_list::instance_ok (void)
03916 {
03917   bool retval = true;
03918 
03919   if (! instance)
03920     {
03921       instance = new octave_stream_list ();
03922 
03923       if (instance)
03924         singleton_cleanup_list::add (cleanup_instance);
03925     }
03926 
03927   if (! instance)
03928     {
03929       ::error ("unable to create stream list object!");
03930 
03931       retval = false;
03932     }
03933 
03934   return retval;
03935 }
03936 
03937 int
03938 octave_stream_list::insert (octave_stream& os)
03939 {
03940   return (instance_ok ()) ? instance->do_insert (os) : -1;
03941 }
03942 
03943 octave_stream
03944 octave_stream_list::lookup (int fid, const std::string& who)
03945 {
03946   return (instance_ok ()) ? instance->do_lookup (fid, who) : octave_stream ();
03947 }
03948 
03949 octave_stream
03950 octave_stream_list::lookup (const octave_value& fid, const std::string& who)
03951 {
03952   return (instance_ok ()) ? instance->do_lookup (fid, who) : octave_stream ();
03953 }
03954 
03955 int
03956 octave_stream_list::remove (int fid, const std::string& who)
03957 {
03958   return (instance_ok ()) ? instance->do_remove (fid, who) : -1;
03959 }
03960 
03961 int
03962 octave_stream_list::remove (const octave_value& fid, const std::string& who)
03963 {
03964   return (instance_ok ()) ? instance->do_remove (fid, who) : -1;
03965 }
03966 
03967 void
03968 octave_stream_list::clear (bool flush)
03969 {
03970   if (instance)
03971     instance->do_clear (flush);
03972 }
03973 
03974 string_vector
03975 octave_stream_list::get_info (int fid)
03976 {
03977   return (instance_ok ()) ? instance->do_get_info (fid) : string_vector ();
03978 }
03979 
03980 string_vector
03981 octave_stream_list::get_info (const octave_value& fid)
03982 {
03983   return (instance_ok ()) ? instance->do_get_info (fid) : string_vector ();
03984 }
03985 
03986 std::string
03987 octave_stream_list::list_open_files (void)
03988 {
03989   return (instance_ok ()) ? instance->do_list_open_files () : std::string ();
03990 }
03991 
03992 octave_value
03993 octave_stream_list::open_file_numbers (void)
03994 {
03995   return (instance_ok ())
03996     ? instance->do_open_file_numbers () : octave_value ();
03997 }
03998 
03999 int
04000 octave_stream_list::get_file_number (const octave_value& fid)
04001 {
04002   return (instance_ok ()) ? instance->do_get_file_number (fid) : -1;
04003 }
04004 
04005 int
04006 octave_stream_list::do_insert (octave_stream& os)
04007 {
04008   // Insert item with key corresponding to file-descriptor.
04009 
04010   int stream_number;
04011 
04012   if ((stream_number = os.file_number ()) == -1)
04013     return stream_number;
04014 
04015   // Should we test for "(list.find (stream_number) != list.end ()) &&
04016   // list[stream_number].is_open ()" and respond with "error
04017   // ("internal error: ...")"? It should not happen except for some
04018   // bug or if the user has opened a stream with an interpreted
04019   // command, but closed it directly with a system call in an
04020   // oct-file; then the kernel knows the fd is free, but Octave does
04021   // not know. If it happens, it should not do harm here to simply
04022   // overwrite this entry, although the wrong entry might have done
04023   // harm before.
04024 
04025   if (list.size () < list.max_size ())
04026     list[stream_number] = os;
04027   else
04028     {
04029       stream_number = -1;
04030       error ("could not create file id");
04031     }
04032 
04033   return stream_number;
04034 
04035 }
04036 
04037 static void
04038 gripe_invalid_file_id (int fid, const std::string& who)
04039 {
04040   if (who.empty ())
04041     ::error ("invalid stream number = %d", fid);
04042   else
04043     ::error ("%s: invalid stream number = %d", who.c_str (), fid);
04044 }
04045 
04046 octave_stream
04047 octave_stream_list::do_lookup (int fid, const std::string& who) const
04048 {
04049   octave_stream retval;
04050 
04051   if (fid >= 0)
04052     {
04053       if (lookup_cache != list.end () && lookup_cache->first == fid)
04054         retval = lookup_cache->second;
04055       else
04056         {
04057           ostrl_map::const_iterator iter = list.find (fid);
04058 
04059           if (iter != list.end ())
04060             {
04061               retval = iter->second;
04062               lookup_cache = iter;
04063             }
04064           else
04065             gripe_invalid_file_id (fid, who);
04066         }
04067     }
04068   else
04069     gripe_invalid_file_id (fid, who);
04070 
04071   return retval;
04072 }
04073 
04074 octave_stream
04075 octave_stream_list::do_lookup (const octave_value& fid,
04076                                const std::string& who) const
04077 {
04078   octave_stream retval;
04079 
04080   int i = get_file_number (fid);
04081 
04082   if (! error_state)
04083     retval = do_lookup (i, who);
04084 
04085   return retval;
04086 }
04087 
04088 int
04089 octave_stream_list::do_remove (int fid, const std::string& who)
04090 {
04091   int retval = -1;
04092 
04093   // Can't remove stdin (std::cin), stdout (std::cout), or stderr
04094   // (std::cerr).
04095 
04096   if (fid > 2)
04097     {
04098       ostrl_map::iterator iter = list.find (fid);
04099 
04100       if (iter != list.end ())
04101         {
04102           octave_stream os = iter->second;
04103           list.erase (iter);
04104           lookup_cache = list.end ();
04105 
04106           // FIXME: is this check redundant?
04107           if (os.is_valid ())
04108             {
04109               os.close ();
04110               retval = 0;
04111             }
04112           else
04113             gripe_invalid_file_id (fid, who);
04114         }
04115       else
04116         gripe_invalid_file_id (fid, who);
04117     }
04118   else
04119     gripe_invalid_file_id (fid, who);
04120 
04121   return retval;
04122 }
04123 
04124 int
04125 octave_stream_list::do_remove (const octave_value& fid, const std::string& who)
04126 {
04127   int retval = -1;
04128 
04129   if (fid.is_string () && fid.string_value () == "all")
04130     {
04131       do_clear (false);
04132 
04133       retval = 0;
04134     }
04135   else
04136     {
04137       int i = get_file_number (fid);
04138 
04139       if (! error_state)
04140         retval = do_remove (i, who);
04141     }
04142 
04143   return retval;
04144 }
04145 
04146 void
04147 octave_stream_list::do_clear (bool flush)
04148 {
04149   if (flush)
04150     {
04151       // Do flush stdout and stderr.
04152 
04153       list[0].flush ();
04154       list[1].flush ();
04155     }
04156 
04157   octave_stream saved_os[3];
04158   // But don't delete them or stdin.
04159   for (ostrl_map::iterator iter = list.begin (); iter != list.end (); iter++)
04160     {
04161       int fid = iter->first;
04162       octave_stream os = iter->second;
04163       if (fid < 3)
04164         saved_os[fid] = os;
04165       else if (os.is_valid ())
04166         os.close ();
04167     }
04168   list.clear ();
04169   for (int fid = 0; fid < 3; fid++) list[fid] = saved_os[fid];
04170   lookup_cache = list.end ();
04171 }
04172 
04173 string_vector
04174 octave_stream_list::do_get_info (int fid) const
04175 {
04176   string_vector retval;
04177 
04178   octave_stream os = do_lookup (fid);
04179 
04180   if (os.is_valid ())
04181     {
04182       retval.resize (3);
04183 
04184       retval(2) = oct_mach_info::float_format_as_string (os.float_format ());
04185       retval(1) = octave_stream::mode_as_string (os.mode ());
04186       retval(0) = os.name ();
04187     }
04188   else
04189     ::error ("invalid file id = %d", fid);
04190 
04191   return retval;
04192 }
04193 
04194 string_vector
04195 octave_stream_list::do_get_info (const octave_value& fid) const
04196 {
04197   string_vector retval;
04198 
04199   int conv_err = 0;
04200 
04201   int int_fid = convert_to_valid_int (fid, conv_err);
04202 
04203   if (! conv_err)
04204     retval = do_get_info (int_fid);
04205   else
04206     ::error ("file id must be a file object or integer value");
04207 
04208   return retval;
04209 }
04210 
04211 std::string
04212 octave_stream_list::do_list_open_files (void) const
04213 {
04214   std::string retval;
04215 
04216   std::ostringstream buf;
04217 
04218   buf << "\n"
04219       << "  number  mode  arch       name\n"
04220       << "  ------  ----  ----       ----\n";
04221 
04222   for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++)
04223     {
04224       octave_stream os = p->second;
04225 
04226       buf << "  "
04227           << std::setiosflags (std::ios::right)
04228           << std::setw (4) << p->first << "     "
04229           << std::setiosflags (std::ios::left)
04230           << std::setw (3)
04231           << octave_stream::mode_as_string (os.mode ())
04232           << "  "
04233           << std::setw (9)
04234           << oct_mach_info::float_format_as_string (os.float_format ())
04235           << "  "
04236           << os.name () << "\n";
04237     }
04238 
04239   buf << "\n";
04240 
04241   retval = buf.str ();
04242 
04243   return retval;
04244 }
04245 
04246 octave_value
04247 octave_stream_list::do_open_file_numbers (void) const
04248 {
04249   Matrix retval (1, list.size (), 0.0);
04250 
04251   int num_open = 0;
04252 
04253   for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++)
04254     {
04255       // Skip stdin, stdout, and stderr.
04256 
04257       if (p->first > 2 && p->second)
04258         retval(0,num_open++) = p->first;
04259     }
04260 
04261   retval.resize ((num_open > 0), num_open);
04262 
04263   return retval;
04264 }
04265 
04266 int
04267 octave_stream_list::do_get_file_number (const octave_value& fid) const
04268 {
04269   int retval = -1;
04270 
04271   if (fid.is_string ())
04272     {
04273       std::string nm = fid.string_value ();
04274 
04275       for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++)
04276         {
04277           // stdin (std::cin), stdout (std::cout), and stderr (std::cerr)
04278           // are unnamed.
04279 
04280           if (p->first > 2)
04281             {
04282               octave_stream os = p->second;
04283 
04284               if (os && os.name () == nm)
04285                 {
04286                   retval = p->first;
04287                   break;
04288                 }
04289             }
04290         }
04291     }
04292   else
04293     {
04294       int conv_err = 0;
04295 
04296       int int_fid = convert_to_valid_int (fid, conv_err);
04297 
04298       if (conv_err)
04299         ::error ("file id must be a file object, std::string, or integer value");
04300       else
04301         retval = int_fid;
04302     }
04303 
04304   return retval;
04305 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines