From 55ca839ef4bfcf78114ef277c618385b521a5f5c Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sat, 1 May 2010 20:32:26 +0200 Subject: [PATCH] ftell, ftello: Work around Solaris bug. --- ChangeLog | 12 ++++++ doc/posix-functions/ftell.texi | 4 ++ doc/posix-functions/ftello.texi | 4 ++ lib/ftello.c | 24 +++++++++++ m4/ftello.m4 | 93 +++++++++++++++++++++++++++++++++++++++-- modules/ftello | 1 + 6 files changed, 135 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 254b5f1cc..5a0d6d96b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,17 @@ 2010-05-01 Bruno Haible + ftell, ftello: Work around Solaris bug. + * m4/ftello.m4 (gl_FUNC_FTELLO): Detect Solaris bug. + * lib/ftello.c: Include stdio-impl.h. + (ftello): On Solaris, when _IOWRT is set, compute the result without + looking at _IOREAD. + * modules/ftello (Files): Add lib/stdio-impl.h. + * doc/posix-functions/ftell.texi: Mention Solaris bug. + * doc/posix-functions/ftello.texi: Likewise. + Reported by Eric Blake. + +2010-05-01 Bruno Haible + freading: Adapt to special meaning of _IOREAD flag on Solaris. * lib/freading.c (freading): On Solaris, ignore the _IOREAD flag if the _IOWRT flag is also set. diff --git a/doc/posix-functions/ftell.texi b/doc/posix-functions/ftell.texi index f2cf56826..319097532 100644 --- a/doc/posix-functions/ftell.texi +++ b/doc/posix-functions/ftell.texi @@ -10,6 +10,10 @@ Portability problems fixed by Gnulib: @itemize @item This function mistakenly succeeds on pipes on some platforms: mingw. +@item +This function produces incorrect results after @code{putc} that followed a +@code{getc} call that reached EOF on some platforms: +Solaris 10. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/posix-functions/ftello.texi b/doc/posix-functions/ftello.texi index 66a96c06e..ac3e3ebc7 100644 --- a/doc/posix-functions/ftello.texi +++ b/doc/posix-functions/ftello.texi @@ -15,6 +15,10 @@ IRIX 5.3, OSF/1 4.0, Solaris 2.5.1, mingw. The declaration of @code{ftello} in @code{} is not enabled by default on some platforms: glibc 2.3.6. @item +This function produces incorrect results after @code{putc} that followed a +@code{getc} call that reached EOF on some platforms: +Solaris 10. +@item This function fails on seekable stdin, stdout, and stderr: cygwin <= 1.5.24. @end itemize diff --git a/lib/ftello.c b/lib/ftello.c index a15e26bc1..098e36ae5 100644 --- a/lib/ftello.c +++ b/lib/ftello.c @@ -22,6 +22,8 @@ /* Get lseek. */ #include +#include "stdio-impl.h" + off_t ftello (FILE *fp) #undef ftello @@ -36,6 +38,28 @@ ftello (FILE *fp) return -1; #endif +#if FTELLO_BROKEN_AFTER_SWITCHING_FROM_READ_TO_WRITE /* Solaris */ + /* The Solaris stdio leaves the _IOREAD flag set after reading from a file + reaches EOF and the program then starts writing to the file. ftello + gets confused by this. */ + if (fp_->_flag & _IOWRT) + { + off_t pos; + + /* Call ftello nevertheless, for the side effects that it does on fp. */ + ftello (fp); + + /* Compute the file position ourselves. */ + pos = llseek (fileno (fp), (off_t) 0, SEEK_CUR); + if (pos >= 0) + { + if ((fp_->_flag & _IONBF) == 0 && fp_->_base != NULL) + pos += fp_->_ptr - fp_->_base; + } + return pos; + } +#endif + #if defined __SL64 && defined __SCLE /* Cygwin */ if ((fp->_flags & __SL64) == 0) { diff --git a/m4/ftello.m4 b/m4/ftello.m4 index fba549a4f..ae9a4e613 100644 --- a/m4/ftello.m4 +++ b/m4/ftello.m4 @@ -1,5 +1,5 @@ -# ftello.m4 serial 6 -dnl Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc. +# ftello.m4 serial 7 +dnl Copyright (C) 2007-2010 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. @@ -10,7 +10,7 @@ AC_DEFUN([gl_FUNC_FTELLO], AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([gl_STDIN_LARGE_OFFSET]) - dnl Persuade glibc to declare fseeko(). + dnl Persuade glibc to declare ftello(). AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) AC_CACHE_CHECK([for ftello], [gl_cv_func_ftello], @@ -23,6 +23,93 @@ AC_DEFUN([gl_FUNC_FTELLO], else if test $gl_cv_var_stdin_large_offset = no; then REPLACE_FTELLO=1 + else + dnl Detect bug on Solaris. + dnl ftell and ftello produce incorrect results after putc that followed a + dnl getc call that reached EOF on Solaris. This is because the _IOREAD + dnl flag does not get cleared in this case, even though _IOWRT gets set, + dnl and ftell and ftello look whether the _IOREAD flag is set. + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_CACHE_CHECK([whether ftello works], + [gl_cv_func_ftello_works], + [ + dnl Initial guess, used when cross-compiling or when /dev/tty cannot + dnl be opened. +changequote(,)dnl + case "$host_os" in + # Guess no on Solaris. + solaris*) gl_cv_func_ftello_works="guessing no" ;; + # Guess yes otherwise. + *) gl_cv_func_ftello_works="guessing yes" ;; + esac +changequote([,])dnl + AC_TRY_RUN([ +#include +#include +#include +#define TESTFILE "conftest.tmp" +int +main (void) +{ + FILE *fp; + + /* Create a file with some contents. */ + fp = fopen (TESTFILE, "w"); + if (fp == NULL) + return 70; + if (fwrite ("foogarsh", 1, 8, fp) < 8) + return 71; + if (fclose (fp)) + return 72; + + /* The file's contents is now "foogarsh". */ + + /* Try writing after reading to EOF. */ + fp = fopen (TESTFILE, "r+"); + if (fp == NULL) + return 73; + if (fseek (fp, -1, SEEK_END)) + return 74; + if (!(getc (fp) == 'h')) + return 1; + if (!(getc (fp) == EOF)) + return 2; + if (!(ftell (fp) == 8)) + return 3; + if (!(ftell (fp) == 8)) + return 4; + if (!(putc ('!', fp) == '!')) + return 5; + if (!(ftell (fp) == 9)) + return 6; + if (!(fclose (fp) == 0)) + return 7; + fp = fopen (TESTFILE, "r"); + if (fp == NULL) + return 75; + { + char buf[10]; + if (!(fread (buf, 1, 10, fp) == 9)) + return 10; + if (!(memcmp (buf, "foogarsh!", 9) == 0)) + return 11; + } + if (!(fclose (fp) == 0)) + return 12; + + /* The file's contents is now "foogarsh!". */ + + return 0; +}], [gl_cv_func_ftello_works=yes], [gl_cv_func_ftello_works=no], [:]) + ]) + case "$gl_cv_func_ftello_works" in + *yes) ;; + *) + REPLACE_FTELLO=1 + AC_DEFINE([FTELLO_BROKEN_AFTER_SWITCHING_FROM_READ_TO_WRITE], [1], + [Define to 1 if the system's ftello function has the Solaris bug.]) + ;; + esac fi fi if test $HAVE_FTELLO = 0 || test $REPLACE_FTELLO = 1; then diff --git a/modules/ftello b/modules/ftello index 9a0b62d02..4ba80e3c7 100644 --- a/modules/ftello +++ b/modules/ftello @@ -3,6 +3,7 @@ ftello() function: Retrieve the position of a FILE stream. Files: lib/ftello.c +lib/stdio-impl.h m4/ftello.m4 Depends-on: -- 2.11.0