summaryrefslogtreecommitdiffstats
path: root/gettext-tools
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2003-09-18 15:57:53 +0000
committerBruno Haible <bruno@clisp.org>2009-06-23 12:11:00 +0200
commit3ac79c15c81d28d9090618a64ccb5308ed8e0eb7 (patch)
tree2463d6c3aea859cdde3b9606912e58a22efbf487 /gettext-tools
parentbf4d1fb1029711bebd86141ff4f6955af992ed5a (diff)
downloadexternal_gettext-3ac79c15c81d28d9090618a64ccb5308ed8e0eb7.zip
external_gettext-3ac79c15c81d28d9090618a64ccb5308ed8e0eb7.tar.gz
external_gettext-3ac79c15c81d28d9090618a64ccb5308ed8e0eb7.tar.bz2
Use fwriteerror() for reliable signalling of write error during stream output.
Diffstat (limited to 'gettext-tools')
-rw-r--r--gettext-tools/ChangeLog4
-rw-r--r--gettext-tools/lib/ChangeLog11
-rw-r--r--gettext-tools/lib/Makefile.am1
-rw-r--r--gettext-tools/lib/Makefile.msvc4
-rw-r--r--gettext-tools/lib/Makefile.vms4
-rw-r--r--gettext-tools/lib/fwriteerror.c122
-rw-r--r--gettext-tools/lib/fwriteerror.h51
-rw-r--r--gettext-tools/src/ChangeLog15
-rw-r--r--gettext-tools/src/write-java.c3
-rw-r--r--gettext-tools/src/write-mo.c3
-rw-r--r--gettext-tools/src/write-po.c3
-rw-r--r--gettext-tools/src/write-tcl.c3
-rw-r--r--gettext-tools/windows/gettextlib.def1
13 files changed, 221 insertions, 4 deletions
diff --git a/gettext-tools/ChangeLog b/gettext-tools/ChangeLog
index c1aac57..9ed08e3 100644
--- a/gettext-tools/ChangeLog
+++ b/gettext-tools/ChangeLog
@@ -1,3 +1,7 @@
+2003-09-14 Bruno Haible <bruno@clisp.org>
+
+ * windows/gettextlib.def: Export fwriteerror.
+
2003-09-13 Bruno Haible <bruno@clisp.org>
* windows/gettextlib.def: Export close_stdout.
diff --git a/gettext-tools/lib/ChangeLog b/gettext-tools/lib/ChangeLog
index 5948692..3a70d78 100644
--- a/gettext-tools/lib/ChangeLog
+++ b/gettext-tools/lib/ChangeLog
@@ -1,3 +1,14 @@
+2003-09-14 Bruno Haible <bruno@clisp.org>
+
+ * fwriteerror.h: New file.
+ * fwriteerror.c: New file.
+ * Makefile.am (libgettextlib_la_SOURCES): Add fwriteerror.h,
+ fwriteerror.c.
+ * Makefile.msvc (OBJECTS): Add fwriteerror.obj.
+ (fwriteerror.obj): New rule.
+ * Makefile.vms (OBJECTS): Add fwriteerror.obj.
+ (fwriteerror.obj): New rule.
+
2003-09-13 Bruno Haible <bruno@clisp.org>
* closeout.h: New file, from gnulib with modifications.
diff --git a/gettext-tools/lib/Makefile.am b/gettext-tools/lib/Makefile.am
index 3e437bb..b6addbb 100644
--- a/gettext-tools/lib/Makefile.am
+++ b/gettext-tools/lib/Makefile.am
@@ -46,6 +46,7 @@ libgettextlib_la_SOURCES = \
findprog.h findprog.c \
fstrcmp.h fstrcmp.c \
full-write.h full-write.c \
+ fwriteerror.h fwriteerror.c \
gcd.h gcd.c \
getopt.h getopt.c getopt1.c \
hash.h hash.c \
diff --git a/gettext-tools/lib/Makefile.msvc b/gettext-tools/lib/Makefile.msvc
index f90705c..b099e97 100644
--- a/gettext-tools/lib/Makefile.msvc
+++ b/gettext-tools/lib/Makefile.msvc
@@ -93,6 +93,7 @@ OBJECTS = \
findprog.obj \
fstrcmp.obj \
full-write.obj \
+ fwriteerror.obj \
gcd.obj \
getopt.obj getopt1.obj \
hash.obj \
@@ -171,6 +172,9 @@ fstrcmp.obj : fstrcmp.c
full-write.obj : full-write.c
$(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c full-write.c
+fwriteerror.obj : fwriteerror.c
+ $(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c fwriteerror.c
+
gcd.obj : gcd.c
$(CC) $(INCLUDES) $(CFLAGS) $(PICFLAGS) -c gcd.c
diff --git a/gettext-tools/lib/Makefile.vms b/gettext-tools/lib/Makefile.vms
index bd70f25..e199087 100644
--- a/gettext-tools/lib/Makefile.vms
+++ b/gettext-tools/lib/Makefile.vms
@@ -51,6 +51,7 @@ OBJECTS = \
findprog.obj, \
fstrcmp.obj, \
full-write.obj, \
+ fwriteerror.obj, \
gcd.obj, \
getopt.obj, getopt1.obj, \
hash.obj, \
@@ -132,6 +133,9 @@ fstrcmp.obj : fstrcmp.c
full-write.obj : full-write.c
$(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) full-write.c
+fwriteerror.obj : fwriteerror.c
+ $(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) fwriteerror.c
+
gcd.obj : gcd.c
$(CC) $(INCLUDES) $(CFLAGS) /define=($(DEFS)) gcd.c
diff --git a/gettext-tools/lib/fwriteerror.c b/gettext-tools/lib/fwriteerror.c
new file mode 100644
index 0000000..364db86
--- /dev/null
+++ b/gettext-tools/lib/fwriteerror.c
@@ -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/gettext-tools/lib/fwriteerror.h b/gettext-tools/lib/fwriteerror.h
new file mode 100644
index 0000000..82cf5f1
--- /dev/null
+++ b/gettext-tools/lib/fwriteerror.h
@@ -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/gettext-tools/src/ChangeLog b/gettext-tools/src/ChangeLog
index daa38c8..8fa8b84 100644
--- a/gettext-tools/src/ChangeLog
+++ b/gettext-tools/src/ChangeLog
@@ -1,3 +1,18 @@
+2003-09-14 Bruno Haible <bruno@clisp.org>
+
+ * write-mo.c: Include fwriterror.h.
+ (msgdomain_write_mo): Use fwriteerror, to get right errno value in
+ error message about write error.
+ * write-po.c: Include fwriterror.h.
+ (msgdomain_list_print): Use fwriteerror, to get right errno value in
+ error message about write error.
+ * write-java.c: Include fwriterror.h.
+ (msgdomain_write_java): Use fwriteerror, to get right errno value in
+ error message about write error.
+ * write-tcl.c: Include fwriterror.h.
+ (msgdomain_write_tcl): Use fwriteerror, to get right errno value in
+ error message about write error.
+
2003-09-18 Bruno Haible <bruno@clisp.org>
* xgettext.c (from_current_source_encoding): Use multiline_error,
diff --git a/gettext-tools/src/write-java.c b/gettext-tools/src/write-java.c
index da8c76d..d8b200b 100644
--- a/gettext-tools/src/write-java.c
+++ b/gettext-tools/src/write-java.c
@@ -74,6 +74,7 @@
#include "po-charset.h"
#include "xmalloc.h"
#include "pathname.h"
+#include "fwriteerror.h"
#include "tmpdir.h"
#include "utf8-ucs4.h"
#include "gettext.h"
@@ -1151,7 +1152,7 @@ msgdomain_write_java (message_list_ty *mlp, const char *canon_encoding,
write_java_code (java_file, class_name, mlp, assume_java2);
- if (fflush (java_file) || ferror (java_file))
+ if (fwriteerror (java_file))
{
error (0, errno, _("error while writing \"%s\" file"), java_file_name);
fclose (java_file);
diff --git a/gettext-tools/src/write-mo.c b/gettext-tools/src/write-mo.c
index 53e6901..adba883 100644
--- a/gettext-tools/src/write-mo.c
+++ b/gettext-tools/src/write-mo.c
@@ -44,6 +44,7 @@
#include "format.h"
#include "xmalloc.h"
#include "binary-io.h"
+#include "fwriteerror.h"
#include "exit.h"
#include "gettext.h"
@@ -701,7 +702,7 @@ msgdomain_write_mo (message_list_ty *mlp,
write_table (output_file, mlp);
/* Make sure nothing went wrong. */
- if (fflush (output_file) || ferror (output_file))
+ if (fwriteerror (output_file))
error (EXIT_FAILURE, errno, _("error while writing \"%s\" file"),
file_name);
diff --git a/gettext-tools/src/write-po.c b/gettext-tools/src/write-po.c
index 985179e..4befb10 100644
--- a/gettext-tools/src/write-po.c
+++ b/gettext-tools/src/write-po.c
@@ -42,6 +42,7 @@
#include "write-properties.h"
#include "xmalloc.h"
#include "strstr.h"
+#include "fwriteerror.h"
#include "exit.h"
#include "error-progname.h"
#include "error.h"
@@ -1091,7 +1092,7 @@ msgdomain_list_print (msgdomain_list_ty *mdlp, const char *filename,
msgdomain_list_print_po (mdlp, fp, debug);
/* Make sure nothing went wrong. */
- if (fflush (fp) || ferror (fp))
+ if (fwriteerror (fp))
error (EXIT_FAILURE, errno, _("error while writing \"%s\" file"),
filename);
diff --git a/gettext-tools/src/write-tcl.c b/gettext-tools/src/write-tcl.c
index b99a103..4b0146b 100644
--- a/gettext-tools/src/write-tcl.c
+++ b/gettext-tools/src/write-tcl.c
@@ -36,6 +36,7 @@
#include "po-charset.h"
#include "xmalloc.h"
#include "pathname.h"
+#include "fwriteerror.h"
#include "exit.h"
#include "utf8-ucs4.h"
#include "gettext.h"
@@ -197,7 +198,7 @@ but the Tcl message catalog format doesn't support plural handling\n")));
write_msg (output_file, mlp, frobbed_locale_name);
/* Make sure nothing went wrong. */
- if (fflush (output_file) || ferror (output_file))
+ if (fwriteerror (output_file))
error (EXIT_FAILURE, errno, _("error while writing \"%s\" file"),
file_name);
diff --git a/gettext-tools/windows/gettextlib.def b/gettext-tools/windows/gettextlib.def
index 96c6653..d28f12e 100644
--- a/gettext-tools/windows/gettextlib.def
+++ b/gettext-tools/windows/gettextlib.def
@@ -45,6 +45,7 @@ find_entry
find_in_path
fstrcmp
full_write
+fwriteerror
gcd
getopt_long
get_version