New module 'fwriteerror'.
authorBruno Haible <bruno@clisp.org>
Mon, 15 Sep 2003 19:15:22 +0000 (19:15 +0000)
committerBruno Haible <bruno@clisp.org>
Mon, 15 Sep 2003 19:15:22 +0000 (19:15 +0000)
ChangeLog
lib/ChangeLog
lib/fwriteerror.c [new file with mode: 0644]
lib/fwriteerror.h [new file with mode: 0644]
modules/fwriteerror [new file with mode: 0644]

index db1fdeb..3b5350c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2003-09-14  Bruno Haible  <bruno@clisp.org>
+
+       * modules/fwriteerror: New file.
+       * MODULES.html.sh (func_all_modules): Add fwriteerror.
+
 2003-09-12  Paul Eggert  <eggert@twinsun.com>
 
        * modules/argmatch, modules/exitfail, modules/fatal, modules/obstack,
index 31d07b6..904cc9c 100644 (file)
@@ -1,3 +1,8 @@
+2003-09-14  Bruno Haible  <bruno@clisp.org>
+
+       * fwriteerror.h: New file.
+       * fwriteerror.c: New file.
+
 2003-09-14  Jim Meyering  <jim@meyering.net>
 
        * getloadavg.c: Correct cpp indentation.
diff --git a/lib/fwriteerror.c b/lib/fwriteerror.c
new file mode 100644 (file)
index 0000000..364db86
--- /dev/null
@@ -0,0 +1,122 @@
+/* Detect write error on a stream.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification.  */
+#include "fwriteerror.h"
+
+#include <errno.h>
+
+int
+fwriteerror (FILE *fp)
+{
+  /* Need to
+     1. test the error indicator of the stream,
+     2. flush the buffers (what fclose() would do), testing for error again.
+     We can equally well swap these steps; this leads to smaller code.  */
+
+  /* Clear errno, so that on non-POSIX systems the caller doesn't see a
+     wrong value of errno when we return -1.  */
+  errno = 0;
+
+  if (fflush (fp))
+    return -1; /* errno is set here */
+
+  if (ferror (fp))
+    {
+      /* The stream had an error earlier, but its errno was lost.  If the
+        error was not temporary, we can get the same errno by writing and
+        flushing one more byte.  We can do so because at this point the
+        stream's contents is garbage anyway.  */
+      if (fputc ('\0', fp) == EOF)
+       return -1; /* errno is set here */
+      if (fflush (fp))
+       return -1; /* errno is set here */
+      /* Give up on errno.  */
+      errno = 0;
+      return -1;
+    }
+
+  return 0;
+}
+
+
+#if TEST
+
+/* Name of a file on which writing fails.  On systems without /dev/full,
+   you can choose a filename on a full filesystem.  */
+#define UNWRITABLE_FILE "/dev/full"
+
+int
+main ()
+{
+  static int sizes[] =
+    {
+       511,  512,  513,
+      1023, 1024, 1025,
+      2047, 2048, 2049,
+      4095, 4096, 4097,
+      8191, 8192, 8193
+    };
+  static char dummy[8193];
+  unsigned int i, j;
+
+  for (i = 0; i < sizeof (sizes) / sizeof (sizes[0]); i++)
+    {
+      size_t size = sizes[i];
+
+      for (j = 0; j < 2; j++)
+       {
+         /* Run a test depending on i and j:
+            Write size bytes and then calls fflush if j==1.  */
+         FILE *stream = fopen (UNWRITABLE_FILE, "w");
+
+         if (stream == NULL)
+           {
+             fprintf (stderr, "Test %u:%u: could not open file\n", i, j);
+             continue;
+           }
+
+         fwrite (dummy, 347, 1, stream);
+         fwrite (dummy, size - 347, 1, stream);
+         if (j)
+           fflush (stream);
+
+         if (fwriteerror (stream) == -1)
+           {
+             if (errno != ENOSPC)
+               fprintf (stderr, "Test %u:%u: fwriteerror ok, errno = %d\n",
+                        i, j, errno);
+           }
+         else
+           fprintf (stderr, "Test %u:%u: fwriteerror found no error!\n",
+                    i, j);
+
+         if (fclose (stream))
+           fprintf (stderr, "Test %u:%u: fclose failed, errno = %d\n",
+                    i, j, errno);
+       }
+    }
+
+  return 0;
+}
+
+#endif
diff --git a/lib/fwriteerror.h b/lib/fwriteerror.h
new file mode 100644 (file)
index 0000000..82cf5f1
--- /dev/null
@@ -0,0 +1,51 @@
+/* Detect write error on a stream.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 2003.
+
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* There are two approaches for detecting a write error on a stream opened
+   for writing:
+
+     (a) Test the return value of every fwrite() or fprintf() call, and react
+         immediately.
+     (b) Just before fclose(), test the error indicator in the stream and
+         the return value of the final fflush() or fclose() call.
+
+   The benefit of (a) is that non file related errors (such that ENOMEM during
+   fprintf) and temporary error conditions can be diagnosed accurately.
+
+   A theoretical benefit of (a) is also that, on POSIX systems, in the case of
+   an ENOSPC error, errno is set and can be used by error() to provide a more
+   accurate error message. But in practice, this benefit is not big because
+   users can easily figure out by themselves why a file cannot be written to,
+   and furthermore the function fwriteerror() can provide errno as well.
+
+   The big drawback of (a) is extensive error checking code: Every function
+   which does stream output must return an error indicator.
+
+   This file provides support for (b).  */
+
+#include <stdio.h>
+
+/* Write out the not yet written buffered contents of the stream FP, and then
+   test whether some error occurred on the stream FP.  FP must be a stream
+   opened for writing.
+   Return 0 if no error occurred.  In this case it can be assumed that
+   fclose (fp) will succeed.
+   Return -1 and set errno if there was an error.  The errno value will be 0
+   if the cause of the error cannot be determined.
+ */
+extern int fwriteerror (FILE *fp);
diff --git a/modules/fwriteerror b/modules/fwriteerror
new file mode 100644 (file)
index 0000000..b360b91
--- /dev/null
@@ -0,0 +1,19 @@
+Description:
+Detect write error on a stream.
+
+Files:
+lib/fwriteerror.h
+lib/fwriteerror.c
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += fwriteerror.h fwriteerror.c
+
+Include:
+"fwriteerror.h"
+
+Maintainer:
+Bruno Haible