+2021-03-20 Bruno Haible <bruno@clisp.org>
+
+ ftello: Work around bug in macOS >= 10.15.
+ Reported by Martin Storsjö <martin@martin.st> in
+ <https://lists.gnu.org/archive/html/bug-gnulib/2020-12/msg00002.html>.
+ * m4/ungetc.m4 (gl_FUNC_UNGETC_WORKS): On macOS, don't define
+ FUNC_UNGETC_BROKEN. Instead, set gl_ftello_broken_after_ungetc to yes.
+ * m4/ftello.m4 (gl_FUNC_FTELLO): Invoke gl_FUNC_UNGETC_WORKS, and
+ arrange to provide the workaround if ftello is broken after ungetc.
+ * lib/ftello.c: Include <errno.h>, intprops.h.
+ (ftello) [FTELLO_BROKEN_AFTER_UNGETC]: Implement from scratch.
+ * modules/ftello (Files): Add m4/ungetc.m4.
+ (Depends-on): Add intprops.
+ * doc/posix-functions/ftello.texi: Mention the macOS bug.
+
2021-03-20 Bruno Haible <bruno@clisp.org>
math C++ tests: Fix compilation error on macOS 11.2.
@code{getc} call that reached EOF on some platforms:
Solaris 11 2010-11.
@item
+This function, when invoked after @code{ungetc}, throws away the @code{ungetc}
+buffer, changes the stream's file position, and returns the wrong position on
+some platforms:
+macOS 10.15 and newer.
+@item
This function fails on seekable stdin, stdout, and stderr: cygwin <= 1.5.24.
@item
On platforms where @code{off_t} is a 32-bit type, @code{ftello} does not work
/* Specification. */
#include <stdio.h>
+#include <errno.h>
+#include "intprops.h"
+
/* Get lseek. */
#include <unistd.h>
# endif
#endif
{
-#if LSEEK_PIPE_BROKEN
+#if FTELLO_BROKEN_AFTER_UNGETC /* macOS >= 10.15 */
+ /* The system's ftello() is completely broken, because it calls __sflush,
+ which makes side effects on the stream. */
+
+ /* Handle non-seekable files first. */
+ if (fp->_file < 0 || fp->_seek == NULL)
+ {
+ errno = ESPIPE;
+ return -1;
+ }
+
+ /* Determine the current offset, ignoring buffered and pushed-back bytes. */
+ off_t pos;
+
+ if (fp->_flags & __SOFF)
+ pos = fp->_offset;
+ else
+ {
+ pos = fp->_seek (fp->_cookie, 0, SEEK_CUR);
+ if (pos < 0)
+ return -1;
+ if (fp->_flags & __SOPT)
+ {
+ fp->_offset = pos;
+ fp->_flags |= __SOFF;
+ }
+ }
+
+ if (fp->_flags & __SRD)
+ {
+ /* Now consider buffered and pushed-back bytes from ungetc. */
+ if (fp->_ub._base != NULL)
+ /* Considering the buffered bytes, we are at position
+ pos - fp->_ur.
+ Considering also the pushed-back bytes, we are at position
+ pos - fp->_ur - fp->_r. */
+ pos = pos - fp->_ur - fp->_r;
+ else
+ /* Considering the buffered bytes, we are at position
+ pos - fp->_r. */
+ pos = pos - fp->_r;
+ if (pos < 0)
+ {
+ errno = EIO;
+ return -1;
+ }
+ }
+ else if ((fp->_flags & __SWR) && fp->_p != NULL)
+ {
+ /* Consider the buffered bytes. */
+ off_t buffered = fp->_p - fp->_bf._base;
+
+ /* Compute pos + buffered, with overflow check. */
+ off_t sum;
+ if (! INT_ADD_OK (pos, buffered, &sum))
+ {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ pos = sum;
+ }
+
+ return pos;
+
+#else
+
+# if LSEEK_PIPE_BROKEN
/* mingw gives bogus answers rather than failure on non-seekable files. */
if (lseek (fileno (fp), 0, SEEK_CUR) == -1)
return -1;
-#endif
+# endif
-#if FTELLO_BROKEN_AFTER_SWITCHING_FROM_READ_TO_WRITE /* Solaris */
+# 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. */
}
return pos;
}
-#endif
+# endif
-#if defined __SL64 && defined __SCLE /* Cygwin */
+# if defined __SL64 && defined __SCLE /* Cygwin */
if ((fp->_flags & __SL64) == 0)
{
/* Cygwin 1.5.0 through 1.5.24 failed to open stdin in 64-bit
fp->_seek64 = tmp->_seek64;
fclose (tmp);
}
-#endif
+# endif
+
return ftello (fp);
+
+#endif
}
-# ftello.m4 serial 13
+# ftello.m4 serial 14
dnl Copyright (C) 2007-2021 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
;;
esac
fi
+ if test $REPLACE_FTELLO = 0; then
+ dnl Detect bug on macOS >= 10.15.
+ gl_FUNC_UNGETC_WORKS
+ if test $gl_ftello_broken_after_ungetc = yes; then
+ REPLACE_FTELLO=1
+ AC_DEFINE([FTELLO_BROKEN_AFTER_UNGETC], [1],
+ [Define to 1 if the system's ftello function has the macOS bug.])
+ fi
+ fi
fi
])
-# ungetc.m4 serial 9
+# ungetc.m4 serial 10
dnl Copyright (C) 2009-2021 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
esac
])
])
+ gl_ftello_broken_after_ungetc=no
case "$gl_cv_func_ungetc_works" in
*yes) ;;
*)
- AC_DEFINE([FUNC_UNGETC_BROKEN], [1],
- [Define to 1 if ungetc is broken when used on arbitrary bytes.])
+ dnl On macOS >= 10.15, where the above program fails with exit code 6,
+ dnl we fix it through an ftello override.
+ case "$host_os" in
+ darwin*) gl_ftello_broken_after_ungetc=yes ;;
+ *)
+ AC_DEFINE([FUNC_UNGETC_BROKEN], [1],
+ [Define to 1 if ungetc is broken when used on arbitrary bytes.])
+ ;;
+ esac
;;
esac
])
lib/stdio-impl.h
m4/fseeko.m4
m4/ftello.m4
+m4/ungetc.m4
Depends-on:
stdio
largefile
sys_types
lseek [test $HAVE_FTELLO = 0 || test $REPLACE_FTELLO = 1]
+intprops [test $HAVE_FTELLO = 0 || test $REPLACE_FTELLO = 1]
# Just to guarantee consistency between ftell() and ftello().
ftell