This makes fflush after ungetc work on BSD systems.
2009-01-15 Bruno Haible <br...@clisp.org> 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. *** lib/fflush.c.orig 2009-01-16 02:05:12.000000000 +0100 --- lib/fflush.c 2009-01-16 01:39:32.000000000 +0100 *************** *** 31,52 **** #undef fflush 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 (HASUB (fp)) { fp_->_p += fp_->_r; fp_->_r = 0; } ! #endif } #if (defined __sferror || defined __DragonFly__) && defined __SNPT /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */ static inline int --- 31,75 ---- #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 __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 */ static inline int *************** *** 104,112 **** 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> --- 127,141 ---- if (stream == NULL || ! freading (stream)) return fflush (stream); ! #if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ! ! clear_ungetc_buffer_preserving_position (stream); ! ! return fflush (stream); ! #else ! ! /* Notes about the file-position indicator: 1) The file position indicator is incremented by fgetc() and decremented by ungetc(): <http://www.opengroup.org/susv3/functions/fgetc.html> *************** *** 119,137 **** "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 /* POSIX does not specify fflush behavior for non-seekable input streams. Some implementations purge unread data, some return --- 148,159 ---- "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." ! Here we are discarding all pushed-back bytes. But more specifically, ! 3) <http://www.opengroup.org/austin/aardvark/latest/xshbug3.txt> 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,148 **** --- 165,173 ---- 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. */