changeset 11017:95eb3a6eb21d

Make fflush-after-ungetc POSIX compliant on glibc systems.
author Bruno Haible <bruno@clisp.org>
date Fri, 16 Jan 2009 00:24:35 +0100
parents 5d3e28b13bb3
children 8a3de59b56aa
files ChangeLog lib/fflush.c lib/fseeko.c m4/fflush.m4
diffstat 4 files changed, 72 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2009-01-15  Bruno Haible  <bruno@clisp.org>
+
+	Make fflush-after-ungetc POSIX compliant on glibc systems.
+	* m4/fflush.m4 (gl_FUNC_FFLUSH): Test also the behaviour of fflush
+	after ungetc.
+	* lib/fflush.c (clear_ungetc_buffer): Implement for glibc systems.
+	(rpl_fflush): On glibc systems, simply call the system's fflush
+	function after clearing the ungetc buffer.
+	* lib/fseeko.c (rpl_fseeko): Don't try to lseek past the end of file.
+	Instead, lseek only to the end of file, then use the system's fseeko
+	for the rest. On glibc systems, reset the EOF indicator bit.
+
 2009-01-15  Jim Meyering  <meyering@redhat.com>
 
 	openmp.m4: revert quote-adding change, for portability to older autoconf
--- a/lib/fflush.c
+++ b/lib/fflush.c
@@ -1,5 +1,5 @@
 /* fflush.c -- allow flushing input streams
-   Copyright (C) 2007-2008 Free Software Foundation, Inc.
+   Copyright (C) 2007-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
@@ -34,7 +34,11 @@
 static inline void
 clear_ungetc_buffer (FILE *fp)
 {
-#if defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */
+#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;
@@ -123,6 +127,12 @@
      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
      EBADF, some do nothing.  */
@@ -140,7 +150,7 @@
   if (result != 0)
     return result;
 
-#if (defined __sferror || defined __DragonFly__) && defined __SNPT /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */
+# if (defined __sferror || defined __DragonFly__) && defined __SNPT /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */
 
   {
     /* Disable seek optimization for the next fseeko call.  This tells the
@@ -154,7 +164,7 @@
   }
   return result;
 
-#else
+# else
 
   pos = lseek (fileno (stream), pos, SEEK_SET);
   if (pos == -1)
@@ -165,5 +175,6 @@
 
   return 0;
 
+# endif
 #endif
 }
--- a/lib/fseeko.c
+++ b/lib/fseeko.c
@@ -1,5 +1,5 @@
 /* An fseeko() function that, together with fflush(), is POSIX compliant.
-   Copyright (C) 2007-2008 Free Software Foundation, Inc.
+   Copyright (C) 2007-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
@@ -86,7 +86,14 @@
   #error "Please port gnulib fseeko.c to your platform! Look at the code in fpurge.c, then report this to bug-gnulib."
 #endif
     {
-      off_t pos = lseek (fileno (fp), offset, whence);
+      /* We get here when an fflush() call immediately preceded this one.  We
+	 know there are no buffers.
+	 POSIX requires us to modify the file descriptor's position.
+	 But we cannot position beyond end of file here.  */
+      off_t pos =
+	lseek (fileno (fp),
+	       whence == SEEK_END && offset > 0 ? 0 : offset,
+	       whence);
       if (pos == -1)
 	{
 #if defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */
@@ -94,20 +101,22 @@
 #endif
 	  return -1;
 	}
-      else
-	{
-#if defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */
-	  fp_->_offset = pos;
-	  fp_->_flags |= __SOFF;
-	  fp_->_flags &= ~__SEOF;
+
+#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
+      fp->_flags &= ~_IO_EOF_SEEN;
+#elif defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */
+      fp_->_offset = pos;
+      fp_->_flags |= __SOFF;
+      fp_->_flags &= ~__SEOF;
 #elif defined __EMX__               /* emx+gcc */
-          fp->_flags &= ~_IOEOF;
+      fp->_flags &= ~_IOEOF;
 #elif defined _IOERR                /* AIX, HP-UX, IRIX, OSF/1, Solaris, OpenServer, mingw */
-          fp->_flag &= ~_IOEOF;
+      fp->_flag &= ~_IOEOF;
 #endif
-	  return 0;
-	}
+      /* If we were not requested to position beyond end of file, we're
+	 done.  */
+      if (!(whence == SEEK_END && offset > 0))
+	return 0;
     }
-  else
-    return fseeko (fp, offset, whence);
+  return fseeko (fp, offset, whence);
 }
--- a/m4/fflush.m4
+++ b/m4/fflush.m4
@@ -1,6 +1,6 @@
-# fflush.m4 serial 6
+# fflush.m4 serial 7
 
-# Copyright (C) 2007-2008 Free Software Foundation, Inc.
+# Copyright (C) 2007-2009 Free Software Foundation, Inc.
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
@@ -22,6 +22,7 @@
        ]], [[FILE *f = fopen ("conftest.txt", "r");
 	 char buffer[10];
 	 int fd;
+	 int c;
 	 if (f == NULL)
 	   return 1;
 	 fd = fileno (f);
@@ -30,17 +31,31 @@
 	 /* For deterministic results, ensure f read a bigger buffer.  */
 	 if (lseek (fd, 0, SEEK_CUR) == 5)
 	   return 3;
-	 /* POSIX requires fflush-fseek to set file offset of fd.  */
+	 /* POSIX requires fflush-fseek to set file offset of fd.  This fails
+	    on BSD systems and on mingw.  */
 	 if (fflush (f) != 0 || fseek (f, 0, SEEK_CUR) != 0)
 	   return 4;
 	 if (lseek (fd, 0, SEEK_CUR) != 5)
 	   return 5;
-	 /* TODO: Verify behaviour of fflush after ungetc, see
-	    <http://lists.gnu.org/archive/html/bug-gnulib/2008-03/msg00131.html>.  */
+	 /* Verify behaviour of fflush after ungetc. See
+	    <http://www.opengroup.org/austin/aardvark/latest/xshbug3.txt>  */
+	 /* Verify behaviour of fflush after a backup ungetc.  This fails on
+	    mingw.  */
+	 c = fgetc (f);
+	 ungetc (c, f);
+	 fflush (f);
+	 if (fgetc (f) != c)
+	   return 6;
+	 /* Verify behaviour of fflush after a non-backup ungetc.  This fails
+	    on glibc 2.8 and on BSD systems.  */
+	 c = fgetc (f);
+	 ungetc ('@', f);
+	 fflush (f);
+	 if (fgetc (f) != c)
+	   return 7;
 	 return 0;
        ]])], [gl_cv_func_fflush_stdin=yes], [gl_cv_func_fflush_stdin=no],
-     [dnl Pessimistically assume fflush is broken.  This is wrong for
-      dnl at least glibc and cygwin; but lib/fflush.c takes this into account.
+     [dnl Pessimistically assume fflush is broken.
       gl_cv_func_fflush_stdin=no])
      rm conftest.txt
     ])