Mercurial > octave
changeset 33124:9c08824262af stable
Fix duplicate final value in scanf function (bug #65390, bug #63467).
* oct-stream.cc (octave_scan): Don't check whether input stream "is" has hit
EOF after skipping whitespace. Instead, call read_value() and let error
propagate up through "is" state to this function. Check state of stream
and either pass on a correctly-read value, or clear EOF bit and propagate
up failure status in stream status bits.
* io.tst: Add regression indicator to solved bug #63383. Add BIST tests
for bug #63467 and bug #65390
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Sat, 02 Mar 2024 13:54:06 -0800 |
parents | 030686799759 |
children | fc467370dacb ca773dcbb420 |
files | libinterp/corefcn/oct-stream.cc test/io.tst |
diffstat | 2 files changed, 38 insertions(+), 17 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/corefcn/oct-stream.cc Thu Feb 29 08:18:25 2024 -0500 +++ b/libinterp/corefcn/oct-stream.cc Sat Mar 02 13:54:06 2024 -0800 @@ -4400,8 +4400,6 @@ octave_scan<> (std::istream& is, const scanf_format_elt& fmt, double *valptr) { - double& ref = *valptr; - switch (fmt.type) { case 'e': @@ -4411,19 +4409,24 @@ case 'G': { is >> std::ws; // skip through whitespace and advance stream pointer - if (is.good ()) + + std::streampos pos = is.tellg (); + + double value = read_value<double> (is); + + std::ios::iostate status = is.rdstate (); + if (! (status & std::ios::failbit)) { - std::streampos pos = is.tellg (); - - ref = read_value<double> (is); - - std::ios::iostate status = is.rdstate (); - if (status & std::ios::failbit) - { - is.clear (); - is.seekg (pos); - is.setstate (status & ~std::ios_base::eofbit); - } + // Copy the converted value if the stream is in a good state + *valptr = value; + } + else + { + // True error. + // Reset stream to original position, clear eof bit, pass status on. + is.clear (); + is.seekg (pos); + is.setstate (status & ~std::ios_base::eofbit); } } break;
--- a/test/io.tst Thu Feb 29 08:18:25 2024 -0500 +++ b/test/io.tst Sat Mar 02 13:54:06 2024 -0800 @@ -600,7 +600,7 @@ %! assert (pos, 5); ## Test '-' within string -%!test <63383> +%!test <*63383> %! [val, count, msg, pos] = sscanf ('1 2 - 3', '%d'); %! assert (val, [1; 2]); %! assert (count, 2); @@ -626,7 +626,7 @@ %! assert (pos, 5); ## Test '+' within string -%!test <63383> +%!test <*63383> %! [val, count, msg, pos] = sscanf ('1 2 + 3', '%d'); %! assert (val, [1; 2]); %! assert (count, 2); @@ -638,7 +638,7 @@ %! assert (msg, 'sscanf: format failed to match'); %! assert (pos, 5); -%## Test +NA, -NA, +NAN, -NAN +## Test +NA, -NA, +NAN, -NAN %!test <*63383> %! [val, count, msg, pos] = sscanf ('+NA -NA 1 +NAN -NAN', '%f'); %! assert (val, [NA; NA; 1; NaN; NaN]); @@ -666,6 +666,24 @@ %! assert (msg, ''); %! assert (pos, 5); +## Test space at end of input string +%!test <63467> +%! [val, count, msg, pos] = sscanf ('1 2 ', '%f'); +%! assert (val, [1; 2]); +%! assert (count, 2); +%! ## FIXME: The message should be empty, but is not. +%! # assert (msg, ''); +%! assert (pos, 5); + +## Test newline at end of input string +%!test <65390> +%! [val, count, msg, pos] = sscanf ("1 2\n", '%f'); +%! assert (val, [1; 2]); +%! assert (count, 2); +%! ## FIXME: The message should be empty, but is not. +%! # assert (msg, ''); +%! assert (pos, 5); + %!test %! [a, b, c] = sscanf ("1.2 3 foo", "%f%d%s", "C"); %! [v1, c1, m1] = sscanf ("1 2 3 4 5 6", "%d");