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