home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / octave-1.1.1p1-src.tgz / tar.out / fsf / octave / src / file-io.cc < prev    next >
C/C++ Source or Header  |  1996-09-28  |  37KB  |  1,893 lines

  1. // file-io.cc                                             -*- C++ -*-
  2. /*
  3.  
  4. Copyright (C) 1993, 1994, 1995 John W. Eaton
  5.  
  6. This file is part of Octave.
  7.  
  8. Octave is free software; you can redistribute it and/or modify it
  9. under the terms of the GNU General Public License as published by the
  10. Free Software Foundation; either version 2, or (at your option) any
  11. later version.
  12.  
  13. Octave is distributed in the hope that it will be useful, but WITHOUT
  14. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with Octave; see the file COPYING.  If not, write to the Free
  20. Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22. */
  23.  
  24. // Written by John C. Campbell <jcc@che.utexas.edu>.
  25.  
  26. #ifdef HAVE_CONFIG_H
  27. #include "config.h"
  28. #endif
  29.  
  30. #include <DLList.h>
  31. #include <unistd.h>
  32. #include <string.h>
  33. #include <stdio.h>
  34. #include <errno.h>
  35. #include <stdlib.h>
  36. #include <strstream.h>
  37. #include <ctype.h>
  38.  
  39. #include "dMatrix.h"
  40.  
  41. #include "statdefs.h"
  42. #include "file-io.h"
  43. #include "input.h"
  44. #include "octave-hist.h"
  45. #include "tree-const.h"
  46. #include "error.h"
  47. #include "help.h"
  48. #include "utils.h"
  49. #include "pager.h"
  50. #include "defun.h"
  51. #include "sysdep.h"
  52. #include "mappers.h"
  53. #include "variables.h"
  54.  
  55. // keeps a count of args sent to printf or scanf
  56. static int fmt_arg_count = 0;
  57.  
  58. // double linked list containing relevant information about open files
  59. static DLList <file_info> file_list;
  60.  
  61. file_info::file_info (void)
  62. {
  63.   file_number = -1;
  64.   file_name = 0;
  65.   file_fptr = 0;
  66.   file_mode = 0;
  67. }
  68.  
  69. file_info::file_info (int n, const char *nm, FILE *t, const char *md)
  70. {
  71.   file_number = n;
  72.   file_name = strsave (nm);
  73.   file_fptr = t;
  74.   file_mode = strsave (md);
  75. }
  76.  
  77. file_info::file_info (const file_info& f)
  78. {
  79.   file_number = f.file_number;
  80.   file_name = strsave (f.file_name);
  81.   file_fptr = f.file_fptr;
  82.   file_mode = strsave (f.file_mode);
  83. }
  84.  
  85. file_info&
  86. file_info::operator = (const file_info& f)
  87. {
  88.   if (this != & f)
  89.     {
  90.       file_number = f.file_number;
  91.       delete [] file_name;
  92.       file_name = strsave (f.file_name);
  93.       file_fptr = f.file_fptr;
  94.       delete [] file_mode;
  95.       file_mode = strsave (f.file_mode);
  96.     }
  97.   return *this;
  98. }
  99.  
  100. file_info::~file_info (void)
  101. {
  102.   delete [] file_name;
  103.   delete [] file_mode;
  104. }
  105.  
  106. int
  107. file_info::number (void) const
  108. {
  109.   return file_number;
  110. }
  111.  
  112. const char *
  113. file_info::name (void) const
  114. {
  115.   return file_name;
  116. }
  117.  
  118. FILE *
  119. file_info::fptr (void) const
  120. {
  121.   return file_fptr;
  122. }
  123.  
  124. const char *
  125. file_info::mode (void) const
  126. {
  127.   return file_mode;
  128. }
  129.  
  130. void
  131. initialize_file_io (void)
  132. {
  133.   file_info octave_stdin (0, "stdin", stdin, "r");
  134.   file_info octave_stdout (1, "stdout", stdout, "w");
  135.   file_info octave_stderr (2, "stderr", stderr, "w");
  136.  
  137.   file_list.append (octave_stdin);
  138.   file_list.append (octave_stdout);
  139.   file_list.append (octave_stderr);
  140. }
  141.  
  142. // Given a file name or number, return a pointer to the corresponding
  143. // open file.  If the file has not already been opened, return NULL.
  144.  
  145. Pix
  146. return_valid_file (const tree_constant& arg)
  147. {
  148.   if (arg.is_string ())
  149.     {
  150.       Pix p = file_list.first ();
  151.       file_info file;
  152.       int file_count = file_list.length ();
  153.       for (int i = 0; i < file_count; i++)
  154.     {
  155.       char *file_name = arg.string_value ();
  156.       file = file_list (p);
  157.       if (strcmp (file.name (), file_name) == 0)
  158.         return p;
  159.       file_list.next (p);
  160.     }
  161.     }
  162.   else
  163.     {
  164.       double file_num = arg.double_value ();
  165.  
  166.       if (! error_state)
  167.     {
  168.       if (D_NINT (file_num) != file_num)
  169.         error ("file number not an integer value");
  170.       else
  171.         {
  172.           Pix p = file_list.first ();
  173.           file_info file;
  174.           int file_count = file_list.length ();
  175.           for (int i = 0; i < file_count; i++)
  176.         {
  177.           file = file_list (p);
  178.           if (file.number () == file_num)
  179.             return p;
  180.           file_list.next (p);
  181.         }
  182.           error ("no file with that number");
  183.         }
  184.     }
  185.       else
  186.     error ("inapproriate file specifier");
  187.     }
  188.  
  189.   return 0;
  190. }
  191.  
  192. static Pix 
  193. fopen_file_for_user (const char *name, const char *mode,
  194.              const char *warn_for)
  195. {
  196.   FILE *file_ptr = fopen (name, mode);
  197.   if (file_ptr)
  198.     {
  199.       int file_number = file_list.length () + 1;
  200.  
  201.       file_info file (file_number, name, file_ptr, mode);
  202.       file_list.append (file);
  203.       
  204.       Pix p = file_list.first ();
  205.       file_info file_from_list;
  206.       int file_count = file_list.length ();
  207.       for (int i = 0; i < file_count; i++)
  208.     {
  209.       file_from_list = file_list (p);
  210.       if (strcmp (file_from_list.name (), name) == 0)
  211.         return p;
  212.       file_list.next (p);
  213.     }
  214.     }
  215.  
  216.   error ("%s: unable to open file `%s'", warn_for, name);
  217.  
  218.   return 0;
  219. }
  220.  
  221. static Pix
  222. file_io_get_file (const tree_constant& arg, const char *mode,
  223.           const char *warn_for)
  224. {
  225.   Pix p = return_valid_file (arg);
  226.  
  227.   if (! p)
  228.     {
  229.       if (arg.is_string ())
  230.     {
  231.       char *name = arg.string_value ();
  232.  
  233.       struct stat buffer;
  234.       int status = stat (name, &buffer);
  235.  
  236.       if (status == 0)
  237.         {
  238.           if ((buffer.st_mode & S_IFREG) == S_IFREG)
  239.         p = fopen_file_for_user (name, mode, warn_for);
  240.           else
  241.         error ("%s: invalid file type", warn_for);
  242.         }
  243.       else if (status < 0 && *mode != 'r')
  244.         p = fopen_file_for_user (name, mode, warn_for);
  245.       else
  246.         error ("%s: can't stat file `%s'", warn_for, name);
  247.     }
  248.       else
  249.     error ("%s: invalid file specifier", warn_for);
  250.     }
  251.  
  252.   return p;
  253. }
  254.  
  255. DEFUN ("fclose", Ffclose, Sfclose, 1, 1,
  256.   "fclose (FILENAME or FILENUM): close a file")
  257. {
  258.   Octave_object retval;
  259.  
  260.   int nargin = args.length ();
  261.  
  262.   if (nargin != 1)
  263.     print_usage ("fclose");
  264.   else
  265.     retval = fclose_internal (args);
  266.  
  267.   return retval;
  268. }
  269.  
  270. Octave_object
  271. fclose_internal (const Octave_object& args)
  272. {
  273.   Octave_object retval;
  274.  
  275.   Pix p = return_valid_file (args(0));
  276.  
  277.   if (! p)
  278.     return retval;
  279.  
  280.   file_info file = file_list (p);
  281.  
  282.   if (file.number () < 3)
  283.     {
  284.       warning ("fclose: can't close stdin, stdout, or stderr!");
  285.       return retval;
  286.     }
  287.  
  288.   int success = fclose (file.fptr ());
  289.   file_list.del (p);
  290.  
  291.   if (success == 0)
  292.     retval(0) = 1.0; // succeeded
  293.   else
  294.     {
  295.       error ("fclose: error on closing file");
  296.       retval(0) = 0.0; // failed
  297.     }
  298.  
  299.   return retval;
  300. }
  301.  
  302. DEFUN ("fflush", Ffflush, Sfflush, 1, 1,
  303.   "fflush (FILENAME or FILENUM): flush buffered data to output file")
  304. {
  305.   Octave_object retval;
  306.  
  307.   int nargin = args.length ();
  308.  
  309.   if (nargin != 1)
  310.     print_usage ("fflush");
  311.   else
  312.     retval = fflush_internal (args);
  313.  
  314.   return retval;
  315. }
  316.  
  317. Octave_object
  318. fflush_internal (const Octave_object& args)
  319. {
  320.   Octave_object retval;
  321.  
  322.   Pix p = return_valid_file (args(0));
  323.  
  324.   if (! p)
  325.     return retval;
  326.  
  327.   file_info file = file_list (p);
  328.  
  329.   if (strcmp (file.mode (), "r") == 0)
  330.     {
  331.       warning ("can't flush an input stream");
  332.       return retval;
  333.     }
  334.  
  335.   int success = 0;
  336.  
  337.   if (file.number () == 1)
  338.     flush_output_to_pager ();
  339.   else
  340.     success = fflush (file.fptr ());
  341.  
  342.   if (success == 0)
  343.     retval(0) = 1.0; // succeeded
  344.   else
  345.     {
  346.       error ("fflush: write error");
  347.       retval(0) = 0.0; // failed
  348.     }
  349.  
  350.   return retval;
  351. }
  352.  
  353. static int
  354. valid_mode (const char *mode)
  355. {
  356.   if (mode)
  357.     {
  358.       char m = mode[0];
  359.       if (m == 'r' || m == 'w' || m == 'a')
  360.     {
  361.       m = mode[1];
  362.       return (m == '\0' || (m == '+' && mode[2] == '\0'));
  363.     }
  364.     }
  365.   return 0;
  366. }
  367.  
  368. DEFUN ("fgets", Ffgets, Sfgets, 2, 2,
  369.   "[STRING, LENGTH] = fgets (FILENAME or FILENUM, LENGTH)\n\
  370. \n\
  371. read a string from a file")
  372. {
  373.   Octave_object retval;
  374.  
  375.   int nargin = args.length ();
  376.  
  377.   if (nargin != 2)
  378.     print_usage ("fgets");
  379.   else
  380.     retval = fgets_internal (args, nargout);
  381.  
  382.   return retval;
  383. }
  384.  
  385. Octave_object
  386. fgets_internal (const Octave_object& args, int nargout)
  387. {
  388.   Octave_object retval;
  389.  
  390.   Pix p = file_io_get_file (args(0), "r", "fgets");
  391.   
  392.   if (! p)
  393.     return retval;
  394.  
  395.  
  396.   double dlen = args(1).double_value ();
  397.  
  398.   if (error_state)
  399.     return retval;
  400.  
  401.   if (xisnan (dlen))
  402.     {
  403.       error ("fgets: NaN invalid as length");
  404.       return retval;
  405.     }
  406.  
  407.   int length = NINT (dlen);
  408.  
  409.   if ((double) length != dlen)
  410.     {
  411.       error ("fgets: length not an integer value");
  412.       return retval;
  413.     }
  414.  
  415.   file_info file = file_list (p);
  416.  
  417.   char string [length+1];
  418.   char *success = fgets (string, length+1, file.fptr ());
  419.  
  420.   if (! success)
  421.     {
  422.       retval(0) = -1.0;
  423.       return retval;
  424.     }
  425.  
  426.   if (nargout == 2)
  427.     retval(1) = (double) strlen (string);
  428.  
  429.   retval(0) = string;
  430.  
  431.   return retval;
  432. }
  433.  
  434. DEFUN ("fopen", Ffopen, Sfopen, 2, 1,
  435.   "FILENUM = fopen (FILENAME, MODE): open a file\n\
  436. \n\
  437.   Valid values for mode include:\n\
  438. \n\
  439.    r  : open text file for reading\n\
  440.    w  : open text file for writing; discard previous contents if any\n\
  441.    a  : append; open or create text file for writing at end of file\n\
  442.    r+ : open text file for update (i.e., reading and writing)\n\
  443.    w+ : create text file for update; discard previous contents if any\n\
  444.    a+ : append; open or create text file for update, writing at end\n\n\
  445.  Update mode permits reading from and writing to the same file.")
  446. {
  447.   Octave_object retval;
  448.  
  449.   int nargin = args.length ();
  450.  
  451.   if (nargin != 2)
  452.     print_usage ("fopen");
  453.   else
  454.     retval = fopen_internal (args);
  455.  
  456.   return retval;
  457. }
  458.  
  459. Octave_object
  460. fopen_internal (const Octave_object& args)
  461. {
  462.   Octave_object retval;
  463.   Pix p;
  464.  
  465.   if (! args(0).is_string ())
  466.     {
  467.       error ("fopen: file name must be a string");
  468.       return retval;
  469.     }
  470.  
  471.   p = return_valid_file (args(0));
  472.  
  473.   if (p)
  474.     {
  475.       file_info file = file_list (p);
  476.  
  477.       retval(0) = (double) file.number ();
  478.  
  479.       return retval;
  480.     }
  481.  
  482.   if (! args(1).is_string ())
  483.     {
  484.       error ("fopen: file mode must be a string");
  485.       return retval;
  486.     }
  487.  
  488.   char *name = args(0).string_value ();
  489.   char *mode = args(1).string_value ();
  490.  
  491.   if (! valid_mode (mode))
  492.     {
  493.       error ("fopen: invalid mode");
  494.       return retval;
  495.     }
  496.  
  497.   struct stat buffer;
  498.   if (stat (name, &buffer) == 0 && (buffer.st_mode & S_IFDIR) == S_IFDIR)
  499.     {
  500.       error ("fopen: can't open directory");
  501.       return retval;
  502.     }
  503.  
  504.   FILE *file_ptr = fopen (name, mode);
  505.  
  506.   if (! file_ptr)
  507.     {
  508.       error ("fopen: unable to open file `%s'", name);
  509.       return retval;
  510.     }
  511.  
  512.   int file_number =  file_list.length () + 1;
  513.  
  514.   file_info file (file_number, name, file_ptr, mode);
  515.   file_list.append (file);
  516.  
  517.   retval(0) = (double) file_number;
  518.  
  519.   return retval;
  520. }
  521.  
  522. DEFUN ("freport", Ffreport, Sfreport, 0, 1,
  523.   "freport (): list open files and their status")
  524. {
  525.   Octave_object retval;
  526.  
  527.   int nargin = args.length ();
  528.  
  529.   if (nargin > 0)
  530.     warning ("freport: ignoring extra arguments");
  531.  
  532.   retval = freport_internal ();
  533.  
  534.   return retval;
  535. }
  536.  
  537. Octave_object
  538. freport_internal (void)
  539. {
  540.   Octave_object retval;
  541.   Pix p = file_list.first ();
  542.  
  543.   ostrstream output_buf;
  544.  
  545.   output_buf << "\n number  mode  name\n\n";
  546.  
  547.   int file_count = file_list.length ();
  548.   for (int i = 0; i < file_count; i++)
  549.     {
  550.       file_info file = file_list (p);
  551.       output_buf.form ("%7d%6s  %s\n", file.number (), file.mode (),
  552.                file.name ());
  553.       file_list.next (p);
  554.     }
  555.  
  556.   output_buf << "\n" << ends;
  557.   maybe_page_output (output_buf);
  558.  
  559.   return retval;
  560. }
  561.  
  562. DEFUN ("frewind", Ffrewind, Sfrewind, 1, 1,
  563.   "frewind (FILENAME or FILENUM): set file position at beginning of file")
  564. {
  565.   Octave_object retval;
  566.  
  567.   int nargin = args.length ();
  568.  
  569.   if (nargin != 1)
  570.     print_usage ("frewind");
  571.   else
  572.     retval = frewind_internal (args);
  573.  
  574.   return retval;
  575. }
  576.  
  577. Octave_object
  578. frewind_internal (const Octave_object& args)
  579. {
  580.   Octave_object retval;
  581.  
  582.   Pix p = file_io_get_file (args(0), "a+", "frewind");
  583.  
  584.   if (p)
  585.     {
  586.       file_info file = file_list (p);
  587.       rewind (file.fptr ());
  588.     }
  589.  
  590.   return retval;
  591. }
  592.  
  593. DEFUN ("fseek", Ffseek, Sfseek, 3, 1,
  594.   "fseek (FILENAME or FILENUM, OFFSET [, ORIGIN])\n\
  595. \n\
  596. set file position for reading or writing")
  597. {
  598.   Octave_object retval;
  599.  
  600.   int nargin = args.length ();
  601.  
  602.   if (nargin != 2 && nargin != 3)
  603.     print_usage ("fseek");
  604.   else
  605.     retval = fseek_internal (args);
  606.  
  607.   return retval;
  608. }
  609.  
  610. Octave_object
  611. fseek_internal (const Octave_object& args)
  612. {
  613.   Octave_object retval;
  614.  
  615.   int nargin = args.length ();
  616.  
  617.   Pix p = file_io_get_file (args(0), "a+", "fseek");
  618.  
  619.   if (! p)
  620.     return retval;
  621.  
  622.   long origin = SEEK_SET;
  623.  
  624.   double doff = args(1).double_value ();
  625.  
  626.   if (error_state)
  627.     return retval;
  628.  
  629.   if (xisnan (doff))
  630.     {
  631.       error ("fseek: NaN invalid as offset");
  632.       return retval;
  633.     }
  634.  
  635.   long offset = NINT (doff);
  636.  
  637.   if ((double) offset != doff)
  638.     {
  639.       error ("fseek: offset not an integer value");
  640.       return retval;
  641.     }
  642.  
  643.   if (nargin == 3)
  644.     {
  645.       double dorig = args(2).double_value ();
  646.  
  647.       if (error_state)
  648.     return retval;
  649.  
  650.       if (xisnan (dorig))
  651.     {
  652.       error ("fseek: NaN invalid as origin");
  653.       return retval;
  654.     }
  655.  
  656.       origin = NINT (dorig);
  657.  
  658.       if ((double) dorig != origin)
  659.     {
  660.       error ("fseek: origin not an integer value");
  661.       return retval;
  662.     }
  663.  
  664.       if (origin == 0)
  665.     origin = SEEK_SET;
  666.       else if (origin == 1)
  667.     origin = SEEK_CUR;
  668.       else if (origin == 2)
  669.     origin = SEEK_END;
  670.       else
  671.     {
  672.       error ("fseek: invalid value for origin");
  673.       return retval;
  674.     }
  675.     }
  676.  
  677.   file_info file = file_list (p);
  678.   int success = fseek (file.fptr (), offset, origin);
  679.  
  680.   if (success == 0)
  681.     retval(0) = 1.0; // succeeded
  682.   else
  683.     {
  684.       error ("fseek: file error");
  685.       retval(0) = 0.0; // failed
  686.     }
  687.  
  688.   return retval;
  689. }
  690.  
  691. // Tell current position of file.
  692.  
  693. DEFUN ("ftell", Fftell, Sftell, 1, 1,
  694.   "POSITION = ftell (FILENAME or FILENUM): returns the current file position")
  695. {
  696.   Octave_object retval;
  697.  
  698.   int nargin = args.length ();
  699.  
  700.   if (nargin != 1)
  701.     print_usage ("ftell");
  702.   else
  703.     retval = ftell_internal (args);
  704.  
  705.   return retval;
  706. }
  707.  
  708. Octave_object
  709. ftell_internal (const Octave_object& args)
  710. {
  711.   Octave_object retval;
  712.  
  713.   Pix p = file_io_get_file (args(0), "a+", "ftell");
  714.  
  715.   if (p)
  716.     {
  717.       file_info file = file_list (p);
  718.       long offset = ftell (file.fptr ());
  719.  
  720.       retval(0) = (double) offset;
  721.  
  722.       if (offset == -1L)
  723.     error ("ftell: write error");
  724.     }
  725.  
  726.   return retval;
  727. }
  728.  
  729. void
  730. close_files (void)
  731. {
  732.   Pix p = file_list.first ();
  733.  
  734.   int file_count = file_list.length ();
  735.   for (int i = 0; i < file_count; i++)
  736.     {
  737.       if (p)
  738.     {
  739.       file_info file = file_list (p);
  740.  
  741.       if (i > 2)   // do not close stdin, stdout, stderr!
  742.         {
  743.           int success = fclose (file.fptr ());
  744.           if (success != 0)
  745.         error ("closing %s", file.name ());
  746.         }
  747.  
  748.       file_list.del (p);
  749.     }
  750.       else
  751.     {
  752.       error ("inconsistent state for internal file list!");
  753.       break;
  754.     }
  755.     }
  756. }
  757.  
  758. static int
  759. process_printf_format (const char *s, const Octave_object& args,
  760.                ostrstream& sb, const char *type)
  761. {
  762.   ostrstream fmt;
  763.  
  764.   int nargin = args.length ();
  765.  
  766.   fmt << "%";  // do_printf() already blew past this one...
  767.  
  768.   int chars_from_fmt_str = 0;
  769.  
  770.  again:
  771.   switch (*s)
  772.     {
  773.     case '+': case '-': case ' ': case '0': case '#':
  774.       chars_from_fmt_str++;
  775.       fmt << *s++;
  776.       goto again;
  777.  
  778.     case '\0':
  779.       goto invalid_format;
  780.  
  781.     default:
  782.       break;
  783.     }
  784.  
  785.   if (*s == '*')
  786.     {
  787.       if (fmt_arg_count > nargin)
  788.     {
  789.       error ("%s: not enough arguments", type);
  790.       return -1;
  791.     }
  792.  
  793.       double tmp_len = args(fmt_arg_count++).double_value ();
  794.  
  795.       if (error_state || xisnan (tmp_len))
  796.     {
  797.       error ("%s: `*' must be replaced by an integer", type);
  798.       return -1;
  799.     }
  800.  
  801.       fmt << NINT (tmp_len);
  802.       s++;
  803.       chars_from_fmt_str++;
  804.     }
  805.   else
  806.     {
  807.       while (*s != '\0' && isdigit (*s))
  808.     {
  809.       chars_from_fmt_str++;
  810.       fmt << *s++;
  811.     }
  812.     }
  813.  
  814.   if (*s == '\0')
  815.     goto invalid_format;
  816.  
  817.   if (*s == '.')
  818.     {
  819.       chars_from_fmt_str++;
  820.       fmt << *s++;
  821.     }
  822.  
  823.   if (*s == '*')
  824.     {
  825.       if (*(s-1) == '*')
  826.     goto invalid_format;
  827.  
  828.       if (fmt_arg_count > nargin)
  829.     {
  830.       error ("%s: not enough arguments", type);
  831.       return -1;
  832.     }
  833.  
  834.       double tmp_len = args(fmt_arg_count++).double_value ();
  835.  
  836.       if (error_state || xisnan (tmp_len))
  837.     {
  838.       error ("%s: `*' must be replaced by an integer", type);
  839.       return -1;
  840.     }
  841.  
  842.       fmt << NINT (tmp_len);
  843.       s++;
  844.       chars_from_fmt_str++;
  845.     }
  846.   else
  847.     {
  848.       while (*s != '\0' && isdigit (*s))
  849.     {
  850.       chars_from_fmt_str++;
  851.       fmt << *s++;
  852.     }
  853.     }
  854.  
  855.   if (*s == '\0')
  856.     goto invalid_format;
  857.  
  858.   if (*s != '\0' && (*s == 'h' || *s == 'l' || *s == 'L'))
  859.     {
  860.       chars_from_fmt_str++;
  861.       fmt << *s++;
  862.     }
  863.  
  864.   if (*s == '\0')
  865.     goto invalid_format;
  866.  
  867.   if (fmt_arg_count > nargin)
  868.     {
  869.       error ("%s: not enough arguments", type);
  870.       return -1;
  871.     }
  872.  
  873.   switch (*s)
  874.     {
  875.     case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
  876.       {
  877.     double d = args(fmt_arg_count++).double_value ();
  878.  
  879.     if (error_state || xisnan (d))
  880.       goto invalid_conversion;
  881.  
  882.     int val = NINT (d);
  883.  
  884.     if ((double) val != d)
  885.       goto invalid_conversion;
  886.     else
  887.       {
  888.         chars_from_fmt_str++;
  889.         fmt << *s << ends;
  890.         char *tmp_fmt = fmt.str ();
  891.         sb.form (tmp_fmt, val);
  892.         delete [] tmp_fmt;
  893.         return chars_from_fmt_str;
  894.       }
  895.       }
  896.  
  897.     case 'e': case 'E': case 'f': case 'g': case 'G':
  898.       {
  899.     double val = args(fmt_arg_count++).double_value ();
  900.  
  901.     if (error_state)
  902.       goto invalid_conversion;
  903.     else
  904.       {
  905.         chars_from_fmt_str++;
  906.         fmt << *s << ends;
  907.         char *tmp_fmt = fmt.str ();
  908.         sb.form (tmp_fmt, val);
  909.         delete [] tmp_fmt;
  910.         return chars_from_fmt_str;
  911.       }
  912.       }
  913.  
  914.     case 's':
  915.       {
  916.     char *val = args(fmt_arg_count++).string_value ();
  917.  
  918.     if (error_state)
  919.       goto invalid_conversion;
  920.     else
  921.       {
  922.         chars_from_fmt_str++;
  923.         fmt << *s << ends;
  924.         char *tmp_fmt = fmt.str ();
  925.         sb.form (tmp_fmt, val);
  926.         delete [] tmp_fmt;
  927.         return chars_from_fmt_str;
  928.       }
  929.       }
  930.  
  931.     case 'c':
  932.       {
  933.     char *val = args(fmt_arg_count++).string_value ();
  934.  
  935.     if (error_state || strlen (val) != 1)
  936.       goto invalid_conversion;
  937.     else
  938.       {
  939.         chars_from_fmt_str++;
  940.         fmt << *s << ends;
  941.         char *tmp_fmt = fmt.str ();
  942.         sb.form (tmp_fmt, *val);
  943.         delete [] tmp_fmt;
  944.         return chars_from_fmt_str;
  945.       }
  946.       }
  947.  
  948.     default:
  949.       goto invalid_format;
  950.    }
  951.  
  952.  invalid_conversion:
  953.   error ("%s: invalid conversion", type);
  954.   return -1;
  955.  
  956.  invalid_format:
  957.   error ("%s: invalid format", type);
  958.   return -1;
  959. }
  960.  
  961. // Formatted printing to a file.
  962.  
  963. DEFUN ("fprintf", Ffprintf, Sfprintf, -1, 1,
  964.   "fprintf (FILENAME or FILENUM, FORMAT, ...)")
  965. {
  966.   Octave_object retval;
  967.  
  968.   int nargin = args.length ();
  969.  
  970.   if (nargin < 2)
  971.     print_usage ("fprintf");
  972.   else
  973.     retval = do_printf ("fprintf", args, nargout);
  974.  
  975.   return retval;
  976. }
  977.  
  978. // Formatted printing.
  979.  
  980. DEFUN ("printf", Fprintf, Sprintf, -1, 1,
  981.   "printf (FORMAT, ...)")
  982. {
  983.   Octave_object retval;
  984.  
  985.   int nargin = args.length ();
  986.  
  987.   if (nargin < 1)
  988.     print_usage ("printf");
  989.   else
  990.     retval = do_printf ("printf", args, nargout);
  991.  
  992.   return retval;
  993. }
  994.  
  995. // Formatted printing to a string.
  996.  
  997. DEFUN ("sprintf", Fsprintf, Ssprintf, -1, 1,
  998.   "s = sprintf (FORMAT, ...)")
  999. {
  1000.   Octave_object retval;
  1001.  
  1002.   int nargin = args.length ();
  1003.  
  1004.   if (nargin < 1)
  1005.     print_usage ("sprintf");
  1006.   else
  1007.     retval = do_printf ("sprintf", args, nargout);
  1008.  
  1009.   return retval;
  1010. }
  1011.  
  1012. Octave_object
  1013. do_printf (const char *type, const Octave_object& args, int nargout)
  1014. {
  1015.   Octave_object retval;
  1016.   fmt_arg_count = 0;
  1017.   char *fmt;
  1018.   file_info file;
  1019.  
  1020.   if (strcmp (type, "fprintf") == 0)
  1021.     {
  1022.       Pix p = file_io_get_file (args(0), "a+", type);
  1023.  
  1024.       if (! p)
  1025.     return retval;
  1026.  
  1027.       file = file_list (p);
  1028.  
  1029.       if (file.mode () == "r")
  1030.     {
  1031.       error ("%s: file is read only", type);
  1032.       return retval;
  1033.     }
  1034.  
  1035.       fmt = args(1).string_value ();
  1036.  
  1037.       if (error_state)
  1038.     {
  1039.       error ("%s: format must be a string", type);
  1040.       return retval;
  1041.     }
  1042.  
  1043.       fmt_arg_count += 2;
  1044.     }
  1045.   else
  1046.     {
  1047.       fmt = args(0).string_value ();
  1048.  
  1049.       if (error_state)
  1050.     {
  1051.       error ("%s: invalid format string", type);
  1052.       return retval;
  1053.     }
  1054.  
  1055.       fmt_arg_count++;
  1056.     }
  1057.  
  1058. // Scan fmt for % escapes and print out the arguments.
  1059.  
  1060.   ostrstream output_buf;
  1061.  
  1062.   char *ptr = fmt;
  1063.  
  1064.   for (;;)
  1065.     {
  1066.       char c;
  1067.       while ((c = *ptr++) != '\0' && c != '%')
  1068.     output_buf << c;
  1069.  
  1070.       if (c == '\0')
  1071.     break;
  1072.  
  1073.       if (*ptr == '%')
  1074.     {
  1075.       ptr++;
  1076.       output_buf << c;
  1077.       continue;
  1078.     }
  1079.  
  1080. // We must be looking at a format specifier.  Extract it or fail.
  1081.  
  1082.  
  1083.       int status = process_printf_format (ptr, args, output_buf, type);
  1084.  
  1085.       if (status < 0)
  1086.     return retval;
  1087.  
  1088.       ptr += status;
  1089.     }
  1090.  
  1091.   output_buf << ends;
  1092.   if (strcmp (type, "printf") == 0
  1093.       || (strcmp (type, "fprintf") == 0 && file.number () == 1))
  1094.     {
  1095.       maybe_page_output (output_buf);
  1096.     }
  1097.   else if (strcmp (type, "fprintf") == 0)
  1098.     {
  1099.       char *msg = output_buf.str ();
  1100.       int success = fputs (msg, file.fptr ());
  1101.       if (success == EOF)
  1102.     warning ("%s: unknown failure writing to file", type);
  1103.       delete [] msg;
  1104.     }
  1105.   else if (strcmp (type, "sprintf") == 0)
  1106.     {
  1107.       char *msg = output_buf.str ();
  1108.       retval(0) = msg;
  1109.       delete [] msg;
  1110.     }
  1111.  
  1112.   return retval;
  1113. }
  1114.  
  1115. static int
  1116. process_scanf_format (const char *s, ostrstream& fmt,
  1117.               const char *type, int nargout, FILE* fptr,
  1118.               Octave_object& values)
  1119. {
  1120.   fmt << "%";
  1121.  
  1122.   int chars_from_fmt_str = 0;
  1123.   int store_value = 1;
  1124.   int string_width = 0;
  1125.   int success = 1;
  1126.  
  1127.   if (*s == '*')
  1128.     {
  1129.       store_value = 0;
  1130.       s++;
  1131.       chars_from_fmt_str++;
  1132.     }
  1133.  
  1134.   if (isdigit (*s))
  1135.     {
  1136.       ostrstream str_number;
  1137.       while (*s != '\0' && isdigit (*s))
  1138.     {
  1139.       chars_from_fmt_str++;
  1140.       str_number << *s;
  1141.       fmt << *s++;
  1142.     }
  1143.       str_number << ends;
  1144.       char *number = str_number.str ();
  1145.       string_width = atoi (number);
  1146.       delete [] number;
  1147.     }
  1148.  
  1149.   if (*s == '\0')
  1150.     goto invalid_format;
  1151.  
  1152.   if (*s != '\0' && (*s == 'h' || *s == 'l' || *s == 'L'))
  1153.     {
  1154.       chars_from_fmt_str++;
  1155.       s++;
  1156.     }
  1157.  
  1158.   if (*s == '\0')
  1159.     goto invalid_format;
  1160.  
  1161. // Even if we don't have a place to store them, attempt to convert
  1162. // everything specified by the format string.
  1163.  
  1164.   if (fmt_arg_count > (nargout ? nargout : 1))
  1165.     store_value = 0;
  1166.  
  1167.   switch (*s)
  1168.     {
  1169.     case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
  1170.       {
  1171.     chars_from_fmt_str++;
  1172.     fmt << *s << ends;
  1173.     int temp;
  1174.     char *str = fmt.str ();
  1175.     success = fscanf (fptr, str, &temp);
  1176.     delete [] str;
  1177.     if (success > 0 && store_value)
  1178.       values(fmt_arg_count++) = (double) temp;
  1179.       }
  1180.       break;
  1181.  
  1182.     case 'e': case 'E': case 'f': case 'g': case 'G':
  1183.       {
  1184.     chars_from_fmt_str++;
  1185.     fmt << 'l' << *s << ends;
  1186.     double temp;
  1187.     char *str = fmt.str ();
  1188.     success = fscanf (fptr, str, &temp);
  1189.     delete [] str;
  1190.     if (success > 0 && store_value)
  1191.       values(fmt_arg_count++) = temp;
  1192.       }
  1193.       break;
  1194.  
  1195.     case 's':
  1196.       {
  1197.     if (string_width < 1)
  1198.       {
  1199. // XXX FIXME XXX -- The code below is miscompiled on the Alpha with
  1200. // gcc 2.6.0, so that string_width is never incremented, even though
  1201. // reading the data works correctly.  One fix is to use a fixed-size
  1202. // buffer...
  1203. //        string_width = 8192;
  1204.  
  1205.         string_width = 0;
  1206.         long original_position = ftell (fptr);
  1207.  
  1208.         int c;
  1209.  
  1210.         while ((c = getc (fptr)) != EOF && isspace (c))
  1211.           ; // Don't count leading whitespace.
  1212.  
  1213.         if (c != EOF)
  1214.           string_width++;
  1215.  
  1216.         for (;;)
  1217.           {
  1218.         c = getc (fptr);
  1219.         if (c != EOF && ! isspace (c))
  1220.           string_width++;
  1221.         else
  1222.           break;
  1223.           }
  1224.  
  1225.         fseek (fptr, original_position, SEEK_SET);
  1226.       }
  1227.     chars_from_fmt_str++;
  1228.     char temp [string_width+1];
  1229.     fmt << *s << ends;
  1230.     char *str = fmt.str ();
  1231.     success = fscanf (fptr, str, temp);
  1232.     delete [] str;
  1233.     temp[string_width] = '\0';
  1234.     if (success > 0 && store_value)
  1235.       values(fmt_arg_count++) = temp;
  1236.       }
  1237.       break;
  1238.  
  1239.     case 'c':
  1240.       {
  1241.     if (string_width < 1)
  1242.       string_width = 1;
  1243.     chars_from_fmt_str++;
  1244.     char temp [string_width+1];
  1245.     memset (temp, '\0', string_width+1);
  1246.     fmt << *s << ends;
  1247.     char *str = fmt.str ();
  1248.     success = fscanf (fptr, str, temp);
  1249.     delete [] str;
  1250.     temp[string_width] = '\0';
  1251.     if (success > 0 && store_value)
  1252.       values(fmt_arg_count++) = temp;
  1253.       }
  1254.       break;
  1255.  
  1256.     default:
  1257.       goto invalid_format;
  1258.     }
  1259.  
  1260.   if (success > 0)
  1261.     return chars_from_fmt_str;
  1262.   else if (success == 0)
  1263.     warning ("%s: invalid conversion", type);
  1264.   else if (success == EOF)
  1265.     {
  1266.       if (strcmp (type, "fscanf") == 0)
  1267.     warning ("%s: end of file reached before final conversion", type);
  1268.       else if (strcmp (type, "sscanf") == 0)
  1269.     warning ("%s: end of string reached before final conversion", type);
  1270.       else if (strcmp (type, "scanf") == 0)
  1271.     warning ("%s: end of input reached before final conversion", type);
  1272.     }
  1273.   else
  1274.     {
  1275.     invalid_format:
  1276.       warning ("%s: invalid format", type);
  1277.     }
  1278.  
  1279.   return -1;
  1280. }
  1281.  
  1282. // Formatted reading from a file.
  1283.  
  1284. DEFUN ("fscanf", Ffscanf, Sfscanf, 2, -1,
  1285.   "[A, B, C, ...] = fscanf (FILENAME or FILENUM, FORMAT)")
  1286. {
  1287.   Octave_object retval;
  1288.  
  1289.   int nargin = args.length ();
  1290.  
  1291.   if (nargin != 1 && nargin != 2)
  1292.     print_usage ("fscanf");
  1293.   else
  1294.     retval = do_scanf ("fscanf", args, nargout);
  1295.  
  1296.   return retval;
  1297. }
  1298.  
  1299. // Formatted reading.
  1300.  
  1301. DEFUN ("scanf", Fscanf, Sscanf, 1, -1,
  1302.   "[A, B, C, ...] = scanf (FORMAT)")
  1303. {
  1304.   Octave_object retval;
  1305.  
  1306.   int nargin = args.length ();
  1307.  
  1308.   if (nargin != 1)
  1309.     print_usage ("scanf");
  1310.   else
  1311.     retval = do_scanf ("scanf", args, nargout);
  1312.  
  1313.   return retval;
  1314. }
  1315.  
  1316. // Formatted reading from a string.
  1317.  
  1318. DEFUN ("sscanf", Fsscanf, Ssscanf, 2, -1,
  1319.   "[A, B, C, ...] = sscanf (STRING, FORMAT)")
  1320. {
  1321.   Octave_object retval;
  1322.  
  1323.   int nargin = args.length ();
  1324.  
  1325.   if (nargin != 2)
  1326.     print_usage ("sscanf");
  1327.   else
  1328.     retval = do_scanf ("sscanf", args, nargout);
  1329.  
  1330.   return retval;
  1331. }
  1332.  
  1333. Octave_object
  1334. do_scanf (const char *type, const Octave_object& args, int nargout)
  1335. {
  1336.   Octave_object retval;
  1337.   char *scanf_fmt = 0;
  1338.   char *tmp_file = 0;
  1339.   int tmp_file_open = 0;
  1340.   FILE *fptr = 0;
  1341.   file_info file;
  1342.  
  1343.   fmt_arg_count = 0;
  1344.  
  1345.   if (strcmp (type, "scanf") != 0)
  1346.     {
  1347.       scanf_fmt = args(1).string_value ();
  1348.  
  1349.       if (error_state)
  1350.     {
  1351.       error ("%s: format must be a string", type);
  1352.       return retval;
  1353.     }
  1354.     }
  1355.  
  1356.   int doing_fscanf = (strcmp (type, "fscanf") == 0);
  1357.  
  1358.   if (doing_fscanf)
  1359.     {
  1360.       Pix p = file_io_get_file (args(0), "r", type);
  1361.  
  1362.       if (! p)
  1363.     return retval;
  1364.  
  1365.       file = file_list (p);
  1366.  
  1367.       if (strcmp (file.mode (), "w") == 0 || strcmp (file.mode (), "a") == 0)
  1368.     {
  1369.       error ("%s: this file is opened for writing only", type);
  1370.       return retval;
  1371.     }
  1372.  
  1373.       fptr = file.fptr ();
  1374.     }
  1375.  
  1376.   if ((! fptr && args(0).is_string ())
  1377.       || (doing_fscanf && file.number () == 0))
  1378.     {
  1379.       char *string;
  1380.  
  1381.       if (strcmp (type, "scanf") == 0)
  1382.     scanf_fmt = args(0).string_value ();
  1383.  
  1384.       if (strcmp (type, "scanf") == 0
  1385.       || (doing_fscanf && file.number () == 0))
  1386.     {
  1387. // XXX FIXME XXX -- this should probably be possible for more than
  1388. // just stdin/stdout pairs, using a list of output streams to flush.
  1389. // The list could be created with a function like iostream's tie().
  1390.  
  1391.       flush_output_to_pager ();
  1392.  
  1393.       string = gnu_readline ("");
  1394.  
  1395.       if (string && *string)
  1396.         maybe_save_history (string);
  1397.     }
  1398.       else
  1399.     string = args(0).string_value ();
  1400.  
  1401.       tmp_file = octave_tmp_file_name ();
  1402.  
  1403.       fptr = fopen (tmp_file, "w+");
  1404.       if (! fptr)
  1405.     {
  1406.       error ("%s: error opening temporary file", type);
  1407.       return retval;
  1408.     }
  1409.       tmp_file_open = 1;
  1410.       unlink (tmp_file);
  1411.  
  1412.       if (! string)
  1413.     {
  1414.       error ("%s: no string to scan", type); 
  1415.       return retval;
  1416.     }
  1417.  
  1418.       int success = fputs (string, fptr);
  1419.       fflush (fptr);
  1420.       rewind (fptr);
  1421.  
  1422.       if (success < 0)
  1423.     {
  1424.       error ("%s: trouble writing temporary file", type);
  1425.       fclose (fptr);
  1426.       return retval;
  1427.     }
  1428.     }
  1429.   else if (! doing_fscanf)
  1430.     {
  1431.       error ("%s: first argument must be a string", type);
  1432.       return retval;
  1433.     }
  1434.  
  1435. // Scan scanf_fmt for % escapes and assign the arguments.
  1436.  
  1437.   retval.resize (nargout);
  1438.  
  1439.   char *ptr = scanf_fmt;
  1440.  
  1441.   for (;;)
  1442.     {
  1443.       ostrstream fmt;
  1444.       char c;
  1445.       while ((c = *ptr++) != '\0' && c != '%')
  1446.     fmt << c;
  1447.  
  1448.       if (c == '\0')
  1449.     break;
  1450.  
  1451.       if (*ptr == '%')
  1452.     {
  1453.       ptr++;
  1454.       fmt << c;
  1455.       continue;
  1456.     }
  1457.  
  1458. // We must be looking at a format specifier.  Extract it or fail.
  1459.  
  1460.       int status = process_scanf_format (ptr, fmt, type, nargout,
  1461.                      fptr, retval);
  1462.  
  1463.       if (status < 0)
  1464.     {
  1465.       if (fmt_arg_count == 0)
  1466.         retval.resize (0);
  1467.       break;
  1468.     }
  1469.  
  1470.       ptr += status;
  1471.     }
  1472.  
  1473.   if (tmp_file_open)
  1474.     fclose (fptr);
  1475.  
  1476.   return retval;
  1477. }
  1478.  
  1479. // Find out how many elements are left to read.
  1480.  
  1481. static long
  1482. num_items_remaining (FILE *fptr, char *type)
  1483. {
  1484.   size_t size;
  1485.  
  1486.   if (strcasecmp (type, "uchar") == 0)
  1487.     size = sizeof (u_char);
  1488.   else if (strcasecmp (type, "char") == 0)
  1489.     size = sizeof (char);
  1490.   else if (strcasecmp (type, "short") == 0)
  1491.     size = sizeof (short);
  1492.   else if (strcasecmp (type, "ushort") == 0)
  1493.     size = sizeof (u_short);
  1494.   else if (strcasecmp (type, "int") == 0)
  1495.     size = sizeof (int);
  1496.   else if (strcasecmp (type, "uint") == 0)
  1497.     size = sizeof (u_int);
  1498.   else if (strcasecmp (type, "long") == 0)
  1499.     size = sizeof (long);
  1500.   else if (strcasecmp (type, "ulong") == 0)
  1501.     size = sizeof (u_long);
  1502.   else if (strcasecmp (type, "float") == 0)
  1503.     size = sizeof (float);
  1504.   else if (strcasecmp (type, "double") == 0)
  1505.     size = sizeof (double);
  1506.   else
  1507.     return 0;
  1508.  
  1509.   long curr_pos = ftell (fptr);
  1510.  
  1511.   fseek (fptr, 0, SEEK_END);
  1512.   long end_of_file = ftell (fptr);
  1513.  
  1514.   fseek (fptr, curr_pos, SEEK_SET);
  1515.  
  1516.   long len = end_of_file - curr_pos;
  1517.  
  1518.   return len / size;
  1519. }
  1520.  
  1521. DEFUN ("fread", Ffread, Sfread, 3, 2,
  1522.   "[DATA, COUNT] = fread (FILENUM, SIZE, PRECISION)\n\
  1523. \n\
  1524.  Reads data in binary form of type PRECISION from a file.\n\
  1525. \n\
  1526.  FILENUM   : file number from fopen\n\
  1527.  SIZE      : size specification for the Data matrix\n\
  1528.  PRECISION : type of data to read, valid types are\n\
  1529. \n\
  1530.                'char',   'schar', 'short',  'int',  'long', 'float'\n\
  1531.                'double', 'uchar', 'ushort', 'uint', 'ulong'\n\
  1532. \n\
  1533.  DATA      : matrix in which the data is stored\n\
  1534.  COUNT     : number of elements read")
  1535. {
  1536.   Octave_object retval;
  1537.  
  1538.   int nargin = args.length ();
  1539.  
  1540.   if (nargin < 1 || nargin > 3)
  1541.     print_usage ("fread");
  1542.   else
  1543.     retval = fread_internal (args, nargout);
  1544.  
  1545.   return retval;
  1546. }
  1547.  
  1548. // Read binary data from a file.
  1549. //
  1550. //   [data, count] = fread (fid, size, 'precision')
  1551. //
  1552. //     fid       : the file id from fopen
  1553. //     size      : the size of the matrix or vector or scaler to read
  1554. //
  1555. //                 n      : reads n elements of a column vector
  1556. //                 inf      : reads to the end of file (default)
  1557. //                 [m, n] : reads enough elements to fill the matrix
  1558. //                          the number of columns can be inf
  1559. //
  1560. //     precision : type of the element.  Can be:
  1561. //
  1562. //                 char, uchar, schar, short, ushort, int, uint,
  1563. //                 long, ulong, float, double
  1564. //
  1565. //                 Default  is uchar.
  1566. //
  1567. //     data     : output data
  1568. //     count     : number of elements read
  1569.  
  1570. Octave_object
  1571. fread_internal (const Octave_object& args, int nargout)
  1572. {
  1573.   Octave_object retval;
  1574.  
  1575.   int nargin = args.length ();
  1576.  
  1577.   Pix p = file_io_get_file (args(0), "r", "fread");
  1578.  
  1579.   if (! p)
  1580.     return retval;
  1581.  
  1582. // Get type and number of bytes per element to read.
  1583.   char *prec = "uchar";
  1584.   if (nargin > 2)
  1585.     {
  1586.       prec = args(2).string_value ();
  1587.  
  1588.       if (error_state)
  1589.     {
  1590.       error ("fread: precision must be a specified as a string");
  1591.       return retval;
  1592.     }
  1593.     }
  1594.  
  1595. // Get file info.
  1596.  
  1597.   file_info file = file_list (p);
  1598.  
  1599.   FILE *fptr = file.fptr ();
  1600.  
  1601. // Set up matrix to read into.  If specified in arguments use that
  1602. // number, otherwise read everyting left in file.
  1603.  
  1604.   double dnr = 0.0;
  1605.   double dnc = 0.0;
  1606.   int nr;
  1607.   int nc;
  1608.  
  1609.   if (nargin > 1)
  1610.     {
  1611.       if (args(1).is_scalar_type ())
  1612.     {
  1613.       dnr = args(1).double_value ();
  1614.  
  1615.       if (error_state)
  1616.         return retval;
  1617.  
  1618.       dnc = 1.0;
  1619.     }
  1620.       else
  1621.     {
  1622.       ColumnVector tmp = args(1).vector_value ();
  1623.  
  1624.       if (error_state || tmp.length () != 2)
  1625.         {
  1626.           error ("fread: invalid size specification\n");
  1627.           return retval;
  1628.         }
  1629.  
  1630.       dnr = tmp.elem (0);
  1631.       dnc = tmp.elem (1);
  1632.     }
  1633.  
  1634.       if ((xisinf (dnr)) && (xisinf (dnc)))
  1635.     {
  1636.       error ("fread: number of rows and columns cannot both be infinite");
  1637.       return retval;
  1638.     }
  1639.  
  1640.       if (xisinf (dnr))
  1641.     {
  1642.       if (xisnan (dnc))
  1643.         {
  1644.           error ("fread: NaN invalid as the number of columns");
  1645.           return retval;
  1646.         }
  1647.       else
  1648.         {
  1649.           nc = NINT (dnc);
  1650.           int n = num_items_remaining (fptr, prec);
  1651.           nr = n / nc;
  1652.           if (n > nr * nc)
  1653.         nr++;
  1654.         }
  1655.     }
  1656.       else if (xisinf (dnc))
  1657.     {
  1658.       if (xisnan (dnr))
  1659.         {
  1660.           error ("fread: NaN invalid as the number of rows");
  1661.           return retval;
  1662.         }
  1663.       else
  1664.         {
  1665.           nr = NINT (dnr);
  1666.           int n = num_items_remaining (fptr, prec);
  1667.           nc = n / nr;
  1668.           if (n > nc * nr)
  1669.         nc++;
  1670.         }
  1671.     }
  1672.       else
  1673.     {
  1674.       if (xisnan (dnr))
  1675.         {
  1676.           error ("fread: NaN invalid as the number of rows");
  1677.           return retval;
  1678.         }
  1679.       else
  1680.         nr = NINT (dnr);
  1681.  
  1682.       if (xisnan (dnc))
  1683.         {
  1684.           error ("fread: NaN invalid as the number of columns");
  1685.           return retval;
  1686.         }
  1687.       else
  1688.         nc = NINT (dnc);
  1689.     }
  1690.     }
  1691.   else
  1692.     {
  1693. // No size parameter, read what's left of the file.
  1694.       nc = 1;
  1695.       int n = num_items_remaining (fptr, prec);
  1696.       nr = n / nc;
  1697.       if (n > nr * nc)
  1698.     nr++;
  1699.     }
  1700.  
  1701.   Matrix m (nr, nc, octave_NaN);
  1702.  
  1703. // Read data.
  1704.  
  1705.   int count = m.read (fptr, prec);
  1706.  
  1707.   if (nargout > 1)
  1708.     retval(1) = (double) count;
  1709.  
  1710.   retval(0) = m;
  1711.  
  1712.   return retval;
  1713. }
  1714.  
  1715. DEFUN ("fwrite", Ffwrite, Sfwrite, 3, 1,
  1716.   "COUNT = fwrite (FILENUM, DATA, PRECISION)\n\
  1717. \n\
  1718.  Writes data to a file in binary form of size PRECISION\n\
  1719. \n\
  1720.  FILENUM   : file number from fopen\n\
  1721.  DATA      : matrix of elements to be written\n\
  1722.  PRECISION : type of data to read, valid types are\n\
  1723. \n\
  1724.                'char',   'schar', 'short',  'int',  'long', 'float'\n\
  1725.                'double', 'uchar', 'ushort', 'uint', 'ulong'\n\
  1726. \n\
  1727.  COUNT     : number of elements written")
  1728. {
  1729.   Octave_object retval;
  1730.  
  1731.   int nargin = args.length ();
  1732.  
  1733.   if (nargin < 2 || nargin > 3)
  1734.     print_usage ("fwrite");
  1735.   else
  1736.     retval = fwrite_internal (args, nargout);
  1737.  
  1738.   return retval;
  1739. }
  1740.  
  1741. // Write binary data to a file.
  1742. //
  1743. //   count = fwrite (fid, data, 'precision')
  1744. //
  1745. //    fid    : file id from fopen
  1746. //    Data    : data to be written
  1747. //    precision    : type of output element.  Can be:
  1748. //
  1749. //                char, uchar, schar, short, ushort, int, uint,
  1750. //                long, float, double
  1751. //
  1752. //                 Default is uchar.
  1753. //
  1754. //    count     : the number of elements written
  1755.  
  1756. Octave_object
  1757. fwrite_internal (const Octave_object& args, int nargout)
  1758. {
  1759.   Octave_object retval;
  1760.  
  1761.   int nargin = args.length ();
  1762.  
  1763.   Pix p = file_io_get_file (args(0), "a+", "fwrite");
  1764.  
  1765.   if (! p)
  1766.     return retval;
  1767.  
  1768. // Get type and number of bytes per element to read.
  1769.   char *prec = "uchar";
  1770.   if (nargin > 2)
  1771.     {
  1772.       prec = args(2).string_value ();
  1773.  
  1774.       if (error_state)
  1775.     {
  1776.       error ("fwrite: precision must be a specified as a string");
  1777.       return retval;
  1778.     }
  1779.     }
  1780.  
  1781.   file_info file = file_list (p);
  1782.  
  1783.   Matrix m = args(1).matrix_value ();
  1784.  
  1785.   if (! error_state)
  1786.     {
  1787.       int count = m.write (file.fptr (), prec);
  1788.  
  1789.       retval(0) = (double) count;
  1790.     }
  1791.  
  1792.   return retval;
  1793. }
  1794.  
  1795. DEFUN ("feof", Ffeof, Sfeof, 1, 1,
  1796.   "ERROR = feof (FILENAME or FILENUM)\n\
  1797. \n\
  1798.  Returns a non zero value for an end of file condition for the\n\
  1799.  file specified by FILENAME or FILENUM from fopen")
  1800. {
  1801.   Octave_object retval;
  1802.  
  1803.   int nargin = args.length ();
  1804.  
  1805.   if (nargin != 1)
  1806.     print_usage ("feof");
  1807.   else
  1808.     retval = feof_internal (args, nargout);
  1809.  
  1810.   return retval;
  1811. }
  1812.  
  1813. // Check for an EOF condition on a file opened by fopen.
  1814. //
  1815. //   eof = feof (fid)
  1816. //
  1817. //     fid : file id from fopen
  1818. //     eof : non zero for an end of file condition
  1819.  
  1820. Octave_object
  1821. feof_internal (const Octave_object& args, int nargout)
  1822. {
  1823.   Octave_object retval;
  1824.  
  1825. // Get file info.
  1826.   Pix p = return_valid_file (args(0));
  1827.  
  1828.   if (! p)
  1829.     return retval;
  1830.  
  1831.   file_info file = file_list (p);
  1832.  
  1833.   retval(0) = (double) feof (file.fptr ());
  1834.  
  1835.   return retval;
  1836. }
  1837.  
  1838. DEFUN ("ferror", Fferror, Sferror, 1, 1,
  1839.   "ERROR = ferror (FILENAME or FILENUM)\n\
  1840. \n\
  1841.  Returns a non zero value for an error condition on the\n\
  1842.  file specified by FILENAME or FILENUM from fopen")
  1843. {
  1844.   Octave_object retval;
  1845.  
  1846.   int nargin = args.length ();
  1847.  
  1848.   if (nargin != 1)
  1849.     print_usage ("ferror");
  1850.   else
  1851.     retval = ferror_internal (args, nargout);
  1852.  
  1853.   return retval;
  1854. }
  1855.  
  1856. // Check for an error condition on a file opened by fopen.
  1857. //
  1858. //   [message, errnum] = ferror (fid)
  1859. //
  1860. //     fid     : file id from fopen
  1861. //     message : system error message
  1862. //     errnum  : error number
  1863.  
  1864. Octave_object
  1865. ferror_internal (const Octave_object& args, int nargout)
  1866. {
  1867.   Octave_object retval;
  1868.  
  1869. // Get file info.
  1870.   Pix p = return_valid_file (args(0));
  1871.  
  1872.   if (! p)
  1873.     return retval;
  1874.  
  1875.   file_info file = file_list (p);
  1876.  
  1877.   int ierr = ferror (file.fptr ());
  1878.  
  1879.   if (nargout > 1)
  1880.     retval(1) = (double) ierr;
  1881.  
  1882.   retval(0) = strsave (strerror (ierr));
  1883.  
  1884.   return retval;
  1885. }
  1886.  
  1887. /*
  1888. ;;; Local Variables: ***
  1889. ;;; mode: C++ ***
  1890. ;;; page-delimiter: "^/\\*" ***
  1891. ;;; End: ***
  1892. */
  1893.