Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Posting-Version: version B 2.10.1     9/27/83; site hplabs.UUCP
Path: utzoo!watmath!clyde!floyd!harpo!seismo!hao!hplabs!kg
From: kg@hplabs.UUCP (Ken Greer)
Newsgroups: net.unix-wizards
Subject: Awk bug+fix
Message-ID: <2389@hplabs.UUCP>
Date: Thu, 1-Mar-84 16:49:43 EST
Article-I.D.: hplabs.2389
Posted: Thu Mar  1 16:49:43 1984
Date-Received: Sun, 4-Mar-84 03:22:23 EST
Organization: Hewlett Packard Labs, Palo Alto CA
Lines: 91

The following awk bug exists on all version of awk I've looked at
which includes 4.1BSD, 4.2BSD, Sys 5 rel. 0, and Sys 5 rel. 2. 

			Ken Greer
			hplabs!kg
			kg@HPLABS (CSNET)
			kg.hplabs@RAND-RELAY (ARPA)

The awk script,

END {
	print "First" > "junk"
	print "cat junk" | "sh"
	print "Second" > "junk"
    }

demonstrates two (and a half) bugs:

1) When finished, the file junk has two lines
   in it, not one.  The second > is treated like an >>.
2) The pipe on line three is executed after awk exits,
   not at the time of the call.
2.5) As a result of 1) and 2), the file cat-ed on line three
     shows two lines, not one.

The problem in awk is:

1) A file opened (with > or >>) is not closed after the
   statement is executed.  The file name is remembered
   and subsequent references to that file name use the same
   open descriptor.  (Efficient but wrong).

2) Pipes are not closed (with pclose).

The diff for the fix is:
-----------------------

In awk/run.c (procedure redirprint):

> = new version
11,16d10
< #define FILENUM	10
< struct
< {
< 	FILE *fp;
< 	char *fname;
< } files[FILENUM];
858d851
< 	register int i;
859a853
> 	FILE *fp;
863,870d856
< 	for (i=0; isval, files[i].fname) == 0)
< 			goto doit;
< 	for (i=0; i= FILENUM)
< 		error(FATAL, "too many output files %d", i);
872c858
< 		files[i].fp = popen(x->sval, "w");
---
> 		fp = popen(x->sval, "w");
874c860
< 		files[i].fp = fopen(x->sval, "a");
---
> 		fp = fopen(x->sval, "a");
876,877c862,863
< 		files[i].fp = fopen(x->sval, "w");
< 	if (files[i].fp == NULL)
---
> 		fp = fopen(x->sval, "w");
> 	if (fp == NULL)
879,884c865,869
< 	files[i].fname = tostring(x->sval);
< doit:
< 	fprintf(files[i].fp, "%s", s);
< #ifndef gcos
< 	fflush(files[i].fp);	/* in case someone is waiting for the output */
< #endif
---
> 	fprintf(fp, "%s", s);
> 	if (a == '|')
> 		pclose(fp);
> 	else
> 		fclose(fp);


-- 
Ken Greer