diff --git a/awk.h b/awk.h index 9e6f2ca..65e7fd4 100644 --- a/awk.h +++ b/awk.h @@ -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); diff --git a/builtin.c b/builtin.c index 386b6ed..fc3b508 100644 --- a/builtin.c +++ b/builtin.c @@ -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 * diff --git a/io.c b/io.c index 91c94d9..dec81bc 100644 --- a/io.c +++ b/io.c @@ -1375,6 +1375,10 @@ 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 take advantage of the error + * handling */ + efflush(rp->output.fp, "close_redir", rp); if (rp->output.fp == stdout || rp->output.fp == stderr) goto checkwarn; /* bypass closing, remove from list */