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