185587Sobrien/****************************************************************
285587SobrienCopyright (C) Lucent Technologies 1997
385587SobrienAll Rights Reserved
485587Sobrien
585587SobrienPermission to use, copy, modify, and distribute this software and
685587Sobrienits documentation for any purpose and without fee is hereby
785587Sobriengranted, provided that the above copyright notice appear in all
885587Sobriencopies and that both that the copyright notice and this
985587Sobrienpermission notice and warranty disclaimer appear in supporting
1085587Sobriendocumentation, and that the name Lucent Technologies or any of
1185587Sobrienits entities not be used in advertising or publicity pertaining
1285587Sobriento distribution of the software without specific, written prior
1385587Sobrienpermission.
1485587Sobrien
1585587SobrienLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1685587SobrienINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1785587SobrienIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
1885587SobrienSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1985587SobrienWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
2085587SobrienIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2185587SobrienARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
2285587SobrienTHIS SOFTWARE.
2385587Sobrien****************************************************************/
2485587Sobrien
25201989Sru#include <sys/cdefs.h>
26201989Sru__FBSDID("$FreeBSD$");
27201989Sru
2885587Sobrien#define DEBUG
2985587Sobrien#include <stdio.h>
3085587Sobrien#include <ctype.h>
3185587Sobrien#include <setjmp.h>
32146299Sru#include <limits.h>
3385587Sobrien#include <math.h>
3485587Sobrien#include <string.h>
3585587Sobrien#include <stdlib.h>
3685587Sobrien#include <time.h>
3785587Sobrien#include "awk.h"
3885587Sobrien#include "ytab.h"
3985587Sobrien
4085587Sobrien#define tempfree(x)	if (istemp(x)) tfree(x); else
4185587Sobrien
4285587Sobrien/*
4385587Sobrien#undef tempfree
4485587Sobrien
4585587Sobrienvoid tempfree(Cell *p) {
4685587Sobrien	if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
4785587Sobrien		WARNING("bad csub %d in Cell %d %s",
4885587Sobrien			p->csub, p->ctype, p->sval);
4985587Sobrien	}
5085587Sobrien	if (istemp(p))
5185587Sobrien		tfree(p);
5285587Sobrien}
5385587Sobrien*/
5485587Sobrien
55170331Srafan/* do we really need these? */
56170331Srafan/* #ifdef _NFILE */
57170331Srafan/* #ifndef FOPEN_MAX */
58170331Srafan/* #define FOPEN_MAX _NFILE */
59170331Srafan/* #endif */
60170331Srafan/* #endif */
61170331Srafan/*  */
62170331Srafan/* #ifndef	FOPEN_MAX */
63170331Srafan/* #define	FOPEN_MAX	40 */	/* max number of open files */
64170331Srafan/* #endif */
65170331Srafan/*  */
66170331Srafan/* #ifndef RAND_MAX */
67170331Srafan/* #define RAND_MAX	32767 */	/* all that ansi guarantees */
68170331Srafan/* #endif */
6985587Sobrien
7085587Sobrienjmp_buf env;
7185587Sobrienextern	int	pairstack[];
72221381Sruextern	Awkfloat	srand_seed;
7385587Sobrien
7485587SobrienNode	*winner = NULL;	/* root of parse tree */
7585587SobrienCell	*tmps;		/* free temporary cells for execution */
7685587Sobrien
7785587Sobrienstatic Cell	truecell	={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
7885587SobrienCell	*True	= &truecell;
7985587Sobrienstatic Cell	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
8085587SobrienCell	*False	= &falsecell;
8185587Sobrienstatic Cell	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
8285587SobrienCell	*jbreak	= &breakcell;
8385587Sobrienstatic Cell	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM };
8485587SobrienCell	*jcont	= &contcell;
8585587Sobrienstatic Cell	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
8685587SobrienCell	*jnext	= &nextcell;
8785587Sobrienstatic Cell	nextfilecell	={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
8885587SobrienCell	*jnextfile	= &nextfilecell;
8985587Sobrienstatic Cell	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
9085587SobrienCell	*jexit	= &exitcell;
9185587Sobrienstatic Cell	retcell		={ OJUMP, JRET, 0, 0, 0.0, NUM };
9285587SobrienCell	*jret	= &retcell;
9385587Sobrienstatic Cell	tempcell	={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
9485587Sobrien
9585587SobrienNode	*curnode = NULL;	/* the node being executed, for debugging */
9685587Sobrien
9785587Sobrien/* buffer memory management */
9885587Sobrienint adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
99107806Sobrien	const char *whatrtn)
10085587Sobrien/* pbuf:    address of pointer to buffer being managed
10185587Sobrien * psiz:    address of buffer size variable
10285587Sobrien * minlen:  minimum length of buffer needed
10385587Sobrien * quantum: buffer size quantum
10485587Sobrien * pbptr:   address of movable pointer into buffer, or 0 if none
10585587Sobrien * whatrtn: name of the calling routine if failure should cause fatal error
10685587Sobrien *
10785587Sobrien * return   0 for realloc failure, !=0 for success
10885587Sobrien */
10985587Sobrien{
11085587Sobrien	if (minlen > *psiz) {
11185587Sobrien		char *tbuf;
11285587Sobrien		int rminlen = quantum ? minlen % quantum : 0;
11385587Sobrien		int boff = pbptr ? *pbptr - *pbuf : 0;
11485587Sobrien		/* round up to next multiple of quantum */
11585587Sobrien		if (rminlen)
11685587Sobrien			minlen += quantum - rminlen;
11785587Sobrien		tbuf = (char *) realloc(*pbuf, minlen);
118170331Srafan		dprintf( ("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, *pbuf, tbuf) );
11985587Sobrien		if (tbuf == NULL) {
12085587Sobrien			if (whatrtn)
12185587Sobrien				FATAL("out of memory in %s", whatrtn);
12285587Sobrien			return 0;
12385587Sobrien		}
12485587Sobrien		*pbuf = tbuf;
12585587Sobrien		*psiz = minlen;
12685587Sobrien		if (pbptr)
12785587Sobrien			*pbptr = tbuf + boff;
12885587Sobrien	}
12985587Sobrien	return 1;
13085587Sobrien}
13185587Sobrien
13285587Sobrienvoid run(Node *a)	/* execution of parse tree starts here */
13385587Sobrien{
13485587Sobrien	extern void stdinit(void);
13585587Sobrien
13685587Sobrien	stdinit();
13785587Sobrien	execute(a);
13885587Sobrien	closeall();
13985587Sobrien}
14085587Sobrien
14185587SobrienCell *execute(Node *u)	/* execute a node of the parse tree */
14285587Sobrien{
14385587Sobrien	Cell *(*proc)(Node **, int);
14485587Sobrien	Cell *x;
14585587Sobrien	Node *a;
14685587Sobrien
14785587Sobrien	if (u == NULL)
14885587Sobrien		return(True);
14985587Sobrien	for (a = u; ; a = a->nnext) {
15085587Sobrien		curnode = a;
15185587Sobrien		if (isvalue(a)) {
15285587Sobrien			x = (Cell *) (a->narg[0]);
15385587Sobrien			if (isfld(x) && !donefld)
15485587Sobrien				fldbld();
15585587Sobrien			else if (isrec(x) && !donerec)
15685587Sobrien				recbld();
15785587Sobrien			return(x);
15885587Sobrien		}
15985587Sobrien		if (notlegal(a->nobj))	/* probably a Cell* but too risky to print */
16085587Sobrien			FATAL("illegal statement");
16185587Sobrien		proc = proctab[a->nobj-FIRSTTOKEN];
16285587Sobrien		x = (*proc)(a->narg, a->nobj);
16385587Sobrien		if (isfld(x) && !donefld)
16485587Sobrien			fldbld();
16585587Sobrien		else if (isrec(x) && !donerec)
16685587Sobrien			recbld();
16785587Sobrien		if (isexpr(a))
16885587Sobrien			return(x);
16985587Sobrien		if (isjump(x))
17085587Sobrien			return(x);
17185587Sobrien		if (a->nnext == NULL)
17285587Sobrien			return(x);
17385587Sobrien		tempfree(x);
17485587Sobrien	}
17585587Sobrien}
17685587Sobrien
17785587Sobrien
17885587SobrienCell *program(Node **a, int n)	/* execute an awk program */
17985587Sobrien{				/* a[0] = BEGIN, a[1] = body, a[2] = END */
18085587Sobrien	Cell *x;
18185587Sobrien
18285587Sobrien	if (setjmp(env) != 0)
18385587Sobrien		goto ex;
18485587Sobrien	if (a[0]) {		/* BEGIN */
18585587Sobrien		x = execute(a[0]);
18685587Sobrien		if (isexit(x))
18785587Sobrien			return(True);
18885587Sobrien		if (isjump(x))
18985587Sobrien			FATAL("illegal break, continue, next or nextfile from BEGIN");
19085587Sobrien		tempfree(x);
19185587Sobrien	}
19285587Sobrien	if (a[1] || a[2])
19385587Sobrien		while (getrec(&record, &recsize, 1) > 0) {
19485587Sobrien			x = execute(a[1]);
19585587Sobrien			if (isexit(x))
19685587Sobrien				break;
19785587Sobrien			tempfree(x);
19885587Sobrien		}
19985587Sobrien  ex:
20085587Sobrien	if (setjmp(env) != 0)	/* handles exit within END */
20185587Sobrien		goto ex1;
20285587Sobrien	if (a[2]) {		/* END */
20385587Sobrien		x = execute(a[2]);
20485587Sobrien		if (isbreak(x) || isnext(x) || iscont(x))
20585587Sobrien			FATAL("illegal break, continue, next or nextfile from END");
20685587Sobrien		tempfree(x);
20785587Sobrien	}
20885587Sobrien  ex1:
20985587Sobrien	return(True);
21085587Sobrien}
21185587Sobrien
21285587Sobrienstruct Frame {	/* stack frame for awk function calls */
21385587Sobrien	int nargs;	/* number of arguments in this call */
21485587Sobrien	Cell *fcncell;	/* pointer to Cell for function */
21585587Sobrien	Cell **args;	/* pointer to array of arguments after execute */
21685587Sobrien	Cell *retval;	/* return value */
21785587Sobrien};
21885587Sobrien
21985587Sobrien#define	NARGS	50	/* max args in a call */
22085587Sobrien
22185587Sobrienstruct Frame *frame = NULL;	/* base of stack frames; dynamically allocated */
22285587Sobrienint	nframe = 0;		/* number of frames allocated */
22385587Sobrienstruct Frame *fp = NULL;	/* frame pointer. bottom level unused */
22485587Sobrien
22585587SobrienCell *call(Node **a, int n)	/* function call.  very kludgy and fragile */
22685587Sobrien{
22785587Sobrien	static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
22885587Sobrien	int i, ncall, ndef;
229125601Sru	int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */
23085587Sobrien	Node *x;
23185587Sobrien	Cell *args[NARGS], *oargs[NARGS];	/* BUG: fixed size arrays */
23285587Sobrien	Cell *y, *z, *fcn;
23385587Sobrien	char *s;
23485587Sobrien
23585587Sobrien	fcn = execute(a[0]);	/* the function itself */
23685587Sobrien	s = fcn->nval;
23785587Sobrien	if (!isfcn(fcn))
23885587Sobrien		FATAL("calling undefined function %s", s);
23985587Sobrien	if (frame == NULL) {
24085587Sobrien		fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
24185587Sobrien		if (frame == NULL)
24285587Sobrien			FATAL("out of space for stack frames calling %s", s);
24385587Sobrien	}
24485587Sobrien	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)	/* args in call */
24585587Sobrien		ncall++;
24685587Sobrien	ndef = (int) fcn->fval;			/* args in defn */
24785587Sobrien	   dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
24885587Sobrien	if (ncall > ndef)
24985587Sobrien		WARNING("function %s called with %d args, uses only %d",
25085587Sobrien			s, ncall, ndef);
25185587Sobrien	if (ncall + ndef > NARGS)
25285587Sobrien		FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
25385587Sobrien	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {	/* get call args */
25485587Sobrien		   dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
25585587Sobrien		y = execute(x);
25685587Sobrien		oargs[i] = y;
25785587Sobrien		   dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
258107806Sobrien			   i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval) );
25985587Sobrien		if (isfcn(y))
26085587Sobrien			FATAL("can't use function %s as argument in %s", y->nval, s);
26185587Sobrien		if (isarr(y))
26285587Sobrien			args[i] = y;	/* arrays by ref */
26385587Sobrien		else
26485587Sobrien			args[i] = copycell(y);
26585587Sobrien		tempfree(y);
26685587Sobrien	}
26785587Sobrien	for ( ; i < ndef; i++) {	/* add null args for ones not provided */
26885587Sobrien		args[i] = gettemp();
26985587Sobrien		*args[i] = newcopycell;
27085587Sobrien	}
27185587Sobrien	fp++;	/* now ok to up frame */
27285587Sobrien	if (fp >= frame + nframe) {
27385587Sobrien		int dfp = fp - frame;	/* old index */
27485587Sobrien		frame = (struct Frame *)
27585587Sobrien			realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
27685587Sobrien		if (frame == NULL)
27785587Sobrien			FATAL("out of space for stack frames in %s", s);
27885587Sobrien		fp = frame + dfp;
27985587Sobrien	}
28085587Sobrien	fp->fcncell = fcn;
28185587Sobrien	fp->args = args;
28285587Sobrien	fp->nargs = ndef;	/* number defined with (excess are locals) */
28385587Sobrien	fp->retval = gettemp();
28485587Sobrien
28585587Sobrien	   dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
28685587Sobrien	y = execute((Node *)(fcn->sval));	/* execute body */
28785587Sobrien	   dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
28885587Sobrien
28985587Sobrien	for (i = 0; i < ndef; i++) {
29085587Sobrien		Cell *t = fp->args[i];
29185587Sobrien		if (isarr(t)) {
29285587Sobrien			if (t->csub == CCOPY) {
29385587Sobrien				if (i >= ncall) {
29485587Sobrien					freesymtab(t);
29585587Sobrien					t->csub = CTEMP;
29685587Sobrien					tempfree(t);
29785587Sobrien				} else {
29885587Sobrien					oargs[i]->tval = t->tval;
29985587Sobrien					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
30085587Sobrien					oargs[i]->sval = t->sval;
30185587Sobrien					tempfree(t);
30285587Sobrien				}
30385587Sobrien			}
30485587Sobrien		} else if (t != y) {	/* kludge to prevent freeing twice */
30585587Sobrien			t->csub = CTEMP;
30685587Sobrien			tempfree(t);
307125601Sru		} else if (t == y && t->csub == CCOPY) {
308125601Sru			t->csub = CTEMP;
309125601Sru			tempfree(t);
310125601Sru			freed = 1;
31185587Sobrien		}
31285587Sobrien	}
31385587Sobrien	tempfree(fcn);
31485587Sobrien	if (isexit(y) || isnext(y))
31585587Sobrien		return y;
316125601Sru	if (freed == 0) {
317125601Sru		tempfree(y);	/* don't free twice! */
318125601Sru	}
31985587Sobrien	z = fp->retval;			/* return value */
32085587Sobrien	   dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
32185587Sobrien	fp--;
32285587Sobrien	return(z);
32385587Sobrien}
32485587Sobrien
32585587SobrienCell *copycell(Cell *x)	/* make a copy of a cell in a temp */
32685587Sobrien{
32785587Sobrien	Cell *y;
32885587Sobrien
32985587Sobrien	y = gettemp();
33085587Sobrien	y->csub = CCOPY;	/* prevents freeing until call is over */
33185587Sobrien	y->nval = x->nval;	/* BUG? */
33285587Sobrien	if (isstr(x))
33385587Sobrien		y->sval = tostring(x->sval);
33485587Sobrien	y->fval = x->fval;
33585587Sobrien	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);	/* copy is not constant or field */
33685587Sobrien							/* is DONTFREE right? */
33785587Sobrien	return y;
33885587Sobrien}
33985587Sobrien
34085587SobrienCell *arg(Node **a, int n)	/* nth argument of a function */
34185587Sobrien{
34285587Sobrien
34385587Sobrien	n = ptoi(a[0]);	/* argument number, counting from 0 */
34485587Sobrien	   dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
34585587Sobrien	if (n+1 > fp->nargs)
34685587Sobrien		FATAL("argument #%d of function %s was not supplied",
34785587Sobrien			n+1, fp->fcncell->nval);
34885587Sobrien	return fp->args[n];
34985587Sobrien}
35085587Sobrien
35185587SobrienCell *jump(Node **a, int n)	/* break, continue, next, nextfile, return */
35285587Sobrien{
35385587Sobrien	Cell *y;
35485587Sobrien
35585587Sobrien	switch (n) {
35685587Sobrien	case EXIT:
35785587Sobrien		if (a[0] != NULL) {
35885587Sobrien			y = execute(a[0]);
35985587Sobrien			errorflag = (int) getfval(y);
36085587Sobrien			tempfree(y);
36185587Sobrien		}
36285587Sobrien		longjmp(env, 1);
36385587Sobrien	case RETURN:
36485587Sobrien		if (a[0] != NULL) {
36585587Sobrien			y = execute(a[0]);
36685587Sobrien			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
36785587Sobrien				setsval(fp->retval, getsval(y));
36885587Sobrien				fp->retval->fval = getfval(y);
36985587Sobrien				fp->retval->tval |= NUM;
37085587Sobrien			}
37185587Sobrien			else if (y->tval & STR)
37285587Sobrien				setsval(fp->retval, getsval(y));
37385587Sobrien			else if (y->tval & NUM)
37485587Sobrien				setfval(fp->retval, getfval(y));
37585587Sobrien			else		/* can't happen */
37685587Sobrien				FATAL("bad type variable %d", y->tval);
37785587Sobrien			tempfree(y);
37885587Sobrien		}
37985587Sobrien		return(jret);
38085587Sobrien	case NEXT:
38185587Sobrien		return(jnext);
38285587Sobrien	case NEXTFILE:
38385587Sobrien		nextfile();
38485587Sobrien		return(jnextfile);
38585587Sobrien	case BREAK:
38685587Sobrien		return(jbreak);
38785587Sobrien	case CONTINUE:
38885587Sobrien		return(jcont);
38985587Sobrien	default:	/* can't happen */
39085587Sobrien		FATAL("illegal jump type %d", n);
39185587Sobrien	}
39285587Sobrien	return 0;	/* not reached */
39385587Sobrien}
39485587Sobrien
395201951SruCell *awkgetline(Node **a, int n)	/* get next line from specific input */
39685587Sobrien{		/* a[0] is variable, a[1] is operator, a[2] is filename */
39785587Sobrien	Cell *r, *x;
39885587Sobrien	extern Cell **fldtab;
39985587Sobrien	FILE *fp;
40085587Sobrien	char *buf;
40185587Sobrien	int bufsize = recsize;
40285587Sobrien	int mode;
40385587Sobrien
40485587Sobrien	if ((buf = (char *) malloc(bufsize)) == NULL)
40585587Sobrien		FATAL("out of memory in getline");
40685587Sobrien
40785587Sobrien	fflush(stdout);	/* in case someone is waiting for a prompt */
40885587Sobrien	r = gettemp();
40985587Sobrien	if (a[1] != NULL) {		/* getline < file */
41085587Sobrien		x = execute(a[2]);		/* filename */
41185587Sobrien		mode = ptoi(a[1]);
41285587Sobrien		if (mode == '|')		/* input pipe */
41385587Sobrien			mode = LE;	/* arbitrary flag */
41485587Sobrien		fp = openfile(mode, getsval(x));
41585587Sobrien		tempfree(x);
41685587Sobrien		if (fp == NULL)
41785587Sobrien			n = -1;
41885587Sobrien		else
41985587Sobrien			n = readrec(&buf, &bufsize, fp);
42085587Sobrien		if (n <= 0) {
42185587Sobrien			;
42285587Sobrien		} else if (a[0] != NULL) {	/* getline var <file */
42385587Sobrien			x = execute(a[0]);
42485587Sobrien			setsval(x, buf);
42585587Sobrien			tempfree(x);
42685587Sobrien		} else {			/* getline <file */
42785587Sobrien			setsval(fldtab[0], buf);
42885587Sobrien			if (is_number(fldtab[0]->sval)) {
42985587Sobrien				fldtab[0]->fval = atof(fldtab[0]->sval);
43085587Sobrien				fldtab[0]->tval |= NUM;
43185587Sobrien			}
43285587Sobrien		}
43385587Sobrien	} else {			/* bare getline; use current input */
43485587Sobrien		if (a[0] == NULL)	/* getline */
43585587Sobrien			n = getrec(&record, &recsize, 1);
43685587Sobrien		else {			/* getline var */
43785587Sobrien			n = getrec(&buf, &bufsize, 0);
43885587Sobrien			x = execute(a[0]);
43985587Sobrien			setsval(x, buf);
44085587Sobrien			tempfree(x);
44185587Sobrien		}
44285587Sobrien	}
44385587Sobrien	setfval(r, (Awkfloat) n);
44485587Sobrien	free(buf);
44585587Sobrien	return r;
44685587Sobrien}
44785587Sobrien
44885587SobrienCell *getnf(Node **a, int n)	/* get NF */
44985587Sobrien{
45085587Sobrien	if (donefld == 0)
45185587Sobrien		fldbld();
45285587Sobrien	return (Cell *) a[0];
45385587Sobrien}
45485587Sobrien
45585587SobrienCell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
45685587Sobrien{
45785587Sobrien	Cell *x, *y, *z;
45885587Sobrien	char *s;
45985587Sobrien	Node *np;
46085587Sobrien	char *buf;
46185587Sobrien	int bufsz = recsize;
46285587Sobrien	int nsub = strlen(*SUBSEP);
46385587Sobrien
46485587Sobrien	if ((buf = (char *) malloc(bufsz)) == NULL)
46585587Sobrien		FATAL("out of memory in array");
46685587Sobrien
46785587Sobrien	x = execute(a[0]);	/* Cell* for symbol table */
46885587Sobrien	buf[0] = 0;
46985587Sobrien	for (np = a[1]; np; np = np->nnext) {
47085587Sobrien		y = execute(np);	/* subscript */
47185587Sobrien		s = getsval(y);
472170331Srafan		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "array"))
47385587Sobrien			FATAL("out of memory for %s[%s...]", x->nval, buf);
47485587Sobrien		strcat(buf, s);
47585587Sobrien		if (np->nnext)
47685587Sobrien			strcat(buf, *SUBSEP);
47785587Sobrien		tempfree(y);
47885587Sobrien	}
47985587Sobrien	if (!isarr(x)) {
480107806Sobrien		   dprintf( ("making %s into an array\n", NN(x->nval)) );
48185587Sobrien		if (freeable(x))
48285587Sobrien			xfree(x->sval);
48385587Sobrien		x->tval &= ~(STR|NUM|DONTFREE);
48485587Sobrien		x->tval |= ARR;
48585587Sobrien		x->sval = (char *) makesymtab(NSYMTAB);
48685587Sobrien	}
48785587Sobrien	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
48885587Sobrien	z->ctype = OCELL;
48985587Sobrien	z->csub = CVAR;
49085587Sobrien	tempfree(x);
49185587Sobrien	free(buf);
49285587Sobrien	return(z);
49385587Sobrien}
49485587Sobrien
49585587SobrienCell *awkdelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
49685587Sobrien{
49785587Sobrien	Cell *x, *y;
49885587Sobrien	Node *np;
49985587Sobrien	char *s;
50085587Sobrien	int nsub = strlen(*SUBSEP);
50185587Sobrien
50285587Sobrien	x = execute(a[0]);	/* Cell* for symbol table */
50385587Sobrien	if (!isarr(x))
50485587Sobrien		return True;
50585587Sobrien	if (a[1] == 0) {	/* delete the elements, not the table */
50685587Sobrien		freesymtab(x);
50785587Sobrien		x->tval &= ~STR;
50885587Sobrien		x->tval |= ARR;
50985587Sobrien		x->sval = (char *) makesymtab(NSYMTAB);
51085587Sobrien	} else {
51185587Sobrien		int bufsz = recsize;
51285587Sobrien		char *buf;
51385587Sobrien		if ((buf = (char *) malloc(bufsz)) == NULL)
51485587Sobrien			FATAL("out of memory in adelete");
51585587Sobrien		buf[0] = 0;
51685587Sobrien		for (np = a[1]; np; np = np->nnext) {
51785587Sobrien			y = execute(np);	/* subscript */
51885587Sobrien			s = getsval(y);
519170331Srafan			if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "awkdelete"))
52085587Sobrien				FATAL("out of memory deleting %s[%s...]", x->nval, buf);
52185587Sobrien			strcat(buf, s);
52285587Sobrien			if (np->nnext)
52385587Sobrien				strcat(buf, *SUBSEP);
52485587Sobrien			tempfree(y);
52585587Sobrien		}
52685587Sobrien		freeelem(x, buf);
52785587Sobrien		free(buf);
52885587Sobrien	}
52985587Sobrien	tempfree(x);
53085587Sobrien	return True;
53185587Sobrien}
53285587Sobrien
53385587SobrienCell *intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
53485587Sobrien{
53585587Sobrien	Cell *x, *ap, *k;
53685587Sobrien	Node *p;
53785587Sobrien	char *buf;
53885587Sobrien	char *s;
53985587Sobrien	int bufsz = recsize;
54085587Sobrien	int nsub = strlen(*SUBSEP);
54185587Sobrien
54285587Sobrien	ap = execute(a[1]);	/* array name */
54385587Sobrien	if (!isarr(ap)) {
54485587Sobrien		   dprintf( ("making %s into an array\n", ap->nval) );
54585587Sobrien		if (freeable(ap))
54685587Sobrien			xfree(ap->sval);
54785587Sobrien		ap->tval &= ~(STR|NUM|DONTFREE);
54885587Sobrien		ap->tval |= ARR;
54985587Sobrien		ap->sval = (char *) makesymtab(NSYMTAB);
55085587Sobrien	}
55185587Sobrien	if ((buf = (char *) malloc(bufsz)) == NULL) {
55285587Sobrien		FATAL("out of memory in intest");
55385587Sobrien	}
55485587Sobrien	buf[0] = 0;
55585587Sobrien	for (p = a[0]; p; p = p->nnext) {
55685587Sobrien		x = execute(p);	/* expr */
55785587Sobrien		s = getsval(x);
558170331Srafan		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "intest"))
55985587Sobrien			FATAL("out of memory deleting %s[%s...]", x->nval, buf);
56085587Sobrien		strcat(buf, s);
56185587Sobrien		tempfree(x);
56285587Sobrien		if (p->nnext)
56385587Sobrien			strcat(buf, *SUBSEP);
56485587Sobrien	}
56585587Sobrien	k = lookup(buf, (Array *) ap->sval);
56685587Sobrien	tempfree(ap);
56785587Sobrien	free(buf);
56885587Sobrien	if (k == NULL)
56985587Sobrien		return(False);
57085587Sobrien	else
57185587Sobrien		return(True);
57285587Sobrien}
57385587Sobrien
57485587Sobrien
57585587SobrienCell *matchop(Node **a, int n)	/* ~ and match() */
57685587Sobrien{
57785587Sobrien	Cell *x, *y;
57885587Sobrien	char *s, *t;
57985587Sobrien	int i;
58085587Sobrien	fa *pfa;
581107806Sobrien	int (*mf)(fa *, const char *) = match, mode = 0;
58285587Sobrien
58385587Sobrien	if (n == MATCHFCN) {
58485587Sobrien		mf = pmatch;
58585587Sobrien		mode = 1;
58685587Sobrien	}
58785587Sobrien	x = execute(a[1]);	/* a[1] = target text */
58885587Sobrien	s = getsval(x);
58985587Sobrien	if (a[0] == 0)		/* a[1] == 0: already-compiled reg expr */
59085587Sobrien		i = (*mf)((fa *) a[2], s);
59185587Sobrien	else {
59285587Sobrien		y = execute(a[2]);	/* a[2] = regular expr */
59385587Sobrien		t = getsval(y);
59485587Sobrien		pfa = makedfa(t, mode);
59585587Sobrien		i = (*mf)(pfa, s);
59685587Sobrien		tempfree(y);
59785587Sobrien	}
59885587Sobrien	tempfree(x);
59985587Sobrien	if (n == MATCHFCN) {
60085587Sobrien		int start = patbeg - s + 1;
60185587Sobrien		if (patlen < 0)
60285587Sobrien			start = 0;
60385587Sobrien		setfval(rstartloc, (Awkfloat) start);
60485587Sobrien		setfval(rlengthloc, (Awkfloat) patlen);
60585587Sobrien		x = gettemp();
60685587Sobrien		x->tval = NUM;
60785587Sobrien		x->fval = start;
60885587Sobrien		return x;
60985587Sobrien	} else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
61085587Sobrien		return(True);
61185587Sobrien	else
61285587Sobrien		return(False);
61385587Sobrien}
61485587Sobrien
61585587Sobrien
61685587SobrienCell *boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
61785587Sobrien{
61885587Sobrien	Cell *x, *y;
61985587Sobrien	int i;
62085587Sobrien
62185587Sobrien	x = execute(a[0]);
62285587Sobrien	i = istrue(x);
62385587Sobrien	tempfree(x);
62485587Sobrien	switch (n) {
62585587Sobrien	case BOR:
62685587Sobrien		if (i) return(True);
62785587Sobrien		y = execute(a[1]);
62885587Sobrien		i = istrue(y);
62985587Sobrien		tempfree(y);
63085587Sobrien		if (i) return(True);
63185587Sobrien		else return(False);
63285587Sobrien	case AND:
63385587Sobrien		if ( !i ) return(False);
63485587Sobrien		y = execute(a[1]);
63585587Sobrien		i = istrue(y);
63685587Sobrien		tempfree(y);
63785587Sobrien		if (i) return(True);
63885587Sobrien		else return(False);
63985587Sobrien	case NOT:
64085587Sobrien		if (i) return(False);
64185587Sobrien		else return(True);
64285587Sobrien	default:	/* can't happen */
64385587Sobrien		FATAL("unknown boolean operator %d", n);
64485587Sobrien	}
64585587Sobrien	return 0;	/*NOTREACHED*/
64685587Sobrien}
64785587Sobrien
64885587SobrienCell *relop(Node **a, int n)	/* a[0 < a[1], etc. */
64985587Sobrien{
65085587Sobrien	int i;
65185587Sobrien	Cell *x, *y;
65285587Sobrien	Awkfloat j;
65385587Sobrien
65485587Sobrien	x = execute(a[0]);
65585587Sobrien	y = execute(a[1]);
65685587Sobrien	if (x->tval&NUM && y->tval&NUM) {
65785587Sobrien		j = x->fval - y->fval;
65885587Sobrien		i = j<0? -1: (j>0? 1: 0);
65985587Sobrien	} else {
660201989Sru		i = strcoll(getsval(x), getsval(y));
66185587Sobrien	}
66285587Sobrien	tempfree(x);
66385587Sobrien	tempfree(y);
66485587Sobrien	switch (n) {
66585587Sobrien	case LT:	if (i<0) return(True);
66685587Sobrien			else return(False);
66785587Sobrien	case LE:	if (i<=0) return(True);
66885587Sobrien			else return(False);
66985587Sobrien	case NE:	if (i!=0) return(True);
67085587Sobrien			else return(False);
67185587Sobrien	case EQ:	if (i == 0) return(True);
67285587Sobrien			else return(False);
67385587Sobrien	case GE:	if (i>=0) return(True);
67485587Sobrien			else return(False);
67585587Sobrien	case GT:	if (i>0) return(True);
67685587Sobrien			else return(False);
67785587Sobrien	default:	/* can't happen */
67885587Sobrien		FATAL("unknown relational operator %d", n);
67985587Sobrien	}
68085587Sobrien	return 0;	/*NOTREACHED*/
68185587Sobrien}
68285587Sobrien
68385587Sobrienvoid tfree(Cell *a)	/* free a tempcell */
68485587Sobrien{
68585587Sobrien	if (freeable(a)) {
686107806Sobrien		   dprintf( ("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval) );
68785587Sobrien		xfree(a->sval);
68885587Sobrien	}
68985587Sobrien	if (a == tmps)
69085587Sobrien		FATAL("tempcell list is curdled");
69185587Sobrien	a->cnext = tmps;
69285587Sobrien	tmps = a;
69385587Sobrien}
69485587Sobrien
69585587SobrienCell *gettemp(void)	/* get a tempcell */
69685587Sobrien{	int i;
69785587Sobrien	Cell *x;
69885587Sobrien
69985587Sobrien	if (!tmps) {
70085587Sobrien		tmps = (Cell *) calloc(100, sizeof(Cell));
70185587Sobrien		if (!tmps)
70285587Sobrien			FATAL("out of space for temporaries");
70385587Sobrien		for(i = 1; i < 100; i++)
70485587Sobrien			tmps[i-1].cnext = &tmps[i];
70585587Sobrien		tmps[i-1].cnext = 0;
70685587Sobrien	}
70785587Sobrien	x = tmps;
70885587Sobrien	tmps = x->cnext;
70985587Sobrien	*x = tempcell;
71085587Sobrien	return(x);
71185587Sobrien}
71285587Sobrien
71385587SobrienCell *indirect(Node **a, int n)	/* $( a[0] ) */
71485587Sobrien{
715146299Sru	Awkfloat val;
71685587Sobrien	Cell *x;
71785587Sobrien	int m;
71885587Sobrien	char *s;
71985587Sobrien
72085587Sobrien	x = execute(a[0]);
721146299Sru	val = getfval(x);	/* freebsd: defend against super large field numbers */
722146299Sru	if ((Awkfloat)INT_MAX < val)
723146299Sru		FATAL("trying to access out of range field %s", x->nval);
724146299Sru	m = (int) val;
72585587Sobrien	if (m == 0 && !is_number(s = getsval(x)))	/* suspicion! */
72685587Sobrien		FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
72785587Sobrien		/* BUG: can x->nval ever be null??? */
72885587Sobrien	tempfree(x);
72985587Sobrien	x = fieldadr(m);
73085587Sobrien	x->ctype = OCELL;	/* BUG?  why are these needed? */
73185587Sobrien	x->csub = CFLD;
73285587Sobrien	return(x);
73385587Sobrien}
73485587Sobrien
73585587SobrienCell *substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
73685587Sobrien{
73785587Sobrien	int k, m, n;
73885587Sobrien	char *s;
73985587Sobrien	int temp;
74085587Sobrien	Cell *x, *y, *z = 0;
74185587Sobrien
74285587Sobrien	x = execute(a[0]);
74385587Sobrien	y = execute(a[1]);
74485587Sobrien	if (a[2] != 0)
74585587Sobrien		z = execute(a[2]);
74685587Sobrien	s = getsval(x);
74785587Sobrien	k = strlen(s) + 1;
74885587Sobrien	if (k <= 1) {
74985587Sobrien		tempfree(x);
75085587Sobrien		tempfree(y);
75185587Sobrien		if (a[2] != 0) {
75285587Sobrien			tempfree(z);
75385587Sobrien		}
75485587Sobrien		x = gettemp();
75585587Sobrien		setsval(x, "");
75685587Sobrien		return(x);
75785587Sobrien	}
75885587Sobrien	m = (int) getfval(y);
75985587Sobrien	if (m <= 0)
76085587Sobrien		m = 1;
76185587Sobrien	else if (m > k)
76285587Sobrien		m = k;
76385587Sobrien	tempfree(y);
76485587Sobrien	if (a[2] != 0) {
76585587Sobrien		n = (int) getfval(z);
76685587Sobrien		tempfree(z);
76785587Sobrien	} else
76885587Sobrien		n = k - 1;
76985587Sobrien	if (n < 0)
77085587Sobrien		n = 0;
77185587Sobrien	else if (n > k - m)
77285587Sobrien		n = k - m;
77385587Sobrien	   dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
77485587Sobrien	y = gettemp();
77585587Sobrien	temp = s[n+m-1];	/* with thanks to John Linderman */
77685587Sobrien	s[n+m-1] = '\0';
77785587Sobrien	setsval(y, s + m - 1);
77885587Sobrien	s[n+m-1] = temp;
77985587Sobrien	tempfree(x);
78085587Sobrien	return(y);
78185587Sobrien}
78285587Sobrien
78385587SobrienCell *sindex(Node **a, int nnn)		/* index(a[0], a[1]) */
78485587Sobrien{
78585587Sobrien	Cell *x, *y, *z;
78685587Sobrien	char *s1, *s2, *p1, *p2, *q;
78785587Sobrien	Awkfloat v = 0.0;
78885587Sobrien
78985587Sobrien	x = execute(a[0]);
79085587Sobrien	s1 = getsval(x);
79185587Sobrien	y = execute(a[1]);
79285587Sobrien	s2 = getsval(y);
79385587Sobrien
79485587Sobrien	z = gettemp();
79585587Sobrien	for (p1 = s1; *p1 != '\0'; p1++) {
79685587Sobrien		for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
79785587Sobrien			;
79885587Sobrien		if (*p2 == '\0') {
79985587Sobrien			v = (Awkfloat) (p1 - s1 + 1);	/* origin 1 */
80085587Sobrien			break;
80185587Sobrien		}
80285587Sobrien	}
80385587Sobrien	tempfree(x);
80485587Sobrien	tempfree(y);
80585587Sobrien	setfval(z, v);
80685587Sobrien	return(z);
80785587Sobrien}
80885587Sobrien
80985587Sobrien#define	MAXNUMSIZE	50
81085587Sobrien
811107806Sobrienint format(char **pbuf, int *pbufsize, const char *s, Node *a)	/* printf-like conversions */
81285587Sobrien{
81385587Sobrien	char *fmt;
814107806Sobrien	char *p, *t;
815107806Sobrien	const char *os;
81685587Sobrien	Cell *x;
81785587Sobrien	int flag = 0, n;
81885587Sobrien	int fmtwd; /* format width */
81985587Sobrien	int fmtsz = recsize;
82085587Sobrien	char *buf = *pbuf;
82185587Sobrien	int bufsize = *pbufsize;
82285587Sobrien
82385587Sobrien	os = s;
82485587Sobrien	p = buf;
82585587Sobrien	if ((fmt = (char *) malloc(fmtsz)) == NULL)
82685587Sobrien		FATAL("out of memory in format()");
82785587Sobrien	while (*s) {
828170331Srafan		adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1");
82985587Sobrien		if (*s != '%') {
83085587Sobrien			*p++ = *s++;
83185587Sobrien			continue;
83285587Sobrien		}
83385587Sobrien		if (*(s+1) == '%') {
83485587Sobrien			*p++ = '%';
83585587Sobrien			s += 2;
83685587Sobrien			continue;
83785587Sobrien		}
83885587Sobrien		/* have to be real careful in case this is a huge number, eg, %100000d */
83985587Sobrien		fmtwd = atoi(s+1);
84085587Sobrien		if (fmtwd < 0)
84185587Sobrien			fmtwd = -fmtwd;
842170331Srafan		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format2");
84385587Sobrien		for (t = fmt; (*t++ = *s) != '\0'; s++) {
844170331Srafan			if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3"))
84585587Sobrien				FATAL("format item %.30s... ran format() out of memory", os);
84685587Sobrien			if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L')
84785587Sobrien				break;	/* the ansi panoply */
84885587Sobrien			if (*s == '*') {
84985587Sobrien				x = execute(a);
85085587Sobrien				a = a->nnext;
85185587Sobrien				sprintf(t-1, "%d", fmtwd=(int) getfval(x));
85285587Sobrien				if (fmtwd < 0)
85385587Sobrien					fmtwd = -fmtwd;
85485587Sobrien				adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
85585587Sobrien				t = fmt + strlen(fmt);
85685587Sobrien				tempfree(x);
85785587Sobrien			}
85885587Sobrien		}
85985587Sobrien		*t = '\0';
86085587Sobrien		if (fmtwd < 0)
86185587Sobrien			fmtwd = -fmtwd;
862170331Srafan		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format4");
86385587Sobrien
86485587Sobrien		switch (*s) {
86585587Sobrien		case 'f': case 'e': case 'g': case 'E': case 'G':
866107806Sobrien			flag = 'f';
86785587Sobrien			break;
86885587Sobrien		case 'd': case 'i':
869107806Sobrien			flag = 'd';
87085587Sobrien			if(*(s-1) == 'l') break;
87185587Sobrien			*(t-1) = 'l';
87285587Sobrien			*t = 'd';
87385587Sobrien			*++t = '\0';
87485587Sobrien			break;
87585587Sobrien		case 'o': case 'x': case 'X': case 'u':
876107806Sobrien			flag = *(s-1) == 'l' ? 'd' : 'u';
87785587Sobrien			break;
87885587Sobrien		case 's':
879107806Sobrien			flag = 's';
88085587Sobrien			break;
88185587Sobrien		case 'c':
882107806Sobrien			flag = 'c';
88385587Sobrien			break;
88485587Sobrien		default:
88585587Sobrien			WARNING("weird printf conversion %s", fmt);
886107806Sobrien			flag = '?';
88785587Sobrien			break;
88885587Sobrien		}
88985587Sobrien		if (a == NULL)
89085587Sobrien			FATAL("not enough args in printf(%s)", os);
89185587Sobrien		x = execute(a);
89285587Sobrien		a = a->nnext;
89385587Sobrien		n = MAXNUMSIZE;
89485587Sobrien		if (fmtwd > n)
89585587Sobrien			n = fmtwd;
896170331Srafan		adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5");
89785587Sobrien		switch (flag) {
898107806Sobrien		case '?':	sprintf(p, "%s", fmt);	/* unknown, so dump it too */
89985587Sobrien			t = getsval(x);
90085587Sobrien			n = strlen(t);
90185587Sobrien			if (fmtwd > n)
90285587Sobrien				n = fmtwd;
903170331Srafan			adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6");
90485587Sobrien			p += strlen(p);
90585587Sobrien			sprintf(p, "%s", t);
90685587Sobrien			break;
907107806Sobrien		case 'f':	sprintf(p, fmt, getfval(x)); break;
908107806Sobrien		case 'd':	sprintf(p, fmt, (long) getfval(x)); break;
909107806Sobrien		case 'u':	sprintf(p, fmt, (int) getfval(x)); break;
910107806Sobrien		case 's':
91185587Sobrien			t = getsval(x);
91285587Sobrien			n = strlen(t);
91385587Sobrien			if (fmtwd > n)
91485587Sobrien				n = fmtwd;
915170331Srafan			if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7"))
91685587Sobrien				FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
91785587Sobrien			sprintf(p, fmt, t);
91885587Sobrien			break;
919107806Sobrien		case 'c':
92085587Sobrien			if (isnum(x)) {
92185587Sobrien				if (getfval(x))
92285587Sobrien					sprintf(p, fmt, (int) getfval(x));
923107806Sobrien				else {
924107806Sobrien					*p++ = '\0'; /* explicit null byte */
925107806Sobrien					*p = '\0';   /* next output will start here */
926107806Sobrien				}
92785587Sobrien			} else
92885587Sobrien				sprintf(p, fmt, getsval(x)[0]);
92985587Sobrien			break;
930107806Sobrien		default:
931107806Sobrien			FATAL("can't happen: bad conversion %c in format()", flag);
93285587Sobrien		}
93385587Sobrien		tempfree(x);
93485587Sobrien		p += strlen(p);
93585587Sobrien		s++;
93685587Sobrien	}
93785587Sobrien	*p = '\0';
93885587Sobrien	free(fmt);
93985587Sobrien	for ( ; a; a = a->nnext)		/* evaluate any remaining args */
94085587Sobrien		execute(a);
94185587Sobrien	*pbuf = buf;
94285587Sobrien	*pbufsize = bufsize;
94385587Sobrien	return p - buf;
94485587Sobrien}
94585587Sobrien
94685587SobrienCell *awksprintf(Node **a, int n)		/* sprintf(a[0]) */
94785587Sobrien{
94885587Sobrien	Cell *x;
94985587Sobrien	Node *y;
95085587Sobrien	char *buf;
95185587Sobrien	int bufsz=3*recsize;
95285587Sobrien
95385587Sobrien	if ((buf = (char *) malloc(bufsz)) == NULL)
95485587Sobrien		FATAL("out of memory in awksprintf");
95585587Sobrien	y = a[0]->nnext;
95685587Sobrien	x = execute(a[0]);
95785587Sobrien	if (format(&buf, &bufsz, getsval(x), y) == -1)
95885587Sobrien		FATAL("sprintf string %.30s... too long.  can't happen.", buf);
95985587Sobrien	tempfree(x);
96085587Sobrien	x = gettemp();
96185587Sobrien	x->sval = buf;
96285587Sobrien	x->tval = STR;
96385587Sobrien	return(x);
96485587Sobrien}
96585587Sobrien
96685587SobrienCell *awkprintf(Node **a, int n)		/* printf */
96785587Sobrien{	/* a[0] is list of args, starting with format string */
96885587Sobrien	/* a[1] is redirection operator, a[2] is redirection file */
96985587Sobrien	FILE *fp;
97085587Sobrien	Cell *x;
97185587Sobrien	Node *y;
97285587Sobrien	char *buf;
97385587Sobrien	int len;
97485587Sobrien	int bufsz=3*recsize;
97585587Sobrien
97685587Sobrien	if ((buf = (char *) malloc(bufsz)) == NULL)
97785587Sobrien		FATAL("out of memory in awkprintf");
97885587Sobrien	y = a[0]->nnext;
97985587Sobrien	x = execute(a[0]);
98085587Sobrien	if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
98185587Sobrien		FATAL("printf string %.30s... too long.  can't happen.", buf);
98285587Sobrien	tempfree(x);
98385587Sobrien	if (a[1] == NULL) {
98485587Sobrien		/* fputs(buf, stdout); */
98585587Sobrien		fwrite(buf, len, 1, stdout);
98685587Sobrien		if (ferror(stdout))
98785587Sobrien			FATAL("write error on stdout");
98885587Sobrien	} else {
98985587Sobrien		fp = redirect(ptoi(a[1]), a[2]);
99085587Sobrien		/* fputs(buf, fp); */
99185587Sobrien		fwrite(buf, len, 1, fp);
99285587Sobrien		fflush(fp);
99385587Sobrien		if (ferror(fp))
99485587Sobrien			FATAL("write error on %s", filename(fp));
99585587Sobrien	}
99685587Sobrien	free(buf);
99785587Sobrien	return(True);
99885587Sobrien}
99985587Sobrien
100085587SobrienCell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
100185587Sobrien{
100285587Sobrien	Awkfloat i, j = 0;
100385587Sobrien	double v;
100485587Sobrien	Cell *x, *y, *z;
100585587Sobrien
100685587Sobrien	x = execute(a[0]);
100785587Sobrien	i = getfval(x);
100885587Sobrien	tempfree(x);
100985587Sobrien	if (n != UMINUS) {
101085587Sobrien		y = execute(a[1]);
101185587Sobrien		j = getfval(y);
101285587Sobrien		tempfree(y);
101385587Sobrien	}
101485587Sobrien	z = gettemp();
101585587Sobrien	switch (n) {
101685587Sobrien	case ADD:
101785587Sobrien		i += j;
101885587Sobrien		break;
101985587Sobrien	case MINUS:
102085587Sobrien		i -= j;
102185587Sobrien		break;
102285587Sobrien	case MULT:
102385587Sobrien		i *= j;
102485587Sobrien		break;
102585587Sobrien	case DIVIDE:
102685587Sobrien		if (j == 0)
102785587Sobrien			FATAL("division by zero");
102885587Sobrien		i /= j;
102985587Sobrien		break;
103085587Sobrien	case MOD:
103185587Sobrien		if (j == 0)
103285587Sobrien			FATAL("division by zero in mod");
103385587Sobrien		modf(i/j, &v);
103485587Sobrien		i = i - j * v;
103585587Sobrien		break;
103685587Sobrien	case UMINUS:
103785587Sobrien		i = -i;
103885587Sobrien		break;
103985587Sobrien	case POWER:
104085587Sobrien		if (j >= 0 && modf(j, &v) == 0.0)	/* pos integer exponent */
104185587Sobrien			i = ipow(i, (int) j);
104285587Sobrien		else
104385587Sobrien			i = errcheck(pow(i, j), "pow");
104485587Sobrien		break;
104585587Sobrien	default:	/* can't happen */
104685587Sobrien		FATAL("illegal arithmetic operator %d", n);
104785587Sobrien	}
104885587Sobrien	setfval(z, i);
104985587Sobrien	return(z);
105085587Sobrien}
105185587Sobrien
105285587Sobriendouble ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
105385587Sobrien{
105485587Sobrien	double v;
105585587Sobrien
105685587Sobrien	if (n <= 0)
105785587Sobrien		return 1;
105885587Sobrien	v = ipow(x, n/2);
105985587Sobrien	if (n % 2 == 0)
106085587Sobrien		return v * v;
106185587Sobrien	else
106285587Sobrien		return x * v * v;
106385587Sobrien}
106485587Sobrien
106585587SobrienCell *incrdecr(Node **a, int n)		/* a[0]++, etc. */
106685587Sobrien{
106785587Sobrien	Cell *x, *z;
106885587Sobrien	int k;
106985587Sobrien	Awkfloat xf;
107085587Sobrien
107185587Sobrien	x = execute(a[0]);
107285587Sobrien	xf = getfval(x);
107385587Sobrien	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
107485587Sobrien	if (n == PREINCR || n == PREDECR) {
107585587Sobrien		setfval(x, xf + k);
107685587Sobrien		return(x);
107785587Sobrien	}
107885587Sobrien	z = gettemp();
107985587Sobrien	setfval(z, xf);
108085587Sobrien	setfval(x, xf + k);
108185587Sobrien	tempfree(x);
108285587Sobrien	return(z);
108385587Sobrien}
108485587Sobrien
108585587SobrienCell *assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
108685587Sobrien{		/* this is subtle; don't muck with it. */
108785587Sobrien	Cell *x, *y;
108885587Sobrien	Awkfloat xf, yf;
108985587Sobrien	double v;
109085587Sobrien
109185587Sobrien	y = execute(a[1]);
109285587Sobrien	x = execute(a[0]);
109385587Sobrien	if (n == ASSIGN) {	/* ordinary assignment */
109485587Sobrien		if (x == y && !(x->tval & (FLD|REC)))	/* self-assignment: */
109585587Sobrien			;		/* leave alone unless it's a field */
109685587Sobrien		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
109785587Sobrien			setsval(x, getsval(y));
109885587Sobrien			x->fval = getfval(y);
109985587Sobrien			x->tval |= NUM;
110085587Sobrien		}
110185587Sobrien		else if (isstr(y))
110285587Sobrien			setsval(x, getsval(y));
110385587Sobrien		else if (isnum(y))
110485587Sobrien			setfval(x, getfval(y));
110585587Sobrien		else
110685587Sobrien			funnyvar(y, "read value of");
110785587Sobrien		tempfree(y);
110885587Sobrien		return(x);
110985587Sobrien	}
111085587Sobrien	xf = getfval(x);
111185587Sobrien	yf = getfval(y);
111285587Sobrien	switch (n) {
111385587Sobrien	case ADDEQ:
111485587Sobrien		xf += yf;
111585587Sobrien		break;
111685587Sobrien	case SUBEQ:
111785587Sobrien		xf -= yf;
111885587Sobrien		break;
111985587Sobrien	case MULTEQ:
112085587Sobrien		xf *= yf;
112185587Sobrien		break;
112285587Sobrien	case DIVEQ:
112385587Sobrien		if (yf == 0)
112485587Sobrien			FATAL("division by zero in /=");
112585587Sobrien		xf /= yf;
112685587Sobrien		break;
112785587Sobrien	case MODEQ:
112885587Sobrien		if (yf == 0)
112985587Sobrien			FATAL("division by zero in %%=");
113085587Sobrien		modf(xf/yf, &v);
113185587Sobrien		xf = xf - yf * v;
113285587Sobrien		break;
113385587Sobrien	case POWEQ:
113485587Sobrien		if (yf >= 0 && modf(yf, &v) == 0.0)	/* pos integer exponent */
113585587Sobrien			xf = ipow(xf, (int) yf);
113685587Sobrien		else
113785587Sobrien			xf = errcheck(pow(xf, yf), "pow");
113885587Sobrien		break;
113985587Sobrien	default:
114085587Sobrien		FATAL("illegal assignment operator %d", n);
114185587Sobrien		break;
114285587Sobrien	}
114385587Sobrien	tempfree(y);
114485587Sobrien	setfval(x, xf);
114585587Sobrien	return(x);
114685587Sobrien}
114785587Sobrien
114885587SobrienCell *cat(Node **a, int q)	/* a[0] cat a[1] */
114985587Sobrien{
115085587Sobrien	Cell *x, *y, *z;
115185587Sobrien	int n1, n2;
115285587Sobrien	char *s;
115385587Sobrien
115485587Sobrien	x = execute(a[0]);
115585587Sobrien	y = execute(a[1]);
115685587Sobrien	getsval(x);
115785587Sobrien	getsval(y);
115885587Sobrien	n1 = strlen(x->sval);
115985587Sobrien	n2 = strlen(y->sval);
116085587Sobrien	s = (char *) malloc(n1 + n2 + 1);
116185587Sobrien	if (s == NULL)
116285587Sobrien		FATAL("out of space concatenating %.15s... and %.15s...",
116385587Sobrien			x->sval, y->sval);
116485587Sobrien	strcpy(s, x->sval);
116585587Sobrien	strcpy(s+n1, y->sval);
1166201951Sru	tempfree(x);
116785587Sobrien	tempfree(y);
116885587Sobrien	z = gettemp();
116985587Sobrien	z->sval = s;
117085587Sobrien	z->tval = STR;
117185587Sobrien	return(z);
117285587Sobrien}
117385587Sobrien
117485587SobrienCell *pastat(Node **a, int n)	/* a[0] { a[1] } */
117585587Sobrien{
117685587Sobrien	Cell *x;
117785587Sobrien
117885587Sobrien	if (a[0] == 0)
117985587Sobrien		x = execute(a[1]);
118085587Sobrien	else {
118185587Sobrien		x = execute(a[0]);
118285587Sobrien		if (istrue(x)) {
118385587Sobrien			tempfree(x);
118485587Sobrien			x = execute(a[1]);
118585587Sobrien		}
118685587Sobrien	}
118785587Sobrien	return x;
118885587Sobrien}
118985587Sobrien
119085587SobrienCell *dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
119185587Sobrien{
119285587Sobrien	Cell *x;
119385587Sobrien	int pair;
119485587Sobrien
119585587Sobrien	pair = ptoi(a[3]);
119685587Sobrien	if (pairstack[pair] == 0) {
119785587Sobrien		x = execute(a[0]);
119885587Sobrien		if (istrue(x))
119985587Sobrien			pairstack[pair] = 1;
120085587Sobrien		tempfree(x);
120185587Sobrien	}
120285587Sobrien	if (pairstack[pair] == 1) {
120385587Sobrien		x = execute(a[1]);
120485587Sobrien		if (istrue(x))
120585587Sobrien			pairstack[pair] = 0;
120685587Sobrien		tempfree(x);
120785587Sobrien		x = execute(a[2]);
120885587Sobrien		return(x);
120985587Sobrien	}
121085587Sobrien	return(False);
121185587Sobrien}
121285587Sobrien
121385587SobrienCell *split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
121485587Sobrien{
121585587Sobrien	Cell *x = 0, *y, *ap;
1216244988Sdelphij	char *s, *origs;
121785587Sobrien	int sep;
121885587Sobrien	char *t, temp, num[50], *fs = 0;
121985587Sobrien	int n, tempstat, arg3type;
122085587Sobrien
122185587Sobrien	y = execute(a[0]);	/* source string */
1222244988Sdelphij	origs = s = strdup(getsval(y));
122385587Sobrien	arg3type = ptoi(a[3]);
122485587Sobrien	if (a[2] == 0)		/* fs string */
122585587Sobrien		fs = *FS;
122685587Sobrien	else if (arg3type == STRING) {	/* split(str,arr,"string") */
122785587Sobrien		x = execute(a[2]);
122885587Sobrien		fs = getsval(x);
122985587Sobrien	} else if (arg3type == REGEXPR)
123085587Sobrien		fs = "(regexpr)";	/* split(str,arr,/regexpr/) */
123185587Sobrien	else
123285587Sobrien		FATAL("illegal type of split");
123385587Sobrien	sep = *fs;
123485587Sobrien	ap = execute(a[1]);	/* array name */
123585587Sobrien	freesymtab(ap);
1236107806Sobrien	   dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs) );
123785587Sobrien	ap->tval &= ~STR;
123885587Sobrien	ap->tval |= ARR;
123985587Sobrien	ap->sval = (char *) makesymtab(NSYMTAB);
124085587Sobrien
124185587Sobrien	n = 0;
1242224731Sru        if (arg3type == REGEXPR && strlen((char*)((fa*)a[2])->restr) == 0) {
1243224731Sru		/* split(s, a, //); have to arrange that it looks like empty sep */
1244224731Sru		arg3type = 0;
1245224731Sru		fs = "";
1246224731Sru		sep = 0;
1247224731Sru	}
1248118194Sru	if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) {	/* reg expr */
124985587Sobrien		fa *pfa;
125085587Sobrien		if (arg3type == REGEXPR) {	/* it's ready already */
125185587Sobrien			pfa = (fa *) a[2];
125285587Sobrien		} else {
125385587Sobrien			pfa = makedfa(fs, 1);
125485587Sobrien		}
125585587Sobrien		if (nematch(pfa,s)) {
125685587Sobrien			tempstat = pfa->initstat;
125785587Sobrien			pfa->initstat = 2;
125885587Sobrien			do {
125985587Sobrien				n++;
126085587Sobrien				sprintf(num, "%d", n);
126185587Sobrien				temp = *patbeg;
126285587Sobrien				*patbeg = '\0';
126385587Sobrien				if (is_number(s))
126485587Sobrien					setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
126585587Sobrien				else
126685587Sobrien					setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
126785587Sobrien				*patbeg = temp;
126885587Sobrien				s = patbeg + patlen;
126985587Sobrien				if (*(patbeg+patlen-1) == 0 || *s == 0) {
127085587Sobrien					n++;
127185587Sobrien					sprintf(num, "%d", n);
127285587Sobrien					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
127385587Sobrien					pfa->initstat = tempstat;
127485587Sobrien					goto spdone;
127585587Sobrien				}
127685587Sobrien			} while (nematch(pfa,s));
1277146299Sru			pfa->initstat = tempstat; 	/* bwk: has to be here to reset */
1278146299Sru							/* cf gsub and refldbld */
127985587Sobrien		}
128085587Sobrien		n++;
128185587Sobrien		sprintf(num, "%d", n);
128285587Sobrien		if (is_number(s))
128385587Sobrien			setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
128485587Sobrien		else
128585587Sobrien			setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
128685587Sobrien  spdone:
128785587Sobrien		pfa = NULL;
128885587Sobrien	} else if (sep == ' ') {
128985587Sobrien		for (n = 0; ; ) {
129085587Sobrien			while (*s == ' ' || *s == '\t' || *s == '\n')
129185587Sobrien				s++;
129285587Sobrien			if (*s == 0)
129385587Sobrien				break;
129485587Sobrien			n++;
129585587Sobrien			t = s;
129685587Sobrien			do
129785587Sobrien				s++;
129885587Sobrien			while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
129985587Sobrien			temp = *s;
130085587Sobrien			*s = '\0';
130185587Sobrien			sprintf(num, "%d", n);
130285587Sobrien			if (is_number(t))
130385587Sobrien				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
130485587Sobrien			else
130585587Sobrien				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
130685587Sobrien			*s = temp;
130785587Sobrien			if (*s != 0)
130885587Sobrien				s++;
130985587Sobrien		}
131085587Sobrien	} else if (sep == 0) {	/* new: split(s, a, "") => 1 char/elem */
131185587Sobrien		for (n = 0; *s != 0; s++) {
131285587Sobrien			char buf[2];
131385587Sobrien			n++;
131485587Sobrien			sprintf(num, "%d", n);
131585587Sobrien			buf[0] = *s;
131685587Sobrien			buf[1] = 0;
131785587Sobrien			if (isdigit((uschar)buf[0]))
131885587Sobrien				setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
131985587Sobrien			else
132085587Sobrien				setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
132185587Sobrien		}
132285587Sobrien	} else if (*s != 0) {
132385587Sobrien		for (;;) {
132485587Sobrien			n++;
132585587Sobrien			t = s;
132685587Sobrien			while (*s != sep && *s != '\n' && *s != '\0')
132785587Sobrien				s++;
132885587Sobrien			temp = *s;
132985587Sobrien			*s = '\0';
133085587Sobrien			sprintf(num, "%d", n);
133185587Sobrien			if (is_number(t))
133285587Sobrien				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
133385587Sobrien			else
133485587Sobrien				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
133585587Sobrien			*s = temp;
133685587Sobrien			if (*s++ == 0)
133785587Sobrien				break;
133885587Sobrien		}
133985587Sobrien	}
134085587Sobrien	tempfree(ap);
134185587Sobrien	tempfree(y);
1342244988Sdelphij	free(origs);
134385587Sobrien	if (a[2] != 0 && arg3type == STRING) {
134485587Sobrien		tempfree(x);
134585587Sobrien	}
134685587Sobrien	x = gettemp();
134785587Sobrien	x->tval = NUM;
134885587Sobrien	x->fval = n;
134985587Sobrien	return(x);
135085587Sobrien}
135185587Sobrien
135285587SobrienCell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
135385587Sobrien{
135485587Sobrien	Cell *x;
135585587Sobrien
135685587Sobrien	x = execute(a[0]);
135785587Sobrien	if (istrue(x)) {
135885587Sobrien		tempfree(x);
135985587Sobrien		x = execute(a[1]);
136085587Sobrien	} else {
136185587Sobrien		tempfree(x);
136285587Sobrien		x = execute(a[2]);
136385587Sobrien	}
136485587Sobrien	return(x);
136585587Sobrien}
136685587Sobrien
136785587SobrienCell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
136885587Sobrien{
136985587Sobrien	Cell *x;
137085587Sobrien
137185587Sobrien	x = execute(a[0]);
137285587Sobrien	if (istrue(x)) {
137385587Sobrien		tempfree(x);
137485587Sobrien		x = execute(a[1]);
137585587Sobrien	} else if (a[2] != 0) {
137685587Sobrien		tempfree(x);
137785587Sobrien		x = execute(a[2]);
137885587Sobrien	}
137985587Sobrien	return(x);
138085587Sobrien}
138185587Sobrien
138285587SobrienCell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
138385587Sobrien{
138485587Sobrien	Cell *x;
138585587Sobrien
138685587Sobrien	for (;;) {
138785587Sobrien		x = execute(a[0]);
138885587Sobrien		if (!istrue(x))
138985587Sobrien			return(x);
139085587Sobrien		tempfree(x);
139185587Sobrien		x = execute(a[1]);
139285587Sobrien		if (isbreak(x)) {
139385587Sobrien			x = True;
139485587Sobrien			return(x);
139585587Sobrien		}
139685587Sobrien		if (isnext(x) || isexit(x) || isret(x))
139785587Sobrien			return(x);
139885587Sobrien		tempfree(x);
139985587Sobrien	}
140085587Sobrien}
140185587Sobrien
140285587SobrienCell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
140385587Sobrien{
140485587Sobrien	Cell *x;
140585587Sobrien
140685587Sobrien	for (;;) {
140785587Sobrien		x = execute(a[0]);
140885587Sobrien		if (isbreak(x))
140985587Sobrien			return True;
141085587Sobrien		if (isnext(x) || isexit(x) || isret(x))
141185587Sobrien			return(x);
141285587Sobrien		tempfree(x);
141385587Sobrien		x = execute(a[1]);
141485587Sobrien		if (!istrue(x))
141585587Sobrien			return(x);
141685587Sobrien		tempfree(x);
141785587Sobrien	}
141885587Sobrien}
141985587Sobrien
142085587SobrienCell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
142185587Sobrien{
142285587Sobrien	Cell *x;
142385587Sobrien
142485587Sobrien	x = execute(a[0]);
142585587Sobrien	tempfree(x);
142685587Sobrien	for (;;) {
142785587Sobrien		if (a[1]!=0) {
142885587Sobrien			x = execute(a[1]);
142985587Sobrien			if (!istrue(x)) return(x);
143085587Sobrien			else tempfree(x);
143185587Sobrien		}
143285587Sobrien		x = execute(a[3]);
143385587Sobrien		if (isbreak(x))		/* turn off break */
143485587Sobrien			return True;
143585587Sobrien		if (isnext(x) || isexit(x) || isret(x))
143685587Sobrien			return(x);
143785587Sobrien		tempfree(x);
143885587Sobrien		x = execute(a[2]);
143985587Sobrien		tempfree(x);
144085587Sobrien	}
144185587Sobrien}
144285587Sobrien
144385587SobrienCell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
144485587Sobrien{
144585587Sobrien	Cell *x, *vp, *arrayp, *cp, *ncp;
144685587Sobrien	Array *tp;
144785587Sobrien	int i;
144885587Sobrien
144985587Sobrien	vp = execute(a[0]);
145085587Sobrien	arrayp = execute(a[1]);
145185587Sobrien	if (!isarr(arrayp)) {
145285587Sobrien		return True;
145385587Sobrien	}
145485587Sobrien	tp = (Array *) arrayp->sval;
145585587Sobrien	tempfree(arrayp);
145685587Sobrien	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
145785587Sobrien		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
145885587Sobrien			setsval(vp, cp->nval);
145985587Sobrien			ncp = cp->cnext;
146085587Sobrien			x = execute(a[2]);
146185587Sobrien			if (isbreak(x)) {
146285587Sobrien				tempfree(vp);
146385587Sobrien				return True;
146485587Sobrien			}
146585587Sobrien			if (isnext(x) || isexit(x) || isret(x)) {
146685587Sobrien				tempfree(vp);
146785587Sobrien				return(x);
146885587Sobrien			}
146985587Sobrien			tempfree(x);
147085587Sobrien		}
147185587Sobrien	}
147285587Sobrien	return True;
147385587Sobrien}
147485587Sobrien
147585587SobrienCell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
147685587Sobrien{
147785587Sobrien	Cell *x, *y;
147885587Sobrien	Awkfloat u;
147985587Sobrien	int t;
1480221381Sru	Awkfloat tmp;
148185587Sobrien	char *p, *buf;
148285587Sobrien	Node *nextarg;
148385587Sobrien	FILE *fp;
148490902Sdes	void flush_all(void);
148585587Sobrien
148685587Sobrien	t = ptoi(a[0]);
148785587Sobrien	x = execute(a[1]);
148885587Sobrien	nextarg = a[1]->nnext;
148985587Sobrien	switch (t) {
149085587Sobrien	case FLENGTH:
149190902Sdes		if (isarr(x))
149290902Sdes			u = ((Array *) x->sval)->nelem;	/* GROT.  should be function*/
149390902Sdes		else
149490902Sdes			u = strlen(getsval(x));
149590902Sdes		break;
149685587Sobrien	case FLOG:
149785587Sobrien		u = errcheck(log(getfval(x)), "log"); break;
149885587Sobrien	case FINT:
149985587Sobrien		modf(getfval(x), &u); break;
150085587Sobrien	case FEXP:
150185587Sobrien		u = errcheck(exp(getfval(x)), "exp"); break;
150285587Sobrien	case FSQRT:
150385587Sobrien		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
150485587Sobrien	case FSIN:
150585587Sobrien		u = sin(getfval(x)); break;
150685587Sobrien	case FCOS:
150785587Sobrien		u = cos(getfval(x)); break;
150885587Sobrien	case FATAN:
150985587Sobrien		if (nextarg == 0) {
151085587Sobrien			WARNING("atan2 requires two arguments; returning 1.0");
151185587Sobrien			u = 1.0;
151285587Sobrien		} else {
151385587Sobrien			y = execute(a[1]->nnext);
151485587Sobrien			u = atan2(getfval(x), getfval(y));
151585587Sobrien			tempfree(y);
151685587Sobrien			nextarg = nextarg->nnext;
151785587Sobrien		}
151885587Sobrien		break;
151985587Sobrien	case FSYSTEM:
152085587Sobrien		fflush(stdout);		/* in case something is buffered already */
152185587Sobrien		u = (Awkfloat) system(getsval(x)) / 256;   /* 256 is unix-dep */
152285587Sobrien		break;
152385587Sobrien	case FRAND:
152485587Sobrien		/* in principle, rand() returns something in 0..RAND_MAX */
152585587Sobrien		u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
152685587Sobrien		break;
152785587Sobrien	case FSRAND:
152885587Sobrien		if (isrec(x))	/* no argument provided */
152985587Sobrien			u = time((time_t *)0);
153085587Sobrien		else
153185587Sobrien			u = getfval(x);
1532221381Sru		tmp = u;
153385587Sobrien		srand((unsigned int) u);
1534221381Sru		u = srand_seed;
1535221381Sru		srand_seed = tmp;
153685587Sobrien		break;
153785587Sobrien	case FTOUPPER:
153885587Sobrien	case FTOLOWER:
153985587Sobrien		buf = tostring(getsval(x));
154085587Sobrien		if (t == FTOUPPER) {
154185587Sobrien			for (p = buf; *p; p++)
154285587Sobrien				if (islower((uschar) *p))
1543112336Sobrien					*p = toupper((uschar)*p);
154485587Sobrien		} else {
154585587Sobrien			for (p = buf; *p; p++)
154685587Sobrien				if (isupper((uschar) *p))
1547112336Sobrien					*p = tolower((uschar)*p);
154885587Sobrien		}
154985587Sobrien		tempfree(x);
155085587Sobrien		x = gettemp();
155185587Sobrien		setsval(x, buf);
155285587Sobrien		free(buf);
155385587Sobrien		return x;
155485587Sobrien	case FFLUSH:
155590902Sdes		if (isrec(x) || strlen(getsval(x)) == 0) {
155690902Sdes			flush_all();	/* fflush() or fflush("") -> all */
155790902Sdes			u = 0;
155890902Sdes		} else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
155985587Sobrien			u = EOF;
156085587Sobrien		else
156185587Sobrien			u = fflush(fp);
156285587Sobrien		break;
156385587Sobrien	default:	/* can't happen */
156485587Sobrien		FATAL("illegal function type %d", t);
156585587Sobrien		break;
156685587Sobrien	}
156785587Sobrien	tempfree(x);
156885587Sobrien	x = gettemp();
156985587Sobrien	setfval(x, u);
157085587Sobrien	if (nextarg != 0) {
157185587Sobrien		WARNING("warning: function has too many arguments");
157285587Sobrien		for ( ; nextarg; nextarg = nextarg->nnext)
157385587Sobrien			execute(nextarg);
157485587Sobrien	}
157585587Sobrien	return(x);
157685587Sobrien}
157785587Sobrien
157885587SobrienCell *printstat(Node **a, int n)	/* print a[0] */
157985587Sobrien{
158085587Sobrien	Node *x;
158185587Sobrien	Cell *y;
158285587Sobrien	FILE *fp;
158385587Sobrien
158485587Sobrien	if (a[1] == 0)	/* a[1] is redirection operator, a[2] is file */
158585587Sobrien		fp = stdout;
158685587Sobrien	else
158785587Sobrien		fp = redirect(ptoi(a[1]), a[2]);
158885587Sobrien	for (x = a[0]; x != NULL; x = x->nnext) {
158985587Sobrien		y = execute(x);
1590107806Sobrien		fputs(getpssval(y), fp);
159185587Sobrien		tempfree(y);
159285587Sobrien		if (x->nnext == NULL)
159385587Sobrien			fputs(*ORS, fp);
159485587Sobrien		else
159585587Sobrien			fputs(*OFS, fp);
159685587Sobrien	}
159785587Sobrien	if (a[1] != 0)
159885587Sobrien		fflush(fp);
159985587Sobrien	if (ferror(fp))
160085587Sobrien		FATAL("write error on %s", filename(fp));
160185587Sobrien	return(True);
160285587Sobrien}
160385587Sobrien
160485587SobrienCell *nullproc(Node **a, int n)
160585587Sobrien{
160685587Sobrien	n = n;
160785587Sobrien	a = a;
160885587Sobrien	return 0;
160985587Sobrien}
161085587Sobrien
161185587Sobrien
161285587SobrienFILE *redirect(int a, Node *b)	/* set up all i/o redirections */
161385587Sobrien{
161485587Sobrien	FILE *fp;
161585587Sobrien	Cell *x;
161685587Sobrien	char *fname;
161785587Sobrien
161885587Sobrien	x = execute(b);
161985587Sobrien	fname = getsval(x);
162085587Sobrien	fp = openfile(a, fname);
162185587Sobrien	if (fp == NULL)
162285587Sobrien		FATAL("can't open file %s", fname);
162385587Sobrien	tempfree(x);
162485587Sobrien	return fp;
162585587Sobrien}
162685587Sobrien
162785587Sobrienstruct files {
162885587Sobrien	FILE	*fp;
1629107806Sobrien	const char	*fname;
163085587Sobrien	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
1631224731Sru} *files;
163285587Sobrien
1633224731Sruint nfiles;
1634224731Sru
163585587Sobrienvoid stdinit(void)	/* in case stdin, etc., are not constants */
163685587Sobrien{
1637224731Sru	nfiles = FOPEN_MAX;
1638224731Sru	files = calloc(nfiles, sizeof(*files));
1639224731Sru	if (files == NULL)
1640224731Sru		FATAL("can't allocate file memory for %u files", nfiles);
1641224731Sru        files[0].fp = stdin;
1642224731Sru	files[0].fname = "/dev/stdin";
1643224731Sru	files[0].mode = LT;
1644224731Sru        files[1].fp = stdout;
1645224731Sru	files[1].fname = "/dev/stdout";
1646224731Sru	files[1].mode = GT;
1647224731Sru        files[2].fp = stderr;
1648224731Sru	files[2].fname = "/dev/stderr";
1649224731Sru	files[2].mode = GT;
165085587Sobrien}
165185587Sobrien
1652107806SobrienFILE *openfile(int a, const char *us)
165385587Sobrien{
1654107806Sobrien	const char *s = us;
165585587Sobrien	int i, m;
165685587Sobrien	FILE *fp = 0;
165785587Sobrien
165885587Sobrien	if (*s == '\0')
165985587Sobrien		FATAL("null file name in print or getline");
1660224731Sru	for (i=0; i < nfiles; i++)
166185587Sobrien		if (files[i].fname && strcmp(s, files[i].fname) == 0) {
166285587Sobrien			if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
166385587Sobrien				return files[i].fp;
166485587Sobrien			if (a == FFLUSH)
166585587Sobrien				return files[i].fp;
166685587Sobrien		}
166785587Sobrien	if (a == FFLUSH)	/* didn't find it, so don't create it! */
166885587Sobrien		return NULL;
166985587Sobrien
1670224731Sru	for (i=0; i < nfiles; i++)
167185587Sobrien		if (files[i].fp == 0)
167285587Sobrien			break;
1673224731Sru	if (i >= nfiles) {
1674224731Sru		struct files *nf;
1675224731Sru		int nnf = nfiles + FOPEN_MAX;
1676224731Sru		nf = realloc(files, nnf * sizeof(*nf));
1677224731Sru		if (nf == NULL)
1678224731Sru			FATAL("cannot grow files for %s and %d files", s, nnf);
1679224731Sru		memset(&nf[nfiles], 0, FOPEN_MAX * sizeof(*nf));
1680224731Sru		nfiles = nnf;
1681224731Sru		files = nf;
1682224731Sru	}
168385587Sobrien	fflush(stdout);	/* force a semblance of order */
168485587Sobrien	m = a;
168585587Sobrien	if (a == GT) {
168685587Sobrien		fp = fopen(s, "w");
168785587Sobrien	} else if (a == APPEND) {
168885587Sobrien		fp = fopen(s, "a");
168985587Sobrien		m = GT;	/* so can mix > and >> */
169085587Sobrien	} else if (a == '|') {	/* output pipe */
169185587Sobrien		fp = popen(s, "w");
169285587Sobrien	} else if (a == LE) {	/* input pipe */
169385587Sobrien		fp = popen(s, "r");
169485587Sobrien	} else if (a == LT) {	/* getline <file */
169585587Sobrien		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
169685587Sobrien	} else	/* can't happen */
169785587Sobrien		FATAL("illegal redirection %d", a);
169885587Sobrien	if (fp != NULL) {
169985587Sobrien		files[i].fname = tostring(s);
170085587Sobrien		files[i].fp = fp;
170185587Sobrien		files[i].mode = m;
170285587Sobrien	}
170385587Sobrien	return fp;
170485587Sobrien}
170585587Sobrien
1706107806Sobrienconst char *filename(FILE *fp)
170785587Sobrien{
170885587Sobrien	int i;
170985587Sobrien
1710224731Sru	for (i = 0; i < nfiles; i++)
171185587Sobrien		if (fp == files[i].fp)
171285587Sobrien			return files[i].fname;
171385587Sobrien	return "???";
171485587Sobrien}
171585587Sobrien
171685587SobrienCell *closefile(Node **a, int n)
171785587Sobrien{
171885587Sobrien	Cell *x;
171985587Sobrien	int i, stat;
172085587Sobrien
172185587Sobrien	n = n;
172285587Sobrien	x = execute(a[0]);
172385587Sobrien	getsval(x);
172485587Sobrien	stat = -1;
1725224731Sru	for (i = 0; i < nfiles; i++) {
172685587Sobrien		if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
172785587Sobrien			if (ferror(files[i].fp))
172885587Sobrien				WARNING( "i/o error occurred on %s", files[i].fname );
172985587Sobrien			if (files[i].mode == '|' || files[i].mode == LE)
173085587Sobrien				stat = pclose(files[i].fp);
173185587Sobrien			else
173285587Sobrien				stat = fclose(files[i].fp);
173385587Sobrien			if (stat == EOF)
173485587Sobrien				WARNING( "i/o error occurred closing %s", files[i].fname );
173585587Sobrien			if (i > 2)	/* don't do /dev/std... */
173685587Sobrien				xfree(files[i].fname);
173785587Sobrien			files[i].fname = NULL;	/* watch out for ref thru this */
173885587Sobrien			files[i].fp = NULL;
173985587Sobrien		}
174085587Sobrien	}
174185587Sobrien	tempfree(x);
174285587Sobrien	x = gettemp();
174385587Sobrien	setfval(x, (Awkfloat) stat);
174485587Sobrien	return(x);
174585587Sobrien}
174685587Sobrien
174785587Sobrienvoid closeall(void)
174885587Sobrien{
174985587Sobrien	int i, stat;
175085587Sobrien
175185587Sobrien	for (i = 0; i < FOPEN_MAX; i++) {
175285587Sobrien		if (files[i].fp) {
175385587Sobrien			if (ferror(files[i].fp))
175485587Sobrien				WARNING( "i/o error occurred on %s", files[i].fname );
175585587Sobrien			if (files[i].mode == '|' || files[i].mode == LE)
175685587Sobrien				stat = pclose(files[i].fp);
175785587Sobrien			else
175885587Sobrien				stat = fclose(files[i].fp);
175985587Sobrien			if (stat == EOF)
176085587Sobrien				WARNING( "i/o error occurred while closing %s", files[i].fname );
176185587Sobrien		}
176285587Sobrien	}
176385587Sobrien}
176485587Sobrien
176590902Sdesvoid flush_all(void)
176690902Sdes{
176790902Sdes	int i;
176890902Sdes
1769224731Sru	for (i = 0; i < nfiles; i++)
177090902Sdes		if (files[i].fp)
177190902Sdes			fflush(files[i].fp);
177290902Sdes}
177390902Sdes
177485587Sobrienvoid backsub(char **pb_ptr, char **sptr_ptr);
177585587Sobrien
177685587SobrienCell *sub(Node **a, int nnn)	/* substitute command */
177785587Sobrien{
177885587Sobrien	char *sptr, *pb, *q;
177985587Sobrien	Cell *x, *y, *result;
178085587Sobrien	char *t, *buf;
178185587Sobrien	fa *pfa;
178285587Sobrien	int bufsz = recsize;
178385587Sobrien
178485587Sobrien	if ((buf = (char *) malloc(bufsz)) == NULL)
178585587Sobrien		FATAL("out of memory in sub");
178685587Sobrien	x = execute(a[3]);	/* target string */
178785587Sobrien	t = getsval(x);
178885587Sobrien	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
178985587Sobrien		pfa = (fa *) a[1];	/* regular expression */
179085587Sobrien	else {
179185587Sobrien		y = execute(a[1]);
179285587Sobrien		pfa = makedfa(getsval(y), 1);
179385587Sobrien		tempfree(y);
179485587Sobrien	}
179585587Sobrien	y = execute(a[2]);	/* replacement string */
179685587Sobrien	result = False;
179785587Sobrien	if (pmatch(pfa, t)) {
179885587Sobrien		sptr = t;
179985587Sobrien		adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
180085587Sobrien		pb = buf;
180185587Sobrien		while (sptr < patbeg)
180285587Sobrien			*pb++ = *sptr++;
180385587Sobrien		sptr = getsval(y);
180485587Sobrien		while (*sptr != 0) {
180585587Sobrien			adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
180685587Sobrien			if (*sptr == '\\') {
180785587Sobrien				backsub(&pb, &sptr);
180885587Sobrien			} else if (*sptr == '&') {
180985587Sobrien				sptr++;
181085587Sobrien				adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
181185587Sobrien				for (q = patbeg; q < patbeg+patlen; )
181285587Sobrien					*pb++ = *q++;
181385587Sobrien			} else
181485587Sobrien				*pb++ = *sptr++;
181585587Sobrien		}
181685587Sobrien		*pb = '\0';
181785587Sobrien		if (pb > buf + bufsz)
181885587Sobrien			FATAL("sub result1 %.30s too big; can't happen", buf);
181985587Sobrien		sptr = patbeg + patlen;
182085587Sobrien		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
182185587Sobrien			adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
182285587Sobrien			while ((*pb++ = *sptr++) != 0)
182385587Sobrien				;
182485587Sobrien		}
182585587Sobrien		if (pb > buf + bufsz)
182685587Sobrien			FATAL("sub result2 %.30s too big; can't happen", buf);
182785587Sobrien		setsval(x, buf);	/* BUG: should be able to avoid copy */
182885587Sobrien		result = True;;
182985587Sobrien	}
183085587Sobrien	tempfree(x);
183185587Sobrien	tempfree(y);
183285587Sobrien	free(buf);
183385587Sobrien	return result;
183485587Sobrien}
183585587Sobrien
183685587SobrienCell *gsub(Node **a, int nnn)	/* global substitute */
183785587Sobrien{
183885587Sobrien	Cell *x, *y;
183985587Sobrien	char *rptr, *sptr, *t, *pb, *q;
184085587Sobrien	char *buf;
184185587Sobrien	fa *pfa;
184285587Sobrien	int mflag, tempstat, num;
184385587Sobrien	int bufsz = recsize;
184485587Sobrien
184585587Sobrien	if ((buf = (char *) malloc(bufsz)) == NULL)
184685587Sobrien		FATAL("out of memory in gsub");
184785587Sobrien	mflag = 0;	/* if mflag == 0, can replace empty string */
184885587Sobrien	num = 0;
184985587Sobrien	x = execute(a[3]);	/* target string */
185085587Sobrien	t = getsval(x);
185185587Sobrien	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
185285587Sobrien		pfa = (fa *) a[1];	/* regular expression */
185385587Sobrien	else {
185485587Sobrien		y = execute(a[1]);
185585587Sobrien		pfa = makedfa(getsval(y), 1);
185685587Sobrien		tempfree(y);
185785587Sobrien	}
185885587Sobrien	y = execute(a[2]);	/* replacement string */
185985587Sobrien	if (pmatch(pfa, t)) {
186085587Sobrien		tempstat = pfa->initstat;
186185587Sobrien		pfa->initstat = 2;
186285587Sobrien		pb = buf;
186385587Sobrien		rptr = getsval(y);
186485587Sobrien		do {
186585587Sobrien			if (patlen == 0 && *patbeg != 0) {	/* matched empty string */
186685587Sobrien				if (mflag == 0) {	/* can replace empty */
186785587Sobrien					num++;
186885587Sobrien					sptr = rptr;
186985587Sobrien					while (*sptr != 0) {
187085587Sobrien						adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
187185587Sobrien						if (*sptr == '\\') {
187285587Sobrien							backsub(&pb, &sptr);
187385587Sobrien						} else if (*sptr == '&') {
187485587Sobrien							sptr++;
187585587Sobrien							adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
187685587Sobrien							for (q = patbeg; q < patbeg+patlen; )
187785587Sobrien								*pb++ = *q++;
187885587Sobrien						} else
187985587Sobrien							*pb++ = *sptr++;
188085587Sobrien					}
188185587Sobrien				}
188285587Sobrien				if (*t == 0)	/* at end */
188385587Sobrien					goto done;
188485587Sobrien				adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
188585587Sobrien				*pb++ = *t++;
188685587Sobrien				if (pb > buf + bufsz)	/* BUG: not sure of this test */
188785587Sobrien					FATAL("gsub result0 %.30s too big; can't happen", buf);
188885587Sobrien				mflag = 0;
188985587Sobrien			}
189085587Sobrien			else {	/* matched nonempty string */
189185587Sobrien				num++;
189285587Sobrien				sptr = t;
189385587Sobrien				adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
189485587Sobrien				while (sptr < patbeg)
189585587Sobrien					*pb++ = *sptr++;
189685587Sobrien				sptr = rptr;
189785587Sobrien				while (*sptr != 0) {
189885587Sobrien					adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
189985587Sobrien					if (*sptr == '\\') {
190085587Sobrien						backsub(&pb, &sptr);
190185587Sobrien					} else if (*sptr == '&') {
190285587Sobrien						sptr++;
190385587Sobrien						adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
190485587Sobrien						for (q = patbeg; q < patbeg+patlen; )
190585587Sobrien							*pb++ = *q++;
190685587Sobrien					} else
190785587Sobrien						*pb++ = *sptr++;
190885587Sobrien				}
190985587Sobrien				t = patbeg + patlen;
191085587Sobrien				if (patlen == 0 || *t == 0 || *(t-1) == 0)
191185587Sobrien					goto done;
191285587Sobrien				if (pb > buf + bufsz)
191385587Sobrien					FATAL("gsub result1 %.30s too big; can't happen", buf);
191485587Sobrien				mflag = 1;
191585587Sobrien			}
191685587Sobrien		} while (pmatch(pfa,t));
191785587Sobrien		sptr = t;
191885587Sobrien		adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
191985587Sobrien		while ((*pb++ = *sptr++) != 0)
192085587Sobrien			;
1921221381Sru	done:	if (pb < buf + bufsz)
1922221381Sru			*pb = '\0';
1923221381Sru		else if (*(pb-1) != '\0')
1924221381Sru			FATAL("gsub result2 %.30s truncated; can't happen", buf);
192585587Sobrien		setsval(x, buf);	/* BUG: should be able to avoid copy + free */
192685587Sobrien		pfa->initstat = tempstat;
192785587Sobrien	}
192885587Sobrien	tempfree(x);
192985587Sobrien	tempfree(y);
193085587Sobrien	x = gettemp();
193185587Sobrien	x->tval = NUM;
193285587Sobrien	x->fval = num;
193385587Sobrien	free(buf);
193485587Sobrien	return(x);
193585587Sobrien}
193685587Sobrien
193785587Sobrienvoid backsub(char **pb_ptr, char **sptr_ptr)	/* handle \\& variations */
193885587Sobrien{						/* sptr[0] == '\\' */
193985587Sobrien	char *pb = *pb_ptr, *sptr = *sptr_ptr;
194085587Sobrien
194185587Sobrien	if (sptr[1] == '\\') {
194285587Sobrien		if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
194385587Sobrien			*pb++ = '\\';
194485587Sobrien			*pb++ = '&';
194585587Sobrien			sptr += 4;
194685587Sobrien		} else if (sptr[2] == '&') {	/* \\& -> \ + matched */
194785587Sobrien			*pb++ = '\\';
194885587Sobrien			sptr += 2;
194985587Sobrien		} else {			/* \\x -> \\x */
195085587Sobrien			*pb++ = *sptr++;
195185587Sobrien			*pb++ = *sptr++;
195285587Sobrien		}
195385587Sobrien	} else if (sptr[1] == '&') {	/* literal & */
195485587Sobrien		sptr++;
195585587Sobrien		*pb++ = *sptr++;
195685587Sobrien	} else				/* literal \ */
195785587Sobrien		*pb++ = *sptr++;
195885587Sobrien
195985587Sobrien	*pb_ptr = pb;
196085587Sobrien	*sptr_ptr = sptr;
196185587Sobrien}
1962