Work around fpurge bug on BSD systems.
authorBruno Haible <bruno@clisp.org>
Sun, 29 Apr 2007 12:16:55 +0000 (12:16 +0000)
committerBruno Haible <bruno@clisp.org>
Sun, 29 Apr 2007 12:16:55 +0000 (12:16 +0000)
ChangeLog
lib/fpurge.c
lib/fpurge.h
lib/fseeko.c
m4/fpurge.m4
modules/fpurge

index 1b1443b..23e16a9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2007-04-29  Bruno Haible  <bruno@clisp.org>
+
+       Work around fpurge bug on BSD systems.
+       * modules/fpurge (Makefile.am): Compile fpurge.c unconditionally.
+       * m4/fpurge.m4 (gl_FUNC_FPURGE): Don't invoke AC_LIBOBJ.
+       * lib/fpurge.h (fpurge): Don't handle __fpurge wrapper here. Define
+       fpurge to rpl_fpurge if the system already has this function.
+       * lib/fpurge.c (fpurge): Handle also the __fpurge wrapper case and
+       the case where the system already has this function. Correct invariants
+       on BSD systems.
+       * lib/fseeko.c (rpl_fseeko): Update recognition of preceding fflush on
+       BSD systems.
+
 2007-04-29  Sergey Poznyakoff  <gray@gnu.org.ua>
 
        * lib/argp-help.c (hol_cluster_cmp): Reverse comparison.  Change
index 863f853..e5d673a 100644 (file)
 /* Specification.  */
 #include "fpurge.h"
 
+#if HAVE___FPURGE                   /* glibc >= 2.2, Solaris >= 7 */
+# include <stdio_ext.h>
+#endif
 #include <stdlib.h>
 
 int
 fpurge (FILE *fp)
 {
+#if HAVE___FPURGE                   /* glibc >= 2.2, Solaris >= 7 */
+
+  __fpurge (fp);
+  /* The __fpurge function does not have a return value.  */
+  return 0;
+
+#elif HAVE_FPURGE                   /* FreeBSD, NetBSD, OpenBSD, MacOS X */
+
+  /* Call the system's fpurge function.  */
+# undef fpurge
+# if !HAVE_DECL_FPURGE
+  extern int fpurge (FILE *);
+# endif
+  int result = fpurge (fp);
+# if defined __sferror              /* FreeBSD, NetBSD, OpenBSD, MacOS X, Cygwin */
+  if (result == 0)
+    /* Correct the invariants that fpurge broke.
+       <stdio.h> on BSD systems says:
+         "The following always hold: if _flags & __SRD, _w is 0."
+       If this invariant is not fulfilled and the stream is read-write but
+       currently writing, subsequent putc or fputc calls will write directly
+       into the buffer, although they shouldn't be allowed to.  */
+    if ((fp->_flags & __SRD) != 0)
+      fp->_w = 0;
+# endif
+  return result;
+
+#else
+
   /* Most systems provide FILE as a struct and the necessary bitmask in
      <stdio.h>, because they need it for implementing getc() and putc() as
      fast macros.  */
-#if defined _IO_ferror_unlocked     /* GNU libc, BeOS */
+# if defined _IO_ferror_unlocked    /* GNU libc, BeOS */
   fp->_IO_read_end = fp->_IO_read_ptr;
   fp->_IO_write_ptr = fp->_IO_write_base;
   /* Avoid memory leak when there is an active ungetc buffer.  */
@@ -38,20 +70,20 @@ fpurge (FILE *fp)
       fp->_IO_save_base = NULL;
     }
   return 0;
-#elif defined __sferror             /* FreeBSD, NetBSD, OpenBSD, MacOS X, Cygwin */
+# elif defined __sferror            /* FreeBSD, NetBSD, OpenBSD, MacOS X, Cygwin */
   fp->_p = fp->_bf._base;
   fp->_r = 0;
-  fp->_w = ((fp->_flags & (__SLBF | __SNBF)) == 0 /* fully buffered? */
+  fp->_w = ((fp->_flags & (__SLBF | __SNBF | __SRD)) == 0 /* fully buffered and not currently reading? */
            ? fp->_bf._size
            : 0);
   /* Avoid memory leak when there is an active ungetc buffer.  */
-# if defined __NetBSD__ || defined __OpenBSD__ /* NetBSD, OpenBSD */
+#  if defined __NetBSD__ || defined __OpenBSD__ /* NetBSD, OpenBSD */
    /* See <http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdio/fileext.h?rev=HEAD&content-type=text/x-cvsweb-markup>
       and <http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/fileext.h?rev=HEAD&content-type=text/x-cvsweb-markup> */
-#  define fp_ub ((struct { struct __sbuf _ub; } *) fp->_ext._base)->_ub
-# else                                         /* FreeBSD, MacOS X, Cygwin */
-#  define fp_ub fp->_ub
-# endif
+#   define fp_ub ((struct { struct __sbuf _ub; } *) fp->_ext._base)->_ub
+#  else                                         /* FreeBSD, MacOS X, Cygwin */
+#   define fp_ub fp->_ub
+#  endif
   if (fp_ub._base != NULL)
     {
       if (fp_ub._base != fp->_ubuf)
@@ -59,12 +91,14 @@ fpurge (FILE *fp)
       fp_ub._base = NULL;
     }
   return 0;
-#elif defined _IOERR                /* AIX, HP-UX, IRIX, OSF/1, Solaris, mingw */
+# elif defined _IOERR               /* AIX, HP-UX, IRIX, OSF/1, Solaris, mingw */
   fp->_ptr = fp->_base;
   if (fp->_ptr != NULL)
     fp->_cnt = 0;
   return 0;
-#else
+# else
  #error "Please port gnulib fpurge.c to your platform! Look at the definitions of fflush, setvbuf and ungetc on your system, then report this to bug-gnulib."
+# endif
+
 #endif
 }
index 87600f8..d4300a6 100644 (file)
    with this program; if not, write to the Free Software Foundation,
    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
+#ifndef _GL_FPURGE_H
+#define _GL_FPURGE_H
+
 #include <stdio.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* Discard all pending buffered I/O on the stream STREAM.
    STREAM must not be wide-character oriented.
    Return 0 if successful.  Upon error, return -1 and set errno.  */
-
-#if HAVE___FPURGE /* glibc >= 2.2, Solaris >= 7 */
-
-# include <stdio_ext.h>
-# define fpurge(stream) (__fpurge (stream), 0)
-
-#elif ! HAVE_DECL_FPURGE
-
-# ifdef __cplusplus
-extern "C" {
-# endif
-
+#if HAVE_FPURGE
+# define fpurge rpl_fpurge
+#endif
 extern int fpurge (FILE *stream);
 
-# ifdef __cplusplus
+#ifdef __cplusplus
 }
-# endif
-
 #endif
+
+#endif /* _GL_FPURGE_H */
index e7a7f74..adb6c64 100644 (file)
@@ -46,7 +46,7 @@ rpl_fseeko (FILE *fp, off_t offset, int whence)
 # endif
   if (fp->_p == fp->_bf._base
       && fp->_r == 0
-      && fp->_w == ((fp->_flags & (__SLBF | __SNBF)) == 0 /* fully buffered? */
+      && fp->_w == ((fp->_flags & (__SLBF | __SNBF | __SRD)) == 0 /* fully buffered and not currently reading? */
                    ? fp->_bf._size
                    : 0)
       && fp_ub._base == NULL)
index 2de2179..796b66c 100644 (file)
@@ -1,4 +1,4 @@
-# fpurge.m4 serial 1
+# fpurge.m4 serial 2
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -9,8 +9,4 @@ AC_DEFUN([gl_FUNC_FPURGE],
   AC_CHECK_FUNCS_ONCE([fpurge])
   AC_CHECK_FUNCS_ONCE([__fpurge])
   AC_CHECK_DECLS([fpurge], , , [#include <stdio.h>])
-  if test $ac_cv_func_fpurge = no && test $ac_cv_func___fpurge = no; then
-    AC_LIBOBJ([fpurge])
-    AC_CHECK_FUNCS([fpurge])
-  fi
 ])
index abec32f..af470e1 100644 (file)
@@ -12,6 +12,7 @@ configure.ac:
 gl_FUNC_FPURGE
 
 Makefile.am:
+lib_SOURCES += fpurge.c
 
 Include:
 "fpurge.h"