# HG changeset patch # User Bruno Haible # Date 1232068073 -3600 # Node ID 8a3de59b56aa0acc9a4570749513e633b7566ad3 # Parent 95eb3a6eb21dd210811e9faf63c04c8e167e4ce7 Make fflush-after-ungetc POSIX compliant on BSD systems. diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2009-01-15 Bruno Haible + + Make fflush-after-ungetc POSIX compliant on BSD systems. + * lib/fflush.c (clear_ungetc_buffer_preserving_position): New function. + (clear_ungetc_buffer): Implement also for other systems. + (rpl_fflush): On glibc systems, invoke + clear_ungetc_buffer_preserving_position. Otherwise, invoke + clear_ungetc_buffer after fetching the stream's position, not before. + 2009-01-15 Bruno Haible Make fflush-after-ungetc POSIX compliant on glibc systems. diff --git a/lib/fflush.c b/lib/fflush.c --- a/lib/fflush.c +++ b/lib/fflush.c @@ -31,21 +31,44 @@ #undef fflush + +#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + +/* Clear the stream's ungetc buffer, preserving the value of ftello (fp). */ +static inline void +clear_ungetc_buffer_preserving_position (FILE *fp) +{ + if (fp->_flags & _IO_IN_BACKUP) + /* _IO_free_backup_area is a bit complicated. Simply call fseek. */ + fseek (fp, 0, SEEK_CUR); +} + +#else + +/* Clear the stream's ungetc buffer. May modify the value of ftello (fp). */ static inline void clear_ungetc_buffer (FILE *fp) { -#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ - if (fp->_flags & _IO_IN_BACKUP) - /* _IO_free_backup_area is a bit complicated. Simply call fseek. */ - fseek (fp, 0, SEEK_CUR); -#elif defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */ +# if defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */ if (HASUB (fp)) { fp_->_p += fp_->_r; fp_->_r = 0; } +# elif defined __EMX__ /* emx+gcc */ + if (fp->_ungetc_count > 0) + { + fp->_ungetc_count = 0; + fp->_rcount = - fp->_rcount; + } +# elif defined _IOERR /* AIX, HP-UX, IRIX, OSF/1, Solaris, OpenServer, mingw */ + /* Nothing to do. */ +# else /* other implementations */ + fseek (fp, 0, SEEK_CUR); +# endif +} + #endif -} #if (defined __sferror || defined __DragonFly__) && defined __SNPT /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */ @@ -104,9 +127,15 @@ if (stream == NULL || ! freading (stream)) return fflush (stream); - /* Clear the ungetc buffer. +#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + + clear_ungetc_buffer_preserving_position (stream); - This is needed before fetching the file-position indicator, because + return fflush (stream); + +#else + + /* Notes about the file-position indicator: 1) The file position indicator is incremented by fgetc() and decremented by ungetc(): @@ -119,19 +148,12 @@ "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. */ - clear_ungetc_buffer (stream); - -#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ - - return fflush (stream); - -#else + Here we are discarding all pushed-back bytes. But more specifically, + 3) says: + "[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() ... shall + be discarded." */ /* POSIX does not specify fflush behavior for non-seekable input streams. Some implementations purge unread data, some return @@ -143,6 +165,9 @@ return EOF; } + /* Clear the ungetc buffer. */ + clear_ungetc_buffer (stream); + /* To get here, we must be flushing a seekable input stream, so the semantics of fpurge are now appropriate to clear the buffer. To avoid losing data, the lseek is also necessary. */