summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Martin <ality@pbrane.org>2020-11-19 23:05:26 -0800
committerAnthony Martin <ality@pbrane.org>2020-11-19 23:05:26 -0800
commitef2fdb6fdd012722394f5dd75ecdf1ffb1193db6 (patch)
treeb334f14a72c8a5c3232b5262423a005b571afd9f
parent808acd51f4e78d8883b81a3df6eb1fe1b61bd903 (diff)
downloadplan9front-ef2fdb6fdd012722394f5dd75ecdf1ffb1193db6.tar.xz
awk: fix truncated input after fflush
Before the "native" awk work, a call to the fflush function resulted in one or more calls to the APE fflush(2). Calling fflush on a stream open for reading has different behavior based on the environment: within APE, it's a no-op¹; on OpenBSD, it's an error²; in musl, it depends on whether or not the underlying file descriptor is seekable³; etc. I'm sure glibc is subtly different. Now that awk uses libbio, things are different: calling Bflush(2) on a file open for reading simply discards any data in the buffer. This explains why we're seeing truncated input. When awk attempts to read in the next record, there's nothing in the buffer and no more data to read so it gets EOF and exits normally. Note that this behavior is not documented in bio(2). It was added in the second edition but I haven't figured out why or what depends on it. The simple fix is to have awk only call Bflush on files that were opened for writing. You could argue that this is the only correct behavior according to the awk(1) manual and it is, in fact, how GNU awk behaves⁴. 1. /sys/src/ape/lib/ap/stdio/fflush.c 2. https://cvsweb.openbsd.org/src/lib/libc/stdio/fflush.c?rev=1.9 3. https://git.musl-libc.org/cgit/musl/tree/src/stdio/fflush.c 4. https://git.savannah.gnu.org/cgit/gawk.git/tree/io.c#n1492
-rw-r--r--sys/src/cmd/awk/run.c10
1 files changed, 6 insertions, 4 deletions
diff --git a/sys/src/cmd/awk/run.c b/sys/src/cmd/awk/run.c
index 9af1b4b01..94918a29f 100644
--- a/sys/src/cmd/awk/run.c
+++ b/sys/src/cmd/awk/run.c
@@ -1706,6 +1706,7 @@ void stdinit(void) /* in case stdin, etc., are not constants */
files[1].fp = &stdout;
files[2].fp = &stderr;
}
+#define writing(m) ((m) != LT && (m) != LE)
Biobuf *openfile(int a, char *us)
{
@@ -1719,8 +1720,11 @@ Biobuf *openfile(int a, char *us)
if (files[i].fname && strcmp(s, files[i].fname) == 0) {
if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
return files[i].fp;
- if (a == FFLUSH)
+ if (a == FFLUSH) {
+ if(!writing(files[i].mode))
+ return nil;
return files[i].fp;
+ }
}
if (a == FFLUSH) /* didn't find it, so don't create it! */
return nil;
@@ -1813,12 +1817,10 @@ void closeall(void)
void flush_all(void)
{
int i;
-
for (i = 0; i < FOPEN_MAX; i++)
- if (files[i].fp)
+ if (files[i].fp && writing(files[i].mode))
Bflush(files[i].fp);
}
-
void backsub(char **pb_ptr, char **sptr_ptr);
Cell *sub(Node **a, int) /* substitute command */