xref: /csrg-svn/contrib/awk.research/run.c (revision 65396)
165393Sbostic /****************************************************************
265393Sbostic Copyright (C) AT&T 1993
365393Sbostic All Rights Reserved
465393Sbostic 
565393Sbostic Permission to use, copy, modify, and distribute this software and
665393Sbostic its documentation for any purpose and without fee is hereby
765393Sbostic granted, provided that the above copyright notice appear in all
865393Sbostic copies and that both that the copyright notice and this
965393Sbostic permission notice and warranty disclaimer appear in supporting
1065393Sbostic documentation, and that the name of AT&T or any of its entities
1165393Sbostic not be used in advertising or publicity pertaining to
1265393Sbostic distribution of the software without specific, written prior
1365393Sbostic permission.
1465393Sbostic 
1565393Sbostic AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1665393Sbostic INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1765393Sbostic IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
1865393Sbostic SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1965393Sbostic WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
2065393Sbostic IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2165393Sbostic ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
2265393Sbostic THIS SOFTWARE.
2365393Sbostic ****************************************************************/
2465393Sbostic 
2565393Sbostic #define tempfree(x)	if (istemp(x)) tfree(x); else
2665393Sbostic 
2765393Sbostic #define DEBUG
2865393Sbostic #include <stdio.h>
2965393Sbostic #include <ctype.h>
3065393Sbostic #include <setjmp.h>
3165393Sbostic #include <math.h>
3265393Sbostic #include <string.h>
3365393Sbostic #include <stdlib.h>
3465393Sbostic #include <time.h>
3565393Sbostic #include "awk.h"
3665393Sbostic #include "y.tab.h"
3765393Sbostic 
3865393Sbostic #ifdef _NFILE
3965393Sbostic #ifndef FOPEN_MAX
4065393Sbostic #define FOPEN_MAX _NFILE
4165393Sbostic #endif
4265393Sbostic #endif
4365393Sbostic 
4465393Sbostic #ifndef	FOPEN_MAX
4565393Sbostic #define	FOPEN_MAX	40	/* max number of open files */
4665393Sbostic #endif
4765393Sbostic 
4865393Sbostic #ifndef RAND_MAX
4965393Sbostic #define RAND_MAX	32767	/* all that ansi guarantees */
5065393Sbostic #endif
5165393Sbostic 
5265393Sbostic jmp_buf env;
5365393Sbostic 
5465393Sbostic /* an attempt to go a bit faster: */
5565393Sbostic 
5665393Sbostic /* #define	execute(p)	(isvalue(p) ? (Cell *)((p)->narg[0]) : r_execute(p)) */
5765393Sbostic #define	execute(p) r_execute(p)
5865393Sbostic #define	getfval(p)	(((p)->tval & (ARR|FLD|REC|NUM)) == NUM ? (p)->fval : r_getfval(p))
5965393Sbostic #define	getsval(p)	(((p)->tval & (ARR|FLD|REC|STR)) == STR ? (p)->sval : r_getsval(p))
6065393Sbostic 
6165393Sbostic 
6265393Sbostic #define PA2NUM	29	/* max number of pat,pat patterns allowed */
6365393Sbostic int	paircnt;		/* number of them in use */
6465393Sbostic int	pairstack[PA2NUM];	/* state of each pat,pat */
6565393Sbostic 
6665393Sbostic Node	*winner = NULL;	/* root of parse tree */
6765393Sbostic Cell	*tmps;		/* free temporary cells for execution */
6865393Sbostic 
6965393Sbostic static Cell	truecell	={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
7065393Sbostic Cell	*true	= &truecell;
7165393Sbostic static Cell	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
7265393Sbostic Cell	*false	= &falsecell;
7365393Sbostic static Cell	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
7465393Sbostic Cell	*jbreak	= &breakcell;
7565393Sbostic static Cell	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM };
7665393Sbostic Cell	*jcont	= &contcell;
7765393Sbostic static Cell	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
7865393Sbostic Cell	*jnext	= &nextcell;
7965393Sbostic static Cell	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
8065393Sbostic Cell	*jexit	= &exitcell;
8165393Sbostic static Cell	retcell		={ OJUMP, JRET, 0, 0, 0.0, NUM };
8265393Sbostic Cell	*jret	= &retcell;
8365393Sbostic static Cell	tempcell	={ OCELL, CTEMP, 0, 0, 0.0, NUM };
8465393Sbostic 
8565393Sbostic Node	*curnode = NULL;	/* the node being executed, for debugging */
8665393Sbostic 
run(Node * a)8765393Sbostic void run(Node *a)	/* execution of parse tree starts here */
8865393Sbostic {
8965393Sbostic 	execute(a);
9065393Sbostic 	closeall();
9165393Sbostic }
9265393Sbostic 
r_execute(Node * u)9365393Sbostic Cell *r_execute(Node *u)	/* execute a node of the parse tree */
9465393Sbostic {
9565393Sbostic 	register Cell *(*proc)(Node **, int);
9665393Sbostic 	register Cell *x;
9765393Sbostic 	register Node *a;
9865393Sbostic 
9965393Sbostic 	if (u == NULL)
10065393Sbostic 		return(true);
10165393Sbostic 	for (a = u; ; a = a->nnext) {
10265393Sbostic 		curnode = a;
10365393Sbostic 		if (isvalue(a)) {
10465393Sbostic 			x = (Cell *) (a->narg[0]);
10565393Sbostic 			if ((x->tval & FLD) && !donefld)
10665393Sbostic 				fldbld();
10765393Sbostic 			else if ((x->tval & REC) && !donerec)
10865393Sbostic 				recbld();
10965393Sbostic 			return(x);
11065393Sbostic 		}
11165393Sbostic 		if (notlegal(a->nobj))	/* probably a Cell* but too risky to print */
11265393Sbostic 			ERROR "illegal statement" FATAL;
11365393Sbostic 		proc = proctab[a->nobj-FIRSTTOKEN];
11465393Sbostic 		x = (*proc)(a->narg, a->nobj);
11565393Sbostic 		if ((x->tval & FLD) && !donefld)
11665393Sbostic 			fldbld();
11765393Sbostic 		else if ((x->tval & REC) && !donerec)
11865393Sbostic 			recbld();
11965393Sbostic 		if (isexpr(a))
12065393Sbostic 			return(x);
12165393Sbostic 		if (isjump(x))
12265393Sbostic 			return(x);
12365393Sbostic 		if (a->nnext == NULL)
12465393Sbostic 			return(x);
12565393Sbostic 		tempfree(x);
12665393Sbostic 	}
12765393Sbostic }
12865393Sbostic 
12965393Sbostic 
program(Node ** a,int n)13065393Sbostic Cell *program(Node **a, int n)	/* execute an awk program */
13165393Sbostic {				/* a[0] = BEGIN, a[1] = body, a[2] = END */
13265393Sbostic 	register Cell *x;
13365393Sbostic 
13465393Sbostic 	if (setjmp(env) != 0)
13565393Sbostic 		goto ex;
13665393Sbostic 	if (a[0]) {		/* BEGIN */
13765393Sbostic 		x = execute(a[0]);
13865393Sbostic 		if (isexit(x))
13965393Sbostic 			return(true);
14065393Sbostic 		if (isjump(x))
14165393Sbostic 			ERROR "illegal break, continue or next from BEGIN" FATAL;
14265393Sbostic 		tempfree(x);
14365393Sbostic 	}
14465393Sbostic   loop:
14565393Sbostic 	if (a[1] || a[2])
14665393Sbostic 		while (getrec(record) > 0) {
14765393Sbostic 			x = execute(a[1]);
14865393Sbostic 			if (isexit(x))
14965393Sbostic 				break;
15065393Sbostic 			tempfree(x);
15165393Sbostic 		}
15265393Sbostic   ex:
15365393Sbostic 	if (setjmp(env) != 0)	/* handles exit within END */
15465393Sbostic 		goto ex1;
15565393Sbostic 	if (a[2]) {		/* END */
15665393Sbostic 		x = execute(a[2]);
15765393Sbostic 		if (isbreak(x) || isnext(x) || iscont(x))
15865393Sbostic 			ERROR "illegal break, next, or continue from END" FATAL;
15965393Sbostic 		tempfree(x);
16065393Sbostic 	}
16165393Sbostic   ex1:
16265393Sbostic 	return(true);
16365393Sbostic }
16465393Sbostic 
16565393Sbostic struct Frame {	/* stack frame for awk function calls */
16665393Sbostic 	int nargs;	/* number of arguments in this call */
16765393Sbostic 	Cell *fcncell;	/* pointer to Cell for function */
16865393Sbostic 	Cell **args;	/* pointer to array of arguments after execute */
16965393Sbostic 	Cell *retval;	/* return value */
17065393Sbostic };
17165393Sbostic 
17265393Sbostic #define	NARGS	50	/* max args in a call */
17365393Sbostic 
17465393Sbostic struct Frame *frame = NULL;	/* base of stack frames; dynamically allocated */
17565393Sbostic int	nframe = 0;		/* number of frames allocated */
17665393Sbostic struct Frame *fp = NULL;	/* frame pointer. bottom level unused */
17765393Sbostic 
call(Node ** a,int n)17865393Sbostic Cell *call(Node **a, int n)	/* function call.  very kludgy and fragile */
17965393Sbostic {
18065393Sbostic 	static Cell newcopycell = { OCELL, CCOPY, 0, (uchar *) "", 0.0, NUM|STR|DONTFREE };
18165393Sbostic 	int i, ncall, ndef;
18265393Sbostic 	Node *x;
18365393Sbostic 	Cell *args[NARGS], *oargs[NARGS], *y, *z, *fcn;
18465393Sbostic 	uchar *s;
18565393Sbostic 
18665393Sbostic 	fcn = execute(a[0]);	/* the function itself */
18765393Sbostic 	s = fcn->nval;
18865393Sbostic 	if (!isfunc(fcn))
18965393Sbostic 		ERROR "calling undefined function %s", s FATAL;
19065393Sbostic 	if (frame == NULL) {
19165393Sbostic 		fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
19265393Sbostic 		if (frame == NULL)
19365393Sbostic 			ERROR "out of space for stack frames calling %s", s FATAL;
19465393Sbostic 	}
19565393Sbostic 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)	/* args in call */
19665393Sbostic 		ncall++;
19765393Sbostic 	ndef = (int) fcn->fval;			/* args in defn */
19865393Sbostic 	dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, fp-frame) );
19965393Sbostic 	if (ncall > ndef)
20065393Sbostic 		ERROR "function %s called with %d args, uses only %d",
20165393Sbostic 			s, ncall, ndef WARNING;
20265393Sbostic 	if (ncall + ndef > NARGS)
20365393Sbostic 		ERROR "function %s has %d arguments, limit %d", s, ncall+ndef, NARGS FATAL;
20465393Sbostic 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {	/* get call args */
20565393Sbostic 		dprintf( ("evaluate args[%d], fp=%d:\n", i, fp-frame) );
20665393Sbostic 		y = execute(x);
20765393Sbostic 		oargs[i] = y;
20865393Sbostic 		dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
20965393Sbostic 			   i, y->nval, y->fval, isarr(y) ? "(array)" : (char*) y->sval, y->tval) );
21065393Sbostic 		if (isfunc(y))
21165393Sbostic 			ERROR "can't use function %s as argument in %s", y->nval, s FATAL;
21265393Sbostic 		if (isarr(y))
21365393Sbostic 			args[i] = y;	/* arrays by ref */
21465393Sbostic 		else
21565393Sbostic 			args[i] = copycell(y);
21665393Sbostic 		tempfree(y);
21765393Sbostic 	}
21865393Sbostic 	for ( ; i < ndef; i++) {	/* add null args for ones not provided */
21965393Sbostic 		args[i] = gettemp();
22065393Sbostic 		*args[i] = newcopycell;
22165393Sbostic 	}
22265393Sbostic 	fp++;	/* now ok to up frame */
22365393Sbostic 	if (fp >= frame + nframe) {
22465393Sbostic 		int dfp = fp - frame;	/* old index */
22565393Sbostic 		frame = (struct Frame *)
22665393Sbostic 			realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
22765393Sbostic 		if (frame == NULL)
22865393Sbostic 			ERROR "out of space for stack frames in %s", s FATAL;
22965393Sbostic 		fp = frame + dfp;
23065393Sbostic 	}
23165393Sbostic 	fp->fcncell = fcn;
23265393Sbostic 	fp->args = args;
23365393Sbostic 	fp->nargs = ndef;	/* number defined with (excess are locals) */
23465393Sbostic 	fp->retval = gettemp();
23565393Sbostic 
23665393Sbostic 	dprintf( ("start exec of %s, fp=%d\n", s, fp-frame) );
23765393Sbostic 	y = execute((Node *)(fcn->sval));	/* execute body */
23865393Sbostic 	dprintf( ("finished exec of %s, fp=%d\n", s, fp-frame) );
23965393Sbostic 
24065393Sbostic 	for (i = 0; i < ndef; i++) {
24165393Sbostic 		Cell *t = fp->args[i];
24265393Sbostic 		if (isarr(t)) {
24365393Sbostic 			if (t->csub == CCOPY) {
24465393Sbostic 				if (i >= ncall) {
24565393Sbostic 					freesymtab(t);
24665393Sbostic 					t->csub = CTEMP;
24765393Sbostic 				} else {
24865393Sbostic 					oargs[i]->tval = t->tval;
24965393Sbostic 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
25065393Sbostic 					oargs[i]->sval = t->sval;
25165393Sbostic 					tempfree(t);
25265393Sbostic 				}
25365393Sbostic 			}
25465393Sbostic 		} else if (t != y) {	/* kludge to prevent freeing twice */
25565393Sbostic 			t->csub = CTEMP;
25665393Sbostic 			tempfree(t);
25765393Sbostic 		}
25865393Sbostic 	}
25965393Sbostic 	tempfree(fcn);
26065393Sbostic 	if (isexit(y) || isnext(y))
26165393Sbostic 		return y;
26265393Sbostic 	tempfree(y);		/* this can free twice! */
26365393Sbostic 	z = fp->retval;			/* return value */
26465393Sbostic 	dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
26565393Sbostic 	fp--;
26665393Sbostic 	return(z);
26765393Sbostic }
26865393Sbostic 
copycell(Cell * x)26965393Sbostic Cell *copycell(Cell *x)	/* make a copy of a cell in a temp */
27065393Sbostic {
27165393Sbostic 	Cell *y;
27265393Sbostic 
27365393Sbostic 	y = gettemp();
27465393Sbostic 	y->csub = CCOPY;	/* prevents freeing until call is over */
27565393Sbostic 	y->nval = x->nval;
27665393Sbostic 	y->sval = x->sval ? tostring(x->sval) : NULL;
27765393Sbostic 	y->fval = x->fval;
27865393Sbostic 	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);	/* copy is not constant or field */
27965393Sbostic 							/* is DONTFREE right? */
28065393Sbostic 	return y;
28165393Sbostic }
28265393Sbostic 
arg(Node ** a,int n)28365393Sbostic Cell *arg(Node **a, int n)	/* nth argument of a function */
28465393Sbostic {
28565393Sbostic 
28665393Sbostic 	n = (int) a[0];	/* argument number, counting from 0 */
28765393Sbostic 	dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
28865393Sbostic 	if (n+1 > fp->nargs)
28965393Sbostic 		ERROR "argument #%d of function %s was not supplied",
29065393Sbostic 			n+1, fp->fcncell->nval FATAL;
29165393Sbostic 	return fp->args[n];
29265393Sbostic }
29365393Sbostic 
jump(Node ** a,int n)29465393Sbostic Cell *jump(Node **a, int n)	/* break, continue, next, continue, return */
29565393Sbostic {
29665393Sbostic 	register Cell *y;
29765393Sbostic 
29865393Sbostic 	switch (n) {
29965393Sbostic 	case EXIT:
30065393Sbostic 		if (a[0] != NULL) {
30165393Sbostic 			y = execute(a[0]);
30265393Sbostic 			errorflag = getfval(y);
30365393Sbostic 			tempfree(y);
30465393Sbostic 		}
30565393Sbostic 		longjmp(env, 1);
30665393Sbostic 	case RETURN:
30765393Sbostic 		if (a[0] != NULL) {
30865393Sbostic 			y = execute(a[0]);
30965393Sbostic 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
31065393Sbostic 				setsval(fp->retval, getsval(y));
31165393Sbostic 				fp->retval->fval = getfval(y);
31265393Sbostic 				fp->retval->tval |= NUM;
31365393Sbostic 			}
31465393Sbostic 			else if (y->tval & STR)
31565393Sbostic 				setsval(fp->retval, getsval(y));
31665393Sbostic 			else if (y->tval & NUM)
31765393Sbostic 				setfval(fp->retval, getfval(y));
31865393Sbostic 			else		/* can't happen */
31965393Sbostic 				ERROR "bad type variable %d", y->tval FATAL;
32065393Sbostic 			tempfree(y);
32165393Sbostic 		}
32265393Sbostic 		return(jret);
32365393Sbostic 	case NEXT:
32465393Sbostic 		return(jnext);
32565393Sbostic 	case BREAK:
32665393Sbostic 		return(jbreak);
32765393Sbostic 	case CONTINUE:
32865393Sbostic 		return(jcont);
32965393Sbostic 	default:	/* can't happen */
33065393Sbostic 		ERROR "illegal jump type %d", n FATAL;
33165393Sbostic 	}
33265393Sbostic 	return 0;	/* not reached */
33365393Sbostic }
33465393Sbostic 
getline(Node ** a,int n)33565393Sbostic Cell *getline(Node **a, int n)	/* get next line from specific input */
33665393Sbostic {		/* a[0] is variable, a[1] is operator, a[2] is filename */
33765393Sbostic 	register Cell *r, *x;
33865393Sbostic 	uchar buf[RECSIZE];
33965393Sbostic 	FILE *fp;
34065393Sbostic 
34165393Sbostic 	fflush(stdout);	/* in case someone is waiting for a prompt */
34265393Sbostic 	r = gettemp();
34365393Sbostic 	if (a[1] != NULL) {		/* getline < file */
34465393Sbostic 		x = execute(a[2]);		/* filename */
34565393Sbostic 		if ((int) a[1] == '|')	/* input pipe */
34665393Sbostic 			a[1] = (Node *) LE;	/* arbitrary flag */
34765393Sbostic 		fp = openfile((int) a[1], getsval(x));
34865393Sbostic 		tempfree(x);
34965393Sbostic 		if (fp == NULL)
35065393Sbostic 			n = -1;
35165393Sbostic 		else
35265393Sbostic 			n = readrec(buf, sizeof(buf), fp);
35365393Sbostic 		if (n <= 0) {
35465393Sbostic 			;
35565393Sbostic 		} else if (a[0] != NULL) {	/* getline var <file */
35665393Sbostic 			setsval(execute(a[0]), buf);
35765393Sbostic 		} else {			/* getline <file */
35865393Sbostic 			if (!(recloc->tval & DONTFREE))
35965393Sbostic 				xfree(recloc->sval);
36065393Sbostic 			strcpy(record, buf);
36165393Sbostic 			recloc->sval = record;
36265393Sbostic 			recloc->tval = REC | STR | DONTFREE;
363*65396Sbostic 			if (is_a_number(recloc->sval)) {
36465393Sbostic 				recloc->fval = atof(recloc->sval);
36565393Sbostic 				recloc->tval |= NUM;
36665393Sbostic 			}
36765393Sbostic 			donerec = 1; donefld = 0;
36865393Sbostic 		}
36965393Sbostic 	} else {			/* bare getline; use current input */
37065393Sbostic 		if (a[0] == NULL)	/* getline */
37165393Sbostic 			n = getrec(record);
37265393Sbostic 		else {			/* getline var */
37365393Sbostic 			n = getrec(buf);
37465393Sbostic 			setsval(execute(a[0]), buf);
37565393Sbostic 		}
37665393Sbostic 	}
37765393Sbostic 	setfval(r, (Awkfloat) n);
37865393Sbostic 	return r;
37965393Sbostic }
38065393Sbostic 
getnf(Node ** a,int n)38165393Sbostic Cell *getnf(Node **a, int n)	/* get NF */
38265393Sbostic {
38365393Sbostic 	if (donefld == 0)
38465393Sbostic 		fldbld();
38565393Sbostic 	return (Cell *) a[0];
38665393Sbostic }
38765393Sbostic 
array(Node ** a,int n)38865393Sbostic Cell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
38965393Sbostic {
39065393Sbostic 	register Cell *x, *y, *z;
39165393Sbostic 	register uchar *s;
39265393Sbostic 	register Node *np;
39365393Sbostic 	uchar buf[RECSIZE];
39465393Sbostic 
39565393Sbostic 	x = execute(a[0]);	/* Cell* for symbol table */
39665393Sbostic 	buf[0] = 0;
39765393Sbostic 	for (np = a[1]; np; np = np->nnext) {
39865393Sbostic 		y = execute(np);	/* subscript */
39965393Sbostic 		s = getsval(y);
40065393Sbostic 		strcat(buf, s);
40165393Sbostic 		if (np->nnext)
40265393Sbostic 			strcat(buf, *SUBSEP);
40365393Sbostic 		tempfree(y);
40465393Sbostic 	}
40565393Sbostic 	if (!isarr(x)) {
40665393Sbostic 		dprintf( ("making %s into an array\n", x->nval) );
40765393Sbostic 		if (freeable(x))
40865393Sbostic 			xfree(x->sval);
40965393Sbostic 		x->tval &= ~(STR|NUM|DONTFREE);
41065393Sbostic 		x->tval |= ARR;
41165393Sbostic 		x->sval = (uchar *) makesymtab(NSYMTAB);
41265393Sbostic 	}
41365393Sbostic 	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
41465393Sbostic 	z->ctype = OCELL;
41565393Sbostic 	z->csub = CVAR;
41665393Sbostic 	tempfree(x);
41765393Sbostic 	return(z);
41865393Sbostic }
41965393Sbostic 
adelete(Node ** a,int n)42065393Sbostic Cell *adelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
42165393Sbostic {
42265393Sbostic 	Cell *x, *y;
42365393Sbostic 	Node *np;
42465393Sbostic 	uchar buf[RECSIZE], *s;
42565393Sbostic 
42665393Sbostic 	x = execute(a[0]);	/* Cell* for symbol table */
42765393Sbostic 	if (!isarr(x))
42865393Sbostic 		return true;
42965393Sbostic 	buf[0] = 0;
43065393Sbostic 	for (np = a[1]; np; np = np->nnext) {
43165393Sbostic 		y = execute(np);	/* subscript */
43265393Sbostic 		s = getsval(y);
43365393Sbostic 		strcat(buf, s);
43465393Sbostic 		if (np->nnext)
43565393Sbostic 			strcat(buf, *SUBSEP);
43665393Sbostic 		tempfree(y);
43765393Sbostic 	}
43865393Sbostic 	freeelem(x, buf);
43965393Sbostic 	tempfree(x);
44065393Sbostic 	return true;
44165393Sbostic }
44265393Sbostic 
intest(Node ** a,int n)44365393Sbostic Cell *intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
44465393Sbostic {
44565393Sbostic 	register Cell *x, *ap, *k;
44665393Sbostic 	Node *p;
44765393Sbostic 	char buf[RECSIZE];
44865393Sbostic 	uchar *s;
44965393Sbostic 
45065393Sbostic 	ap = execute(a[1]);	/* array name */
45165393Sbostic 	if (!isarr(ap)) {
45265393Sbostic 		dprintf( ("making %s into an array\n", ap->nval) );
45365393Sbostic 		if (freeable(ap))
45465393Sbostic 			xfree(ap->sval);
45565393Sbostic 		ap->tval &= ~(STR|NUM|DONTFREE);
45665393Sbostic 		ap->tval |= ARR;
45765393Sbostic 		ap->sval = (uchar *) makesymtab(NSYMTAB);
45865393Sbostic 	}
45965393Sbostic 	buf[0] = 0;
46065393Sbostic 	for (p = a[0]; p; p = p->nnext) {
46165393Sbostic 		x = execute(p);	/* expr */
46265393Sbostic 		s = getsval(x);
46365393Sbostic 		strcat(buf, s);
46465393Sbostic 		tempfree(x);
46565393Sbostic 		if (p->nnext)
46665393Sbostic 			strcat(buf, *SUBSEP);
46765393Sbostic 	}
46865393Sbostic 	k = lookup(buf, (Array *) ap->sval);
46965393Sbostic 	tempfree(ap);
47065393Sbostic 	if (k == NULL)
47165393Sbostic 		return(false);
47265393Sbostic 	else
47365393Sbostic 		return(true);
47465393Sbostic }
47565393Sbostic 
47665393Sbostic 
matchop(Node ** a,int n)47765393Sbostic Cell *matchop(Node **a, int n)	/* ~ and match() */
47865393Sbostic {
47965393Sbostic 	register Cell *x, *y;
48065393Sbostic 	register uchar *s, *t;
48165393Sbostic 	register int i;
48265393Sbostic 	fa *pfa;
48365393Sbostic 	int (*mf)(fa *, uchar *) = match, mode = 0;
48465393Sbostic 
48565393Sbostic 	if (n == MATCHFCN) {
48665393Sbostic 		mf = pmatch;
48765393Sbostic 		mode = 1;
48865393Sbostic 	}
48965393Sbostic 	x = execute(a[1]);	/* a[1] = target text */
49065393Sbostic 	s = getsval(x);
49165393Sbostic 	if (a[0] == 0)		/* a[1] == 0: already-compiled reg expr */
49265393Sbostic 		i = (*mf)((fa *) a[2], s);
49365393Sbostic 	else {
49465393Sbostic 		y = execute(a[2]);	/* a[2] = regular expr */
49565393Sbostic 		t = getsval(y);
49665393Sbostic 		pfa = makedfa(t, mode);
49765393Sbostic 		i = (*mf)(pfa, s);
49865393Sbostic 		tempfree(y);
49965393Sbostic 	}
50065393Sbostic 	tempfree(x);
50165393Sbostic 	if (n == MATCHFCN) {
50265393Sbostic 		int start = patbeg - s + 1;
50365393Sbostic 		if (patlen < 0)
50465393Sbostic 			start = 0;
50565393Sbostic 		setfval(rstartloc, (Awkfloat) start);
50665393Sbostic 		setfval(rlengthloc, (Awkfloat) patlen);
50765393Sbostic 		x = gettemp();
50865393Sbostic 		x->tval = NUM;
50965393Sbostic 		x->fval = start;
51065393Sbostic 		return x;
51165393Sbostic 	} else if (n == MATCH && i == 1 || n == NOTMATCH && i == 0)
51265393Sbostic 		return(true);
51365393Sbostic 	else
51465393Sbostic 		return(false);
51565393Sbostic }
51665393Sbostic 
51765393Sbostic 
boolop(Node ** a,int n)51865393Sbostic Cell *boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
51965393Sbostic {
52065393Sbostic 	register Cell *x, *y;
52165393Sbostic 	register int i;
52265393Sbostic 
52365393Sbostic 	x = execute(a[0]);
52465393Sbostic 	i = istrue(x);
52565393Sbostic 	tempfree(x);
52665393Sbostic 	switch (n) {
52765393Sbostic 	case BOR:
52865393Sbostic 		if (i) return(true);
52965393Sbostic 		y = execute(a[1]);
53065393Sbostic 		i = istrue(y);
53165393Sbostic 		tempfree(y);
53265393Sbostic 		if (i) return(true);
53365393Sbostic 		else return(false);
53465393Sbostic 	case AND:
53565393Sbostic 		if ( !i ) return(false);
53665393Sbostic 		y = execute(a[1]);
53765393Sbostic 		i = istrue(y);
53865393Sbostic 		tempfree(y);
53965393Sbostic 		if (i) return(true);
54065393Sbostic 		else return(false);
54165393Sbostic 	case NOT:
54265393Sbostic 		if (i) return(false);
54365393Sbostic 		else return(true);
54465393Sbostic 	default:	/* can't happen */
54565393Sbostic 		ERROR "unknown boolean operator %d", n FATAL;
54665393Sbostic 	}
54765393Sbostic 	return 0;	/*NOTREACHED*/
54865393Sbostic }
54965393Sbostic 
relop(Node ** a,int n)55065393Sbostic Cell *relop(Node **a, int n)	/* a[0 < a[1], etc. */
55165393Sbostic {
55265393Sbostic 	register int i;
55365393Sbostic 	register Cell *x, *y;
55465393Sbostic 	Awkfloat j;
55565393Sbostic 
55665393Sbostic 	x = execute(a[0]);
55765393Sbostic 	y = execute(a[1]);
55865393Sbostic 	if (x->tval&NUM && y->tval&NUM) {
55965393Sbostic 		j = x->fval - y->fval;
56065393Sbostic 		i = j<0? -1: (j>0? 1: 0);
56165393Sbostic 	} else {
56265393Sbostic 		i = strcmp(getsval(x), getsval(y));
56365393Sbostic 	}
56465393Sbostic 	tempfree(x);
56565393Sbostic 	tempfree(y);
56665393Sbostic 	switch (n) {
56765393Sbostic 	case LT:	if (i<0) return(true);
56865393Sbostic 			else return(false);
56965393Sbostic 	case LE:	if (i<=0) return(true);
57065393Sbostic 			else return(false);
57165393Sbostic 	case NE:	if (i!=0) return(true);
57265393Sbostic 			else return(false);
57365393Sbostic 	case EQ:	if (i == 0) return(true);
57465393Sbostic 			else return(false);
57565393Sbostic 	case GE:	if (i>=0) return(true);
57665393Sbostic 			else return(false);
57765393Sbostic 	case GT:	if (i>0) return(true);
57865393Sbostic 			else return(false);
57965393Sbostic 	default:	/* can't happen */
58065393Sbostic 		ERROR "unknown relational operator %d", n FATAL;
58165393Sbostic 	}
58265393Sbostic 	return 0;	/*NOTREACHED*/
58365393Sbostic }
58465393Sbostic 
tfree(Cell * a)58565393Sbostic void tfree(Cell *a)	/* free a tempcell */
58665393Sbostic {
58765393Sbostic 	if (freeable(a))
58865393Sbostic 		xfree(a->sval);
58965393Sbostic 	if (a == tmps)
59065393Sbostic 		ERROR "tempcell list is curdled" FATAL;
59165393Sbostic 	a->cnext = tmps;
59265393Sbostic 	tmps = a;
59365393Sbostic }
59465393Sbostic 
gettemp(void)59565393Sbostic Cell *gettemp(void)	/* get a tempcell */
59665393Sbostic {	int i;
59765393Sbostic 	register Cell *x;
59865393Sbostic 
59965393Sbostic 	if (!tmps) {
60065393Sbostic 		tmps = (Cell *) calloc(100, sizeof(Cell));
60165393Sbostic 		if (!tmps)
60265393Sbostic 			ERROR "out of space for temporaries" FATAL;
60365393Sbostic 		for(i = 1; i < 100; i++)
60465393Sbostic 			tmps[i-1].cnext = &tmps[i];
60565393Sbostic 		tmps[i-1].cnext = 0;
60665393Sbostic 	}
60765393Sbostic 	x = tmps;
60865393Sbostic 	tmps = x->cnext;
60965393Sbostic 	*x = tempcell;
61065393Sbostic 	return(x);
61165393Sbostic }
61265393Sbostic 
indirect(Node ** a,int n)61365393Sbostic Cell *indirect(Node **a, int n)	/* $( a[0] ) */
61465393Sbostic {
61565393Sbostic 	register Cell *x;
61665393Sbostic 	register int m;
61765393Sbostic 	register uchar *s;
61865393Sbostic 
61965393Sbostic 	x = execute(a[0]);
62065393Sbostic 	m = getfval(x);
621*65396Sbostic 	if (m == 0 && !is_a_number(s = getsval(x)))	/* suspicion! */
62265393Sbostic 		ERROR "illegal field $(%s), name \"%s\"", s, x->nval FATAL;
62365393Sbostic   /* can x->nval ever be null??? */
62465393Sbostic 		/* ERROR "illegal field $(%s)", s FATAL; */
62565393Sbostic 	tempfree(x);
62665393Sbostic 	x = fieldadr(m);
62765393Sbostic 	x->ctype = OCELL;
62865393Sbostic 	x->csub = CFLD;
62965393Sbostic 	return(x);
63065393Sbostic }
63165393Sbostic 
substr(Node ** a,int nnn)63265393Sbostic Cell *substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
63365393Sbostic {
63465393Sbostic 	register int k, m, n;
63565393Sbostic 	register uchar *s;
63665393Sbostic 	int temp;
63765393Sbostic 	register Cell *x, *y, *z;
63865393Sbostic 
63965393Sbostic 	x = execute(a[0]);
64065393Sbostic 	y = execute(a[1]);
64165393Sbostic 	if (a[2] != 0)
64265393Sbostic 		z = execute(a[2]);
64365393Sbostic 	s = getsval(x);
64465393Sbostic 	k = strlen(s) + 1;
64565393Sbostic 	if (k <= 1) {
64665393Sbostic 		tempfree(x);
64765393Sbostic 		tempfree(y);
64865393Sbostic 		if (a[2] != 0)
64965393Sbostic 			tempfree(z);
65065393Sbostic 		x = gettemp();
65165393Sbostic 		setsval(x, "");
65265393Sbostic 		return(x);
65365393Sbostic 	}
65465393Sbostic 	m = getfval(y);
65565393Sbostic 	if (m <= 0)
65665393Sbostic 		m = 1;
65765393Sbostic 	else if (m > k)
65865393Sbostic 		m = k;
65965393Sbostic 	tempfree(y);
66065393Sbostic 	if (a[2] != 0) {
66165393Sbostic 		n = getfval(z);
66265393Sbostic 		tempfree(z);
66365393Sbostic 	} else
66465393Sbostic 		n = k - 1;
66565393Sbostic 	if (n < 0)
66665393Sbostic 		n = 0;
66765393Sbostic 	else if (n > k - m)
66865393Sbostic 		n = k - m;
66965393Sbostic 	dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
67065393Sbostic 	y = gettemp();
67165393Sbostic 	temp = s[n+m-1];	/* with thanks to John Linderman */
67265393Sbostic 	s[n+m-1] = '\0';
67365393Sbostic 	setsval(y, s + m - 1);
67465393Sbostic 	s[n+m-1] = temp;
67565393Sbostic 	tempfree(x);
67665393Sbostic 	return(y);
67765393Sbostic }
67865393Sbostic 
sindex(Node ** a,int nnn)67965393Sbostic Cell *sindex(Node **a, int nnn)		/* index(a[0], a[1]) */
68065393Sbostic {
68165393Sbostic 	register Cell *x, *y, *z;
68265393Sbostic 	register uchar *s1, *s2, *p1, *p2, *q;
68365393Sbostic 	Awkfloat v = 0.0;
68465393Sbostic 
68565393Sbostic 	x = execute(a[0]);
68665393Sbostic 	s1 = getsval(x);
68765393Sbostic 	y = execute(a[1]);
68865393Sbostic 	s2 = getsval(y);
68965393Sbostic 
69065393Sbostic 	z = gettemp();
69165393Sbostic 	for (p1 = s1; *p1 != '\0'; p1++) {
69265393Sbostic 		for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
69365393Sbostic 			;
69465393Sbostic 		if (*p2 == '\0') {
69565393Sbostic 			v = (Awkfloat) (p1 - s1 + 1);	/* origin 1 */
69665393Sbostic 			break;
69765393Sbostic 		}
69865393Sbostic 	}
69965393Sbostic 	tempfree(x);
70065393Sbostic 	tempfree(y);
70165393Sbostic 	setfval(z, v);
70265393Sbostic 	return(z);
70365393Sbostic }
70465393Sbostic 
format(uchar * buf,int bufsize,uchar * s,Node * a)70565393Sbostic format(uchar *buf, int bufsize, uchar *s, Node *a)	/* printf-like conversions */
70665393Sbostic {
70765393Sbostic 	uchar fmt[RECSIZE];
70865393Sbostic 	register uchar *p, *t, *os;
70965393Sbostic 	register Cell *x;
71065393Sbostic 	int flag = 0, n;
71165393Sbostic 
71265393Sbostic 	os = s;
71365393Sbostic 	p = buf;
71465393Sbostic 	while (*s) {
71565393Sbostic 		if (p - buf >= bufsize)
71665393Sbostic 			return -1;
71765393Sbostic 		if (*s != '%') {
71865393Sbostic 			*p++ = *s++;
71965393Sbostic 			continue;
72065393Sbostic 		}
72165393Sbostic 		if (*(s+1) == '%') {
72265393Sbostic 			*p++ = '%';
72365393Sbostic 			s += 2;
72465393Sbostic 			continue;
72565393Sbostic 		}
72665393Sbostic 		for (t=fmt; (*t++ = *s) != '\0'; s++) {
72765393Sbostic 			if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
72865393Sbostic 				break;	/* the ansi panoply */
72965393Sbostic 			if (*s == '*') {
73065393Sbostic 				x = execute(a);
73165393Sbostic 				a = a->nnext;
73265393Sbostic 				sprintf((char *)t-1, "%d", (int) getfval(x));
73365393Sbostic 				t = fmt + strlen(fmt);
73465393Sbostic 				tempfree(x);
73565393Sbostic 			}
73665393Sbostic 		}
73765393Sbostic 		*t = '\0';
73865393Sbostic 		if (t >= fmt + sizeof(fmt))
73965393Sbostic 			ERROR "format item %.30s... too long", os FATAL;
74065393Sbostic 		switch (*s) {
74165393Sbostic 		case 'f': case 'e': case 'g': case 'E': case 'G':
74265393Sbostic 			flag = 1;
74365393Sbostic 			break;
74465393Sbostic 		case 'd': case 'i':
74565393Sbostic 			flag = 2;
74665393Sbostic 			if(*(s-1) == 'l') break;
74765393Sbostic 			*(t-1) = 'l';
74865393Sbostic 			*t = 'd';
74965393Sbostic 			*++t = '\0';
75065393Sbostic 			break;
75165393Sbostic 		case 'o': case 'x': case 'X': case 'u':
75265393Sbostic 			flag = *(s-1) == 'l' ? 2 : 3;
75365393Sbostic 			break;
75465393Sbostic 		case 's':
75565393Sbostic 			flag = 4;
75665393Sbostic 			break;
75765393Sbostic 		case 'c':
75865393Sbostic 			flag = 5;
75965393Sbostic 			break;
76065393Sbostic 		default:
76165393Sbostic 			ERROR "weird printf conversion %s", fmt WARNING;
76265393Sbostic 			flag = 0;
76365393Sbostic 			break;
76465393Sbostic 		}
76565393Sbostic 		if (a == NULL)
76665393Sbostic 			ERROR "not enough args in printf(%s)", os FATAL;
76765393Sbostic 		x = execute(a);
76865393Sbostic 		a = a->nnext;
76965393Sbostic 		switch (flag) {
77065393Sbostic 		case 0:	sprintf((char *)p, "%s", fmt);	/* unknown, so dump it too */
77165393Sbostic 			p += strlen(p);
77265393Sbostic 			sprintf((char *)p, "%s", getsval(x));
77365393Sbostic 			break;
77465393Sbostic 		case 1:	sprintf((char *)p, (char *)fmt, getfval(x)); break;
77565393Sbostic 		case 2:	sprintf((char *)p, (char *)fmt, (long) getfval(x)); break;
77665393Sbostic 		case 3:	sprintf((char *)p, (char *)fmt, (int) getfval(x)); break;
77765393Sbostic 		case 4:
77865393Sbostic 			t = getsval(x);
77965393Sbostic 			n = strlen(t);
78065393Sbostic 			if (n >= bufsize)
78165393Sbostic 				ERROR "huge string (%d chars) in printf %.30s...",
78265393Sbostic 					n, t FATAL;
78365393Sbostic 			sprintf((char *)p, (char *)fmt, t);
78465393Sbostic 			break;
78565393Sbostic 		case 5:
78665393Sbostic 			isnum(x) ? sprintf((char *)p, (char *)fmt, (int) getfval(x))
78765393Sbostic 				 : sprintf((char *)p, (char *)fmt, getsval(x)[0]);
78865393Sbostic 			break;
78965393Sbostic 		}
79065393Sbostic 		tempfree(x);
79165393Sbostic 		p += strlen(p);
79265393Sbostic 		s++;
79365393Sbostic 	}
79465393Sbostic 	*p = '\0';
79565393Sbostic 	for ( ; a; a = a->nnext)		/* evaluate any remaining args */
79665393Sbostic 		execute(a);
79765393Sbostic 	return 0;
79865393Sbostic }
79965393Sbostic 
asprintf(Node ** a,int n)80065393Sbostic Cell *asprintf(Node **a, int n)		/* sprintf(a[0]) */
80165393Sbostic {
80265393Sbostic 	register Cell *x;
80365393Sbostic 	register Node *y;
80465393Sbostic 	uchar buf[3*RECSIZE];
80565393Sbostic 
80665393Sbostic 	y = a[0]->nnext;
80765393Sbostic 	x = execute(a[0]);
80865393Sbostic 	if (format(buf, sizeof buf, getsval(x), y) == -1)
80965393Sbostic 		ERROR "sprintf string %.30s... too long", buf FATAL;
81065393Sbostic 	tempfree(x);
81165393Sbostic 	x = gettemp();
81265393Sbostic 	x->sval = tostring(buf);
81365393Sbostic 	x->tval = STR;
81465393Sbostic 	return(x);
81565393Sbostic }
81665393Sbostic 
aprintf(Node ** a,int n)81765393Sbostic Cell *aprintf(Node **a, int n)		/* printf */
81865393Sbostic {	/* a[0] is list of args, starting with format string */
81965393Sbostic 	/* a[1] is redirection operator, a[2] is redirection file */
82065393Sbostic 	FILE *fp;
82165393Sbostic 	register Cell *x;
82265393Sbostic 	register Node *y;
82365393Sbostic 	uchar buf[3*RECSIZE];
82465393Sbostic 
82565393Sbostic 	y = a[0]->nnext;
82665393Sbostic 	x = execute(a[0]);
82765393Sbostic 	if (format(buf, sizeof buf, getsval(x), y) == -1)
82865393Sbostic 		ERROR "printf string %.30s... too long", buf FATAL;
82965393Sbostic 	tempfree(x);
83065393Sbostic 	if (a[1] == NULL) {
83165393Sbostic 		fputs((char *)buf, stdout);
83265393Sbostic 		if (ferror(stdout))
83365393Sbostic 			ERROR "write error on stdout" FATAL;
83465393Sbostic 	} else {
83565393Sbostic 		fp = redirect((int)a[1], a[2]);
83665393Sbostic 		fputs((char *)buf, fp);
83765393Sbostic 		fflush(fp);
83865393Sbostic 		if (ferror(fp))
83965393Sbostic 			ERROR "write error on %s", filename(fp) FATAL;
84065393Sbostic 	}
84165393Sbostic 	return(true);
84265393Sbostic }
84365393Sbostic 
arith(Node ** a,int n)84465393Sbostic Cell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
84565393Sbostic {
84665393Sbostic 	Awkfloat i, j;
84765393Sbostic 	double v;
84865393Sbostic 	register Cell *x, *y, *z;
84965393Sbostic 
85065393Sbostic 	x = execute(a[0]);
85165393Sbostic 	i = getfval(x);
85265393Sbostic 	tempfree(x);
85365393Sbostic 	if (n != UMINUS) {
85465393Sbostic 		y = execute(a[1]);
85565393Sbostic 		j = getfval(y);
85665393Sbostic 		tempfree(y);
85765393Sbostic 	}
85865393Sbostic 	z = gettemp();
85965393Sbostic 	switch (n) {
86065393Sbostic 	case ADD:
86165393Sbostic 		i += j;
86265393Sbostic 		break;
86365393Sbostic 	case MINUS:
86465393Sbostic 		i -= j;
86565393Sbostic 		break;
86665393Sbostic 	case MULT:
86765393Sbostic 		i *= j;
86865393Sbostic 		break;
86965393Sbostic 	case DIVIDE:
87065393Sbostic 		if (j == 0)
87165393Sbostic 			ERROR "division by zero" FATAL;
87265393Sbostic 		i /= j;
87365393Sbostic 		break;
87465393Sbostic 	case MOD:
87565393Sbostic 		if (j == 0)
87665393Sbostic 			ERROR "division by zero in mod" FATAL;
87765393Sbostic 		modf(i/j, &v);
87865393Sbostic 		i = i - j * v;
87965393Sbostic 		break;
88065393Sbostic 	case UMINUS:
88165393Sbostic 		i = -i;
88265393Sbostic 		break;
88365393Sbostic 	case POWER:
88465393Sbostic 		if (j >= 0 && modf(j, &v) == 0.0)	/* pos integer exponent */
88565393Sbostic 			i = ipow(i, (int) j);
88665393Sbostic 		else
88765393Sbostic 			i = errcheck(pow(i, j), "pow");
88865393Sbostic 		break;
88965393Sbostic 	default:	/* can't happen */
89065393Sbostic 		ERROR "illegal arithmetic operator %d", n FATAL;
89165393Sbostic 	}
89265393Sbostic 	setfval(z, i);
89365393Sbostic 	return(z);
89465393Sbostic }
89565393Sbostic 
ipow(double x,int n)89665393Sbostic double ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
89765393Sbostic {
89865393Sbostic 	double v;
89965393Sbostic 
90065393Sbostic 	if (n <= 0)
90165393Sbostic 		return 1;
90265393Sbostic 	v = ipow(x, n/2);
90365393Sbostic 	if (n % 2 == 0)
90465393Sbostic 		return v * v;
90565393Sbostic 	else
90665393Sbostic 		return x * v * v;
90765393Sbostic }
90865393Sbostic 
incrdecr(Node ** a,int n)90965393Sbostic Cell *incrdecr(Node **a, int n)		/* a[0]++, etc. */
91065393Sbostic {
91165393Sbostic 	register Cell *x, *z;
91265393Sbostic 	register int k;
91365393Sbostic 	Awkfloat xf;
91465393Sbostic 
91565393Sbostic 	x = execute(a[0]);
91665393Sbostic 	xf = getfval(x);
91765393Sbostic 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
91865393Sbostic 	if (n == PREINCR || n == PREDECR) {
91965393Sbostic 		setfval(x, xf + k);
92065393Sbostic 		return(x);
92165393Sbostic 	}
92265393Sbostic 	z = gettemp();
92365393Sbostic 	setfval(z, xf);
92465393Sbostic 	setfval(x, xf + k);
92565393Sbostic 	tempfree(x);
92665393Sbostic 	return(z);
92765393Sbostic }
92865393Sbostic 
assign(Node ** a,int n)92965393Sbostic Cell *assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
93065393Sbostic {		/* this is subtle; don't muck with it. */
93165393Sbostic 	register Cell *x, *y;
93265393Sbostic 	Awkfloat xf, yf;
93365393Sbostic 	double v;
93465393Sbostic 
93565393Sbostic 	y = execute(a[1]);
93665393Sbostic 	x = execute(a[0]);
93765393Sbostic 	if (n == ASSIGN) {	/* ordinary assignment */
93865393Sbostic 		if (x == y && !(x->tval & (FLD|REC)))	/* self-assignment: */
93965393Sbostic 			;		/* leave alone unless it's a field */
94065393Sbostic 		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
94165393Sbostic 			setsval(x, getsval(y));
94265393Sbostic 			x->fval = getfval(y);
94365393Sbostic 			x->tval |= NUM;
94465393Sbostic 		}
94565393Sbostic 		else if (y->tval & STR)
94665393Sbostic 			setsval(x, getsval(y));
94765393Sbostic 		else if (y->tval & NUM)
94865393Sbostic 			setfval(x, getfval(y));
94965393Sbostic 		else
95065393Sbostic 			funnyvar(y, "read value of");
95165393Sbostic 		tempfree(y);
95265393Sbostic 		return(x);
95365393Sbostic 	}
95465393Sbostic 	xf = getfval(x);
95565393Sbostic 	yf = getfval(y);
95665393Sbostic 	switch (n) {
95765393Sbostic 	case ADDEQ:
95865393Sbostic 		xf += yf;
95965393Sbostic 		break;
96065393Sbostic 	case SUBEQ:
96165393Sbostic 		xf -= yf;
96265393Sbostic 		break;
96365393Sbostic 	case MULTEQ:
96465393Sbostic 		xf *= yf;
96565393Sbostic 		break;
96665393Sbostic 	case DIVEQ:
96765393Sbostic 		if (yf == 0)
96865393Sbostic 			ERROR "division by zero in /=" FATAL;
96965393Sbostic 		xf /= yf;
97065393Sbostic 		break;
97165393Sbostic 	case MODEQ:
97265393Sbostic 		if (yf == 0)
97365393Sbostic 			ERROR "division by zero in %%=" FATAL;
97465393Sbostic 		modf(xf/yf, &v);
97565393Sbostic 		xf = xf - yf * v;
97665393Sbostic 		break;
97765393Sbostic 	case POWEQ:
97865393Sbostic 		if (yf >= 0 && modf(yf, &v) == 0.0)	/* pos integer exponent */
97965393Sbostic 			xf = ipow(xf, (int) yf);
98065393Sbostic 		else
98165393Sbostic 			xf = errcheck(pow(xf, yf), "pow");
98265393Sbostic 		break;
98365393Sbostic 	default:
98465393Sbostic 		ERROR "illegal assignment operator %d", n FATAL;
98565393Sbostic 		break;
98665393Sbostic 	}
98765393Sbostic 	tempfree(y);
98865393Sbostic 	setfval(x, xf);
98965393Sbostic 	return(x);
99065393Sbostic }
99165393Sbostic 
cat(Node ** a,int q)99265393Sbostic Cell *cat(Node **a, int q)	/* a[0] cat a[1] */
99365393Sbostic {
99465393Sbostic 	register Cell *x, *y, *z;
99565393Sbostic 	register int n1, n2;
99665393Sbostic 	register uchar *s;
99765393Sbostic 
99865393Sbostic 	x = execute(a[0]);
99965393Sbostic 	y = execute(a[1]);
100065393Sbostic 	getsval(x);
100165393Sbostic 	getsval(y);
100265393Sbostic 	n1 = strlen(x->sval);
100365393Sbostic 	n2 = strlen(y->sval);
100465393Sbostic 	s = (uchar *) malloc(n1 + n2 + 1);
100565393Sbostic 	if (s == NULL)
100665393Sbostic 		ERROR "out of space concatenating %.15s... and %.15s...",
100765393Sbostic 			x->sval, y->sval FATAL;
100865393Sbostic 	strcpy(s, x->sval);
100965393Sbostic 	strcpy(s+n1, y->sval);
101065393Sbostic 	tempfree(y);
101165393Sbostic 	z = gettemp();
101265393Sbostic 	z->sval = s;
101365393Sbostic 	z->tval = STR;
101465393Sbostic 	tempfree(x);
101565393Sbostic 	return(z);
101665393Sbostic }
101765393Sbostic 
pastat(Node ** a,int n)101865393Sbostic Cell *pastat(Node **a, int n)	/* a[0] { a[1] } */
101965393Sbostic {
102065393Sbostic 	register Cell *x;
102165393Sbostic 
102265393Sbostic 	if (a[0] == 0)
102365393Sbostic 		x = execute(a[1]);
102465393Sbostic 	else {
102565393Sbostic 		x = execute(a[0]);
102665393Sbostic 		if (istrue(x)) {
102765393Sbostic 			tempfree(x);
102865393Sbostic 			x = execute(a[1]);
102965393Sbostic 		}
103065393Sbostic 	}
103165393Sbostic 	return x;
103265393Sbostic }
103365393Sbostic 
dopa2(Node ** a,int n)103465393Sbostic Cell *dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
103565393Sbostic {
103665393Sbostic 	register Cell *x;
103765393Sbostic 	register int pair;
103865393Sbostic 
103965393Sbostic 	pair = (int) a[3];
104065393Sbostic 	if (pairstack[pair] == 0) {
104165393Sbostic 		x = execute(a[0]);
104265393Sbostic 		if (istrue(x))
104365393Sbostic 			pairstack[pair] = 1;
104465393Sbostic 		tempfree(x);
104565393Sbostic 	}
104665393Sbostic 	if (pairstack[pair] == 1) {
104765393Sbostic 		x = execute(a[1]);
104865393Sbostic 		if (istrue(x))
104965393Sbostic 			pairstack[pair] = 0;
105065393Sbostic 		tempfree(x);
105165393Sbostic 		x = execute(a[2]);
105265393Sbostic 		return(x);
105365393Sbostic 	}
105465393Sbostic 	return(false);
105565393Sbostic }
105665393Sbostic 
split(Node ** a,int nnn)105765393Sbostic Cell *split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
105865393Sbostic {
105965393Sbostic 	Cell *x, *y, *ap;
106065393Sbostic 	register uchar *s;
106165393Sbostic 	register int sep;
106265393Sbostic 	uchar *t, temp, num[10], *fs;
106365393Sbostic 	int n, tempstat;
106465393Sbostic 
106565393Sbostic 	y = execute(a[0]);	/* source string */
106665393Sbostic 	s = getsval(y);
106765393Sbostic 	if (a[2] == 0)		/* fs string */
106865393Sbostic 		fs = *FS;
106965393Sbostic 	else if ((int) a[3] == STRING) {	/* split(str,arr,"string") */
107065393Sbostic 		x = execute(a[2]);
107165393Sbostic 		fs = getsval(x);
107265393Sbostic 	} else if ((int) a[3] == REGEXPR)
107365393Sbostic 		fs = (uchar*) "(regexpr)";	/* split(str,arr,/regexpr/) */
107465393Sbostic 	else
107565393Sbostic 		ERROR "illegal type of split()" FATAL;
107665393Sbostic 	sep = *fs;
107765393Sbostic 	ap = execute(a[1]);	/* array name */
107865393Sbostic 	freesymtab(ap);
107965393Sbostic 	dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
108065393Sbostic 	ap->tval &= ~STR;
108165393Sbostic 	ap->tval |= ARR;
108265393Sbostic 	ap->sval = (uchar *) makesymtab(NSYMTAB);
108365393Sbostic 
108465393Sbostic 	n = 0;
108565393Sbostic 	if (*s != '\0' && strlen(fs) > 1 || (int) a[3] == REGEXPR) {	/* reg expr */
108665393Sbostic 		fa *pfa;
108765393Sbostic 		if ((int) a[3] == REGEXPR) {	/* it's ready already */
108865393Sbostic 			pfa = (fa *) a[2];
108965393Sbostic 		} else {
109065393Sbostic 			pfa = makedfa(fs, 1);
109165393Sbostic 		}
109265393Sbostic 		if (nematch(pfa,s)) {
109365393Sbostic 			tempstat = pfa->initstat;
109465393Sbostic 			pfa->initstat = 2;
109565393Sbostic 			do {
109665393Sbostic 				n++;
109765393Sbostic 				sprintf((char *)num, "%d", n);
109865393Sbostic 				temp = *patbeg;
109965393Sbostic 				*patbeg = '\0';
1100*65396Sbostic 				if (is_a_number(s))
110165393Sbostic 					setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval);
110265393Sbostic 				else
110365393Sbostic 					setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
110465393Sbostic 				*patbeg = temp;
110565393Sbostic 				s = patbeg + patlen;
110665393Sbostic 				if (*(patbeg+patlen-1) == 0 || *s == 0) {
110765393Sbostic 					n++;
110865393Sbostic 					sprintf((char *)num, "%d", n);
110965393Sbostic 					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
111065393Sbostic 					pfa->initstat = tempstat;
111165393Sbostic 					goto spdone;
111265393Sbostic 				}
111365393Sbostic 			} while (nematch(pfa,s));
111465393Sbostic 		}
111565393Sbostic 		n++;
111665393Sbostic 		sprintf((char *)num, "%d", n);
1117*65396Sbostic 		if (is_a_number(s))
111865393Sbostic 			setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval);
111965393Sbostic 		else
112065393Sbostic 			setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
112165393Sbostic   spdone:
112265393Sbostic 		pfa = NULL;
112365393Sbostic 	} else if (sep == ' ') {
112465393Sbostic 		for (n = 0; ; ) {
112565393Sbostic 			while (*s == ' ' || *s == '\t' || *s == '\n')
112665393Sbostic 				s++;
112765393Sbostic 			if (*s == 0)
112865393Sbostic 				break;
112965393Sbostic 			n++;
113065393Sbostic 			t = s;
113165393Sbostic 			do
113265393Sbostic 				s++;
113365393Sbostic 			while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
113465393Sbostic 			temp = *s;
113565393Sbostic 			*s = '\0';
113665393Sbostic 			sprintf((char *)num, "%d", n);
1137*65396Sbostic 			if (is_a_number(t))
113865393Sbostic 				setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
113965393Sbostic 			else
114065393Sbostic 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
114165393Sbostic 			*s = temp;
114265393Sbostic 			if (*s != 0)
114365393Sbostic 				s++;
114465393Sbostic 		}
114565393Sbostic 	} else if (*s != 0) {
114665393Sbostic 		for (;;) {
114765393Sbostic 			n++;
114865393Sbostic 			t = s;
114965393Sbostic 			while (*s != sep && *s != '\n' && *s != '\0')
115065393Sbostic 				s++;
115165393Sbostic 			temp = *s;
115265393Sbostic 			*s = '\0';
115365393Sbostic 			sprintf((char *)num, "%d", n);
1154*65396Sbostic 			if (is_a_number(t))
115565393Sbostic 				setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
115665393Sbostic 			else
115765393Sbostic 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
115865393Sbostic 			*s = temp;
115965393Sbostic 			if (*s++ == 0)
116065393Sbostic 				break;
116165393Sbostic 		}
116265393Sbostic 	}
116365393Sbostic 	tempfree(ap);
116465393Sbostic 	tempfree(y);
116565393Sbostic 	if (a[2] != 0 && (int) a[3] == STRING)
116665393Sbostic 		tempfree(x);
116765393Sbostic 	x = gettemp();
116865393Sbostic 	x->tval = NUM;
116965393Sbostic 	x->fval = n;
117065393Sbostic 	return(x);
117165393Sbostic }
117265393Sbostic 
condexpr(Node ** a,int n)117365393Sbostic Cell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
117465393Sbostic {
117565393Sbostic 	register Cell *x;
117665393Sbostic 
117765393Sbostic 	x = execute(a[0]);
117865393Sbostic 	if (istrue(x)) {
117965393Sbostic 		tempfree(x);
118065393Sbostic 		x = execute(a[1]);
118165393Sbostic 	} else {
118265393Sbostic 		tempfree(x);
118365393Sbostic 		x = execute(a[2]);
118465393Sbostic 	}
118565393Sbostic 	return(x);
118665393Sbostic }
118765393Sbostic 
ifstat(Node ** a,int n)118865393Sbostic Cell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
118965393Sbostic {
119065393Sbostic 	register Cell *x;
119165393Sbostic 
119265393Sbostic 	x = execute(a[0]);
119365393Sbostic 	if (istrue(x)) {
119465393Sbostic 		tempfree(x);
119565393Sbostic 		x = execute(a[1]);
119665393Sbostic 	} else if (a[2] != 0) {
119765393Sbostic 		tempfree(x);
119865393Sbostic 		x = execute(a[2]);
119965393Sbostic 	}
120065393Sbostic 	return(x);
120165393Sbostic }
120265393Sbostic 
whilestat(Node ** a,int n)120365393Sbostic Cell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
120465393Sbostic {
120565393Sbostic 	register Cell *x;
120665393Sbostic 
120765393Sbostic 	for (;;) {
120865393Sbostic 		x = execute(a[0]);
120965393Sbostic 		if (!istrue(x))
121065393Sbostic 			return(x);
121165393Sbostic 		tempfree(x);
121265393Sbostic 		x = execute(a[1]);
121365393Sbostic 		if (isbreak(x)) {
121465393Sbostic 			x = true;
121565393Sbostic 			return(x);
121665393Sbostic 		}
121765393Sbostic 		if (isnext(x) || isexit(x) || isret(x))
121865393Sbostic 			return(x);
121965393Sbostic 		tempfree(x);
122065393Sbostic 	}
122165393Sbostic }
122265393Sbostic 
dostat(Node ** a,int n)122365393Sbostic Cell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
122465393Sbostic {
122565393Sbostic 	register Cell *x;
122665393Sbostic 
122765393Sbostic 	for (;;) {
122865393Sbostic 		x = execute(a[0]);
122965393Sbostic 		if (isbreak(x))
123065393Sbostic 			return true;
123165393Sbostic 		if (isnext(x) || isexit(x) || isret(x))
123265393Sbostic 			return(x);
123365393Sbostic 		tempfree(x);
123465393Sbostic 		x = execute(a[1]);
123565393Sbostic 		if (!istrue(x))
123665393Sbostic 			return(x);
123765393Sbostic 		tempfree(x);
123865393Sbostic 	}
123965393Sbostic }
124065393Sbostic 
forstat(Node ** a,int n)124165393Sbostic Cell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
124265393Sbostic {
124365393Sbostic 	register Cell *x;
124465393Sbostic 
124565393Sbostic 	x = execute(a[0]);
124665393Sbostic 	tempfree(x);
124765393Sbostic 	for (;;) {
124865393Sbostic 		if (a[1]!=0) {
124965393Sbostic 			x = execute(a[1]);
125065393Sbostic 			if (!istrue(x)) return(x);
125165393Sbostic 			else tempfree(x);
125265393Sbostic 		}
125365393Sbostic 		x = execute(a[3]);
125465393Sbostic 		if (isbreak(x))		/* turn off break */
125565393Sbostic 			return true;
125665393Sbostic 		if (isnext(x) || isexit(x) || isret(x))
125765393Sbostic 			return(x);
125865393Sbostic 		tempfree(x);
125965393Sbostic 		x = execute(a[2]);
126065393Sbostic 		tempfree(x);
126165393Sbostic 	}
126265393Sbostic }
126365393Sbostic 
instat(Node ** a,int n)126465393Sbostic Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
126565393Sbostic {
126665393Sbostic 	register Cell *x, *vp, *arrayp, *cp, *ncp;
126765393Sbostic 	Array *tp;
126865393Sbostic 	int i;
126965393Sbostic 
127065393Sbostic 	vp = execute(a[0]);
127165393Sbostic 	arrayp = execute(a[1]);
127265393Sbostic 	if (!isarr(arrayp)) {
127365393Sbostic 		return true;
127465393Sbostic 	}
127565393Sbostic 	tp = (Array *) arrayp->sval;
127665393Sbostic 	tempfree(arrayp);
127765393Sbostic 	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
127865393Sbostic 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
127965393Sbostic 			setsval(vp, cp->nval);
128065393Sbostic 			ncp = cp->cnext;
128165393Sbostic 			x = execute(a[2]);
128265393Sbostic 			if (isbreak(x)) {
128365393Sbostic 				tempfree(vp);
128465393Sbostic 				return true;
128565393Sbostic 			}
128665393Sbostic 			if (isnext(x) || isexit(x) || isret(x)) {
128765393Sbostic 				tempfree(vp);
128865393Sbostic 				return(x);
128965393Sbostic 			}
129065393Sbostic 			tempfree(x);
129165393Sbostic 		}
129265393Sbostic 	}
129365393Sbostic 	return true;
129465393Sbostic }
129565393Sbostic 
129665393Sbostic /* if someone ever wants to run over the arrays in sorted order, */
129765393Sbostic /* here it is.  but it will likely run slower, not faster. */
129865393Sbostic 
129965393Sbostic /*
130065393Sbostic  *int qstrcmp(p, q)
130165393Sbostic  *	uchar **p, **q;
130265393Sbostic  *{
130365393Sbostic  *	return strcmp(*p, *q);
130465393Sbostic  *}
130565393Sbostic  */
130665393Sbostic 
130765393Sbostic /*Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
130865393Sbostic /*{
130965393Sbostic /*	register Cell *x, *vp, *arrayp, *cp, *ncp, *ret;
131065393Sbostic /*	Array *tp;
131165393Sbostic /*	int i, ne;
131265393Sbostic /*#define BIGENOUGH 1000
131365393Sbostic /*	uchar *elems[BIGENOUGH], **ep;
131465393Sbostic /*
131565393Sbostic /*	vp = execute(a[0]);
131665393Sbostic /*	arrayp = execute(a[1]);
131765393Sbostic /*	if (!isarr(arrayp))
131865393Sbostic /*		ERROR "%s is not an array", arrayp->nval FATAL;
131965393Sbostic /*	tp = (Array *) arrayp->sval;
132065393Sbostic /*	tempfree(arrayp);
132165393Sbostic /*	ep = elems;
132265393Sbostic /*	ret = true;
132365393Sbostic /*	if (tp->nelem >= BIGENOUGH)
132465393Sbostic /*		ep = (uchar **) malloc(tp->nelem * sizeof(char *));
132565393Sbostic /*
132665393Sbostic /*	for (i = ne = 0; i < tp->size; i++)
132765393Sbostic /*		for (cp = tp->tab[i]; cp != NULL; cp = cp->cnext)
132865393Sbostic /*			ep[ne++] = cp->nval;
132965393Sbostic /*	if (ne != tp->nelem)
133065393Sbostic /*		ERROR "can't happen: lost elems %d vs. %d", ne, tp->nelem FATAL;
133165393Sbostic /*	qsort(ep, ne, sizeof(char *), qstrcmp);
133265393Sbostic /*	for (i = 0; i < ne; i++) {
133365393Sbostic /*		setsval(vp, ep[i]);
133465393Sbostic /*		x = execute(a[2]);
133565393Sbostic /*		if (isbreak(x)) {
133665393Sbostic /*			tempfree(vp);
133765393Sbostic /*			break;
133865393Sbostic /*		}
133965393Sbostic /*		if (isnext(x) || isexit(x) || isret(x)) {
134065393Sbostic /*			tempfree(vp);
134165393Sbostic /*			ret = x;
134265393Sbostic /*			break;
134365393Sbostic /*		}
134465393Sbostic /*		tempfree(x);
134565393Sbostic /*	}
134665393Sbostic /*	if (ep != elems)
134765393Sbostic /*		free(ep);
134865393Sbostic /*	return ret;
134965393Sbostic /*}
135065393Sbostic */
135165393Sbostic 
135265393Sbostic 
bltin(Node ** a,int n)135365393Sbostic Cell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
135465393Sbostic {
135565393Sbostic 	register Cell *x, *y;
135665393Sbostic 	Awkfloat u;
135765393Sbostic 	register int t;
135865393Sbostic 	uchar *p, buf[RECSIZE];
135965393Sbostic 	Node *nextarg;
136065393Sbostic 	FILE *fp;
136165393Sbostic 
136265393Sbostic 	t = (int) a[0];
136365393Sbostic 	x = execute(a[1]);
136465393Sbostic 	nextarg = a[1]->nnext;
136565393Sbostic 	switch (t) {
136665393Sbostic 	case FLENGTH:
136765393Sbostic 		u = strlen(getsval(x)); break;
136865393Sbostic 	case FLOG:
136965393Sbostic 		u = errcheck(log(getfval(x)), "log"); break;
137065393Sbostic 	case FINT:
137165393Sbostic 		modf(getfval(x), &u); break;
137265393Sbostic 	case FEXP:
137365393Sbostic 		u = errcheck(exp(getfval(x)), "exp"); break;
137465393Sbostic 	case FSQRT:
137565393Sbostic 		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
137665393Sbostic 	case FSIN:
137765393Sbostic 		u = sin(getfval(x)); break;
137865393Sbostic 	case FCOS:
137965393Sbostic 		u = cos(getfval(x)); break;
138065393Sbostic 	case FATAN:
138165393Sbostic 		if (nextarg == 0) {
138265393Sbostic 			ERROR "atan2 requires two arguments; returning 1.0" WARNING;
138365393Sbostic 			u = 1.0;
138465393Sbostic 		} else {
138565393Sbostic 			y = execute(a[1]->nnext);
138665393Sbostic 			u = atan2(getfval(x), getfval(y));
138765393Sbostic 			tempfree(y);
138865393Sbostic 			nextarg = nextarg->nnext;
138965393Sbostic 		}
139065393Sbostic 		break;
139165393Sbostic 	case FSYSTEM:
139265393Sbostic 		fflush(stdout);		/* in case something is buffered already */
139365393Sbostic 		u = (Awkfloat) system((char *)getsval(x)) / 256;   /* 256 is unix-dep */
139465393Sbostic 		break;
139565393Sbostic 	case FRAND:
139665393Sbostic 		/* in principle, rand() returns something in 0..RAND_MAX */
139765393Sbostic 		u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
139865393Sbostic 		break;
139965393Sbostic 	case FSRAND:
140065393Sbostic 		if (x->tval & REC)	/* no argument provided */
140165393Sbostic 			u = time((long *)0);
140265393Sbostic 		else
140365393Sbostic 			u = getfval(x);
140465393Sbostic 		srand((int) u); u = (int) u;
140565393Sbostic 		break;
140665393Sbostic 	case FTOUPPER:
140765393Sbostic 	case FTOLOWER:
140865393Sbostic 		strcpy(buf, getsval(x));
140965393Sbostic 		if (t == FTOUPPER) {
141065393Sbostic 			for (p = buf; *p; p++)
141165393Sbostic 				if (islower(*p))
141265393Sbostic 					*p = toupper(*p);
141365393Sbostic 		} else {
141465393Sbostic 			for (p = buf; *p; p++)
141565393Sbostic 				if (isupper(*p))
141665393Sbostic 					*p = tolower(*p);
141765393Sbostic 		}
141865393Sbostic 		tempfree(x);
141965393Sbostic 		x = gettemp();
142065393Sbostic 		setsval(x, buf);
142165393Sbostic 		return x;
142265393Sbostic 	case FFLUSH:
142365393Sbostic 		if ((fp = openfile(GT, getsval(x))) == NULL)
142465393Sbostic 			u = EOF;
142565393Sbostic 		else
142665393Sbostic 			u = fflush(fp);
142765393Sbostic 		break;
142865393Sbostic 	default:	/* can't happen */
142965393Sbostic 		ERROR "illegal function type %d", t FATAL;
143065393Sbostic 		break;
143165393Sbostic 	}
143265393Sbostic 	tempfree(x);
143365393Sbostic 	x = gettemp();
143465393Sbostic 	setfval(x, u);
143565393Sbostic 	if (nextarg != 0) {
143665393Sbostic 		ERROR "warning: function has too many arguments" WARNING;
143765393Sbostic 		for ( ; nextarg; nextarg = nextarg->nnext)
143865393Sbostic 			execute(nextarg);
143965393Sbostic 	}
144065393Sbostic 	return(x);
144165393Sbostic }
144265393Sbostic 
printstat(Node ** a,int n)144365393Sbostic Cell *printstat(Node **a, int n)	/* print a[0] */
144465393Sbostic {
144565393Sbostic 	register Node *x;
144665393Sbostic 	register Cell *y;
144765393Sbostic 	FILE *fp;
144865393Sbostic 
144965393Sbostic 	if (a[1] == 0)	/* a[1] is redirection operator, a[2] is file */
145065393Sbostic 		fp = stdout;
145165393Sbostic 	else
145265393Sbostic 		fp = redirect((int)a[1], a[2]);
145365393Sbostic 	for (x = a[0]; x != NULL; x = x->nnext) {
145465393Sbostic 		y = execute(x);
145565393Sbostic 		fputs((char *)getsval(y), fp);
145665393Sbostic 		tempfree(y);
145765393Sbostic 		if (x->nnext == NULL)
145865393Sbostic 			fputs((char *)*ORS, fp);
145965393Sbostic 		else
146065393Sbostic 			fputs((char *)*OFS, fp);
146165393Sbostic 	}
146265393Sbostic 	if (a[1] != 0)
146365393Sbostic 		fflush(fp);
146465393Sbostic 	if (ferror(fp))
146565393Sbostic 		ERROR "write error on %s", filename(fp) FATAL;
146665393Sbostic 	return(true);
146765393Sbostic }
146865393Sbostic 
nullproc(Node ** a,int n)146965393Sbostic Cell *nullproc(Node **a, int n)
147065393Sbostic {
147165393Sbostic 	n;
147265393Sbostic 	a;
147365393Sbostic 	return 0;
147465393Sbostic }
147565393Sbostic 
147665393Sbostic 
redirect(int a,Node * b)147765393Sbostic FILE *redirect(int a, Node *b)	/* set up all i/o redirections */
147865393Sbostic {
147965393Sbostic 	FILE *fp;
148065393Sbostic 	Cell *x;
148165393Sbostic 	uchar *fname;
148265393Sbostic 
148365393Sbostic 	x = execute(b);
148465393Sbostic 	fname = getsval(x);
148565393Sbostic 	fp = openfile(a, fname);
148665393Sbostic 	if (fp == NULL)
148765393Sbostic 		ERROR "can't open file %s", fname FATAL;
148865393Sbostic 	tempfree(x);
148965393Sbostic 	return fp;
149065393Sbostic }
149165393Sbostic 
149265393Sbostic struct files {
149365393Sbostic 	FILE	*fp;
149465393Sbostic 	uchar	*fname;
149565393Sbostic 	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
149665393Sbostic } files[FOPEN_MAX] ={
149765393Sbostic 	{ stdin,  "/dev/stdin",  LT },	/* watch out: don't free this! */
149865393Sbostic 	{ stdout, "/dev/stdout", GT },
149965393Sbostic 	{ stderr, "/dev/stderr", GT }
150065393Sbostic };
150165393Sbostic 
openfile(int a,uchar * us)150265393Sbostic FILE *openfile(int a, uchar *us)
150365393Sbostic {
150465393Sbostic 	char *s = us;
150565393Sbostic 	register int i, m;
150665393Sbostic 	register FILE *fp;
150765393Sbostic 
150865393Sbostic 	if (*s == '\0')
150965393Sbostic 		ERROR "null file name in print or getline" FATAL;
151065393Sbostic 	for (i=0; i < FOPEN_MAX; i++)
151165393Sbostic 		if (files[i].fname && strcmp(s, files[i].fname) == 0)
151265393Sbostic 			if (a == files[i].mode || a==APPEND && files[i].mode==GT)
151365393Sbostic 				return files[i].fp;
151465393Sbostic 	for (i=0; i < FOPEN_MAX; i++)
151565393Sbostic 		if (files[i].fp == 0)
151665393Sbostic 			break;
151765393Sbostic 	if (i >= FOPEN_MAX)
151865393Sbostic 		ERROR "%s makes too many open files", s FATAL;
151965393Sbostic 	fflush(stdout);	/* force a semblance of order */
152065393Sbostic 	m = a;
152165393Sbostic 	if (a == GT) {
152265393Sbostic 		fp = fopen(s, "w");
152365393Sbostic 	} else if (a == APPEND) {
152465393Sbostic 		fp = fopen(s, "a");
152565393Sbostic 		m = GT;	/* so can mix > and >> */
152665393Sbostic 	} else if (a == '|') {	/* output pipe */
152765393Sbostic 		fp = popen(s, "w");
152865393Sbostic 	} else if (a == LE) {	/* input pipe */
152965393Sbostic 		fp = popen(s, "r");
153065393Sbostic 	} else if (a == LT) {	/* getline <file */
153165393Sbostic 		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
153265393Sbostic 	} else	/* can't happen */
153365393Sbostic 		ERROR "illegal redirection %d", a FATAL;
153465393Sbostic 	if (fp != NULL) {
153565393Sbostic 		files[i].fname = tostring(s);
153665393Sbostic 		files[i].fp = fp;
153765393Sbostic 		files[i].mode = m;
153865393Sbostic 	}
153965393Sbostic 	return fp;
154065393Sbostic }
154165393Sbostic 
filename(FILE * fp)154265393Sbostic uchar *filename(FILE *fp)
154365393Sbostic {
154465393Sbostic 	int i;
154565393Sbostic 
154665393Sbostic 	for (i = 0; i < FOPEN_MAX; i++)
154765393Sbostic 		if (fp == files[i].fp)
154865393Sbostic 			return files[i].fname;
154965393Sbostic 	return "???";
155065393Sbostic }
155165393Sbostic 
closefile(Node ** a,int n)155265393Sbostic Cell *closefile(Node **a, int n)
155365393Sbostic {
155465393Sbostic 	register Cell *x;
155565393Sbostic 	int i, stat;
155665393Sbostic 
155765393Sbostic 	n;
155865393Sbostic 	x = execute(a[0]);
155965393Sbostic 	getsval(x);
156065393Sbostic 	for (i = 0; i < FOPEN_MAX; i++)
156165393Sbostic 		if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
156265393Sbostic 			if (ferror(files[i].fp))
156365393Sbostic 				ERROR "i/o error occurred on %s", files[i].fname WARNING;
156465393Sbostic 			if (files[i].mode == '|' || files[i].mode == LE)
156565393Sbostic 				stat = pclose(files[i].fp);
156665393Sbostic 			else
156765393Sbostic 				stat = fclose(files[i].fp);
156865393Sbostic 			if (stat == EOF)
156965393Sbostic 				ERROR "i/o error occurred closing %s", files[i].fname WARNING;
157065393Sbostic 			if (i > 2)	/* don't do /dev/std... */
157165393Sbostic 				xfree(files[i].fname);
157265393Sbostic 			files[i].fname = NULL;	/* watch out for ref thru this */
157365393Sbostic 			files[i].fp = NULL;
157465393Sbostic 		}
157565393Sbostic 	tempfree(x);
157665393Sbostic 	return(true);
157765393Sbostic }
157865393Sbostic 
closeall(void)157965393Sbostic void closeall(void)
158065393Sbostic {
158165393Sbostic 	int i, stat;
158265393Sbostic 
158365393Sbostic 	for (i = 0; i < FOPEN_MAX; i++)
158465393Sbostic 		if (files[i].fp) {
158565393Sbostic 			if (ferror(files[i].fp))
158665393Sbostic 				ERROR "i/o error occurred on %s", files[i].fname WARNING;
158765393Sbostic 			if (files[i].mode == '|' || files[i].mode == LE)
158865393Sbostic 				stat = pclose(files[i].fp);
158965393Sbostic 			else
159065393Sbostic 				stat = fclose(files[i].fp);
159165393Sbostic 			if (stat == EOF)
159265393Sbostic 				ERROR "i/o error occurred while closing %s", files[i].fname WARNING;
159365393Sbostic 		}
159465393Sbostic }
159565393Sbostic 
159665393Sbostic #define	SUBSIZE	(20 * RECSIZE)
159765393Sbostic 
sub(Node ** a,int nnn)159865393Sbostic Cell *sub(Node **a, int nnn)	/* substitute command */
159965393Sbostic {
160065393Sbostic 	register uchar *sptr, *pb, *q;
160165393Sbostic 	register Cell *x, *y, *result;
160265393Sbostic 	uchar buf[SUBSIZE], *t;
160365393Sbostic 	fa *pfa;
160465393Sbostic 
160565393Sbostic 	x = execute(a[3]);	/* target string */
160665393Sbostic 	t = getsval(x);
160765393Sbostic 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
160865393Sbostic 		pfa = (fa *) a[1];	/* regular expression */
160965393Sbostic 	else {
161065393Sbostic 		y = execute(a[1]);
161165393Sbostic 		pfa = makedfa(getsval(y), 1);
161265393Sbostic 		tempfree(y);
161365393Sbostic 	}
161465393Sbostic 	y = execute(a[2]);	/* replacement string */
161565393Sbostic 	result = false;
161665393Sbostic 	if (pmatch(pfa, t)) {
161765393Sbostic 		pb = buf;
161865393Sbostic 		sptr = t;
161965393Sbostic 		while (sptr < patbeg)
162065393Sbostic 			*pb++ = *sptr++;
162165393Sbostic 		sptr = getsval(y);
162265393Sbostic 		while (*sptr != 0 && pb < buf + SUBSIZE - 1)
162365393Sbostic 			if (*sptr == '\\' && *(sptr+1) == '&') {
162465393Sbostic 				sptr++;		/* skip \, */
162565393Sbostic 				*pb++ = *sptr++; /* add & */
162665393Sbostic 			} else if (*sptr == '&') {
162765393Sbostic 				sptr++;
162865393Sbostic 				for (q = patbeg; q < patbeg+patlen; )
162965393Sbostic 					*pb++ = *q++;
163065393Sbostic 			} else
163165393Sbostic 				*pb++ = *sptr++;
163265393Sbostic 		*pb = '\0';
163365393Sbostic 		if (pb >= buf + SUBSIZE)
163465393Sbostic 			ERROR "sub() result %30s too big", buf FATAL;
163565393Sbostic 		sptr = patbeg + patlen;
163665393Sbostic 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1)))
163765393Sbostic 			while (*pb++ = *sptr++)
163865393Sbostic 				;
163965393Sbostic 		if (pb >= buf + SUBSIZE)
164065393Sbostic 			ERROR "sub() result %.30s too big", buf FATAL;
164165393Sbostic 		setsval(x, buf);
164265393Sbostic 		result = true;;
164365393Sbostic 	}
164465393Sbostic 	tempfree(x);
164565393Sbostic 	tempfree(y);
164665393Sbostic 	return result;
164765393Sbostic }
164865393Sbostic 
gsub(Node ** a,int nnn)164965393Sbostic Cell *gsub(Node **a, int nnn)	/* global substitute */
165065393Sbostic {
165165393Sbostic 	register Cell *x, *y;
165265393Sbostic 	register uchar *rptr, *sptr, *t, *pb;
165365393Sbostic 	uchar buf[SUBSIZE];
165465393Sbostic 	register fa *pfa;
165565393Sbostic 	int mflag, tempstat, num;
165665393Sbostic 
165765393Sbostic 	mflag = 0;	/* if mflag == 0, can replace empty string */
165865393Sbostic 	num = 0;
165965393Sbostic 	x = execute(a[3]);	/* target string */
166065393Sbostic 	t = getsval(x);
166165393Sbostic 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
166265393Sbostic 		pfa = (fa *) a[1];	/* regular expression */
166365393Sbostic 	else {
166465393Sbostic 		y = execute(a[1]);
166565393Sbostic 		pfa = makedfa(getsval(y), 1);
166665393Sbostic 		tempfree(y);
166765393Sbostic 	}
166865393Sbostic 	y = execute(a[2]);	/* replacement string */
166965393Sbostic 	if (pmatch(pfa, t)) {
167065393Sbostic 		tempstat = pfa->initstat;
167165393Sbostic 		pfa->initstat = 2;
167265393Sbostic 		pb = buf;
167365393Sbostic 		rptr = getsval(y);
167465393Sbostic 		do {
167565393Sbostic 			/*
167665393Sbostic 			uchar *p;
167765393Sbostic 			int i;
167865393Sbostic 			printf("target string: %s, *patbeg = %o, patlen = %d\n",
167965393Sbostic 				t, *patbeg, patlen);
168065393Sbostic 			printf("	match found: ");
168165393Sbostic 			p=patbeg;
168265393Sbostic 			for (i=0; i<patlen; i++)
168365393Sbostic 				printf("%c", *p++);
168465393Sbostic 			printf("\n");
168565393Sbostic 			*/
168665393Sbostic 			if (patlen == 0 && *patbeg != 0) {	/* matched empty string */
168765393Sbostic 				if (mflag == 0) {	/* can replace empty */
168865393Sbostic 					num++;
168965393Sbostic 					sptr = rptr;
169065393Sbostic 					while (*sptr != 0 && pb < buf + SUBSIZE-1)
169165393Sbostic 						if (*sptr == '\\' && *(sptr+1) == '&') {
169265393Sbostic 							sptr++;
169365393Sbostic 							*pb++ = *sptr++;
169465393Sbostic 						} else if (*sptr == '&') {
169565393Sbostic 							uchar *q;
169665393Sbostic 							sptr++;
169765393Sbostic 							for (q = patbeg; q < patbeg+patlen; )
169865393Sbostic 								*pb++ = *q++;
169965393Sbostic 						} else
170065393Sbostic 							*pb++ = *sptr++;
170165393Sbostic 				}
170265393Sbostic 				if (*t == 0)	/* at end */
170365393Sbostic 					goto done;
170465393Sbostic 				*pb++ = *t++;
170565393Sbostic 				if (pb >= buf + SUBSIZE-1)
170665393Sbostic 					ERROR "gsub() result %.30s too big", buf FATAL;
170765393Sbostic 				mflag = 0;
170865393Sbostic 			}
170965393Sbostic 			else {	/* matched nonempty string */
171065393Sbostic 				num++;
171165393Sbostic 				sptr = t;
171265393Sbostic 				while (sptr < patbeg && pb < buf + SUBSIZE-1)
171365393Sbostic 					*pb++ = *sptr++;
171465393Sbostic 				sptr = rptr;
171565393Sbostic 				while (*sptr != 0 && pb < buf + SUBSIZE-1)
171665393Sbostic 					if (*sptr == '\\' && *(sptr+1) == '&') {
171765393Sbostic 						sptr++;
171865393Sbostic 						*pb++ = *sptr++;
171965393Sbostic 					} else if (*sptr == '&') {
172065393Sbostic 						uchar *q;
172165393Sbostic 						sptr++;
172265393Sbostic 						for (q = patbeg; q < patbeg+patlen; )
172365393Sbostic 							*pb++ = *q++;
172465393Sbostic 					} else
172565393Sbostic 						*pb++ = *sptr++;
172665393Sbostic 				t = patbeg + patlen;
172765393Sbostic 				if ((*(t-1) == 0) || (*t == 0))
172865393Sbostic 					goto done;
172965393Sbostic 				if (pb >= buf + SUBSIZE-1)
173065393Sbostic 					ERROR "gsub() result %.30s too big", buf FATAL;
173165393Sbostic 				mflag = 1;
173265393Sbostic 			}
173365393Sbostic 		} while (pmatch(pfa,t));
173465393Sbostic 		sptr = t;
173565393Sbostic 		while (*pb++ = *sptr++)
173665393Sbostic 			;
173765393Sbostic 	done:	if (pb >= buf + SUBSIZE-1)
173865393Sbostic 			ERROR "gsub() result %.30s too big", buf FATAL;
173965393Sbostic 		*pb = '\0';
174065393Sbostic 		setsval(x, buf);
174165393Sbostic 		pfa->initstat = tempstat;
174265393Sbostic 	}
174365393Sbostic 	tempfree(x);
174465393Sbostic 	tempfree(y);
174565393Sbostic 	x = gettemp();
174665393Sbostic 	x->tval = NUM;
174765393Sbostic 	x->fval = num;
174865393Sbostic 	return(x);
174965393Sbostic }
1750