>From 074424d5666e3499132421d67dfe50e1702bcbae Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 22 Aug 2021 11:54:44 -0700 Subject: [PATCH 2/4] maint: use clearerr on stdin when appropriate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is so that commands like ‘fmt - -’ read from stdin both times, even when it is a tty. Fix some other minor issues that are related. * src/blake2/b2sum.c (main): * src/cksum.c (cksum): * src/cut.c (cut_file): * src/expand-common.c (next_file): * src/fmt.c (fmt): * src/fold.c (fold_file): * src/md5sum.c (digest_file, digest_check): * src/nl.c (nl_file): * src/od.c (check_and_close): * src/paste.c (paste_parallel, paste_serial): * src/pr.c (close_file): * src/sum.c (bsd_sum_file): Use clearerr on stdin so that stdin can be read multiple times even if it is a tty. Do not assume that ferror preserves errno as POSIX does not guarantee this. Coalesce duplicate diagnostic calls. * src/blake2/b2sum.c (main): * src/fmt.c (main, fmt): Report read error, even if it's merely fclose failure. * src/fmt.c: Include die.h. (fmt): New arg FILE. Close input (reporting error) if not stdin. All callers changed. * src/ptx.c (swallow_file_in_memory): Clear stdin's EOF flag. * src/sort.c (xfclose): Remove unnecessary feof call. --- src/blake2/b2sum.c | 5 ++++- src/cksum.c | 19 +++++++++---------- src/cut.c | 12 ++++++------ src/expand-common.c | 12 ++++++------ src/fmt.c | 45 +++++++++++++++++++++++++++++++-------------- src/fold.c | 16 ++++++++-------- src/md5sum.c | 31 +++++++++++++++---------------- src/nl.c | 14 +++++++------- src/od.c | 17 ++++++++--------- src/paste.c | 26 ++++++++++++-------------- src/pr.c | 14 ++++++++++---- src/ptx.c | 3 +++ src/sort.c | 3 +-- src/sum.c | 19 +++++++++---------- 14 files changed, 129 insertions(+), 107 deletions(-) diff --git a/src/blake2/b2sum.c b/src/blake2/b2sum.c index 9f1108137..0a2387b39 100644 --- a/src/blake2/b2sum.c +++ b/src/blake2/b2sum.c @@ -388,7 +388,10 @@ int main( int argc, char **argv ) printf( " %s\n", argv[i] ); } - if( f != stdin ) fclose( f ); + if( f == stdin ) + clearerr( f ); + else if( fclose( f ) != 0 ) + fprintf( stderr, "Could not close `%s': %s\n", argv[i], strerror( errno ) ); } return 0; diff --git a/src/cksum.c b/src/cksum.c index c3416f866..3cc4296bc 100644 --- a/src/cksum.c +++ b/src/cksum.c @@ -298,17 +298,16 @@ cksum (char const *file, bool print_name) if (! cksum_fp (fp, file, &crc, &length)) return false; - if (ferror (fp)) - { - error (0, errno, "%s", quotef (file)); - if (!STREQ (file, "-")) - fclose (fp); - return false; - } - - if (!STREQ (file, "-") && fclose (fp) == EOF) + int err = errno; + if (!ferror (fp)) + err = 0; + if (STREQ (file, "-")) + clearerr (fp); + else if (fclose (fp) != 0 && !err) + err = errno; + if (err) { - error (0, errno, "%s", quotef (file)); + error (0, err, "%s", quotef (file)); return false; } diff --git a/src/cut.c b/src/cut.c index f4d44c211..cdf33d897 100644 --- a/src/cut.c +++ b/src/cut.c @@ -460,16 +460,16 @@ cut_file (char const *file) cut_stream (stream); - if (ferror (stream)) - { - error (0, errno, "%s", quotef (file)); - return false; - } + int err = errno; + if (!ferror (stream)) + err = 0; if (STREQ (file, "-")) clearerr (stream); /* Also clear EOF. */ else if (fclose (stream) == EOF) + err = errno; + if (err) { - error (0, errno, "%s", quotef (file)); + error (0, err, "%s", quotef (file)); return false; } return true; diff --git a/src/expand-common.c b/src/expand-common.c index 55df8dc0f..4deb7bd8a 100644 --- a/src/expand-common.c +++ b/src/expand-common.c @@ -338,16 +338,16 @@ next_file (FILE *fp) if (fp) { assert (prev_file); - if (ferror (fp)) - { - error (0, errno, "%s", quotef (prev_file)); - exit_status = EXIT_FAILURE; - } + int err = errno; + if (!ferror (fp)) + err = 0; if (STREQ (prev_file, "-")) clearerr (fp); /* Also clear EOF. */ else if (fclose (fp) != 0) + err = errno; + if (err) { - error (0, errno, "%s", quotef (prev_file)); + error (0, err, "%s", quotef (prev_file)); exit_status = EXIT_FAILURE; } } diff --git a/src/fmt.c b/src/fmt.c index ca9231b99..bfccd9ba1 100644 --- a/src/fmt.c +++ b/src/fmt.c @@ -28,6 +28,7 @@ #include "system.h" #include "error.h" +#include "die.h" #include "fadvise.h" #include "xdectoint.h" @@ -151,7 +152,7 @@ struct Word /* Forward declarations. */ static void set_prefix (char *p); -static void fmt (FILE *f); +static bool fmt (FILE *f, char const *); static bool get_paragraph (FILE *f); static int get_line (FILE *f, int c); static int get_prefix (FILE *f); @@ -412,28 +413,29 @@ main (int argc, char **argv) goal_width = max_width * (2 * (100 - LEEWAY) + 1) / 200; } + bool have_read_stdin = false; + if (optind == argc) - fmt (stdin); + { + have_read_stdin = true; + ok = fmt (stdin, "-"); + } else { for (; optind < argc; optind++) { char *file = argv[optind]; if (STREQ (file, "-")) - fmt (stdin); + { + ok &= fmt (stdin, file); + have_read_stdin = true; + } else { FILE *in_stream; in_stream = fopen (file, "r"); if (in_stream != NULL) - { - fmt (in_stream); - if (fclose (in_stream) == EOF) - { - error (0, errno, "%s", quotef (file)); - ok = false; - } - } + ok &= fmt (in_stream, file); else { error (0, errno, _("cannot open %s for reading"), @@ -444,6 +446,9 @@ main (int argc, char **argv) } } + if (have_read_stdin && fclose (stdin) != 0) + die (EXIT_FAILURE, errno, "%s", _("closing standard input")); + return ok ? EXIT_SUCCESS : EXIT_FAILURE; } @@ -470,10 +475,13 @@ set_prefix (char *p) prefix_length = s - p; } -/* read file F and send formatted output to stdout. */ +/* Read F and send formatted output to stdout. + Close F when done, unless F is stdin. Diagnose input errors, using FILE. + If !F, assume F resulted from an fopen failure and diagnose that. + Return true if successful. */ -static void -fmt (FILE *f) +static bool +fmt (FILE *f, char const *file) { fadvise (f, FADVISE_SEQUENTIAL); tabs = false; @@ -484,6 +492,15 @@ fmt (FILE *f) fmt_paragraph (); put_paragraph (word_limit); } + + int err = ferror (f) ? 0 : -1; + if (f == stdin) + clearerr (f); + else if (fclose (f) != 0 && err < 0) + err = errno; + if (0 <= err) + error (0, err, err ? "%s" : _("read error"), quotef (file)); + return err < 0; } /* Set the global variable 'other_indent' according to SAME_PARAGRAPH diff --git a/src/fold.c b/src/fold.c index ae33dd368..94a6d378e 100644 --- a/src/fold.c +++ b/src/fold.c @@ -216,20 +216,20 @@ fold_file (char const *filename, size_t width) } saved_errno = errno; + if (!ferror (istream)) + saved_errno = 0; if (offset_out) fwrite (line_out, sizeof (char), (size_t) offset_out, stdout); - if (ferror (istream)) + if (STREQ (filename, "-")) + clearerr (istream); + else if (fclose (istream) != 0 && !saved_errno) + saved_errno = errno; + + if (saved_errno) { error (0, saved_errno, "%s", quotef (filename)); - if (!STREQ (filename, "-")) - fclose (istream); - return false; - } - if (!STREQ (filename, "-") && fclose (istream) == EOF) - { - error (0, errno, "%s", quotef (filename)); return false; } diff --git a/src/md5sum.c b/src/md5sum.c index cbfdc3ab2..e2071cfd2 100644 --- a/src/md5sum.c +++ b/src/md5sum.c @@ -631,17 +631,15 @@ digest_file (char const *filename, int *binary, unsigned char *bin_result, #else err = DIGEST_STREAM (fp, bin_result); #endif - if (err) - { - error (0, errno, "%s", quotef (filename)); - if (fp != stdin) - fclose (fp); - return false; - } + err = err ? errno : 0; + if (is_stdin) + clearerr (fp); + else if (fclose (fp) != 0 && !err) + err = errno; - if (!is_stdin && fclose (fp) != 0) + if (err) { - error (0, errno, "%s", quotef (filename)); + error (0, err, "%s", quotef (filename)); return false; } @@ -798,15 +796,16 @@ digest_check (char const *checkfile_name) free (line); - if (ferror (checkfile_stream)) - { - error (0, 0, _("%s: read error"), quotef (checkfile_name)); - return false; - } + int err = ferror (checkfile_stream) ? 0 : -1; + if (is_stdin) + clearerr (checkfile_stream); + else if (fclose (checkfile_stream) != 0 && err < 0) + err = errno; - if (!is_stdin && fclose (checkfile_stream) != 0) + if (0 <= err) { - error (0, errno, "%s", quotef (checkfile_name)); + error (0, err, err ? "%s" : _("%s: read error"), + quotef (checkfile_name)); return false; } diff --git a/src/nl.c b/src/nl.c index f3ba46c9b..7a13bcb97 100644 --- a/src/nl.c +++ b/src/nl.c @@ -457,16 +457,16 @@ nl_file (char const *file) process_file (stream); - if (ferror (stream)) - { - error (0, errno, "%s", quotef (file)); - return false; - } + int err = errno; + if (!ferror (stream)) + err = 0; if (STREQ (file, "-")) clearerr (stream); /* Also clear EOF. */ - else if (fclose (stream) == EOF) + else if (fclose (stream) != 0 && !err) + err = errno; + if (err) { - error (0, errno, "%s", quotef (file)); + error (0, err, "%s", quotef (file)); return false; } return true; diff --git a/src/od.c b/src/od.c index f04e0ccb7..111c94935 100644 --- a/src/od.c +++ b/src/od.c @@ -949,16 +949,15 @@ check_and_close (int in_errno) if (in_stream != NULL) { - if (ferror (in_stream)) + if (!ferror (in_stream)) + in_errno = 0; + if (STREQ (file_list[-1], "-")) + clearerr (in_stream); + else if (fclose (in_stream) != 0 && !in_errno) + in_errno = errno; + if (in_errno) { - error (0, in_errno, _("%s: read error"), quotef (input_filename)); - if (! STREQ (file_list[-1], "-")) - fclose (in_stream); - ok = false; - } - else if (! STREQ (file_list[-1], "-") && fclose (in_stream) != 0) - { - error (0, errno, "%s", quotef (input_filename)); + error (0, in_errno, "%s", quotef (input_filename)); ok = false; } diff --git a/src/paste.c b/src/paste.c index 48229acc5..f43fb56c2 100644 --- a/src/paste.c +++ b/src/paste.c @@ -266,16 +266,15 @@ paste_parallel (size_t nfiles, char **fnamptr) If an EOF or error, close the file. */ if (fileptr[i]) { - if (ferror (fileptr[i])) - { - error (0, err, "%s", quotef (fnamptr[i])); - ok = false; - } + if (!ferror (fileptr[i])) + err = 0; if (fileptr[i] == stdin) clearerr (fileptr[i]); /* Also clear EOF. */ - else if (fclose (fileptr[i]) == EOF) + else if (fclose (fileptr[i]) == EOF && !err) + err = errno; + if (err) { - error (0, errno, "%s", quotef (fnamptr[i])); + error (0, err, "%s", quotef (fnamptr[i])); ok = false; } @@ -410,16 +409,15 @@ paste_serial (size_t nfiles, char **fnamptr) if (charold != line_delim) xputchar (line_delim); - if (ferror (fileptr)) - { - error (0, saved_errno, "%s", quotef (*fnamptr)); - ok = false; - } + if (!ferror (fileptr)) + saved_errno = 0; if (is_stdin) clearerr (fileptr); /* Also clear EOF. */ - else if (fclose (fileptr) == EOF) + else if (fclose (fileptr) != 0 && !saved_errno) + saved_errno = errno; + if (saved_errno) { - error (0, errno, "%s", quotef (*fnamptr)); + error (0, saved_errno, "%s", quotef (*fnamptr)); ok = false; } } diff --git a/src/pr.c b/src/pr.c index da5795554..8f84d0f59 100644 --- a/src/pr.c +++ b/src/pr.c @@ -1506,10 +1506,16 @@ close_file (COLUMN *p) if (p->status == CLOSED) return; - if (ferror (p->fp)) - die (EXIT_FAILURE, errno, "%s", quotef (p->name)); - if (fileno (p->fp) != STDIN_FILENO && fclose (p->fp) != 0) - die (EXIT_FAILURE, errno, "%s", quotef (p->name)); + + int err = errno; + if (!ferror (p->fp)) + err = 0; + if (fileno (p->fp) == STDIN_FILENO) + clearerr (p->fp); + else if (fclose (p->fp) != 0 && !err) + err = errno; + if (err) + die (EXIT_FAILURE, err, "%s", quotef (p->name)); if (!parallel_files) { diff --git a/src/ptx.c b/src/ptx.c index 85c26aa1d..43075c840 100644 --- a/src/ptx.c +++ b/src/ptx.c @@ -526,6 +526,9 @@ swallow_file_in_memory (char const *file_name, BLOCK *block) if (!block->start) die (EXIT_FAILURE, errno, "%s", quotef (using_stdin ? "-" : file_name)); + if (using_stdin) + clearerr (stdin); + block->end = block->start + used_length; } diff --git a/src/sort.c b/src/sort.c index cba809c33..5f4c817de 100644 --- a/src/sort.c +++ b/src/sort.c @@ -1001,8 +1001,7 @@ xfclose (FILE *fp, char const *file) { case STDIN_FILENO: /* Allow reading stdin from tty more than once. */ - if (feof (fp)) - clearerr (fp); + clearerr (fp); break; case STDOUT_FILENO: diff --git a/src/sum.c b/src/sum.c index f9641dbb1..c17af3f6b 100644 --- a/src/sum.c +++ b/src/sum.c @@ -120,17 +120,16 @@ bsd_sum_file (char const *file, int print_name) checksum &= 0xffff; /* Keep it within bounds. */ } - if (ferror (fp)) - { - error (0, errno, "%s", quotef (file)); - if (!is_stdin) - fclose (fp); - return false; - } - - if (!is_stdin && fclose (fp) != 0) + int err = errno; + if (!ferror (fp)) + err = 0; + if (is_stdin) + clearerr (fp); + else if (fclose (fp) != 0 && !err) + err = errno; + if (err) { - error (0, errno, "%s", quotef (file)); + error (0, err, "%s", quotef (file)); return false; } -- 2.31.1