From 922dba2a9a00c35abb19c5dba01169e7335ce23b Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 6 Mar 2018 14:08:23 +0000 Subject: winansi: check for broken pipe Microsoft Windows doesn't support SIGPIPE and its support for the EPIPE error is somewhat inadequate. Most of the time a broken pipe leads to an EINVAL error which is misleading: $ yes hello | head -1 hello yes: Invalid argument Add a function to test for the underlying Windows error that indicates a broken pipe and set errno to EPIPE. Call this function in a few strategic places. --- win32/winansi.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/win32/winansi.c b/win32/winansi.c index 8e583e0ce..256ef4fa9 100644 --- a/win32/winansi.c +++ b/win32/winansi.c @@ -475,16 +475,31 @@ int winansi_puts(const char *s) return (winansi_fputs(s, stdout) == EOF || putchar('\n') == EOF) ? EOF : 0; } +static void check_pipe(FILE *stream) +{ + if (GetLastError() == ERROR_NO_DATA && ferror(stream)) { + int fd = fileno(stream); + if (fd != -1 && + GetFileType((HANDLE)_get_osfhandle(fd)) == FILE_TYPE_PIPE) { + errno = EPIPE; + } + } +} + size_t winansi_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { - size_t lsize, lmemb; + size_t lsize, lmemb, ret; char *str; int rv; lsize = MIN(size, nmemb); lmemb = MAX(size, nmemb); - if (lsize != 1 || !is_console(fileno(stream))) - return fwrite(ptr, size, nmemb, stream); + if (lsize != 1 || !is_console(fileno(stream))) { + SetLastError(0); + if ((ret=fwrite(ptr, size, nmemb, stream)) < nmemb) + check_pipe(stream); + return ret; + } str = xmalloc(lmemb+1); memcpy(str, ptr, lmemb); @@ -498,8 +513,14 @@ size_t winansi_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) int winansi_fputs(const char *str, FILE *stream) { - if (!is_console(fileno(stream))) - return fputs(str, stream); + int ret; + + if (!is_console(fileno(stream))) { + SetLastError(0); + if ((ret=fputs(str, stream)) == EOF) + check_pipe(stream); + return ret; + } return ansi_emulate(str, stream) == EOF ? EOF : 0; } @@ -538,7 +559,9 @@ int winansi_vfprintf(FILE *stream, const char *format, va_list list) return rv; abort: - rv = vfprintf(stream, format, list); + SetLastError(0); + if ((rv=vfprintf(stream, format, list)) == EOF) + check_pipe(stream); return rv; } -- cgit v1.2.3-55-g6feb