# HG changeset patch # User Rik # Date 1669134224 28800 # Node ID d006285b7509e8bd5428876897c8a9a7981a6a85 # Parent 2a12350f9410927f4607269643b861e50c424b53 Fix scanf handling of bare '-' character for floating point formats (bug #63383) * oct-stream.cc (octave_scan): Use "is >> std::ws" instead of hand-rolled code to skipe whitespace. Capture stream pointer before calling read_value(). If read failed (failbit set) then restore stream pointer for correct positioning. * lo-utils.cc (read_fp_value): Use "is >> std::ws" instead of hand-rolled code to skipe whitespace. If character after '+' or '-' is whitespace, rather than a number, then set failbit on stream because this is a pattern match error. * io.tst: Fix BIST test copy&paste error for Inf-reading test. diff -r 2a12350f9410 -r d006285b7509 libinterp/corefcn/oct-stream.cc --- a/libinterp/corefcn/oct-stream.cc Tue Nov 22 12:48:29 2022 +0100 +++ b/libinterp/corefcn/oct-stream.cc Tue Nov 22 08:23:44 2022 -0800 @@ -4441,17 +4441,17 @@ case 'E': case 'G': { - int c1 = std::istream::traits_type::eof (); - - while (is && (c1 = is.get ()) != std::istream::traits_type::eof () - && isspace (c1)) - ; // skip whitespace - - if (c1 != std::istream::traits_type::eof ()) + is >> std::ws; // skip through whitespace and advance stream pointer + std::streampos pos = is.tellg (); + + ref = read_value (is); + + std::ios::iostate status = is.rdstate (); + if (status & std::ios::failbit) { - is.putback (c1); - - ref = read_value (is); + is.clear (); + is.seekg (pos); + is.setstate (status & ~std::ios_base::eofbit); } } break; diff -r 2a12350f9410 -r d006285b7509 liboctave/util/lo-utils.cc --- a/liboctave/util/lo-utils.cc Tue Nov 22 12:48:29 2022 +0100 +++ b/liboctave/util/lo-utils.cc Tue Nov 22 08:23:44 2022 -0800 @@ -263,16 +263,13 @@ T val = 0.0; // FIXME: resetting stream position is likely to fail unless we are - // reading from a file. + // reading from a file. std::streampos pos = is.tellg (); - char c1 = ' '; - - while (isspace (c1)) - c1 = is.get (); + is >> std::ws; // skip through whitespace and advance stream pointer bool neg = false; - + char c1 = is.get (); switch (c1) { case '-': @@ -285,6 +282,8 @@ c2 = is.get (); if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N') val = read_inf_nan_na (is, c2); + else if (isspace (c2)) + is.setstate (std::ios::failbit); else { is.putback (c2); diff -r 2a12350f9410 -r d006285b7509 test/io.tst --- a/test/io.tst Tue Nov 22 12:48:29 2022 +0100 +++ b/test/io.tst Tue Nov 22 08:23:44 2022 -0800 @@ -556,13 +556,13 @@ %! assert (count, 2); %! assert (msg, 'sscanf: format failed to match'); %! assert (pos, 5); -%! [val, count, msg, pos] = sscanf ('2 3 na', '%f'); -%! assert (val, [2; 3; NA]); -%! assert (count, 3); -%! assert (msg, ''); -%! assert (pos, 7); -%! [val, count, msg, pos] = sscanf ('2 3 nan', '%f'); -%! assert (val, [2; 3; NaN]); +%! [val, count, msg, pos] = sscanf ('2 3 in', '%f'); +%! assert (val, [2; 3]); +%! assert (count, 2); +%! assert (msg, 'sscanf: format failed to match'); +%! assert (pos, 5); +%! [val, count, msg, pos] = sscanf ('2 3 inf', '%f'); +%! assert (val, [2; 3; Inf]); %! assert (count, 3); %! assert (msg, ''); %! assert (pos, 8);