changeset 14583:8b22057e98d2

Support non-blocking pipe I/O in read() on native Windows. * lib/unistd.in.h: Include <sys/types.h> also for 'read'. (read): New declaration. * lib/read.c: New file. * lib/stdio.in.h (_GL_ATTRIBUTE_FORMAT_SCANF, _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM): New macros. (fgetc, fgets, fread, fscanf, getc, getchar, gets, scanf, vfscanf, vscanf): New declarations. * lib/stdio-read.c: New file. * m4/read.m4: New file. * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Initialize GNULIB_READ, REPLACE_READ. * m4/stdio_h.m4 (gl_STDIO_H): Set GNULIB_FGETC, GNULIB_FGETS, GNULIB_FREAD, GNULIB_FSCANF, GNULIB_GETC, GNULIB_GETCHAR, GNULIB_GETS, GNULIB_SCANF, GNULIB_VFSCANF, GNULIB_VSCANF. In non-blocking I/O is desired and needs workarounds, set REPLACE_STDIO_READ_FUNCS. (gl_STDIO_H_DEFAULTS): Initialize GNULIB_FGETC, GNULIB_FGETS, GNULIB_FREAD, GNULIB_FSCANF, GNULIB_GETC, GNULIB_GETCHAR, GNULIB_GETS, GNULIB_SCANF, GNULIB_VFSCANF, GNULIB_VSCANF, REPLACE_STDIO_READ_FUNCS. * modules/read: New file. * modules/nonblocking (Files): Add lib/stdio-read.c. * modules/unistd (Makefile.am): Substitute GNULIB_READ, REPLACE_READ. * modules/stdio (Makefile.am): Substitute GNULIB_FGETC, GNULIB_FGETS, GNULIB_FREAD, GNULIB_FSCANF, GNULIB_GETC, GNULIB_GETCHAR, GNULIB_GETS, GNULIB_SCANF, GNULIB_VFSCANF, GNULIB_VSCANF, REPLACE_STDIO_READ_FUNCS. * modules/pread (Depends-on): Add read. * modules/safe-read (Depends-on): Likewise. * tests/test-stdio-c++.cc (fgetc, fgets, fread, fscanf, getc, getchar, gets, scanf, vfscanf, vscanf): Verify signatures. * doc/posix-functions/read.texi: Mention 'nonblocking' module and problem with non-blocking pipes. * doc/posix-functions/fgetc.texi: Likewise. * doc/posix-functions/fgets.texi: Likewise. * doc/posix-functions/fread.texi: Likewise. * doc/posix-functions/fscanf.texi: Likewise. * doc/posix-functions/getc.texi: Likewise. * doc/posix-functions/getchar.texi: Likewise. * doc/posix-functions/gets.texi: Likewise. * doc/posix-functions/scanf.texi: Likewise. * doc/posix-functions/vfscanf.texi: Likewise. * doc/posix-functions/vscanf.texi: Likewise.
author Bruno Haible <bruno@clisp.org>
date Fri, 15 Apr 2011 01:02:13 +0200
parents 3a41e32d28ab
children 2ee8ba36aa81
files ChangeLog doc/posix-functions/fgetc.texi doc/posix-functions/fgets.texi doc/posix-functions/fread.texi doc/posix-functions/fscanf.texi doc/posix-functions/getc.texi doc/posix-functions/getchar.texi doc/posix-functions/gets.texi doc/posix-functions/read.texi doc/posix-functions/scanf.texi doc/posix-functions/vfscanf.texi doc/posix-functions/vscanf.texi lib/read.c lib/stdio-read.c lib/stdio.in.h lib/unistd.in.h m4/read.m4 m4/stdio_h.m4 m4/unistd_h.m4 modules/nonblocking modules/pread modules/read modules/safe-read modules/stdio modules/unistd tests/test-stdio-c++.cc
diffstat 26 files changed, 685 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,47 @@
+2011-04-14  Bruno Haible  <bruno@clisp.org>
+
+	Support non-blocking pipe I/O in read() on native Windows.
+	* lib/unistd.in.h: Include <sys/types.h> also for 'read'.
+	(read): New declaration.
+	* lib/read.c: New file.
+	* lib/stdio.in.h (_GL_ATTRIBUTE_FORMAT_SCANF,
+	_GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM): New macros.
+	(fgetc, fgets, fread, fscanf, getc, getchar, gets, scanf, vfscanf,
+	vscanf): New declarations.
+	* lib/stdio-read.c: New file.
+	* m4/read.m4: New file.
+	* m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Initialize GNULIB_READ,
+	REPLACE_READ.
+	* m4/stdio_h.m4 (gl_STDIO_H): Set GNULIB_FGETC, GNULIB_FGETS,
+	GNULIB_FREAD, GNULIB_FSCANF, GNULIB_GETC, GNULIB_GETCHAR, GNULIB_GETS,
+	GNULIB_SCANF, GNULIB_VFSCANF, GNULIB_VSCANF. In non-blocking I/O is
+	desired and needs workarounds, set REPLACE_STDIO_READ_FUNCS.
+	(gl_STDIO_H_DEFAULTS): Initialize GNULIB_FGETC, GNULIB_FGETS,
+	GNULIB_FREAD, GNULIB_FSCANF, GNULIB_GETC, GNULIB_GETCHAR, GNULIB_GETS,
+	GNULIB_SCANF, GNULIB_VFSCANF, GNULIB_VSCANF, REPLACE_STDIO_READ_FUNCS.
+	* modules/read: New file.
+	* modules/nonblocking (Files): Add lib/stdio-read.c.
+	* modules/unistd (Makefile.am): Substitute GNULIB_READ, REPLACE_READ.
+	* modules/stdio (Makefile.am): Substitute GNULIB_FGETC, GNULIB_FGETS,
+	GNULIB_FREAD, GNULIB_FSCANF, GNULIB_GETC, GNULIB_GETCHAR, GNULIB_GETS,
+	GNULIB_SCANF, GNULIB_VFSCANF, GNULIB_VSCANF, REPLACE_STDIO_READ_FUNCS.
+	* modules/pread (Depends-on): Add read.
+	* modules/safe-read (Depends-on): Likewise.
+	* tests/test-stdio-c++.cc (fgetc, fgets, fread, fscanf, getc, getchar,
+	gets, scanf, vfscanf, vscanf): Verify signatures.
+	* doc/posix-functions/read.texi: Mention 'nonblocking' module and
+	problem with non-blocking pipes.
+	* doc/posix-functions/fgetc.texi: Likewise.
+	* doc/posix-functions/fgets.texi: Likewise.
+	* doc/posix-functions/fread.texi: Likewise.
+	* doc/posix-functions/fscanf.texi: Likewise.
+	* doc/posix-functions/getc.texi: Likewise.
+	* doc/posix-functions/getchar.texi: Likewise.
+	* doc/posix-functions/gets.texi: Likewise.
+	* doc/posix-functions/scanf.texi: Likewise.
+	* doc/posix-functions/vfscanf.texi: Likewise.
+	* doc/posix-functions/vscanf.texi: Likewise.
+
 2011-04-14  Bruno Haible  <bruno@clisp.org>
 
 	Support non-blocking pipe I/O in write() on native Windows.
--- a/doc/posix-functions/fgetc.texi
+++ b/doc/posix-functions/fgetc.texi
@@ -4,10 +4,15 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/fgetc.html}
 
-Gnulib module: ---
+Gnulib module: stdio, nonblocking
 
-Portability problems fixed by Gnulib:
+Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}:
 @itemize
+@item
+When reading from a non-blocking pipe whose buffer is empty, this function
+fails with @code{errno} being set to @code{EINVAL} instead of @code{EAGAIN} on
+some platforms:
+mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/doc/posix-functions/fgets.texi
+++ b/doc/posix-functions/fgets.texi
@@ -4,10 +4,15 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/fgets.html}
 
-Gnulib module: ---
+Gnulib module: stdio, nonblocking
 
-Portability problems fixed by Gnulib:
+Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}:
 @itemize
+@item
+When reading from a non-blocking pipe whose buffer is empty, this function
+fails with @code{errno} being set to @code{EINVAL} instead of @code{EAGAIN} on
+some platforms:
+mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/doc/posix-functions/fread.texi
+++ b/doc/posix-functions/fread.texi
@@ -4,10 +4,15 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/fread.html}
 
-Gnulib module: ---
+Gnulib module: stdio, nonblocking
 
-Portability problems fixed by Gnulib:
+Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}:
 @itemize
+@item
+When reading from a non-blocking pipe whose buffer is empty, this function
+fails with @code{errno} being set to @code{EINVAL} instead of @code{EAGAIN} on
+some platforms:
+mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/doc/posix-functions/fscanf.texi
+++ b/doc/posix-functions/fscanf.texi
@@ -4,10 +4,15 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/fscanf.html}
 
-Gnulib module: ---
+Gnulib module: stdio, nonblocking
 
-Portability problems fixed by Gnulib:
+Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}:
 @itemize
+@item
+When reading from a non-blocking pipe whose buffer is empty, this function
+fails with @code{errno} being set to @code{EINVAL} instead of @code{EAGAIN} on
+some platforms:
+mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/doc/posix-functions/getc.texi
+++ b/doc/posix-functions/getc.texi
@@ -4,10 +4,15 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/getc.html}
 
-Gnulib module: ---
+Gnulib module: stdio, nonblocking
 
-Portability problems fixed by Gnulib:
+Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}:
 @itemize
+@item
+When reading from a non-blocking pipe whose buffer is empty, this function
+fails with @code{errno} being set to @code{EINVAL} instead of @code{EAGAIN} on
+some platforms:
+mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/doc/posix-functions/getchar.texi
+++ b/doc/posix-functions/getchar.texi
@@ -4,10 +4,15 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/getchar.html}
 
-Gnulib module: ---
+Gnulib module: stdio, nonblocking
 
-Portability problems fixed by Gnulib:
+Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}:
 @itemize
+@item
+When reading from a non-blocking pipe whose buffer is empty, this function
+fails with @code{errno} being set to @code{EINVAL} instead of @code{EAGAIN} on
+some platforms:
+mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/doc/posix-functions/gets.texi
+++ b/doc/posix-functions/gets.texi
@@ -4,10 +4,15 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/gets.html}
 
-Gnulib module: ---
+Gnulib module: stdio, nonblocking
 
-Portability problems fixed by Gnulib:
+Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}:
 @itemize
+@item
+When reading from a non-blocking pipe whose buffer is empty, this function
+fails with @code{errno} being set to @code{EINVAL} instead of @code{EAGAIN} on
+some platforms:
+mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/doc/posix-functions/read.texi
+++ b/doc/posix-functions/read.texi
@@ -4,10 +4,15 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/read.html}
 
-Gnulib module: ---
+Gnulib module: stdio, nonblocking
 
-Portability problems fixed by Gnulib:
+Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}:
 @itemize
+@item
+When reading from a non-blocking pipe whose buffer is empty, this function
+fails with @code{errno} being set to @code{EINVAL} instead of @code{EAGAIN} on
+some platforms:
+mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/doc/posix-functions/scanf.texi
+++ b/doc/posix-functions/scanf.texi
@@ -4,10 +4,15 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/scanf.html}
 
-Gnulib module: ---
+Gnulib module: stdio, nonblocking
 
-Portability problems fixed by Gnulib:
+Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}:
 @itemize
+@item
+When reading from a non-blocking pipe whose buffer is empty, this function
+fails with @code{errno} being set to @code{EINVAL} instead of @code{EAGAIN} on
+some platforms:
+mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/doc/posix-functions/vfscanf.texi
+++ b/doc/posix-functions/vfscanf.texi
@@ -4,10 +4,15 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/vfscanf.html}
 
-Gnulib module: ---
+Gnulib module: stdio, nonblocking
 
-Portability problems fixed by Gnulib:
+Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}:
 @itemize
+@item
+When reading from a non-blocking pipe whose buffer is empty, this function
+fails with @code{errno} being set to @code{EINVAL} instead of @code{EAGAIN} on
+some platforms:
+mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/doc/posix-functions/vscanf.texi
+++ b/doc/posix-functions/vscanf.texi
@@ -4,10 +4,15 @@
 
 POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/vscanf.html}
 
-Gnulib module: ---
+Gnulib module: stdio, nonblocking
 
-Portability problems fixed by Gnulib:
+Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}:
 @itemize
+@item
+When reading from a non-blocking pipe whose buffer is empty, this function
+fails with @code{errno} being set to @code{EINVAL} instead of @code{EAGAIN} on
+some platforms:
+mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
new file mode 100644
--- /dev/null
+++ b/lib/read.c
@@ -0,0 +1,59 @@
+/* POSIX compatible read() function.
+   Copyright (C) 2008-2011 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2011.
+
+   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 3 of the License, 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, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+/* Replace this function only if module 'nonblocking' is requested.  */
+#if GNULIB_NONBLOCKING
+
+# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+
+#  include <errno.h>
+#  include <io.h>
+
+#  define WIN32_LEAN_AND_MEAN  /* avoid including junk */
+#  include <windows.h>
+
+ssize_t
+rpl_read (int fd, void *buf, size_t count)
+#undef read
+{
+  ssize_t ret = read (fd, buf, count);
+
+  if (ret < 0
+      && GetLastError () == ERROR_NO_DATA)
+    {
+      HANDLE h = (HANDLE) _get_osfhandle (fd);
+      if (GetFileType (h) == FILE_TYPE_PIPE)
+        {
+          /* h is a pipe or socket.  */
+          DWORD state;
+          if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0)
+              && (state & PIPE_NOWAIT) != 0)
+            /* h is a pipe in non-blocking mode.
+               Change errno from EINVAL to EAGAIN.  */
+            errno = EAGAIN;
+        }
+    }
+  return ret;
+}
+
+# endif
+#endif
new file mode 100644
--- /dev/null
+++ b/lib/stdio-read.c
@@ -0,0 +1,148 @@
+/* POSIX compatible FILE stream read function.
+   Copyright (C) 2008-2011 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2011.
+
+   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 3 of the License, 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, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <stdio.h>
+
+/* Replace these functions only if module 'nonblocking' is requested.  */
+#if GNULIB_NONBLOCKING
+
+/* On native Windows platforms, when read() is called on a non-blocking pipe
+   with an empty buffer, ReadFile() fails with error GetLastError() =
+   ERROR_NO_DATA, and read() in consequence fails with error EINVAL.  This
+   read() function is at the basis of the function which fills the buffer of
+   a FILE stream.  */
+
+# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+
+#  include <errno.h>
+#  include <io.h>
+
+#  define WIN32_LEAN_AND_MEAN  /* avoid including junk */
+#  include <windows.h>
+
+#  define CALL_WITH_ERRNO_FIX(RETTYPE, EXPRESSION, FAILED) \
+  if (ferror (stream))                                                        \
+    return (EXPRESSION);                                                      \
+  else                                                                        \
+    {                                                                         \
+      RETTYPE ret;                                                            \
+      SetLastError (0);                                                       \
+      ret = (EXPRESSION);                                                     \
+      if (FAILED)                                                             \
+        {                                                                     \
+          if (GetLastError () == ERROR_NO_DATA && ferror (stream))            \
+            {                                                                 \
+              int fd = fileno (stream);                                       \
+              if (fd >= 0)                                                    \
+                {                                                             \
+                  HANDLE h = (HANDLE) _get_osfhandle (fd);                    \
+                  if (GetFileType (h) == FILE_TYPE_PIPE)                      \
+                    {                                                         \
+                      /* h is a pipe or socket.  */                           \
+                      DWORD state;                                            \
+                      if (GetNamedPipeHandleState (h, &state, NULL, NULL,     \
+                                                   NULL, NULL, 0)             \
+                          && (state & PIPE_NOWAIT) != 0)                      \
+                        /* h is a pipe in non-blocking mode.                  \
+                           Change errno from EINVAL to EAGAIN.  */            \
+                        errno = EAGAIN;                                       \
+                    }                                                         \
+                }                                                             \
+            }                                                                 \
+        }                                                                     \
+      return ret;                                                             \
+    }
+
+int
+scanf (const char *format, ...)
+{
+  int retval;
+  va_list args;
+
+  va_start (args, format);
+  retval = vfscanf (stdin, format, args);
+  va_end (args);
+
+  return retval;
+}
+
+int
+fscanf (FILE *stream, const char *format, ...)
+{
+  int retval;
+  va_list args;
+
+  va_start (args, format);
+  retval = vfscanf (stream, format, args);
+  va_end (args);
+
+  return retval;
+}
+
+int
+vscanf (const char *format, va_list args)
+{
+  return vfscanf (stdin, format, args);
+}
+
+int
+vfscanf (FILE *stream, const char *format, va_list args)
+#undef vfscanf
+{
+  CALL_WITH_ERRNO_FIX (int, vfscanf (stream, format, args), ret == EOF)
+}
+
+int
+getchar (void)
+{
+  return fgetc (stdin);
+}
+
+int
+fgetc (FILE *stream)
+#undef fgetc
+{
+  CALL_WITH_ERRNO_FIX (int, fgetc (stream), ret == EOF)
+}
+
+char *
+fgets (char *s, int n, FILE *stream)
+#undef fgets
+{
+  CALL_WITH_ERRNO_FIX (char *, fgets (s, n, stream), ret == NULL)
+}
+
+char *
+gets (char *s)
+#undef gets
+{
+  FILE *stream = stdin;
+  CALL_WITH_ERRNO_FIX (char *, gets (s), ret == NULL)
+}
+
+size_t
+fread (void *ptr, size_t s, size_t n, FILE *stream)
+#undef fread
+{
+  CALL_WITH_ERRNO_FIX (size_t, fread (ptr, s, n, stream), ret < n)
+}
+
+# endif
+#endif
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -87,6 +87,25 @@
 #define _GL_ATTRIBUTE_FORMAT_PRINTF_SYSTEM(formatstring_parameter, first_argument) \
   _GL_ATTRIBUTE_FORMAT ((__printf__, formatstring_parameter, first_argument))
 
+/* _GL_ATTRIBUTE_FORMAT_SCANF
+   indicates to GCC that the function takes a format string and arguments,
+   where the format string directives are the ones standardized by ISO C99
+   and POSIX.  */
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
+# define _GL_ATTRIBUTE_FORMAT_SCANF(formatstring_parameter, first_argument) \
+   _GL_ATTRIBUTE_FORMAT ((__gnu_scanf__, formatstring_parameter, first_argument))
+#else
+# define _GL_ATTRIBUTE_FORMAT_SCANF(formatstring_parameter, first_argument) \
+   _GL_ATTRIBUTE_FORMAT ((__scanf__, formatstring_parameter, first_argument))
+#endif
+
+/* _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM is like _GL_ATTRIBUTE_FORMAT_SCANF,
+   except that it indicates to GCC that the supported format string directives
+   are the ones of the system scanf(), rather than the ones standardized by
+   ISO C99 and POSIX.  */
+#define _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM(formatstring_parameter, first_argument) \
+  _GL_ATTRIBUTE_FORMAT ((__scanf__, formatstring_parameter, first_argument))
+
 /* Solaris 10 declares renameat in <unistd.h>, not in <stdio.h>.  */
 /* But in any case avoid namespace pollution on glibc systems.  */
 #if (@GNULIB_RENAMEAT@ || defined GNULIB_POSIXCHECK) && defined __sun \
@@ -175,11 +194,34 @@
                  "use gnulib module fflush for portable POSIX compliance");
 #endif
 
-/* It is very rare that the developer ever has full control of stdin,
-   so any use of gets warrants an unconditional warning.  Assume it is
-   always declared, since it is required by C89.  */
-#undef gets
-_GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
+#if @GNULIB_FGETC@
+# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef fgetc
+#   define fgetc rpl_fgetc
+#  endif
+_GL_FUNCDECL_RPL (fgetc, int, (FILE *stream) _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (fgetc, int, (FILE *stream));
+# else
+_GL_CXXALIAS_SYS (fgetc, int, (FILE *stream));
+# endif
+_GL_CXXALIASWARN (fgetc);
+#endif
+
+#if @GNULIB_FGETS@
+# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef fgets
+#   define fgets rpl_fgets
+#  endif
+_GL_FUNCDECL_RPL (fgets, char *, (char *s, int n, FILE *stream)
+                                 _GL_ARG_NONNULL ((1, 3)));
+_GL_CXXALIAS_RPL (fgets, char *, (char *s, int n, FILE *stream));
+# else
+_GL_CXXALIAS_SYS (fgets, char *, (char *s, int n, FILE *stream));
+# endif
+_GL_CXXALIASWARN (fgets);
+#endif
 
 #if @GNULIB_FOPEN@
 # if @REPLACE_FOPEN@
@@ -290,6 +332,21 @@
 _GL_CXXALIASWARN (fputs);
 #endif
 
+#if @GNULIB_FREAD@
+# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef fread
+#   define fread rpl_fread
+#  endif
+_GL_FUNCDECL_RPL (fread, size_t, (void *ptr, size_t s, size_t n, FILE *stream)
+                                 _GL_ARG_NONNULL ((4)));
+_GL_CXXALIAS_RPL (fread, size_t, (void *ptr, size_t s, size_t n, FILE *stream));
+# else
+_GL_CXXALIAS_SYS (fread, size_t, (void *ptr, size_t s, size_t n, FILE *stream));
+# endif
+_GL_CXXALIASWARN (fread);
+#endif
+
 #if @GNULIB_FREOPEN@
 # if @REPLACE_FREOPEN@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -314,6 +371,22 @@
                  "use gnulib module freopen for portability");
 #endif
 
+#if @GNULIB_FSCANF@
+# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef fscanf
+#   define fscanf rpl_fscanf
+#  endif
+_GL_FUNCDECL_RPL (fscanf, int, (FILE *stream, const char *format, ...)
+                               _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (2, 3)
+                               _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_RPL (fscanf, int, (FILE *stream, const char *format, ...));
+# else
+_GL_CXXALIAS_SYS (fscanf, int, (FILE *stream, const char *format, ...));
+# endif
+_GL_CXXALIASWARN (fscanf);
+#endif
+
 
 /* Set up the following warnings, based on which modules are in use.
    GNU Coding Standards discourage the use of fseek, since it imposes
@@ -540,6 +613,34 @@
 _GL_CXXALIASWARN (fwrite);
 #endif
 
+#if @GNULIB_GETC@
+# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef getc
+#   define getc rpl_fgetc
+#  endif
+_GL_FUNCDECL_RPL (fgetc, int, (FILE *stream) _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL_1 (getc, rpl_fgetc, int, (FILE *stream));
+# else
+_GL_CXXALIAS_SYS (getc, int, (FILE *stream));
+# endif
+_GL_CXXALIASWARN (getc);
+#endif
+
+#if @GNULIB_GETCHAR@
+# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef getchar
+#   define getchar rpl_getchar
+#  endif
+_GL_FUNCDECL_RPL (getchar, int, (void));
+_GL_CXXALIAS_RPL (getchar, int, (void));
+# else
+_GL_CXXALIAS_SYS (getchar, int, (void));
+# endif
+_GL_CXXALIASWARN (getchar);
+#endif
+
 #if @GNULIB_GETDELIM@
 /* Read input, up to (and including) the next occurrence of DELIMITER, from
    STREAM, store it in *LINEPTR (and NUL-terminate it).
@@ -616,6 +717,26 @@
 # endif
 #endif
 
+#if @GNULIB_GETS@
+# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef gets
+#   define gets rpl_gets
+#  endif
+_GL_FUNCDECL_RPL (gets, char *, (char *s) _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (gets, char *, (char *s));
+# else
+_GL_CXXALIAS_SYS (gets, char *, (char *s));
+#  undef gets
+# endif
+_GL_CXXALIASWARN (gets);
+/* It is very rare that the developer ever has full control of stdin,
+   so any use of gets warrants an unconditional warning.  Assume it is
+   always declared, since it is required by C89.  */
+_GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
+#endif
+
+
 #if @GNULIB_OBSTACK_PRINTF@ || @GNULIB_OBSTACK_PRINTF_POSIX@
 struct obstack;
 /* Grow an obstack with formatted output.  Return the number of
@@ -872,6 +993,37 @@
 # endif
 #endif
 
+#if @GNULIB_SCANF@
+# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@
+#  if defined __GNUC__
+#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#    undef scanf
+/* Don't break __attribute__((format(scanf,M,N))).  */
+#    define scanf __scanf__
+#   endif
+_GL_FUNCDECL_RPL_1 (__scanf__, int,
+                    (const char *format, ...)
+                    __asm__ (@ASM_SYMBOL_PREFIX@
+                             _GL_STDIO_MACROEXPAND_AND_STRINGIZE(rpl_scanf))
+                    _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 2)
+                    _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL_1 (scanf, __scanf__, int, (const char *format, ...));
+#  else
+#   if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#    undef scanf
+#    define scanf rpl_scanf
+#   endif
+_GL_FUNCDECL_RPL (scanf, int, (const char *format, ...)
+                              _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 2)
+                              _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (scanf, int, (const char *format, ...));
+#  endif
+# else
+_GL_CXXALIAS_SYS (scanf, int, (const char *format, ...));
+# endif
+_GL_CXXALIASWARN (scanf);
+#endif
+
 #if @GNULIB_SNPRINTF@
 # if @REPLACE_SNPRINTF@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
@@ -1065,6 +1217,25 @@
                       "POSIX compliance");
 #endif
 
+#if @GNULIB_VFSCANF@
+# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef vfscanf
+#   define vfscanf rpl_vfscanf
+#  endif
+_GL_FUNCDECL_RPL (vfscanf, int,
+                  (FILE *stream, const char *format, va_list args)
+                  _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (2, 0)
+                  _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_RPL (vfscanf, int,
+                  (FILE *stream, const char *format, va_list args));
+# else
+_GL_CXXALIAS_SYS (vfscanf, int,
+                  (FILE *stream, const char *format, va_list args));
+# endif
+_GL_CXXALIASWARN (vfscanf);
+#endif
+
 #if @GNULIB_VPRINTF_POSIX@ || @GNULIB_VPRINTF@
 # if (@GNULIB_VPRINTF_POSIX@ && @REPLACE_VPRINTF@) \
      || (@GNULIB_VPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@))
@@ -1100,6 +1271,22 @@
                  "POSIX compliance");
 #endif
 
+#if @GNULIB_VSCANF@
+# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef vscanf
+#   define vscanf rpl_vscanf
+#  endif
+_GL_FUNCDECL_RPL (vscanf, int, (const char *format, va_list args)
+                               _GL_ATTRIBUTE_FORMAT_SCANF_SYSTEM (1, 0)
+                               _GL_ARG_NONNULL ((1)));
+_GL_CXXALIAS_RPL (vscanf, int, (const char *format, va_list args));
+# else
+_GL_CXXALIAS_SYS (vscanf, int, (const char *format, va_list args));
+# endif
+_GL_CXXALIASWARN (vscanf);
+#endif
+
 #if @GNULIB_VSNPRINTF@
 # if @REPLACE_VSNPRINTF@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
--- a/lib/unistd.in.h
+++ b/lib/unistd.in.h
@@ -97,7 +97,8 @@
 # include <netdb.h>
 #endif
 
-#if (@GNULIB_WRITE@ || @GNULIB_READLINK@ || @GNULIB_READLINKAT@ \
+#if (@GNULIB_READ@ || @GNULIB_WRITE@ \
+     || @GNULIB_READLINK@ || @GNULIB_READLINKAT@ \
      || @GNULIB_PREAD@ || @GNULIB_PWRITE@ || defined GNULIB_POSIXCHECK)
 /* Get ssize_t.  */
 # include <sys/types.h>
@@ -1105,6 +1106,28 @@
 #endif
 
 
+#if @GNULIB_READ@
+/* Read up to COUNT bytes from file descriptor FD into the buffer starting
+   at BUF.  See the POSIX:2001 specification
+   <http://www.opengroup.org/susv3xsh/read.html>.  */
+# if @REPLACE_READ@ && @GNULIB_UNISTD_H_NONBLOCKING@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef read
+#   define read rpl_read
+#  endif
+_GL_FUNCDECL_RPL (read, ssize_t, (int fd, void *buf, size_t count)
+                                 _GL_ARG_NONNULL ((2)));
+_GL_CXXALIAS_RPL (read, ssize_t, (int fd, void *buf, size_t count));
+# else
+/* Need to cast, because on mingw, the third parameter is
+                                                          unsigned int count
+   and the return type is 'int'.  */
+_GL_CXXALIAS_SYS_CAST (read, ssize_t, (int fd, void *buf, size_t count));
+# endif
+_GL_CXXALIASWARN (read);
+#endif
+
+
 #if @GNULIB_READLINK@
 /* Read the contents of the symbolic link FILE and place the first BUFSIZE
    bytes of it into BUF.  Return the number of bytes placed into BUF if
new file mode 100644
--- /dev/null
+++ b/m4/read.m4
@@ -0,0 +1,20 @@
+# read.m4 serial 1
+dnl Copyright (C) 2011 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.
+
+AC_DEFUN([gl_FUNC_READ],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  dnl This ifdef is just an optimization, to avoid performing a configure
+  dnl check whose result is not used. It does not make the test of
+  dnl GNULIB_UNISTD_H_NONBLOCKING or GNULIB_NONBLOCKING redundant.
+  m4_ifdef([gl_NONBLOCKING_IO], [
+    gl_NONBLOCKING_IO
+    if test $gl_cv_have_nonblocking != yes; then
+      REPLACE_READ=1
+      AC_LIBOBJ([read])
+    fi
+  ])
+])
--- a/m4/stdio_h.m4
+++ b/m4/stdio_h.m4
@@ -1,4 +1,4 @@
-# stdio_h.m4 serial 34
+# stdio_h.m4 serial 35
 dnl Copyright (C) 2007-2011 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,6 +9,30 @@
   AC_REQUIRE([gl_STDIO_H_DEFAULTS])
   AC_REQUIRE([AC_C_INLINE])
   gl_NEXT_HEADERS([stdio.h])
+
+  dnl No need to create extra modules for these functions. Everyone who uses
+  dnl <stdio.h> likely needs them.
+  GNULIB_FSCANF=1
+  GNULIB_SCANF=1
+  GNULIB_VFSCANF=1
+  GNULIB_VSCANF=1
+  GNULIB_FGETC=1
+  GNULIB_GETC=1
+  GNULIB_GETCHAR=1
+  GNULIB_FGETS=1
+  GNULIB_GETS=1
+  GNULIB_FREAD=1
+  dnl This ifdef is just an optimization, to avoid performing a configure
+  dnl check whose result is not used. It does not make the test of
+  dnl GNULIB_STDIO_H_NONBLOCKING or GNULIB_NONBLOCKING redundant.
+  m4_ifdef([gl_NONBLOCKING_IO], [
+    gl_NONBLOCKING_IO
+    if test $gl_cv_have_nonblocking != yes; then
+      REPLACE_STDIO_READ_FUNCS=1
+      AC_LIBOBJ([stdio-read])
+    fi
+  ])
+
   dnl No need to create extra modules for these functions. Everyone who uses
   dnl <stdio.h> likely needs them.
   GNULIB_FPRINTF=1
@@ -62,20 +86,27 @@
   GNULIB_DPRINTF=0;              AC_SUBST([GNULIB_DPRINTF])
   GNULIB_FCLOSE=0;               AC_SUBST([GNULIB_FCLOSE])
   GNULIB_FFLUSH=0;               AC_SUBST([GNULIB_FFLUSH])
+  GNULIB_FGETC=0;                AC_SUBST([GNULIB_FGETC])
+  GNULIB_FGETS=0;                AC_SUBST([GNULIB_FGETS])
   GNULIB_FOPEN=0;                AC_SUBST([GNULIB_FOPEN])
   GNULIB_FPRINTF=0;              AC_SUBST([GNULIB_FPRINTF])
   GNULIB_FPRINTF_POSIX=0;        AC_SUBST([GNULIB_FPRINTF_POSIX])
   GNULIB_FPURGE=0;               AC_SUBST([GNULIB_FPURGE])
   GNULIB_FPUTC=0;                AC_SUBST([GNULIB_FPUTC])
   GNULIB_FPUTS=0;                AC_SUBST([GNULIB_FPUTS])
+  GNULIB_FREAD=0;                AC_SUBST([GNULIB_FREAD])
   GNULIB_FREOPEN=0;              AC_SUBST([GNULIB_FREOPEN])
+  GNULIB_FSCANF=0;               AC_SUBST([GNULIB_FSCANF])
   GNULIB_FSEEK=0;                AC_SUBST([GNULIB_FSEEK])
   GNULIB_FSEEKO=0;               AC_SUBST([GNULIB_FSEEKO])
   GNULIB_FTELL=0;                AC_SUBST([GNULIB_FTELL])
   GNULIB_FTELLO=0;               AC_SUBST([GNULIB_FTELLO])
   GNULIB_FWRITE=0;               AC_SUBST([GNULIB_FWRITE])
+  GNULIB_GETC=0;                 AC_SUBST([GNULIB_GETC])
+  GNULIB_GETCHAR=0;              AC_SUBST([GNULIB_GETCHAR])
   GNULIB_GETDELIM=0;             AC_SUBST([GNULIB_GETDELIM])
   GNULIB_GETLINE=0;              AC_SUBST([GNULIB_GETLINE])
+  GNULIB_GETS=0;                 AC_SUBST([GNULIB_GETS])
   GNULIB_OBSTACK_PRINTF=0;       AC_SUBST([GNULIB_OBSTACK_PRINTF])
   GNULIB_OBSTACK_PRINTF_POSIX=0; AC_SUBST([GNULIB_OBSTACK_PRINTF_POSIX])
   GNULIB_PERROR=0;               AC_SUBST([GNULIB_PERROR])
@@ -88,12 +119,15 @@
   GNULIB_REMOVE=0;               AC_SUBST([GNULIB_REMOVE])
   GNULIB_RENAME=0;               AC_SUBST([GNULIB_RENAME])
   GNULIB_RENAMEAT=0;             AC_SUBST([GNULIB_RENAMEAT])
+  GNULIB_SCANF=0;                AC_SUBST([GNULIB_SCANF])
   GNULIB_SNPRINTF=0;             AC_SUBST([GNULIB_SNPRINTF])
   GNULIB_SPRINTF_POSIX=0;        AC_SUBST([GNULIB_SPRINTF_POSIX])
   GNULIB_STDIO_H_NONBLOCKING=0;  AC_SUBST([GNULIB_STDIO_H_NONBLOCKING])
   GNULIB_STDIO_H_SIGPIPE=0;      AC_SUBST([GNULIB_STDIO_H_SIGPIPE])
   GNULIB_TMPFILE=0;              AC_SUBST([GNULIB_TMPFILE])
   GNULIB_VASPRINTF=0;            AC_SUBST([GNULIB_VASPRINTF])
+  GNULIB_VFSCANF=0;              AC_SUBST([GNULIB_VFSCANF])
+  GNULIB_VSCANF=0;               AC_SUBST([GNULIB_VSCANF])
   GNULIB_VDPRINTF=0;             AC_SUBST([GNULIB_VDPRINTF])
   GNULIB_VFPRINTF=0;             AC_SUBST([GNULIB_VFPRINTF])
   GNULIB_VFPRINTF_POSIX=0;       AC_SUBST([GNULIB_VFPRINTF_POSIX])
@@ -138,6 +172,7 @@
   REPLACE_RENAMEAT=0;            AC_SUBST([REPLACE_RENAMEAT])
   REPLACE_SNPRINTF=0;            AC_SUBST([REPLACE_SNPRINTF])
   REPLACE_SPRINTF=0;             AC_SUBST([REPLACE_SPRINTF])
+  REPLACE_STDIO_READ_FUNCS=0;    AC_SUBST([REPLACE_STDIO_READ_FUNCS])
   REPLACE_STDIO_WRITE_FUNCS=0;   AC_SUBST([REPLACE_STDIO_WRITE_FUNCS])
   REPLACE_TMPFILE=0;             AC_SUBST([REPLACE_TMPFILE])
   REPLACE_VASPRINTF=0;           AC_SUBST([REPLACE_VASPRINTF])
--- a/m4/unistd_h.m4
+++ b/m4/unistd_h.m4
@@ -1,4 +1,4 @@
-# unistd_h.m4 serial 54
+# unistd_h.m4 serial 55
 dnl Copyright (C) 2006-2011 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -80,6 +80,7 @@
   GNULIB_PIPE2=0;                AC_SUBST([GNULIB_PIPE2])
   GNULIB_PREAD=0;                AC_SUBST([GNULIB_PREAD])
   GNULIB_PWRITE=0;               AC_SUBST([GNULIB_PWRITE])
+  GNULIB_READ=0;                 AC_SUBST([GNULIB_READ])
   GNULIB_READLINK=0;             AC_SUBST([GNULIB_READLINK])
   GNULIB_READLINKAT=0;           AC_SUBST([GNULIB_READLINKAT])
   GNULIB_RMDIR=0;                AC_SUBST([GNULIB_RMDIR])
@@ -148,6 +149,7 @@
   REPLACE_LSEEK=0;        AC_SUBST([REPLACE_LSEEK])
   REPLACE_PREAD=0;        AC_SUBST([REPLACE_PREAD])
   REPLACE_PWRITE=0;       AC_SUBST([REPLACE_PWRITE])
+  REPLACE_READ=0;         AC_SUBST([REPLACE_READ])
   REPLACE_READLINK=0;     AC_SUBST([REPLACE_READLINK])
   REPLACE_RMDIR=0;        AC_SUBST([REPLACE_RMDIR])
   REPLACE_SLEEP=0;        AC_SUBST([REPLACE_SLEEP])
--- a/modules/nonblocking
+++ b/modules/nonblocking
@@ -5,6 +5,7 @@
 lib/nonblocking.h
 lib/nonblocking.c
 m4/nonblocking.m4
+lib/stdio-read.c
 lib/stdio-write.c
 m4/asm-underscore.m4
 
--- a/modules/pread
+++ b/modules/pread
@@ -8,6 +8,7 @@
 Depends-on:
 extensions
 lseek
+read
 unistd
 
 configure.ac:
new file mode 100644
--- /dev/null
+++ b/modules/read
@@ -0,0 +1,24 @@
+Description:
+POSIX compatible read() function: read data from a file descriptor
+
+Files:
+lib/read.c
+m4/read.m4
+
+Depends-on:
+unistd
+
+configure.ac:
+gl_FUNC_READ
+gl_UNISTD_MODULE_INDICATOR([read])
+
+Makefile.am:
+
+Include:
+<unistd.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+Bruno Haible
--- a/modules/safe-read
+++ b/modules/safe-read
@@ -7,6 +7,7 @@
 m4/safe-read.m4
 
 Depends-on:
+read
 ssize_t
 
 configure.ac:
--- a/modules/stdio
+++ b/modules/stdio
@@ -30,20 +30,27 @@
 	      -e 's|@''GNULIB_DPRINTF''@|$(GNULIB_DPRINTF)|g' \
 	      -e 's|@''GNULIB_FCLOSE''@|$(GNULIB_FCLOSE)|g' \
 	      -e 's|@''GNULIB_FFLUSH''@|$(GNULIB_FFLUSH)|g' \
+	      -e 's|@''GNULIB_FGETC''@|$(GNULIB_FGETC)|g' \
+	      -e 's|@''GNULIB_FGETS''@|$(GNULIB_FGETS)|g' \
 	      -e 's|@''GNULIB_FOPEN''@|$(GNULIB_FOPEN)|g' \
 	      -e 's|@''GNULIB_FPRINTF''@|$(GNULIB_FPRINTF)|g' \
 	      -e 's|@''GNULIB_FPRINTF_POSIX''@|$(GNULIB_FPRINTF_POSIX)|g' \
 	      -e 's|@''GNULIB_FPURGE''@|$(GNULIB_FPURGE)|g' \
 	      -e 's|@''GNULIB_FPUTC''@|$(GNULIB_FPUTC)|g' \
 	      -e 's|@''GNULIB_FPUTS''@|$(GNULIB_FPUTS)|g' \
+	      -e 's|@''GNULIB_FREAD''@|$(GNULIB_FREAD)|g' \
 	      -e 's|@''GNULIB_FREOPEN''@|$(GNULIB_FREOPEN)|g' \
+	      -e 's|@''GNULIB_FSCANF''@|$(GNULIB_FSCANF)|g' \
 	      -e 's|@''GNULIB_FSEEK''@|$(GNULIB_FSEEK)|g' \
 	      -e 's|@''GNULIB_FSEEKO''@|$(GNULIB_FSEEKO)|g' \
 	      -e 's|@''GNULIB_FTELL''@|$(GNULIB_FTELL)|g' \
 	      -e 's|@''GNULIB_FTELLO''@|$(GNULIB_FTELLO)|g' \
 	      -e 's|@''GNULIB_FWRITE''@|$(GNULIB_FWRITE)|g' \
+	      -e 's|@''GNULIB_GETC''@|$(GNULIB_GETC)|g' \
+	      -e 's|@''GNULIB_GETCHAR''@|$(GNULIB_GETCHAR)|g' \
 	      -e 's|@''GNULIB_GETDELIM''@|$(GNULIB_GETDELIM)|g' \
 	      -e 's|@''GNULIB_GETLINE''@|$(GNULIB_GETLINE)|g' \
+	      -e 's|@''GNULIB_GETS''@|$(GNULIB_GETS)|g' \
 	      -e 's|@''GNULIB_OBSTACK_PRINTF''@|$(GNULIB_OBSTACK_PRINTF)|g' \
 	      -e 's|@''GNULIB_OBSTACK_PRINTF_POSIX''@|$(GNULIB_OBSTACK_PRINTF_POSIX)|g' \
 	      -e 's|@''GNULIB_PERROR''@|$(GNULIB_PERROR)|g' \
@@ -56,6 +63,7 @@
 	      -e 's|@''GNULIB_REMOVE''@|$(GNULIB_REMOVE)|g' \
 	      -e 's|@''GNULIB_RENAME''@|$(GNULIB_RENAME)|g' \
 	      -e 's|@''GNULIB_RENAMEAT''@|$(GNULIB_RENAMEAT)|g' \
+	      -e 's|@''GNULIB_SCANF''@|$(GNULIB_SCANF)|g' \
 	      -e 's|@''GNULIB_SNPRINTF''@|$(GNULIB_SNPRINTF)|g' \
 	      -e 's|@''GNULIB_SPRINTF_POSIX''@|$(GNULIB_SPRINTF_POSIX)|g' \
 	      -e 's|@''GNULIB_STDIO_H_NONBLOCKING''@|$(GNULIB_STDIO_H_NONBLOCKING)|g' \
@@ -65,6 +73,8 @@
 	      -e 's|@''GNULIB_VDPRINTF''@|$(GNULIB_VDPRINTF)|g' \
 	      -e 's|@''GNULIB_VFPRINTF''@|$(GNULIB_VFPRINTF)|g' \
 	      -e 's|@''GNULIB_VFPRINTF_POSIX''@|$(GNULIB_VFPRINTF_POSIX)|g' \
+	      -e 's|@''GNULIB_VFSCANF''@|$(GNULIB_VFSCANF)|g' \
+	      -e 's|@''GNULIB_VSCANF''@|$(GNULIB_VSCANF)|g' \
 	      -e 's|@''GNULIB_VPRINTF''@|$(GNULIB_VPRINTF)|g' \
 	      -e 's|@''GNULIB_VPRINTF_POSIX''@|$(GNULIB_VPRINTF_POSIX)|g' \
 	      -e 's|@''GNULIB_VSNPRINTF''@|$(GNULIB_VSNPRINTF)|g' \
@@ -106,6 +116,7 @@
 	      -e 's|@''REPLACE_RENAMEAT''@|$(REPLACE_RENAMEAT)|g' \
 	      -e 's|@''REPLACE_SNPRINTF''@|$(REPLACE_SNPRINTF)|g' \
 	      -e 's|@''REPLACE_SPRINTF''@|$(REPLACE_SPRINTF)|g' \
+	      -e 's|@''REPLACE_STDIO_READ_FUNCS''@|$(REPLACE_STDIO_READ_FUNCS)|g' \
 	      -e 's|@''REPLACE_STDIO_WRITE_FUNCS''@|$(REPLACE_STDIO_WRITE_FUNCS)|g' \
 	      -e 's|@''REPLACE_TMPFILE''@|$(REPLACE_TMPFILE)|g' \
 	      -e 's|@''REPLACE_VASPRINTF''@|$(REPLACE_VASPRINTF)|g' \
--- a/modules/unistd
+++ b/modules/unistd
@@ -56,6 +56,7 @@
 	      -e 's|@''GNULIB_PIPE2''@|$(GNULIB_PIPE2)|g' \
 	      -e 's|@''GNULIB_PREAD''@|$(GNULIB_PREAD)|g' \
 	      -e 's|@''GNULIB_PWRITE''@|$(GNULIB_PWRITE)|g' \
+	      -e 's|@''GNULIB_READ''@|$(GNULIB_READ)|g' \
 	      -e 's|@''GNULIB_READLINK''@|$(GNULIB_READLINK)|g' \
 	      -e 's|@''GNULIB_READLINKAT''@|$(GNULIB_READLINKAT)|g' \
 	      -e 's|@''GNULIB_RMDIR''@|$(GNULIB_RMDIR)|g' \
@@ -125,6 +126,7 @@
 	      -e 's|@''REPLACE_LSEEK''@|$(REPLACE_LSEEK)|g' \
 	      -e 's|@''REPLACE_PREAD''@|$(REPLACE_PREAD)|g' \
 	      -e 's|@''REPLACE_PWRITE''@|$(REPLACE_PWRITE)|g' \
+	      -e 's|@''REPLACE_READ''@|$(REPLACE_READ)|g' \
 	      -e 's|@''REPLACE_READLINK''@|$(REPLACE_READLINK)|g' \
 	      -e 's|@''REPLACE_RMDIR''@|$(REPLACE_RMDIR)|g' \
 	      -e 's|@''REPLACE_SLEEP''@|$(REPLACE_SLEEP)|g' \
--- a/tests/test-stdio-c++.cc
+++ b/tests/test-stdio-c++.cc
@@ -36,6 +36,14 @@
 SIGNATURE_CHECK (GNULIB_NAMESPACE::fflush, int, (FILE *));
 #endif
 
+#if GNULIB_TEST_FGETC
+SIGNATURE_CHECK (GNULIB_NAMESPACE::fgetc, int, (FILE *));
+#endif
+
+#if GNULIB_TEST_FGETS
+SIGNATURE_CHECK (GNULIB_NAMESPACE::fgets, char *, (char *, int, FILE *));
+#endif
+
 #if GNULIB_TEST_FOPEN
 SIGNATURE_CHECK (GNULIB_NAMESPACE::fopen, FILE *,
                  (const char *, const char *));
@@ -57,11 +65,20 @@
 SIGNATURE_CHECK (GNULIB_NAMESPACE::fputs, int, (const char *, FILE *));
 #endif
 
+#if GNULIB_TEST_FREAD
+SIGNATURE_CHECK (GNULIB_NAMESPACE::fread, size_t,
+                 (void *, size_t, size_t, FILE *));
+#endif
+
 #if GNULIB_TEST_FREOPEN
 SIGNATURE_CHECK (GNULIB_NAMESPACE::freopen, FILE *,
                  (const char *, const char *, FILE *));
 #endif
 
+#if GNULIB_TEST_FSCANF
+SIGNATURE_CHECK (GNULIB_NAMESPACE::fscanf, int, (FILE *, const char *, ...));
+#endif
+
 #if GNULIB_TEST_FSEEK
 SIGNATURE_CHECK (GNULIB_NAMESPACE::fseek, int, (FILE *, long, int));
 #endif
@@ -83,6 +100,14 @@
                  (const void *, size_t, size_t, FILE *));
 #endif
 
+#if GNULIB_TEST_GETC
+SIGNATURE_CHECK (GNULIB_NAMESPACE::getc, int, (FILE *));
+#endif
+
+#if GNULIB_TEST_GETCHAR
+SIGNATURE_CHECK (GNULIB_NAMESPACE::getchar, int, (void));
+#endif
+
 #if GNULIB_TEST_GETDELIM
 SIGNATURE_CHECK (GNULIB_NAMESPACE::getdelim, ssize_t,
                  (char **, size_t *, int, FILE *));
@@ -93,6 +118,10 @@
                  (char **, size_t *, FILE *));
 #endif
 
+#if GNULIB_TEST_GETS
+SIGNATURE_CHECK (GNULIB_NAMESPACE::gets, char *, (char *));
+#endif
+
 #if GNULIB_TEST_OBSTACK_PRINTF || GNULIB_TEST_OBSTACK_PRINTF_POSIX
 SIGNATURE_CHECK (GNULIB_NAMESPACE::obstack_printf, int,
                  (struct obstack *, const char *, ...));
@@ -140,6 +169,10 @@
                  (int, char const *, int, char const *));
 #endif
 
+#if GNULIB_TEST_SCANF
+SIGNATURE_CHECK (GNULIB_NAMESPACE::scanf, int, (const char *, ...));
+#endif
+
 #if GNULIB_TEST_SNPRINTF
 SIGNATURE_CHECK (GNULIB_NAMESPACE::snprintf, int,
                  (char *, size_t, const char *, ...));
@@ -170,10 +203,19 @@
                  (FILE *, const char *, va_list));
 #endif
 
+#if GNULIB_TEST_VFSCANF
+SIGNATURE_CHECK (GNULIB_NAMESPACE::vfscanf, int,
+                 (FILE *, const char *, va_list));
+#endif
+
 #if GNULIB_TEST_VPRINTF_POSIX || GNULIB_TEST_VPRINTF
 SIGNATURE_CHECK (GNULIB_NAMESPACE::vprintf, int, (const char *, va_list));
 #endif
 
+#if GNULIB_TEST_VSCANF
+SIGNATURE_CHECK (GNULIB_NAMESPACE::vscanf, int, (const char *, va_list));
+#endif
+
 #if GNULIB_TEST_VSNPRINTF
 SIGNATURE_CHECK (GNULIB_NAMESPACE::vsnprintf, int,
                  (char *, size_t, const char *, va_list));