* closeout.c (close_stdout): Don't assume 'bool' converts nonzero
[gnulib.git] / lib / closeout.c
index b0eed90..2137fd4 100644 (file)
@@ -1,7 +1,7 @@
 /* closeout.c - close standard output
 
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Free Software
-   Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006 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
 
    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.  */
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
-#if HAVE_CONFIG_H
+#ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
 
 #include "closeout.h"
 
 #include <stdio.h>
+#include <stdbool.h>
 #include <errno.h>
 
 #include "gettext.h"
@@ -32,6 +33,7 @@
 #include "error.h"
 #include "exitfail.h"
 #include "quotearg.h"
+#include "__fpending.h"
 
 #if USE_UNLOCKED_IO
 # include "unlocked-io.h"
@@ -71,14 +73,25 @@ close_stdout_set_file_name (const char *file)
 void
 close_stdout (void)
 {
-  int e = ferror (stdout) ? 0 : -1;
+  bool none_pending = (__fpending (stdout) == 0);
+  bool prev_fail = (ferror (stdout) != 0);
+  bool fclose_fail = (fclose (stdout) != 0);
 
-  if (fclose (stdout) != 0)
-    e = errno;
-
-  if (0 <= e)
+  if (prev_fail || fclose_fail)
     {
-      char const *write_error = _("write error");
+      int e = fclose_fail ? errno : 0;
+      char const *write_error;
+
+      /* If ferror returned zero, no data remains to be flushed, and we'd
+        otherwise fail with EBADF due to a failed fclose, then assume that
+        it's ok to ignore the fclose failure.  That can happen when a
+        program like cp is invoked like this `cp a b >&-' (i.e., with
+        stdout closed) and doesn't generate any output (hence no previous
+        error and nothing to be flushed).  */
+      if (e == EBADF && !prev_fail && none_pending)
+       return;
+
+      write_error = _("write error");
       if (file_name)
        error (exit_failure, e, "%s: %s", quotearg_colon (file_name),
               write_error);