Mercurial > hg > octave-lyh > gnulib-hg
changeset 9772:cfd020716bf2
Make fflush after ungetc work on BSD platforms.
author | Bruno Haible <bruno@clisp.org> |
---|---|
date | Fri, 07 Mar 2008 03:34:46 +0100 |
parents | 4405a3880f94 |
children | a94669b4c7b9 |
files | ChangeLog doc/posix-functions/fflush.texi lib/fflush.c modules/fflush-tests tests/test-fflush2.c tests/test-fflush2.sh |
diffstat | 6 files changed, 152 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2008-03-06 Bruno Haible <bruno@clisp.org> + + Make fflush after ungetc work on BSD platforms. + * lib/fflush.c (rpl_fflush): Discard ungetc buffer if possible. + * tests/test-fflush2.c: New file. + * tests/test-fflush2.sh: New file. + * modules/fflush-tests (Files): Add tests/test-fflush2.sh, + tests/test-fflush2.c. + (Makefile.am): Build test-fflush2 and run test-fflush2.sh. + * doc/posix-functions/fflush.texi: Document fflush after ungetc bug. + 2008-03-06 Eric Blake <ebb9@byu.net> Likewise for ftello.
--- a/doc/posix-functions/fflush.texi +++ b/doc/posix-functions/fflush.texi @@ -15,6 +15,11 @@ @item @code{fflush} on an input stream changes the position of the stream to the end of the previous buffer, on some platforms: mingw. +@item +@code{fflush} on an input stream right after @code{ungetc} does not discard +the @code{ungetc} buffer, on some platforms: +MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, Cygwin. +Cygwin. @end itemize Portability problems not fixed by Gnulib: @@ -26,4 +31,8 @@ @item On Windows platforms (excluding Cygwin), this function does not set @code{errno} upon failure. +@item +@code{fflush} on an input stream right after @code{ungetc} does not discard +the @code{ungetc} buffer, on some platforms: +AIX 5.1, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw. @end itemize
--- a/lib/fflush.c +++ b/lib/fflush.c @@ -1,5 +1,5 @@ /* fflush.c -- allow flushing input streams - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007-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 @@ -59,6 +59,46 @@ if (stream == NULL || ! freading (stream)) return fflush (stream); + /* Clear the ungetc buffer. + + This is needed before fetching the file-position indicator, because + 1) The file position indicator is incremented by fgetc() and decremented + by ungetc(): + <http://www.opengroup.org/susv3/functions/fgetc.html> + "The file-position indicator is decremented by each successful + call to ungetc()..." + <http://www.opengroup.org/susv3/functions/ungetc.html> + "... the fgetc() function shall ... advance the associated file + position indicator for the stream ..." + 2) <http://www.opengroup.org/susv3/functions/ungetc.html> says: + "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." + 3) Here we are discarding all pushed-back bytes. + + Unfortunately it is impossible to implement this on platforms with + _IOERR, because an ungetc() on this platform prepends the pushed-back + bytes to the buffer without an indication of the limit between the + pushed-back bytes and the read-ahead bytes. */ +#if defined __sferror /* FreeBSD, NetBSD, OpenBSD, MacOS X, Cygwin */ + { +# if defined __NetBSD__ || defined __OpenBSD__ + struct __sfileext + { + struct __sbuf _ub; /* ungetc buffer */ + /* More fields, not relevant here. */ + }; + if (((struct __sfileext *) stream->_ext._base)->_ub._base != NULL) +# else + if (stream->_ub._base != NULL) +# endif + { + stream->_p += stream->_r; + stream->_r = 0; + } + } +#endif + /* POSIX does not specify fflush behavior for non-seekable input streams. Some implementations purge unread data, some return EBADF, some do nothing. */
--- a/modules/fflush-tests +++ b/modules/fflush-tests @@ -1,5 +1,7 @@ Files: tests/test-fflush.c +tests/test-fflush2.sh +tests/test-fflush2.c Depends-on: fseeko @@ -7,6 +9,7 @@ configure.ac: Makefile.am: -TESTS += test-fflush -check_PROGRAMS += test-fflush +TESTS += test-fflush test-fflush2.sh +TESTS_ENVIRONMENT += EXEEXT='@EXEEXT@' srcdir='$(srcdir)' +check_PROGRAMS += test-fflush test-fflush2 MOSTLYCLEANFILES += test-fflush.txt
new file mode 100644 --- /dev/null +++ b/tests/test-fflush2.c @@ -0,0 +1,78 @@ +/* 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 + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <stdio.h> + +#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)) \ + { \ + fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \ + abort (); \ + } \ + } \ + 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) +{ + /* 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 == '/'); + + return 0; +}
new file mode 100755 --- /dev/null +++ b/tests/test-fflush2.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +# 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