Mercurial > octave
changeset 31504:d006285b7509
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.
author | Rik <rik@octave.org> |
---|---|
date | Tue, 22 Nov 2022 08:23:44 -0800 |
parents | 2a12350f9410 |
children | fb123529131b |
files | libinterp/corefcn/oct-stream.cc liboctave/util/lo-utils.cc test/io.tst |
diffstat | 3 files changed, 22 insertions(+), 23 deletions(-) [+] |
line wrap: on
line diff
--- 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<double> (is); + + std::ios::iostate status = is.rdstate (); + if (status & std::ios::failbit) { - is.putback (c1); - - ref = read_value<double> (is); + is.clear (); + is.seekg (pos); + is.setstate (status & ~std::ios_base::eofbit); } } break;
--- 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<T> (is, c2); + else if (isspace (c2)) + is.setstate (std::ios::failbit); else { is.putback (c2);
--- 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);