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