changeset 2215:ab0e1fd337f5

[project @ 1996-05-16 15:56:40 by jwe]
author jwe
date Thu, 16 May 1996 15:56:40 +0000
parents b5c7309168f3
children 59740768906f
files src/file-io.cc src/oct-stream.cc src/oct-stream.h
diffstat 3 files changed, 467 insertions(+), 108 deletions(-) [+]
line wrap: on
line diff
--- a/src/file-io.cc	Thu May 16 15:49:42 1996 +0000
+++ b/src/file-io.cc	Thu May 16 15:56:40 1996 +0000
@@ -592,16 +592,19 @@
 \n\
 If it is omitted, a value of Inf is assumed.\n\
 \n\
-The number of items successfully read is returned in COUNT")
+The number of items successfully read is returned in COUNT.\n\
+\n\
+[A, B, ...] = fscanf (FILENUM, FORMAT, \"C\")\n\
+\n\
+Read from FILENUM according to FORMAT, with each conversion specifier\n\
+in FORMAT corresponding to a single scalar return value.  This form is\n\
+more `C-like', and also compatible with previous versions of Octave")
 {
   octave_value_list retval;
 
-  retval (1) = 0.0;
-  retval (0) = Matrix ();
-
   int nargin = args.length ();
 
-  if (nargin == 2 || nargin == 3)
+  if (nargin == 3 && args(2).is_string ())
     {
       octave_stream *os = octave_stream_list::lookup (args(0));
 
@@ -611,18 +614,7 @@
 	    {
 	      string fmt = args(1).string_value ();
 
-	      int count = 0;
-
-	      Matrix size = (nargin == 3)
-		? args(2).matrix_value () : Matrix (1, 1, octave_Inf);
-
-	      if (! error_state)
-		{
-		  octave_value tmp = os->scanf (fmt, size, count);
-
-		  retval(1) = (double) count;
-		  retval(0) = tmp;
-		}
+	      retval = os->oscanf (fmt);
 	    }
 	  else
 	    ::error ("fscanf: format must be a string");
@@ -631,7 +623,42 @@
 	gripe_invalid_file_id ("fscanf");
     }
   else
-    print_usage ("fscanf");
+    {
+      retval (1) = 0.0;
+      retval (0) = Matrix ();
+
+      if (nargin == 2 || nargin == 3)
+	{
+	  octave_stream *os = octave_stream_list::lookup (args(0));
+
+	  if (os)
+	    {
+	      if (args(1).is_string ())
+		{
+		  string fmt = args(1).string_value ();
+
+		  int count = 0;
+
+		  Matrix size = (nargin == 3)
+		    ? args(2).matrix_value () : Matrix (1, 1, octave_Inf);
+
+		  if (! error_state)
+		    {
+		      octave_value tmp = os->scanf (fmt, size, count);
+
+		      retval(1) = (double) count;
+		      retval(0) = tmp;
+		    }
+		}
+	      else
+		::error ("fscanf: format must be a string");
+	    }
+	  else
+	    gripe_invalid_file_id ("fscanf");
+	}
+      else
+	print_usage ("fscanf");
+    }
 
   return retval;
 }
@@ -639,7 +666,7 @@
 DEFUN (sscanf, args, ,
   "[A, COUNT, ERRMSG, INDEX] = sscanf (STRING, FORMAT, SIZE)\n\
 \n\
-Read from FILENUM according to FORMAT, returning the result in the\n\
+Read from STRING according to FORMAT, returning the result in the\n\
 matrix A.  SIZE is optional.  If present, it can be one of\n\
 \n\
        Inf : read as much as possible, returning a column vector\n\
@@ -654,19 +681,20 @@
 The number of items successfully read is returned in COUNT.  If an\n\
 error occurs, ERRMSG contains the text of the corresponding error\n\
 message.  INDEX contains the index of the next character to be read\n\
-from STRING")
+from STRING\n\
+\n\
+[A, B, ...] = sscanf (STRING, FORMAT, \"C\")\n\
+\n\
+Read from STRING according to FORMAT, with each conversion specifier\n\
+in FORMAT corresponding to a single scalar return value.  This form is\n\
+more `C-like', and also compatible with previous versions of Octave")
 {
   octave_value_list retval;
 
   int nargin = args.length ();
 
-  if (nargin == 2 || nargin == 3)
+  if (nargin == 3 && args(2).is_string ())
     {
-      retval(3) = -1.0;
-      retval(2) = "unknown error";
-      retval(1) = 0.0;
-      retval(0) = Matrix ();
-
       if (args(0).is_string ())
 	{
 	  string data = args(0).string_value ();
@@ -681,22 +709,7 @@
 		{
 		  string fmt = args(1).string_value ();
 
-		  int count = 0;
-
-		  Matrix size = (nargin == 3)
-		    ? args(2).matrix_value () : Matrix (1, 1, octave_Inf);
-
-		  octave_value tmp = os.scanf (fmt, size, count);
-
-		  // XXX FIXME XXX -- is this the right thing to do?
-		  // Extract error message first, because getting
-		  // position will clear it.
-		  string errmsg = os.error ();
-
-		  retval(3) = (double) (os.tell () + 1);
-		  retval(2) = errmsg;
-		  retval(1) = (double) count;
-		  retval(0) = tmp;
+		  retval = os.oscanf (fmt);
 		}
 	      else
 		::error ("sscanf: format must be a string");
@@ -708,11 +721,75 @@
 	::error ("sscanf: first argument must be a string");
     }
   else
-    print_usage ("sscanf");
+    {
+      if (nargin == 2 || nargin == 3)
+	{
+	  retval(3) = -1.0;
+	  retval(2) = "unknown error";
+	  retval(1) = 0.0;
+	  retval(0) = Matrix ();
+
+	  if (args(0).is_string ())
+	    {
+	      string data = args(0).string_value ();
+
+	      octave_istrstream istr (data);
+
+	      octave_stream os (&istr, true);
+
+	      if (os)
+		{
+		  if (args(1).is_string ())
+		    {
+		      string fmt = args(1).string_value ();
+
+		      int count = 0;
+
+		      Matrix size = (nargin == 3)
+			? args(2).matrix_value () : Matrix (1, 1, octave_Inf);
+
+		      octave_value tmp = os.scanf (fmt, size, count);
+
+		      // XXX FIXME XXX -- is this the right thing to do?
+		      // Extract error message first, because getting
+		      // position will clear it.
+		      string errmsg = os.error ();
+
+		      retval(3) = (double) (os.tell () + 1);
+		      retval(2) = errmsg;
+		      retval(1) = (double) count;
+		      retval(0) = tmp;
+		    }
+		  else
+		    ::error ("sscanf: format must be a string");
+		}
+	      else
+		::error ("sscanf: unable to create temporary input buffer");
+	    }
+	  else
+	    ::error ("sscanf: first argument must be a string");
+	}
+      else
+	print_usage ("sscanf");
+    }
 
   return retval;
 }
 
+DEFUN (scanf, args, nargout,
+  "scanf (FORMAT) is equivalent to fscanf (stdin, FORMAT)")
+{
+  int nargin = args.length ();
+
+  octave_value_list tmp_args (nargin+1, octave_value ());
+
+  tmp_args (0) = 0.0;
+  for (int i = 0; i < nargin; i++)
+    tmp_args (i+1) = args (i);
+
+  return Ffscanf (tmp_args, nargout);
+}
+
 static octave_value
 do_fread (octave_stream& os, const octave_value& size_arg,
 	  const octave_value& prec_arg, const octave_value& skip_arg,
--- a/src/oct-stream.cc	Thu May 16 15:49:42 1996 +0000
+++ b/src/oct-stream.cc	Thu May 16 15:56:40 1996 +0000
@@ -24,6 +24,8 @@
 #include <config.h>
 #endif
 
+#include <cstring>
+
 #include <iomanip.h>
 #include <strstream.h>
 
@@ -149,6 +151,7 @@
 
   int i = 0;
 
+  int width = 0;
   bool discard = false;
   char modifier = '\0';
   char type = '\0';
@@ -164,11 +167,13 @@
 
       if (s[i] == '%')
 	{
-	  process_conversion (s, i, n, discard, type, modifier, num_elts);
+	  process_conversion (s, i, n, width, discard, type, modifier,
+			      num_elts);
 	  have_more = (buf != 0);
 	}
       else
 	{
+	  width = 0;
 	  discard = false;
 	  modifier = '\0';
 	  type = '\0';
@@ -183,7 +188,7 @@
     }
 
   if (have_more)
-    add_elt_to_list (discard, type, modifier, num_elts);
+    add_elt_to_list (width, discard, type, modifier, num_elts);
 
   list.resize (num_elts);
 
@@ -202,7 +207,7 @@
 }
 
 void
-scanf_format_list::add_elt_to_list (bool discard, char type,
+scanf_format_list::add_elt_to_list (int width, bool discard, char type,
 				    char modifier, int& num_elts)
 {
   if (buf)
@@ -216,7 +221,7 @@
 	  if (*text)
 	    {
 	      scanf_format_elt *elt
-		= new scanf_format_elt (text, discard, type, modifier);
+		= new scanf_format_elt (text, width, discard, type, modifier);
 
 	      if (num_elts == list.length ())
 		list.resize (2 * num_elts);
@@ -234,10 +239,11 @@
 
 void
 scanf_format_list::process_conversion (const string& s, int& i, int n,
-				       bool& discard, char& type,
+				       int& width, bool& discard, char& type,
 				       char& modifier, int& num_elts)
 
 {
+  width = 0;
   discard = false;
   modifier = '\0';
   type = '\0';
@@ -266,10 +272,16 @@
 	    nconv = -1;
 	  else
 	    {
+	      char c = s[i++];
+	      width = width * 10 + c - '0';
 	      have_width = true;
-	      *buf << s[i++];
+	      *buf << c;
 	      while (i < n && isdigit (s[i]))
-		*buf << s[i++];
+		{
+		  c = s[i++];
+		  width = width * 10 + c - '0';
+		  *buf << c;
+		}
 	    }
 	  break;
 
@@ -309,7 +321,7 @@
 
 	fini:
 	  {
-	    if (finish_conversion (s, i, n, discard, type,
+	    if (finish_conversion (s, i, n, width, discard, type,
 				   modifier, num_elts) == 0)
 	      return;
 	  }
@@ -329,7 +341,7 @@
 
 int
 scanf_format_list::finish_conversion (const string& s, int& i, int n,
-				      bool discard, char& type,
+				      int& width, bool discard, char& type,
 				      char modifier, int& num_elts)
 {
   int retval = 0;
@@ -365,23 +377,12 @@
 	    retval = nconv = -1;
 	}
       else
-	{
-	  // XXX FIXME XXX -- this is a kludge, and probably not the
-	  // right thing to do here.
-
-	  if (type == 's')
-	    {
-	      *buf << 'c';
-	      i++;
-	    }
-	  else
-	    *buf << s[i++];
-	}
+	*buf << s[i++];
 
       nconv++;
 
       if (nconv > 0)
-	add_elt_to_list (discard, type, modifier, num_elts);
+	add_elt_to_list (width, discard, type, modifier, num_elts);
     }
 
   return retval;
@@ -396,7 +397,8 @@
     {
       scanf_format_elt *elt = list.elem (i);
 
-      cerr << elt->discard << "\t"
+      cerr << elt->width << "\t"
+	   << elt->discard << "\t"
 	   << elt->type << "\t"
 	   << elt->modifier << "\t"
 	   << undo_string_escapes (elt->text) << "\n";
@@ -742,7 +744,7 @@
 
   if (isp)
     {
-      istream is = *isp;
+      istream& is = *isp;
 
       // XXX FIXME XXX -- this should probably be converted to use
       // sstream when that is available.
@@ -867,7 +869,7 @@
 
   if (isp)
     {
-      istream is = *isp;
+      istream& is = *isp;
 
       for (;;)
 	{
@@ -1037,8 +1039,6 @@
 #define do_scanf_conv(is, fmt, valptr, mval, data, idx, max_size, discard) \
   do \
     { \
-      is.clear (); \
- \
       is.scan (fmt, valptr); \
  \
       if (is) \
@@ -1104,7 +1104,7 @@
 
   if (isp)
     {
-      istream is = *isp;
+      istream& is = *isp;
 
       const scanf_format_elt *elt = fmt_list.first ();
 
@@ -1112,11 +1112,6 @@
 
       for (;;)
 	{
-	  // Restore format flags in case we had to change them (note
-	  // 'c' conversion below).
-
-	  is.setf (flags);
-
 	  if (elt)
 	    {
 	      if (nr > 0 && nc > 0 && count == max_size)
@@ -1137,8 +1132,7 @@
 		  {
 		    int dummy;
 
-		    do_scanf_conv (is, fmt, &dummy, mval, data, count,
-				   max_size, discard);
+		    is.scan (fmt, &dummy);
 		  }
 		  break;
 
@@ -1176,15 +1170,55 @@
 
 		case 's':
 		  {
-		    char tmp;
-
-		    do_scanf_conv (is, fmt, &tmp, mval, data, count,
-				   max_size, discard);
+		    int len = strlen (fmt);
+		    char *tmp_fmt = new char [len+1];
+		    strcpy (tmp_fmt, fmt);
+		    if (tmp_fmt[len-1] == 's')
+		      tmp_fmt[len-1] = 'c';
+
+		    int width = elt->width ? elt->width : 1;
+
+		    char *tmp = new char [width+1];
+
+		    is.scan (tmp_fmt, tmp);
+
+		    delete [] tmp_fmt;
+
+		    tmp[width] = '\0';
+
+		    if (is)
+		      {
+			int i = 0;
+
+			if (! discard)
+			  {
+			    while (i < width && tmp[i] != '\0')
+			      {
+				if (count == max_size)
+				  {
+				    max_size *= 2;
+
+				    if (nr > 0)
+				      mval.resize (nr, max_size / nr, 0.0);
+				    else
+				      mval.resize (max_size, 1, 0.0);
+
+				    data = mval.fortran_vec ();
+				  }
+
+				data[count++] = tmp[i++];
+			      }
+			  }
+		      }
+
+		    delete [] tmp;
+
+		    is.setf (flags);
 		  }
 		  break;
 
 		case 'p': case '[':
-		  error ("fscanf: unrecognized format specifier");
+		  error ("fscanf: unsupported format specifier");
 		  break;
 
 		default:
@@ -1273,10 +1307,6 @@
 octave_base_stream::scanf (const string& fmt, const Matrix& size,
 			   int& count)
 {
-  // XXX FIXME XXX -- is this the right thing to do?
-  if (name () == "stdin")
-    fail = false;
-
   octave_value retval = Matrix ();
 
   count = 0;
@@ -1285,7 +1315,7 @@
 
   if (isp)
     {
-      istream is = *isp;
+      istream& is = *isp;
 
       scanf_format_list fmt_list (fmt);
 
@@ -1310,6 +1340,221 @@
 		    error ("fscanf: read error");
 
 		    // XXX FIXME XXX -- is this the right thing to do?
+
+		    if (name () == "stdin")
+		      {
+			is.clear ();
+
+			// Skip to end of line.
+
+			bool err;
+			do_gets (-1, err, false, "fscanf");
+		      }
+		  }
+	      }
+	  }
+	  break;
+
+	default:
+	  {
+	    int nr = -1;
+	    int nc = -1;
+
+	    get_size (size, nr, nc, "fscanf");
+
+	    if (! error_state)
+	      retval = do_scanf (fmt_list, nr, nc, count);
+	  }
+	  break;
+	}
+    }
+  else
+    invalid_operation ("fscanf", "writing");
+
+  return retval;
+}
+
+#define do_oscanf_num_conv(is, fmt, valptr) \
+  do \
+    { \
+      streambuf *isb = is.rdbuf (); \
+ \
+      if (isb->scan (fmt, valptr) > 0) \
+	{ \
+	  if (! discard && is) \
+	    retval = (double) (*valptr); \
+	} \
+      else \
+	error ("fscanf: conversion failed"); \
+    } \
+  while (0)
+
+#define do_oscanf_str_conv(is, fmt, sptr, maxlen) \
+  do \
+    { \
+      streambuf *isb = is.rdbuf (); \
+ \
+      if (isb->scan (fmt, sptr) > 0) \
+	{ \
+	  if (! discard && is) \
+	    { \
+	      sptr[maxlen] = '\0'; \
+	      retval = sptr; \
+	    } \
+	} \
+      else \
+	error ("fscanf: conversion failed"); \
+    } \
+  while (0)
+
+octave_value
+octave_base_stream::do_oscanf (const scanf_format_elt *elt)
+{
+  octave_value retval = Matrix ();
+
+  istream *isp = input_stream ();
+
+  if (isp)
+    {
+      istream& is = *isp;
+
+      ios::fmtflags flags = is.flags ();
+
+      if (elt)
+	{
+	  const char *fmt = elt->text;
+
+	  bool discard = elt->discard;
+
+	  switch (elt->type)
+	    {
+	    case '%':
+	      {
+		int dummy;
+
+		is.scan (fmt, &dummy);
+	      }
+	      break;
+
+	    case 'd': case 'i': case 'o': case 'u': case 'x':
+	      {
+		int tmp;
+
+		do_oscanf_num_conv (is, fmt, &tmp);
+	      }
+	      break;
+
+	    case 'e': case 'f': case 'g':
+	      {
+		if (elt->modifier == 'l')
+		  {
+		    double tmp;
+
+		    do_oscanf_num_conv (is, fmt, &tmp);
+		  }
+		else
+		  {
+		    float tmp;
+
+		    do_oscanf_num_conv (is, fmt, &tmp);
+		  }
+	      }
+	      break;
+
+	    case 'c':
+	      {
+		is.unsetf (ios::skipws);
+
+		int width = elt->width ? elt->width : 1;
+
+		char *tmp = new char[width + 1];
+
+		do_oscanf_str_conv (is, fmt, tmp, width);
+
+		is.setf (flags);
+
+		delete [] tmp;
+	      }
+	      break;
+
+	    case 's':
+	      {
+		// XXX FIXME XXX -- this must be fixed!
+
+		int width = 65535;
+		char *tmp = new char [width+1];
+		do_oscanf_str_conv (is, fmt, tmp, width);
+		delete [] tmp;
+	      }
+	      break;
+
+	    case 'p': case '[':
+	      error ("fscanf: unsupported format specifier");
+	      break;
+
+	    default:
+	      error ("fscanf: internal format error");
+	      break;
+	    }
+	}
+
+      if (ok () && is.fail ())
+	{
+	  error ("fscanf: read error");
+      
+	  // XXX FIXME XXX -- is this the right thing to do?
+	  // What about other streams?
+	  if (name () == "stdin")
+	    {
+	      is.clear ();
+
+	      // Skip to end of line.
+
+	      bool err;
+	      do_gets (-1, err, false, "fscanf");
+	    }
+	}
+    }
+
+  return retval;
+}
+
+octave_value_list
+octave_base_stream::oscanf (const string& fmt)
+{
+  octave_value_list retval;
+
+  istream *isp = input_stream ();
+
+  if (isp)
+    {
+      istream& is = *isp;
+
+      scanf_format_list fmt_list (fmt);
+
+      int nconv = fmt_list.num_conversions ();
+
+      switch (nconv)
+	{
+	case -1:
+	  ::error ("fscanf: invalid format specified");
+	  break;
+
+	case 0:
+	  {
+	    const scanf_format_elt *elt = fmt_list.first ();
+
+	    if (elt)
+	      {
+		is.clear ();
+
+		is.scan (elt->text);
+
+		if (! is)
+		  {
+		    error ("fscanf: read error");
+
+		    // XXX FIXME XXX -- is this the right thing to do?
 		    // Maybe.  We should probably also arrange to
 		    // flush the pending input prior to printing a
 		    // prompt.  Or maybe just blow off scanf for stdin
@@ -1331,13 +1576,25 @@
 
 	default:
 	  {
-	    int nr = -1;
-	    int nc = -1;
-
-	    get_size (size, nr, nc, "fscanf");
-
-	    if (! error_state)
-	      retval = do_scanf (fmt_list, nr, nc, count);
+	    int len = fmt_list.length ();
+
+	    retval.resize (nconv, Matrix ());
+
+	    const scanf_format_elt *elt = fmt_list.first ();
+
+	    for (int i = 0; i < nconv; i++)
+	      {
+		retval (i) = do_oscanf (elt);
+
+		if (! ok ())
+		  break;
+
+		elt = fmt_list.next ();
+	      }
+
+	    // Pick up any trailing stuff.
+	    if (ok () && len > nconv)
+	      do_oscanf (elt);
 	  }
 	  break;
 	}
@@ -1393,7 +1650,7 @@
 
   if (osp)
     {
-      ostream os = *osp;
+      ostream& os = *osp;
 
       // XXX FIXME XXX -- maybe there should be a special case for
       // skip == 0.
@@ -1714,7 +1971,7 @@
 
   if (osp)
     {
-      ostream os = *osp;
+      ostream& os = *osp;
 
       const printf_format_elt *elt = fmt_list.first ();
 
@@ -1844,7 +2101,7 @@
 
   if (osp)
     {
-      ostream os = *osp;
+      ostream& os = *osp;
 
       printf_format_list fmt_list (fmt);
 
@@ -1895,7 +2152,7 @@
 
   if (osp)
     {
-      ostream os = *osp;
+      ostream& os = *osp;
 
       os << s;
 
@@ -2146,6 +2403,17 @@
   return retval;
 }
 
+octave_value_list
+octave_stream::oscanf (const string& fmt)
+{
+  octave_value_list retval;
+
+  if (stream_ok ("fscanf"))
+    retval = rep->oscanf (fmt);
+
+  return retval;
+}
+
 int
 octave_stream::printf (const string& fmt, const octave_value_list& args)
 {
@@ -2205,8 +2473,6 @@
   if (stream_ok ("ferror", false))
     retval = rep->error (clear, errno);
 
-  cerr << retval;
-
   return retval;
 }
 
--- a/src/oct-stream.h	Thu May 16 15:49:42 1996 +0000
+++ b/src/oct-stream.h	Thu May 16 15:56:40 1996 +0000
@@ -36,13 +36,14 @@
 struct
 scanf_format_elt
 {
-  scanf_format_elt (const char *txt = 0, bool d = false,
+  scanf_format_elt (const char *txt = 0, int w = 0, bool d = false,
 		    char typ = '\0', char mod = '\0')
-    : text (txt), discard (d), type (typ), modifier (mod) { }
+    : text (txt), width (w), discard (d), type (typ), modifier (mod) { }
 
   ~scanf_format_elt (void) { delete text; }
 
   const char *text;
+  int width;
   bool discard;
   char type;
   char modifier;
@@ -59,6 +60,13 @@
 
   int num_conversions (void) { return nconv; }
 
+  // The length can be different than the number of conversions.
+  // For example, "x %d y %d z" has 2 conversions but the length of
+  // the list is 3 because of the characters that appear after the
+  // last conversion.
+
+  int length (void) { return list.length (); }
+
   const scanf_format_elt *first (void)
     {
       curr_idx = 0;
@@ -101,14 +109,16 @@
   // Temporary buffer.
   ostrstream *buf;
 
-  void add_elt_to_list (bool discard, char type, char modifier,
+  void add_elt_to_list (int width, bool discard, char type, char modifier,
 			int& num_elts);
 
-  void process_conversion (const string& s, int& i, int n, bool& discard,
-			   char& type, char& modifier, int& num_elts);
+  void process_conversion (const string& s, int& i, int n, int& width,
+			   bool& discard, char& type, char& modifier,
+			   int& num_elts);
 
-  int finish_conversion (const string& s, int& i, int n, bool discard,
-			 char& type, char modifier, int& num_elts);
+  int finish_conversion (const string& s, int& i, int n, int& width,
+			 bool discard, char& type, char modifier,
+			 int& num_elts);
   // No copying!
 
   scanf_format_list (const scanf_format_list&);
@@ -326,6 +336,10 @@
 
   octave_value scanf (const string& fmt, const Matrix& size, int& count);
 
+  octave_value do_oscanf (const scanf_format_elt *elt);
+
+  octave_value_list oscanf (const string& fmt);
+
   // Functions that are defined for all output streams (output streams
   // are those that define os).
 
@@ -397,6 +411,8 @@
 
   octave_value scanf (const string& fmt, const Matrix& size, int& count);
 
+  octave_value_list oscanf (const string& fmt);
+
   int printf (const string& fmt, const octave_value_list& args);
 
   int puts (const string& s);