Home | History | Annotate | Download | only in awk
      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