diff options
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | awk.h | 1 | ||||
-rw-r--r-- | builtin.c | 73 | ||||
-rw-r--r-- | io.c | 3 |
4 files changed, 64 insertions, 30 deletions
@@ -1,3 +1,20 @@ +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 loginc 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. @@ -1464,6 +1464,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); @@ -96,39 +96,12 @@ 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; - -wrerror: #ifdef __MINGW32__ if (errno == 0 || errno == EINVAL) w32_maybe_set_errno(); @@ -150,6 +123,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)) + return wrerror(fp, from, rp); + } else { + fflush(fp); + if (ferror(fp)) + return 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 */ |