changeset 8759:95c5da6920cb

Work around fpurge bug on BSD systems.
author Bruno Haible <bruno@clisp.org>
date Sun, 29 Apr 2007 12:16:55 +0000
parents 29e3274acedc
children 72eb420b405f
files ChangeLog lib/fpurge.c lib/fpurge.h lib/fseeko.c m4/fpurge.m4 modules/fpurge
diffstat 6 files changed, 73 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- 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
--- a/lib/fpurge.c
+++ b/lib/fpurge.c
@@ -20,15 +20,47 @@
 /* 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 @@
       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 @@
       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
 }
--- a/lib/fpurge.h
+++ b/lib/fpurge.h
@@ -15,27 +15,25 @@
    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
+#endif /* _GL_FPURGE_H */
--- a/lib/fseeko.c
+++ b/lib/fseeko.c
@@ -46,7 +46,7 @@
 # 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)
--- a/m4/fpurge.m4
+++ b/m4/fpurge.m4
@@ -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_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
 ])
--- a/modules/fpurge
+++ b/modules/fpurge
@@ -12,6 +12,7 @@
 gl_FUNC_FPURGE
 
 Makefile.am:
+lib_SOURCES += fpurge.c
 
 Include:
 "fpurge.h"