[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: fflush after ungetc
From: |
Bruno Haible |
Subject: |
Re: fflush after ungetc |
Date: |
Fri, 7 Mar 2008 03:33:08 +0100 |
User-agent: |
KMail/1.5.4 |
Eric Blake wrote:
> Newlib has two bugs - first, fflush is failing to discard ungetc data when
> changing the underlying fd offset.
This bug is common to all BSD and AT&T Unix derived implementations. For BSD
systems, I'm committing this fix. For AT&T Unix derived implementations, I
don't see an easy fix.
2008-03-06 Bruno Haible <address@hidden>
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.
*** lib/fflush.c.orig 2008-03-07 03:24:45.000000000 +0100
--- lib/fflush.c 2008-03-07 02:44:45.000000000 +0100
***************
*** 1,5 ****
/* fflush.c -- allow flushing input streams
! Copyright (C) 2007 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 ----
/* fflush.c -- allow flushing input streams
! 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,64 ****
--- 59,104 ----
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. */
======================= tests/test-fflush2.c ============================
/* 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;
}
=============================== tests/test-fflush2.sh =========================
#!/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
===============================================================================
*** modules/fflush-tests.orig 2008-03-07 03:24:45.000000000 +0100
--- modules/fflush-tests 2008-03-06 22:59:12.000000000 +0100
***************
*** 1,5 ****
--- 1,7 ----
Files:
tests/test-fflush.c
+ tests/test-fflush2.sh
+ tests/test-fflush2.c
Depends-on:
fseeko
***************
*** 7,12 ****
configure.ac:
Makefile.am:
! TESTS += test-fflush
! check_PROGRAMS += test-fflush
MOSTLYCLEANFILES += test-fflush.txt
--- 9,15 ----
configure.ac:
Makefile.am:
! TESTS += test-fflush test-fflush2.sh
! TESTS_ENVIRONMENT += EXEEXT='@EXEEXT@' srcdir='$(srcdir)'
! check_PROGRAMS += test-fflush test-fflush2
MOSTLYCLEANFILES += test-fflush.txt
*** doc/posix-functions/fflush.texi.orig 2008-03-07 03:24:45.000000000
+0100
--- doc/posix-functions/fflush.texi 2008-03-07 03:05:55.000000000 +0100
***************
*** 15,20 ****
--- 15,25 ----
@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,29 ****
--- 31,38 ----
@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
- Re: new module 'freadseek', (continued)
- Message not available
- Re: fflush after ungetc, Eric Blake, 2008/03/26
- Re: fflush after ungetc,
Bruno Haible <=
- Re: fflush after ungetc, Eric Blake, 2008/03/06
- Re: fflush after ungetc, Bruno Haible, 2008/03/09
- Re: fflush after ungetc, Eric Blake, 2008/03/29
- Re: fflush after ungetc, Eric Blake, 2008/03/29
- Re: fflush after ungetc, Bruno Haible, 2008/03/29
- Re: fflush after ungetc, Eric Blake, 2008/03/29
- Re: freadseek, Bruno Haible, 2008/03/30
- Re: fflush after ungetc, Bruno Haible, 2008/03/30
- Re: Cygwin ftell bug, Bruno Haible, 2008/03/06