changeset 8720:367787d55c9c

Implement freading and fwriting. * lib/freading.c: New file. * lib/freading.h: Likewise. * m4/freading.m4: Likewise. * modules/freading: Likewise. * modules/freading-tests: Likewise. * tests/test-freading.c: Likewise. * lib/fwriting.c: New file. * lib/fwriting.h: Likewise. * m4/fwriting.m4: Likewise. * modules/fwriting: Likewise. * modules/fwriting-tests: Likewise. * tests/test-fwriting.c: Likewise. * MODULES.html.sh (File stream based Input/Output): Mention them.
author Eric Blake <ebb9@byu.net>
date Thu, 26 Apr 2007 13:16:50 +0000
parents 0d671904d407
children 5122cdde0f7b
files ChangeLog MODULES.html.sh lib/freading.c lib/freading.h lib/fwriting.c lib/fwriting.h m4/freading.m4 m4/fwriting.m4 modules/freading modules/freading-tests modules/fwriting modules/fwriting-tests tests/test-freading.c tests/test-fwriting.c
diffstat 14 files changed, 511 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2007-04-26  Eric Blake  <ebb9@byu.net>
+	and Bruno Haible  <bruno@clisp.org>
+
+	Implement freading and fwriting.
+	* lib/freading.c: New file.
+	* lib/freading.h: Likewise.
+	* m4/freading.m4: Likewise.
+	* modules/freading: Likewise.
+	* modules/freading-tests: Likewise.
+	* tests/test-freading.c: Likewise.
+	* lib/fwriting.c: New file.
+	* lib/fwriting.h: Likewise.
+	* m4/fwriting.m4: Likewise.
+	* modules/fwriting: Likewise.
+	* modules/fwriting-tests: Likewise.
+	* tests/test-fwriting.c: Likewise.
+	* MODULES.html.sh (File stream based Input/Output): Mention them.
+
 2007-04-26  Bruno Haible  <bruno@clisp.org>
 
 	* lib/stdio_.h (fseeko, ftello): Check that off_t has the same size as
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -2196,6 +2196,8 @@
   func_module closeout
   func_module fopen-safer
   func_module fpending
+  func_module freading
+  func_module fwriting
   func_module getpass
   func_module getpass-gnu
   func_module stdlib-safer
new file mode 100644
--- /dev/null
+++ b/lib/freading.c
@@ -0,0 +1,47 @@
+/* Retrieve information about a FILE stream.
+   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 "freading.h"
+
+/* Don't use glibc's __freading function, see
+   <http://sourceware.org/bugzilla/show_bug.cgi?id=4359>  */
+#if !(HAVE___FREADING && !defined __GLIBC__)
+
+bool
+freading (FILE *fp)
+{
+  /* Most systems provide FILE as a struct and the necessary bitmask in
+     <stdio.h>, because they need it for implementing getc() and putc() as
+     fast macros.  */
+#if defined _IO_ferror_unlocked     /* GNU libc, BeOS */
+  return ((fp->_flags & _IO_NO_WRITES) != 0
+	  || ((fp->_flags & _IO_NO_READS) == 0
+	      && (fp->_flags & _IO_CURRENTLY_PUTTING) == 0
+	      && fp->_IO_read_base != NULL));
+#elif defined __sferror             /* FreeBSD, NetBSD, OpenBSD, MacOS X, Cygwin */
+  return (fp->_flags & __SRD) != 0;
+#elif defined _IOERR                /* AIX, HP-UX, IRIX, OSF/1, Solaris, mingw */
+  return (fp->_flag & _IOREAD) != 0;
+#else
+ #error "Please port gnulib freading.c to your platform!"
+#endif
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/lib/freading.h
@@ -0,0 +1,44 @@
+/* Retrieve information about a FILE stream.
+   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 <stdbool.h>
+#include <stdio.h>
+
+/* Return true if the stream STREAM is opened read-only, or if the last
+   operation on the stream was a read operation.  Return false if the stream
+   supports writing and the last operation on it was a write operation or
+   there was no such operation.
+   STREAM must not be wide-character oriented.  */
+
+#if HAVE___FREADING && !defined __GLIBC__ /* Solaris >= 7, not glibc >= 2.2  */
+
+# include <stdio_ext.h>
+# define freading(stream) (__freading (stream) != 0)
+
+#else
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+extern bool freading (FILE *stream);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
new file mode 100644
--- /dev/null
+++ b/lib/fwriting.c
@@ -0,0 +1,38 @@
+/* Retrieve information about a FILE stream.
+   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 "fwriting.h"
+
+bool
+fwriting (FILE *fp)
+{
+  /* Most systems provide FILE as a struct and the necessary bitmask in
+     <stdio.h>, because they need it for implementing getc() and putc() as
+     fast macros.  */
+#if defined _IO_ferror_unlocked     /* GNU libc, BeOS */
+  return (fp->_flags & (_IO_NO_READS | _IO_CURRENTLY_PUTTING)) != 0;
+#elif defined __sferror             /* FreeBSD, NetBSD, OpenBSD, MacOS X, Cygwin */
+  return (fp->_flags & __SWR) != 0;
+#elif defined _IOERR                /* AIX, HP-UX, IRIX, OSF/1, Solaris, mingw */
+  return (fp->_flag & _IOWRT) != 0;
+#else
+ #error "Please port gnulib fwriting.c to your platform!"
+#endif
+}
new file mode 100644
--- /dev/null
+++ b/lib/fwriting.h
@@ -0,0 +1,44 @@
+/* Retrieve information about a FILE stream.
+   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 <stdbool.h>
+#include <stdio.h>
+
+/* Return true if the stream STREAM is opened write-only or append-only, or
+   if the last operation on the stream was a write operation.  Return false
+   if the stream supports reading and the last operation on it was a read
+   operation or there was no such operation.
+   STREAM must not be wide-character oriented.  */
+
+#if HAVE___FWRITING /* glibc >= 2.2, Solaris >= 7 */
+
+# include <stdio_ext.h>
+# define fwriting(stream) (__fwriting (stream) != 0)
+
+#else
+
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+extern bool fwriting (FILE *stream);
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif
new file mode 100644
--- /dev/null
+++ b/m4/freading.m4
@@ -0,0 +1,10 @@
+# freading.m4 serial 1
+dnl Copyright (C) 2007 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_FREADING],
+[
+  AC_CHECK_FUNCS_ONCE([__freading])
+])
new file mode 100644
--- /dev/null
+++ b/m4/fwriting.m4
@@ -0,0 +1,13 @@
+# fwriting.m4 serial 1
+dnl Copyright (C) 2007 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_FWRITING],
+[
+  AC_CHECK_FUNCS_ONCE([__fwriting])
+  if test $ac_cv_func___fwriting = no; then
+    AC_LIBOBJ([fwriting])
+  fi
+])
new file mode 100644
--- /dev/null
+++ b/modules/freading
@@ -0,0 +1,26 @@
+Description:
+freading() function: Determine whether a FILE stream is currently doing reading.
+
+Files:
+lib/freading.h
+lib/freading.c
+m4/freading.m4
+
+Depends-on:
+stdbool
+
+configure.ac:
+gl_FUNC_FREADING
+
+Makefile.am:
+lib_SOURCES += freading.c
+
+Include:
+"freading.h"
+
+License:
+LGPL
+
+Maintainer:
+Bruno Haible, Eric Blake
+
new file mode 100644
--- /dev/null
+++ b/modules/freading-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-freading.c
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-freading
+check_PROGRAMS += test-freading
+MOSTLYCLEANFILES += t-freading.tmp
new file mode 100644
--- /dev/null
+++ b/modules/fwriting
@@ -0,0 +1,25 @@
+Description:
+fwriting() function: Determine whether a FILE stream is currently doing writing.
+
+Files:
+lib/fwriting.h
+lib/fwriting.c
+m4/fwriting.m4
+
+Depends-on:
+stdbool
+
+configure.ac:
+gl_FUNC_FWRITING
+
+Makefile.am:
+
+Include:
+"fwriting.h"
+
+License:
+LGPL
+
+Maintainer:
+Bruno Haible, Eric Blake
+
new file mode 100644
--- /dev/null
+++ b/modules/fwriting-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-fwriting.c
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-fwriting
+check_PROGRAMS += test-fwriting
+MOSTLYCLEANFILES += t-fwriting.tmp
new file mode 100644
--- /dev/null
+++ b/tests/test-freading.c
@@ -0,0 +1,111 @@
+/* Test of freading() function.
+   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.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
+
+#include <config.h>
+
+#include "freading.h"
+
+#include <stdlib.h>
+
+#define ASSERT(expr) if (!(expr)) abort ();
+
+#define TESTFILE "t-freading.tmp"
+
+int
+main ()
+{
+  FILE *fp;
+
+  /* Create a file with some contents.  Write-only file is never reading.  */
+  fp = fopen (TESTFILE, "w");
+  if (fp == NULL)
+    goto skip;
+  ASSERT (!freading (fp));
+  if (fwrite ("foobarsh", 1, 8, fp) < 8)
+    goto skip;
+  ASSERT (!freading (fp));
+  if (fclose (fp))
+    goto skip;
+
+  /* Open it in read-only mode.  Read-only file is always reading.  */
+  fp = fopen (TESTFILE, "r");
+  if (fp == NULL)
+    goto skip;
+  ASSERT (freading (fp));
+  if (fgetc (fp) != 'f')
+    goto skip;
+  ASSERT (freading (fp));
+  if (fseek (fp, 2, SEEK_CUR))
+    goto skip;
+  ASSERT (freading (fp));
+  if (fgetc (fp) != 'b')
+    goto skip;
+  ASSERT (freading (fp));
+  if (fseek (fp, 0, SEEK_END))
+    goto skip;
+  ASSERT (freading (fp));
+  if (fclose (fp))
+    goto skip;
+
+  /* Open it in read-write mode.  POSIX requires a reposition (fseek,
+     fsetpos, rewind) or EOF when transitioning from read to write;
+     freading is only deterministic after input or output, but this
+     test case should be portable even on open, after reposition, and
+     at EOF.  */
+  fp = fopen (TESTFILE, "r+");
+  if (fp == NULL)
+    goto skip;
+  ASSERT (!freading (fp));
+  if (fgetc (fp) != 'f')
+    goto skip;
+  ASSERT (freading (fp));
+  if (fseek (fp, 2, SEEK_CUR))
+    goto skip;
+  /* freading (fp)) is undefined here, but fwriting is false.  */
+  if (fgetc (fp) != 'b')
+    goto skip;
+  ASSERT (freading (fp));
+  if (fseek (fp, 0, SEEK_CUR) != 0)
+    goto skip;
+  if (fputc ('z', fp) != 'z')
+    goto skip;
+  ASSERT (!freading (fp));
+  if (fseek (fp, 0, SEEK_END))
+    goto skip;
+  ASSERT (!freading (fp));
+  if (fclose (fp))
+    goto skip;
+
+  /* Open it in append mode.  Write-only file is never reading.  */
+  fp = fopen (TESTFILE, "a");
+  if (fp == NULL)
+    goto skip;
+  ASSERT (!freading (fp));
+  if (fwrite ("bla", 1, 3, fp) < 3)
+    goto skip;
+  ASSERT (!freading (fp));
+  if (fclose (fp))
+    goto skip;
+
+  return 0;
+
+ skip:
+  fprintf (stderr, "Skipping test: file operations failed.\n");
+  return 77;
+}
new file mode 100644
--- /dev/null
+++ b/tests/test-fwriting.c
@@ -0,0 +1,111 @@
+/* Test of fwriting() function.
+   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.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
+
+#include <config.h>
+
+#include "fwriting.h"
+
+#include <stdlib.h>
+
+#define ASSERT(expr) if (!(expr)) abort ();
+
+#define TESTFILE "t-fwriting.tmp"
+
+int
+main ()
+{
+  FILE *fp;
+
+  /* Create a file with some contents.  Write-only file is always writing.  */
+  fp = fopen (TESTFILE, "w");
+  if (fp == NULL)
+    goto skip;
+  ASSERT (fwriting (fp));
+  if (fwrite ("foobarsh", 1, 8, fp) < 8)
+    goto skip;
+  ASSERT (fwriting (fp));
+  if (fclose (fp))
+    goto skip;
+
+  /* Open it in read-only mode.  Read-only file is never writing.  */
+  fp = fopen (TESTFILE, "r");
+  if (fp == NULL)
+    goto skip;
+  ASSERT (!fwriting (fp));
+  if (fgetc (fp) != 'f')
+    goto skip;
+  ASSERT (!fwriting (fp));
+  if (fseek (fp, 2, SEEK_CUR))
+    goto skip;
+  ASSERT (!fwriting (fp));
+  if (fgetc (fp) != 'b')
+    goto skip;
+  ASSERT (!fwriting (fp));
+  if (fseek (fp, 0, SEEK_END))
+    goto skip;
+  ASSERT (!fwriting (fp));
+  if (fclose (fp))
+    goto skip;
+
+  /* Open it in read-write mode.  POSIX requires a reposition (fseek,
+     fsetpos, rewind) or fflush when transitioning from write to read,
+     fwriting is only deterministic after input or output, but this
+     test case should be portable even on open, after reposition, and
+     after fflush.  */
+  fp = fopen (TESTFILE, "r+");
+  if (fp == NULL)
+    goto skip;
+  ASSERT (!fwriting (fp));
+  if (fgetc (fp) != 'f')
+    goto skip;
+  ASSERT (!fwriting (fp));
+  if (fseek (fp, 2, SEEK_CUR))
+    goto skip;
+  ASSERT (!fwriting (fp));
+  if (fgetc (fp) != 'b')
+    goto skip;
+  ASSERT (!fwriting (fp));
+  if (fseek (fp, 0, SEEK_CUR) != 0)
+    goto skip;
+  if (fputc ('z', fp) != 'z')
+    goto skip;
+  ASSERT (fwriting (fp));
+  if (fseek (fp, 0, SEEK_END))
+    goto skip;
+  /* fwriting (fp) is undefined here, but freading is false.  */
+  if (fclose (fp))
+    goto skip;
+
+  /* Open it in append mode.  */
+  fp = fopen (TESTFILE, "a");
+  if (fp == NULL)
+    goto skip;
+  ASSERT (fwriting (fp));
+  if (fwrite ("bla", 1, 3, fp) < 3)
+    goto skip;
+  ASSERT (fwriting (fp));
+  if (fclose (fp))
+    goto skip;
+
+  return 0;
+
+ skip:
+  fprintf (stderr, "Skipping test: file operations failed.\n");
+  return 77;
+}