On 2007-04-13, I wrote: > 2) fseek() is heavily optimized: fseeko (fp, pos, SEEK_SET) will position > the file descriptor to pos & ~fp->_blksize and then read one buffer, > [or if pos is inside the current buffer, optimize even more: just > change some pointers and counters, without accessing the file descriptor], > unless > - fp is not seekable, or > - fp is open for writing (__SWR | __SRW), or > - fp is unbuffered (__SNBF), or > - fp has an unusual block size set through setvbuf (__SNPT). > If your fflush or fseek was to invoke setvbuf, it's hard to keep programs > working that use setvbuf as well. > > A solution might be to make a wrapper around fseek() roughly like this: > > rpl_fseek (...) > { > if (fp is not open for writing > && fp's buffer is empty, like after fpurge) > perform just an lseek > else > fseek (...); > }
This implements it. 2007-04-25 Bruno Haible <[EMAIL PROTECTED]> Make fflush+fseek POSIX-compliant on FreeBSD and MacOS X. * lib/fseeko.c: New file. * lib/stdio_.h: Include <sys/types.h> when off_t is needed. (fseeko, fseek): Define to replacements if REPLACE_FFLUSH. * m4/fseeko.m4 (gl_CHECK_FSEEKO): New macro, extracted from gl_FUNC_FSEEKO. (gl_FUNC_FSEEKO): Invoke it. * m4/fflush.m4 (gl_REPLACE_FFLUSH): Arrange to compile fseeko.c. Invoke gl_CHECK_FSEEKO. Define HAVE_FSEEKO. * modules/fflush (Files): Add lib/fseeko.c, m4/fseeko.m4. ======================== lib/fseeko.c ==================================== /* An fseek() function that, together with fflush(), is POSIX compliant. Copyright (C) 2007 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 the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <config.h> /* Specification. */ #include <stdio.h> /* Get off_t and lseek. */ #include <unistd.h> #undef fseeko #if !HAVE_FSEEKO # define fseeko fseek #endif int rpl_fseeko (FILE *fp, off_t offset, int whence) { /* These tests are based on fpurge.c. */ #if defined _IO_ferror_unlocked /* GNU libc, BeOS */ if (fp->_IO_read_end == fp->_IO_read_ptr && fp->_IO_write_ptr == fp->_IO_write_base && fp->_IO_save_base == NULL) #elif defined __sferror /* FreeBSD, NetBSD, OpenBSD, MacOS X, Cygwin */ # 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 if (fp->_p == fp->_bf._base && fp->_r == 0 && fp->_w == ((fp->_flags & (__SLBF | __SNBF)) == 0 /* fully buffered? */ ? fp->_bf._size : 0) && fp_ub._base == NULL) #elif defined _IOERR /* AIX, HP-UX, IRIX, OSF/1, Solaris, mingw */ # if defined __sun && defined __sparc && defined _LP64 /* Solaris/SPARC 64-bit */ # define fp_ ((struct { unsigned char *_ptr; \ unsigned char *_base; \ unsigned char *_end; \ long _cnt; \ } *) fp) if (fp_->_ptr == fp_->_base && (fp_->_ptr == NULL || fp_->_cnt == 0)) # else if (fp->_ptr == fp->_base && (fp->_ptr == NULL || fp->_cnt == 0)) # endif #else #error "Please port gnulib fseeko.c to your platform! Look at the code in fpurge.c, then report this to bug-gnulib." #endif return (lseek (fileno (fp), offset, whence) == (off_t)(-1) ? -1 : 0); else return fseeko (fp, offset, whence); } ========================================================================== *** lib/stdio_.h 25 Apr 2007 07:51:53 -0000 1.19 --- lib/stdio_.h 25 Apr 2007 09:10:07 -0000 *************** *** 38,43 **** --- 38,48 ---- #include <stdarg.h> #include <stddef.h> + #if @GNULIB_FFLUSH@ && @REPLACE_FFLUSH@ + /* Get off_t. */ + # include <sys/types.h> + #endif + #ifndef __attribute__ /* This feature is available in gcc versions 2.5 and later. */ # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ *************** *** 207,213 **** # endif #endif ! #if @GNULIB_FSEEKO@ # if [EMAIL PROTECTED]@ /* Assume 'off_t' is the same type as 'long'. */ # define fseeko fseek --- 212,223 ---- # endif #endif ! #if @GNULIB_FFLUSH@ && @REPLACE_FFLUSH@ ! /* Provide fseek, fseeko functions that are aware of a preceding fflush(). */ ! # define fseeko rpl_fseeko ! extern int fseeko (FILE *fp, off_t offset, int whence); ! # define fseek(fp, offset, whence) fseeko (fp, (off_t)(offset), whence) ! #elif @GNULIB_FSEEKO@ # if [EMAIL PROTECTED]@ /* Assume 'off_t' is the same type as 'long'. */ # define fseeko fseek *** m4/fseeko.m4 25 Apr 2007 07:39:56 -0000 1.1 --- m4/fseeko.m4 25 Apr 2007 09:10:07 -0000 *************** *** 7,19 **** AC_DEFUN([gl_FUNC_FSEEKO], [ AC_REQUIRE([gl_STDIO_H_DEFAULTS]) AC_REQUIRE([AC_PROG_CC]) AC_CACHE_CHECK([for fseeko], [gl_cv_func_fseeko], [ AC_TRY_LINK([#include <stdio.h>], [fseeko (stdin, 0, 0);], [gl_cv_func_fseeko=yes], [gl_cv_func_fseeko=no]) ]) - if test $gl_cv_func_fseeko = no; then - HAVE_FSEEKO=0 - fi ]) --- 7,24 ---- AC_DEFUN([gl_FUNC_FSEEKO], [ AC_REQUIRE([gl_STDIO_H_DEFAULTS]) + gl_CHECK_FSEEKO + if test $gl_cv_func_fseeko = no; then + HAVE_FSEEKO=0 + fi + ]) + + AC_DEFUN([gl_CHECK_FSEEKO], + [ AC_REQUIRE([AC_PROG_CC]) AC_CACHE_CHECK([for fseeko], [gl_cv_func_fseeko], [ AC_TRY_LINK([#include <stdio.h>], [fseeko (stdin, 0, 0);], [gl_cv_func_fseeko=yes], [gl_cv_func_fseeko=no]) ]) ]) *** m4/fflush.m4 17 Apr 2007 03:40:30 -0000 1.3 --- m4/fflush.m4 25 Apr 2007 09:10:07 -0000 *************** *** 1,4 **** ! #serial 2 # Copyright (C) 2007 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation --- 1,4 ---- ! #serial 3 # Copyright (C) 2007 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation *************** *** 45,50 **** --- 45,56 ---- AC_DEFUN([gl_REPLACE_FFLUSH], [ AC_LIBOBJ([fflush]) + AC_LIBOBJ([fseeko]) AC_REQUIRE([gl_STDIO_H_DEFAULTS]) REPLACE_FFLUSH=1 + gl_CHECK_FSEEKO + if test $gl_cv_func_fseeko = yes; then + AC_DEFINE([HAVE_FSEEKO], 1, + [Define to 1 if you have the fseeko() function or macro.]) + fi ]) *** modules/fflush 25 Apr 2007 07:56:32 -0000 1.4 --- modules/fflush 25 Apr 2007 09:10:07 -0000 *************** *** 3,9 **** --- 3,11 ---- Files: lib/fflush.c + lib/fseeko.c m4/fflush.m4 + m4/fseeko.m4 Depends-on: fpurge