NEWS.stable: log cherry-pick [e446f25]->[c092018] relocatable-shell: Update suggested...
[gnulib.git] / lib / closein.c
index 4450d5b..5b2c915 100644 (file)
@@ -1,11 +1,11 @@
 /* Close standard input, rewinding seekable stdin if necessary.
 
 /* Close standard input, rewinding seekable stdin if necessary.
 
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2009-2014 Free Software Foundation, Inc.
 
 
-   This program is free software; you can redistribute it and/or modify
+   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
    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.
+   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
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,8 +13,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    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.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
 
 #include <config.h>
 
@@ -32,6 +31,7 @@
 #include "closeout.h"
 #include "error.h"
 #include "exitfail.h"
 #include "closeout.h"
 #include "error.h"
 #include "exitfail.h"
+#include "freadahead.h"
 #include "quotearg.h"
 
 static const char *file_name;
 #include "quotearg.h"
 
 static const char *file_name;
@@ -55,7 +55,7 @@ close_stdin_set_file_name (const char *file)
    For example, POSIX requires that these two commands behave alike:
 
      (sed -ne 1q; cat) < file
    For example, POSIX requires that these two commands behave alike:
 
      (sed -ne 1q; cat) < file
-     tail -n 1 file
+     tail -n +2 file
 
    Since close_stdin is commonly registered via 'atexit', POSIX
    and the C standard both say that it should not call 'exit',
 
    Since close_stdin is commonly registered via 'atexit', POSIX
    and the C standard both say that it should not call 'exit',
@@ -72,7 +72,7 @@ close_stdin_set_file_name (const char *file)
    the removal of these files.
 
    It's important to detect such failures and exit nonzero because many
    the removal of these files.
 
    It's important to detect such failures and exit nonzero because many
-   tools (most notably `make' and other build-management systems) depend
+   tools (most notably 'make' and other build-management systems) depend
    on being able to detect failure in other tools via their exit status.  */
 
 void
    on being able to detect failure in other tools via their exit status.  */
 
 void
@@ -80,22 +80,29 @@ close_stdin (void)
 {
   bool fail = false;
 
 {
   bool fail = false;
 
-  /* Only attempt flush if stdin is seekable, as fflush is entitled to
-     fail on non-seekable streams.  */
-  if (fseeko (stdin, 0, SEEK_CUR) == 0 && fflush (stdin) != 0)
-    fail = true;
+  /* There is no need to flush stdin if we can determine quickly that stdin's
+     input buffer is empty; in this case we know that if stdin is seekable,
+     (fseeko (stdin, 0, SEEK_CUR), ftello (stdin))
+     == lseek (0, 0, SEEK_CUR).  */
+  if (freadahead (stdin) > 0)
+    {
+      /* Only attempt flush if stdin is seekable, as fflush is entitled to
+         fail on non-seekable streams.  */
+      if (fseeko (stdin, 0, SEEK_CUR) == 0 && fflush (stdin) != 0)
+        fail = true;
+    }
   if (close_stream (stdin) != 0)
     fail = true;
   if (fail)
     {
       /* Report failure, but defer exit until after closing stdout,
   if (close_stream (stdin) != 0)
     fail = true;
   if (fail)
     {
       /* Report failure, but defer exit until after closing stdout,
-        since the failure report should still be flushed.  */
+         since the failure report should still be flushed.  */
       char const *close_error = _("error closing file");
       if (file_name)
       char const *close_error = _("error closing file");
       if (file_name)
-       error (0, errno, "%s: %s", quotearg_colon (file_name),
-              close_error);
+        error (0, errno, "%s: %s", quotearg_colon (file_name),
+               close_error);
       else
       else
-       error (0, errno, "%s", close_error);
+        error (0, errno, "%s", close_error);
     }
 
   close_stdout ();
     }
 
   close_stdout ();