xref: /plan9-contrib/sys/src/cmd/awk/run.c (revision a2c41696452f8a895ad2951a6355034fbc3034ed)
17dd7cddfSDavid du Colombier /****************************************************************
27dd7cddfSDavid du Colombier Copyright (C) Lucent Technologies 1997
33e12c5d1SDavid du Colombier All Rights Reserved
43e12c5d1SDavid du Colombier 
57dd7cddfSDavid du Colombier Permission to use, copy, modify, and distribute this software and
67dd7cddfSDavid du Colombier its documentation for any purpose and without fee is hereby
77dd7cddfSDavid du Colombier granted, provided that the above copyright notice appear in all
87dd7cddfSDavid du Colombier copies and that both that the copyright notice and this
97dd7cddfSDavid du Colombier permission notice and warranty disclaimer appear in supporting
107dd7cddfSDavid du Colombier documentation, and that the name Lucent Technologies or any of
117dd7cddfSDavid du Colombier its entities not be used in advertising or publicity pertaining
127dd7cddfSDavid du Colombier to distribution of the software without specific, written prior
137dd7cddfSDavid du Colombier permission.
143e12c5d1SDavid du Colombier 
157dd7cddfSDavid du Colombier LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
167dd7cddfSDavid du Colombier INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
177dd7cddfSDavid du Colombier IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
187dd7cddfSDavid du Colombier SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
197dd7cddfSDavid du Colombier WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
207dd7cddfSDavid du Colombier IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
217dd7cddfSDavid du Colombier ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
227dd7cddfSDavid du Colombier THIS SOFTWARE.
237dd7cddfSDavid du Colombier ****************************************************************/
243e12c5d1SDavid du Colombier 
253e12c5d1SDavid du Colombier #define DEBUG
263e12c5d1SDavid du Colombier #include <stdio.h>
273e12c5d1SDavid du Colombier #include <ctype.h>
283e12c5d1SDavid du Colombier #include <setjmp.h>
29*a2c41696SDavid du Colombier #include <limits.h>
303e12c5d1SDavid du Colombier #include <math.h>
313e12c5d1SDavid du Colombier #include <string.h>
323e12c5d1SDavid du Colombier #include <stdlib.h>
333e12c5d1SDavid du Colombier #include <time.h>
34535404a9SDavid du Colombier #include <utf.h>
353e12c5d1SDavid du Colombier #include "awk.h"
363e12c5d1SDavid du Colombier #include "y.tab.h"
373e12c5d1SDavid du Colombier 
387dd7cddfSDavid du Colombier #define tempfree(x)	if (istemp(x)) tfree(x); else
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier /*
417dd7cddfSDavid du Colombier #undef tempfree
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier void tempfree(Cell *p) {
447dd7cddfSDavid du Colombier 	if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
457dd7cddfSDavid du Colombier 		WARNING("bad csub %d in Cell %d %s",
467dd7cddfSDavid du Colombier 			p->csub, p->ctype, p->sval);
477dd7cddfSDavid du Colombier 	}
487dd7cddfSDavid du Colombier 	if (istemp(p))
497dd7cddfSDavid du Colombier 		tfree(p);
507dd7cddfSDavid du Colombier }
517dd7cddfSDavid du Colombier */
527dd7cddfSDavid du Colombier 
53*a2c41696SDavid du Colombier /* do we really need these? */
54*a2c41696SDavid du Colombier /* #ifdef _NFILE */
55*a2c41696SDavid du Colombier /* #ifndef FOPEN_MAX */
56*a2c41696SDavid du Colombier /* #define FOPEN_MAX _NFILE */
57*a2c41696SDavid du Colombier /* #endif */
58*a2c41696SDavid du Colombier /* #endif */
59*a2c41696SDavid du Colombier /*  */
60*a2c41696SDavid du Colombier /* #ifndef	FOPEN_MAX */
61*a2c41696SDavid du Colombier /* #define	FOPEN_MAX	40 */	/* max number of open files */
62*a2c41696SDavid du Colombier /* #endif */
63*a2c41696SDavid du Colombier /*  */
64*a2c41696SDavid du Colombier /* #ifndef RAND_MAX */
65*a2c41696SDavid du Colombier /* #define RAND_MAX	32767 */	/* all that ansi guarantees */
66*a2c41696SDavid du Colombier /* #endif */
673e12c5d1SDavid du Colombier 
683e12c5d1SDavid du Colombier jmp_buf env;
697dd7cddfSDavid du Colombier extern	int	pairstack[];
70*a2c41696SDavid du Colombier extern	Awkfloat	srand_seed;
71219b2ee8SDavid du Colombier 
72219b2ee8SDavid du Colombier Node	*winner = NULL;	/* root of parse tree */
73219b2ee8SDavid du Colombier Cell	*tmps;		/* free temporary cells for execution */
743e12c5d1SDavid du Colombier 
753e12c5d1SDavid du Colombier static Cell	truecell	={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
767dd7cddfSDavid du Colombier Cell	*True	= &truecell;
773e12c5d1SDavid du Colombier static Cell	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
787dd7cddfSDavid du Colombier Cell	*False	= &falsecell;
793e12c5d1SDavid du Colombier static Cell	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
803e12c5d1SDavid du Colombier Cell	*jbreak	= &breakcell;
813e12c5d1SDavid du Colombier static Cell	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM };
823e12c5d1SDavid du Colombier Cell	*jcont	= &contcell;
833e12c5d1SDavid du Colombier static Cell	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
843e12c5d1SDavid du Colombier Cell	*jnext	= &nextcell;
857dd7cddfSDavid du Colombier static Cell	nextfilecell	={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
867dd7cddfSDavid du Colombier Cell	*jnextfile	= &nextfilecell;
873e12c5d1SDavid du Colombier static Cell	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
883e12c5d1SDavid du Colombier Cell	*jexit	= &exitcell;
893e12c5d1SDavid du Colombier static Cell	retcell		={ OJUMP, JRET, 0, 0, 0.0, NUM };
903e12c5d1SDavid du Colombier Cell	*jret	= &retcell;
917dd7cddfSDavid du Colombier static Cell	tempcell	={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
923e12c5d1SDavid du Colombier 
933e12c5d1SDavid du Colombier Node	*curnode = NULL;	/* the node being executed, for debugging */
943e12c5d1SDavid du Colombier 
957dd7cddfSDavid du Colombier /* buffer memory management */
adjbuf(char ** pbuf,int * psiz,int minlen,int quantum,char ** pbptr,const char * whatrtn)967dd7cddfSDavid du Colombier int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
97*a2c41696SDavid du Colombier 	const char *whatrtn)
987dd7cddfSDavid du Colombier /* pbuf:    address of pointer to buffer being managed
997dd7cddfSDavid du Colombier  * psiz:    address of buffer size variable
1007dd7cddfSDavid du Colombier  * minlen:  minimum length of buffer needed
1017dd7cddfSDavid du Colombier  * quantum: buffer size quantum
1027dd7cddfSDavid du Colombier  * pbptr:   address of movable pointer into buffer, or 0 if none
1037dd7cddfSDavid du Colombier  * whatrtn: name of the calling routine if failure should cause fatal error
1047dd7cddfSDavid du Colombier  *
1057dd7cddfSDavid du Colombier  * return   0 for realloc failure, !=0 for success
1067dd7cddfSDavid du Colombier  */
1077dd7cddfSDavid du Colombier {
1087dd7cddfSDavid du Colombier 	if (minlen > *psiz) {
1097dd7cddfSDavid du Colombier 		char *tbuf;
1107dd7cddfSDavid du Colombier 		int rminlen = quantum ? minlen % quantum : 0;
1117dd7cddfSDavid du Colombier 		int boff = pbptr ? *pbptr - *pbuf : 0;
1127dd7cddfSDavid du Colombier 		/* round up to next multiple of quantum */
1137dd7cddfSDavid du Colombier 		if (rminlen)
1147dd7cddfSDavid du Colombier 			minlen += quantum - rminlen;
1157dd7cddfSDavid du Colombier 		tbuf = (char *) realloc(*pbuf, minlen);
116*a2c41696SDavid du Colombier 		dprintf( ("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, *pbuf, tbuf) );
1177dd7cddfSDavid du Colombier 		if (tbuf == NULL) {
1187dd7cddfSDavid du Colombier 			if (whatrtn)
1197dd7cddfSDavid du Colombier 				FATAL("out of memory in %s", whatrtn);
1207dd7cddfSDavid du Colombier 			return 0;
1217dd7cddfSDavid du Colombier 		}
1227dd7cddfSDavid du Colombier 		*pbuf = tbuf;
1237dd7cddfSDavid du Colombier 		*psiz = minlen;
1247dd7cddfSDavid du Colombier 		if (pbptr)
1257dd7cddfSDavid du Colombier 			*pbptr = tbuf + boff;
1267dd7cddfSDavid du Colombier 	}
1277dd7cddfSDavid du Colombier 	return 1;
1287dd7cddfSDavid du Colombier }
1297dd7cddfSDavid du Colombier 
run(Node * a)130219b2ee8SDavid du Colombier void run(Node *a)	/* execution of parse tree starts here */
1313e12c5d1SDavid du Colombier {
1327dd7cddfSDavid du Colombier 	extern void stdinit(void);
1337dd7cddfSDavid du Colombier 
1347dd7cddfSDavid du Colombier 	stdinit();
1353e12c5d1SDavid du Colombier 	execute(a);
1363e12c5d1SDavid du Colombier 	closeall();
1373e12c5d1SDavid du Colombier }
1383e12c5d1SDavid du Colombier 
execute(Node * u)1397dd7cddfSDavid du Colombier Cell *execute(Node *u)	/* execute a node of the parse tree */
1403e12c5d1SDavid du Colombier {
14105bfb676SDavid du Colombier 	int nobj;
1427dd7cddfSDavid du Colombier 	Cell *(*proc)(Node **, int);
1437dd7cddfSDavid du Colombier 	Cell *x;
1447dd7cddfSDavid du Colombier 	Node *a;
1453e12c5d1SDavid du Colombier 
1463e12c5d1SDavid du Colombier 	if (u == NULL)
1477dd7cddfSDavid du Colombier 		return(True);
1483e12c5d1SDavid du Colombier 	for (a = u; ; a = a->nnext) {
1493e12c5d1SDavid du Colombier 		curnode = a;
1503e12c5d1SDavid du Colombier 		if (isvalue(a)) {
1513e12c5d1SDavid du Colombier 			x = (Cell *) (a->narg[0]);
1527dd7cddfSDavid du Colombier 			if (isfld(x) && !donefld)
1533e12c5d1SDavid du Colombier 				fldbld();
1547dd7cddfSDavid du Colombier 			else if (isrec(x) && !donerec)
1553e12c5d1SDavid du Colombier 				recbld();
1563e12c5d1SDavid du Colombier 			return(x);
1573e12c5d1SDavid du Colombier 		}
15805bfb676SDavid du Colombier 		nobj = a->nobj;
15905bfb676SDavid du Colombier 		if (notlegal(nobj))	/* probably a Cell* but too risky to print */
1607dd7cddfSDavid du Colombier 			FATAL("illegal statement");
16105bfb676SDavid du Colombier 		proc = proctab[nobj-FIRSTTOKEN];
16205bfb676SDavid du Colombier 		x = (*proc)(a->narg, nobj);
1637dd7cddfSDavid du Colombier 		if (isfld(x) && !donefld)
1643e12c5d1SDavid du Colombier 			fldbld();
1657dd7cddfSDavid du Colombier 		else if (isrec(x) && !donerec)
1663e12c5d1SDavid du Colombier 			recbld();
1673e12c5d1SDavid du Colombier 		if (isexpr(a))
1683e12c5d1SDavid du Colombier 			return(x);
1693e12c5d1SDavid du Colombier 		if (isjump(x))
1703e12c5d1SDavid du Colombier 			return(x);
1713e12c5d1SDavid du Colombier 		if (a->nnext == NULL)
1723e12c5d1SDavid du Colombier 			return(x);
1733e12c5d1SDavid du Colombier 		tempfree(x);
1743e12c5d1SDavid du Colombier 	}
1753e12c5d1SDavid du Colombier }
1763e12c5d1SDavid du Colombier 
1773e12c5d1SDavid du Colombier 
program(Node ** a,int n)178219b2ee8SDavid du Colombier Cell *program(Node **a, int n)	/* execute an awk program */
179219b2ee8SDavid du Colombier {				/* a[0] = BEGIN, a[1] = body, a[2] = END */
1807dd7cddfSDavid du Colombier 	Cell *x;
1813e12c5d1SDavid du Colombier 
1823e12c5d1SDavid du Colombier 	if (setjmp(env) != 0)
1833e12c5d1SDavid du Colombier 		goto ex;
1843e12c5d1SDavid du Colombier 	if (a[0]) {		/* BEGIN */
1853e12c5d1SDavid du Colombier 		x = execute(a[0]);
1863e12c5d1SDavid du Colombier 		if (isexit(x))
1877dd7cddfSDavid du Colombier 			return(True);
1883e12c5d1SDavid du Colombier 		if (isjump(x))
1897dd7cddfSDavid du Colombier 			FATAL("illegal break, continue, next or nextfile from BEGIN");
1903e12c5d1SDavid du Colombier 		tempfree(x);
1913e12c5d1SDavid du Colombier 	}
1923e12c5d1SDavid du Colombier 	if (a[1] || a[2])
1937dd7cddfSDavid du Colombier 		while (getrec(&record, &recsize, 1) > 0) {
1943e12c5d1SDavid du Colombier 			x = execute(a[1]);
1953e12c5d1SDavid du Colombier 			if (isexit(x))
1963e12c5d1SDavid du Colombier 				break;
1973e12c5d1SDavid du Colombier 			tempfree(x);
1983e12c5d1SDavid du Colombier 		}
1993e12c5d1SDavid du Colombier   ex:
2003e12c5d1SDavid du Colombier 	if (setjmp(env) != 0)	/* handles exit within END */
2013e12c5d1SDavid du Colombier 		goto ex1;
2023e12c5d1SDavid du Colombier 	if (a[2]) {		/* END */
2033e12c5d1SDavid du Colombier 		x = execute(a[2]);
2043e12c5d1SDavid du Colombier 		if (isbreak(x) || isnext(x) || iscont(x))
2057dd7cddfSDavid du Colombier 			FATAL("illegal break, continue, next or nextfile from END");
2063e12c5d1SDavid du Colombier 		tempfree(x);
2073e12c5d1SDavid du Colombier 	}
2083e12c5d1SDavid du Colombier   ex1:
2097dd7cddfSDavid du Colombier 	return(True);
2103e12c5d1SDavid du Colombier }
2113e12c5d1SDavid du Colombier 
212219b2ee8SDavid du Colombier struct Frame {	/* stack frame for awk function calls */
2133e12c5d1SDavid du Colombier 	int nargs;	/* number of arguments in this call */
2143e12c5d1SDavid du Colombier 	Cell *fcncell;	/* pointer to Cell for function */
2153e12c5d1SDavid du Colombier 	Cell **args;	/* pointer to array of arguments after execute */
2163e12c5d1SDavid du Colombier 	Cell *retval;	/* return value */
2173e12c5d1SDavid du Colombier };
2183e12c5d1SDavid du Colombier 
219219b2ee8SDavid du Colombier #define	NARGS	50	/* max args in a call */
2203e12c5d1SDavid du Colombier 
2213e12c5d1SDavid du Colombier struct Frame *frame = NULL;	/* base of stack frames; dynamically allocated */
2223e12c5d1SDavid du Colombier int	nframe = 0;		/* number of frames allocated */
2233e12c5d1SDavid du Colombier struct Frame *fp = NULL;	/* frame pointer. bottom level unused */
2243e12c5d1SDavid du Colombier 
call(Node ** a,int n)225219b2ee8SDavid du Colombier Cell *call(Node **a, int n)	/* function call.  very kludgy and fragile */
2263e12c5d1SDavid du Colombier {
2277dd7cddfSDavid du Colombier 	static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
2283e12c5d1SDavid du Colombier 	int i, ncall, ndef;
229*a2c41696SDavid du Colombier 	int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */
2303e12c5d1SDavid du Colombier 	Node *x;
2317dd7cddfSDavid du Colombier 	Cell *args[NARGS], *oargs[NARGS];	/* BUG: fixed size arrays */
2327dd7cddfSDavid du Colombier 	Cell *y, *z, *fcn;
2337dd7cddfSDavid du Colombier 	char *s;
2343e12c5d1SDavid du Colombier 
2353e12c5d1SDavid du Colombier 	fcn = execute(a[0]);	/* the function itself */
2363e12c5d1SDavid du Colombier 	s = fcn->nval;
2377dd7cddfSDavid du Colombier 	if (!isfcn(fcn))
2387dd7cddfSDavid du Colombier 		FATAL("calling undefined function %s", s);
2393e12c5d1SDavid du Colombier 	if (frame == NULL) {
2403e12c5d1SDavid du Colombier 		fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
2413e12c5d1SDavid du Colombier 		if (frame == NULL)
2427dd7cddfSDavid du Colombier 			FATAL("out of space for stack frames calling %s", s);
2433e12c5d1SDavid du Colombier 	}
2443e12c5d1SDavid du Colombier 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)	/* args in call */
2453e12c5d1SDavid du Colombier 		ncall++;
2463e12c5d1SDavid du Colombier 	ndef = (int) fcn->fval;			/* args in defn */
2477dd7cddfSDavid du Colombier 	   dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
2483e12c5d1SDavid du Colombier 	if (ncall > ndef)
2497dd7cddfSDavid du Colombier 		WARNING("function %s called with %d args, uses only %d",
2507dd7cddfSDavid du Colombier 			s, ncall, ndef);
2513e12c5d1SDavid du Colombier 	if (ncall + ndef > NARGS)
2527dd7cddfSDavid du Colombier 		FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
2533e12c5d1SDavid du Colombier 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {	/* get call args */
2547dd7cddfSDavid du Colombier 		   dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
2553e12c5d1SDavid du Colombier 		y = execute(x);
2563e12c5d1SDavid du Colombier 		oargs[i] = y;
2573e12c5d1SDavid du Colombier 		   dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
258*a2c41696SDavid du Colombier 			   i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval) );
2597dd7cddfSDavid du Colombier 		if (isfcn(y))
2607dd7cddfSDavid du Colombier 			FATAL("can't use function %s as argument in %s", y->nval, s);
2613e12c5d1SDavid du Colombier 		if (isarr(y))
2623e12c5d1SDavid du Colombier 			args[i] = y;	/* arrays by ref */
2633e12c5d1SDavid du Colombier 		else
2643e12c5d1SDavid du Colombier 			args[i] = copycell(y);
2653e12c5d1SDavid du Colombier 		tempfree(y);
2663e12c5d1SDavid du Colombier 	}
2673e12c5d1SDavid du Colombier 	for ( ; i < ndef; i++) {	/* add null args for ones not provided */
2683e12c5d1SDavid du Colombier 		args[i] = gettemp();
2693e12c5d1SDavid du Colombier 		*args[i] = newcopycell;
2703e12c5d1SDavid du Colombier 	}
2713e12c5d1SDavid du Colombier 	fp++;	/* now ok to up frame */
2723e12c5d1SDavid du Colombier 	if (fp >= frame + nframe) {
2733e12c5d1SDavid du Colombier 		int dfp = fp - frame;	/* old index */
2743e12c5d1SDavid du Colombier 		frame = (struct Frame *)
275219b2ee8SDavid du Colombier 			realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
2763e12c5d1SDavid du Colombier 		if (frame == NULL)
2777dd7cddfSDavid du Colombier 			FATAL("out of space for stack frames in %s", s);
2783e12c5d1SDavid du Colombier 		fp = frame + dfp;
2793e12c5d1SDavid du Colombier 	}
2803e12c5d1SDavid du Colombier 	fp->fcncell = fcn;
2813e12c5d1SDavid du Colombier 	fp->args = args;
2823e12c5d1SDavid du Colombier 	fp->nargs = ndef;	/* number defined with (excess are locals) */
2833e12c5d1SDavid du Colombier 	fp->retval = gettemp();
2843e12c5d1SDavid du Colombier 
2857dd7cddfSDavid du Colombier 	   dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
2863e12c5d1SDavid du Colombier 	y = execute((Node *)(fcn->sval));	/* execute body */
2877dd7cddfSDavid du Colombier 	   dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
2883e12c5d1SDavid du Colombier 
2893e12c5d1SDavid du Colombier 	for (i = 0; i < ndef; i++) {
2903e12c5d1SDavid du Colombier 		Cell *t = fp->args[i];
2913e12c5d1SDavid du Colombier 		if (isarr(t)) {
2923e12c5d1SDavid du Colombier 			if (t->csub == CCOPY) {
2933e12c5d1SDavid du Colombier 				if (i >= ncall) {
2943e12c5d1SDavid du Colombier 					freesymtab(t);
2953e12c5d1SDavid du Colombier 					t->csub = CTEMP;
2967dd7cddfSDavid du Colombier 					tempfree(t);
2973e12c5d1SDavid du Colombier 				} else {
2983e12c5d1SDavid du Colombier 					oargs[i]->tval = t->tval;
2993e12c5d1SDavid du Colombier 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
3003e12c5d1SDavid du Colombier 					oargs[i]->sval = t->sval;
3013e12c5d1SDavid du Colombier 					tempfree(t);
3023e12c5d1SDavid du Colombier 				}
3033e12c5d1SDavid du Colombier 			}
3043e12c5d1SDavid du Colombier 		} else if (t != y) {	/* kludge to prevent freeing twice */
3053e12c5d1SDavid du Colombier 			t->csub = CTEMP;
3063e12c5d1SDavid du Colombier 			tempfree(t);
307*a2c41696SDavid du Colombier 		} else if (t == y && t->csub == CCOPY) {
308*a2c41696SDavid du Colombier 			t->csub = CTEMP;
309*a2c41696SDavid du Colombier 			tempfree(t);
310*a2c41696SDavid du Colombier 			freed = 1;
3113e12c5d1SDavid du Colombier 		}
3123e12c5d1SDavid du Colombier 	}
3133e12c5d1SDavid du Colombier 	tempfree(fcn);
314*a2c41696SDavid du Colombier 	if (isexit(y) || isnext(y))
3153e12c5d1SDavid du Colombier 		return y;
316*a2c41696SDavid du Colombier 	if (freed == 0) {
317*a2c41696SDavid du Colombier 		tempfree(y);	/* don't free twice! */
318*a2c41696SDavid du Colombier 	}
3193e12c5d1SDavid du Colombier 	z = fp->retval;			/* return value */
3203e12c5d1SDavid du Colombier 	   dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
3213e12c5d1SDavid du Colombier 	fp--;
3223e12c5d1SDavid du Colombier 	return(z);
3233e12c5d1SDavid du Colombier }
3243e12c5d1SDavid du Colombier 
copycell(Cell * x)3253e12c5d1SDavid du Colombier Cell *copycell(Cell *x)	/* make a copy of a cell in a temp */
3263e12c5d1SDavid du Colombier {
3273e12c5d1SDavid du Colombier 	Cell *y;
3283e12c5d1SDavid du Colombier 
3293e12c5d1SDavid du Colombier 	y = gettemp();
3303e12c5d1SDavid du Colombier 	y->csub = CCOPY;	/* prevents freeing until call is over */
3317dd7cddfSDavid du Colombier 	y->nval = x->nval;	/* BUG? */
332*a2c41696SDavid du Colombier 	if (isstr(x))
333*a2c41696SDavid du Colombier 		y->sval = tostring(x->sval);
3343e12c5d1SDavid du Colombier 	y->fval = x->fval;
3353e12c5d1SDavid du Colombier 	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);	/* copy is not constant or field */
3363e12c5d1SDavid du Colombier 							/* is DONTFREE right? */
3373e12c5d1SDavid du Colombier 	return y;
3383e12c5d1SDavid du Colombier }
3393e12c5d1SDavid du Colombier 
arg(Node ** a,int n)340219b2ee8SDavid du Colombier Cell *arg(Node **a, int n)	/* nth argument of a function */
3413e12c5d1SDavid du Colombier {
3423e12c5d1SDavid du Colombier 
3437dd7cddfSDavid du Colombier 	n = ptoi(a[0]);	/* argument number, counting from 0 */
3443e12c5d1SDavid du Colombier 	   dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
3453e12c5d1SDavid du Colombier 	if (n+1 > fp->nargs)
3467dd7cddfSDavid du Colombier 		FATAL("argument #%d of function %s was not supplied",
3477dd7cddfSDavid du Colombier 			n+1, fp->fcncell->nval);
3483e12c5d1SDavid du Colombier 	return fp->args[n];
3493e12c5d1SDavid du Colombier }
3503e12c5d1SDavid du Colombier 
jump(Node ** a,int n)3517dd7cddfSDavid du Colombier Cell *jump(Node **a, int n)	/* break, continue, next, nextfile, return */
3523e12c5d1SDavid du Colombier {
3537dd7cddfSDavid du Colombier 	Cell *y;
3543e12c5d1SDavid du Colombier 
3553e12c5d1SDavid du Colombier 	switch (n) {
3563e12c5d1SDavid du Colombier 	case EXIT:
3573e12c5d1SDavid du Colombier 		if (a[0] != NULL) {
3583e12c5d1SDavid du Colombier 			y = execute(a[0]);
3597dd7cddfSDavid du Colombier 			errorflag = (int) getfval(y);
3603e12c5d1SDavid du Colombier 			tempfree(y);
3613e12c5d1SDavid du Colombier 		}
3623e12c5d1SDavid du Colombier 		longjmp(env, 1);
3633e12c5d1SDavid du Colombier 	case RETURN:
3643e12c5d1SDavid du Colombier 		if (a[0] != NULL) {
3653e12c5d1SDavid du Colombier 			y = execute(a[0]);
3663e12c5d1SDavid du Colombier 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
3673e12c5d1SDavid du Colombier 				setsval(fp->retval, getsval(y));
3683e12c5d1SDavid du Colombier 				fp->retval->fval = getfval(y);
3693e12c5d1SDavid du Colombier 				fp->retval->tval |= NUM;
3703e12c5d1SDavid du Colombier 			}
3713e12c5d1SDavid du Colombier 			else if (y->tval & STR)
3723e12c5d1SDavid du Colombier 				setsval(fp->retval, getsval(y));
3733e12c5d1SDavid du Colombier 			else if (y->tval & NUM)
3743e12c5d1SDavid du Colombier 				setfval(fp->retval, getfval(y));
3753e12c5d1SDavid du Colombier 			else		/* can't happen */
3767dd7cddfSDavid du Colombier 				FATAL("bad type variable %d", y->tval);
3773e12c5d1SDavid du Colombier 			tempfree(y);
3783e12c5d1SDavid du Colombier 		}
3793e12c5d1SDavid du Colombier 		return(jret);
3803e12c5d1SDavid du Colombier 	case NEXT:
3813e12c5d1SDavid du Colombier 		return(jnext);
3827dd7cddfSDavid du Colombier 	case NEXTFILE:
3837dd7cddfSDavid du Colombier 		nextfile();
3847dd7cddfSDavid du Colombier 		return(jnextfile);
3853e12c5d1SDavid du Colombier 	case BREAK:
3863e12c5d1SDavid du Colombier 		return(jbreak);
3873e12c5d1SDavid du Colombier 	case CONTINUE:
3883e12c5d1SDavid du Colombier 		return(jcont);
3893e12c5d1SDavid du Colombier 	default:	/* can't happen */
3907dd7cddfSDavid du Colombier 		FATAL("illegal jump type %d", n);
3913e12c5d1SDavid du Colombier 	}
3923e12c5d1SDavid du Colombier 	return 0;	/* not reached */
3933e12c5d1SDavid du Colombier }
3943e12c5d1SDavid du Colombier 
awkgetline(Node ** a,int n)395*a2c41696SDavid du Colombier Cell *awkgetline(Node **a, int n)	/* get next line from specific input */
396219b2ee8SDavid du Colombier {		/* a[0] is variable, a[1] is operator, a[2] is filename */
3977dd7cddfSDavid du Colombier 	Cell *r, *x;
3987dd7cddfSDavid du Colombier 	extern Cell **fldtab;
3993e12c5d1SDavid du Colombier 	FILE *fp;
4007dd7cddfSDavid du Colombier 	char *buf;
4017dd7cddfSDavid du Colombier 	int bufsize = recsize;
4027dd7cddfSDavid du Colombier 	int mode;
4037dd7cddfSDavid du Colombier 
4047dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsize)) == NULL)
4057dd7cddfSDavid du Colombier 		FATAL("out of memory in getline");
4063e12c5d1SDavid du Colombier 
4073e12c5d1SDavid du Colombier 	fflush(stdout);	/* in case someone is waiting for a prompt */
4083e12c5d1SDavid du Colombier 	r = gettemp();
4093e12c5d1SDavid du Colombier 	if (a[1] != NULL) {		/* getline < file */
4103e12c5d1SDavid du Colombier 		x = execute(a[2]);		/* filename */
4117dd7cddfSDavid du Colombier 		mode = ptoi(a[1]);
4127dd7cddfSDavid du Colombier 		if (mode == '|')		/* input pipe */
4137dd7cddfSDavid du Colombier 			mode = LE;	/* arbitrary flag */
4147dd7cddfSDavid du Colombier 		fp = openfile(mode, getsval(x));
4153e12c5d1SDavid du Colombier 		tempfree(x);
4163e12c5d1SDavid du Colombier 		if (fp == NULL)
4173e12c5d1SDavid du Colombier 			n = -1;
4183e12c5d1SDavid du Colombier 		else
4197dd7cddfSDavid du Colombier 			n = readrec(&buf, &bufsize, fp);
4203e12c5d1SDavid du Colombier 		if (n <= 0) {
4213e12c5d1SDavid du Colombier 			;
4223e12c5d1SDavid du Colombier 		} else if (a[0] != NULL) {	/* getline var <file */
4237dd7cddfSDavid du Colombier 			x = execute(a[0]);
4247dd7cddfSDavid du Colombier 			setsval(x, buf);
4257dd7cddfSDavid du Colombier 			tempfree(x);
4263e12c5d1SDavid du Colombier 		} else {			/* getline <file */
4277dd7cddfSDavid du Colombier 			setsval(fldtab[0], buf);
4287dd7cddfSDavid du Colombier 			if (is_number(fldtab[0]->sval)) {
4297dd7cddfSDavid du Colombier 				fldtab[0]->fval = atof(fldtab[0]->sval);
4307dd7cddfSDavid du Colombier 				fldtab[0]->tval |= NUM;
4313e12c5d1SDavid du Colombier 			}
4323e12c5d1SDavid du Colombier 		}
4333e12c5d1SDavid du Colombier 	} else {			/* bare getline; use current input */
4343e12c5d1SDavid du Colombier 		if (a[0] == NULL)	/* getline */
4357dd7cddfSDavid du Colombier 			n = getrec(&record, &recsize, 1);
4363e12c5d1SDavid du Colombier 		else {			/* getline var */
4377dd7cddfSDavid du Colombier 			n = getrec(&buf, &bufsize, 0);
4387dd7cddfSDavid du Colombier 			x = execute(a[0]);
4397dd7cddfSDavid du Colombier 			setsval(x, buf);
4407dd7cddfSDavid du Colombier 			tempfree(x);
4413e12c5d1SDavid du Colombier 		}
4423e12c5d1SDavid du Colombier 	}
4433e12c5d1SDavid du Colombier 	setfval(r, (Awkfloat) n);
4447dd7cddfSDavid du Colombier 	free(buf);
4453e12c5d1SDavid du Colombier 	return r;
4463e12c5d1SDavid du Colombier }
4473e12c5d1SDavid du Colombier 
getnf(Node ** a,int n)448219b2ee8SDavid du Colombier Cell *getnf(Node **a, int n)	/* get NF */
4493e12c5d1SDavid du Colombier {
4503e12c5d1SDavid du Colombier 	if (donefld == 0)
4513e12c5d1SDavid du Colombier 		fldbld();
4523e12c5d1SDavid du Colombier 	return (Cell *) a[0];
4533e12c5d1SDavid du Colombier }
4543e12c5d1SDavid du Colombier 
array(Node ** a,int n)455219b2ee8SDavid du Colombier Cell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
4563e12c5d1SDavid du Colombier {
4577dd7cddfSDavid du Colombier 	Cell *x, *y, *z;
4587dd7cddfSDavid du Colombier 	char *s;
4597dd7cddfSDavid du Colombier 	Node *np;
4607dd7cddfSDavid du Colombier 	char *buf;
4617dd7cddfSDavid du Colombier 	int bufsz = recsize;
4627dd7cddfSDavid du Colombier 	int nsub = strlen(*SUBSEP);
4637dd7cddfSDavid du Colombier 
4647dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL)
4657dd7cddfSDavid du Colombier 		FATAL("out of memory in array");
4663e12c5d1SDavid du Colombier 
4673e12c5d1SDavid du Colombier 	x = execute(a[0]);	/* Cell* for symbol table */
4683e12c5d1SDavid du Colombier 	buf[0] = 0;
4693e12c5d1SDavid du Colombier 	for (np = a[1]; np; np = np->nnext) {
4703e12c5d1SDavid du Colombier 		y = execute(np);	/* subscript */
4713e12c5d1SDavid du Colombier 		s = getsval(y);
472*a2c41696SDavid du Colombier 		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "array"))
4737dd7cddfSDavid du Colombier 			FATAL("out of memory for %s[%s...]", x->nval, buf);
4743e12c5d1SDavid du Colombier 		strcat(buf, s);
4753e12c5d1SDavid du Colombier 		if (np->nnext)
4763e12c5d1SDavid du Colombier 			strcat(buf, *SUBSEP);
4773e12c5d1SDavid du Colombier 		tempfree(y);
4783e12c5d1SDavid du Colombier 	}
4793e12c5d1SDavid du Colombier 	if (!isarr(x)) {
480*a2c41696SDavid du Colombier 		   dprintf( ("making %s into an array\n", NN(x->nval)) );
4813e12c5d1SDavid du Colombier 		if (freeable(x))
4823e12c5d1SDavid du Colombier 			xfree(x->sval);
4833e12c5d1SDavid du Colombier 		x->tval &= ~(STR|NUM|DONTFREE);
4843e12c5d1SDavid du Colombier 		x->tval |= ARR;
4857dd7cddfSDavid du Colombier 		x->sval = (char *) makesymtab(NSYMTAB);
4863e12c5d1SDavid du Colombier 	}
4873e12c5d1SDavid du Colombier 	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
4883e12c5d1SDavid du Colombier 	z->ctype = OCELL;
4893e12c5d1SDavid du Colombier 	z->csub = CVAR;
4903e12c5d1SDavid du Colombier 	tempfree(x);
4917dd7cddfSDavid du Colombier 	free(buf);
4923e12c5d1SDavid du Colombier 	return(z);
4933e12c5d1SDavid du Colombier }
4943e12c5d1SDavid du Colombier 
awkdelete(Node ** a,int n)4957dd7cddfSDavid du Colombier Cell *awkdelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
4963e12c5d1SDavid du Colombier {
4973e12c5d1SDavid du Colombier 	Cell *x, *y;
4983e12c5d1SDavid du Colombier 	Node *np;
4997dd7cddfSDavid du Colombier 	char *s;
5007dd7cddfSDavid du Colombier 	int nsub = strlen(*SUBSEP);
5013e12c5d1SDavid du Colombier 
5023e12c5d1SDavid du Colombier 	x = execute(a[0]);	/* Cell* for symbol table */
5033e12c5d1SDavid du Colombier 	if (!isarr(x))
5047dd7cddfSDavid du Colombier 		return True;
5057dd7cddfSDavid du Colombier 	if (a[1] == 0) {	/* delete the elements, not the table */
5067dd7cddfSDavid du Colombier 		freesymtab(x);
5077dd7cddfSDavid du Colombier 		x->tval &= ~STR;
5087dd7cddfSDavid du Colombier 		x->tval |= ARR;
5097dd7cddfSDavid du Colombier 		x->sval = (char *) makesymtab(NSYMTAB);
5107dd7cddfSDavid du Colombier 	} else {
5117dd7cddfSDavid du Colombier 		int bufsz = recsize;
5127dd7cddfSDavid du Colombier 		char *buf;
5137dd7cddfSDavid du Colombier 		if ((buf = (char *) malloc(bufsz)) == NULL)
5147dd7cddfSDavid du Colombier 			FATAL("out of memory in adelete");
5153e12c5d1SDavid du Colombier 		buf[0] = 0;
5163e12c5d1SDavid du Colombier 		for (np = a[1]; np; np = np->nnext) {
5173e12c5d1SDavid du Colombier 			y = execute(np);	/* subscript */
5183e12c5d1SDavid du Colombier 			s = getsval(y);
519*a2c41696SDavid du Colombier 			if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "awkdelete"))
5207dd7cddfSDavid du Colombier 				FATAL("out of memory deleting %s[%s...]", x->nval, buf);
5213e12c5d1SDavid du Colombier 			strcat(buf, s);
5223e12c5d1SDavid du Colombier 			if (np->nnext)
5233e12c5d1SDavid du Colombier 				strcat(buf, *SUBSEP);
5243e12c5d1SDavid du Colombier 			tempfree(y);
5253e12c5d1SDavid du Colombier 		}
5263e12c5d1SDavid du Colombier 		freeelem(x, buf);
5277dd7cddfSDavid du Colombier 		free(buf);
5287dd7cddfSDavid du Colombier 	}
5293e12c5d1SDavid du Colombier 	tempfree(x);
5307dd7cddfSDavid du Colombier 	return True;
5313e12c5d1SDavid du Colombier }
5323e12c5d1SDavid du Colombier 
intest(Node ** a,int n)533219b2ee8SDavid du Colombier Cell *intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
5343e12c5d1SDavid du Colombier {
5357dd7cddfSDavid du Colombier 	Cell *x, *ap, *k;
5363e12c5d1SDavid du Colombier 	Node *p;
5377dd7cddfSDavid du Colombier 	char *buf;
5387dd7cddfSDavid du Colombier 	char *s;
5397dd7cddfSDavid du Colombier 	int bufsz = recsize;
5407dd7cddfSDavid du Colombier 	int nsub = strlen(*SUBSEP);
5413e12c5d1SDavid du Colombier 
5423e12c5d1SDavid du Colombier 	ap = execute(a[1]);	/* array name */
5433e12c5d1SDavid du Colombier 	if (!isarr(ap)) {
5443e12c5d1SDavid du Colombier 		   dprintf( ("making %s into an array\n", ap->nval) );
5453e12c5d1SDavid du Colombier 		if (freeable(ap))
5463e12c5d1SDavid du Colombier 			xfree(ap->sval);
5473e12c5d1SDavid du Colombier 		ap->tval &= ~(STR|NUM|DONTFREE);
5483e12c5d1SDavid du Colombier 		ap->tval |= ARR;
5497dd7cddfSDavid du Colombier 		ap->sval = (char *) makesymtab(NSYMTAB);
5507dd7cddfSDavid du Colombier 	}
5517dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL) {
5527dd7cddfSDavid du Colombier 		FATAL("out of memory in intest");
5533e12c5d1SDavid du Colombier 	}
5543e12c5d1SDavid du Colombier 	buf[0] = 0;
5553e12c5d1SDavid du Colombier 	for (p = a[0]; p; p = p->nnext) {
5563e12c5d1SDavid du Colombier 		x = execute(p);	/* expr */
5573e12c5d1SDavid du Colombier 		s = getsval(x);
558*a2c41696SDavid du Colombier 		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "intest"))
5597dd7cddfSDavid du Colombier 			FATAL("out of memory deleting %s[%s...]", x->nval, buf);
5603e12c5d1SDavid du Colombier 		strcat(buf, s);
5613e12c5d1SDavid du Colombier 		tempfree(x);
5623e12c5d1SDavid du Colombier 		if (p->nnext)
5633e12c5d1SDavid du Colombier 			strcat(buf, *SUBSEP);
5643e12c5d1SDavid du Colombier 	}
5653e12c5d1SDavid du Colombier 	k = lookup(buf, (Array *) ap->sval);
5663e12c5d1SDavid du Colombier 	tempfree(ap);
5677dd7cddfSDavid du Colombier 	free(buf);
5683e12c5d1SDavid du Colombier 	if (k == NULL)
5697dd7cddfSDavid du Colombier 		return(False);
5703e12c5d1SDavid du Colombier 	else
5717dd7cddfSDavid du Colombier 		return(True);
5723e12c5d1SDavid du Colombier }
5733e12c5d1SDavid du Colombier 
5743e12c5d1SDavid du Colombier 
matchop(Node ** a,int n)575219b2ee8SDavid du Colombier Cell *matchop(Node **a, int n)	/* ~ and match() */
5763e12c5d1SDavid du Colombier {
5777dd7cddfSDavid du Colombier 	Cell *x, *y;
5787dd7cddfSDavid du Colombier 	char *s, *t;
5797dd7cddfSDavid du Colombier 	int i;
5803e12c5d1SDavid du Colombier 	void *p;
5813e12c5d1SDavid du Colombier 
582219b2ee8SDavid du Colombier 	x = execute(a[1]);	/* a[1] = target text */
5833e12c5d1SDavid du Colombier 	s = getsval(x);
584219b2ee8SDavid du Colombier 	if (a[0] == 0)		/* a[1] == 0: already-compiled reg expr */
5853e12c5d1SDavid du Colombier 		p = (void *) a[2];
5863e12c5d1SDavid du Colombier 	else {
587219b2ee8SDavid du Colombier 		y = execute(a[2]);	/* a[2] = regular expr */
5883e12c5d1SDavid du Colombier 		t = getsval(y);
5893e12c5d1SDavid du Colombier 		p = compre(t);
5903e12c5d1SDavid du Colombier 		tempfree(y);
5913e12c5d1SDavid du Colombier 	}
5923e12c5d1SDavid du Colombier 	if (n == MATCHFCN)
5933e12c5d1SDavid du Colombier 		i = pmatch(p, s, s);
5943e12c5d1SDavid du Colombier 	else
5953e12c5d1SDavid du Colombier 		i = match(p, s, s);
5963e12c5d1SDavid du Colombier 	tempfree(x);
5973e12c5d1SDavid du Colombier 	if (n == MATCHFCN) {
598d9306527SDavid du Colombier 		int start = countposn(s, patbeg-s)+1;
5993e12c5d1SDavid du Colombier 		if (patlen < 0)
6003e12c5d1SDavid du Colombier 			start = 0;
6013e12c5d1SDavid du Colombier 		setfval(rstartloc, (Awkfloat) start);
6023e12c5d1SDavid du Colombier 		setfval(rlengthloc, (Awkfloat) countposn(patbeg, patlen));
6033e12c5d1SDavid du Colombier 		x = gettemp();
6043e12c5d1SDavid du Colombier 		x->tval = NUM;
6053e12c5d1SDavid du Colombier 		x->fval = start;
6063e12c5d1SDavid du Colombier 		return x;
6077dd7cddfSDavid du Colombier 	} else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
6087dd7cddfSDavid du Colombier 		return(True);
6093e12c5d1SDavid du Colombier 	else
6107dd7cddfSDavid du Colombier 		return(False);
6113e12c5d1SDavid du Colombier }
6123e12c5d1SDavid du Colombier 
6133e12c5d1SDavid du Colombier 
boolop(Node ** a,int n)614219b2ee8SDavid du Colombier Cell *boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
6153e12c5d1SDavid du Colombier {
6167dd7cddfSDavid du Colombier 	Cell *x, *y;
6177dd7cddfSDavid du Colombier 	int i;
6183e12c5d1SDavid du Colombier 
6193e12c5d1SDavid du Colombier 	x = execute(a[0]);
6203e12c5d1SDavid du Colombier 	i = istrue(x);
6213e12c5d1SDavid du Colombier 	tempfree(x);
6223e12c5d1SDavid du Colombier 	switch (n) {
6233e12c5d1SDavid du Colombier 	case BOR:
6247dd7cddfSDavid du Colombier 		if (i) return(True);
6253e12c5d1SDavid du Colombier 		y = execute(a[1]);
6263e12c5d1SDavid du Colombier 		i = istrue(y);
6273e12c5d1SDavid du Colombier 		tempfree(y);
6287dd7cddfSDavid du Colombier 		if (i) return(True);
6297dd7cddfSDavid du Colombier 		else return(False);
6303e12c5d1SDavid du Colombier 	case AND:
6317dd7cddfSDavid du Colombier 		if ( !i ) return(False);
6323e12c5d1SDavid du Colombier 		y = execute(a[1]);
6333e12c5d1SDavid du Colombier 		i = istrue(y);
6343e12c5d1SDavid du Colombier 		tempfree(y);
6357dd7cddfSDavid du Colombier 		if (i) return(True);
6367dd7cddfSDavid du Colombier 		else return(False);
6373e12c5d1SDavid du Colombier 	case NOT:
6387dd7cddfSDavid du Colombier 		if (i) return(False);
6397dd7cddfSDavid du Colombier 		else return(True);
6403e12c5d1SDavid du Colombier 	default:	/* can't happen */
6417dd7cddfSDavid du Colombier 		FATAL("unknown boolean operator %d", n);
6423e12c5d1SDavid du Colombier 	}
6433e12c5d1SDavid du Colombier 	return 0;	/*NOTREACHED*/
6443e12c5d1SDavid du Colombier }
6453e12c5d1SDavid du Colombier 
relop(Node ** a,int n)646219b2ee8SDavid du Colombier Cell *relop(Node **a, int n)	/* a[0 < a[1], etc. */
6473e12c5d1SDavid du Colombier {
6487dd7cddfSDavid du Colombier 	int i;
6497dd7cddfSDavid du Colombier 	Cell *x, *y;
6503e12c5d1SDavid du Colombier 	Awkfloat j;
6513e12c5d1SDavid du Colombier 
6523e12c5d1SDavid du Colombier 	x = execute(a[0]);
6533e12c5d1SDavid du Colombier 	y = execute(a[1]);
6543e12c5d1SDavid du Colombier 	if (x->tval&NUM && y->tval&NUM) {
6553e12c5d1SDavid du Colombier 		j = x->fval - y->fval;
6563e12c5d1SDavid du Colombier 		i = j<0? -1: (j>0? 1: 0);
6573e12c5d1SDavid du Colombier 	} else {
6583e12c5d1SDavid du Colombier 		i = strcmp(getsval(x), getsval(y));
6593e12c5d1SDavid du Colombier 	}
6603e12c5d1SDavid du Colombier 	tempfree(x);
6613e12c5d1SDavid du Colombier 	tempfree(y);
6623e12c5d1SDavid du Colombier 	switch (n) {
6637dd7cddfSDavid du Colombier 	case LT:	if (i<0) return(True);
6647dd7cddfSDavid du Colombier 			else return(False);
6657dd7cddfSDavid du Colombier 	case LE:	if (i<=0) return(True);
6667dd7cddfSDavid du Colombier 			else return(False);
6677dd7cddfSDavid du Colombier 	case NE:	if (i!=0) return(True);
6687dd7cddfSDavid du Colombier 			else return(False);
6697dd7cddfSDavid du Colombier 	case EQ:	if (i == 0) return(True);
6707dd7cddfSDavid du Colombier 			else return(False);
6717dd7cddfSDavid du Colombier 	case GE:	if (i>=0) return(True);
6727dd7cddfSDavid du Colombier 			else return(False);
6737dd7cddfSDavid du Colombier 	case GT:	if (i>0) return(True);
6747dd7cddfSDavid du Colombier 			else return(False);
6753e12c5d1SDavid du Colombier 	default:	/* can't happen */
6767dd7cddfSDavid du Colombier 		FATAL("unknown relational operator %d", n);
6773e12c5d1SDavid du Colombier 	}
6783e12c5d1SDavid du Colombier 	return 0;	/*NOTREACHED*/
6793e12c5d1SDavid du Colombier }
6803e12c5d1SDavid du Colombier 
tfree(Cell * a)681219b2ee8SDavid du Colombier void tfree(Cell *a)	/* free a tempcell */
6823e12c5d1SDavid du Colombier {
6837dd7cddfSDavid du Colombier 	if (freeable(a)) {
684*a2c41696SDavid du Colombier 		   dprintf( ("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval) );
6853e12c5d1SDavid du Colombier 		xfree(a->sval);
6867dd7cddfSDavid du Colombier 	}
6873e12c5d1SDavid du Colombier 	if (a == tmps)
6887dd7cddfSDavid du Colombier 		FATAL("tempcell list is curdled");
6893e12c5d1SDavid du Colombier 	a->cnext = tmps;
6903e12c5d1SDavid du Colombier 	tmps = a;
6913e12c5d1SDavid du Colombier }
6923e12c5d1SDavid du Colombier 
gettemp(void)693219b2ee8SDavid du Colombier Cell *gettemp(void)	/* get a tempcell */
6943e12c5d1SDavid du Colombier {	int i;
6957dd7cddfSDavid du Colombier 	Cell *x;
6963e12c5d1SDavid du Colombier 
6973e12c5d1SDavid du Colombier 	if (!tmps) {
6983e12c5d1SDavid du Colombier 		tmps = (Cell *) calloc(100, sizeof(Cell));
6993e12c5d1SDavid du Colombier 		if (!tmps)
7007dd7cddfSDavid du Colombier 			FATAL("out of space for temporaries");
7013e12c5d1SDavid du Colombier 		for(i = 1; i < 100; i++)
7023e12c5d1SDavid du Colombier 			tmps[i-1].cnext = &tmps[i];
7033e12c5d1SDavid du Colombier 		tmps[i-1].cnext = 0;
7043e12c5d1SDavid du Colombier 	}
7053e12c5d1SDavid du Colombier 	x = tmps;
7063e12c5d1SDavid du Colombier 	tmps = x->cnext;
7073e12c5d1SDavid du Colombier 	*x = tempcell;
7083e12c5d1SDavid du Colombier 	return(x);
7093e12c5d1SDavid du Colombier }
7103e12c5d1SDavid du Colombier 
indirect(Node ** a,int n)711219b2ee8SDavid du Colombier Cell *indirect(Node **a, int n)	/* $( a[0] ) */
7123e12c5d1SDavid du Colombier {
713*a2c41696SDavid du Colombier 	Awkfloat val;
7147dd7cddfSDavid du Colombier 	Cell *x;
7157dd7cddfSDavid du Colombier 	int m;
7167dd7cddfSDavid du Colombier 	char *s;
7173e12c5d1SDavid du Colombier 
7183e12c5d1SDavid du Colombier 	x = execute(a[0]);
719*a2c41696SDavid du Colombier 	val = getfval(x);	/* freebsd: defend against super large field numbers */
720*a2c41696SDavid du Colombier 	if ((Awkfloat)INT_MAX < val)
721*a2c41696SDavid du Colombier 		FATAL("trying to access out of range field %s", x->nval);
722*a2c41696SDavid du Colombier 	m = (int) val;
7237dd7cddfSDavid du Colombier 	if (m == 0 && !is_number(s = getsval(x)))	/* suspicion! */
7247dd7cddfSDavid du Colombier 		FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
7257dd7cddfSDavid du Colombier 		/* BUG: can x->nval ever be null??? */
7263e12c5d1SDavid du Colombier 	tempfree(x);
7273e12c5d1SDavid du Colombier 	x = fieldadr(m);
7287dd7cddfSDavid du Colombier 	x->ctype = OCELL;	/* BUG?  why are these needed? */
7293e12c5d1SDavid du Colombier 	x->csub = CFLD;
7303e12c5d1SDavid du Colombier 	return(x);
7313e12c5d1SDavid du Colombier }
7323e12c5d1SDavid du Colombier 
substr(Node ** a,int nnn)733219b2ee8SDavid du Colombier Cell *substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
7343e12c5d1SDavid du Colombier {
7357dd7cddfSDavid du Colombier 	int k, m, n;
736*a2c41696SDavid du Colombier 	char *s;
7373e12c5d1SDavid du Colombier 	int temp;
7387dd7cddfSDavid du Colombier 	Cell *x, *y, *z = 0;
7393e12c5d1SDavid du Colombier 
7403e12c5d1SDavid du Colombier 	x = execute(a[0]);
7413e12c5d1SDavid du Colombier 	y = execute(a[1]);
7423e12c5d1SDavid du Colombier 	if (a[2] != 0)
7433e12c5d1SDavid du Colombier 		z = execute(a[2]);
7443e12c5d1SDavid du Colombier 	s = getsval(x);
745*a2c41696SDavid du Colombier 	k = strlen(s) + 1;
7463e12c5d1SDavid du Colombier 	if (k <= 1) {
7473e12c5d1SDavid du Colombier 		tempfree(x);
7483e12c5d1SDavid du Colombier 		tempfree(y);
749*a2c41696SDavid du Colombier 		if (a[2] != 0) {
7503e12c5d1SDavid du Colombier 			tempfree(z);
751*a2c41696SDavid du Colombier 		}
7523e12c5d1SDavid du Colombier 		x = gettemp();
7533e12c5d1SDavid du Colombier 		setsval(x, "");
7543e12c5d1SDavid du Colombier 		return(x);
7553e12c5d1SDavid du Colombier 	}
7567dd7cddfSDavid du Colombier 	m = (int) getfval(y);
7573e12c5d1SDavid du Colombier 	if (m <= 0)
7583e12c5d1SDavid du Colombier 		m = 1;
7593e12c5d1SDavid du Colombier 	else if (m > k)
7603e12c5d1SDavid du Colombier 		m = k;
7613e12c5d1SDavid du Colombier 	tempfree(y);
7623e12c5d1SDavid du Colombier 	if (a[2] != 0) {
7637dd7cddfSDavid du Colombier 		n = (int) getfval(z);
7643e12c5d1SDavid du Colombier 		tempfree(z);
7653e12c5d1SDavid du Colombier 	} else
7663e12c5d1SDavid du Colombier 		n = k - 1;
7673e12c5d1SDavid du Colombier 	if (n < 0)
7683e12c5d1SDavid du Colombier 		n = 0;
7693e12c5d1SDavid du Colombier 	else if (n > k - m)
7703e12c5d1SDavid du Colombier 		n = k - m;
7713e12c5d1SDavid du Colombier 	   dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
7723e12c5d1SDavid du Colombier 	y = gettemp();
773*a2c41696SDavid du Colombier 	temp = s[n+m-1];	/* with thanks to John Linderman */
774*a2c41696SDavid du Colombier 	s[n+m-1] = '\0';
775*a2c41696SDavid du Colombier 	setsval(y, s + m - 1);
776*a2c41696SDavid du Colombier 	s[n+m-1] = temp;
7773e12c5d1SDavid du Colombier 	tempfree(x);
7783e12c5d1SDavid du Colombier 	return(y);
7793e12c5d1SDavid du Colombier }
7803e12c5d1SDavid du Colombier 
sindex(Node ** a,int nnn)781219b2ee8SDavid du Colombier Cell *sindex(Node **a, int nnn)		/* index(a[0], a[1]) */
7823e12c5d1SDavid du Colombier {
7837dd7cddfSDavid du Colombier 	Cell *x, *y, *z;
7847dd7cddfSDavid du Colombier 	char *s1, *s2, *p1, *p2, *q;
7853e12c5d1SDavid du Colombier 	Awkfloat v = 0.0;
7863e12c5d1SDavid du Colombier 
7873e12c5d1SDavid du Colombier 	x = execute(a[0]);
7883e12c5d1SDavid du Colombier 	s1 = getsval(x);
7893e12c5d1SDavid du Colombier 	y = execute(a[1]);
7903e12c5d1SDavid du Colombier 	s2 = getsval(y);
7913e12c5d1SDavid du Colombier 
7923e12c5d1SDavid du Colombier 	z = gettemp();
7933e12c5d1SDavid du Colombier 	for (p1 = s1; *p1 != '\0'; p1++) {
7943e12c5d1SDavid du Colombier 		for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
7953e12c5d1SDavid du Colombier 			;
7963e12c5d1SDavid du Colombier 		if (*p2 == '\0') {
797*a2c41696SDavid du Colombier 			v = (Awkfloat) (p1 - s1 + 1);	/* origin 1 */
7983e12c5d1SDavid du Colombier 			break;
7993e12c5d1SDavid du Colombier 		}
8003e12c5d1SDavid du Colombier 	}
8013e12c5d1SDavid du Colombier 	tempfree(x);
8023e12c5d1SDavid du Colombier 	tempfree(y);
8033e12c5d1SDavid du Colombier 	setfval(z, v);
8043e12c5d1SDavid du Colombier 	return(z);
8053e12c5d1SDavid du Colombier }
8063e12c5d1SDavid du Colombier 
8077dd7cddfSDavid du Colombier #define	MAXNUMSIZE	50
808219b2ee8SDavid du Colombier 
format(char ** pbuf,int * pbufsize,const char * s,Node * a)809*a2c41696SDavid du Colombier int format(char **pbuf, int *pbufsize, const char *s, Node *a)	/* printf-like conversions */
8103e12c5d1SDavid du Colombier {
8117dd7cddfSDavid du Colombier 	char *fmt;
812*a2c41696SDavid du Colombier 	char *p, *t;
813*a2c41696SDavid du Colombier 	const char *os;
8147dd7cddfSDavid du Colombier 	Cell *x;
8153e12c5d1SDavid du Colombier 	int flag = 0, n;
8167dd7cddfSDavid du Colombier 	int fmtwd; /* format width */
8177dd7cddfSDavid du Colombier 	int fmtsz = recsize;
8187dd7cddfSDavid du Colombier 	char *buf = *pbuf;
8197dd7cddfSDavid du Colombier 	int bufsize = *pbufsize;
8203e12c5d1SDavid du Colombier 
8213e12c5d1SDavid du Colombier 	os = s;
8223e12c5d1SDavid du Colombier 	p = buf;
8237dd7cddfSDavid du Colombier 	if ((fmt = (char *) malloc(fmtsz)) == NULL)
8247dd7cddfSDavid du Colombier 		FATAL("out of memory in format()");
8253e12c5d1SDavid du Colombier 	while (*s) {
826*a2c41696SDavid du Colombier 		adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1");
8273e12c5d1SDavid du Colombier 		if (*s != '%') {
8283e12c5d1SDavid du Colombier 			*p++ = *s++;
8293e12c5d1SDavid du Colombier 			continue;
8303e12c5d1SDavid du Colombier 		}
8313e12c5d1SDavid du Colombier 		if (*(s+1) == '%') {
8323e12c5d1SDavid du Colombier 			*p++ = '%';
8333e12c5d1SDavid du Colombier 			s += 2;
8343e12c5d1SDavid du Colombier 			continue;
8353e12c5d1SDavid du Colombier 		}
8367dd7cddfSDavid du Colombier 		/* have to be real careful in case this is a huge number, eg, %100000d */
8377dd7cddfSDavid du Colombier 		fmtwd = atoi(s+1);
8387dd7cddfSDavid du Colombier 		if (fmtwd < 0)
8397dd7cddfSDavid du Colombier 			fmtwd = -fmtwd;
840*a2c41696SDavid du Colombier 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format2");
8413e12c5d1SDavid du Colombier 		for (t = fmt; (*t++ = *s) != '\0'; s++) {
842*a2c41696SDavid du Colombier 			if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3"))
8437dd7cddfSDavid du Colombier 				FATAL("format item %.30s... ran format() out of memory", os);
844*a2c41696SDavid du Colombier 			if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L')
8453e12c5d1SDavid du Colombier 				break;	/* the ansi panoply */
8463e12c5d1SDavid du Colombier 			if (*s == '*') {
8473e12c5d1SDavid du Colombier 				x = execute(a);
8483e12c5d1SDavid du Colombier 				a = a->nnext;
8497dd7cddfSDavid du Colombier 				sprintf(t-1, "%d", fmtwd=(int) getfval(x));
8507dd7cddfSDavid du Colombier 				if (fmtwd < 0)
8517dd7cddfSDavid du Colombier 					fmtwd = -fmtwd;
8527dd7cddfSDavid du Colombier 				adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
8533e12c5d1SDavid du Colombier 				t = fmt + strlen(fmt);
8543e12c5d1SDavid du Colombier 				tempfree(x);
8553e12c5d1SDavid du Colombier 			}
8563e12c5d1SDavid du Colombier 		}
8573e12c5d1SDavid du Colombier 		*t = '\0';
8587dd7cddfSDavid du Colombier 		if (fmtwd < 0)
8597dd7cddfSDavid du Colombier 			fmtwd = -fmtwd;
860*a2c41696SDavid du Colombier 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format4");
8617dd7cddfSDavid du Colombier 
8623e12c5d1SDavid du Colombier 		switch (*s) {
8633e12c5d1SDavid du Colombier 		case 'f': case 'e': case 'g': case 'E': case 'G':
864*a2c41696SDavid du Colombier 			flag = 'f';
8653e12c5d1SDavid du Colombier 			break;
8663e12c5d1SDavid du Colombier 		case 'd': case 'i':
867*a2c41696SDavid du Colombier 			flag = 'd';
8683e12c5d1SDavid du Colombier 			if(*(s-1) == 'l') break;
8693e12c5d1SDavid du Colombier 			*(t-1) = 'l';
8703e12c5d1SDavid du Colombier 			*t = 'd';
8713e12c5d1SDavid du Colombier 			*++t = '\0';
8723e12c5d1SDavid du Colombier 			break;
8733e12c5d1SDavid du Colombier 		case 'o': case 'x': case 'X': case 'u':
874*a2c41696SDavid du Colombier 			flag = *(s-1) == 'l' ? 'd' : 'u';
8753e12c5d1SDavid du Colombier 			break;
8763e12c5d1SDavid du Colombier 		case 's':
877*a2c41696SDavid du Colombier 			flag = 's';
8783e12c5d1SDavid du Colombier 			break;
8793e12c5d1SDavid du Colombier 		case 'c':
880*a2c41696SDavid du Colombier 			flag = 'c';
8813e12c5d1SDavid du Colombier 			break;
8823e12c5d1SDavid du Colombier 		default:
8837dd7cddfSDavid du Colombier 			WARNING("weird printf conversion %s", fmt);
884*a2c41696SDavid du Colombier 			flag = '?';
8853e12c5d1SDavid du Colombier 			break;
8863e12c5d1SDavid du Colombier 		}
8873e12c5d1SDavid du Colombier 		if (a == NULL)
8887dd7cddfSDavid du Colombier 			FATAL("not enough args in printf(%s)", os);
8893e12c5d1SDavid du Colombier 		x = execute(a);
8903e12c5d1SDavid du Colombier 		a = a->nnext;
8917dd7cddfSDavid du Colombier 		n = MAXNUMSIZE;
8927dd7cddfSDavid du Colombier 		if (fmtwd > n)
8937dd7cddfSDavid du Colombier 			n = fmtwd;
894*a2c41696SDavid du Colombier 		adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5");
8953e12c5d1SDavid du Colombier 		switch (flag) {
896*a2c41696SDavid du Colombier 		case '?':	sprintf(p, "%s", fmt);	/* unknown, so dump it too */
8977dd7cddfSDavid du Colombier 			t = getsval(x);
8987dd7cddfSDavid du Colombier 			n = strlen(t);
8997dd7cddfSDavid du Colombier 			if (fmtwd > n)
9007dd7cddfSDavid du Colombier 				n = fmtwd;
901*a2c41696SDavid du Colombier 			adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6");
9023e12c5d1SDavid du Colombier 			p += strlen(p);
9037dd7cddfSDavid du Colombier 			sprintf(p, "%s", t);
9043e12c5d1SDavid du Colombier 			break;
905*a2c41696SDavid du Colombier 		case 'f':	sprintf(p, fmt, getfval(x)); break;
906*a2c41696SDavid du Colombier 		case 'd':	sprintf(p, fmt, (long) getfval(x)); break;
907*a2c41696SDavid du Colombier 		case 'u':	sprintf(p, fmt, (int) getfval(x)); break;
908*a2c41696SDavid du Colombier 		case 's':
9093e12c5d1SDavid du Colombier 			t = getsval(x);
9103e12c5d1SDavid du Colombier 			n = strlen(t);
9117dd7cddfSDavid du Colombier 			if (fmtwd > n)
9127dd7cddfSDavid du Colombier 				n = fmtwd;
913*a2c41696SDavid du Colombier 			if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7"))
9147dd7cddfSDavid du Colombier 				FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
9157dd7cddfSDavid du Colombier 			sprintf(p, fmt, t);
9163e12c5d1SDavid du Colombier 			break;
917*a2c41696SDavid du Colombier 		case 'c':
9187dd7cddfSDavid du Colombier 			if (isnum(x)) {
9197dd7cddfSDavid du Colombier 				if (getfval(x))
9207dd7cddfSDavid du Colombier 					sprintf(p, fmt, (int) getfval(x));
92176f6a3b8SDavid du Colombier 				else {
922*a2c41696SDavid du Colombier 					*p++ = '\0'; /* explicit null byte */
923*a2c41696SDavid du Colombier 					*p = '\0';   /* next output will start here */
92476f6a3b8SDavid du Colombier 				}
9257dd7cddfSDavid du Colombier 			} else
9267dd7cddfSDavid du Colombier 				sprintf(p, fmt, getsval(x)[0]);
9273e12c5d1SDavid du Colombier 			break;
928*a2c41696SDavid du Colombier 		default:
929*a2c41696SDavid du Colombier 			FATAL("can't happen: bad conversion %c in format()", flag);
9303e12c5d1SDavid du Colombier 		}
9313e12c5d1SDavid du Colombier 		tempfree(x);
9323e12c5d1SDavid du Colombier 		p += strlen(p);
9333e12c5d1SDavid du Colombier 		s++;
9343e12c5d1SDavid du Colombier 	}
9353e12c5d1SDavid du Colombier 	*p = '\0';
9367dd7cddfSDavid du Colombier 	free(fmt);
9373e12c5d1SDavid du Colombier 	for ( ; a; a = a->nnext)		/* evaluate any remaining args */
9383e12c5d1SDavid du Colombier 		execute(a);
9397dd7cddfSDavid du Colombier 	*pbuf = buf;
9407dd7cddfSDavid du Colombier 	*pbufsize = bufsize;
9417dd7cddfSDavid du Colombier 	return p - buf;
9423e12c5d1SDavid du Colombier }
9433e12c5d1SDavid du Colombier 
awksprintf(Node ** a,int n)9447dd7cddfSDavid du Colombier Cell *awksprintf(Node **a, int n)		/* sprintf(a[0]) */
9453e12c5d1SDavid du Colombier {
9467dd7cddfSDavid du Colombier 	Cell *x;
9477dd7cddfSDavid du Colombier 	Node *y;
9487dd7cddfSDavid du Colombier 	char *buf;
9497dd7cddfSDavid du Colombier 	int bufsz=3*recsize;
9503e12c5d1SDavid du Colombier 
9517dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL)
9527dd7cddfSDavid du Colombier 		FATAL("out of memory in awksprintf");
9533e12c5d1SDavid du Colombier 	y = a[0]->nnext;
9543e12c5d1SDavid du Colombier 	x = execute(a[0]);
9557dd7cddfSDavid du Colombier 	if (format(&buf, &bufsz, getsval(x), y) == -1)
9567dd7cddfSDavid du Colombier 		FATAL("sprintf string %.30s... too long.  can't happen.", buf);
9573e12c5d1SDavid du Colombier 	tempfree(x);
9583e12c5d1SDavid du Colombier 	x = gettemp();
9597dd7cddfSDavid du Colombier 	x->sval = buf;
9603e12c5d1SDavid du Colombier 	x->tval = STR;
9613e12c5d1SDavid du Colombier 	return(x);
9623e12c5d1SDavid du Colombier }
9633e12c5d1SDavid du Colombier 
awkprintf(Node ** a,int n)9647dd7cddfSDavid du Colombier Cell *awkprintf(Node **a, int n)		/* printf */
965219b2ee8SDavid du Colombier {	/* a[0] is list of args, starting with format string */
966219b2ee8SDavid du Colombier 	/* a[1] is redirection operator, a[2] is redirection file */
9673e12c5d1SDavid du Colombier 	FILE *fp;
9687dd7cddfSDavid du Colombier 	Cell *x;
9697dd7cddfSDavid du Colombier 	Node *y;
9707dd7cddfSDavid du Colombier 	char *buf;
9717dd7cddfSDavid du Colombier 	int len;
9727dd7cddfSDavid du Colombier 	int bufsz=3*recsize;
9733e12c5d1SDavid du Colombier 
9747dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL)
9757dd7cddfSDavid du Colombier 		FATAL("out of memory in awkprintf");
9763e12c5d1SDavid du Colombier 	y = a[0]->nnext;
9773e12c5d1SDavid du Colombier 	x = execute(a[0]);
9787dd7cddfSDavid du Colombier 	if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
9797dd7cddfSDavid du Colombier 		FATAL("printf string %.30s... too long.  can't happen.", buf);
9803e12c5d1SDavid du Colombier 	tempfree(x);
9813e12c5d1SDavid du Colombier 	if (a[1] == NULL) {
9827dd7cddfSDavid du Colombier 		/* fputs(buf, stdout); */
9837dd7cddfSDavid du Colombier 		fwrite(buf, len, 1, stdout);
9843e12c5d1SDavid du Colombier 		if (ferror(stdout))
9857dd7cddfSDavid du Colombier 			FATAL("write error on stdout");
9863e12c5d1SDavid du Colombier 	} else {
9877dd7cddfSDavid du Colombier 		fp = redirect(ptoi(a[1]), a[2]);
9887dd7cddfSDavid du Colombier 		/* fputs(buf, fp); */
9897dd7cddfSDavid du Colombier 		fwrite(buf, len, 1, fp);
9903e12c5d1SDavid du Colombier 		fflush(fp);
9913e12c5d1SDavid du Colombier 		if (ferror(fp))
9927dd7cddfSDavid du Colombier 			FATAL("write error on %s", filename(fp));
9933e12c5d1SDavid du Colombier 	}
9947dd7cddfSDavid du Colombier 	free(buf);
9957dd7cddfSDavid du Colombier 	return(True);
9963e12c5d1SDavid du Colombier }
9973e12c5d1SDavid du Colombier 
arith(Node ** a,int n)998219b2ee8SDavid du Colombier Cell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
9993e12c5d1SDavid du Colombier {
10007dd7cddfSDavid du Colombier 	Awkfloat i, j = 0;
10013e12c5d1SDavid du Colombier 	double v;
10027dd7cddfSDavid du Colombier 	Cell *x, *y, *z;
10033e12c5d1SDavid du Colombier 
10043e12c5d1SDavid du Colombier 	x = execute(a[0]);
10053e12c5d1SDavid du Colombier 	i = getfval(x);
10063e12c5d1SDavid du Colombier 	tempfree(x);
10073e12c5d1SDavid du Colombier 	if (n != UMINUS) {
10083e12c5d1SDavid du Colombier 		y = execute(a[1]);
10093e12c5d1SDavid du Colombier 		j = getfval(y);
10103e12c5d1SDavid du Colombier 		tempfree(y);
10113e12c5d1SDavid du Colombier 	}
10123e12c5d1SDavid du Colombier 	z = gettemp();
10133e12c5d1SDavid du Colombier 	switch (n) {
10143e12c5d1SDavid du Colombier 	case ADD:
10153e12c5d1SDavid du Colombier 		i += j;
10163e12c5d1SDavid du Colombier 		break;
10173e12c5d1SDavid du Colombier 	case MINUS:
10183e12c5d1SDavid du Colombier 		i -= j;
10193e12c5d1SDavid du Colombier 		break;
10203e12c5d1SDavid du Colombier 	case MULT:
10213e12c5d1SDavid du Colombier 		i *= j;
10223e12c5d1SDavid du Colombier 		break;
10233e12c5d1SDavid du Colombier 	case DIVIDE:
10243e12c5d1SDavid du Colombier 		if (j == 0)
10257dd7cddfSDavid du Colombier 			FATAL("division by zero");
10263e12c5d1SDavid du Colombier 		i /= j;
10273e12c5d1SDavid du Colombier 		break;
10283e12c5d1SDavid du Colombier 	case MOD:
10293e12c5d1SDavid du Colombier 		if (j == 0)
10307dd7cddfSDavid du Colombier 			FATAL("division by zero in mod");
10313e12c5d1SDavid du Colombier 		modf(i/j, &v);
10323e12c5d1SDavid du Colombier 		i = i - j * v;
10333e12c5d1SDavid du Colombier 		break;
10343e12c5d1SDavid du Colombier 	case UMINUS:
10353e12c5d1SDavid du Colombier 		i = -i;
10363e12c5d1SDavid du Colombier 		break;
10373e12c5d1SDavid du Colombier 	case POWER:
10383e12c5d1SDavid du Colombier 		if (j >= 0 && modf(j, &v) == 0.0)	/* pos integer exponent */
10393e12c5d1SDavid du Colombier 			i = ipow(i, (int) j);
10403e12c5d1SDavid du Colombier 		else
10413e12c5d1SDavid du Colombier 			i = errcheck(pow(i, j), "pow");
10423e12c5d1SDavid du Colombier 		break;
10433e12c5d1SDavid du Colombier 	default:	/* can't happen */
10447dd7cddfSDavid du Colombier 		FATAL("illegal arithmetic operator %d", n);
10453e12c5d1SDavid du Colombier 	}
10463e12c5d1SDavid du Colombier 	setfval(z, i);
10473e12c5d1SDavid du Colombier 	return(z);
10483e12c5d1SDavid du Colombier }
10493e12c5d1SDavid du Colombier 
ipow(double x,int n)1050219b2ee8SDavid du Colombier double ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
10513e12c5d1SDavid du Colombier {
10523e12c5d1SDavid du Colombier 	double v;
10533e12c5d1SDavid du Colombier 
10543e12c5d1SDavid du Colombier 	if (n <= 0)
10553e12c5d1SDavid du Colombier 		return 1;
10563e12c5d1SDavid du Colombier 	v = ipow(x, n/2);
10573e12c5d1SDavid du Colombier 	if (n % 2 == 0)
10583e12c5d1SDavid du Colombier 		return v * v;
10593e12c5d1SDavid du Colombier 	else
10603e12c5d1SDavid du Colombier 		return x * v * v;
10613e12c5d1SDavid du Colombier }
10623e12c5d1SDavid du Colombier 
incrdecr(Node ** a,int n)1063219b2ee8SDavid du Colombier Cell *incrdecr(Node **a, int n)		/* a[0]++, etc. */
10643e12c5d1SDavid du Colombier {
10657dd7cddfSDavid du Colombier 	Cell *x, *z;
10667dd7cddfSDavid du Colombier 	int k;
10673e12c5d1SDavid du Colombier 	Awkfloat xf;
10683e12c5d1SDavid du Colombier 
10693e12c5d1SDavid du Colombier 	x = execute(a[0]);
10703e12c5d1SDavid du Colombier 	xf = getfval(x);
10713e12c5d1SDavid du Colombier 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
10723e12c5d1SDavid du Colombier 	if (n == PREINCR || n == PREDECR) {
10733e12c5d1SDavid du Colombier 		setfval(x, xf + k);
10743e12c5d1SDavid du Colombier 		return(x);
10753e12c5d1SDavid du Colombier 	}
10763e12c5d1SDavid du Colombier 	z = gettemp();
10773e12c5d1SDavid du Colombier 	setfval(z, xf);
10783e12c5d1SDavid du Colombier 	setfval(x, xf + k);
10793e12c5d1SDavid du Colombier 	tempfree(x);
10803e12c5d1SDavid du Colombier 	return(z);
10813e12c5d1SDavid du Colombier }
10823e12c5d1SDavid du Colombier 
assign(Node ** a,int n)1083219b2ee8SDavid du Colombier Cell *assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
1084219b2ee8SDavid du Colombier {		/* this is subtle; don't muck with it. */
10857dd7cddfSDavid du Colombier 	Cell *x, *y;
10863e12c5d1SDavid du Colombier 	Awkfloat xf, yf;
10873e12c5d1SDavid du Colombier 	double v;
10883e12c5d1SDavid du Colombier 
10893e12c5d1SDavid du Colombier 	y = execute(a[1]);
10903e12c5d1SDavid du Colombier 	x = execute(a[0]);
10913e12c5d1SDavid du Colombier 	if (n == ASSIGN) {	/* ordinary assignment */
1092219b2ee8SDavid du Colombier 		if (x == y && !(x->tval & (FLD|REC)))	/* self-assignment: */
1093219b2ee8SDavid du Colombier 			;		/* leave alone unless it's a field */
10943e12c5d1SDavid du Colombier 		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
10953e12c5d1SDavid du Colombier 			setsval(x, getsval(y));
10963e12c5d1SDavid du Colombier 			x->fval = getfval(y);
10973e12c5d1SDavid du Colombier 			x->tval |= NUM;
10983e12c5d1SDavid du Colombier 		}
10997dd7cddfSDavid du Colombier 		else if (isstr(y))
11003e12c5d1SDavid du Colombier 			setsval(x, getsval(y));
11017dd7cddfSDavid du Colombier 		else if (isnum(y))
11023e12c5d1SDavid du Colombier 			setfval(x, getfval(y));
11033e12c5d1SDavid du Colombier 		else
11043e12c5d1SDavid du Colombier 			funnyvar(y, "read value of");
11053e12c5d1SDavid du Colombier 		tempfree(y);
11063e12c5d1SDavid du Colombier 		return(x);
11073e12c5d1SDavid du Colombier 	}
11083e12c5d1SDavid du Colombier 	xf = getfval(x);
11093e12c5d1SDavid du Colombier 	yf = getfval(y);
11103e12c5d1SDavid du Colombier 	switch (n) {
11113e12c5d1SDavid du Colombier 	case ADDEQ:
11123e12c5d1SDavid du Colombier 		xf += yf;
11133e12c5d1SDavid du Colombier 		break;
11143e12c5d1SDavid du Colombier 	case SUBEQ:
11153e12c5d1SDavid du Colombier 		xf -= yf;
11163e12c5d1SDavid du Colombier 		break;
11173e12c5d1SDavid du Colombier 	case MULTEQ:
11183e12c5d1SDavid du Colombier 		xf *= yf;
11193e12c5d1SDavid du Colombier 		break;
11203e12c5d1SDavid du Colombier 	case DIVEQ:
11213e12c5d1SDavid du Colombier 		if (yf == 0)
11227dd7cddfSDavid du Colombier 			FATAL("division by zero in /=");
11233e12c5d1SDavid du Colombier 		xf /= yf;
11243e12c5d1SDavid du Colombier 		break;
11253e12c5d1SDavid du Colombier 	case MODEQ:
11263e12c5d1SDavid du Colombier 		if (yf == 0)
11277dd7cddfSDavid du Colombier 			FATAL("division by zero in %%=");
11283e12c5d1SDavid du Colombier 		modf(xf/yf, &v);
11293e12c5d1SDavid du Colombier 		xf = xf - yf * v;
11303e12c5d1SDavid du Colombier 		break;
11313e12c5d1SDavid du Colombier 	case POWEQ:
11323e12c5d1SDavid du Colombier 		if (yf >= 0 && modf(yf, &v) == 0.0)	/* pos integer exponent */
11333e12c5d1SDavid du Colombier 			xf = ipow(xf, (int) yf);
11343e12c5d1SDavid du Colombier 		else
11353e12c5d1SDavid du Colombier 			xf = errcheck(pow(xf, yf), "pow");
11363e12c5d1SDavid du Colombier 		break;
11373e12c5d1SDavid du Colombier 	default:
11387dd7cddfSDavid du Colombier 		FATAL("illegal assignment operator %d", n);
11393e12c5d1SDavid du Colombier 		break;
11403e12c5d1SDavid du Colombier 	}
11413e12c5d1SDavid du Colombier 	tempfree(y);
11423e12c5d1SDavid du Colombier 	setfval(x, xf);
11433e12c5d1SDavid du Colombier 	return(x);
11443e12c5d1SDavid du Colombier }
11453e12c5d1SDavid du Colombier 
cat(Node ** a,int q)1146219b2ee8SDavid du Colombier Cell *cat(Node **a, int q)	/* a[0] cat a[1] */
11473e12c5d1SDavid du Colombier {
11487dd7cddfSDavid du Colombier 	Cell *x, *y, *z;
11497dd7cddfSDavid du Colombier 	int n1, n2;
11507dd7cddfSDavid du Colombier 	char *s;
11513e12c5d1SDavid du Colombier 
11523e12c5d1SDavid du Colombier 	x = execute(a[0]);
11533e12c5d1SDavid du Colombier 	y = execute(a[1]);
11543e12c5d1SDavid du Colombier 	getsval(x);
11553e12c5d1SDavid du Colombier 	getsval(y);
11563e12c5d1SDavid du Colombier 	n1 = strlen(x->sval);
11573e12c5d1SDavid du Colombier 	n2 = strlen(y->sval);
11587dd7cddfSDavid du Colombier 	s = (char *) malloc(n1 + n2 + 1);
11593e12c5d1SDavid du Colombier 	if (s == NULL)
11607dd7cddfSDavid du Colombier 		FATAL("out of space concatenating %.15s... and %.15s...",
11617dd7cddfSDavid du Colombier 			x->sval, y->sval);
11623e12c5d1SDavid du Colombier 	strcpy(s, x->sval);
11633e12c5d1SDavid du Colombier 	strcpy(s+n1, y->sval);
1164*a2c41696SDavid du Colombier 	tempfree(x);
11653e12c5d1SDavid du Colombier 	tempfree(y);
11663e12c5d1SDavid du Colombier 	z = gettemp();
11673e12c5d1SDavid du Colombier 	z->sval = s;
11683e12c5d1SDavid du Colombier 	z->tval = STR;
11693e12c5d1SDavid du Colombier 	return(z);
11703e12c5d1SDavid du Colombier }
11713e12c5d1SDavid du Colombier 
pastat(Node ** a,int n)11723e12c5d1SDavid du Colombier Cell *pastat(Node **a, int n)	/* a[0] { a[1] } */
11733e12c5d1SDavid du Colombier {
11747dd7cddfSDavid du Colombier 	Cell *x;
11753e12c5d1SDavid du Colombier 
11763e12c5d1SDavid du Colombier 	if (a[0] == 0)
11773e12c5d1SDavid du Colombier 		x = execute(a[1]);
11783e12c5d1SDavid du Colombier 	else {
11793e12c5d1SDavid du Colombier 		x = execute(a[0]);
11803e12c5d1SDavid du Colombier 		if (istrue(x)) {
11813e12c5d1SDavid du Colombier 			tempfree(x);
11823e12c5d1SDavid du Colombier 			x = execute(a[1]);
11833e12c5d1SDavid du Colombier 		}
11843e12c5d1SDavid du Colombier 	}
11853e12c5d1SDavid du Colombier 	return x;
11863e12c5d1SDavid du Colombier }
11873e12c5d1SDavid du Colombier 
dopa2(Node ** a,int n)11883e12c5d1SDavid du Colombier Cell *dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
11893e12c5d1SDavid du Colombier {
11907dd7cddfSDavid du Colombier 	Cell *x;
11917dd7cddfSDavid du Colombier 	int pair;
11923e12c5d1SDavid du Colombier 
11937dd7cddfSDavid du Colombier 	pair = ptoi(a[3]);
11943e12c5d1SDavid du Colombier 	if (pairstack[pair] == 0) {
11953e12c5d1SDavid du Colombier 		x = execute(a[0]);
11963e12c5d1SDavid du Colombier 		if (istrue(x))
11973e12c5d1SDavid du Colombier 			pairstack[pair] = 1;
11983e12c5d1SDavid du Colombier 		tempfree(x);
11993e12c5d1SDavid du Colombier 	}
12003e12c5d1SDavid du Colombier 	if (pairstack[pair] == 1) {
12013e12c5d1SDavid du Colombier 		x = execute(a[1]);
12023e12c5d1SDavid du Colombier 		if (istrue(x))
12033e12c5d1SDavid du Colombier 			pairstack[pair] = 0;
12043e12c5d1SDavid du Colombier 		tempfree(x);
12053e12c5d1SDavid du Colombier 		x = execute(a[2]);
12063e12c5d1SDavid du Colombier 		return(x);
12073e12c5d1SDavid du Colombier 	}
12087dd7cddfSDavid du Colombier 	return(False);
12093e12c5d1SDavid du Colombier }
12103e12c5d1SDavid du Colombier 
split(Node ** a,int nnn)12113e12c5d1SDavid du Colombier Cell *split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
12123e12c5d1SDavid du Colombier {
12137dd7cddfSDavid du Colombier 	Cell *x = 0, *y, *ap;
1214535404a9SDavid du Colombier 	char *s, *t, *fs = 0;
1215535404a9SDavid du Colombier 	char temp, num[50];
1216535404a9SDavid du Colombier 	int n, nb, sep, tempstat, arg3type;
12173e12c5d1SDavid du Colombier 
12183e12c5d1SDavid du Colombier 	y = execute(a[0]);	/* source string */
12193e12c5d1SDavid du Colombier 	s = getsval(y);
12207dd7cddfSDavid du Colombier 	arg3type = ptoi(a[3]);
12213e12c5d1SDavid du Colombier 	if (a[2] == 0)		/* fs string */
12223e12c5d1SDavid du Colombier 		fs = *FS;
12237dd7cddfSDavid du Colombier 	else if (arg3type == STRING) {	/* split(str,arr,"string") */
12243e12c5d1SDavid du Colombier 		x = execute(a[2]);
12253e12c5d1SDavid du Colombier 		fs = getsval(x);
12267dd7cddfSDavid du Colombier 	} else if (arg3type == REGEXPR)
12277dd7cddfSDavid du Colombier 		fs = "(regexpr)";	/* split(str,arr,/regexpr/) */
12283e12c5d1SDavid du Colombier 	else
12297dd7cddfSDavid du Colombier 		FATAL("illegal type of split");
12303e12c5d1SDavid du Colombier 	sep = *fs;
12313e12c5d1SDavid du Colombier 	ap = execute(a[1]);	/* array name */
12323e12c5d1SDavid du Colombier 	freesymtab(ap);
12333e12c5d1SDavid du Colombier 	   dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
12343e12c5d1SDavid du Colombier 	ap->tval &= ~STR;
12353e12c5d1SDavid du Colombier 	ap->tval |= ARR;
12367dd7cddfSDavid du Colombier 	ap->sval = (char *) makesymtab(NSYMTAB);
12373e12c5d1SDavid du Colombier 
12383e12c5d1SDavid du Colombier 	n = 0;
12397dd7cddfSDavid du Colombier 	if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) {	/* reg expr */
12403e12c5d1SDavid du Colombier 		void *p;
12417dd7cddfSDavid du Colombier 		if (arg3type == REGEXPR) {	/* it's ready already */
12423e12c5d1SDavid du Colombier 			p = (void *) a[2];
12433e12c5d1SDavid du Colombier 		} else {
12443e12c5d1SDavid du Colombier 			p = compre(fs);
12453e12c5d1SDavid du Colombier 		}
12463e12c5d1SDavid du Colombier 		t = s;
12473e12c5d1SDavid du Colombier 		if (nematch(p,s,t)) {
12483e12c5d1SDavid du Colombier 			do {
12493e12c5d1SDavid du Colombier 				n++;
12507dd7cddfSDavid du Colombier 				sprintf(num, "%d", n);
12513e12c5d1SDavid du Colombier 				temp = *patbeg;
12523e12c5d1SDavid du Colombier 				*patbeg = '\0';
12537dd7cddfSDavid du Colombier 				if (is_number(t))
12547dd7cddfSDavid du Colombier 					setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
12553e12c5d1SDavid du Colombier 				else
12563e12c5d1SDavid du Colombier 					setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
12573e12c5d1SDavid du Colombier 				*patbeg = temp;
12583e12c5d1SDavid du Colombier 				t = patbeg + patlen;
12593e12c5d1SDavid du Colombier 				if (t[-1] == 0 || *t == 0) {
12603e12c5d1SDavid du Colombier 					n++;
12617dd7cddfSDavid du Colombier 					sprintf(num, "%d", n);
12623e12c5d1SDavid du Colombier 					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
12633e12c5d1SDavid du Colombier 					goto spdone;
12643e12c5d1SDavid du Colombier 				}
12653e12c5d1SDavid du Colombier 			} while (nematch(p,s,t));
12663e12c5d1SDavid du Colombier 		}
12673e12c5d1SDavid du Colombier 		n++;
12687dd7cddfSDavid du Colombier 		sprintf(num, "%d", n);
12697dd7cddfSDavid du Colombier 		if (is_number(t))
12707dd7cddfSDavid du Colombier 			setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
12713e12c5d1SDavid du Colombier 		else
12723e12c5d1SDavid du Colombier 			setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
12733e12c5d1SDavid du Colombier   spdone:
12743e12c5d1SDavid du Colombier 		p = NULL;
12753e12c5d1SDavid du Colombier 	} else if (sep == ' ') {
12763e12c5d1SDavid du Colombier 		for (n = 0; ; ) {
12773e12c5d1SDavid du Colombier 			while (*s == ' ' || *s == '\t' || *s == '\n')
12783e12c5d1SDavid du Colombier 				s++;
12793e12c5d1SDavid du Colombier 			if (*s == 0)
12803e12c5d1SDavid du Colombier 				break;
12813e12c5d1SDavid du Colombier 			n++;
12823e12c5d1SDavid du Colombier 			t = s;
12833e12c5d1SDavid du Colombier 			do
12843e12c5d1SDavid du Colombier 				s++;
12853e12c5d1SDavid du Colombier 			while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
12863e12c5d1SDavid du Colombier 			temp = *s;
12873e12c5d1SDavid du Colombier 			*s = '\0';
12887dd7cddfSDavid du Colombier 			sprintf(num, "%d", n);
12897dd7cddfSDavid du Colombier 			if (is_number(t))
12907dd7cddfSDavid du Colombier 				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
12913e12c5d1SDavid du Colombier 			else
12923e12c5d1SDavid du Colombier 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
12933e12c5d1SDavid du Colombier 			*s = temp;
12943e12c5d1SDavid du Colombier 			if (*s != 0)
12953e12c5d1SDavid du Colombier 				s++;
12963e12c5d1SDavid du Colombier 		}
12977dd7cddfSDavid du Colombier 	} else if (sep == 0) {	/* new: split(s, a, "") => 1 char/elem */
1298535404a9SDavid du Colombier 		for (n = 0; *s != 0; s += nb) {
1299535404a9SDavid du Colombier 			Rune r;
1300535404a9SDavid du Colombier 			char buf[UTFmax+1];
1301535404a9SDavid du Colombier 
13027dd7cddfSDavid du Colombier 			n++;
1303535404a9SDavid du Colombier 			snprintf(num, sizeof num, "%d", n);
1304535404a9SDavid du Colombier 			nb = chartorune(&r, s);
1305535404a9SDavid du Colombier 			memmove(buf, s, nb);
1306535404a9SDavid du Colombier 			buf[nb] = '\0';
13077dd7cddfSDavid du Colombier 			if (isdigit(buf[0]))
13087dd7cddfSDavid du Colombier 				setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
13097dd7cddfSDavid du Colombier 			else
13107dd7cddfSDavid du Colombier 				setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
13117dd7cddfSDavid du Colombier 		}
13123e12c5d1SDavid du Colombier 	} else if (*s != 0) {
13133e12c5d1SDavid du Colombier 		for (;;) {
13143e12c5d1SDavid du Colombier 			n++;
13153e12c5d1SDavid du Colombier 			t = s;
13163e12c5d1SDavid du Colombier 			while (*s != sep && *s != '\n' && *s != '\0')
13173e12c5d1SDavid du Colombier 				s++;
13183e12c5d1SDavid du Colombier 			temp = *s;
13193e12c5d1SDavid du Colombier 			*s = '\0';
13207dd7cddfSDavid du Colombier 			sprintf(num, "%d", n);
13217dd7cddfSDavid du Colombier 			if (is_number(t))
13227dd7cddfSDavid du Colombier 				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
13233e12c5d1SDavid du Colombier 			else
13243e12c5d1SDavid du Colombier 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
13253e12c5d1SDavid du Colombier 			*s = temp;
13263e12c5d1SDavid du Colombier 			if (*s++ == 0)
13273e12c5d1SDavid du Colombier 				break;
13283e12c5d1SDavid du Colombier 		}
13293e12c5d1SDavid du Colombier 	}
13303e12c5d1SDavid du Colombier 	tempfree(ap);
13313e12c5d1SDavid du Colombier 	tempfree(y);
1332*a2c41696SDavid du Colombier 	if (a[2] != 0 && arg3type == STRING) {
13333e12c5d1SDavid du Colombier 		tempfree(x);
1334*a2c41696SDavid du Colombier 	}
13353e12c5d1SDavid du Colombier 	x = gettemp();
13363e12c5d1SDavid du Colombier 	x->tval = NUM;
13373e12c5d1SDavid du Colombier 	x->fval = n;
13383e12c5d1SDavid du Colombier 	return(x);
13393e12c5d1SDavid du Colombier }
13403e12c5d1SDavid du Colombier 
condexpr(Node ** a,int n)13413e12c5d1SDavid du Colombier Cell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
13423e12c5d1SDavid du Colombier {
13437dd7cddfSDavid du Colombier 	Cell *x;
13443e12c5d1SDavid du Colombier 
13453e12c5d1SDavid du Colombier 	x = execute(a[0]);
13463e12c5d1SDavid du Colombier 	if (istrue(x)) {
13473e12c5d1SDavid du Colombier 		tempfree(x);
13483e12c5d1SDavid du Colombier 		x = execute(a[1]);
13493e12c5d1SDavid du Colombier 	} else {
13503e12c5d1SDavid du Colombier 		tempfree(x);
13513e12c5d1SDavid du Colombier 		x = execute(a[2]);
13523e12c5d1SDavid du Colombier 	}
13533e12c5d1SDavid du Colombier 	return(x);
13543e12c5d1SDavid du Colombier }
13553e12c5d1SDavid du Colombier 
ifstat(Node ** a,int n)13563e12c5d1SDavid du Colombier Cell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
13573e12c5d1SDavid du Colombier {
13587dd7cddfSDavid du Colombier 	Cell *x;
13593e12c5d1SDavid du Colombier 
13603e12c5d1SDavid du Colombier 	x = execute(a[0]);
13613e12c5d1SDavid du Colombier 	if (istrue(x)) {
13623e12c5d1SDavid du Colombier 		tempfree(x);
13633e12c5d1SDavid du Colombier 		x = execute(a[1]);
13643e12c5d1SDavid du Colombier 	} else if (a[2] != 0) {
13653e12c5d1SDavid du Colombier 		tempfree(x);
13663e12c5d1SDavid du Colombier 		x = execute(a[2]);
13673e12c5d1SDavid du Colombier 	}
13683e12c5d1SDavid du Colombier 	return(x);
13693e12c5d1SDavid du Colombier }
13703e12c5d1SDavid du Colombier 
whilestat(Node ** a,int n)13713e12c5d1SDavid du Colombier Cell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
13723e12c5d1SDavid du Colombier {
13737dd7cddfSDavid du Colombier 	Cell *x;
13743e12c5d1SDavid du Colombier 
13753e12c5d1SDavid du Colombier 	for (;;) {
13763e12c5d1SDavid du Colombier 		x = execute(a[0]);
13773e12c5d1SDavid du Colombier 		if (!istrue(x))
13783e12c5d1SDavid du Colombier 			return(x);
13793e12c5d1SDavid du Colombier 		tempfree(x);
13803e12c5d1SDavid du Colombier 		x = execute(a[1]);
13813e12c5d1SDavid du Colombier 		if (isbreak(x)) {
13827dd7cddfSDavid du Colombier 			x = True;
13833e12c5d1SDavid du Colombier 			return(x);
13843e12c5d1SDavid du Colombier 		}
13853e12c5d1SDavid du Colombier 		if (isnext(x) || isexit(x) || isret(x))
13863e12c5d1SDavid du Colombier 			return(x);
13873e12c5d1SDavid du Colombier 		tempfree(x);
13883e12c5d1SDavid du Colombier 	}
13893e12c5d1SDavid du Colombier }
13903e12c5d1SDavid du Colombier 
dostat(Node ** a,int n)13913e12c5d1SDavid du Colombier Cell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
13923e12c5d1SDavid du Colombier {
13937dd7cddfSDavid du Colombier 	Cell *x;
13943e12c5d1SDavid du Colombier 
13953e12c5d1SDavid du Colombier 	for (;;) {
13963e12c5d1SDavid du Colombier 		x = execute(a[0]);
13973e12c5d1SDavid du Colombier 		if (isbreak(x))
13987dd7cddfSDavid du Colombier 			return True;
1399*a2c41696SDavid du Colombier 		if (isnext(x) || isexit(x) || isret(x))
14003e12c5d1SDavid du Colombier 			return(x);
14013e12c5d1SDavid du Colombier 		tempfree(x);
14023e12c5d1SDavid du Colombier 		x = execute(a[1]);
14033e12c5d1SDavid du Colombier 		if (!istrue(x))
14043e12c5d1SDavid du Colombier 			return(x);
14053e12c5d1SDavid du Colombier 		tempfree(x);
14063e12c5d1SDavid du Colombier 	}
14073e12c5d1SDavid du Colombier }
14083e12c5d1SDavid du Colombier 
forstat(Node ** a,int n)14093e12c5d1SDavid du Colombier Cell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
14103e12c5d1SDavid du Colombier {
14117dd7cddfSDavid du Colombier 	Cell *x;
14123e12c5d1SDavid du Colombier 
14133e12c5d1SDavid du Colombier 	x = execute(a[0]);
14143e12c5d1SDavid du Colombier 	tempfree(x);
14153e12c5d1SDavid du Colombier 	for (;;) {
14163e12c5d1SDavid du Colombier 		if (a[1]!=0) {
14173e12c5d1SDavid du Colombier 			x = execute(a[1]);
14183e12c5d1SDavid du Colombier 			if (!istrue(x)) return(x);
14193e12c5d1SDavid du Colombier 			else tempfree(x);
14203e12c5d1SDavid du Colombier 		}
14213e12c5d1SDavid du Colombier 		x = execute(a[3]);
14223e12c5d1SDavid du Colombier 		if (isbreak(x))		/* turn off break */
14237dd7cddfSDavid du Colombier 			return True;
14243e12c5d1SDavid du Colombier 		if (isnext(x) || isexit(x) || isret(x))
14253e12c5d1SDavid du Colombier 			return(x);
14263e12c5d1SDavid du Colombier 		tempfree(x);
14273e12c5d1SDavid du Colombier 		x = execute(a[2]);
14283e12c5d1SDavid du Colombier 		tempfree(x);
14293e12c5d1SDavid du Colombier 	}
14303e12c5d1SDavid du Colombier }
14313e12c5d1SDavid du Colombier 
instat(Node ** a,int n)14323e12c5d1SDavid du Colombier Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
14333e12c5d1SDavid du Colombier {
14347dd7cddfSDavid du Colombier 	Cell *x, *vp, *arrayp, *cp, *ncp;
14353e12c5d1SDavid du Colombier 	Array *tp;
14363e12c5d1SDavid du Colombier 	int i;
14373e12c5d1SDavid du Colombier 
14383e12c5d1SDavid du Colombier 	vp = execute(a[0]);
14393e12c5d1SDavid du Colombier 	arrayp = execute(a[1]);
14403e12c5d1SDavid du Colombier 	if (!isarr(arrayp)) {
14417dd7cddfSDavid du Colombier 		return True;
14423e12c5d1SDavid du Colombier 	}
14433e12c5d1SDavid du Colombier 	tp = (Array *) arrayp->sval;
14443e12c5d1SDavid du Colombier 	tempfree(arrayp);
14453e12c5d1SDavid du Colombier 	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
14463e12c5d1SDavid du Colombier 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
14473e12c5d1SDavid du Colombier 			setsval(vp, cp->nval);
14483e12c5d1SDavid du Colombier 			ncp = cp->cnext;
14493e12c5d1SDavid du Colombier 			x = execute(a[2]);
14503e12c5d1SDavid du Colombier 			if (isbreak(x)) {
14513e12c5d1SDavid du Colombier 				tempfree(vp);
14527dd7cddfSDavid du Colombier 				return True;
14533e12c5d1SDavid du Colombier 			}
14543e12c5d1SDavid du Colombier 			if (isnext(x) || isexit(x) || isret(x)) {
14553e12c5d1SDavid du Colombier 				tempfree(vp);
14563e12c5d1SDavid du Colombier 				return(x);
14573e12c5d1SDavid du Colombier 			}
14583e12c5d1SDavid du Colombier 			tempfree(x);
14593e12c5d1SDavid du Colombier 		}
14603e12c5d1SDavid du Colombier 	}
14617dd7cddfSDavid du Colombier 	return True;
14623e12c5d1SDavid du Colombier }
14633e12c5d1SDavid du Colombier 
bltin(Node ** a,int n)1464219b2ee8SDavid du Colombier Cell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
14653e12c5d1SDavid du Colombier {
14667dd7cddfSDavid du Colombier 	Cell *x, *y;
14673e12c5d1SDavid du Colombier 	Awkfloat u;
14687dd7cddfSDavid du Colombier 	int t;
1469*a2c41696SDavid du Colombier 	Awkfloat tmp;
1470219b2ee8SDavid du Colombier 	wchar_t wc;
14717dd7cddfSDavid du Colombier 	char *p, *buf;
14727dd7cddfSDavid du Colombier 	char mbc[50];
14733e12c5d1SDavid du Colombier 	Node *nextarg;
14743e12c5d1SDavid du Colombier 	FILE *fp;
14754eeb7838SDavid du Colombier 	void flush_all(void);
14763e12c5d1SDavid du Colombier 
14777dd7cddfSDavid du Colombier 	t = ptoi(a[0]);
14783e12c5d1SDavid du Colombier 	x = execute(a[1]);
14793e12c5d1SDavid du Colombier 	nextarg = a[1]->nnext;
14803e12c5d1SDavid du Colombier 	switch (t) {
14813e12c5d1SDavid du Colombier 	case FLENGTH:
14824eeb7838SDavid du Colombier 		if (isarr(x))
14834eeb7838SDavid du Colombier 			u = ((Array *) x->sval)->nelem;	/* GROT.  should be function*/
1484*a2c41696SDavid du Colombier 		else
1485*a2c41696SDavid du Colombier 			u = strlen(getsval(x));
14864eeb7838SDavid du Colombier 		break;
14873e12c5d1SDavid du Colombier 	case FLOG:
14883e12c5d1SDavid du Colombier 		u = errcheck(log(getfval(x)), "log"); break;
14893e12c5d1SDavid du Colombier 	case FINT:
14903e12c5d1SDavid du Colombier 		modf(getfval(x), &u); break;
14913e12c5d1SDavid du Colombier 	case FEXP:
14923e12c5d1SDavid du Colombier 		u = errcheck(exp(getfval(x)), "exp"); break;
14933e12c5d1SDavid du Colombier 	case FSQRT:
14943e12c5d1SDavid du Colombier 		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
14953e12c5d1SDavid du Colombier 	case FSIN:
14963e12c5d1SDavid du Colombier 		u = sin(getfval(x)); break;
14973e12c5d1SDavid du Colombier 	case FCOS:
14983e12c5d1SDavid du Colombier 		u = cos(getfval(x)); break;
14993e12c5d1SDavid du Colombier 	case FATAN:
15003e12c5d1SDavid du Colombier 		if (nextarg == 0) {
15017dd7cddfSDavid du Colombier 			WARNING("atan2 requires two arguments; returning 1.0");
15023e12c5d1SDavid du Colombier 			u = 1.0;
15033e12c5d1SDavid du Colombier 		} else {
15043e12c5d1SDavid du Colombier 			y = execute(a[1]->nnext);
15053e12c5d1SDavid du Colombier 			u = atan2(getfval(x), getfval(y));
15063e12c5d1SDavid du Colombier 			tempfree(y);
15073e12c5d1SDavid du Colombier 			nextarg = nextarg->nnext;
15083e12c5d1SDavid du Colombier 		}
15093e12c5d1SDavid du Colombier 		break;
15103e12c5d1SDavid du Colombier 	case FSYSTEM:
15113e12c5d1SDavid du Colombier 		fflush(stdout);		/* in case something is buffered already */
15127dd7cddfSDavid du Colombier 		u = (Awkfloat) system(getsval(x)) / 256;   /* 256 is unix-dep */
15133e12c5d1SDavid du Colombier 		break;
15143e12c5d1SDavid du Colombier 	case FRAND:
15153e12c5d1SDavid du Colombier 		/* in principle, rand() returns something in 0..RAND_MAX */
15163e12c5d1SDavid du Colombier 		u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
15173e12c5d1SDavid du Colombier 		break;
15183e12c5d1SDavid du Colombier 	case FSRAND:
15197dd7cddfSDavid du Colombier 		if (isrec(x))	/* no argument provided */
15207dd7cddfSDavid du Colombier 			u = time((time_t *)0);
15213e12c5d1SDavid du Colombier 		else
15223e12c5d1SDavid du Colombier 			u = getfval(x);
1523*a2c41696SDavid du Colombier 		tmp = u;
15247dd7cddfSDavid du Colombier 		srand((unsigned int) u);
1525*a2c41696SDavid du Colombier 		u = srand_seed;
1526*a2c41696SDavid du Colombier 		srand_seed = tmp;
15273e12c5d1SDavid du Colombier 		break;
15283e12c5d1SDavid du Colombier 	case FTOUPPER:
15293e12c5d1SDavid du Colombier 	case FTOLOWER:
15307dd7cddfSDavid du Colombier 		buf = tostring(getsval(x));
15313e12c5d1SDavid du Colombier 		if (t == FTOUPPER) {
15323e12c5d1SDavid du Colombier 			for (p = buf; *p; p++)
1533*a2c41696SDavid du Colombier 				if (islower((uschar) *p))
1534*a2c41696SDavid du Colombier 					*p = toupper((uschar)*p);
15353e12c5d1SDavid du Colombier 		} else {
15363e12c5d1SDavid du Colombier 			for (p = buf; *p; p++)
1537*a2c41696SDavid du Colombier 				if (isupper((uschar) *p))
1538*a2c41696SDavid du Colombier 					*p = tolower((uschar)*p);
15393e12c5d1SDavid du Colombier 		}
15403e12c5d1SDavid du Colombier 		tempfree(x);
15413e12c5d1SDavid du Colombier 		x = gettemp();
15423e12c5d1SDavid du Colombier 		setsval(x, buf);
15437dd7cddfSDavid du Colombier 		free(buf);
15443e12c5d1SDavid du Colombier 		return x;
15453e12c5d1SDavid du Colombier 	case FFLUSH:
15464eeb7838SDavid du Colombier 		if (isrec(x) || strlen(getsval(x)) == 0) {
15474eeb7838SDavid du Colombier 			flush_all();	/* fflush() or fflush("") -> all */
15484eeb7838SDavid du Colombier 			u = 0;
15494eeb7838SDavid du Colombier 		} else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
15503e12c5d1SDavid du Colombier 			u = EOF;
15513e12c5d1SDavid du Colombier 		else
15523e12c5d1SDavid du Colombier 			u = fflush(fp);
15533e12c5d1SDavid du Colombier 		break;
1554219b2ee8SDavid du Colombier 	case FUTF:
1555219b2ee8SDavid du Colombier 		wc = (int)getfval(x);
1556219b2ee8SDavid du Colombier 		mbc[wctomb(mbc, wc)] = 0;
1557219b2ee8SDavid du Colombier 		tempfree(x);
1558219b2ee8SDavid du Colombier 		x = gettemp();
1559219b2ee8SDavid du Colombier 		setsval(x, mbc);
1560219b2ee8SDavid du Colombier 		return x;
15613e12c5d1SDavid du Colombier 	default:	/* can't happen */
15627dd7cddfSDavid du Colombier 		FATAL("illegal function type %d", t);
15633e12c5d1SDavid du Colombier 		break;
15643e12c5d1SDavid du Colombier 	}
15653e12c5d1SDavid du Colombier 	tempfree(x);
15663e12c5d1SDavid du Colombier 	x = gettemp();
15673e12c5d1SDavid du Colombier 	setfval(x, u);
15683e12c5d1SDavid du Colombier 	if (nextarg != 0) {
15697dd7cddfSDavid du Colombier 		WARNING("warning: function has too many arguments");
15703e12c5d1SDavid du Colombier 		for ( ; nextarg; nextarg = nextarg->nnext)
15713e12c5d1SDavid du Colombier 			execute(nextarg);
15723e12c5d1SDavid du Colombier 	}
15733e12c5d1SDavid du Colombier 	return(x);
15743e12c5d1SDavid du Colombier }
15753e12c5d1SDavid du Colombier 
printstat(Node ** a,int n)1576219b2ee8SDavid du Colombier Cell *printstat(Node **a, int n)	/* print a[0] */
15773e12c5d1SDavid du Colombier {
157805bfb676SDavid du Colombier 	int r;
15797dd7cddfSDavid du Colombier 	Node *x;
15807dd7cddfSDavid du Colombier 	Cell *y;
15813e12c5d1SDavid du Colombier 	FILE *fp;
15823e12c5d1SDavid du Colombier 
1583219b2ee8SDavid du Colombier 	if (a[1] == 0)	/* a[1] is redirection operator, a[2] is file */
15843e12c5d1SDavid du Colombier 		fp = stdout;
15853e12c5d1SDavid du Colombier 	else
15867dd7cddfSDavid du Colombier 		fp = redirect(ptoi(a[1]), a[2]);
15873e12c5d1SDavid du Colombier 	for (x = a[0]; x != NULL; x = x->nnext) {
15883e12c5d1SDavid du Colombier 		y = execute(x);
15897dd7cddfSDavid du Colombier 		fputs(getsval(y), fp);
15903e12c5d1SDavid du Colombier 		tempfree(y);
15913e12c5d1SDavid du Colombier 		if (x->nnext == NULL)
159205bfb676SDavid du Colombier 			r = fputs(*ORS, fp);
15933e12c5d1SDavid du Colombier 		else
159405bfb676SDavid du Colombier 			r = fputs(*OFS, fp);
159505bfb676SDavid du Colombier 		if (r == EOF)
159605bfb676SDavid du Colombier 			FATAL("write error on %s", filename(fp));
15973e12c5d1SDavid du Colombier 	}
15983e12c5d1SDavid du Colombier 	if (a[1] != 0)
159905bfb676SDavid du Colombier 		if (fflush(fp) == EOF)
16007dd7cddfSDavid du Colombier 			FATAL("write error on %s", filename(fp));
16017dd7cddfSDavid du Colombier 	return(True);
16023e12c5d1SDavid du Colombier }
16033e12c5d1SDavid du Colombier 
nullproc(Node ** a,int n)16043e12c5d1SDavid du Colombier Cell *nullproc(Node **a, int n)
16053e12c5d1SDavid du Colombier {
16067dd7cddfSDavid du Colombier 	n = n;
16077dd7cddfSDavid du Colombier 	a = a;
16083e12c5d1SDavid du Colombier 	return 0;
16093e12c5d1SDavid du Colombier }
16103e12c5d1SDavid du Colombier 
16113e12c5d1SDavid du Colombier 
redirect(int a,Node * b)1612219b2ee8SDavid du Colombier FILE *redirect(int a, Node *b)	/* set up all i/o redirections */
16133e12c5d1SDavid du Colombier {
16143e12c5d1SDavid du Colombier 	FILE *fp;
16153e12c5d1SDavid du Colombier 	Cell *x;
16167dd7cddfSDavid du Colombier 	char *fname;
16173e12c5d1SDavid du Colombier 
16183e12c5d1SDavid du Colombier 	x = execute(b);
16193e12c5d1SDavid du Colombier 	fname = getsval(x);
16203e12c5d1SDavid du Colombier 	fp = openfile(a, fname);
16213e12c5d1SDavid du Colombier 	if (fp == NULL)
16227dd7cddfSDavid du Colombier 		FATAL("can't open file %s", fname);
16233e12c5d1SDavid du Colombier 	tempfree(x);
16243e12c5d1SDavid du Colombier 	return fp;
16253e12c5d1SDavid du Colombier }
16263e12c5d1SDavid du Colombier 
1627219b2ee8SDavid du Colombier struct files {
1628219b2ee8SDavid du Colombier 	FILE	*fp;
1629*a2c41696SDavid du Colombier 	const char	*fname;
1630219b2ee8SDavid du Colombier 	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
1631*a2c41696SDavid du Colombier } *files;
1632*a2c41696SDavid du Colombier 
1633*a2c41696SDavid du Colombier int nfiles;
1634219b2ee8SDavid du Colombier 
stdinit(void)16357dd7cddfSDavid du Colombier void stdinit(void)	/* in case stdin, etc., are not constants */
16363e12c5d1SDavid du Colombier {
1637*a2c41696SDavid du Colombier 	nfiles = FOPEN_MAX;
1638*a2c41696SDavid du Colombier 	files = calloc(nfiles, sizeof(*files));
1639*a2c41696SDavid du Colombier 	if (files == NULL)
1640*a2c41696SDavid du Colombier 		FATAL("can't allocate file memory for %u files", nfiles);
16417dd7cddfSDavid du Colombier         files[0].fp = stdin;
1642*a2c41696SDavid du Colombier 	files[0].fname = "/dev/stdin";
1643*a2c41696SDavid du Colombier 	files[0].mode = LT;
16447dd7cddfSDavid du Colombier         files[1].fp = stdout;
1645*a2c41696SDavid du Colombier 	files[1].fname = "/dev/stdout";
1646*a2c41696SDavid du Colombier 	files[1].mode = GT;
16477dd7cddfSDavid du Colombier         files[2].fp = stderr;
1648*a2c41696SDavid du Colombier 	files[2].fname = "/dev/stderr";
1649*a2c41696SDavid du Colombier 	files[2].mode = GT;
16507dd7cddfSDavid du Colombier }
16517dd7cddfSDavid du Colombier 
openfile(int a,const char * us)1652*a2c41696SDavid du Colombier FILE *openfile(int a, const char *us)
16537dd7cddfSDavid du Colombier {
1654*a2c41696SDavid du Colombier 	const char *s = us;
16557dd7cddfSDavid du Colombier 	int i, m;
16567dd7cddfSDavid du Colombier 	FILE *fp = 0;
16573e12c5d1SDavid du Colombier 
16583e12c5d1SDavid du Colombier 	if (*s == '\0')
16597dd7cddfSDavid du Colombier 		FATAL("null file name in print or getline");
1660*a2c41696SDavid du Colombier 	for (i=0; i < nfiles; i++)
16617dd7cddfSDavid du Colombier 		if (files[i].fname && strcmp(s, files[i].fname) == 0) {
16627dd7cddfSDavid du Colombier 			if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
16633e12c5d1SDavid du Colombier 				return files[i].fp;
16647dd7cddfSDavid du Colombier 			if (a == FFLUSH)
16657dd7cddfSDavid du Colombier 				return files[i].fp;
16667dd7cddfSDavid du Colombier 		}
16677dd7cddfSDavid du Colombier 	if (a == FFLUSH)	/* didn't find it, so don't create it! */
16687dd7cddfSDavid du Colombier 		return NULL;
16697dd7cddfSDavid du Colombier 
1670*a2c41696SDavid du Colombier 	for (i=0; i < nfiles; i++)
16713e12c5d1SDavid du Colombier 		if (files[i].fp == 0)
16723e12c5d1SDavid du Colombier 			break;
1673*a2c41696SDavid du Colombier 	if (i >= nfiles) {
1674*a2c41696SDavid du Colombier 		struct files *nf;
1675*a2c41696SDavid du Colombier 		int nnf = nfiles + FOPEN_MAX;
1676*a2c41696SDavid du Colombier 		nf = realloc(files, nnf * sizeof(*nf));
1677*a2c41696SDavid du Colombier 		if (nf == NULL)
1678*a2c41696SDavid du Colombier 			FATAL("cannot grow files for %s and %d files", s, nnf);
1679*a2c41696SDavid du Colombier 		memset(&nf[nfiles], 0, FOPEN_MAX * sizeof(*nf));
1680*a2c41696SDavid du Colombier 		nfiles = nnf;
1681*a2c41696SDavid du Colombier 		files = nf;
1682*a2c41696SDavid du Colombier 	}
16833e12c5d1SDavid du Colombier 	fflush(stdout);	/* force a semblance of order */
16843e12c5d1SDavid du Colombier 	m = a;
16853e12c5d1SDavid du Colombier 	if (a == GT) {
1686219b2ee8SDavid du Colombier 		fp = fopen(s, "w");
16873e12c5d1SDavid du Colombier 	} else if (a == APPEND) {
1688219b2ee8SDavid du Colombier 		fp = fopen(s, "a");
16893e12c5d1SDavid du Colombier 		m = GT;	/* so can mix > and >> */
16903e12c5d1SDavid du Colombier 	} else if (a == '|') {	/* output pipe */
1691219b2ee8SDavid du Colombier 		fp = popen(s, "w");
16923e12c5d1SDavid du Colombier 	} else if (a == LE) {	/* input pipe */
1693219b2ee8SDavid du Colombier 		fp = popen(s, "r");
16943e12c5d1SDavid du Colombier 	} else if (a == LT) {	/* getline <file */
1695219b2ee8SDavid du Colombier 		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
16963e12c5d1SDavid du Colombier 	} else	/* can't happen */
16977dd7cddfSDavid du Colombier 		FATAL("illegal redirection %d", a);
16983e12c5d1SDavid du Colombier 	if (fp != NULL) {
16993e12c5d1SDavid du Colombier 		files[i].fname = tostring(s);
17003e12c5d1SDavid du Colombier 		files[i].fp = fp;
17013e12c5d1SDavid du Colombier 		files[i].mode = m;
17023e12c5d1SDavid du Colombier 	}
17033e12c5d1SDavid du Colombier 	return fp;
17043e12c5d1SDavid du Colombier }
17053e12c5d1SDavid du Colombier 
filename(FILE * fp)1706*a2c41696SDavid du Colombier const char *filename(FILE *fp)
17073e12c5d1SDavid du Colombier {
17083e12c5d1SDavid du Colombier 	int i;
17093e12c5d1SDavid du Colombier 
1710*a2c41696SDavid du Colombier 	for (i = 0; i < nfiles; i++)
17113e12c5d1SDavid du Colombier 		if (fp == files[i].fp)
17123e12c5d1SDavid du Colombier 			return files[i].fname;
1713219b2ee8SDavid du Colombier 	return "???";
17143e12c5d1SDavid du Colombier }
17153e12c5d1SDavid du Colombier 
closefile(Node ** a,int n)17163e12c5d1SDavid du Colombier Cell *closefile(Node **a, int n)
17173e12c5d1SDavid du Colombier {
17187dd7cddfSDavid du Colombier 	Cell *x;
17193e12c5d1SDavid du Colombier 	int i, stat;
17203e12c5d1SDavid du Colombier 
17217dd7cddfSDavid du Colombier 	n = n;
17223e12c5d1SDavid du Colombier 	x = execute(a[0]);
17233e12c5d1SDavid du Colombier 	getsval(x);
1724*a2c41696SDavid du Colombier 	stat = -1;
1725*a2c41696SDavid du Colombier 	for (i = 0; i < nfiles; i++) {
17263e12c5d1SDavid du Colombier 		if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
17273e12c5d1SDavid du Colombier 			if (ferror(files[i].fp))
17287dd7cddfSDavid du Colombier 				WARNING( "i/o error occurred on %s", files[i].fname );
17293e12c5d1SDavid du Colombier 			if (files[i].mode == '|' || files[i].mode == LE)
17303e12c5d1SDavid du Colombier 				stat = pclose(files[i].fp);
17313e12c5d1SDavid du Colombier 			else
17323e12c5d1SDavid du Colombier 				stat = fclose(files[i].fp);
17333e12c5d1SDavid du Colombier 			if (stat == EOF)
17347dd7cddfSDavid du Colombier 				WARNING( "i/o error occurred closing %s", files[i].fname );
1735219b2ee8SDavid du Colombier 			if (i > 2)	/* don't do /dev/std... */
17363e12c5d1SDavid du Colombier 				xfree(files[i].fname);
17373e12c5d1SDavid du Colombier 			files[i].fname = NULL;	/* watch out for ref thru this */
17383e12c5d1SDavid du Colombier 			files[i].fp = NULL;
17393e12c5d1SDavid du Colombier 		}
1740*a2c41696SDavid du Colombier 	}
17413e12c5d1SDavid du Colombier 	tempfree(x);
1742*a2c41696SDavid du Colombier 	x = gettemp();
1743*a2c41696SDavid du Colombier 	setfval(x, (Awkfloat) stat);
1744*a2c41696SDavid du Colombier 	return(x);
17453e12c5d1SDavid du Colombier }
17463e12c5d1SDavid du Colombier 
closeall(void)17473e12c5d1SDavid du Colombier void closeall(void)
17483e12c5d1SDavid du Colombier {
17493e12c5d1SDavid du Colombier 	int i, stat;
17503e12c5d1SDavid du Colombier 
1751*a2c41696SDavid du Colombier 	for (i = 0; i < FOPEN_MAX; i++) {
17523e12c5d1SDavid du Colombier 		if (files[i].fp) {
17533e12c5d1SDavid du Colombier 			if (ferror(files[i].fp))
17547dd7cddfSDavid du Colombier 				WARNING( "i/o error occurred on %s", files[i].fname );
17553e12c5d1SDavid du Colombier 			if (files[i].mode == '|' || files[i].mode == LE)
17563e12c5d1SDavid du Colombier 				stat = pclose(files[i].fp);
17573e12c5d1SDavid du Colombier 			else
17583e12c5d1SDavid du Colombier 				stat = fclose(files[i].fp);
17593e12c5d1SDavid du Colombier 			if (stat == EOF)
17607dd7cddfSDavid du Colombier 				WARNING( "i/o error occurred while closing %s", files[i].fname );
17613e12c5d1SDavid du Colombier 		}
17623e12c5d1SDavid du Colombier 	}
1763*a2c41696SDavid du Colombier }
17643e12c5d1SDavid du Colombier 
flush_all(void)17654eeb7838SDavid du Colombier void flush_all(void)
17664eeb7838SDavid du Colombier {
17674eeb7838SDavid du Colombier 	int i;
17684eeb7838SDavid du Colombier 
1769*a2c41696SDavid du Colombier 	for (i = 0; i < nfiles; i++)
17704eeb7838SDavid du Colombier 		if (files[i].fp)
17714eeb7838SDavid du Colombier 			fflush(files[i].fp);
17724eeb7838SDavid du Colombier }
17734eeb7838SDavid du Colombier 
17747dd7cddfSDavid du Colombier void backsub(char **pb_ptr, char **sptr_ptr);
17753e12c5d1SDavid du Colombier 
sub(Node ** a,int nnn)1776219b2ee8SDavid du Colombier Cell *sub(Node **a, int nnn)	/* substitute command */
17773e12c5d1SDavid du Colombier {
17787dd7cddfSDavid du Colombier 	char *sptr, *pb, *q;
17797dd7cddfSDavid du Colombier 	Cell *x, *y, *result;
17807dd7cddfSDavid du Colombier 	char *t, *buf;
17813e12c5d1SDavid du Colombier 	void *p;
17827dd7cddfSDavid du Colombier 	int bufsz = recsize;
17833e12c5d1SDavid du Colombier 
17847dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL)
17857dd7cddfSDavid du Colombier 		FATAL("out of memory in sub");
17863e12c5d1SDavid du Colombier 	x = execute(a[3]);	/* target string */
17873e12c5d1SDavid du Colombier 	t = getsval(x);
1788219b2ee8SDavid du Colombier 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
17893e12c5d1SDavid du Colombier 		p = (void *) a[1];	/* regular expression */
17903e12c5d1SDavid du Colombier 	else {
17913e12c5d1SDavid du Colombier 		y = execute(a[1]);
17923e12c5d1SDavid du Colombier 		p = compre(getsval(y));
17933e12c5d1SDavid du Colombier 		tempfree(y);
17943e12c5d1SDavid du Colombier 	}
17953e12c5d1SDavid du Colombier 	y = execute(a[2]);	/* replacement string */
17967dd7cddfSDavid du Colombier 	result = False;
17973e12c5d1SDavid du Colombier 	if (pmatch(p, t, t)) {
17983e12c5d1SDavid du Colombier 		sptr = t;
17997dd7cddfSDavid du Colombier 		adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
18007dd7cddfSDavid du Colombier 		pb = buf;
18013e12c5d1SDavid du Colombier 		while (sptr < patbeg)
18023e12c5d1SDavid du Colombier 			*pb++ = *sptr++;
18033e12c5d1SDavid du Colombier 		sptr = getsval(y);
18047dd7cddfSDavid du Colombier 		while (*sptr != 0) {
18057dd7cddfSDavid du Colombier 			adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
18067dd7cddfSDavid du Colombier 			if (*sptr == '\\') {
18077dd7cddfSDavid du Colombier 				backsub(&pb, &sptr);
18083e12c5d1SDavid du Colombier 			} else if (*sptr == '&') {
18093e12c5d1SDavid du Colombier 				sptr++;
18107dd7cddfSDavid du Colombier 				adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
18113e12c5d1SDavid du Colombier 				for (q = patbeg; q < patbeg+patlen; )
18123e12c5d1SDavid du Colombier 					*pb++ = *q++;
18133e12c5d1SDavid du Colombier 			} else
18143e12c5d1SDavid du Colombier 				*pb++ = *sptr++;
18157dd7cddfSDavid du Colombier 		}
18163e12c5d1SDavid du Colombier 		*pb = '\0';
18177dd7cddfSDavid du Colombier 		if (pb > buf + bufsz)
18187dd7cddfSDavid du Colombier 			FATAL("sub result1 %.30s too big; can't happen", buf);
18193e12c5d1SDavid du Colombier 		sptr = patbeg + patlen;
18207dd7cddfSDavid du Colombier 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
18217dd7cddfSDavid du Colombier 			adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
18227dd7cddfSDavid du Colombier 			while ((*pb++ = *sptr++) != 0)
18233e12c5d1SDavid du Colombier 				;
18247dd7cddfSDavid du Colombier 		}
18257dd7cddfSDavid du Colombier 		if (pb > buf + bufsz)
18267dd7cddfSDavid du Colombier 			FATAL("sub result2 %.30s too big; can't happen", buf);
18277dd7cddfSDavid du Colombier 		setsval(x, buf);	/* BUG: should be able to avoid copy */
18287dd7cddfSDavid du Colombier 		result = True;;
18293e12c5d1SDavid du Colombier 	}
18303e12c5d1SDavid du Colombier 	tempfree(x);
18313e12c5d1SDavid du Colombier 	tempfree(y);
18327dd7cddfSDavid du Colombier 	free(buf);
18333e12c5d1SDavid du Colombier 	return result;
18343e12c5d1SDavid du Colombier }
18353e12c5d1SDavid du Colombier 
gsub(Node ** a,int nnn)1836219b2ee8SDavid du Colombier Cell *gsub(Node **a, int nnn)	/* global substitute */
18373e12c5d1SDavid du Colombier {
18387dd7cddfSDavid du Colombier 	Cell *x, *y;
18397dd7cddfSDavid du Colombier 	char *rptr, *sptr, *t, *pb, *c;
18407dd7cddfSDavid du Colombier 	char *buf;
18417dd7cddfSDavid du Colombier 	void *p;
18423e12c5d1SDavid du Colombier 	int mflag, num;
18437dd7cddfSDavid du Colombier 	int bufsz = recsize;
18443e12c5d1SDavid du Colombier 
18457dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL)
18467dd7cddfSDavid du Colombier 		FATAL("out of memory in gsub");
18473e12c5d1SDavid du Colombier 	mflag = 0;	/* if mflag == 0, can replace empty string */
18483e12c5d1SDavid du Colombier 	num = 0;
18493e12c5d1SDavid du Colombier 	x = execute(a[3]);	/* target string */
18503e12c5d1SDavid du Colombier 	c = t = getsval(x);
1851219b2ee8SDavid du Colombier 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
18523e12c5d1SDavid du Colombier 		p = (void *) a[1];	/* regular expression */
18533e12c5d1SDavid du Colombier 	else {
18543e12c5d1SDavid du Colombier 		y = execute(a[1]);
18553e12c5d1SDavid du Colombier 		p = compre(getsval(y));
18563e12c5d1SDavid du Colombier 		tempfree(y);
18573e12c5d1SDavid du Colombier 	}
18583e12c5d1SDavid du Colombier 	y = execute(a[2]);	/* replacement string */
18593e12c5d1SDavid du Colombier 	if (pmatch(p, t, c)) {
18603e12c5d1SDavid du Colombier 		pb = buf;
18613e12c5d1SDavid du Colombier 		rptr = getsval(y);
18623e12c5d1SDavid du Colombier 		do {
18633e12c5d1SDavid du Colombier 			if (patlen == 0 && *patbeg != 0) {	/* matched empty string */
18643e12c5d1SDavid du Colombier 				if (mflag == 0) {	/* can replace empty */
18653e12c5d1SDavid du Colombier 					num++;
18663e12c5d1SDavid du Colombier 					sptr = rptr;
18677dd7cddfSDavid du Colombier 					while (*sptr != 0) {
18687dd7cddfSDavid du Colombier 						adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
18697dd7cddfSDavid du Colombier 						if (*sptr == '\\') {
18707dd7cddfSDavid du Colombier 							backsub(&pb, &sptr);
18713e12c5d1SDavid du Colombier 						} else if (*sptr == '&') {
18727dd7cddfSDavid du Colombier 							char *q;
18733e12c5d1SDavid du Colombier 							sptr++;
18747dd7cddfSDavid du Colombier 							adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
18753e12c5d1SDavid du Colombier 							for (q = patbeg; q < patbeg+patlen; )
18763e12c5d1SDavid du Colombier 								*pb++ = *q++;
18773e12c5d1SDavid du Colombier 						} else
18783e12c5d1SDavid du Colombier 							*pb++ = *sptr++;
18793e12c5d1SDavid du Colombier 					}
18807dd7cddfSDavid du Colombier 				}
18813e12c5d1SDavid du Colombier 				if (*c == 0)	/* at end */
18823e12c5d1SDavid du Colombier 					goto done;
18837dd7cddfSDavid du Colombier 				adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
18843e12c5d1SDavid du Colombier 				*pb++ = *c++;
18857dd7cddfSDavid du Colombier 				if (pb > buf + bufsz)	/* BUG: not sure of this test */
18867dd7cddfSDavid du Colombier 					FATAL("gsub result0 %.30s too big; can't happen", buf);
18873e12c5d1SDavid du Colombier 				mflag = 0;
18883e12c5d1SDavid du Colombier 			}
18893e12c5d1SDavid du Colombier 			else {	/* matched nonempty string */
18903e12c5d1SDavid du Colombier 				num++;
18913e12c5d1SDavid du Colombier 				sptr = c;
18927dd7cddfSDavid du Colombier 				adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
18937dd7cddfSDavid du Colombier 				while (sptr < patbeg)
18943e12c5d1SDavid du Colombier 					*pb++ = *sptr++;
18953e12c5d1SDavid du Colombier 				sptr = rptr;
18967dd7cddfSDavid du Colombier 				while (*sptr != 0) {
18977dd7cddfSDavid du Colombier 					adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
18987dd7cddfSDavid du Colombier 					if (*sptr == '\\') {
18997dd7cddfSDavid du Colombier 						backsub(&pb, &sptr);
19003e12c5d1SDavid du Colombier 					} else if (*sptr == '&') {
19017dd7cddfSDavid du Colombier 						char *q;
19023e12c5d1SDavid du Colombier 						sptr++;
19037dd7cddfSDavid du Colombier 						adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
19043e12c5d1SDavid du Colombier 						for (q = patbeg; q < patbeg+patlen; )
19053e12c5d1SDavid du Colombier 							*pb++ = *q++;
19063e12c5d1SDavid du Colombier 					} else
19073e12c5d1SDavid du Colombier 						*pb++ = *sptr++;
19087dd7cddfSDavid du Colombier 				}
19093e12c5d1SDavid du Colombier 				c = patbeg + patlen;
19103e12c5d1SDavid du Colombier 				if ((c[-1] == 0) || (*c == 0))
19113e12c5d1SDavid du Colombier 					goto done;
19127dd7cddfSDavid du Colombier 				if (pb > buf + bufsz)
19137dd7cddfSDavid du Colombier 					FATAL("gsub result1 %.30s too big; can't happen", buf);
19143e12c5d1SDavid du Colombier 				mflag = 1;
19153e12c5d1SDavid du Colombier 			}
19163e12c5d1SDavid du Colombier 		} while (pmatch(p, t, c));
19173e12c5d1SDavid du Colombier 		sptr = c;
19187dd7cddfSDavid du Colombier 		adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
19197dd7cddfSDavid du Colombier 		while ((*pb++ = *sptr++) != 0)
19203e12c5d1SDavid du Colombier 			;
1921*a2c41696SDavid du Colombier 	done:	if (pb < buf + bufsz)
19223e12c5d1SDavid du Colombier 			*pb = '\0';
1923*a2c41696SDavid du Colombier 		else if (*(pb-1) != '\0')
1924*a2c41696SDavid du Colombier 			FATAL("gsub result2 %.30s truncated; can't happen", buf);
19257dd7cddfSDavid du Colombier 		setsval(x, buf);	/* BUG: should be able to avoid copy + free */
19263e12c5d1SDavid du Colombier 	}
19273e12c5d1SDavid du Colombier 	tempfree(x);
19283e12c5d1SDavid du Colombier 	tempfree(y);
19293e12c5d1SDavid du Colombier 	x = gettemp();
19303e12c5d1SDavid du Colombier 	x->tval = NUM;
19313e12c5d1SDavid du Colombier 	x->fval = num;
19327dd7cddfSDavid du Colombier 	free(buf);
19333e12c5d1SDavid du Colombier 	return(x);
19343e12c5d1SDavid du Colombier }
19357dd7cddfSDavid du Colombier 
backsub(char ** pb_ptr,char ** sptr_ptr)19367dd7cddfSDavid du Colombier void backsub(char **pb_ptr, char **sptr_ptr)	/* handle \\& variations */
19377dd7cddfSDavid du Colombier {						/* sptr[0] == '\\' */
19387dd7cddfSDavid du Colombier 	char *pb = *pb_ptr, *sptr = *sptr_ptr;
19397dd7cddfSDavid du Colombier 
19407dd7cddfSDavid du Colombier 	if (sptr[1] == '\\') {
19417dd7cddfSDavid du Colombier 		if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
19427dd7cddfSDavid du Colombier 			*pb++ = '\\';
19437dd7cddfSDavid du Colombier 			*pb++ = '&';
19447dd7cddfSDavid du Colombier 			sptr += 4;
19457dd7cddfSDavid du Colombier 		} else if (sptr[2] == '&') {	/* \\& -> \ + matched */
19467dd7cddfSDavid du Colombier 			*pb++ = '\\';
19477dd7cddfSDavid du Colombier 			sptr += 2;
19487dd7cddfSDavid du Colombier 		} else {			/* \\x -> \\x */
19497dd7cddfSDavid du Colombier 			*pb++ = *sptr++;
19507dd7cddfSDavid du Colombier 			*pb++ = *sptr++;
19517dd7cddfSDavid du Colombier 		}
19527dd7cddfSDavid du Colombier 	} else if (sptr[1] == '&') {	/* literal & */
19537dd7cddfSDavid du Colombier 		sptr++;
19547dd7cddfSDavid du Colombier 		*pb++ = *sptr++;
19557dd7cddfSDavid du Colombier 	} else				/* literal \ */
19567dd7cddfSDavid du Colombier 		*pb++ = *sptr++;
19577dd7cddfSDavid du Colombier 
19587dd7cddfSDavid du Colombier 	*pb_ptr = pb;
19597dd7cddfSDavid du Colombier 	*sptr_ptr = sptr;
19607dd7cddfSDavid du Colombier }
1961