cosmopolitan/test/libc/stdio
Ivan Komarov f7ff515961
*scanf() fixes to make TeX work (#1109)
* Fix reading the same symbol twice when using `{f,}scanf()`

PR #924 appears to use `unget()` subtly incorrectly when parsing
floating point numbers. The rest of the code only uses `unget()`
immediately followed by `goto Done;` to return back the symbol that
can't possibly belong to the directive we're processing.

With floating-point, however, the ungot characters could very well
be valid for the *next* directive, so we will essentially read them
twice. It can't be seen in `sscanf()` tests because `unget()` is a
no-op there, but the test I added for `fscanf()` fails like this:

        ...
        EXPECT_EQ(0xDEAD, i1)
                need 57005 (or 0xdead) =
                 got 908973 (or 0x000ddead)
        ...
        EXPECT_EQ(0xBEEF, i2)
                need 48879 (or 0xbeef) =
                 got 769775 (or 0x000bbeef)

This means we read 0xDDEAD instead of 0xDEAD and 0xBBEEF instead of
0xBEEF. I checked that both musl and glibc read 0xDEAD/0xBEEF, as
expected.

Fix the failing test by removing the unneeded `unget()` calls.

* Don't read invalid floating-point numbers in `*scanf()`

Currently, we just ignore any errors from `strtod()`. They can
happen either because no valid float can be parsed at all, or
because the state machine recognizes only a prefix of a valid
floating-point number.

Fix this by making sure `strtod()` parses everything we recognized,
provided it's non-empty. This requires to pop the last character
off the FP buffer, which is supposed to be parsed by the next
`*scanf()` directive.

* Make `%c` parsing in `*scanf()` respect the C standard

Currently, `%c`-style directives always succeed even if there
are actually fewer characters in the input than requested.

Before the fix, the added test fails like this:

        ...
        EXPECT_EQ(2, sscanf("ab", "%c %c %c", &c2, &c3, &c4))
                need 2 (or 0x02 or '\2' or ENOENT) =
                 got 3 (or 0x03 or '\3' or ESRCH)
        ...
        EXPECT_EQ(0, sscanf("abcd", "%5c", s2))
                need 0 (or 0x0 or '\0') =
                 got 1 (or 0x01 or '\1' or EPERM)

musl and glibc pass this test.
2024-02-23 07:15:30 -08:00
..
BUILD.mk more modeline errata (#1019) 2023-12-16 23:07:10 -05:00
crypt_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
devrand_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
dirstream_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
dtoa_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
dumphexc_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
ecvt_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
fds_torture_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
fgetln_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
fgets_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
fgetwc_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
fmemopen_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
fmt_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
fprintf_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
fputc_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
fputs_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
fread_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
freopen_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
fscanf_test.c *scanf() fixes to make TeX work (#1109) 2024-02-23 07:15:30 -08:00
fseeko_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
ftell_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
fwrite_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
getdelim_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
getentropy_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
gz_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
iconv_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
joinstrlist_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
memory_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
mt19937_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
palandprintf_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
popen_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
rand_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
rngset_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
snprintf_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
sprintf_s.inc flip et / noet in modelines 2023-12-07 22:17:11 -05:00
sprintf_s_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
sscanf_test.c *scanf() fixes to make TeX work (#1109) 2024-02-23 07:15:30 -08:00
tmpfile_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00
ungetc_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
vappendf_test.c flip et / noet in modelines 2023-12-07 22:17:11 -05:00
zipdir_test.c Bring back gc() function 2024-01-08 10:26:28 -08:00