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