changeset 27132:8ea53aa9ac39

Fix stream positioning when using scanf with widths (bug #56200). * oct-stream.cc (octave_scan (std::istream&, const scanf_format_elt&, T*)): Rename variable "tmp" to "strbuf" for clarity. Record position of input stream "is" in variable "orig_pos" before any operations. After scanning operation on stringstream object "ss" check whether eof() is set (full width of characters were used). If not, restore "is" position back to value at start of function. Find the number of characters read on stringstream object with tellg() and then re-perform the extraction operation on input stream with the "correct" width (number of characters). Copy the failbit from the "ss" object to the "is" object to propagate any pattern matching errors.
author Rik <rik@octave.org>
date Sat, 01 Jun 2019 08:56:51 -0700
parents acedcba362be
children fbe46901ae62
files libinterp/corefcn/oct-stream.cc
diffstat 1 files changed, 30 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/oct-stream.cc	Thu May 30 11:23:16 2019 +0000
+++ b/libinterp/corefcn/oct-stream.cc	Sat Jun 01 08:56:51 2019 -0700
@@ -4269,14 +4269,40 @@
       {
         // Limit input to fmt.width characters by reading into a
         // temporary stringstream buffer.
-        std::string tmp;
+        std::string strbuf;
+
+        auto orig_pos = is.tellg ();
 
         is.width (fmt.width);
-        is >> tmp;
-
-        std::istringstream ss (tmp);
+        is >> strbuf;
+
+        std::istringstream ss (strbuf);
 
         octave_scan_1 (ss, fmt, valptr);
+
+        if (! ss.eof ())
+          {
+            // If fewer characters than width were used to read a number then
+            // the original istream object positioning is incorrect.
+            // Rather than attempt to update istream state and positioning,
+            // just redo the '>>' operation with the correct width so that
+            // all flags get set correctly.
+
+            is.clear ();  // Clear EOF, FAILBIT, BADBIT
+            is.seekg (orig_pos, is.beg);
+
+            int chars_read = ss.tellg ();
+            if (chars_read > 0)
+              {
+                is.width (chars_read);
+                is >> strbuf;
+              }
+          }
+
+        // If pattern failed to match then propagate fail bit to 'is' stream.
+        if (ss.fail ())
+          is.setstate (std::ios::failbit);
+
       }
     else
       octave_scan_1 (is, fmt, valptr);