Make fflush-after-ungetc POSIX compliant on glibc systems.
authorBruno Haible <bruno@clisp.org>
Thu, 15 Jan 2009 23:24:35 +0000 (00:24 +0100)
committerBruno Haible <bruno@clisp.org>
Thu, 15 Jan 2009 23:24:35 +0000 (00:24 +0100)
ChangeLog
lib/fflush.c
lib/fseeko.c
m4/fflush.m4

index fb11852..63e69d4 100644 (file)
--- 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
index 22d7d02..9772789 100644 (file)
@@ -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
 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 @@ rpl_fflush (FILE *stream)
      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 @@ rpl_fflush (FILE *stream)
   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 @@ rpl_fflush (FILE *stream)
   }
   return result;
 
-#else
+# else
 
   pos = lseek (fileno (stream), pos, SEEK_SET);
   if (pos == -1)
@@ -165,5 +175,6 @@ rpl_fflush (FILE *stream)
 
   return 0;
 
+# endif
 #endif
 }
index ac0af57..47beac4 100644 (file)
@@ -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 @@ rpl_fseeko (FILE *fp, off_t offset, int whence)
   #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 @@ rpl_fseeko (FILE *fp, off_t offset, int whence)
 #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);
 }
index 97f1284..da30e1f 100644 (file)
@@ -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 @@ AC_DEFUN([gl_FUNC_FFLUSH],
        ]], [[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 @@ AC_DEFUN([gl_FUNC_FFLUSH],
         /* 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
     ])