xref: /illumos-gate/usr/src/cmd/awk/run.c (revision d656abb5804319b33c85955a73ee450ef7ff9739)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 #define	tempfree(x, s)	if (istemp(x)) tfree(x, s)
31 
32 #define	execute(p) r_execute(p)
33 
34 #define	DEBUG
35 #include	"awk.h"
36 #include	<math.h>
37 #include	"y.tab.h"
38 #include	<stdio.h>
39 #include	<ctype.h>
40 #include	<setjmp.h>
41 #include	<time.h>
42 
43 #ifndef	FOPEN_MAX
44 #define	FOPEN_MAX	15	/* max number of open files, from ANSI std. */
45 #endif
46 
47 
48 static jmp_buf env;
49 
50 static	Cell	*r_execute(Node *);
51 static	Cell	*gettemp(char *), *copycell(Cell *);
52 static	FILE	*openfile(int, uchar *), *redirect(int, Node *);
53 
54 int	paircnt;
55 Node	*winner = NULL;
56 
57 static Cell	*tmps;
58 
59 static Cell	truecell	= { OBOOL, BTRUE, 0, 0, 1.0, NUM };
60 Cell	*true	= &truecell;
61 static Cell	falsecell	= { OBOOL, BFALSE, 0, 0, 0.0, NUM };
62 Cell	*false	= &falsecell;
63 static Cell	breakcell	= { OJUMP, JBREAK, 0, 0, 0.0, NUM };
64 Cell	*jbreak	= &breakcell;
65 static Cell	contcell	= { OJUMP, JCONT, 0, 0, 0.0, NUM };
66 Cell	*jcont	= &contcell;
67 static Cell	nextcell	= { OJUMP, JNEXT, 0, 0, 0.0, NUM };
68 Cell	*jnext	= &nextcell;
69 static Cell	exitcell	= { OJUMP, JEXIT, 0, 0, 0.0, NUM };
70 Cell	*jexit	= &exitcell;
71 static Cell	retcell		= { OJUMP, JRET, 0, 0, 0.0, NUM };
72 Cell	*jret	= &retcell;
73 static Cell	tempcell	= { OCELL, CTEMP, 0, 0, 0.0, NUM };
74 
75 Node	*curnode = NULL;	/* the node being executed, for debugging */
76 
77 static	void	tfree(Cell *, char *);
78 static	void	closeall(void);
79 static	double	ipow(double, int);
80 
81 void
82 run(Node *a)
83 {
84 	(void) execute(a);
85 	closeall();
86 }
87 
88 static Cell *
89 r_execute(Node *u)
90 {
91 	register Cell *(*proc)();
92 	register Cell *x;
93 	register Node *a;
94 
95 	if (u == NULL)
96 		return (true);
97 	for (a = u; ; a = a->nnext) {
98 		curnode = a;
99 		if (isvalue(a)) {
100 			x = (Cell *) (a->narg[0]);
101 			if ((x->tval & FLD) && !donefld)
102 				fldbld();
103 			else if ((x->tval & REC) && !donerec)
104 				recbld();
105 			return (x);
106 		}
107 		/* probably a Cell* but too risky to print */
108 		if (notlegal(a->nobj))
109 			ERROR "illegal statement" FATAL;
110 		proc = proctab[a->nobj-FIRSTTOKEN];
111 		x = (*proc)(a->narg, a->nobj);
112 		if ((x->tval & FLD) && !donefld)
113 			fldbld();
114 		else if ((x->tval & REC) && !donerec)
115 			recbld();
116 		if (isexpr(a))
117 			return (x);
118 		/* a statement, goto next statement */
119 		if (isjump(x))
120 			return (x);
121 		if (a->nnext == (Node *)NULL)
122 			return (x);
123 		tempfree(x, "execute");
124 	}
125 }
126 
127 /*ARGSUSED*/
128 Cell *
129 program(Node **a, int n)
130 {
131 	register Cell *x;
132 
133 	if (setjmp(env) != 0)
134 		goto ex;
135 	if (a[0]) {		/* BEGIN */
136 		x = execute(a[0]);
137 		if (isexit(x))
138 			return (true);
139 		if (isjump(x)) {
140 			ERROR "illegal break, continue or next from BEGIN"
141 			    FATAL;
142 		}
143 		tempfree(x, "");
144 	}
145 loop:
146 	if (a[1] || a[2])
147 		while (getrec(&record, &record_size) > 0) {
148 			x = execute(a[1]);
149 			if (isexit(x))
150 				break;
151 			tempfree(x, "");
152 		}
153 ex:
154 	if (setjmp(env) != 0)
155 		goto ex1;
156 	if (a[2]) {		/* END */
157 		x = execute(a[2]);
158 		if (iscont(x))	/* read some more */
159 			goto loop;
160 		if (isbreak(x) || isnext(x))
161 			ERROR "illegal break or next from END" FATAL;
162 		tempfree(x, "");
163 	}
164 ex1:
165 	return (true);
166 }
167 
168 struct Frame {
169 	int nargs;	/* number of arguments in this call */
170 	Cell *fcncell;	/* pointer to Cell for function */
171 	Cell **args;	/* pointer to array of arguments after execute */
172 	Cell *retval;	/* return value */
173 };
174 
175 #define	NARGS	30
176 
177 struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
178 int	nframe = 0;		/* number of frames allocated */
179 struct Frame *fp = NULL;	/* frame pointer. bottom level unused */
180 
181 /*ARGSUSED*/
182 Cell *
183 call(Node **a, int n)
184 {
185 	static Cell newcopycell =
186 		{ OCELL, CCOPY, 0, (uchar *) "", 0.0, NUM|STR|DONTFREE };
187 	int i, ncall, ndef, freed = 0;
188 	Node *x;
189 	Cell *args[NARGS], *oargs[NARGS], *y, *z, *fcn;
190 	uchar *s;
191 
192 	fcn = execute(a[0]);	/* the function itself */
193 	s = fcn->nval;
194 	if (!isfunc(fcn))
195 		ERROR "calling undefined function %s", s FATAL;
196 	if (frame == NULL) {
197 		fp = frame = (struct Frame *)calloc(nframe += 100,
198 		    sizeof (struct Frame));
199 		if (frame == NULL) {
200 			ERROR "out of space for stack frames calling %s",
201 			    s FATAL;
202 		}
203 	}
204 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
205 		ncall++;
206 	ndef = (int)fcn->fval;			/* args in defn */
207 	dprintf(("calling %s, %d args (%d in defn), fp=%d\n",
208 	    s, ncall, ndef, fp-frame));
209 	if (ncall > ndef) {
210 		ERROR "function %s called with %d args, uses only %d",
211 		    s, ncall, ndef WARNING;
212 	}
213 	if (ncall + ndef > NARGS) {
214 		ERROR "function %s has %d arguments, limit %d",
215 		    s, ncall+ndef, NARGS FATAL;
216 	}
217 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {
218 		/* get call args */
219 		dprintf(("evaluate args[%d], fp=%d:\n", i, fp-frame));
220 		y = execute(x);
221 		oargs[i] = y;
222 		dprintf(("args[%d]: %s %f <%s>, t=%o\n",
223 		    i, y->nval, y->fval,
224 		    isarr(y) ? "(array)" : (char *)y->sval, y->tval));
225 		if (isfunc(y)) {
226 			ERROR "can't use function %s as argument in %s",
227 			    y->nval, s FATAL;
228 		}
229 		if (isarr(y))
230 			args[i] = y;	/* arrays by ref */
231 		else
232 			args[i] = copycell(y);
233 		tempfree(y, "callargs");
234 	}
235 	for (; i < ndef; i++) { /* add null args for ones not provided */
236 		args[i] = gettemp("nullargs");
237 		*args[i] = newcopycell;
238 	}
239 	fp++;	/* now ok to up frame */
240 	if (fp >= frame + nframe) {
241 		int dfp = fp - frame;	/* old index */
242 		frame = (struct Frame *)
243 		    realloc(frame, (nframe += 100) * sizeof (struct Frame));
244 		if (frame == NULL)
245 			ERROR "out of space for stack frames in %s", s FATAL;
246 		fp = frame + dfp;
247 	}
248 	fp->fcncell = fcn;
249 	fp->args = args;
250 	fp->nargs = ndef;	/* number defined with (excess are locals) */
251 	fp->retval = gettemp("retval");
252 
253 	dprintf(("start exec of %s, fp=%d\n", s, fp-frame));
254 	/*LINTED align*/
255 	y = execute((Node *)(fcn->sval));	/* execute body */
256 	dprintf(("finished exec of %s, fp=%d\n", s, fp-frame));
257 
258 	for (i = 0; i < ndef; i++) {
259 		Cell *t = fp->args[i];
260 		if (isarr(t)) {
261 			if (t->csub == CCOPY) {
262 				if (i >= ncall) {
263 					freesymtab(t);
264 					t->csub = CTEMP;
265 				} else {
266 					oargs[i]->tval = t->tval;
267 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
268 					oargs[i]->sval = t->sval;
269 					tempfree(t, "oargsarr");
270 				}
271 			}
272 		} else {
273 			t->csub = CTEMP;
274 			tempfree(t, "fp->args");
275 			if (t == y) freed = 1;
276 		}
277 	}
278 	tempfree(fcn, "call.fcn");
279 	if (isexit(y) || isnext(y))
280 		return (y);
281 	if (!freed)
282 		tempfree(y, "fcn ret"); /* this can free twice! */
283 	z = fp->retval;			/* return value */
284 	dprintf(("%s returns %g |%s| %o\n",
285 	    s, getfval(z), getsval(z), z->tval));
286 	fp--;
287 	return (z);
288 }
289 
290 static Cell *
291 copycell(Cell *x)	/* make a copy of a cell in a temp */
292 {
293 	Cell *y;
294 
295 	y = gettemp("copycell");
296 	y->csub = CCOPY;	/* prevents freeing until call is over */
297 	y->nval = x->nval;
298 	y->sval = x->sval ? tostring(x->sval) : NULL;
299 	y->fval = x->fval;
300 	/* copy is not constant or field is DONTFREE right? */
301 	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);
302 	return (y);
303 }
304 
305 /*ARGSUSED*/
306 Cell *
307 arg(Node **a, int nnn)
308 {
309 	int n;
310 
311 	n = (int)a[0];	/* argument number, counting from 0 */
312 	dprintf(("arg(%d), fp->nargs=%d\n", n, fp->nargs));
313 	if (n+1 > fp->nargs) {
314 		ERROR "argument #%d of function %s was not supplied",
315 		    n+1, fp->fcncell->nval FATAL;
316 	}
317 	return (fp->args[n]);
318 }
319 
320 Cell *
321 jump(Node **a, int n)
322 {
323 	register Cell *y;
324 
325 	switch (n) {
326 	case EXIT:
327 		if (a[0] != NULL) {
328 			y = execute(a[0]);
329 			errorflag = (int)getfval(y);
330 			tempfree(y, "");
331 		}
332 		longjmp(env, 1);
333 		/*NOTREACHED*/
334 	case RETURN:
335 		if (a[0] != NULL) {
336 			y = execute(a[0]);
337 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
338 				(void) setsval(fp->retval, getsval(y));
339 				fp->retval->fval = getfval(y);
340 				fp->retval->tval |= NUM;
341 			} else if (y->tval & STR)
342 				(void) setsval(fp->retval, getsval(y));
343 			else if (y->tval & NUM)
344 				(void) setfval(fp->retval, getfval(y));
345 			tempfree(y, "");
346 		}
347 		return (jret);
348 	case NEXT:
349 		return (jnext);
350 	case BREAK:
351 		return (jbreak);
352 	case CONTINUE:
353 		return (jcont);
354 	default:	/* can't happen */
355 		ERROR "illegal jump type %d", n FATAL;
356 	}
357 	/*NOTREACHED*/
358 	return (NULL);
359 }
360 
361 Cell *
362 getline(Node **a, int n)
363 {
364 	/* a[0] is variable, a[1] is operator, a[2] is filename */
365 	register Cell *r, *x;
366 	uchar *buf;
367 	FILE *fp;
368 	size_t len;
369 
370 	(void) fflush(stdout);	/* in case someone is waiting for a prompt */
371 	r = gettemp("");
372 	if (a[1] != NULL) {		/* getline < file */
373 		x = execute(a[2]);		/* filename */
374 		if ((int)a[1] == '|')	/* input pipe */
375 			a[1] = (Node *)LE;	/* arbitrary flag */
376 		fp = openfile((int)a[1], getsval(x));
377 		tempfree(x, "");
378 		buf = NULL;
379 		if (fp == NULL)
380 			n = -1;
381 		else
382 			n = readrec(&buf, &len, fp);
383 		if (n > 0) {
384 			if (a[0] != NULL) {	/* getline var <file */
385 				(void) setsval(execute(a[0]), buf);
386 			} else {			/* getline <file */
387 				if (!(recloc->tval & DONTFREE))
388 					xfree(recloc->sval);
389 				expand_buf(&record, &record_size, len);
390 				(void) memcpy(record, buf, len);
391 				record[len] = '\0';
392 				recloc->sval = record;
393 				recloc->tval = REC | STR | DONTFREE;
394 				donerec = 1; donefld = 0;
395 			}
396 		}
397 		if (buf != NULL)
398 			free(buf);
399 	} else {			/* bare getline; use current input */
400 		if (a[0] == NULL)	/* getline */
401 			n = getrec(&record, &record_size);
402 		else {			/* getline var */
403 			init_buf(&buf, &len, LINE_INCR);
404 			n = getrec(&buf, &len);
405 			(void) setsval(execute(a[0]), buf);
406 			free(buf);
407 		}
408 	}
409 	(void) setfval(r, (Awkfloat)n);
410 	return (r);
411 }
412 
413 /*ARGSUSED*/
414 Cell *
415 getnf(Node **a, int n)
416 {
417 	if (donefld == 0)
418 		fldbld();
419 	return ((Cell *)a[0]);
420 }
421 
422 /*ARGSUSED*/
423 Cell *
424 array(Node **a, int n)
425 {
426 	register Cell *x, *y, *z;
427 	register uchar *s;
428 	register Node *np;
429 	uchar	*buf;
430 	size_t	bsize, tlen, len, slen;
431 
432 	x = execute(a[0]);	/* Cell* for symbol table */
433 	init_buf(&buf, &bsize, LINE_INCR);
434 	buf[0] = '\0';
435 	tlen = 0;
436 	slen = strlen((char *)*SUBSEP);
437 	for (np = a[1]; np; np = np->nnext) {
438 		y = execute(np);	/* subscript */
439 		s = getsval(y);
440 		len = strlen((char *)s);
441 		expand_buf(&buf, &bsize, tlen + len + slen);
442 		(void) memcpy(&buf[tlen], s, len);
443 		tlen += len;
444 		if (np->nnext) {
445 			(void) memcpy(&buf[tlen], *SUBSEP, slen);
446 			tlen += slen;
447 		}
448 		buf[tlen] = '\0';
449 		tempfree(y, "");
450 	}
451 	if (!isarr(x)) {
452 		dprintf(("making %s into an array\n", x->nval));
453 		if (freeable(x))
454 			xfree(x->sval);
455 		x->tval &= ~(STR|NUM|DONTFREE);
456 		x->tval |= ARR;
457 		x->sval = (uchar *) makesymtab(NSYMTAB);
458 	}
459 	/*LINTED align*/
460 	z = setsymtab(buf, (uchar *)"", 0.0, STR|NUM, (Array *)x->sval);
461 	z->ctype = OCELL;
462 	z->csub = CVAR;
463 	tempfree(x, "");
464 	free(buf);
465 	return (z);
466 }
467 
468 /*ARGSUSED*/
469 Cell *
470 delete(Node **a, int n)
471 {
472 	Cell *x, *y;
473 	Node *np;
474 	uchar *buf, *s;
475 	size_t bsize, tlen, slen, len;
476 
477 	x = execute(a[0]);	/* Cell* for symbol table */
478 	if (!isarr(x))
479 		return (true);
480 	init_buf(&buf, &bsize, LINE_INCR);
481 	buf[0] = '\0';
482 	tlen = 0;
483 	slen = strlen((char *)*SUBSEP);
484 	for (np = a[1]; np; np = np->nnext) {
485 		y = execute(np);	/* subscript */
486 		s = getsval(y);
487 		len = strlen((char *)s);
488 		expand_buf(&buf, &bsize, tlen + len + slen);
489 		(void) memcpy(&buf[tlen], s, len);
490 		tlen += len;
491 		if (np->nnext) {
492 			(void) memcpy(&buf[tlen], *SUBSEP, slen);
493 			tlen += slen;
494 		}
495 		buf[tlen] = '\0';
496 		tempfree(y, "");
497 	}
498 	freeelem(x, buf);
499 	tempfree(x, "");
500 	free(buf);
501 	return (true);
502 }
503 
504 /*ARGSUSED*/
505 Cell *
506 intest(Node **a, int n)
507 {
508 	register Cell *x, *ap, *k;
509 	Node *p;
510 	uchar *buf;
511 	uchar *s;
512 	size_t bsize, tlen, slen, len;
513 
514 	ap = execute(a[1]);	/* array name */
515 	if (!isarr(ap))
516 		ERROR "%s is not an array", ap->nval FATAL;
517 	init_buf(&buf, &bsize, LINE_INCR);
518 	buf[0] = 0;
519 	tlen = 0;
520 	slen = strlen((char *)*SUBSEP);
521 	for (p = a[0]; p; p = p->nnext) {
522 		x = execute(p);	/* expr */
523 		s = getsval(x);
524 		len = strlen((char *)s);
525 		expand_buf(&buf, &bsize, tlen + len + slen);
526 		(void) memcpy(&buf[tlen], s, len);
527 		tlen += len;
528 		tempfree(x, "");
529 		if (p->nnext) {
530 			(void) memcpy(&buf[tlen], *SUBSEP, slen);
531 			tlen += slen;
532 		}
533 		buf[tlen] = '\0';
534 	}
535 	/*LINTED align*/
536 	k = lookup(buf, (Array *)ap->sval);
537 	tempfree(ap, "");
538 	free(buf);
539 	if (k == NULL)
540 		return (false);
541 	else
542 		return (true);
543 }
544 
545 
546 Cell *
547 matchop(Node **a, int n)
548 {
549 	register Cell *x, *y;
550 	register uchar *s, *t;
551 	register int i;
552 	fa *pfa;
553 	int (*mf)() = match, mode = 0;
554 
555 	if (n == MATCHFCN) {
556 		mf = pmatch;
557 		mode = 1;
558 	}
559 	x = execute(a[1]);
560 	s = getsval(x);
561 	if (a[0] == 0)
562 		i = (*mf)(a[2], s);
563 	else {
564 		y = execute(a[2]);
565 		t = getsval(y);
566 		pfa = makedfa(t, mode);
567 		i = (*mf)(pfa, s);
568 		tempfree(y, "");
569 	}
570 	tempfree(x, "");
571 	if (n == MATCHFCN) {
572 		int start = patbeg - s + 1;
573 		if (patlen < 0)
574 			start = 0;
575 		(void) setfval(rstartloc, (Awkfloat)start);
576 		(void) setfval(rlengthloc, (Awkfloat)patlen);
577 		x = gettemp("");
578 		x->tval = NUM;
579 		x->fval = start;
580 		return (x);
581 	} else if (n == MATCH && i == 1 || n == NOTMATCH && i == 0)
582 		return (true);
583 	else
584 		return (false);
585 }
586 
587 
588 Cell *
589 boolop(Node **a, int n)
590 {
591 	register Cell *x, *y;
592 	register int i;
593 
594 	x = execute(a[0]);
595 	i = istrue(x);
596 	tempfree(x, "");
597 	switch (n) {
598 	case BOR:
599 		if (i)
600 			return (true);
601 		y = execute(a[1]);
602 		i = istrue(y);
603 		tempfree(y, "");
604 		return (i ? true : false);
605 	case AND:
606 		if (!i)
607 			return (false);
608 		y = execute(a[1]);
609 		i = istrue(y);
610 		tempfree(y, "");
611 		return (i ? true : false);
612 	case NOT:
613 		return (i ? false : true);
614 	default:	/* can't happen */
615 		ERROR "unknown boolean operator %d", n FATAL;
616 	}
617 	/*NOTREACHED*/
618 	return (NULL);
619 }
620 
621 Cell *
622 relop(Node **a, int n)
623 {
624 	register int i;
625 	register Cell *x, *y;
626 	Awkfloat j;
627 
628 	x = execute(a[0]);
629 	y = execute(a[1]);
630 	if (x->tval&NUM && y->tval&NUM) {
631 		j = x->fval - y->fval;
632 		i = j < 0 ? -1: (j > 0 ? 1: 0);
633 	} else {
634 		i = strcmp((char *)getsval(x), (char *)getsval(y));
635 	}
636 	tempfree(x, "");
637 	tempfree(y, "");
638 	switch (n) {
639 	case LT:	return (i < 0 ? true : false);
640 	case LE:	return (i <= 0 ? true : false);
641 	case NE:	return (i != 0 ? true : false);
642 	case EQ:	return (i == 0 ? true : false);
643 	case GE:	return (i >= 0 ? true : false);
644 	case GT:	return (i > 0 ? true : false);
645 	default:	/* can't happen */
646 		ERROR "unknown relational operator %d", n FATAL;
647 	}
648 	/*NOTREACHED*/
649 	return (false);
650 }
651 
652 static void
653 tfree(Cell *a, char *s)
654 {
655 	if (dbg > 1) {
656 		(void) printf("## tfree %.8s %06lo %s\n",
657 		    s, (ulong_t)a, a->sval ? a->sval : (uchar *)"");
658 	}
659 	if (freeable(a))
660 		xfree(a->sval);
661 	if (a == tmps)
662 		ERROR "tempcell list is curdled" FATAL;
663 	a->cnext = tmps;
664 	tmps = a;
665 }
666 
667 static Cell *
668 gettemp(char *s)
669 {
670 	int i;
671 	register Cell *x;
672 
673 	if (!tmps) {
674 		tmps = (Cell *)calloc(100, sizeof (Cell));
675 		if (!tmps)
676 			ERROR "no space for temporaries" FATAL;
677 		for (i = 1; i < 100; i++)
678 			tmps[i-1].cnext = &tmps[i];
679 		tmps[i-1].cnext = 0;
680 	}
681 	x = tmps;
682 	tmps = x->cnext;
683 	*x = tempcell;
684 	if (dbg > 1)
685 		(void) printf("## gtemp %.8s %06lo\n", s, (ulong_t)x);
686 	return (x);
687 }
688 
689 /*ARGSUSED*/
690 Cell *
691 indirect(Node **a, int n)
692 {
693 	register Cell *x;
694 	register int m;
695 	register uchar *s;
696 
697 	x = execute(a[0]);
698 	m = (int)getfval(x);
699 	if (m == 0 && !is_number(s = getsval(x)))	/* suspicion! */
700 		ERROR "illegal field $(%s)", s FATAL;
701 	tempfree(x, "");
702 	x = fieldadr(m);
703 	x->ctype = OCELL;
704 	x->csub = CFLD;
705 	return (x);
706 }
707 
708 /*ARGSUSED*/
709 Cell *
710 substr(Node **a, int nnn)
711 {
712 	register int k, m, n;
713 	register uchar *s;
714 	int temp;
715 	register Cell *x, *y, *z;
716 
717 	x = execute(a[0]);
718 	y = execute(a[1]);
719 	if (a[2] != 0)
720 		z = execute(a[2]);
721 	s = getsval(x);
722 	k = strlen((char *)s) + 1;
723 	if (k <= 1) {
724 		tempfree(x, "");
725 		tempfree(y, "");
726 		if (a[2] != 0)
727 			tempfree(z, "");
728 		x = gettemp("");
729 		(void) setsval(x, (uchar *)"");
730 		return (x);
731 	}
732 	m = (int)getfval(y);
733 	if (m <= 0)
734 		m = 1;
735 	else if (m > k)
736 		m = k;
737 	tempfree(y, "");
738 	if (a[2] != 0) {
739 		n = (int)getfval(z);
740 		tempfree(z, "");
741 	} else
742 		n = k - 1;
743 	if (n < 0)
744 		n = 0;
745 	else if (n > k - m)
746 		n = k - m;
747 	dprintf(("substr: m=%d, n=%d, s=%s\n", m, n, s));
748 	y = gettemp("");
749 	temp = s[n + m - 1];	/* with thanks to John Linderman */
750 	s[n + m - 1] = '\0';
751 	(void) setsval(y, s + m - 1);
752 	s[n + m - 1] = temp;
753 	tempfree(x, "");
754 	return (y);
755 }
756 
757 /*ARGSUSED*/
758 Cell *
759 sindex(Node **a, int nnn)
760 {
761 	register Cell *x, *y, *z;
762 	register uchar *s1, *s2, *p1, *p2, *q;
763 	Awkfloat v = 0.0;
764 
765 	x = execute(a[0]);
766 	s1 = getsval(x);
767 	y = execute(a[1]);
768 	s2 = getsval(y);
769 
770 	z = gettemp("");
771 	for (p1 = s1; *p1 != '\0'; p1++) {
772 		for (q = p1, p2 = s2; *p2 != '\0' && *q == *p2; q++, p2++)
773 			;
774 		if (*p2 == '\0') {
775 			v = (Awkfloat) (p1 - s1 + 1);	/* origin 1 */
776 			break;
777 		}
778 	}
779 	tempfree(x, "");
780 	tempfree(y, "");
781 	(void) setfval(z, v);
782 	return (z);
783 }
784 
785 void
786 format(uchar **bufp, uchar *s, Node *a)
787 {
788 	uchar *fmt;
789 	register uchar *os;
790 	register Cell *x;
791 	int flag = 0, len;
792 	uchar_t	*buf;
793 	size_t bufsize, fmtsize, cnt, tcnt, ret;
794 
795 	init_buf(&buf, &bufsize, LINE_INCR);
796 	init_buf(&fmt, &fmtsize, LINE_INCR);
797 	os = s;
798 	cnt = 0;
799 	while (*s) {
800 		if (*s != '%') {
801 			expand_buf(&buf, &bufsize, cnt);
802 			buf[cnt++] = *s++;
803 			continue;
804 		}
805 		if (*(s+1) == '%') {
806 			expand_buf(&buf, &bufsize, cnt);
807 			buf[cnt++] = '%';
808 			s += 2;
809 			continue;
810 		}
811 		for (tcnt = 0; ; s++) {
812 			expand_buf(&fmt, &fmtsize, tcnt);
813 			fmt[tcnt++] = *s;
814 			if (*s == '\0')
815 				break;
816 			if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
817 				break;	/* the ansi panoply */
818 			if (*s == '*') {
819 				if (a == NULL) {
820 					ERROR
821 		"not enough args in printf(%s) or sprintf(%s)", os, os FATAL;
822 				}
823 				x = execute(a);
824 				a = a->nnext;
825 				tcnt--;
826 				expand_buf(&fmt, &fmtsize, tcnt + 12);
827 				ret = sprintf((char *)&fmt[tcnt], "%d",
828 				    (int)getfval(x));
829 				tcnt += ret;
830 				tempfree(x, "");
831 			}
832 		}
833 		fmt[tcnt] = '\0';
834 
835 		switch (*s) {
836 		case 'f': case 'e': case 'g': case 'E': case 'G':
837 			flag = 1;
838 			break;
839 		case 'd': case 'i':
840 			flag = 2;
841 			if (*(s-1) == 'l')
842 				break;
843 			fmt[tcnt - 1] = 'l';
844 			expand_buf(&fmt, &fmtsize, tcnt);
845 			fmt[tcnt++] = 'd';
846 			fmt[tcnt] = '\0';
847 			break;
848 		case 'o': case 'x': case 'X': case 'u':
849 			flag = *(s-1) == 'l' ? 2 : 3;
850 			break;
851 		case 's':
852 			flag = 4;
853 			break;
854 		case 'c':
855 			flag = 5;
856 			break;
857 		default:
858 			flag = 0;
859 			break;
860 		}
861 		if (flag == 0) {
862 			len = strlen((char *)fmt);
863 			expand_buf(&buf, &bufsize, cnt + len);
864 			(void) memcpy(&buf[cnt], fmt, len);
865 			cnt += len;
866 			buf[cnt] = '\0';
867 			continue;
868 		}
869 		if (a == NULL) {
870 			ERROR
871 	"not enough args in printf(%s) or sprintf(%s)", os, os FATAL;
872 		}
873 		x = execute(a);
874 		a = a->nnext;
875 		for (;;) {
876 			/* make sure we have at least 1 byte space */
877 			expand_buf(&buf, &bufsize, cnt + 1);
878 			len = bufsize - cnt;
879 			switch (flag) {
880 			case 1:
881 				/*LINTED*/
882 				ret = snprintf((char *)&buf[cnt], len,
883 				    (char *)fmt, getfval(x));
884 				break;
885 			case 2:
886 				/*LINTED*/
887 				ret = snprintf((char *)&buf[cnt], len,
888 				    (char *)fmt, (long)getfval(x));
889 				break;
890 			case 3:
891 				/*LINTED*/
892 				ret = snprintf((char *)&buf[cnt], len,
893 				    (char *)fmt, (int)getfval(x));
894 				break;
895 			case 4:
896 				/*LINTED*/
897 				ret = snprintf((char *)&buf[cnt], len,
898 				    (char *)fmt, getsval(x));
899 				break;
900 			case 5:
901 				if (isnum(x)) {
902 					/*LINTED*/
903 					ret = snprintf((char *)&buf[cnt], len,
904 					    (char *)fmt, (int)getfval(x));
905 				} else {
906 					/*LINTED*/
907 					ret = snprintf((char *)&buf[cnt], len,
908 					    (char *)fmt, getsval(x)[0]);
909 				}
910 				break;
911 			default:
912 				ret = 0;
913 			}
914 			if (ret < len)
915 				break;
916 			expand_buf(&buf, &bufsize, cnt + ret);
917 		}
918 		tempfree(x, "");
919 		cnt += ret;
920 		s++;
921 	}
922 	buf[cnt] = '\0';
923 	for (; a; a = a->nnext)	/* evaluate any remaining args */
924 		(void) execute(a);
925 	*bufp = tostring(buf);
926 	free(buf);
927 	free(fmt);
928 }
929 
930 /*ARGSUSED*/
931 Cell *
932 a_sprintf(Node **a, int n)
933 {
934 	register Cell *x;
935 	register Node *y;
936 	uchar *buf;
937 
938 	y = a[0]->nnext;
939 	x = execute(a[0]);
940 	format(&buf, getsval(x), y);
941 	tempfree(x, "");
942 	x = gettemp("");
943 	x->sval = buf;
944 	x->tval = STR;
945 	return (x);
946 }
947 
948 /*ARGSUSED*/
949 Cell *
950 aprintf(Node **a, int n)
951 {
952 	FILE *fp;
953 	register Cell *x;
954 	register Node *y;
955 	uchar *buf;
956 
957 	y = a[0]->nnext;
958 	x = execute(a[0]);
959 	format(&buf, getsval(x), y);
960 	tempfree(x, "");
961 	if (a[1] == NULL)
962 		(void) fputs((char *)buf, stdout);
963 	else {
964 		fp = redirect((int)a[1], a[2]);
965 		(void) fputs((char *)buf, fp);
966 		(void) fflush(fp);
967 	}
968 	free(buf);
969 	return (true);
970 }
971 
972 Cell *
973 arith(Node **a, int n)
974 {
975 	Awkfloat i, j;
976 	double v;
977 	register Cell *x, *y, *z;
978 
979 	x = execute(a[0]);
980 	i = getfval(x);
981 	tempfree(x, "");
982 	if (n != UMINUS) {
983 		y = execute(a[1]);
984 		j = getfval(y);
985 		tempfree(y, "");
986 	}
987 	z = gettemp("");
988 	switch (n) {
989 	case ADD:
990 		i += j;
991 		break;
992 	case MINUS:
993 		i -= j;
994 		break;
995 	case MULT:
996 		i *= j;
997 		break;
998 	case DIVIDE:
999 		if (j == 0)
1000 			ERROR "division by zero" FATAL;
1001 		i /= j;
1002 		break;
1003 	case MOD:
1004 		if (j == 0)
1005 			ERROR "division by zero in mod" FATAL;
1006 		(void) modf(i/j, &v);
1007 		i = i - j * v;
1008 		break;
1009 	case UMINUS:
1010 		i = -i;
1011 		break;
1012 	case POWER:
1013 		if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1014 			i = ipow(i, (int)j);
1015 		else
1016 			i = errcheck(pow(i, j), "pow");
1017 		break;
1018 	default:	/* can't happen */
1019 		ERROR "illegal arithmetic operator %d", n FATAL;
1020 	}
1021 	(void) setfval(z, i);
1022 	return (z);
1023 }
1024 
1025 static double
1026 ipow(double x, int n)
1027 {
1028 	double v;
1029 
1030 	if (n <= 0)
1031 		return (1.0);
1032 	v = ipow(x, n/2);
1033 	if (n % 2 == 0)
1034 		return (v * v);
1035 	else
1036 		return (x * v * v);
1037 }
1038 
1039 Cell *
1040 incrdecr(Node **a, int n)
1041 {
1042 	register Cell *x, *z;
1043 	register int k;
1044 	Awkfloat xf;
1045 
1046 	x = execute(a[0]);
1047 	xf = getfval(x);
1048 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1049 	if (n == PREINCR || n == PREDECR) {
1050 		(void) setfval(x, xf + k);
1051 		return (x);
1052 	}
1053 	z = gettemp("");
1054 	(void) setfval(z, xf);
1055 	(void) setfval(x, xf + k);
1056 	tempfree(x, "");
1057 	return (z);
1058 }
1059 
1060 Cell *
1061 assign(Node **a, int n)
1062 {
1063 	register Cell *x, *y;
1064 	Awkfloat xf, yf;
1065 	double v;
1066 
1067 	y = execute(a[1]);
1068 	x = execute(a[0]);	/* order reversed from before... */
1069 	if (n == ASSIGN) {	/* ordinary assignment */
1070 		if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1071 			(void) setsval(x, getsval(y));
1072 			x->fval = getfval(y);
1073 			x->tval |= NUM;
1074 		} else if (y->tval & STR)
1075 			(void) setsval(x, getsval(y));
1076 		else if (y->tval & NUM)
1077 			(void) setfval(x, getfval(y));
1078 		else
1079 			funnyvar(y, "read value of");
1080 		tempfree(y, "");
1081 		return (x);
1082 	}
1083 	xf = getfval(x);
1084 	yf = getfval(y);
1085 	switch (n) {
1086 	case ADDEQ:
1087 		xf += yf;
1088 		break;
1089 	case SUBEQ:
1090 		xf -= yf;
1091 		break;
1092 	case MULTEQ:
1093 		xf *= yf;
1094 		break;
1095 	case DIVEQ:
1096 		if (yf == 0)
1097 			ERROR "division by zero in /=" FATAL;
1098 		xf /= yf;
1099 		break;
1100 	case MODEQ:
1101 		if (yf == 0)
1102 			ERROR "division by zero in %%=" FATAL;
1103 		(void) modf(xf/yf, &v);
1104 		xf = xf - yf * v;
1105 		break;
1106 	case POWEQ:
1107 		if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1108 			xf = ipow(xf, (int)yf);
1109 		else
1110 			xf = errcheck(pow(xf, yf), "pow");
1111 		break;
1112 	default:
1113 		ERROR "illegal assignment operator %d", n FATAL;
1114 		break;
1115 	}
1116 	tempfree(y, "");
1117 	(void) setfval(x, xf);
1118 	return (x);
1119 }
1120 
1121 /*ARGSUSED*/
1122 Cell *
1123 cat(Node **a, int q)
1124 {
1125 	register Cell *x, *y, *z;
1126 	register int n1, n2;
1127 	register uchar *s;
1128 
1129 	x = execute(a[0]);
1130 	y = execute(a[1]);
1131 	(void) getsval(x);
1132 	(void) getsval(y);
1133 	n1 = strlen((char *)x->sval);
1134 	n2 = strlen((char *)y->sval);
1135 	s = (uchar *)malloc(n1 + n2 + 1);
1136 	if (s == NULL) {
1137 		ERROR "out of space concatenating %.15s and %.15s",
1138 		    x->sval, y->sval FATAL;
1139 	}
1140 	(void) strcpy((char *)s, (char *)x->sval);
1141 	(void) strcpy((char *)s + n1, (char *)y->sval);
1142 	tempfree(y, "");
1143 	z = gettemp("");
1144 	z->sval = s;
1145 	z->tval = STR;
1146 	tempfree(x, "");
1147 	return (z);
1148 }
1149 
1150 /*ARGSUSED*/
1151 Cell *
1152 pastat(Node **a, int n)
1153 {
1154 	register Cell *x;
1155 
1156 	if (a[0] == 0)
1157 		x = execute(a[1]);
1158 	else {
1159 		x = execute(a[0]);
1160 		if (istrue(x)) {
1161 			tempfree(x, "");
1162 			x = execute(a[1]);
1163 		}
1164 	}
1165 	return (x);
1166 }
1167 
1168 /*ARGSUSED*/
1169 Cell *
1170 dopa2(Node **a, int n)
1171 {
1172 	Cell	*x;
1173 	int	pair;
1174 	static int	*pairstack = NULL;
1175 
1176 	if (!pairstack) {
1177 		/* first time */
1178 		dprintf(("paircnt: %d\n", paircnt));
1179 		pairstack = (int *)malloc(sizeof (int) * paircnt);
1180 		if (!pairstack)
1181 			ERROR "out of space in dopa2" FATAL;
1182 		(void) memset(pairstack, 0, sizeof (int) * paircnt);
1183 	}
1184 
1185 	pair = (int)a[3];
1186 	if (pairstack[pair] == 0) {
1187 		x = execute(a[0]);
1188 		if (istrue(x))
1189 			pairstack[pair] = 1;
1190 		tempfree(x, "");
1191 	}
1192 	if (pairstack[pair] == 1) {
1193 		x = execute(a[1]);
1194 		if (istrue(x))
1195 			pairstack[pair] = 0;
1196 		tempfree(x, "");
1197 		x = execute(a[2]);
1198 		return (x);
1199 	}
1200 	return (false);
1201 }
1202 
1203 /*ARGSUSED*/
1204 Cell *
1205 split(Node **a, int nnn)
1206 {
1207 	Cell *x, *y, *ap;
1208 	register uchar *s;
1209 	register int sep;
1210 	uchar *t, temp, num[11], *fs;
1211 	int n, tempstat;
1212 
1213 	y = execute(a[0]);	/* source string */
1214 	s = getsval(y);
1215 	if (a[2] == 0)		/* fs string */
1216 		fs = *FS;
1217 	else if ((int)a[3] == STRING) {	/* split(str,arr,"string") */
1218 		x = execute(a[2]);
1219 		fs = getsval(x);
1220 	} else if ((int)a[3] == REGEXPR)
1221 		fs = (uchar *)"(regexpr)";	/* split(str,arr,/regexpr/) */
1222 	else
1223 		ERROR "illegal type of split()" FATAL;
1224 	sep = *fs;
1225 	ap = execute(a[1]);	/* array name */
1226 	freesymtab(ap);
1227 	dprintf(("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs));
1228 	ap->tval &= ~STR;
1229 	ap->tval |= ARR;
1230 	ap->sval = (uchar *)makesymtab(NSYMTAB);
1231 
1232 	n = 0;
1233 	if (*s != '\0' && strlen((char *)fs) > 1 || (int)a[3] == REGEXPR) {
1234 		/* reg expr */
1235 		fa *pfa;
1236 		if ((int)a[3] == REGEXPR) {	/* it's ready already */
1237 			pfa = (fa *)a[2];
1238 		} else {
1239 			pfa = makedfa(fs, 1);
1240 		}
1241 		if (nematch(pfa, s)) {
1242 			tempstat = pfa->initstat;
1243 			pfa->initstat = 2;
1244 			do {
1245 				n++;
1246 				(void) sprintf((char *)num, "%d", n);
1247 				temp = *patbeg;
1248 				*patbeg = '\0';
1249 				if (is_number(s)) {
1250 					(void) setsymtab(num, s,
1251 					    atof((char *)s),
1252 					    /*LINTED align*/
1253 					    STR|NUM, (Array *)ap->sval);
1254 				} else {
1255 					(void) setsymtab(num, s, 0.0,
1256 					    /*LINTED align*/
1257 					    STR, (Array *)ap->sval);
1258 				}
1259 				*patbeg = temp;
1260 				s = patbeg + patlen;
1261 				if (*(patbeg+patlen-1) == 0 || *s == 0) {
1262 					n++;
1263 					(void) sprintf((char *)num, "%d", n);
1264 					(void) setsymtab(num, (uchar *)"", 0.0,
1265 					    /*LINTED align*/
1266 					    STR, (Array *)ap->sval);
1267 					pfa->initstat = tempstat;
1268 					goto spdone;
1269 				}
1270 			} while (nematch(pfa, s));
1271 		}
1272 		n++;
1273 		(void) sprintf((char *)num, "%d", n);
1274 		if (is_number(s)) {
1275 			(void) setsymtab(num, s, atof((char *)s),
1276 			    /*LINTED align*/
1277 			    STR|NUM, (Array *)ap->sval);
1278 		} else {
1279 			/*LINTED align*/
1280 			(void) setsymtab(num, s, 0.0, STR, (Array *)ap->sval);
1281 		}
1282 spdone:
1283 		pfa = NULL;
1284 	} else if (sep == ' ') {
1285 		for (n = 0; ; ) {
1286 			while (*s == ' ' || *s == '\t' || *s == '\n')
1287 				s++;
1288 			if (*s == 0)
1289 				break;
1290 			n++;
1291 			t = s;
1292 			do
1293 				s++;
1294 			while (*s != ' ' && *s != '\t' &&
1295 			    *s != '\n' && *s != '\0')
1296 				;
1297 			temp = *s;
1298 			*s = '\0';
1299 			(void) sprintf((char *)num, "%d", n);
1300 			if (is_number(t)) {
1301 				(void) setsymtab(num, t, atof((char *)t),
1302 				    /*LINTED align*/
1303 				    STR|NUM, (Array *)ap->sval);
1304 			} else {
1305 				(void) setsymtab(num, t, 0.0,
1306 				    /*LINTED align*/
1307 				    STR, (Array *)ap->sval);
1308 			}
1309 			*s = temp;
1310 			if (*s != 0)
1311 				s++;
1312 		}
1313 	} else if (*s != 0) {
1314 		for (;;) {
1315 			n++;
1316 			t = s;
1317 			while (*s != sep && *s != '\n' && *s != '\0')
1318 				s++;
1319 			temp = *s;
1320 			*s = '\0';
1321 			(void) sprintf((char *)num, "%d", n);
1322 			if (is_number(t)) {
1323 				(void) setsymtab(num, t, atof((char *)t),
1324 				    /*LINTED align*/
1325 				    STR|NUM, (Array *)ap->sval);
1326 			} else {
1327 				(void) setsymtab(num, t, 0.0,
1328 				    /*LINTED align*/
1329 				    STR, (Array *)ap->sval);
1330 			}
1331 			*s = temp;
1332 			if (*s++ == 0)
1333 				break;
1334 		}
1335 	}
1336 	tempfree(ap, "");
1337 	tempfree(y, "");
1338 	if (a[2] != 0 && (int)a[3] == STRING)
1339 		tempfree(x, "");
1340 	x = gettemp("");
1341 	x->tval = NUM;
1342 	x->fval = n;
1343 	return (x);
1344 }
1345 
1346 /*ARGSUSED*/
1347 Cell *
1348 condexpr(Node **a, int n)
1349 {
1350 	register Cell *x;
1351 
1352 	x = execute(a[0]);
1353 	if (istrue(x)) {
1354 		tempfree(x, "");
1355 		x = execute(a[1]);
1356 	} else {
1357 		tempfree(x, "");
1358 		x = execute(a[2]);
1359 	}
1360 	return (x);
1361 }
1362 
1363 /*ARGSUSED*/
1364 Cell *
1365 ifstat(Node **a, int n)
1366 {
1367 	register Cell *x;
1368 
1369 	x = execute(a[0]);
1370 	if (istrue(x)) {
1371 		tempfree(x, "");
1372 		x = execute(a[1]);
1373 	} else if (a[2] != 0) {
1374 		tempfree(x, "");
1375 		x = execute(a[2]);
1376 	}
1377 	return (x);
1378 }
1379 
1380 /*ARGSUSED*/
1381 Cell *
1382 whilestat(Node **a, int n)
1383 {
1384 	register Cell *x;
1385 
1386 	for (;;) {
1387 		x = execute(a[0]);
1388 		if (!istrue(x))
1389 			return (x);
1390 		tempfree(x, "");
1391 		x = execute(a[1]);
1392 		if (isbreak(x)) {
1393 			x = true;
1394 			return (x);
1395 		}
1396 		if (isnext(x) || isexit(x) || isret(x))
1397 			return (x);
1398 		tempfree(x, "");
1399 	}
1400 }
1401 
1402 /*ARGSUSED*/
1403 Cell *
1404 dostat(Node **a, int n)
1405 {
1406 	register Cell *x;
1407 
1408 	for (;;) {
1409 		x = execute(a[0]);
1410 		if (isbreak(x))
1411 			return (true);
1412 		if (isnext(x) || isexit(x) || isret(x))
1413 			return (x);
1414 		tempfree(x, "");
1415 		x = execute(a[1]);
1416 		if (!istrue(x))
1417 			return (x);
1418 		tempfree(x, "");
1419 	}
1420 }
1421 
1422 /*ARGSUSED*/
1423 Cell *
1424 forstat(Node **a, int n)
1425 {
1426 	register Cell *x;
1427 
1428 	x = execute(a[0]);
1429 	tempfree(x, "");
1430 	for (;;) {
1431 		if (a[1] != 0) {
1432 			x = execute(a[1]);
1433 			if (!istrue(x))
1434 				return (x);
1435 			else
1436 				tempfree(x, "");
1437 		}
1438 		x = execute(a[3]);
1439 		if (isbreak(x))		/* turn off break */
1440 			return (true);
1441 		if (isnext(x) || isexit(x) || isret(x))
1442 			return (x);
1443 		tempfree(x, "");
1444 		x = execute(a[2]);
1445 		tempfree(x, "");
1446 	}
1447 }
1448 
1449 /*ARGSUSED*/
1450 Cell *
1451 instat(Node **a, int n)
1452 {
1453 	register Cell *x, *vp, *arrayp, *cp, *ncp;
1454 	Array *tp;
1455 	int i;
1456 
1457 	vp = execute(a[0]);
1458 	arrayp = execute(a[1]);
1459 	if (!isarr(arrayp))
1460 		ERROR "%s is not an array", arrayp->nval FATAL;
1461 	/*LINTED align*/
1462 	tp = (Array *)arrayp->sval;
1463 	tempfree(arrayp, "");
1464 	for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1465 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1466 			(void) setsval(vp, cp->nval);
1467 			ncp = cp->cnext;
1468 			x = execute(a[2]);
1469 			if (isbreak(x)) {
1470 				tempfree(vp, "");
1471 				return (true);
1472 			}
1473 			if (isnext(x) || isexit(x) || isret(x)) {
1474 				tempfree(vp, "");
1475 				return (x);
1476 			}
1477 			tempfree(x, "");
1478 		}
1479 	}
1480 	return (true);
1481 }
1482 
1483 /*ARGSUSED*/
1484 Cell *
1485 bltin(Node **a, int n)
1486 {
1487 	register Cell *x, *y;
1488 	Awkfloat u;
1489 	register int t;
1490 	uchar *p, *buf;
1491 	Node *nextarg;
1492 
1493 	t = (int)a[0];
1494 	x = execute(a[1]);
1495 	nextarg = a[1]->nnext;
1496 	switch (t) {
1497 	case FLENGTH:
1498 		u = (Awkfloat)strlen((char *)getsval(x)); break;
1499 	case FLOG:
1500 		u = errcheck(log(getfval(x)), "log"); break;
1501 	case FINT:
1502 		(void) modf(getfval(x), &u); break;
1503 	case FEXP:
1504 		u = errcheck(exp(getfval(x)), "exp"); break;
1505 	case FSQRT:
1506 		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1507 	case FSIN:
1508 		u = sin(getfval(x)); break;
1509 	case FCOS:
1510 		u = cos(getfval(x)); break;
1511 	case FATAN:
1512 		if (nextarg == 0) {
1513 			ERROR "atan2 requires two arguments; returning 1.0"
1514 			    WARNING;
1515 			u = 1.0;
1516 		} else {
1517 			y = execute(a[1]->nnext);
1518 			u = atan2(getfval(x), getfval(y));
1519 			tempfree(y, "");
1520 			nextarg = nextarg->nnext;
1521 		}
1522 		break;
1523 	case FSYSTEM:
1524 		/* in case something is buffered already */
1525 		(void) fflush(stdout);
1526 		/* 256 is unix-dep */
1527 		u = (Awkfloat)system((char *)getsval(x)) / 256;
1528 		break;
1529 	case FRAND:
1530 		u = (Awkfloat)(rand() % 32767) / 32767.0;
1531 		break;
1532 	case FSRAND:
1533 		if (x->tval & REC)	/* no argument provided */
1534 			u = time((time_t *)0);
1535 		else
1536 			u = getfval(x);
1537 		srand((int)u); u = (int)u;
1538 		break;
1539 	case FTOUPPER:
1540 	case FTOLOWER:
1541 		buf = tostring(getsval(x));
1542 		if (t == FTOUPPER) {
1543 			for (p = buf; *p; p++)
1544 				if (islower(*p))
1545 					*p = toupper(*p);
1546 		} else {
1547 			for (p = buf; *p; p++)
1548 				if (isupper(*p))
1549 					*p = tolower(*p);
1550 		}
1551 		tempfree(x, "");
1552 		x = gettemp("");
1553 		(void) setsval(x, buf);
1554 		free(buf);
1555 		return (x);
1556 	default:	/* can't happen */
1557 		ERROR "illegal function type %d", t FATAL;
1558 		break;
1559 	}
1560 	tempfree(x, "");
1561 	x = gettemp("");
1562 	(void) setfval(x, u);
1563 	if (nextarg != 0) {
1564 		ERROR "warning: function has too many arguments" WARNING;
1565 		for (; nextarg; nextarg = nextarg->nnext)
1566 			(void) execute(nextarg);
1567 	}
1568 	return (x);
1569 }
1570 
1571 /*ARGSUSED*/
1572 Cell *
1573 print(Node **a, int n)
1574 {
1575 	register Node *x;
1576 	register Cell *y;
1577 	FILE *fp;
1578 
1579 	if (a[1] == 0)
1580 		fp = stdout;
1581 	else
1582 		fp = redirect((int)a[1], a[2]);
1583 	for (x = a[0]; x != NULL; x = x->nnext) {
1584 		y = execute(x);
1585 		(void) fputs((char *)getsval(y), fp);
1586 		tempfree(y, "");
1587 		if (x->nnext == NULL)
1588 			(void) fputs((char *)*ORS, fp);
1589 		else
1590 			(void) fputs((char *)*OFS, fp);
1591 	}
1592 	if (a[1] != 0)
1593 		(void) fflush(fp);
1594 	return (true);
1595 }
1596 
1597 /*ARGSUSED*/
1598 Cell *
1599 nullproc(Node **a, int n)
1600 {
1601 	return (0);
1602 }
1603 
1604 struct {
1605 	FILE	*fp;
1606 	uchar	*fname;
1607 	int	mode;	/* '|', 'a', 'w' */
1608 } files[FOPEN_MAX];
1609 
1610 static FILE *
1611 redirect(int a, Node *b)
1612 {
1613 	FILE *fp;
1614 	Cell *x;
1615 	uchar *fname;
1616 
1617 	x = execute(b);
1618 	fname = getsval(x);
1619 	fp = openfile(a, fname);
1620 	if (fp == NULL)
1621 		ERROR "can't open file %s", fname FATAL;
1622 	tempfree(x, "");
1623 	return (fp);
1624 }
1625 
1626 static FILE *
1627 openfile(int a, uchar *s)
1628 {
1629 	register int i, m;
1630 	register FILE *fp;
1631 
1632 	if (*s == '\0')
1633 		ERROR "null file name in print or getline" FATAL;
1634 	for (i = 0; i < FOPEN_MAX; i++) {
1635 		if (files[i].fname &&
1636 		    strcmp((char *)s, (char *)files[i].fname) == 0) {
1637 			if (a == files[i].mode ||
1638 			    a == APPEND && files[i].mode == GT) {
1639 				return (files[i].fp);
1640 			}
1641 		}
1642 	}
1643 	for (i = 0; i < FOPEN_MAX; i++) {
1644 		if (files[i].fp == 0)
1645 			break;
1646 	}
1647 	if (i >= FOPEN_MAX)
1648 		ERROR "%s makes too many open files", s FATAL;
1649 	(void) fflush(stdout);	/* force a semblance of order */
1650 	m = a;
1651 	if (a == GT) {
1652 		fp = fopen((char *)s, "w");
1653 	} else if (a == APPEND) {
1654 		fp = fopen((char *)s, "a");
1655 		m = GT;	/* so can mix > and >> */
1656 	} else if (a == '|') {	/* output pipe */
1657 		fp = popen((char *)s, "w");
1658 	} else if (a == LE) {	/* input pipe */
1659 		fp = popen((char *)s, "r");
1660 	} else if (a == LT) {	/* getline <file */
1661 		fp = strcmp((char *)s, "-") == 0 ?
1662 		    stdin : fopen((char *)s, "r");	/* "-" is stdin */
1663 	} else	/* can't happen */
1664 		ERROR "illegal redirection" FATAL;
1665 	if (fp != NULL) {
1666 		files[i].fname = tostring(s);
1667 		files[i].fp = fp;
1668 		files[i].mode = m;
1669 	}
1670 	return (fp);
1671 }
1672 
1673 /*ARGSUSED*/
1674 Cell *
1675 closefile(Node **a, int n)
1676 {
1677 	register Cell *x;
1678 	int i, stat;
1679 
1680 	x = execute(a[0]);
1681 	(void) getsval(x);
1682 	for (i = 0; i < FOPEN_MAX; i++) {
1683 		if (files[i].fname &&
1684 		    strcmp((char *)x->sval, (char *)files[i].fname) == 0) {
1685 			if (ferror(files[i].fp)) {
1686 				ERROR "i/o error occurred on %s",
1687 				    files[i].fname WARNING;
1688 			}
1689 			if (files[i].mode == '|' || files[i].mode == LE)
1690 				stat = pclose(files[i].fp);
1691 			else
1692 				stat = fclose(files[i].fp);
1693 			if (stat == EOF) {
1694 				ERROR "i/o error occurred closing %s",
1695 				    files[i].fname WARNING;
1696 			}
1697 			xfree(files[i].fname);
1698 			/* watch out for ref thru this */
1699 			files[i].fname = NULL;
1700 			files[i].fp = NULL;
1701 		}
1702 	}
1703 	tempfree(x, "close");
1704 	return (true);
1705 }
1706 
1707 static void
1708 closeall(void)
1709 {
1710 	int i, stat;
1711 
1712 	for (i = 0; i < FOPEN_MAX; i++) {
1713 		if (files[i].fp) {
1714 			if (ferror(files[i].fp)) {
1715 				ERROR "i/o error occurred on %s",
1716 				    files[i].fname WARNING;
1717 			}
1718 			if (files[i].mode == '|' || files[i].mode == LE)
1719 				stat = pclose(files[i].fp);
1720 			else
1721 				stat = fclose(files[i].fp);
1722 			if (stat == EOF) {
1723 				ERROR "i/o error occurred while closing %s",
1724 				    files[i].fname WARNING;
1725 			}
1726 		}
1727 	}
1728 }
1729 
1730 /*ARGSUSED*/
1731 Cell *
1732 sub(Node **a, int nnn)
1733 {
1734 	register uchar *sptr;
1735 	register Cell *x, *y, *result;
1736 	uchar *buf, *t;
1737 	fa *pfa;
1738 	size_t	bsize, cnt, len;
1739 
1740 	x = execute(a[3]);	/* target string */
1741 	t = getsval(x);
1742 	if (a[0] == 0)
1743 		pfa = (fa *)a[1];	/* regular expression */
1744 	else {
1745 		y = execute(a[1]);
1746 		pfa = makedfa(getsval(y), 1);
1747 		tempfree(y, "");
1748 	}
1749 	y = execute(a[2]);	/* replacement string */
1750 	result = false;
1751 	if (pmatch(pfa, t)) {
1752 		init_buf(&buf, &bsize, LINE_INCR);
1753 		cnt = 0;
1754 		sptr = t;
1755 		len = patbeg - sptr;
1756 		if (len > 0) {
1757 			expand_buf(&buf, &bsize, cnt + len);
1758 			(void) memcpy(buf, sptr, len);
1759 			cnt += len;
1760 		}
1761 		sptr = getsval(y);
1762 		while (*sptr != 0) {
1763 			expand_buf(&buf, &bsize, cnt);
1764 			if (*sptr == '\\' &&
1765 			    (*(sptr+1) == '&' || *(sptr+1) == '\\')) {
1766 				sptr++;		/* skip \, */
1767 				buf[cnt++] = *sptr++; /* add & or \ */
1768 			} else if (*sptr == '&') {
1769 				expand_buf(&buf, &bsize, cnt + patlen);
1770 				sptr++;
1771 				(void) memcpy(&buf[cnt], patbeg, patlen);
1772 				cnt += patlen;
1773 			} else {
1774 				buf[cnt++] = *sptr++;
1775 			}
1776 		}
1777 		sptr = patbeg + patlen;
1778 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1779 			len = strlen((char *)sptr);
1780 			expand_buf(&buf, &bsize, cnt + len);
1781 			(void) memcpy(&buf[cnt], sptr, len);
1782 			cnt += len;
1783 		}
1784 		buf[cnt] = '\0';
1785 		(void) setsval(x, buf);
1786 		free(buf);
1787 		result = true;
1788 	}
1789 	tempfree(x, "");
1790 	tempfree(y, "");
1791 	return (result);
1792 }
1793 
1794 /*ARGSUSED*/
1795 Cell *
1796 gsub(Node **a, int nnn)
1797 {
1798 	register Cell *x, *y;
1799 	register uchar *rptr, *sptr, *t;
1800 	uchar *buf;
1801 	register fa *pfa;
1802 	int mflag, tempstat, num;
1803 	size_t	bsize, cnt, len;
1804 
1805 	mflag = 0;	/* if mflag == 0, can replace empty string */
1806 	num = 0;
1807 	x = execute(a[3]);	/* target string */
1808 	t = getsval(x);
1809 	if (a[0] == 0)
1810 		pfa = (fa *) a[1];	/* regular expression */
1811 	else {
1812 		y = execute(a[1]);
1813 		pfa = makedfa(getsval(y), 1);
1814 		tempfree(y, "");
1815 	}
1816 	y = execute(a[2]);	/* replacement string */
1817 	if (pmatch(pfa, t)) {
1818 		tempstat = pfa->initstat;
1819 		pfa->initstat = 2;
1820 		init_buf(&buf, &bsize, LINE_INCR);
1821 		rptr = getsval(y);
1822 		cnt = 0;
1823 		do {
1824 			if (patlen == 0 && *patbeg != 0) {
1825 				/* matched empty string */
1826 				if (mflag == 0) {	/* can replace empty */
1827 					num++;
1828 					sptr = rptr;
1829 					while (*sptr != 0) {
1830 						expand_buf(&buf, &bsize, cnt);
1831 						if (*sptr == '\\' &&
1832 						    (*(sptr+1) == '&' ||
1833 						    *(sptr+1) == '\\')) {
1834 							sptr++;
1835 							buf[cnt++] = *sptr++;
1836 						} else if (*sptr == '&') {
1837 							expand_buf(&buf,
1838 							    &bsize,
1839 							    cnt + patlen);
1840 							sptr++;
1841 							(void) memcpy(&buf[cnt],
1842 							    patbeg, patlen);
1843 							cnt += patlen;
1844 						} else {
1845 							buf[cnt++] = *sptr++;
1846 						}
1847 					}
1848 				}
1849 				if (*t == 0)	/* at end */
1850 					goto done;
1851 				expand_buf(&buf, &bsize, cnt);
1852 				buf[cnt++] = *t++;
1853 				mflag = 0;
1854 			} else {	/* matched nonempty string */
1855 				num++;
1856 				sptr = t;
1857 				len = patbeg - sptr;
1858 				if (len > 0) {
1859 					expand_buf(&buf, &bsize, cnt + len);
1860 					(void) memcpy(&buf[cnt], sptr, len);
1861 					cnt += len;
1862 				}
1863 				sptr = rptr;
1864 				while (*sptr != 0) {
1865 					expand_buf(&buf, &bsize, cnt);
1866 					if (*sptr == '\\' &&
1867 					    (*(sptr+1) == '&' ||
1868 					    *(sptr+1) == '\\')) {
1869 						sptr++;
1870 						buf[cnt++] = *sptr++;
1871 					} else if (*sptr == '&') {
1872 						expand_buf(&buf, &bsize,
1873 						    cnt + patlen);
1874 						sptr++;
1875 						(void) memcpy(&buf[cnt],
1876 						    patbeg, patlen);
1877 						cnt += patlen;
1878 					} else {
1879 						buf[cnt++] = *sptr++;
1880 					}
1881 				}
1882 				t = patbeg + patlen;
1883 				if ((*(t-1) == 0) || (*t == 0))
1884 					goto done;
1885 				mflag = 1;
1886 			}
1887 		} while (pmatch(pfa, t));
1888 		sptr = t;
1889 		len = strlen((char *)sptr);
1890 		expand_buf(&buf, &bsize, len + cnt);
1891 		(void) memcpy(&buf[cnt], sptr, len);
1892 		cnt += len;
1893 	done:
1894 		buf[cnt] = '\0';
1895 		(void) setsval(x, buf);
1896 		free(buf);
1897 		pfa->initstat = tempstat;
1898 	}
1899 	tempfree(x, "");
1900 	tempfree(y, "");
1901 	x = gettemp("");
1902 	x->tval = NUM;
1903 	x->fval = num;
1904 	return (x);
1905 }
1906