changeset 21622:fed1111e1899

textscan: eliminate ReturnOnError="continue" mode (bug #47538) * oct-stream.cc (textscan_format_list::read_first_row, textscan::scan_one) No longer skip failed fields. (textscan::do_scan): Do not terminate on no_conversions. (textscan::read_format_once): Only "fail" if field wasn't empty. (textscan::parse_options): No longer parse "continue" option. * file-io.cc (Ftextscan): Update docstring and self-tests.
author Lachlan Andrew <lachlanbis@gmail.com>
date Sun, 10 Apr 2016 19:49:50 +1000
parents fe0a6de805e4
children 555b6c78d677
files libinterp/corefcn/file-io.cc libinterp/corefcn/oct-stream.cc
diffstat 2 files changed, 23 insertions(+), 69 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/file-io.cc	Tue Apr 12 21:05:50 2016 +1000
+++ b/libinterp/corefcn/file-io.cc	Sun Apr 10 19:49:50 2016 +1000
@@ -1337,8 +1337,7 @@
 @item literals\n\
 In addition the format may contain literal character strings; these will be\n\
 skipped during reading.  If the input string does not match this literal,\n\
-the processing terminates, unless @qcode{\"ReturnOnError\"} is set to\n\
-@qcode{\"continue\"}.\n\
+the processing terminates.\n\
 @end table\n\
 \n\
 Parsed words corresponding to the first specifier are returned in the first\n\
@@ -1456,10 +1455,8 @@
 \n\
 @item @qcode{\"ReturnOnError\"}\n\
 If set to numerical 1 or true, return normally as soon as an error is\n\
-encountered, such as trying to read a string using @qcode{%f}.  If set to 0\n\
-or false, return an error and no data.  If set to @qcode{\"continue\"}\n\
-(default), textscan attempts to continue reading beyond the location;\n\
-however, this may cause the parsing to get out of sync.\n\
+encountered, such as trying to read a string using @qcode{%f}.\n\
+If set to 0 or false, return an error and no data.\n\
 \n\
 @item @qcode{\"Whitespace\"}\n\
 Any character in @var{value} will be interpreted as whitespace and trimmed;\n\
@@ -1690,18 +1687,13 @@
 %! str = "1 2 3\n4 s 6";
 %! fprintf (fid, str);
 %! fseek (fid, 0, "bof");
-%! c = textscan (fid, "%f %f %f");
-%! fseek (fid, 0, "bof");
-%! d = textscan (fid, "%f %f %f", "ReturnOnError", 1);
+%! c = textscan (fid, "%f %f %f", "ReturnOnError", 1);
 %! fseek (fid, 0, "bof");
 %! fclose (fid);
 %! unlink (f);
-%! u = textscan (str, "%f %f %f");
-%! v = textscan (str, "%f %f %f", "ReturnOnError", 1);
-%! assert (c, {[1;4], [2;NaN], [3;6]});
-%! assert (d, {[1;4], [2], [3]});
-%! assert (u, {[1;4], [2;NaN], [3;6]});
-%! assert (v, {[1;4], [2], [3]});
+%! u = textscan (str, "%f %f %f", "ReturnOnError", 1);
+%! assert (c, {[1;4], [2], [3]});
+%! assert (u, {[1;4], [2], [3]});
 
 %!test
 %! ## Check ReturnOnError
@@ -1726,14 +1718,11 @@
 %! fid = fopen (f, "w+");
 %! fprintf (fid, "1 s 3\n4 5 6");
 %! fseek (fid, 0, "bof");
-%! c = textscan (fid, "");
-%! fseek (fid, 0, "bof");
-%! d = textscan (fid, "", "ReturnOnError", 1);
+%! c = textscan (fid, "", "ReturnOnError", 1);
 %! fseek (fid, 0, "bof");
 %! fclose (fid);
 %! unlink (f);
-%! assert (c, {[1;4], [NaN;5], [3;6]});
-%! assert (d, {1});
+%! assert (c, {1});
 
 %!test
 %! ## Check ReturnOnError with empty fields
--- a/libinterp/corefcn/oct-stream.cc	Tue Apr 12 21:05:50 2016 +1000
+++ b/libinterp/corefcn/oct-stream.cc	Sun Apr 10 19:49:50 2016 +1000
@@ -2459,31 +2459,15 @@
           if (ds.eof ())
             break;
 
-          // If we don't continue after a conversion error, then
-          // unless this was a missing value (i.e., followed by a delimiter),
+          // Unless this was a missing value (i.e., followed by a delimiter),
           // return with an error status.
-          if (ts.return_on_error < 2)
+          ts.skip_delim (ds);
+          if (ds.no_progress ())
             {
-              ts.skip_delim (ds);
-              if (ds.no_progress ())
-                {
-                  retval = 4;
-                  break;
-                }
-              already_skipped_delim = true;
+              retval = 4;
+              break;
             }
-          else  // skip offending field
-            {
-              std::ios::iostate state = ds.rdstate ();
-              ds.clear ();          // clear to allow read pointer to advance
-
-              std::string dummy;
-              textscan_format_elt fe ("", first_line.length ());
-              ts.scan_string (ds, fe, dummy);
-
-              progress = (dummy.length ());
-              ds.setstate (state);
-            }
+          already_skipped_delim = true;
 
           val = ts.empty_value.scalar_value ();
 
@@ -2534,7 +2518,7 @@
     empty_value (octave_NaN), exp_chars ("edED"),
     header_lines (0), treat_as_empty (), treat_as_empty_len (0),
     whitespace (" \b\t"), eol1 ('\r'), eol2 ('\n'),
-    return_on_error (2), collect_output (false),
+    return_on_error (1), collect_output (false),
     multiple_delims_as_one (false), default_exp (true),
     numeric_delim (false), lines (0)
 { }
@@ -2674,7 +2658,7 @@
           row_idx(0) = row;
           err = read_format_once (is, fmt_list, out, row_idx, done_after);
 
-          if (err > 0 || ! is || (lines >= ntimes && ntimes > -1))
+          if ((err & ~1) > 0 || ! is || (lines >= ntimes && ntimes > -1))
             break;
         }
     }
@@ -3393,24 +3377,8 @@
               }
         }
 
-      if (is.fail ())
-        {
-          if (! fmt.discard)
-            ov = do_cat_op (ov, empty_value, row);
-
-          // If we are continuing after errors, skip over this field
-          if (return_on_error == 2)
-            {
-              std::ios::iostate state = is.rdstate ();
-              is.clear ();          // clear to allow read pointer to advance
-
-              std::string dummy;
-              scan_string (is, fmt, dummy);
-
-              is.setstate (state);
-            }
-        }
-
+      if (is.fail () & ! fmt.discard)
+        ov = do_cat_op (ov, empty_value, row);
     }
   else
     {
@@ -3510,10 +3478,10 @@
         }
       else
         {
-          if (return_on_error < 2)
+          is.clear (is.rdstate () & ~std::ios::failbit);
+
+          if (!is.eof () && ~is_delim (is.peek ()))
             this_conversion_failed = true;
-
-          is.clear (is.rdstate () & ~std::ios::failbit);
         }
 
       if (! elem->discard)
@@ -3696,10 +3664,7 @@
         }
       else if (param == "returnonerror")
         {
-          if (args(i+1).is_string () && args(i+1).string_value () == "continue")
-            return_on_error = 2;
-          else
-            return_on_error = args(i+1).xbool_value ("%s: ReturnOnError must be logical, numeric, or the string \"continue\"", who.c_str ());
+          return_on_error = args(i+1).xbool_value ("%s: ReturnOnError must be logical or numeric", who.c_str ());
         }
       else if (param == "whitespace")
         {