diff options
-rw-r--r-- | ChangeLog | 33 | ||||
-rw-r--r-- | awk.h | 2 | ||||
-rw-r--r-- | builtin.c | 77 | ||||
-rw-r--r-- | io.c | 21 | ||||
-rw-r--r-- | main.c | 12 | ||||
-rw-r--r-- | nonposix.h | 1 | ||||
-rw-r--r-- | pc/ChangeLog | 5 | ||||
-rw-r--r-- | pc/gawkmisc.pc | 38 | ||||
-rw-r--r-- | posix/ChangeLog | 4 | ||||
-rw-r--r-- | posix/gawkmisc.c | 5 | ||||
-rw-r--r-- | vms/ChangeLog | 4 | ||||
-rw-r--r-- | vms/gawkmisc.vms | 5 |
12 files changed, 135 insertions, 72 deletions
@@ -1,3 +1,36 @@ +2021-12-01 Arnold D. Robbins <arnold@skeeve.com> + + * builtin.c (efflush): Don't use return in call of function + returning void. It works, but is funky, and I think some + compilers will complain. + + Unrelated. Clean up the calls to w32_maybe_set_errno. + + * awk.h (os_maybe_set_errno): Add declaration. + * builtin.c (wrerror): Replaced ifdef'ed code calling + w32_maybe_set_errno() with simple call to os_maybe_set_errno(). + * io.c (non_fatal_flush_std_file, close_io): Ditto. + * main.c (usage, copyleft): Ditto. + * nonposix.h (w32_maybe_set_errno): Remove declaration. + +2021-11-30 Andrew J. Schorr <aschorr@telemetry-investments.com> + + Improve output redirection error handling for problems not detected + until the final flush or close. Thanks to Miguel Pineiro Jr. + <mpj@pineiro.cc> for the bug report and suggesting a fix. + + * awk.h (efflush): Add declaration. + * builtin.c (efwrite): Break up into 3 functions by moving the + flushing logic into efflush and the error handling logic into + wrerror. + (wrerror): New function containing the error-handling logic extracted + from efwrite. + (efflush): New function containing the fflush logic extracted from + efwrite. + * io.c (close_redir): Call efflush prior to closing the redirection + to identify any problems with flushing output and to take advantage + of the error-handling logic used for print and printf. + 2021-11-21 Arnold D. Robbins <arnold@skeeve.com> * builtin.c (do_typeof): Make Node_array_ref handling smarter. @@ -1469,6 +1469,7 @@ extern bool is_identchar(int c); extern NODE *make_regnode(NODETYPE type, NODE *exp); extern bool validate_qualified_name(char *token); /* builtin.c */ +extern void efflush(FILE *fp, const char *from, struct redirect *rp); extern double double_to_int(double d); extern NODE *do_exp(int nargs); extern NODE *do_fflush(int nargs); @@ -1621,6 +1622,7 @@ extern int os_isreadable(const awk_input_buf_t *iobuf, bool *isdir); extern int os_is_setuid(void); extern int os_setbinmode(int fd, int mode); extern void os_restore_mode(int fd); +extern void os_maybe_set_errno(void); extern size_t optimal_bufsize(int fd, struct stat *sbuf); extern int ispath(const char *file); extern int isdirpunct(int c); @@ -96,43 +96,14 @@ fatal(_("attempt to use array `%s' in a scalar context"), array_vname(s1)); \ */ #define GAWK_RANDOM_MAX 0x7fffffffL -/* efwrite --- like fwrite, but with error checking */ + +/* wrerror --- handle a write or flush error */ static void -efwrite(const void *ptr, - size_t size, - size_t count, - FILE *fp, - const char *from, - struct redirect *rp, - bool flush) +wrerror(FILE *fp, const char *from, struct redirect *rp) { - errno = 0; - if (rp != NULL) { - if (rp->output.gawk_fwrite(ptr, size, count, fp, rp->output.opaque) != count) - goto wrerror; - } else if (fwrite(ptr, size, count, fp) != count) - goto wrerror; - if (flush - && ((fp == stdout && output_is_tty) - || (rp != NULL && (rp->flag & RED_NOBUF) != 0))) { - if (rp != NULL) { - rp->output.gawk_fflush(fp, rp->output.opaque); - if (rp->output.gawk_ferror(fp, rp->output.opaque)) - goto wrerror; - } else { - fflush(fp); - if (ferror(fp)) - goto wrerror; - } - } - return; + os_maybe_set_errno(); -wrerror: -#ifdef __MINGW32__ - if (errno == 0 || errno == EINVAL) - w32_maybe_set_errno(); -#endif /* for stdout, die with a real SIGPIPE, like other awks */ if (fp == stdout && errno == EPIPE) die_via_sigpipe(); @@ -150,6 +121,46 @@ wrerror: errno ? strerror(errno) : _("reason unknown")); } +/* efflush --- flush output with proper error handling */ + +void +efflush(FILE *fp, const char *from, struct redirect *rp) +{ + errno = 0; + if (rp != NULL) { + rp->output.gawk_fflush(fp, rp->output.opaque); + if (rp->output.gawk_ferror(fp, rp->output.opaque)) + wrerror(fp, from, rp); + } else { + fflush(fp); + if (ferror(fp)) + wrerror(fp, from, rp); + } +} + +/* efwrite --- like fwrite, but with error checking */ + +static void +efwrite(const void *ptr, + size_t size, + size_t count, + FILE *fp, + const char *from, + struct redirect *rp, + bool flush) +{ + errno = 0; + if (rp != NULL) { + if (rp->output.gawk_fwrite(ptr, size, count, fp, rp->output.opaque) != count) + return wrerror(fp, from, rp); + } else if (fwrite(ptr, size, count, fp) != count) + return wrerror(fp, from, rp); + if (flush + && ((fp == stdout && output_is_tty) + || (rp != NULL && (rp->flag & RED_NOBUF) != 0))) + efflush(fp, from, rp); +} + /* do_exp --- exponential function */ NODE * @@ -1375,6 +1375,9 @@ close_redir(struct redirect *rp, bool exitwarn, two_way_close_type how) if (rp == NULL) return 0; + if ((rp->flag & RED_WRITE) && rp->output.fp) + /* flush before closing to leverage special error handling */ + efflush(rp->output.fp, "flush", rp); if (rp->output.fp == stdout || rp->output.fp == stderr) goto checkwarn; /* bypass closing, remove from list */ @@ -1460,10 +1463,8 @@ non_fatal_flush_std_file(FILE *fp) bool is_fatal = ! is_non_fatal_std(fp); if (is_fatal) { -#ifdef __MINGW32__ - if (errno == 0 || errno == EINVAL) - w32_maybe_set_errno(); -#endif + os_maybe_set_errno(); + if (errno == EPIPE) die_via_sigpipe(); else @@ -1560,10 +1561,8 @@ close_io(bool *stdio_problem, bool *got_EPIPE) *stdio_problem = false; /* we don't warn about stdout/stderr if EPIPE, but we do error exit */ if (fflush(stdout) != 0) { -#ifdef __MINGW32__ - if (errno == 0 || errno == EINVAL) - w32_maybe_set_errno(); -#endif + os_maybe_set_errno(); + if (errno != EPIPE) warning(_("error writing standard output: %s"), strerror(errno)); else @@ -1573,10 +1572,8 @@ close_io(bool *stdio_problem, bool *got_EPIPE) *stdio_problem = true; } if (fflush(stderr) != 0) { -#ifdef __MINGW32__ - if (errno == 0 || errno == EINVAL) - w32_maybe_set_errno(); -#endif + os_maybe_set_errno(); + if (errno != EPIPE) warning(_("error writing standard error: %s"), strerror(errno)); else @@ -654,10 +654,8 @@ By default it reads standard input and writes standard output.\n\n"), fp); fflush(fp); if (ferror(fp)) { -#ifdef __MINGW32__ - if (errno == 0 || errno == EINVAL) - w32_maybe_set_errno(); -#endif + os_maybe_set_errno(); + /* don't warn about stdout/stderr if EPIPE, but do error exit */ if (errno == EPIPE) die_via_sigpipe(); @@ -704,10 +702,8 @@ along with this program. If not, see http://www.gnu.org/licenses/.\n"); fflush(stdout); if (ferror(stdout)) { -#ifdef __MINGW32__ - if (errno == 0 || errno == EINVAL) - w32_maybe_set_errno(); -#endif + os_maybe_set_errno(); + /* don't warn about stdout if EPIPE, but do error exit */ if (errno != EPIPE) warning(_("error writing standard output: %s"), strerror(errno)); @@ -56,7 +56,6 @@ unsigned int getegid (void); /* gawkmisc.pc */ int unsetenv (const char *); int setenv (const char *, const char *, int); -void w32_maybe_set_errno (void); char *w32_setlocale (int, const char *); /* libintl.h from GNU gettext defines setlocale to redirect that to its own function. Note: this will have to be revisited if MinGW diff --git a/pc/ChangeLog b/pc/ChangeLog index c0027c38..d1acbf50 100644 --- a/pc/ChangeLog +++ b/pc/ChangeLog @@ -1,3 +1,8 @@ +2021-12-01 Arnold D. Robbins <arnold@skeeve.com> + + * gawkmisc.pc (os_maybe_set_errno): Renamed from + w32_maybe_set_errno. Add check for errno values. + 2021-11-21 Arnold D. Robbins <arnold@skeeve.com> * Makefile.tst: Regenerated. diff --git a/pc/gawkmisc.pc b/pc/gawkmisc.pc index 1843a168..149ea62c 100644 --- a/pc/gawkmisc.pc +++ b/pc/gawkmisc.pc @@ -1066,25 +1066,27 @@ w32_status_to_termsig (unsigned status) } void -w32_maybe_set_errno (void) +os_maybe_set_errno (void) { - DWORD w32err = GetLastError (); - - switch (w32err) - { - /* When stdout is redirected to a pipe, and the program that - reads the pipe (e.g., a pager) exits, Windows doesn't set - errno to a useful value. Help it DTRT. */ - case ERROR_BAD_PIPE: - case ERROR_PIPE_BUSY: - case ERROR_NO_DATA: - case ERROR_PIPE_NOT_CONNECTED: - errno = EPIPE; - break; - default: - errno = EINVAL; - break; - } + if (errno == 0 || errno == EINVAL) { + DWORD w32err = GetLastError (); + + switch (w32err) + { + /* When stdout is redirected to a pipe, and the program that + reads the pipe (e.g., a pager) exits, Windows doesn't set + errno to a useful value. Help it DTRT. */ + case ERROR_BAD_PIPE: + case ERROR_PIPE_BUSY: + case ERROR_NO_DATA: + case ERROR_PIPE_NOT_CONNECTED: + errno = EPIPE; + break; + default: + errno = EINVAL; + break; + } + } } #endif /* __MINGW32__ */ diff --git a/posix/ChangeLog b/posix/ChangeLog index 0553a19f..06b16f74 100644 --- a/posix/ChangeLog +++ b/posix/ChangeLog @@ -1,3 +1,7 @@ +2021-12-01 Arnold D. Robbins <arnold@skeeve.com> + + * gawkmisc.c (os_maybe_set_errno): New, empty function. + 2021-10-27 Arnold D. Robbins <arnold@skeeve.com> * 5.1.1: Release tar ball made. diff --git a/posix/gawkmisc.c b/posix/gawkmisc.c index 10c543ca..e6f316c9 100644 --- a/posix/gawkmisc.c +++ b/posix/gawkmisc.c @@ -290,6 +290,11 @@ init_sockets(void) { } +void +os_maybe_set_errno(void) +{ +} + // For MSYS, restore behavior of working in text mode. #ifdef __MSYS__ void diff --git a/vms/ChangeLog b/vms/ChangeLog index fa2a0fba..1f332f57 100644 --- a/vms/ChangeLog +++ b/vms/ChangeLog @@ -1,3 +1,7 @@ +2021-12-01 Arnold D. Robbins <arnold@skeeve.com> + + * gawkmisc.vms (os_maybe_set_errno): New, empty function. + 2021-10-27 Arnold D. Robbins <arnold@skeeve.com> * 5.1.1: Release tar ball made. diff --git a/vms/gawkmisc.vms b/vms/gawkmisc.vms index c4a2f086..23246bd8 100644 --- a/vms/gawkmisc.vms +++ b/vms/gawkmisc.vms @@ -660,3 +660,8 @@ void init_sockets(void) { } + +void +os_maybe_set_errno(void) +{ +} |