stdio patch

Eric Blake ebb9@byu.net
Thu Dec 14 22:54:00 GMT 2006


Jeff, this patch is based on what you sent me privately, plus a typo fix for 
SEEK_SET instead of SEEK_CUR, and the additional fix to keep fp->offset up-to-
date when __SOFF.  With it, I now get the POSIX-mandated behavior on cygwin for:

$ echo 1 2 3 | tr ' ' '\n' > file
$ (sed -n 1q; cat) < file
2
3


2006-12-14  Jeff Johnston  <jjohnstn@redhat.com>
        and Eric Blake  <ebb9@byu.net>

        * libc/stdio/fflush.c (fflush): On seekable streams, always flush
        read but unused data.
        * libc/stdio/fclose.c (_fclose_r): Always flush streams, since
        even read streams may have side effects that must happen.

Index: libc/stdio/fclose.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/fclose.c,v
retrieving revision 1.11
diff -u -p -r1.11 fclose.c
--- libc/stdio/fclose.c 26 Sep 2006 21:22:19 -0000      1.11
+++ libc/stdio/fclose.c 14 Dec 2006 21:22:44 -0000
@@ -86,7 +86,10 @@ _DEFUN(_fclose_r, (rptr, fp),
       __sfp_lock_release ();
       return (0);
     }
-  r = fp->_flags & __SWR ? fflush (fp) : 0;
+  /* Unconditionally flush to allow special handling for seekable read
+     files to reposition file to last byte processed as opposed to
+     last byte read ahead into the buffer.  */
+  r = fflush (fp);
   if (fp->_close != NULL && (*fp->_close) (fp->_cookie) < 0)
     r = EOF;
   if (fp->_flags & __SMBF)
Index: libc/stdio/fflush.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdio/fflush.c,v
retrieving revision 1.7
diff -u -p -r1.7 fflush.c
--- libc/stdio/fflush.c 26 Sep 2006 21:22:19 -0000      1.7
+++ libc/stdio/fflush.c 14 Dec 2006 21:22:44 -0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1990 The Regents of the University of California.
+ * Copyright (c) 1990, 2006 The Regents of the University of California.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms are permitted
@@ -74,10 +74,56 @@ _DEFUN(fflush, (fp),
   t = fp->_flags;
   if ((t & __SWR) == 0)
     {
+      _fpos_t _EXFUN((*seekfn), (_PTR, _fpos_t, int));
+
       /* For a read stream, an fflush causes the next seek to be
          unoptimized (i.e. forces a system-level seek).  This conforms
          to the POSIX and SUSv3 standards.  */
       fp->_flags |= __SNPT;
+
+      /* For a seekable stream with buffered read characters, we will attempt
+         a seek to the current position now.  A subsequent read will then get
+         the next byte from the file rather than the buffer.  This conforms
+         to the POSIX and SUSv3 standards.  Note that the standards allow
+         this seek to be deferred until necessary, but we choose to do it here
+         to make the change simpler, more contained, and less likely
+         to miss a code scenario.  */
+      if ((fp->_r > 0 || fp->_ur > 0) && (seekfn = fp->_seek) != NULL)
+        {
+          _fpos_t curoff;
+
+          /* Get the physical position we are at in the file.  */
+          if (fp->_flags & __SOFF)
+            curoff = fp->_offset;
+          else
+            {
+              /* We don't know current physical offset, so ask for it.  */
+              curoff = (*seekfn) (fp->_cookie, (_fpos_t) 0, SEEK_CUR);
+              if (curoff == -1L)
+                {
+                  _funlockfile (fp);
+                  return 0;
+                }
+            }
+          if (fp->_flags & __SRD)
+            {
+              /* Current offset is at end of buffer.  Compensate for
+                 characters not yet read.  */
+              curoff -= fp->_r;
+              if (HASUB (fp))
+                curoff -= fp->_ur;
+            }
+          /* Now physically seek to after byte last read.  */
+          if ((*seekfn)(fp->_cookie, curoff, SEEK_SET) != -1)
+            {
+              /* Seek successful.  We can clear read buffer now.  */
+              fp->_flags &= ~__SNPT;
+              fp->_r = 0;
+              fp->_p = fp->_bf._base;
+              if (fp->_flags & __SOFF)
+                fp->_offset = curoff;
+            }
+        } 
       _funlockfile (fp);
       return 0;
     }




More information about the Newlib mailing list