Hi Eric, > A while ago, we wrote some unit tests that failed on a number of systems > with different behaviors of fflush after ungetc (particularly if you used > ungetc to push back a different byte than what was originally read). At > the time, Bruno ended up commenting the tests out until we had an official > ruling from the POSIX folks on what should happen. > > Well, the topic finally came up in yesterday's meeting: > > https://www.opengroup.org/sophocles/show_mail.tpl?CALLER=index.tpl&source=L&listname=austin-group-l&id=11808 > > For more details, browse to > http://www.opengroup.org/austin/aardvark/latest/xshbug3.txt > and search for Enhancement Request Number 17 > > in particular, the new wording states that after fflush, "the file offset > of the underlying open file description shall be set to the file position > of the stream, and any characters pushed back onto the stream by ungetc() > or ungetwc() that have not subsequently been read from the stream shall be > discarded."
Thanks a lot for pursuing this issue until it came to a resolution!! > We ought to go ahead and reinstate the proper unit tests for these > behaviors, as well as improve the fflush and other modules (and perhaps > add an ungetc module) to make this behavior consistent across platforms. I agree. The appended patch enables two fflush-after-ungetc tests. It passes on AIX, HP-UX, IRIX, OSF/1, Solaris, but fails on glibc, *BSD, mingw platforms. More work to be done for these platforms... 2009-01-15 Bruno Haible <br...@clisp.org> * tests/test-fflush2.sh: Invoke test-fflush2 twice. * tests/test-fflush2.c (ASSERT): Always fail. (main): Add two tests for fflush() after ungetc(), taking into account the Austin Group's clarification. Suggested by Eric Blake. *** tests/test-fflush2.c.orig 2009-01-15 12:16:35.000000000 +0100 --- tests/test-fflush2.c 2009-01-15 12:00:16.000000000 +0100 *************** *** 1,5 **** /* Test of POSIX compatible fflush() function. ! Copyright (C) 2008 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by --- 1,5 ---- /* Test of POSIX compatible fflush() function. ! Copyright (C) 2008-2009 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by *************** *** 20,28 **** #include <stdlib.h> ! /* This test can only be made to work on specific platforms. */ ! #if defined _IO_ferror_unlocked || defined __sferror /* GNU libc, BeOS; FreeBSD, NetBSD, OpenBSD, MacOS X, Cygwin */ ! # define ASSERT(expr) \ do \ { \ if (!(expr)) \ --- 20,26 ---- #include <stdlib.h> ! #define ASSERT(expr) \ do \ { \ if (!(expr)) \ *************** *** 33,89 **** } \ } \ while (0) - #else - # define ASSERT(expr) \ - do \ - { \ - if (!(expr)) \ - { \ - printf ("Skipping test: expected failure on this platform\n"); \ - exit (77); \ - } \ - } \ - while (0) - #endif int main (int argc, char **argv) { - #if 0 - /* Check fflush after a backup ungetc() call. This is case 1 in terms of - <http://lists.gnu.org/archive/html/bug-gnulib/2008-03/msg00131.html>. - The Austin Group has not yet decided how this should behave. */ - #endif - #if 0 - /* Check fflush after a non-backup ungetc() call. This is case 2 in terms of - <http://lists.gnu.org/archive/html/bug-gnulib/2008-03/msg00131.html>. - The Austin Group has not yet decided how this should behave. */ - /* Check that fflush after a non-backup ungetc() call discards the ungetc - buffer. This is mandated by POSIX - <http://www.opengroup.org/susv3/functions/ungetc.html>: - "The value of the file-position indicator for the stream after - reading or discarding all pushed-back bytes shall be the same - as it was before the bytes were pushed back." */ int c; ! c = fgetc (stdin); ! ASSERT (c == '#'); ! c = fgetc (stdin); ! ASSERT (c == '!'); ! /* Here the file-position indicator must be 2. */ ! c = ungetc ('@', stdin); ! ASSERT (c == '@'); ! fflush (stdin); ! /* Here the file-position indicator must be 2 again. */ ! c = fgetc (stdin); ! ASSERT (c == '/'); ! #endif ! return 0; } --- 31,115 ---- } \ } \ while (0) int main (int argc, char **argv) { int c; ! if (argc > 1) ! switch (argv[1][0]) ! { ! case '1': ! /* Check fflush after a backup ungetc() call. This is case 1a in ! terms of ! <http://lists.gnu.org/archive/html/bug-gnulib/2008-03/msg00131.html>, ! according to the Austin Group's resolution on 2009-01-08. */ ! ! c = fgetc (stdin); ! ASSERT (c == '#'); ! ! c = fgetc (stdin); ! ASSERT (c == '!'); ! ! /* Here the file-position indicator must be 2. */ ! ! c = ungetc ('!', stdin); ! ASSERT (c == '!'); ! ! fflush (stdin); ! ! /* Here the file-position indicator must be 1. */ ! ! c = fgetc (stdin); ! ASSERT (c == '!'); ! ! c = fgetc (stdin); ! ASSERT (c == '/'); ! ! return 0; ! ! case '2': ! /* Check fflush after a non-backup ungetc() call. This is case 2a in ! terms of ! <http://lists.gnu.org/archive/html/bug-gnulib/2008-03/msg00131.html>, ! according to the Austin Group's resolution on 2009-01-08. */ ! /* Check that fflush after a non-backup ungetc() call discards the ! ungetc buffer. This is mandated by POSIX ! <http://www.opengroup.org/susv3/functions/ungetc.html>: ! "The value of the file-position indicator for the stream after ! reading or discarding all pushed-back bytes shall be the same ! as it was before the bytes were pushed back." ! <http://www.opengroup.org/austin/aardvark/latest/xshbug3.txt> ! "[After fflush(),] the file offset of the underlying open file ! description shall be set to the file position of the stream, and ! any characters pushed back onto the stream by ungetc() or ! ungetwc() that have not subsequently been read from the stream ! shall be discarded." */ ! ! c = fgetc (stdin); ! ASSERT (c == '#'); ! ! c = fgetc (stdin); ! ASSERT (c == '!'); ! ! /* Here the file-position indicator must be 2. */ ! c = ungetc ('@', stdin); ! ASSERT (c == '@'); ! fflush (stdin); ! /* Here the file-position indicator must be 1. */ ! c = fgetc (stdin); ! ASSERT (c == '!'); ! c = fgetc (stdin); ! ASSERT (c == '/'); ! return 0; ! } ! return 1; } *** tests/test-fflush2.sh.orig 2009-01-15 12:16:35.000000000 +0100 --- tests/test-fflush2.sh 2009-01-15 11:24:32.000000000 +0100 *************** *** 2,8 **** # Execute the test only with seekable input stream. # The behaviour of fflush() on a non-seekable input stream is undefined. ! ./test-fflush2${EXEEXT} < "$srcdir/test-fflush2.sh" || exit $? #cat "$srcdir/test-fflush2.sh" | ./test-fflush2${EXEEXT} || exit $? exit 0 --- 2,9 ---- # Execute the test only with seekable input stream. # The behaviour of fflush() on a non-seekable input stream is undefined. ! ./test-fflush2${EXEEXT} 1 < "$srcdir/test-fflush2.sh" || exit $? ! ./test-fflush2${EXEEXT} 2 < "$srcdir/test-fflush2.sh" || exit $? #cat "$srcdir/test-fflush2.sh" | ./test-fflush2${EXEEXT} || exit $? exit 0