Adding a unit test for such pushback characters show that the EOF recognition must be done with lower priority than the pushback character test.
2024-12-30 Bruno Haible <br...@clisp.org> mbfile: Support pushback characters also right before EOF. * lib/mbfile.h (mbfile_multi_getc): Read pushed-back character before testing for sticky EOF. * tests/test-mbfile.c (main): Test pushback at EOF. diff --git a/lib/mbfile.h b/lib/mbfile.h index b110aff229..b36ed1c350 100644 --- a/lib/mbfile.h +++ b/lib/mbfile.h @@ -89,11 +89,6 @@ mbfile_multi_getc (struct mbchar *mbc, struct mbfile_multi *mbf) unsigned int new_bufcount; size_t bytes; - /* If EOF has already been seen, don't use getc. This matters if - mbf->fp is connected to an interactive tty. */ - if (mbf->eof_seen) - goto eof; - /* Return character pushed back, if there is one. */ if (mbf->pushback_count > 0) { @@ -102,6 +97,11 @@ mbfile_multi_getc (struct mbchar *mbc, struct mbfile_multi *mbf) return; } + /* If EOF has already been seen, don't use getc. This matters if + mbf->fp is connected to an interactive tty. */ + if (mbf->eof_seen) + goto eof; + new_bufcount = mbf->bufcount; /* If mbf->state is not in an initial state, some more 32-bit wide character diff --git a/tests/test-mbfile.c b/tests/test-mbfile.c index 3565404294..c59803d308 100644 --- a/tests/test-mbfile.c +++ b/tests/test-mbfile.c @@ -45,6 +45,7 @@ main () /* The input consists of 4 UTF-8 characters: '$', U+00A5, U+20AC, U+0001F403. */ mbf_char_t next; + mbf_char_t prev; mbf_getc (next, mbstdin); ASSERT (!mb_iseof (next)); @@ -65,9 +66,24 @@ main () ASSERT (!mb_iseof (next)); ASSERT (mb_len (next) == 4); ASSERT (mb_iseq (next, 0x1F403)); + mb_copy (&prev, &next); mbf_getc (next, mbstdin); ASSERT (mb_iseof (next)); + /* Even at EOF, we need to be able to push back 2 characters. */ + mbf_ungetc (next, mbstdin); + mbf_ungetc (prev, mbstdin); + + mbf_char_t renext; + + mbf_getc (renext, mbstdin); + ASSERT (!mb_iseof (renext)); + ASSERT (mb_len (renext) == 4); + ASSERT (mb_iseq (renext, 0x1F403)); + + mbf_getc (renext, mbstdin); + ASSERT (mb_iseof (renext)); + return test_exit_status; }