xref: /original-bsd/old/awk/run.c (revision a51a1dd1)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)run.c	4.10 (Berkeley) 05/26/93";
10 #endif /* not lint */
11 
12 #include "sys/param.h"
13 #include "awk.def"
14 #include "math.h"
15 #include "awk.h"
16 #include "stdio.h"
17 #include "fcntl.h"
18 #define RECSIZE BUFSIZ
19 
20 #define FILENUM	NOFILE
21 struct
22 {
23 	FILE *fp;
24 	int type;
25 	char *fname;
26 } files[FILENUM];
27 FILE *popen();
28 
29 extern obj execute(), nodetoobj(), fieldel(), dopa2(), gettemp();
30 #define PA2NUM	29
31 int pairstack[PA2NUM], paircnt;
32 node *winner = (node *)NULL;
33 #define MAXTMP 20
34 cell tmps[MAXTMP];
35 static cell nullval ={EMPTY,EMPTY,0.0,NUM,0};
36 obj	true	={ OBOOL, BTRUE, 0 };
37 obj	false	={ OBOOL, BFALSE, 0 };
38 
39 run()
40 {
41 	register int i;
42 
43 	execute(winner);
44 
45 	/* Wait for children to complete if output to a pipe. */
46 	for (i=0; i<FILENUM; i++)
47 		if (files[i].fp && files[i].type == '|')
48 			pclose(files[i].fp);
49 }
50 
51 obj execute(u) node *u;
52 {
53 	register obj (*proc)();
54 	obj x;
55 	node *a;
56 	extern char *printname[];
57 
58 	if (u==(node *)NULL)
59 		return(true);
60 	for (a = u; ; a = a->nnext) {
61 		if (cantexec(a))
62 			return(nodetoobj(a));
63 		if (a->ntype==NPA2)
64 			proc=dopa2;
65 		else {
66 			if (notlegal(a->nobj))
67 				error(FATAL, "illegal statement %o", a);
68 			proc = proctab[a->nobj-FIRSTTOKEN];
69 		}
70 		x = (*proc)(a->narg,a->nobj);
71 		if (isfld(x)) fldbld();
72 		if (isexpr(a))
73 			return(x);
74 		/* a statement, goto next statement */
75 		if (isjump(x))
76 			return(x);
77 		if (a->nnext == (node *)NULL)
78 			return(x);
79 		tempfree(x);
80 	}
81 }
82 
83 obj program(a, n) node **a;
84 {
85 	obj x;
86 
87 	if (a[0] != NULL) {
88 		x = execute(a[0]);
89 		if (isexit(x))
90 			return(true);
91 		if (isjump(x))
92 			error(FATAL, "unexpected break, continue or next");
93 		tempfree(x);
94 	}
95 	while (getrec()) {
96 		x = execute(a[1]);
97 		if (isexit(x)) break;
98 		tempfree(x);
99 	}
100 	tempfree(x);
101 	if (a[2] != NULL) {
102 		x = execute(a[2]);
103 		if (isbreak(x) || isnext(x) || iscont(x))
104 			error(FATAL, "unexpected break, continue or next");
105 		tempfree(x);
106 	}
107 	return(true);
108 }
109 
110 obj getline()
111 {
112 	obj x;
113 
114 	x = gettemp();
115 	setfval(x.optr, (awkfloat) getrec());
116 	return(x);
117 }
118 
119 obj array(a,n) node **a;
120 {
121 	obj x, y;
122 	extern obj arrayel();
123 
124 	x = execute(a[1]);
125 	y = arrayel(a[0], x);
126 	tempfree(x);
127 	return(y);
128 }
129 
130 obj arrayel(a,b) node *a; obj b;
131 {
132 	char *s;
133 	cell *x;
134 	int i;
135 	obj y;
136 
137 	s = getsval(b.optr);
138 	x = (cell *) a;
139 	if (!(x->tval&ARR)) {
140 		strfree(x->sval);
141 		x->tval &= ~STR;
142 		x->tval |= ARR;
143 		x->sval = (char *) makesymtab();
144 	}
145 	y.optr = setsymtab(s, tostring(""), 0.0, STR|NUM, x->sval);
146 	y.otype = OCELL;
147 	y.osub = CVAR;
148 	return(y);
149 }
150 
151 obj matchop(a,n) node **a;
152 {
153 	obj x;
154 	char *s;
155 	int i;
156 
157 	x = execute(a[0]);
158 	if (isstr(x)) s = x.optr->sval;
159 	else	s = getsval(x.optr);
160 	tempfree(x);
161 	i = match(a[1], s);
162 	if (n==MATCH && i==1 || n==NOTMATCH && i==0)
163 		return(true);
164 	else
165 		return(false);
166 }
167 
168 obj boolop(a,n) node **a;
169 {
170 	obj x, y;
171 	int i;
172 
173 	x = execute(a[0]);
174 	i = istrue(x);
175 	tempfree(x);
176 	switch (n) {
177 	default:
178 		error(FATAL, "unknown boolean operator %d", n);
179 	case BOR:
180 		if (i) return(true);
181 		y = execute(a[1]);
182 		i = istrue(y);
183 		tempfree(y);
184 		if (i) return(true);
185 		else return(false);
186 	case AND:
187 		if ( !i ) return(false);
188 		y = execute(a[1]);
189 		i = istrue(y);
190 		tempfree(y);
191 		if (i) return(true);
192 		else return(false);
193 	case NOT:
194 		if (i) return(false);
195 		else return(true);
196 	}
197 }
198 
199 obj relop(a,n) node **a;
200 {
201 	int i;
202 	obj x, y;
203 	awkfloat j;
204 
205 	x = execute(a[0]);
206 	y = execute(a[1]);
207 	if (x.optr->tval&NUM && y.optr->tval&NUM) {
208 		j = x.optr->fval - y.optr->fval;
209 		i = j<0? -1: (j>0? 1: 0);
210 	} else {
211 		i = strcmp(getsval(x.optr), getsval(y.optr));
212 	}
213 	tempfree(x);
214 	tempfree(y);
215 	switch (n) {
216 	default:
217 		error(FATAL, "unknown relational operator %d", n);
218 	case LT:	if (i<0) return(true);
219 			else return(false);
220 	case LE:	if (i<=0) return(true);
221 			else return(false);
222 	case NE:	if (i!=0) return(true);
223 			else return(false);
224 	case EQ:	if (i==0) return(true);
225 			else return(false);
226 	case GE:	if (i>=0) return(true);
227 			else return(false);
228 	case GT:	if (i>0) return(true);
229 			else return(false);
230 	}
231 }
232 
233 tempfree(a) obj a;
234 {
235 	if (!istemp(a)) return;
236 	strfree(a.optr->sval);
237 	a.optr->tval = 0;
238 }
239 
240 obj gettemp()
241 {
242 	int i;
243 	obj x;
244 
245 	for (i=0; i<MAXTMP; i++)
246 		if (tmps[i].tval==0)
247 			break;
248 	if (i==MAXTMP)
249 		error(FATAL, "out of temporaries in gettemp");
250 	x.optr = &tmps[i];
251 	tmps[i] = nullval;
252 	x.otype = OCELL;
253 	x.osub = CTEMP;
254 	return(x);
255 }
256 
257 obj indirect(a,n) node **a;
258 {
259 	obj x;
260 	int m;
261 	cell *fieldadr();
262 
263 	x = execute(a[0]);
264 	m = getfval(x.optr);
265 	tempfree(x);
266 	x.optr = fieldadr(m);
267 	x.otype = OCELL;
268 	x.osub = CFLD;
269 	return(x);
270 }
271 
272 obj substr(a, nnn) node **a;
273 {
274 	char *s, temp;
275 	obj x;
276 	int k, m, n;
277 
278 	x = execute(a[0]);
279 	s = getsval(x.optr);
280 	k = strlen(s) + 1;
281 	tempfree(x);
282 	x = execute(a[1]);
283 	m = getfval(x.optr);
284 	if (m <= 0)
285 		m = 1;
286 	else if (m > k)
287 		m = k;
288 	tempfree(x);
289 	if (a[2] != nullstat) {
290 		x = execute(a[2]);
291 		n = getfval(x.optr);
292 		tempfree(x);
293 	}
294 	else
295 		n = k - 1;
296 	if (n < 0)
297 		n = 0;
298 	else if (n > k - m)
299 		n = k - m;
300 	dprintf("substr: m=%d, n=%d, s=%s\n", m, n, s);
301 	x = gettemp();
302 	temp = s[n+m-1];	/* with thanks to John Linderman */
303 	s[n+m-1] = '\0';
304 	setsval(x.optr, s + m - 1);
305 	s[n+m-1] = temp;
306 	return(x);
307 }
308 
309 obj sindex(a, nnn) node **a;
310 {
311 	obj x;
312 	char *s1, *s2, *p1, *p2, *q;
313 
314 	x = execute(a[0]);
315 	s1 = getsval(x.optr);
316 	tempfree(x);
317 	x = execute(a[1]);
318 	s2 = getsval(x.optr);
319 	tempfree(x);
320 
321 	x = gettemp();
322 	for (p1 = s1; *p1 != '\0'; p1++) {
323 		for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
324 			;
325 		if (*p2 == '\0') {
326 			setfval(x.optr, (awkfloat) (p1 - s1 + 1));	/* origin 1 */
327 			return(x);
328 		}
329 	}
330 	setfval(x.optr, 0.0);
331 	return(x);
332 }
333 
334 char *format(s,a) char *s; node *a;
335 {
336 	char *buf, *p, fmt[200], *t, *os;
337 	obj x;
338 	int flag = 0;
339 	awkfloat xf;
340 
341 	os = s;
342 	p = buf = (char *)malloc(RECSIZE);
343 	while (*s) {
344 		if (*s != '%') {
345 			*p++ = *s++;
346 			continue;
347 		}
348 		if (*(s+1) == '%') {
349 			*p++ = '%';
350 			s += 2;
351 			continue;
352 		}
353 		for (t=fmt; (*t++ = *s) != '\0'; s++)
354 			if (*s >= 'a' && *s <= 'z' && *s != 'l')
355 				break;
356 		*t = '\0';
357 		if (t >= fmt + sizeof(fmt))
358 			error(FATAL, "format item %.20s... too long", os);
359 		switch (*s) {
360 		case 'f': case 'e': case 'g':
361 			flag = 1;
362 			break;
363 		case 'd':
364 			flag = 2;
365 			if(*(s-1) == 'l') break;
366 			*(t-1) = 'l';
367 			*t = 'd';
368 			*++t = '\0';
369 			break;
370 		case 'o': case 'x':
371 			flag = *(s-1)=='l' ? 2 : 3;
372 			break;
373 		case 'c':
374 			flag = 3;
375 			break;
376 		case 's':
377 			flag = 4;
378 			break;
379 		default:
380 			flag = 0;
381 			break;
382 		}
383 		if (flag == 0) {
384 			(void)sprintf(p, "%s", fmt);
385 			p += strlen(p);
386 			continue;
387 		}
388 		if (a == NULL)
389 			error(FATAL, "not enough arguments in printf(%s)", os);
390 		x = execute(a);
391 		a = a->nnext;
392 		if (flag != 4)	/* watch out for converting to numbers! */
393 			xf = getfval(x.optr);
394 		if (flag==1) (void)sprintf(p, fmt, xf);
395 		else if (flag==2) (void)sprintf(p, fmt, (long)xf);
396 		else if (flag==3) (void)sprintf(p, fmt, (int)xf);
397 		else if (flag==4) (void)sprintf(p, fmt, x.optr->sval==NULL ? "" : getsval(x.optr));
398 		tempfree(x);
399 		p += strlen(p);
400 		s++;
401 	}
402 	*p = '\0';
403 	return(buf);
404 }
405 
406 obj asprintf(a,n) node **a;
407 {
408 	obj x;
409 	node *y;
410 	char *s;
411 
412 	y = a[0]->nnext;
413 	x = execute(a[0]);
414 	s = format(getsval(x.optr), y);
415 	tempfree(x);
416 	x = gettemp();
417 	x.optr->sval = s;
418 	x.optr->tval = STR;
419 	return(x);
420 }
421 
422 obj arith(a,n) node **a;
423 {
424 	awkfloat i,j;
425 	obj x,y,z;
426 
427 	x = execute(a[0]);
428 	i = getfval(x.optr);
429 	tempfree(x);
430 	if (n != UMINUS) {
431 		y = execute(a[1]);
432 		j = getfval(y.optr);
433 		tempfree(y);
434 	}
435 	z = gettemp();
436 	switch (n) {
437 	default:
438 		error(FATAL, "illegal arithmetic operator %d", n);
439 	case ADD:
440 		i += j;
441 		break;
442 	case MINUS:
443 		i -= j;
444 		break;
445 	case MULT:
446 		i *= j;
447 		break;
448 	case DIVIDE:
449 		if (j == 0)
450 			error(FATAL, "division by zero");
451 		i /= j;
452 		break;
453 	case MOD:
454 		if (j == 0)
455 			error(FATAL, "division by zero");
456 		i = i - j*(long)(i/j);
457 		break;
458 	case UMINUS:
459 		i = -i;
460 		break;
461 	}
462 	setfval(z.optr, i);
463 	return(z);
464 }
465 
466 obj incrdecr(a, n) node **a;
467 {
468 	obj x, z;
469 	int k;
470 	awkfloat xf;
471 
472 	x = execute(a[0]);
473 	xf = getfval(x.optr);
474 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
475 	if (n == PREINCR || n == PREDECR) {
476 		setfval(x.optr, xf + k);
477 		return(x);
478 	}
479 	z = gettemp();
480 	setfval(z.optr, xf);
481 	setfval(x.optr, xf + k);
482 	tempfree(x);
483 	return(z);
484 }
485 
486 
487 obj assign(a,n) node **a;
488 {
489 	obj x, y;
490 	awkfloat xf, yf;
491 
492 	x = execute(a[0]);
493 	y = execute(a[1]);
494 	if (n == ASSIGN) {	/* ordinary assignment */
495 		if ((y.optr->tval & (STR|NUM)) == (STR|NUM)) {
496 			setsval(x.optr, y.optr->sval);
497 			x.optr->fval = y.optr->fval;
498 			x.optr->tval |= NUM;
499 		}
500 		else if (y.optr->tval & STR)
501 			setsval(x.optr, y.optr->sval);
502 		else if (y.optr->tval & NUM)
503 			setfval(x.optr, y.optr->fval);
504 		tempfree(y);
505 		return(x);
506 	}
507 	xf = getfval(x.optr);
508 	yf = getfval(y.optr);
509 	switch (n) {
510 	case ADDEQ:
511 		xf += yf;
512 		break;
513 	case SUBEQ:
514 		xf -= yf;
515 		break;
516 	case MULTEQ:
517 		xf *= yf;
518 		break;
519 	case DIVEQ:
520 		if (yf == 0)
521 			error(FATAL, "division by zero");
522 		xf /= yf;
523 		break;
524 	case MODEQ:
525 		if (yf == 0)
526 			error(FATAL, "division by zero");
527 		xf = xf - yf*(long)(xf/yf);
528 		break;
529 	default:
530 		error(FATAL, "illegal assignment operator %d", n);
531 		break;
532 	}
533 	tempfree(y);
534 	setfval(x.optr, xf);
535 	return(x);
536 }
537 
538 obj cat(a,q) node **a;
539 {
540 	obj x,y,z;
541 	int n1, n2;
542 	char *s;
543 
544 	x = execute(a[0]);
545 	y = execute(a[1]);
546 	getsval(x.optr);
547 	getsval(y.optr);
548 	n1 = strlen(x.optr->sval);
549 	n2 = strlen(y.optr->sval);
550 	s = (char *) malloc(n1 + n2 + 1);
551 	strcpy(s, x.optr->sval);
552 	strcpy(s+n1, y.optr->sval);
553 	tempfree(y);
554 	z = gettemp();
555 	z.optr->sval = s;
556 	z.optr->tval = STR;
557 	tempfree(x);
558 	return(z);
559 }
560 
561 obj pastat(a,n) node **a;
562 {
563 	obj x;
564 
565 	if (a[0]==nullstat)
566 		x = true;
567 	else
568 		x = execute(a[0]);
569 	if (istrue(x)) {
570 		tempfree(x);
571 		x = execute(a[1]);
572 	}
573 	return(x);
574 }
575 
576 obj dopa2(a,n) node **a;
577 {
578 	obj x;
579 
580 	if (pairstack[n]==0) {
581 		x = execute(a[0]);
582 		if (istrue(x))
583 			pairstack[n] = 1;
584 		tempfree(x);
585 	}
586 	if (pairstack[n] == 1) {
587 		x = execute(a[1]);
588 		if (istrue(x))
589 			pairstack[n] = 0;
590 		tempfree(x);
591 		x = execute(a[2]);
592 		return(x);
593 	}
594 	return(false);
595 }
596 
597 obj aprintf(a,n) node **a;
598 {
599 	obj x;
600 
601 	x = asprintf(a,n);
602 	if (a[1]==NULL) {
603 		printf("%s", x.optr->sval);
604 		tempfree(x);
605 		return(true);
606 	}
607 	redirprint(x.optr->sval, (int)a[1], a[2]);
608 	return(x);
609 }
610 
611 obj split(a,nnn) node **a;
612 {
613 	obj x;
614 	cell *ap;
615 	register char *s, *p;
616 	char *t, temp, num[5];
617 	register int sep;
618 	int n, flag;
619 
620 	x = execute(a[0]);
621 	s = getsval(x.optr);
622 	tempfree(x);
623 	if (a[2] == nullstat)
624 		sep = **FS;
625 	else {
626 		x = execute(a[2]);
627 		sep = getsval(x.optr)[0];
628 		tempfree(x);
629 	}
630 	ap = (cell *) a[1];
631 	freesymtab(ap);
632 	dprintf("split: s=|%s|, a=%s, sep=|%c|\n", s, ap->nval, sep);
633 	ap->tval &= ~STR;
634 	ap->tval |= ARR;
635 	ap->sval = (char *) makesymtab();
636 
637 	n = 0;
638 	if (sep == ' ')
639 		for (n = 0; ; ) {
640 			while (*s == ' ' || *s == '\t' || *s == '\n')
641 				s++;
642 			if (*s == 0)
643 				break;
644 			n++;
645 			t = s;
646 			do
647 				s++;
648 			while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
649 			temp = *s;
650 			*s = '\0';
651 			(void)sprintf(num, "%d", n);
652 			if (isanumber(t))
653 				setsymtab(num, tostring(t), atof(t), STR|NUM, ap->sval);
654 			else
655 				setsymtab(num, tostring(t), 0.0, STR, ap->sval);
656 			*s = temp;
657 			if (*s != 0)
658 				s++;
659 		}
660 	else if (*s != 0)
661 		for (;;) {
662 			n++;
663 			t = s;
664 			while (*s != sep && *s != '\n' && *s != '\0')
665 				s++;
666 			temp = *s;
667 			*s = '\0';
668 			(void)sprintf(num, "%d", n);
669 			if (isanumber(t))
670 				setsymtab(num, tostring(t), atof(t), STR|NUM, ap->sval);
671 			else
672 				setsymtab(num, tostring(t), 0.0, STR, ap->sval);
673 			*s = temp;
674 			if (*s++ == 0)
675 				break;
676 		}
677 	x = gettemp();
678 	x.optr->tval = NUM;
679 	x.optr->fval = n;
680 	return(x);
681 }
682 
683 obj ifstat(a,n) node **a;
684 {
685 	obj x;
686 
687 	x = execute(a[0]);
688 	if (istrue(x)) {
689 		tempfree(x);
690 		x = execute(a[1]);
691 	}
692 	else if (a[2] != nullstat) {
693 		tempfree(x);
694 		x = execute(a[2]);
695 	}
696 	return(x);
697 }
698 
699 obj whilestat(a,n) node **a;
700 {
701 	obj x;
702 
703 	for (;;) {
704 		x = execute(a[0]);
705 		if (!istrue(x)) return(x);
706 		tempfree(x);
707 		x = execute(a[1]);
708 		if (isbreak(x)) {
709 			x = true;
710 			return(x);
711 		}
712 		if (isnext(x) || isexit(x))
713 			return(x);
714 		tempfree(x);
715 	}
716 }
717 
718 obj forstat(a,n) node **a;
719 {
720 	obj x;
721 
722 	tempfree(execute(a[0]));
723 	for (;;) {
724 		if (a[1]!=nullstat) {
725 			x = execute(a[1]);
726 			if (!istrue(x)) return(x);
727 			else tempfree(x);
728 		}
729 		x = execute(a[3]);
730 		if (isbreak(x)) {	/* turn off break */
731 			x = true;
732 			return(x);
733 		}
734 		if (isnext(x) || isexit(x))
735 			return(x);
736 		tempfree(x);
737 		tempfree(execute(a[2]));
738 	}
739 }
740 
741 obj instat(a, n) node **a;
742 {
743 	cell *vp, *arrayp, *cp, **tp;
744 	obj x;
745 	int i;
746 
747 	vp = (cell *) a[0];
748 	arrayp = (cell *) a[1];
749 	if (!(arrayp->tval & ARR))
750 		error(FATAL, "%s is not an array", arrayp->nval);
751 	tp = (cell **) arrayp->sval;
752 	for (i = 0; i < MAXSYM; i++) {	/* this routine knows too much */
753 		for (cp = tp[i]; cp != NULL; cp = cp->nextval) {
754 			setsval(vp, cp->nval);
755 			x = execute(a[2]);
756 			if (isbreak(x)) {
757 				x = true;
758 				return(x);
759 			}
760 			if (isnext(x) || isexit(x))
761 				return(x);
762 			tempfree(x);
763 		}
764 	}
765 	return (true);
766 }
767 
768 obj jump(a,n) node **a;
769 {
770 	obj x, y;
771 
772 	x.otype = OJUMP;
773 	switch (n) {
774 	default:
775 		error(FATAL, "illegal jump type %d", n);
776 		break;
777 	case EXIT:
778 		if (a[0] != 0) {
779 			y = execute(a[0]);
780 			errorflag = getfval(y.optr);
781 		}
782 		x.osub = JEXIT;
783 		break;
784 	case NEXT:
785 		x.osub = JNEXT;
786 		break;
787 	case BREAK:
788 		x.osub = JBREAK;
789 		break;
790 	case CONTINUE:
791 		x.osub = JCONT;
792 		break;
793 	}
794 	return(x);
795 }
796 
797 obj fncn(a,n) node **a;
798 {
799 	obj x;
800 	awkfloat u;
801 	int t;
802 
803 	t = (int) a[0];
804 	x = execute(a[1]);
805 	if (t == FLENGTH)
806 		u = (awkfloat) strlen(getsval(x.optr));
807 	else if (t == FLOG)
808 		u = log(getfval(x.optr));
809 	else if (t == FINT)
810 		u = (awkfloat) (long) getfval(x.optr);
811 	else if (t == FEXP)
812 		u = exp(getfval(x.optr));
813 	else if (t == FSQRT)
814 		u = sqrt(getfval(x.optr));
815 	else
816 		error(FATAL, "illegal function type %d", t);
817 	tempfree(x);
818 	x = gettemp();
819 	setfval(x.optr, u);
820 	return(x);
821 }
822 
823 obj print(a,n) node **a;
824 {
825 	register node *x;
826 	obj y;
827 	char s[RECSIZE];
828 
829 	s[0] = '\0';
830 	for (x=a[0]; x!=NULL; x=x->nnext) {
831 		y = execute(x);
832 		strcat(s, getsval(y.optr));
833 		tempfree(y);
834 		if (x->nnext==NULL)
835 			strcat(s, *ORS);
836 		else
837 			strcat(s, *OFS);
838 	}
839 	if (strlen(s) >= RECSIZE)
840 		error(FATAL, "string %.20s ... too long to print", s);
841 	if (a[1]==nullstat) {
842 		printf("%s", s);
843 		return(true);
844 	}
845 	redirprint(s, (int)a[1], a[2]);
846 	return(false);
847 }
848 
849 obj nullproc() {}
850 
851 obj nodetoobj(a) node *a;
852 {
853 	obj x;
854 
855 	x.optr = (cell *) a->nobj;
856 	x.otype = OCELL;
857 	x.osub = a->subtype;
858 	if (isfld(x)) fldbld();
859 	return(x);
860 }
861 
862 redirprint(s, a, b) char *s; node *b;
863 {
864 	register int i;
865 	obj x;
866 
867 	x = execute(b);
868 	getsval(x.optr);
869 	for (i=0; i<FILENUM; i++)
870 		if (files[i].fp && strcmp(x.optr->sval, files[i].fname) == 0)
871 			goto doit;
872 	for (i=0; i<FILENUM; i++)
873 		if (files[i].fp == 0)
874 			break;
875 	if (i >= FILENUM)
876 		error(FATAL, "too many output files %d", i);
877 	if (a == '|')	/* a pipe! */
878 		files[i].fp = popen(x.optr->sval, "w");
879 	else if (a == APPEND)
880 		files[i].fp = fopen(x.optr->sval, "a");
881 	else
882 		files[i].fp = fopen(x.optr->sval, "w");
883 	if (files[i].fp == NULL)
884 		error(FATAL, "can't open file %s", x.optr->sval);
885 	if (fcntl(fileno(files[i].fp), F_SETFD, 1) < 0)
886 		error(FATAL, "close on exec failure");
887 	files[i].fname = tostring(x.optr->sval);
888 	files[i].type = a;
889 doit:
890 	fprintf(files[i].fp, "%s", s);
891 #ifndef gcos
892 	fflush(files[i].fp);	/* in case someone is waiting for the output */
893 #endif
894 	tempfree(x);
895 }
896