diff options
author | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2016-09-18 15:45:51 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2016-09-18 15:45:51 +0000 |
commit | 9a8774fec27d9d9dd81a79782d59e1922bfd1a8b (patch) | |
tree | f382921ce049ac568cf1a59ff3e888a2446d6e9a /usr.bin | |
parent | ebe614d4ec539ca16f4f7e739e1a78c61edd070f (diff) |
We cannot use fputs(3) in passthrough() because the stdout stream
might be in stdio wide orientation due to prior formatting of an
unformatted manual in man -aTutf8 mode. So for now, use fflush(3)
followed by unbuffered write(2) instead. Fixes output corruption
on glibc discovered on Linux while testing a diff to fix a loosely
related bug reported by <jmates at ee dot washington dot edu>.
I detest the concept of stdio stream orientation. One day, i will
rewrite term_ascii.c to always use narrow streams, even in UTF-8
output mode. But that's too much work for today.
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/mandoc/main.c | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/usr.bin/mandoc/main.c b/usr.bin/mandoc/main.c index 1a0602882e1..e0893d19367 100644 --- a/usr.bin/mandoc/main.c +++ b/usr.bin/mandoc/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.179 2016/09/18 15:21:00 schwarze Exp $ */ +/* $OpenBSD: main.c,v 1.180 2016/09/18 15:45:50 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2010-2012, 2014-2016 Ingo Schwarze <schwarze@openbsd.org> @@ -790,11 +790,17 @@ passthrough(const char *file, int fd, int synopsis_only) const char *syscall; char *line, *cp; size_t linesz; + ssize_t len, written; int print; line = NULL; linesz = 0; + if (fflush(stdout) == EOF) { + syscall = "fflush"; + goto fail; + } + if ((stream = fdopen(fd, "r")) == NULL) { close(fd); syscall = "fdopen"; @@ -802,14 +808,16 @@ passthrough(const char *file, int fd, int synopsis_only) } print = 0; - while (getline(&line, &linesz, stream) != -1) { + while ((len = getline(&line, &linesz, stream)) != -1) { cp = line; if (synopsis_only) { if (print) { if ( ! isspace((unsigned char)*cp)) goto done; - while (isspace((unsigned char)*cp)) + while (isspace((unsigned char)*cp)) { cp++; + len--; + } } else { if (strcmp(cp, synb) == 0 || strcmp(cp, synr) == 0) @@ -817,9 +825,11 @@ passthrough(const char *file, int fd, int synopsis_only) continue; } } - if (fputs(cp, stdout)) { + for (; len > 0; len -= written) { + if ((written = write(STDOUT_FILENO, cp, len)) != -1) + continue; fclose(stream); - syscall = "fputs"; + syscall = "write"; goto fail; } } |