changeset 27137:30f53f7a7293

Return correct error messages on octave-streams when scanf fails (bug #56396) * file-io.cc (Fsscanf): Add BIST test for bug #56396. * oct-stream.cc (base_stream::do_scanf): Perform end-of-scan processing if EOF has been detected, not just when FAILBIT has been set. If FAILBIT has been set, call error() to set an error message on the octave-stream. At end of function, assign any partial results obtained to output. Don't require that all conversions were successful. * io.tst: Update BIST tests to reflect new Matlab-compatible behavior for error message output.
author Rik <rik@octave.org>
date Mon, 03 Jun 2019 09:04:41 -0700
parents 512399fefc1b
children 9e5c1d343a2c
files libinterp/corefcn/file-io.cc libinterp/corefcn/oct-stream.cc test/io.tst
diffstat 3 files changed, 23 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/file-io.cc	Sat Jun 01 21:01:45 2019 -0700
+++ b/libinterp/corefcn/file-io.cc	Mon Jun 03 09:04:41 2019 -0700
@@ -1166,6 +1166,15 @@
   return retval;
 }
 
+/*
+%!test <*56396>
+%! [val, count, errmsg, nextpos] = sscanf ('1234a6', '%2d', 3);
+%! assert (val, [12; 34]);
+%! assert (count, 2);
+%! assert (errmsg, "sscanf: format failed to match");
+%! assert (nextpos, 5);
+*/
+
 DEFMETHOD (scanf, interp, args, ,
            doc: /* -*- texinfo -*-
 @deftypefn  {} {[@var{val}, @var{count}, @var{errmsg}] =} scanf (@var{template}, @var{size})
--- a/libinterp/corefcn/oct-stream.cc	Sat Jun 01 21:01:45 2019 -0700
+++ b/libinterp/corefcn/oct-stream.cc	Mon Jun 03 09:04:41 2019 -0700
@@ -4903,7 +4903,7 @@
                   {
                     break;
                   }
-                else if (! is)
+                else if (is.eof () || ! is)
                   {
                     if (all_char_conv)
                       {
@@ -4945,7 +4945,10 @@
                     // If it looks like we have a matching failure, then
                     // reset the failbit in the stream state.
                     if (is.rdstate () & std::ios::failbit)
-                      is.clear (is.rdstate () & (~std::ios::failbit));
+                      {
+                        error (who, "format failed to match");
+                        is.clear (is.rdstate () & (~std::ios::failbit));
+                      }
 
                     // FIXME: is this the right thing to do?
                     if (application::interactive ()
@@ -4996,15 +4999,12 @@
           }
       }
 
-    if (ok ())
-      {
-        mval.resize (final_nr, final_nc, 0.0);
-
-        retval = mval;
-
-        if (all_char_conv)
-          retval = retval.convert_to_str (false, true);
-      }
+    mval.resize (final_nr, final_nc, 0.0);
+
+    retval = mval;
+
+    if (all_char_conv)
+      retval = retval.convert_to_str (false, true);
 
     return retval;
   }
--- a/test/io.tst	Sat Jun 01 21:01:45 2019 -0700
+++ b/test/io.tst	Mon Jun 03 09:04:41 2019 -0700
@@ -336,7 +336,7 @@
 %! [val, count, msg, pos] = sscanf ("3I2", "%f");
 %! assert (val, 3);
 %! assert (count, 1);
-%! assert (msg, "");
+%! assert (msg, "sscanf: format failed to match");
 %! assert (pos, 2);
 
 %!xtest <47413>
@@ -345,14 +345,14 @@
 %! [val, count, msg, pos] = sscanf ("3I2", "%f");
 %! assert (val, 3);
 %! assert (count, 1);
-%! assert (msg, "");
+%! assert (msg, "sscanf: format failed to match");
 %! assert (pos, 2);
 
 %!testif ; ! ismac ()
 %! [val, count, msg, pos] = sscanf ("3In2", "%f");
 %! assert (val, 3);
 %! assert (count, 1);
-%! assert (msg, "");
+%! assert (msg, "sscanf: format failed to match");
 %! assert (pos, 2);
 
 %!xtest <47413>