xref: /plan9/sys/src/cmd/awk/run.c (revision 05bfb676bfe3b84c9fb5fa2c9ef6d09a93084a7b)
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>
293e12c5d1SDavid du Colombier #include <math.h>
303e12c5d1SDavid du Colombier #include <string.h>
313e12c5d1SDavid du Colombier #include <stdlib.h>
323e12c5d1SDavid du Colombier #include <time.h>
333e12c5d1SDavid du Colombier #include "awk.h"
343e12c5d1SDavid du Colombier #include "y.tab.h"
353e12c5d1SDavid du Colombier 
367dd7cddfSDavid du Colombier #define tempfree(x)	if (istemp(x)) tfree(x); else
377dd7cddfSDavid du Colombier 
387dd7cddfSDavid du Colombier /*
397dd7cddfSDavid du Colombier #undef tempfree
407dd7cddfSDavid du Colombier 
417dd7cddfSDavid du Colombier void tempfree(Cell *p) {
427dd7cddfSDavid du Colombier 	if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
437dd7cddfSDavid du Colombier 		WARNING("bad csub %d in Cell %d %s",
447dd7cddfSDavid du Colombier 			p->csub, p->ctype, p->sval);
457dd7cddfSDavid du Colombier 	}
467dd7cddfSDavid du Colombier 	if (istemp(p))
477dd7cddfSDavid du Colombier 		tfree(p);
487dd7cddfSDavid du Colombier }
497dd7cddfSDavid du Colombier */
507dd7cddfSDavid du Colombier 
513e12c5d1SDavid du Colombier #ifdef _NFILE
523e12c5d1SDavid du Colombier #ifndef FOPEN_MAX
533e12c5d1SDavid du Colombier #define FOPEN_MAX _NFILE
543e12c5d1SDavid du Colombier #endif
553e12c5d1SDavid du Colombier #endif
563e12c5d1SDavid du Colombier 
573e12c5d1SDavid du Colombier #ifndef	FOPEN_MAX
583e12c5d1SDavid du Colombier #define	FOPEN_MAX	40	/* max number of open files */
593e12c5d1SDavid du Colombier #endif
603e12c5d1SDavid du Colombier 
613e12c5d1SDavid du Colombier #ifndef RAND_MAX
623e12c5d1SDavid du Colombier #define RAND_MAX	32767	/* all that ansi guarantees */
633e12c5d1SDavid du Colombier #endif
643e12c5d1SDavid du Colombier 
653e12c5d1SDavid du Colombier jmp_buf env;
667dd7cddfSDavid du Colombier extern	int	pairstack[];
67219b2ee8SDavid du Colombier 
68219b2ee8SDavid du Colombier Node	*winner = NULL;	/* root of parse tree */
69219b2ee8SDavid du Colombier Cell	*tmps;		/* free temporary cells for execution */
703e12c5d1SDavid du Colombier 
713e12c5d1SDavid du Colombier static Cell	truecell	={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
727dd7cddfSDavid du Colombier Cell	*True	= &truecell;
733e12c5d1SDavid du Colombier static Cell	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
747dd7cddfSDavid du Colombier Cell	*False	= &falsecell;
753e12c5d1SDavid du Colombier static Cell	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
763e12c5d1SDavid du Colombier Cell	*jbreak	= &breakcell;
773e12c5d1SDavid du Colombier static Cell	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM };
783e12c5d1SDavid du Colombier Cell	*jcont	= &contcell;
793e12c5d1SDavid du Colombier static Cell	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
803e12c5d1SDavid du Colombier Cell	*jnext	= &nextcell;
817dd7cddfSDavid du Colombier static Cell	nextfilecell	={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
827dd7cddfSDavid du Colombier Cell	*jnextfile	= &nextfilecell;
833e12c5d1SDavid du Colombier static Cell	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
843e12c5d1SDavid du Colombier Cell	*jexit	= &exitcell;
853e12c5d1SDavid du Colombier static Cell	retcell		={ OJUMP, JRET, 0, 0, 0.0, NUM };
863e12c5d1SDavid du Colombier Cell	*jret	= &retcell;
877dd7cddfSDavid du Colombier static Cell	tempcell	={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
883e12c5d1SDavid du Colombier 
893e12c5d1SDavid du Colombier Node	*curnode = NULL;	/* the node being executed, for debugging */
903e12c5d1SDavid du Colombier 
917dd7cddfSDavid du Colombier /* buffer memory management */
927dd7cddfSDavid du Colombier int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
937dd7cddfSDavid du Colombier 	char *whatrtn)
947dd7cddfSDavid du Colombier /* pbuf:    address of pointer to buffer being managed
957dd7cddfSDavid du Colombier  * psiz:    address of buffer size variable
967dd7cddfSDavid du Colombier  * minlen:  minimum length of buffer needed
977dd7cddfSDavid du Colombier  * quantum: buffer size quantum
987dd7cddfSDavid du Colombier  * pbptr:   address of movable pointer into buffer, or 0 if none
997dd7cddfSDavid du Colombier  * whatrtn: name of the calling routine if failure should cause fatal error
1007dd7cddfSDavid du Colombier  *
1017dd7cddfSDavid du Colombier  * return   0 for realloc failure, !=0 for success
1027dd7cddfSDavid du Colombier  */
1037dd7cddfSDavid du Colombier {
1047dd7cddfSDavid du Colombier 	if (minlen > *psiz) {
1057dd7cddfSDavid du Colombier 		char *tbuf;
1067dd7cddfSDavid du Colombier 		int rminlen = quantum ? minlen % quantum : 0;
1077dd7cddfSDavid du Colombier 		int boff = pbptr ? *pbptr - *pbuf : 0;
1087dd7cddfSDavid du Colombier 		/* round up to next multiple of quantum */
1097dd7cddfSDavid du Colombier 		if (rminlen)
1107dd7cddfSDavid du Colombier 			minlen += quantum - rminlen;
1117dd7cddfSDavid du Colombier 		tbuf = (char *) realloc(*pbuf, minlen);
1127dd7cddfSDavid du Colombier 		if (tbuf == NULL) {
1137dd7cddfSDavid du Colombier 			if (whatrtn)
1147dd7cddfSDavid du Colombier 				FATAL("out of memory in %s", whatrtn);
1157dd7cddfSDavid du Colombier 			return 0;
1167dd7cddfSDavid du Colombier 		}
1177dd7cddfSDavid du Colombier 		*pbuf = tbuf;
1187dd7cddfSDavid du Colombier 		*psiz = minlen;
1197dd7cddfSDavid du Colombier 		if (pbptr)
1207dd7cddfSDavid du Colombier 			*pbptr = tbuf + boff;
1217dd7cddfSDavid du Colombier 	}
1227dd7cddfSDavid du Colombier 	return 1;
1237dd7cddfSDavid du Colombier }
1247dd7cddfSDavid du Colombier 
125219b2ee8SDavid du Colombier void run(Node *a)	/* execution of parse tree starts here */
1263e12c5d1SDavid du Colombier {
1277dd7cddfSDavid du Colombier 	extern void stdinit(void);
1287dd7cddfSDavid du Colombier 
1297dd7cddfSDavid du Colombier 	stdinit();
1303e12c5d1SDavid du Colombier 	execute(a);
1313e12c5d1SDavid du Colombier 	closeall();
1323e12c5d1SDavid du Colombier }
1333e12c5d1SDavid du Colombier 
1347dd7cddfSDavid du Colombier Cell *execute(Node *u)	/* execute a node of the parse tree */
1353e12c5d1SDavid du Colombier {
136*05bfb676SDavid du Colombier 	int nobj;
1377dd7cddfSDavid du Colombier 	Cell *(*proc)(Node **, int);
1387dd7cddfSDavid du Colombier 	Cell *x;
1397dd7cddfSDavid du Colombier 	Node *a;
1403e12c5d1SDavid du Colombier 
1413e12c5d1SDavid du Colombier 	if (u == NULL)
1427dd7cddfSDavid du Colombier 		return(True);
1433e12c5d1SDavid du Colombier 	for (a = u; ; a = a->nnext) {
1443e12c5d1SDavid du Colombier 		curnode = a;
1453e12c5d1SDavid du Colombier 		if (isvalue(a)) {
1463e12c5d1SDavid du Colombier 			x = (Cell *) (a->narg[0]);
1477dd7cddfSDavid du Colombier 			if (isfld(x) && !donefld)
1483e12c5d1SDavid du Colombier 				fldbld();
1497dd7cddfSDavid du Colombier 			else if (isrec(x) && !donerec)
1503e12c5d1SDavid du Colombier 				recbld();
1513e12c5d1SDavid du Colombier 			return(x);
1523e12c5d1SDavid du Colombier 		}
153*05bfb676SDavid du Colombier 		nobj = a->nobj;
154*05bfb676SDavid du Colombier 		if (notlegal(nobj))	/* probably a Cell* but too risky to print */
1557dd7cddfSDavid du Colombier 			FATAL("illegal statement");
156*05bfb676SDavid du Colombier 		proc = proctab[nobj-FIRSTTOKEN];
157*05bfb676SDavid du Colombier 		x = (*proc)(a->narg, nobj);
1587dd7cddfSDavid du Colombier 		if (isfld(x) && !donefld)
1593e12c5d1SDavid du Colombier 			fldbld();
1607dd7cddfSDavid du Colombier 		else if (isrec(x) && !donerec)
1613e12c5d1SDavid du Colombier 			recbld();
1623e12c5d1SDavid du Colombier 		if (isexpr(a))
1633e12c5d1SDavid du Colombier 			return(x);
1643e12c5d1SDavid du Colombier 		if (isjump(x))
1653e12c5d1SDavid du Colombier 			return(x);
1663e12c5d1SDavid du Colombier 		if (a->nnext == NULL)
1673e12c5d1SDavid du Colombier 			return(x);
1683e12c5d1SDavid du Colombier 		tempfree(x);
1693e12c5d1SDavid du Colombier 	}
1703e12c5d1SDavid du Colombier }
1713e12c5d1SDavid du Colombier 
1723e12c5d1SDavid du Colombier 
173219b2ee8SDavid du Colombier Cell *program(Node **a, int n)	/* execute an awk program */
174219b2ee8SDavid du Colombier {				/* a[0] = BEGIN, a[1] = body, a[2] = END */
1757dd7cddfSDavid du Colombier 	Cell *x;
1763e12c5d1SDavid du Colombier 
1773e12c5d1SDavid du Colombier 	if (setjmp(env) != 0)
1783e12c5d1SDavid du Colombier 		goto ex;
1793e12c5d1SDavid du Colombier 	if (a[0]) {		/* BEGIN */
1803e12c5d1SDavid du Colombier 		x = execute(a[0]);
1813e12c5d1SDavid du Colombier 		if (isexit(x))
1827dd7cddfSDavid du Colombier 			return(True);
1833e12c5d1SDavid du Colombier 		if (isjump(x))
1847dd7cddfSDavid du Colombier 			FATAL("illegal break, continue, next or nextfile from BEGIN");
1853e12c5d1SDavid du Colombier 		tempfree(x);
1863e12c5d1SDavid du Colombier 	}
1873e12c5d1SDavid du Colombier 	if (a[1] || a[2])
1887dd7cddfSDavid du Colombier 		while (getrec(&record, &recsize, 1) > 0) {
1893e12c5d1SDavid du Colombier 			x = execute(a[1]);
1903e12c5d1SDavid du Colombier 			if (isexit(x))
1913e12c5d1SDavid du Colombier 				break;
1923e12c5d1SDavid du Colombier 			tempfree(x);
1933e12c5d1SDavid du Colombier 		}
1943e12c5d1SDavid du Colombier   ex:
1953e12c5d1SDavid du Colombier 	if (setjmp(env) != 0)	/* handles exit within END */
1963e12c5d1SDavid du Colombier 		goto ex1;
1973e12c5d1SDavid du Colombier 	if (a[2]) {		/* END */
1983e12c5d1SDavid du Colombier 		x = execute(a[2]);
1993e12c5d1SDavid du Colombier 		if (isbreak(x) || isnext(x) || iscont(x))
2007dd7cddfSDavid du Colombier 			FATAL("illegal break, continue, next or nextfile from END");
2013e12c5d1SDavid du Colombier 		tempfree(x);
2023e12c5d1SDavid du Colombier 	}
2033e12c5d1SDavid du Colombier   ex1:
2047dd7cddfSDavid du Colombier 	return(True);
2053e12c5d1SDavid du Colombier }
2063e12c5d1SDavid du Colombier 
207219b2ee8SDavid du Colombier struct Frame {	/* stack frame for awk function calls */
2083e12c5d1SDavid du Colombier 	int nargs;	/* number of arguments in this call */
2093e12c5d1SDavid du Colombier 	Cell *fcncell;	/* pointer to Cell for function */
2103e12c5d1SDavid du Colombier 	Cell **args;	/* pointer to array of arguments after execute */
2113e12c5d1SDavid du Colombier 	Cell *retval;	/* return value */
2123e12c5d1SDavid du Colombier };
2133e12c5d1SDavid du Colombier 
214219b2ee8SDavid du Colombier #define	NARGS	50	/* max args in a call */
2153e12c5d1SDavid du Colombier 
2163e12c5d1SDavid du Colombier struct Frame *frame = NULL;	/* base of stack frames; dynamically allocated */
2173e12c5d1SDavid du Colombier int	nframe = 0;		/* number of frames allocated */
2183e12c5d1SDavid du Colombier struct Frame *fp = NULL;	/* frame pointer. bottom level unused */
2193e12c5d1SDavid du Colombier 
220219b2ee8SDavid du Colombier Cell *call(Node **a, int n)	/* function call.  very kludgy and fragile */
2213e12c5d1SDavid du Colombier {
2227dd7cddfSDavid du Colombier 	static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
2233e12c5d1SDavid du Colombier 	int i, ncall, ndef;
2243e12c5d1SDavid du Colombier 	Node *x;
2257dd7cddfSDavid du Colombier 	Cell *args[NARGS], *oargs[NARGS];	/* BUG: fixed size arrays */
2267dd7cddfSDavid du Colombier 	Cell *y, *z, *fcn;
2277dd7cddfSDavid du Colombier 	char *s;
2283e12c5d1SDavid du Colombier 
2293e12c5d1SDavid du Colombier 	fcn = execute(a[0]);	/* the function itself */
2303e12c5d1SDavid du Colombier 	s = fcn->nval;
2317dd7cddfSDavid du Colombier 	if (!isfcn(fcn))
2327dd7cddfSDavid du Colombier 		FATAL("calling undefined function %s", s);
2333e12c5d1SDavid du Colombier 	if (frame == NULL) {
2343e12c5d1SDavid du Colombier 		fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
2353e12c5d1SDavid du Colombier 		if (frame == NULL)
2367dd7cddfSDavid du Colombier 			FATAL("out of space for stack frames calling %s", s);
2373e12c5d1SDavid du Colombier 	}
2383e12c5d1SDavid du Colombier 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)	/* args in call */
2393e12c5d1SDavid du Colombier 		ncall++;
2403e12c5d1SDavid du Colombier 	ndef = (int) fcn->fval;			/* args in defn */
2417dd7cddfSDavid du Colombier 	   dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
2423e12c5d1SDavid du Colombier 	if (ncall > ndef)
2437dd7cddfSDavid du Colombier 		WARNING("function %s called with %d args, uses only %d",
2447dd7cddfSDavid du Colombier 			s, ncall, ndef);
2453e12c5d1SDavid du Colombier 	if (ncall + ndef > NARGS)
2467dd7cddfSDavid du Colombier 		FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
2473e12c5d1SDavid du Colombier 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {	/* get call args */
2487dd7cddfSDavid du Colombier 		   dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
2493e12c5d1SDavid du Colombier 		y = execute(x);
2503e12c5d1SDavid du Colombier 		oargs[i] = y;
2513e12c5d1SDavid du Colombier 		   dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
2527dd7cddfSDavid du Colombier 			   i, y->nval, y->fval, isarr(y) ? "(array)" : y->sval, y->tval) );
2537dd7cddfSDavid du Colombier 		if (isfcn(y))
2547dd7cddfSDavid du Colombier 			FATAL("can't use function %s as argument in %s", y->nval, s);
2553e12c5d1SDavid du Colombier 		if (isarr(y))
2563e12c5d1SDavid du Colombier 			args[i] = y;	/* arrays by ref */
2573e12c5d1SDavid du Colombier 		else
2583e12c5d1SDavid du Colombier 			args[i] = copycell(y);
2593e12c5d1SDavid du Colombier 		tempfree(y);
2603e12c5d1SDavid du Colombier 	}
2613e12c5d1SDavid du Colombier 	for ( ; i < ndef; i++) {	/* add null args for ones not provided */
2623e12c5d1SDavid du Colombier 		args[i] = gettemp();
2633e12c5d1SDavid du Colombier 		*args[i] = newcopycell;
2643e12c5d1SDavid du Colombier 	}
2653e12c5d1SDavid du Colombier 	fp++;	/* now ok to up frame */
2663e12c5d1SDavid du Colombier 	if (fp >= frame + nframe) {
2673e12c5d1SDavid du Colombier 		int dfp = fp - frame;	/* old index */
2683e12c5d1SDavid du Colombier 		frame = (struct Frame *)
269219b2ee8SDavid du Colombier 			realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
2703e12c5d1SDavid du Colombier 		if (frame == NULL)
2717dd7cddfSDavid du Colombier 			FATAL("out of space for stack frames in %s", s);
2723e12c5d1SDavid du Colombier 		fp = frame + dfp;
2733e12c5d1SDavid du Colombier 	}
2743e12c5d1SDavid du Colombier 	fp->fcncell = fcn;
2753e12c5d1SDavid du Colombier 	fp->args = args;
2763e12c5d1SDavid du Colombier 	fp->nargs = ndef;	/* number defined with (excess are locals) */
2773e12c5d1SDavid du Colombier 	fp->retval = gettemp();
2783e12c5d1SDavid du Colombier 
2797dd7cddfSDavid du Colombier 	   dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
2803e12c5d1SDavid du Colombier 	y = execute((Node *)(fcn->sval));	/* execute body */
2817dd7cddfSDavid du Colombier 	   dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
2823e12c5d1SDavid du Colombier 
2833e12c5d1SDavid du Colombier 	for (i = 0; i < ndef; i++) {
2843e12c5d1SDavid du Colombier 		Cell *t = fp->args[i];
2853e12c5d1SDavid du Colombier 		if (isarr(t)) {
2863e12c5d1SDavid du Colombier 			if (t->csub == CCOPY) {
2873e12c5d1SDavid du Colombier 				if (i >= ncall) {
2883e12c5d1SDavid du Colombier 					freesymtab(t);
2893e12c5d1SDavid du Colombier 					t->csub = CTEMP;
2907dd7cddfSDavid du Colombier 					tempfree(t);
2913e12c5d1SDavid du Colombier 				} else {
2923e12c5d1SDavid du Colombier 					oargs[i]->tval = t->tval;
2933e12c5d1SDavid du Colombier 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
2943e12c5d1SDavid du Colombier 					oargs[i]->sval = t->sval;
2953e12c5d1SDavid du Colombier 					tempfree(t);
2963e12c5d1SDavid du Colombier 				}
2973e12c5d1SDavid du Colombier 			}
2983e12c5d1SDavid du Colombier 		} else if (t != y) {	/* kludge to prevent freeing twice */
2993e12c5d1SDavid du Colombier 			t->csub = CTEMP;
3003e12c5d1SDavid du Colombier 			tempfree(t);
3013e12c5d1SDavid du Colombier 		}
3023e12c5d1SDavid du Colombier 	}
3033e12c5d1SDavid du Colombier 	tempfree(fcn);
3047dd7cddfSDavid du Colombier 	if (isexit(y) || isnext(y) || isnextfile(y))
3053e12c5d1SDavid du Colombier 		return y;
3063e12c5d1SDavid du Colombier 	tempfree(y);		/* this can free twice! */
3073e12c5d1SDavid du Colombier 	z = fp->retval;			/* return value */
3083e12c5d1SDavid du Colombier 	   dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
3093e12c5d1SDavid du Colombier 	fp--;
3103e12c5d1SDavid du Colombier 	return(z);
3113e12c5d1SDavid du Colombier }
3123e12c5d1SDavid du Colombier 
3133e12c5d1SDavid du Colombier Cell *copycell(Cell *x)	/* make a copy of a cell in a temp */
3143e12c5d1SDavid du Colombier {
3153e12c5d1SDavid du Colombier 	Cell *y;
3163e12c5d1SDavid du Colombier 
3173e12c5d1SDavid du Colombier 	y = gettemp();
3183e12c5d1SDavid du Colombier 	y->csub = CCOPY;	/* prevents freeing until call is over */
3197dd7cddfSDavid du Colombier 	y->nval = x->nval;	/* BUG? */
3203e12c5d1SDavid du Colombier 	y->sval = x->sval ? tostring(x->sval) : NULL;
3213e12c5d1SDavid du Colombier 	y->fval = x->fval;
3223e12c5d1SDavid du Colombier 	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);	/* copy is not constant or field */
3233e12c5d1SDavid du Colombier 							/* is DONTFREE right? */
3243e12c5d1SDavid du Colombier 	return y;
3253e12c5d1SDavid du Colombier }
3263e12c5d1SDavid du Colombier 
327219b2ee8SDavid du Colombier Cell *arg(Node **a, int n)	/* nth argument of a function */
3283e12c5d1SDavid du Colombier {
3293e12c5d1SDavid du Colombier 
3307dd7cddfSDavid du Colombier 	n = ptoi(a[0]);	/* argument number, counting from 0 */
3313e12c5d1SDavid du Colombier 	   dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
3323e12c5d1SDavid du Colombier 	if (n+1 > fp->nargs)
3337dd7cddfSDavid du Colombier 		FATAL("argument #%d of function %s was not supplied",
3347dd7cddfSDavid du Colombier 			n+1, fp->fcncell->nval);
3353e12c5d1SDavid du Colombier 	return fp->args[n];
3363e12c5d1SDavid du Colombier }
3373e12c5d1SDavid du Colombier 
3387dd7cddfSDavid du Colombier Cell *jump(Node **a, int n)	/* break, continue, next, nextfile, return */
3393e12c5d1SDavid du Colombier {
3407dd7cddfSDavid du Colombier 	Cell *y;
3413e12c5d1SDavid du Colombier 
3423e12c5d1SDavid du Colombier 	switch (n) {
3433e12c5d1SDavid du Colombier 	case EXIT:
3443e12c5d1SDavid du Colombier 		if (a[0] != NULL) {
3453e12c5d1SDavid du Colombier 			y = execute(a[0]);
3467dd7cddfSDavid du Colombier 			errorflag = (int) getfval(y);
3473e12c5d1SDavid du Colombier 			tempfree(y);
3483e12c5d1SDavid du Colombier 		}
3493e12c5d1SDavid du Colombier 		longjmp(env, 1);
3503e12c5d1SDavid du Colombier 	case RETURN:
3513e12c5d1SDavid du Colombier 		if (a[0] != NULL) {
3523e12c5d1SDavid du Colombier 			y = execute(a[0]);
3533e12c5d1SDavid du Colombier 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
3543e12c5d1SDavid du Colombier 				setsval(fp->retval, getsval(y));
3553e12c5d1SDavid du Colombier 				fp->retval->fval = getfval(y);
3563e12c5d1SDavid du Colombier 				fp->retval->tval |= NUM;
3573e12c5d1SDavid du Colombier 			}
3583e12c5d1SDavid du Colombier 			else if (y->tval & STR)
3593e12c5d1SDavid du Colombier 				setsval(fp->retval, getsval(y));
3603e12c5d1SDavid du Colombier 			else if (y->tval & NUM)
3613e12c5d1SDavid du Colombier 				setfval(fp->retval, getfval(y));
3623e12c5d1SDavid du Colombier 			else		/* can't happen */
3637dd7cddfSDavid du Colombier 				FATAL("bad type variable %d", y->tval);
3643e12c5d1SDavid du Colombier 			tempfree(y);
3653e12c5d1SDavid du Colombier 		}
3663e12c5d1SDavid du Colombier 		return(jret);
3673e12c5d1SDavid du Colombier 	case NEXT:
3683e12c5d1SDavid du Colombier 		return(jnext);
3697dd7cddfSDavid du Colombier 	case NEXTFILE:
3707dd7cddfSDavid du Colombier 		nextfile();
3717dd7cddfSDavid du Colombier 		return(jnextfile);
3723e12c5d1SDavid du Colombier 	case BREAK:
3733e12c5d1SDavid du Colombier 		return(jbreak);
3743e12c5d1SDavid du Colombier 	case CONTINUE:
3753e12c5d1SDavid du Colombier 		return(jcont);
3763e12c5d1SDavid du Colombier 	default:	/* can't happen */
3777dd7cddfSDavid du Colombier 		FATAL("illegal jump type %d", n);
3783e12c5d1SDavid du Colombier 	}
3793e12c5d1SDavid du Colombier 	return 0;	/* not reached */
3803e12c5d1SDavid du Colombier }
3813e12c5d1SDavid du Colombier 
382219b2ee8SDavid du Colombier Cell *getline(Node **a, int n)	/* get next line from specific input */
383219b2ee8SDavid du Colombier {		/* a[0] is variable, a[1] is operator, a[2] is filename */
3847dd7cddfSDavid du Colombier 	Cell *r, *x;
3857dd7cddfSDavid du Colombier 	extern Cell **fldtab;
3863e12c5d1SDavid du Colombier 	FILE *fp;
3877dd7cddfSDavid du Colombier 	char *buf;
3887dd7cddfSDavid du Colombier 	int bufsize = recsize;
3897dd7cddfSDavid du Colombier 	int mode;
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsize)) == NULL)
3927dd7cddfSDavid du Colombier 		FATAL("out of memory in getline");
3933e12c5d1SDavid du Colombier 
3943e12c5d1SDavid du Colombier 	fflush(stdout);	/* in case someone is waiting for a prompt */
3953e12c5d1SDavid du Colombier 	r = gettemp();
3963e12c5d1SDavid du Colombier 	if (a[1] != NULL) {		/* getline < file */
3973e12c5d1SDavid du Colombier 		x = execute(a[2]);		/* filename */
3987dd7cddfSDavid du Colombier 		mode = ptoi(a[1]);
3997dd7cddfSDavid du Colombier 		if (mode == '|')		/* input pipe */
4007dd7cddfSDavid du Colombier 			mode = LE;	/* arbitrary flag */
4017dd7cddfSDavid du Colombier 		fp = openfile(mode, getsval(x));
4023e12c5d1SDavid du Colombier 		tempfree(x);
4033e12c5d1SDavid du Colombier 		if (fp == NULL)
4043e12c5d1SDavid du Colombier 			n = -1;
4053e12c5d1SDavid du Colombier 		else
4067dd7cddfSDavid du Colombier 			n = readrec(&buf, &bufsize, fp);
4073e12c5d1SDavid du Colombier 		if (n <= 0) {
4083e12c5d1SDavid du Colombier 			;
4093e12c5d1SDavid du Colombier 		} else if (a[0] != NULL) {	/* getline var <file */
4107dd7cddfSDavid du Colombier 			x = execute(a[0]);
4117dd7cddfSDavid du Colombier 			setsval(x, buf);
4127dd7cddfSDavid du Colombier 			tempfree(x);
4133e12c5d1SDavid du Colombier 		} else {			/* getline <file */
4147dd7cddfSDavid du Colombier 			setsval(fldtab[0], buf);
4157dd7cddfSDavid du Colombier 			if (is_number(fldtab[0]->sval)) {
4167dd7cddfSDavid du Colombier 				fldtab[0]->fval = atof(fldtab[0]->sval);
4177dd7cddfSDavid du Colombier 				fldtab[0]->tval |= NUM;
4183e12c5d1SDavid du Colombier 			}
4193e12c5d1SDavid du Colombier 		}
4203e12c5d1SDavid du Colombier 	} else {			/* bare getline; use current input */
4213e12c5d1SDavid du Colombier 		if (a[0] == NULL)	/* getline */
4227dd7cddfSDavid du Colombier 			n = getrec(&record, &recsize, 1);
4233e12c5d1SDavid du Colombier 		else {			/* getline var */
4247dd7cddfSDavid du Colombier 			n = getrec(&buf, &bufsize, 0);
4257dd7cddfSDavid du Colombier 			x = execute(a[0]);
4267dd7cddfSDavid du Colombier 			setsval(x, buf);
4277dd7cddfSDavid du Colombier 			tempfree(x);
4283e12c5d1SDavid du Colombier 		}
4293e12c5d1SDavid du Colombier 	}
4303e12c5d1SDavid du Colombier 	setfval(r, (Awkfloat) n);
4317dd7cddfSDavid du Colombier 	free(buf);
4323e12c5d1SDavid du Colombier 	return r;
4333e12c5d1SDavid du Colombier }
4343e12c5d1SDavid du Colombier 
435219b2ee8SDavid du Colombier Cell *getnf(Node **a, int n)	/* get NF */
4363e12c5d1SDavid du Colombier {
4373e12c5d1SDavid du Colombier 	if (donefld == 0)
4383e12c5d1SDavid du Colombier 		fldbld();
4393e12c5d1SDavid du Colombier 	return (Cell *) a[0];
4403e12c5d1SDavid du Colombier }
4413e12c5d1SDavid du Colombier 
442219b2ee8SDavid du Colombier Cell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
4433e12c5d1SDavid du Colombier {
4447dd7cddfSDavid du Colombier 	Cell *x, *y, *z;
4457dd7cddfSDavid du Colombier 	char *s;
4467dd7cddfSDavid du Colombier 	Node *np;
4477dd7cddfSDavid du Colombier 	char *buf;
4487dd7cddfSDavid du Colombier 	int bufsz = recsize;
4497dd7cddfSDavid du Colombier 	int nsub = strlen(*SUBSEP);
4507dd7cddfSDavid du Colombier 
4517dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL)
4527dd7cddfSDavid du Colombier 		FATAL("out of memory in array");
4533e12c5d1SDavid du Colombier 
4543e12c5d1SDavid du Colombier 	x = execute(a[0]);	/* Cell* for symbol table */
4553e12c5d1SDavid du Colombier 	buf[0] = 0;
4563e12c5d1SDavid du Colombier 	for (np = a[1]; np; np = np->nnext) {
4573e12c5d1SDavid du Colombier 		y = execute(np);	/* subscript */
4583e12c5d1SDavid du Colombier 		s = getsval(y);
4597dd7cddfSDavid du Colombier 		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
4607dd7cddfSDavid du Colombier 			FATAL("out of memory for %s[%s...]", x->nval, buf);
4613e12c5d1SDavid du Colombier 		strcat(buf, s);
4623e12c5d1SDavid du Colombier 		if (np->nnext)
4633e12c5d1SDavid du Colombier 			strcat(buf, *SUBSEP);
4643e12c5d1SDavid du Colombier 		tempfree(y);
4653e12c5d1SDavid du Colombier 	}
4663e12c5d1SDavid du Colombier 	if (!isarr(x)) {
4673e12c5d1SDavid du Colombier 		   dprintf( ("making %s into an array\n", x->nval) );
4683e12c5d1SDavid du Colombier 		if (freeable(x))
4693e12c5d1SDavid du Colombier 			xfree(x->sval);
4703e12c5d1SDavid du Colombier 		x->tval &= ~(STR|NUM|DONTFREE);
4713e12c5d1SDavid du Colombier 		x->tval |= ARR;
4727dd7cddfSDavid du Colombier 		x->sval = (char *) makesymtab(NSYMTAB);
4733e12c5d1SDavid du Colombier 	}
4743e12c5d1SDavid du Colombier 	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
4753e12c5d1SDavid du Colombier 	z->ctype = OCELL;
4763e12c5d1SDavid du Colombier 	z->csub = CVAR;
4773e12c5d1SDavid du Colombier 	tempfree(x);
4787dd7cddfSDavid du Colombier 	free(buf);
4793e12c5d1SDavid du Colombier 	return(z);
4803e12c5d1SDavid du Colombier }
4813e12c5d1SDavid du Colombier 
4827dd7cddfSDavid du Colombier Cell *awkdelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
4833e12c5d1SDavid du Colombier {
4843e12c5d1SDavid du Colombier 	Cell *x, *y;
4853e12c5d1SDavid du Colombier 	Node *np;
4867dd7cddfSDavid du Colombier 	char *s;
4877dd7cddfSDavid du Colombier 	int nsub = strlen(*SUBSEP);
4883e12c5d1SDavid du Colombier 
4893e12c5d1SDavid du Colombier 	x = execute(a[0]);	/* Cell* for symbol table */
4903e12c5d1SDavid du Colombier 	if (!isarr(x))
4917dd7cddfSDavid du Colombier 		return True;
4927dd7cddfSDavid du Colombier 	if (a[1] == 0) {	/* delete the elements, not the table */
4937dd7cddfSDavid du Colombier 		freesymtab(x);
4947dd7cddfSDavid du Colombier 		x->tval &= ~STR;
4957dd7cddfSDavid du Colombier 		x->tval |= ARR;
4967dd7cddfSDavid du Colombier 		x->sval = (char *) makesymtab(NSYMTAB);
4977dd7cddfSDavid du Colombier 	} else {
4987dd7cddfSDavid du Colombier 		int bufsz = recsize;
4997dd7cddfSDavid du Colombier 		char *buf;
5007dd7cddfSDavid du Colombier 		if ((buf = (char *) malloc(bufsz)) == NULL)
5017dd7cddfSDavid du Colombier 			FATAL("out of memory in adelete");
5023e12c5d1SDavid du Colombier 		buf[0] = 0;
5033e12c5d1SDavid du Colombier 		for (np = a[1]; np; np = np->nnext) {
5043e12c5d1SDavid du Colombier 			y = execute(np);	/* subscript */
5053e12c5d1SDavid du Colombier 			s = getsval(y);
5067dd7cddfSDavid du Colombier 			if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
5077dd7cddfSDavid du Colombier 				FATAL("out of memory deleting %s[%s...]", x->nval, buf);
5083e12c5d1SDavid du Colombier 			strcat(buf, s);
5093e12c5d1SDavid du Colombier 			if (np->nnext)
5103e12c5d1SDavid du Colombier 				strcat(buf, *SUBSEP);
5113e12c5d1SDavid du Colombier 			tempfree(y);
5123e12c5d1SDavid du Colombier 		}
5133e12c5d1SDavid du Colombier 		freeelem(x, buf);
5147dd7cddfSDavid du Colombier 		free(buf);
5157dd7cddfSDavid du Colombier 	}
5163e12c5d1SDavid du Colombier 	tempfree(x);
5177dd7cddfSDavid du Colombier 	return True;
5183e12c5d1SDavid du Colombier }
5193e12c5d1SDavid du Colombier 
520219b2ee8SDavid du Colombier Cell *intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
5213e12c5d1SDavid du Colombier {
5227dd7cddfSDavid du Colombier 	Cell *x, *ap, *k;
5233e12c5d1SDavid du Colombier 	Node *p;
5247dd7cddfSDavid du Colombier 	char *buf;
5257dd7cddfSDavid du Colombier 	char *s;
5267dd7cddfSDavid du Colombier 	int bufsz = recsize;
5277dd7cddfSDavid du Colombier 	int nsub = strlen(*SUBSEP);
5283e12c5d1SDavid du Colombier 
5293e12c5d1SDavid du Colombier 	ap = execute(a[1]);	/* array name */
5303e12c5d1SDavid du Colombier 	if (!isarr(ap)) {
5313e12c5d1SDavid du Colombier 		   dprintf( ("making %s into an array\n", ap->nval) );
5323e12c5d1SDavid du Colombier 		if (freeable(ap))
5333e12c5d1SDavid du Colombier 			xfree(ap->sval);
5343e12c5d1SDavid du Colombier 		ap->tval &= ~(STR|NUM|DONTFREE);
5353e12c5d1SDavid du Colombier 		ap->tval |= ARR;
5367dd7cddfSDavid du Colombier 		ap->sval = (char *) makesymtab(NSYMTAB);
5377dd7cddfSDavid du Colombier 	}
5387dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL) {
5397dd7cddfSDavid du Colombier 		FATAL("out of memory in intest");
5403e12c5d1SDavid du Colombier 	}
5413e12c5d1SDavid du Colombier 	buf[0] = 0;
5423e12c5d1SDavid du Colombier 	for (p = a[0]; p; p = p->nnext) {
5433e12c5d1SDavid du Colombier 		x = execute(p);	/* expr */
5443e12c5d1SDavid du Colombier 		s = getsval(x);
5457dd7cddfSDavid du Colombier 		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
5467dd7cddfSDavid du Colombier 			FATAL("out of memory deleting %s[%s...]", x->nval, buf);
5473e12c5d1SDavid du Colombier 		strcat(buf, s);
5483e12c5d1SDavid du Colombier 		tempfree(x);
5493e12c5d1SDavid du Colombier 		if (p->nnext)
5503e12c5d1SDavid du Colombier 			strcat(buf, *SUBSEP);
5513e12c5d1SDavid du Colombier 	}
5523e12c5d1SDavid du Colombier 	k = lookup(buf, (Array *) ap->sval);
5533e12c5d1SDavid du Colombier 	tempfree(ap);
5547dd7cddfSDavid du Colombier 	free(buf);
5553e12c5d1SDavid du Colombier 	if (k == NULL)
5567dd7cddfSDavid du Colombier 		return(False);
5573e12c5d1SDavid du Colombier 	else
5587dd7cddfSDavid du Colombier 		return(True);
5593e12c5d1SDavid du Colombier }
5603e12c5d1SDavid du Colombier 
5613e12c5d1SDavid du Colombier 
562219b2ee8SDavid du Colombier Cell *matchop(Node **a, int n)	/* ~ and match() */
5633e12c5d1SDavid du Colombier {
5647dd7cddfSDavid du Colombier 	Cell *x, *y;
5657dd7cddfSDavid du Colombier 	char *s, *t;
5667dd7cddfSDavid du Colombier 	int i;
5673e12c5d1SDavid du Colombier 	void *p;
5683e12c5d1SDavid du Colombier 
569219b2ee8SDavid du Colombier 	x = execute(a[1]);	/* a[1] = target text */
5703e12c5d1SDavid du Colombier 	s = getsval(x);
571219b2ee8SDavid du Colombier 	if (a[0] == 0)		/* a[1] == 0: already-compiled reg expr */
5723e12c5d1SDavid du Colombier 		p = (void *) a[2];
5733e12c5d1SDavid du Colombier 	else {
574219b2ee8SDavid du Colombier 		y = execute(a[2]);	/* a[2] = regular expr */
5753e12c5d1SDavid du Colombier 		t = getsval(y);
5763e12c5d1SDavid du Colombier 		p = compre(t);
5773e12c5d1SDavid du Colombier 		tempfree(y);
5783e12c5d1SDavid du Colombier 	}
5793e12c5d1SDavid du Colombier 	if (n == MATCHFCN)
5803e12c5d1SDavid du Colombier 		i = pmatch(p, s, s);
5813e12c5d1SDavid du Colombier 	else
5823e12c5d1SDavid du Colombier 		i = match(p, s, s);
5833e12c5d1SDavid du Colombier 	tempfree(x);
5843e12c5d1SDavid du Colombier 	if (n == MATCHFCN) {
585d9306527SDavid du Colombier 		int start = countposn(s, patbeg-s)+1;
5863e12c5d1SDavid du Colombier 		if (patlen < 0)
5873e12c5d1SDavid du Colombier 			start = 0;
5883e12c5d1SDavid du Colombier 		setfval(rstartloc, (Awkfloat) start);
5893e12c5d1SDavid du Colombier 		setfval(rlengthloc, (Awkfloat) countposn(patbeg, patlen));
5903e12c5d1SDavid du Colombier 		x = gettemp();
5913e12c5d1SDavid du Colombier 		x->tval = NUM;
5923e12c5d1SDavid du Colombier 		x->fval = start;
5933e12c5d1SDavid du Colombier 		return x;
5947dd7cddfSDavid du Colombier 	} else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
5957dd7cddfSDavid du Colombier 		return(True);
5963e12c5d1SDavid du Colombier 	else
5977dd7cddfSDavid du Colombier 		return(False);
5983e12c5d1SDavid du Colombier }
5993e12c5d1SDavid du Colombier 
6003e12c5d1SDavid du Colombier 
601219b2ee8SDavid du Colombier Cell *boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
6023e12c5d1SDavid du Colombier {
6037dd7cddfSDavid du Colombier 	Cell *x, *y;
6047dd7cddfSDavid du Colombier 	int i;
6053e12c5d1SDavid du Colombier 
6063e12c5d1SDavid du Colombier 	x = execute(a[0]);
6073e12c5d1SDavid du Colombier 	i = istrue(x);
6083e12c5d1SDavid du Colombier 	tempfree(x);
6093e12c5d1SDavid du Colombier 	switch (n) {
6103e12c5d1SDavid du Colombier 	case BOR:
6117dd7cddfSDavid du Colombier 		if (i) return(True);
6123e12c5d1SDavid du Colombier 		y = execute(a[1]);
6133e12c5d1SDavid du Colombier 		i = istrue(y);
6143e12c5d1SDavid du Colombier 		tempfree(y);
6157dd7cddfSDavid du Colombier 		if (i) return(True);
6167dd7cddfSDavid du Colombier 		else return(False);
6173e12c5d1SDavid du Colombier 	case AND:
6187dd7cddfSDavid du Colombier 		if ( !i ) return(False);
6193e12c5d1SDavid du Colombier 		y = execute(a[1]);
6203e12c5d1SDavid du Colombier 		i = istrue(y);
6213e12c5d1SDavid du Colombier 		tempfree(y);
6227dd7cddfSDavid du Colombier 		if (i) return(True);
6237dd7cddfSDavid du Colombier 		else return(False);
6243e12c5d1SDavid du Colombier 	case NOT:
6257dd7cddfSDavid du Colombier 		if (i) return(False);
6267dd7cddfSDavid du Colombier 		else return(True);
6273e12c5d1SDavid du Colombier 	default:	/* can't happen */
6287dd7cddfSDavid du Colombier 		FATAL("unknown boolean operator %d", n);
6293e12c5d1SDavid du Colombier 	}
6303e12c5d1SDavid du Colombier 	return 0;	/*NOTREACHED*/
6313e12c5d1SDavid du Colombier }
6323e12c5d1SDavid du Colombier 
633219b2ee8SDavid du Colombier Cell *relop(Node **a, int n)	/* a[0 < a[1], etc. */
6343e12c5d1SDavid du Colombier {
6357dd7cddfSDavid du Colombier 	int i;
6367dd7cddfSDavid du Colombier 	Cell *x, *y;
6373e12c5d1SDavid du Colombier 	Awkfloat j;
6383e12c5d1SDavid du Colombier 
6393e12c5d1SDavid du Colombier 	x = execute(a[0]);
6403e12c5d1SDavid du Colombier 	y = execute(a[1]);
6413e12c5d1SDavid du Colombier 	if (x->tval&NUM && y->tval&NUM) {
6423e12c5d1SDavid du Colombier 		j = x->fval - y->fval;
6433e12c5d1SDavid du Colombier 		i = j<0? -1: (j>0? 1: 0);
6443e12c5d1SDavid du Colombier 	} else {
6453e12c5d1SDavid du Colombier 		i = strcmp(getsval(x), getsval(y));
6463e12c5d1SDavid du Colombier 	}
6473e12c5d1SDavid du Colombier 	tempfree(x);
6483e12c5d1SDavid du Colombier 	tempfree(y);
6493e12c5d1SDavid du Colombier 	switch (n) {
6507dd7cddfSDavid du Colombier 	case LT:	if (i<0) return(True);
6517dd7cddfSDavid du Colombier 			else return(False);
6527dd7cddfSDavid du Colombier 	case LE:	if (i<=0) return(True);
6537dd7cddfSDavid du Colombier 			else return(False);
6547dd7cddfSDavid du Colombier 	case NE:	if (i!=0) return(True);
6557dd7cddfSDavid du Colombier 			else return(False);
6567dd7cddfSDavid du Colombier 	case EQ:	if (i == 0) return(True);
6577dd7cddfSDavid du Colombier 			else return(False);
6587dd7cddfSDavid du Colombier 	case GE:	if (i>=0) return(True);
6597dd7cddfSDavid du Colombier 			else return(False);
6607dd7cddfSDavid du Colombier 	case GT:	if (i>0) return(True);
6617dd7cddfSDavid du Colombier 			else return(False);
6623e12c5d1SDavid du Colombier 	default:	/* can't happen */
6637dd7cddfSDavid du Colombier 		FATAL("unknown relational operator %d", n);
6643e12c5d1SDavid du Colombier 	}
6653e12c5d1SDavid du Colombier 	return 0;	/*NOTREACHED*/
6663e12c5d1SDavid du Colombier }
6673e12c5d1SDavid du Colombier 
668219b2ee8SDavid du Colombier void tfree(Cell *a)	/* free a tempcell */
6693e12c5d1SDavid du Colombier {
6707dd7cddfSDavid du Colombier 	if (freeable(a)) {
6717dd7cddfSDavid du Colombier 		   dprintf( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) );
6723e12c5d1SDavid du Colombier 		xfree(a->sval);
6737dd7cddfSDavid du Colombier 	}
6743e12c5d1SDavid du Colombier 	if (a == tmps)
6757dd7cddfSDavid du Colombier 		FATAL("tempcell list is curdled");
6763e12c5d1SDavid du Colombier 	a->cnext = tmps;
6773e12c5d1SDavid du Colombier 	tmps = a;
6783e12c5d1SDavid du Colombier }
6793e12c5d1SDavid du Colombier 
680219b2ee8SDavid du Colombier Cell *gettemp(void)	/* get a tempcell */
6813e12c5d1SDavid du Colombier {	int i;
6827dd7cddfSDavid du Colombier 	Cell *x;
6833e12c5d1SDavid du Colombier 
6843e12c5d1SDavid du Colombier 	if (!tmps) {
6853e12c5d1SDavid du Colombier 		tmps = (Cell *) calloc(100, sizeof(Cell));
6863e12c5d1SDavid du Colombier 		if (!tmps)
6877dd7cddfSDavid du Colombier 			FATAL("out of space for temporaries");
6883e12c5d1SDavid du Colombier 		for(i = 1; i < 100; i++)
6893e12c5d1SDavid du Colombier 			tmps[i-1].cnext = &tmps[i];
6903e12c5d1SDavid du Colombier 		tmps[i-1].cnext = 0;
6913e12c5d1SDavid du Colombier 	}
6923e12c5d1SDavid du Colombier 	x = tmps;
6933e12c5d1SDavid du Colombier 	tmps = x->cnext;
6943e12c5d1SDavid du Colombier 	*x = tempcell;
6953e12c5d1SDavid du Colombier 	return(x);
6963e12c5d1SDavid du Colombier }
6973e12c5d1SDavid du Colombier 
698219b2ee8SDavid du Colombier Cell *indirect(Node **a, int n)	/* $( a[0] ) */
6993e12c5d1SDavid du Colombier {
7007dd7cddfSDavid du Colombier 	Cell *x;
7017dd7cddfSDavid du Colombier 	int m;
7027dd7cddfSDavid du Colombier 	char *s;
7033e12c5d1SDavid du Colombier 
7043e12c5d1SDavid du Colombier 	x = execute(a[0]);
7057dd7cddfSDavid du Colombier 	m = (int) getfval(x);
7067dd7cddfSDavid du Colombier 	if (m == 0 && !is_number(s = getsval(x)))	/* suspicion! */
7077dd7cddfSDavid du Colombier 		FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
7087dd7cddfSDavid du Colombier 		/* BUG: can x->nval ever be null??? */
7093e12c5d1SDavid du Colombier 	tempfree(x);
7103e12c5d1SDavid du Colombier 	x = fieldadr(m);
7117dd7cddfSDavid du Colombier 	x->ctype = OCELL;	/* BUG?  why are these needed? */
7123e12c5d1SDavid du Colombier 	x->csub = CFLD;
7133e12c5d1SDavid du Colombier 	return(x);
7143e12c5d1SDavid du Colombier }
7153e12c5d1SDavid du Colombier 
716219b2ee8SDavid du Colombier Cell *substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
7173e12c5d1SDavid du Colombier {
7187dd7cddfSDavid du Colombier 	int k, m, n;
7197dd7cddfSDavid du Colombier 	char *s, *p;
7203e12c5d1SDavid du Colombier 	int temp;
7217dd7cddfSDavid du Colombier 	Cell *x, *y, *z = 0;
7223e12c5d1SDavid du Colombier 
7233e12c5d1SDavid du Colombier 	x = execute(a[0]);
7243e12c5d1SDavid du Colombier 	y = execute(a[1]);
7253e12c5d1SDavid du Colombier 	if (a[2] != 0)
7263e12c5d1SDavid du Colombier 		z = execute(a[2]);
7273e12c5d1SDavid du Colombier 	s = getsval(x);
7283e12c5d1SDavid du Colombier 	k = countposn(s, strlen(s)) + 1;
7293e12c5d1SDavid du Colombier 	if (k <= 1) {
7303e12c5d1SDavid du Colombier 		tempfree(x);
7313e12c5d1SDavid du Colombier 		tempfree(y);
7323e12c5d1SDavid du Colombier 		if (a[2] != 0)
7333e12c5d1SDavid du Colombier 			tempfree(z);
7343e12c5d1SDavid du Colombier 		x = gettemp();
7353e12c5d1SDavid du Colombier 		setsval(x, "");
7363e12c5d1SDavid du Colombier 		return(x);
7373e12c5d1SDavid du Colombier 	}
7387dd7cddfSDavid du Colombier 	m = (int) getfval(y);
7393e12c5d1SDavid du Colombier 	if (m <= 0)
7403e12c5d1SDavid du Colombier 		m = 1;
7413e12c5d1SDavid du Colombier 	else if (m > k)
7423e12c5d1SDavid du Colombier 		m = k;
7433e12c5d1SDavid du Colombier 	tempfree(y);
7443e12c5d1SDavid du Colombier 	if (a[2] != 0) {
7457dd7cddfSDavid du Colombier 		n = (int) getfval(z);
7463e12c5d1SDavid du Colombier 		tempfree(z);
7473e12c5d1SDavid du Colombier 	} else
7483e12c5d1SDavid du Colombier 		n = k - 1;
7493e12c5d1SDavid du Colombier 	if (n < 0)
7503e12c5d1SDavid du Colombier 		n = 0;
7513e12c5d1SDavid du Colombier 	else if (n > k - m)
7523e12c5d1SDavid du Colombier 		n = k - m;
7533e12c5d1SDavid du Colombier 	   dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
7543e12c5d1SDavid du Colombier 	y = gettemp();
7553e12c5d1SDavid du Colombier 	while (*s && --m)
7563e12c5d1SDavid du Colombier 		 s += mblen(s, k);
7573e12c5d1SDavid du Colombier 	for (p = s; *p && n--; p += mblen(p, k))
7583e12c5d1SDavid du Colombier 			;
7593e12c5d1SDavid du Colombier 	temp = *p;	/* with thanks to John Linderman */
7603e12c5d1SDavid du Colombier 	*p = '\0';
7613e12c5d1SDavid du Colombier 	setsval(y, s);
7623e12c5d1SDavid du Colombier 	*p = temp;
7633e12c5d1SDavid du Colombier 	tempfree(x);
7643e12c5d1SDavid du Colombier 	return(y);
7653e12c5d1SDavid du Colombier }
7663e12c5d1SDavid du Colombier 
767219b2ee8SDavid du Colombier Cell *sindex(Node **a, int nnn)		/* index(a[0], a[1]) */
7683e12c5d1SDavid du Colombier {
7697dd7cddfSDavid du Colombier 	Cell *x, *y, *z;
7707dd7cddfSDavid du Colombier 	char *s1, *s2, *p1, *p2, *q;
7713e12c5d1SDavid du Colombier 	Awkfloat v = 0.0;
7723e12c5d1SDavid du Colombier 
7733e12c5d1SDavid du Colombier 	x = execute(a[0]);
7743e12c5d1SDavid du Colombier 	s1 = getsval(x);
7753e12c5d1SDavid du Colombier 	y = execute(a[1]);
7763e12c5d1SDavid du Colombier 	s2 = getsval(y);
7773e12c5d1SDavid du Colombier 
7783e12c5d1SDavid du Colombier 	z = gettemp();
7793e12c5d1SDavid du Colombier 	for (p1 = s1; *p1 != '\0'; p1++) {
7803e12c5d1SDavid du Colombier 		for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
7813e12c5d1SDavid du Colombier 			;
7823e12c5d1SDavid du Colombier 		if (*p2 == '\0') {
7833e12c5d1SDavid du Colombier 			v = (Awkfloat) countposn(s1, p1-s1) + 1;	/* origin 1 */
7843e12c5d1SDavid du Colombier 			break;
7853e12c5d1SDavid du Colombier 		}
7863e12c5d1SDavid du Colombier 	}
7873e12c5d1SDavid du Colombier 	tempfree(x);
7883e12c5d1SDavid du Colombier 	tempfree(y);
7893e12c5d1SDavid du Colombier 	setfval(z, v);
7903e12c5d1SDavid du Colombier 	return(z);
7913e12c5d1SDavid du Colombier }
7923e12c5d1SDavid du Colombier 
7937dd7cddfSDavid du Colombier #define	MAXNUMSIZE	50
794219b2ee8SDavid du Colombier 
7957dd7cddfSDavid du Colombier int format(char **pbuf, int *pbufsize, char *s, Node *a)	/* printf-like conversions */
7963e12c5d1SDavid du Colombier {
7977dd7cddfSDavid du Colombier 	char *fmt;
7987dd7cddfSDavid du Colombier 	char *p, *t, *os;
7997dd7cddfSDavid du Colombier 	Cell *x;
8003e12c5d1SDavid du Colombier 	int flag = 0, n;
8017dd7cddfSDavid du Colombier 	int fmtwd; /* format width */
8027dd7cddfSDavid du Colombier 	int fmtsz = recsize;
8037dd7cddfSDavid du Colombier 	char *buf = *pbuf;
8047dd7cddfSDavid du Colombier 	int bufsize = *pbufsize;
8053e12c5d1SDavid du Colombier 
8063e12c5d1SDavid du Colombier 	os = s;
8073e12c5d1SDavid du Colombier 	p = buf;
8087dd7cddfSDavid du Colombier 	if ((fmt = (char *) malloc(fmtsz)) == NULL)
8097dd7cddfSDavid du Colombier 		FATAL("out of memory in format()");
8103e12c5d1SDavid du Colombier 	while (*s) {
8117dd7cddfSDavid du Colombier 		adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format");
8123e12c5d1SDavid du Colombier 		if (*s != '%') {
8133e12c5d1SDavid du Colombier 			*p++ = *s++;
8143e12c5d1SDavid du Colombier 			continue;
8153e12c5d1SDavid du Colombier 		}
8163e12c5d1SDavid du Colombier 		if (*(s+1) == '%') {
8173e12c5d1SDavid du Colombier 			*p++ = '%';
8183e12c5d1SDavid du Colombier 			s += 2;
8193e12c5d1SDavid du Colombier 			continue;
8203e12c5d1SDavid du Colombier 		}
8217dd7cddfSDavid du Colombier 		/* have to be real careful in case this is a huge number, eg, %100000d */
8227dd7cddfSDavid du Colombier 		fmtwd = atoi(s+1);
8237dd7cddfSDavid du Colombier 		if (fmtwd < 0)
8247dd7cddfSDavid du Colombier 			fmtwd = -fmtwd;
8257dd7cddfSDavid du Colombier 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
8263e12c5d1SDavid du Colombier 		for (t = fmt; (*t++ = *s) != '\0'; s++) {
8277dd7cddfSDavid du Colombier 			if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0))
8287dd7cddfSDavid du Colombier 				FATAL("format item %.30s... ran format() out of memory", os);
8293e12c5d1SDavid du Colombier 			if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
8303e12c5d1SDavid du Colombier 				break;	/* the ansi panoply */
8313e12c5d1SDavid du Colombier 			if (*s == '*') {
8323e12c5d1SDavid du Colombier 				x = execute(a);
8333e12c5d1SDavid du Colombier 				a = a->nnext;
8347dd7cddfSDavid du Colombier 				sprintf(t-1, "%d", fmtwd=(int) getfval(x));
8357dd7cddfSDavid du Colombier 				if (fmtwd < 0)
8367dd7cddfSDavid du Colombier 					fmtwd = -fmtwd;
8377dd7cddfSDavid du Colombier 				adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
8383e12c5d1SDavid du Colombier 				t = fmt + strlen(fmt);
8393e12c5d1SDavid du Colombier 				tempfree(x);
8403e12c5d1SDavid du Colombier 			}
8413e12c5d1SDavid du Colombier 		}
8423e12c5d1SDavid du Colombier 		*t = '\0';
8437dd7cddfSDavid du Colombier 		if (fmtwd < 0)
8447dd7cddfSDavid du Colombier 			fmtwd = -fmtwd;
8457dd7cddfSDavid du Colombier 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
8467dd7cddfSDavid du Colombier 
8473e12c5d1SDavid du Colombier 		switch (*s) {
8483e12c5d1SDavid du Colombier 		case 'f': case 'e': case 'g': case 'E': case 'G':
8493e12c5d1SDavid du Colombier 			flag = 1;
8503e12c5d1SDavid du Colombier 			break;
8513e12c5d1SDavid du Colombier 		case 'd': case 'i':
8523e12c5d1SDavid du Colombier 			flag = 2;
8533e12c5d1SDavid du Colombier 			if(*(s-1) == 'l') break;
8543e12c5d1SDavid du Colombier 			*(t-1) = 'l';
8553e12c5d1SDavid du Colombier 			*t = 'd';
8563e12c5d1SDavid du Colombier 			*++t = '\0';
8573e12c5d1SDavid du Colombier 			break;
8583e12c5d1SDavid du Colombier 		case 'o': case 'x': case 'X': case 'u':
8593e12c5d1SDavid du Colombier 			flag = *(s-1) == 'l' ? 2 : 3;
8603e12c5d1SDavid du Colombier 			break;
8613e12c5d1SDavid du Colombier 		case 's':
8623e12c5d1SDavid du Colombier 			flag = 4;
8633e12c5d1SDavid du Colombier 			break;
8643e12c5d1SDavid du Colombier 		case 'c':
8653e12c5d1SDavid du Colombier 			flag = 5;
8663e12c5d1SDavid du Colombier 			break;
8673e12c5d1SDavid du Colombier 		default:
8687dd7cddfSDavid du Colombier 			WARNING("weird printf conversion %s", fmt);
8693e12c5d1SDavid du Colombier 			flag = 0;
8703e12c5d1SDavid du Colombier 			break;
8713e12c5d1SDavid du Colombier 		}
8723e12c5d1SDavid du Colombier 		if (a == NULL)
8737dd7cddfSDavid du Colombier 			FATAL("not enough args in printf(%s)", os);
8743e12c5d1SDavid du Colombier 		x = execute(a);
8753e12c5d1SDavid du Colombier 		a = a->nnext;
8767dd7cddfSDavid du Colombier 		n = MAXNUMSIZE;
8777dd7cddfSDavid du Colombier 		if (fmtwd > n)
8787dd7cddfSDavid du Colombier 			n = fmtwd;
8797dd7cddfSDavid du Colombier 		adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
8803e12c5d1SDavid du Colombier 		switch (flag) {
8817dd7cddfSDavid du Colombier 		case 0:	sprintf(p, "%s", fmt);	/* unknown, so dump it too */
8827dd7cddfSDavid du Colombier 			t = getsval(x);
8837dd7cddfSDavid du Colombier 			n = strlen(t);
8847dd7cddfSDavid du Colombier 			if (fmtwd > n)
8857dd7cddfSDavid du Colombier 				n = fmtwd;
8867dd7cddfSDavid du Colombier 			adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
8873e12c5d1SDavid du Colombier 			p += strlen(p);
8887dd7cddfSDavid du Colombier 			sprintf(p, "%s", t);
8893e12c5d1SDavid du Colombier 			break;
8907dd7cddfSDavid du Colombier 		case 1:	sprintf(p, fmt, getfval(x)); break;
8917dd7cddfSDavid du Colombier 		case 2:	sprintf(p, fmt, (long) getfval(x)); break;
8927dd7cddfSDavid du Colombier 		case 3:	sprintf(p, fmt, (int) getfval(x)); break;
8933e12c5d1SDavid du Colombier 		case 4:
8943e12c5d1SDavid du Colombier 			t = getsval(x);
8953e12c5d1SDavid du Colombier 			n = strlen(t);
8967dd7cddfSDavid du Colombier 			if (fmtwd > n)
8977dd7cddfSDavid du Colombier 				n = fmtwd;
8987dd7cddfSDavid du Colombier 			if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
8997dd7cddfSDavid du Colombier 				FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
9007dd7cddfSDavid du Colombier 			sprintf(p, fmt, t);
9013e12c5d1SDavid du Colombier 			break;
902219b2ee8SDavid du Colombier 		case 5:
9037dd7cddfSDavid du Colombier 			if (isnum(x)) {
9047dd7cddfSDavid du Colombier 				if (getfval(x))
9057dd7cddfSDavid du Colombier 					sprintf(p, fmt, (int) getfval(x));
9067dd7cddfSDavid du Colombier 				else
9077dd7cddfSDavid du Colombier 					*p++ = '\0';
9087dd7cddfSDavid du Colombier 			} else
9097dd7cddfSDavid du Colombier 				sprintf(p, fmt, getsval(x)[0]);
9103e12c5d1SDavid du Colombier 			break;
9113e12c5d1SDavid du Colombier 		}
9123e12c5d1SDavid du Colombier 		tempfree(x);
9133e12c5d1SDavid du Colombier 		p += strlen(p);
9143e12c5d1SDavid du Colombier 		s++;
9153e12c5d1SDavid du Colombier 	}
9163e12c5d1SDavid du Colombier 	*p = '\0';
9177dd7cddfSDavid du Colombier 	free(fmt);
9183e12c5d1SDavid du Colombier 	for ( ; a; a = a->nnext)		/* evaluate any remaining args */
9193e12c5d1SDavid du Colombier 		execute(a);
9207dd7cddfSDavid du Colombier 	*pbuf = buf;
9217dd7cddfSDavid du Colombier 	*pbufsize = bufsize;
9227dd7cddfSDavid du Colombier 	return p - buf;
9233e12c5d1SDavid du Colombier }
9243e12c5d1SDavid du Colombier 
9257dd7cddfSDavid du Colombier Cell *awksprintf(Node **a, int n)		/* sprintf(a[0]) */
9263e12c5d1SDavid du Colombier {
9277dd7cddfSDavid du Colombier 	Cell *x;
9287dd7cddfSDavid du Colombier 	Node *y;
9297dd7cddfSDavid du Colombier 	char *buf;
9307dd7cddfSDavid du Colombier 	int bufsz=3*recsize;
9313e12c5d1SDavid du Colombier 
9327dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL)
9337dd7cddfSDavid du Colombier 		FATAL("out of memory in awksprintf");
9343e12c5d1SDavid du Colombier 	y = a[0]->nnext;
9353e12c5d1SDavid du Colombier 	x = execute(a[0]);
9367dd7cddfSDavid du Colombier 	if (format(&buf, &bufsz, getsval(x), y) == -1)
9377dd7cddfSDavid du Colombier 		FATAL("sprintf string %.30s... too long.  can't happen.", buf);
9383e12c5d1SDavid du Colombier 	tempfree(x);
9393e12c5d1SDavid du Colombier 	x = gettemp();
9407dd7cddfSDavid du Colombier 	x->sval = buf;
9413e12c5d1SDavid du Colombier 	x->tval = STR;
9423e12c5d1SDavid du Colombier 	return(x);
9433e12c5d1SDavid du Colombier }
9443e12c5d1SDavid du Colombier 
9457dd7cddfSDavid du Colombier Cell *awkprintf(Node **a, int n)		/* printf */
946219b2ee8SDavid du Colombier {	/* a[0] is list of args, starting with format string */
947219b2ee8SDavid du Colombier 	/* a[1] is redirection operator, a[2] is redirection file */
9483e12c5d1SDavid du Colombier 	FILE *fp;
9497dd7cddfSDavid du Colombier 	Cell *x;
9507dd7cddfSDavid du Colombier 	Node *y;
9517dd7cddfSDavid du Colombier 	char *buf;
9527dd7cddfSDavid du Colombier 	int len;
9537dd7cddfSDavid du Colombier 	int bufsz=3*recsize;
9543e12c5d1SDavid du Colombier 
9557dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL)
9567dd7cddfSDavid du Colombier 		FATAL("out of memory in awkprintf");
9573e12c5d1SDavid du Colombier 	y = a[0]->nnext;
9583e12c5d1SDavid du Colombier 	x = execute(a[0]);
9597dd7cddfSDavid du Colombier 	if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
9607dd7cddfSDavid du Colombier 		FATAL("printf string %.30s... too long.  can't happen.", buf);
9613e12c5d1SDavid du Colombier 	tempfree(x);
9623e12c5d1SDavid du Colombier 	if (a[1] == NULL) {
9637dd7cddfSDavid du Colombier 		/* fputs(buf, stdout); */
9647dd7cddfSDavid du Colombier 		fwrite(buf, len, 1, stdout);
9653e12c5d1SDavid du Colombier 		if (ferror(stdout))
9667dd7cddfSDavid du Colombier 			FATAL("write error on stdout");
9673e12c5d1SDavid du Colombier 	} else {
9687dd7cddfSDavid du Colombier 		fp = redirect(ptoi(a[1]), a[2]);
9697dd7cddfSDavid du Colombier 		/* fputs(buf, fp); */
9707dd7cddfSDavid du Colombier 		fwrite(buf, len, 1, fp);
9713e12c5d1SDavid du Colombier 		fflush(fp);
9723e12c5d1SDavid du Colombier 		if (ferror(fp))
9737dd7cddfSDavid du Colombier 			FATAL("write error on %s", filename(fp));
9743e12c5d1SDavid du Colombier 	}
9757dd7cddfSDavid du Colombier 	free(buf);
9767dd7cddfSDavid du Colombier 	return(True);
9773e12c5d1SDavid du Colombier }
9783e12c5d1SDavid du Colombier 
979219b2ee8SDavid du Colombier Cell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
9803e12c5d1SDavid du Colombier {
9817dd7cddfSDavid du Colombier 	Awkfloat i, j = 0;
9823e12c5d1SDavid du Colombier 	double v;
9837dd7cddfSDavid du Colombier 	Cell *x, *y, *z;
9843e12c5d1SDavid du Colombier 
9853e12c5d1SDavid du Colombier 	x = execute(a[0]);
9863e12c5d1SDavid du Colombier 	i = getfval(x);
9873e12c5d1SDavid du Colombier 	tempfree(x);
9883e12c5d1SDavid du Colombier 	if (n != UMINUS) {
9893e12c5d1SDavid du Colombier 		y = execute(a[1]);
9903e12c5d1SDavid du Colombier 		j = getfval(y);
9913e12c5d1SDavid du Colombier 		tempfree(y);
9923e12c5d1SDavid du Colombier 	}
9933e12c5d1SDavid du Colombier 	z = gettemp();
9943e12c5d1SDavid du Colombier 	switch (n) {
9953e12c5d1SDavid du Colombier 	case ADD:
9963e12c5d1SDavid du Colombier 		i += j;
9973e12c5d1SDavid du Colombier 		break;
9983e12c5d1SDavid du Colombier 	case MINUS:
9993e12c5d1SDavid du Colombier 		i -= j;
10003e12c5d1SDavid du Colombier 		break;
10013e12c5d1SDavid du Colombier 	case MULT:
10023e12c5d1SDavid du Colombier 		i *= j;
10033e12c5d1SDavid du Colombier 		break;
10043e12c5d1SDavid du Colombier 	case DIVIDE:
10053e12c5d1SDavid du Colombier 		if (j == 0)
10067dd7cddfSDavid du Colombier 			FATAL("division by zero");
10073e12c5d1SDavid du Colombier 		i /= j;
10083e12c5d1SDavid du Colombier 		break;
10093e12c5d1SDavid du Colombier 	case MOD:
10103e12c5d1SDavid du Colombier 		if (j == 0)
10117dd7cddfSDavid du Colombier 			FATAL("division by zero in mod");
10123e12c5d1SDavid du Colombier 		modf(i/j, &v);
10133e12c5d1SDavid du Colombier 		i = i - j * v;
10143e12c5d1SDavid du Colombier 		break;
10153e12c5d1SDavid du Colombier 	case UMINUS:
10163e12c5d1SDavid du Colombier 		i = -i;
10173e12c5d1SDavid du Colombier 		break;
10183e12c5d1SDavid du Colombier 	case POWER:
10193e12c5d1SDavid du Colombier 		if (j >= 0 && modf(j, &v) == 0.0)	/* pos integer exponent */
10203e12c5d1SDavid du Colombier 			i = ipow(i, (int) j);
10213e12c5d1SDavid du Colombier 		else
10223e12c5d1SDavid du Colombier 			i = errcheck(pow(i, j), "pow");
10233e12c5d1SDavid du Colombier 		break;
10243e12c5d1SDavid du Colombier 	default:	/* can't happen */
10257dd7cddfSDavid du Colombier 		FATAL("illegal arithmetic operator %d", n);
10263e12c5d1SDavid du Colombier 	}
10273e12c5d1SDavid du Colombier 	setfval(z, i);
10283e12c5d1SDavid du Colombier 	return(z);
10293e12c5d1SDavid du Colombier }
10303e12c5d1SDavid du Colombier 
1031219b2ee8SDavid du Colombier double ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
10323e12c5d1SDavid du Colombier {
10333e12c5d1SDavid du Colombier 	double v;
10343e12c5d1SDavid du Colombier 
10353e12c5d1SDavid du Colombier 	if (n <= 0)
10363e12c5d1SDavid du Colombier 		return 1;
10373e12c5d1SDavid du Colombier 	v = ipow(x, n/2);
10383e12c5d1SDavid du Colombier 	if (n % 2 == 0)
10393e12c5d1SDavid du Colombier 		return v * v;
10403e12c5d1SDavid du Colombier 	else
10413e12c5d1SDavid du Colombier 		return x * v * v;
10423e12c5d1SDavid du Colombier }
10433e12c5d1SDavid du Colombier 
1044219b2ee8SDavid du Colombier Cell *incrdecr(Node **a, int n)		/* a[0]++, etc. */
10453e12c5d1SDavid du Colombier {
10467dd7cddfSDavid du Colombier 	Cell *x, *z;
10477dd7cddfSDavid du Colombier 	int k;
10483e12c5d1SDavid du Colombier 	Awkfloat xf;
10493e12c5d1SDavid du Colombier 
10503e12c5d1SDavid du Colombier 	x = execute(a[0]);
10513e12c5d1SDavid du Colombier 	xf = getfval(x);
10523e12c5d1SDavid du Colombier 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
10533e12c5d1SDavid du Colombier 	if (n == PREINCR || n == PREDECR) {
10543e12c5d1SDavid du Colombier 		setfval(x, xf + k);
10553e12c5d1SDavid du Colombier 		return(x);
10563e12c5d1SDavid du Colombier 	}
10573e12c5d1SDavid du Colombier 	z = gettemp();
10583e12c5d1SDavid du Colombier 	setfval(z, xf);
10593e12c5d1SDavid du Colombier 	setfval(x, xf + k);
10603e12c5d1SDavid du Colombier 	tempfree(x);
10613e12c5d1SDavid du Colombier 	return(z);
10623e12c5d1SDavid du Colombier }
10633e12c5d1SDavid du Colombier 
1064219b2ee8SDavid du Colombier Cell *assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
1065219b2ee8SDavid du Colombier {		/* this is subtle; don't muck with it. */
10667dd7cddfSDavid du Colombier 	Cell *x, *y;
10673e12c5d1SDavid du Colombier 	Awkfloat xf, yf;
10683e12c5d1SDavid du Colombier 	double v;
10693e12c5d1SDavid du Colombier 
10703e12c5d1SDavid du Colombier 	y = execute(a[1]);
10713e12c5d1SDavid du Colombier 	x = execute(a[0]);
10723e12c5d1SDavid du Colombier 	if (n == ASSIGN) {	/* ordinary assignment */
1073219b2ee8SDavid du Colombier 		if (x == y && !(x->tval & (FLD|REC)))	/* self-assignment: */
1074219b2ee8SDavid du Colombier 			;		/* leave alone unless it's a field */
10753e12c5d1SDavid du Colombier 		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
10763e12c5d1SDavid du Colombier 			setsval(x, getsval(y));
10773e12c5d1SDavid du Colombier 			x->fval = getfval(y);
10783e12c5d1SDavid du Colombier 			x->tval |= NUM;
10793e12c5d1SDavid du Colombier 		}
10807dd7cddfSDavid du Colombier 		else if (isstr(y))
10813e12c5d1SDavid du Colombier 			setsval(x, getsval(y));
10827dd7cddfSDavid du Colombier 		else if (isnum(y))
10833e12c5d1SDavid du Colombier 			setfval(x, getfval(y));
10843e12c5d1SDavid du Colombier 		else
10853e12c5d1SDavid du Colombier 			funnyvar(y, "read value of");
10863e12c5d1SDavid du Colombier 		tempfree(y);
10873e12c5d1SDavid du Colombier 		return(x);
10883e12c5d1SDavid du Colombier 	}
10893e12c5d1SDavid du Colombier 	xf = getfval(x);
10903e12c5d1SDavid du Colombier 	yf = getfval(y);
10913e12c5d1SDavid du Colombier 	switch (n) {
10923e12c5d1SDavid du Colombier 	case ADDEQ:
10933e12c5d1SDavid du Colombier 		xf += yf;
10943e12c5d1SDavid du Colombier 		break;
10953e12c5d1SDavid du Colombier 	case SUBEQ:
10963e12c5d1SDavid du Colombier 		xf -= yf;
10973e12c5d1SDavid du Colombier 		break;
10983e12c5d1SDavid du Colombier 	case MULTEQ:
10993e12c5d1SDavid du Colombier 		xf *= yf;
11003e12c5d1SDavid du Colombier 		break;
11013e12c5d1SDavid du Colombier 	case DIVEQ:
11023e12c5d1SDavid du Colombier 		if (yf == 0)
11037dd7cddfSDavid du Colombier 			FATAL("division by zero in /=");
11043e12c5d1SDavid du Colombier 		xf /= yf;
11053e12c5d1SDavid du Colombier 		break;
11063e12c5d1SDavid du Colombier 	case MODEQ:
11073e12c5d1SDavid du Colombier 		if (yf == 0)
11087dd7cddfSDavid du Colombier 			FATAL("division by zero in %%=");
11093e12c5d1SDavid du Colombier 		modf(xf/yf, &v);
11103e12c5d1SDavid du Colombier 		xf = xf - yf * v;
11113e12c5d1SDavid du Colombier 		break;
11123e12c5d1SDavid du Colombier 	case POWEQ:
11133e12c5d1SDavid du Colombier 		if (yf >= 0 && modf(yf, &v) == 0.0)	/* pos integer exponent */
11143e12c5d1SDavid du Colombier 			xf = ipow(xf, (int) yf);
11153e12c5d1SDavid du Colombier 		else
11163e12c5d1SDavid du Colombier 			xf = errcheck(pow(xf, yf), "pow");
11173e12c5d1SDavid du Colombier 		break;
11183e12c5d1SDavid du Colombier 	default:
11197dd7cddfSDavid du Colombier 		FATAL("illegal assignment operator %d", n);
11203e12c5d1SDavid du Colombier 		break;
11213e12c5d1SDavid du Colombier 	}
11223e12c5d1SDavid du Colombier 	tempfree(y);
11233e12c5d1SDavid du Colombier 	setfval(x, xf);
11243e12c5d1SDavid du Colombier 	return(x);
11253e12c5d1SDavid du Colombier }
11263e12c5d1SDavid du Colombier 
1127219b2ee8SDavid du Colombier Cell *cat(Node **a, int q)	/* a[0] cat a[1] */
11283e12c5d1SDavid du Colombier {
11297dd7cddfSDavid du Colombier 	Cell *x, *y, *z;
11307dd7cddfSDavid du Colombier 	int n1, n2;
11317dd7cddfSDavid du Colombier 	char *s;
11323e12c5d1SDavid du Colombier 
11333e12c5d1SDavid du Colombier 	x = execute(a[0]);
11343e12c5d1SDavid du Colombier 	y = execute(a[1]);
11353e12c5d1SDavid du Colombier 	getsval(x);
11363e12c5d1SDavid du Colombier 	getsval(y);
11373e12c5d1SDavid du Colombier 	n1 = strlen(x->sval);
11383e12c5d1SDavid du Colombier 	n2 = strlen(y->sval);
11397dd7cddfSDavid du Colombier 	s = (char *) malloc(n1 + n2 + 1);
11403e12c5d1SDavid du Colombier 	if (s == NULL)
11417dd7cddfSDavid du Colombier 		FATAL("out of space concatenating %.15s... and %.15s...",
11427dd7cddfSDavid du Colombier 			x->sval, y->sval);
11433e12c5d1SDavid du Colombier 	strcpy(s, x->sval);
11443e12c5d1SDavid du Colombier 	strcpy(s+n1, y->sval);
11453e12c5d1SDavid du Colombier 	tempfree(y);
11463e12c5d1SDavid du Colombier 	z = gettemp();
11473e12c5d1SDavid du Colombier 	z->sval = s;
11483e12c5d1SDavid du Colombier 	z->tval = STR;
11493e12c5d1SDavid du Colombier 	tempfree(x);
11503e12c5d1SDavid du Colombier 	return(z);
11513e12c5d1SDavid du Colombier }
11523e12c5d1SDavid du Colombier 
11533e12c5d1SDavid du Colombier Cell *pastat(Node **a, int n)	/* a[0] { a[1] } */
11543e12c5d1SDavid du Colombier {
11557dd7cddfSDavid du Colombier 	Cell *x;
11563e12c5d1SDavid du Colombier 
11573e12c5d1SDavid du Colombier 	if (a[0] == 0)
11583e12c5d1SDavid du Colombier 		x = execute(a[1]);
11593e12c5d1SDavid du Colombier 	else {
11603e12c5d1SDavid du Colombier 		x = execute(a[0]);
11613e12c5d1SDavid du Colombier 		if (istrue(x)) {
11623e12c5d1SDavid du Colombier 			tempfree(x);
11633e12c5d1SDavid du Colombier 			x = execute(a[1]);
11643e12c5d1SDavid du Colombier 		}
11653e12c5d1SDavid du Colombier 	}
11663e12c5d1SDavid du Colombier 	return x;
11673e12c5d1SDavid du Colombier }
11683e12c5d1SDavid du Colombier 
11693e12c5d1SDavid du Colombier Cell *dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
11703e12c5d1SDavid du Colombier {
11717dd7cddfSDavid du Colombier 	Cell *x;
11727dd7cddfSDavid du Colombier 	int pair;
11733e12c5d1SDavid du Colombier 
11747dd7cddfSDavid du Colombier 	pair = ptoi(a[3]);
11753e12c5d1SDavid du Colombier 	if (pairstack[pair] == 0) {
11763e12c5d1SDavid du Colombier 		x = execute(a[0]);
11773e12c5d1SDavid du Colombier 		if (istrue(x))
11783e12c5d1SDavid du Colombier 			pairstack[pair] = 1;
11793e12c5d1SDavid du Colombier 		tempfree(x);
11803e12c5d1SDavid du Colombier 	}
11813e12c5d1SDavid du Colombier 	if (pairstack[pair] == 1) {
11823e12c5d1SDavid du Colombier 		x = execute(a[1]);
11833e12c5d1SDavid du Colombier 		if (istrue(x))
11843e12c5d1SDavid du Colombier 			pairstack[pair] = 0;
11853e12c5d1SDavid du Colombier 		tempfree(x);
11863e12c5d1SDavid du Colombier 		x = execute(a[2]);
11873e12c5d1SDavid du Colombier 		return(x);
11883e12c5d1SDavid du Colombier 	}
11897dd7cddfSDavid du Colombier 	return(False);
11903e12c5d1SDavid du Colombier }
11913e12c5d1SDavid du Colombier 
11923e12c5d1SDavid du Colombier Cell *split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
11933e12c5d1SDavid du Colombier {
11947dd7cddfSDavid du Colombier 	Cell *x = 0, *y, *ap;
11957dd7cddfSDavid du Colombier 	char *s;
11967dd7cddfSDavid du Colombier 	int sep;
11977dd7cddfSDavid du Colombier 	char *t, temp, num[50], *fs = 0;
11987dd7cddfSDavid du Colombier 	int n, tempstat, arg3type;
11993e12c5d1SDavid du Colombier 
12003e12c5d1SDavid du Colombier 	y = execute(a[0]);	/* source string */
12013e12c5d1SDavid du Colombier 	s = getsval(y);
12027dd7cddfSDavid du Colombier 	arg3type = ptoi(a[3]);
12033e12c5d1SDavid du Colombier 	if (a[2] == 0)		/* fs string */
12043e12c5d1SDavid du Colombier 		fs = *FS;
12057dd7cddfSDavid du Colombier 	else if (arg3type == STRING) {	/* split(str,arr,"string") */
12063e12c5d1SDavid du Colombier 		x = execute(a[2]);
12073e12c5d1SDavid du Colombier 		fs = getsval(x);
12087dd7cddfSDavid du Colombier 	} else if (arg3type == REGEXPR)
12097dd7cddfSDavid du Colombier 		fs = "(regexpr)";	/* split(str,arr,/regexpr/) */
12103e12c5d1SDavid du Colombier 	else
12117dd7cddfSDavid du Colombier 		FATAL("illegal type of split");
12123e12c5d1SDavid du Colombier 	sep = *fs;
12133e12c5d1SDavid du Colombier 	ap = execute(a[1]);	/* array name */
12143e12c5d1SDavid du Colombier 	freesymtab(ap);
12153e12c5d1SDavid du Colombier 	   dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
12163e12c5d1SDavid du Colombier 	ap->tval &= ~STR;
12173e12c5d1SDavid du Colombier 	ap->tval |= ARR;
12187dd7cddfSDavid du Colombier 	ap->sval = (char *) makesymtab(NSYMTAB);
12193e12c5d1SDavid du Colombier 
12203e12c5d1SDavid du Colombier 	n = 0;
12217dd7cddfSDavid du Colombier 	if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) {	/* reg expr */
12223e12c5d1SDavid du Colombier 		void *p;
12237dd7cddfSDavid du Colombier 		if (arg3type == REGEXPR) {	/* it's ready already */
12243e12c5d1SDavid du Colombier 			p = (void *) a[2];
12253e12c5d1SDavid du Colombier 		} else {
12263e12c5d1SDavid du Colombier 			p = compre(fs);
12273e12c5d1SDavid du Colombier 		}
12283e12c5d1SDavid du Colombier 		t = s;
12293e12c5d1SDavid du Colombier 		if (nematch(p,s,t)) {
12303e12c5d1SDavid du Colombier 			do {
12313e12c5d1SDavid du Colombier 				n++;
12327dd7cddfSDavid du Colombier 				sprintf(num, "%d", n);
12333e12c5d1SDavid du Colombier 				temp = *patbeg;
12343e12c5d1SDavid du Colombier 				*patbeg = '\0';
12357dd7cddfSDavid du Colombier 				if (is_number(t))
12367dd7cddfSDavid du Colombier 					setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
12373e12c5d1SDavid du Colombier 				else
12383e12c5d1SDavid du Colombier 					setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
12393e12c5d1SDavid du Colombier 				*patbeg = temp;
12403e12c5d1SDavid du Colombier 				t = patbeg + patlen;
12413e12c5d1SDavid du Colombier 				if (t[-1] == 0 || *t == 0) {
12423e12c5d1SDavid du Colombier 					n++;
12437dd7cddfSDavid du Colombier 					sprintf(num, "%d", n);
12443e12c5d1SDavid du Colombier 					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
12453e12c5d1SDavid du Colombier 					goto spdone;
12463e12c5d1SDavid du Colombier 				}
12473e12c5d1SDavid du Colombier 			} while (nematch(p,s,t));
12483e12c5d1SDavid du Colombier 		}
12493e12c5d1SDavid du Colombier 		n++;
12507dd7cddfSDavid du Colombier 		sprintf(num, "%d", n);
12517dd7cddfSDavid du Colombier 		if (is_number(t))
12527dd7cddfSDavid du Colombier 			setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
12533e12c5d1SDavid du Colombier 		else
12543e12c5d1SDavid du Colombier 			setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
12553e12c5d1SDavid du Colombier   spdone:
12563e12c5d1SDavid du Colombier 		p = NULL;
12573e12c5d1SDavid du Colombier 	} else if (sep == ' ') {
12583e12c5d1SDavid du Colombier 		for (n = 0; ; ) {
12593e12c5d1SDavid du Colombier 			while (*s == ' ' || *s == '\t' || *s == '\n')
12603e12c5d1SDavid du Colombier 				s++;
12613e12c5d1SDavid du Colombier 			if (*s == 0)
12623e12c5d1SDavid du Colombier 				break;
12633e12c5d1SDavid du Colombier 			n++;
12643e12c5d1SDavid du Colombier 			t = s;
12653e12c5d1SDavid du Colombier 			do
12663e12c5d1SDavid du Colombier 				s++;
12673e12c5d1SDavid du Colombier 			while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
12683e12c5d1SDavid du Colombier 			temp = *s;
12693e12c5d1SDavid du Colombier 			*s = '\0';
12707dd7cddfSDavid du Colombier 			sprintf(num, "%d", n);
12717dd7cddfSDavid du Colombier 			if (is_number(t))
12727dd7cddfSDavid du Colombier 				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
12733e12c5d1SDavid du Colombier 			else
12743e12c5d1SDavid du Colombier 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
12753e12c5d1SDavid du Colombier 			*s = temp;
12763e12c5d1SDavid du Colombier 			if (*s != 0)
12773e12c5d1SDavid du Colombier 				s++;
12783e12c5d1SDavid du Colombier 		}
12797dd7cddfSDavid du Colombier 	} else if (sep == 0) {	/* new: split(s, a, "") => 1 char/elem */
12807dd7cddfSDavid du Colombier 		for (n = 0; *s != 0; s++) {
12817dd7cddfSDavid du Colombier 			char buf[2];
12827dd7cddfSDavid du Colombier 			n++;
12837dd7cddfSDavid du Colombier 			sprintf(num, "%d", n);
12847dd7cddfSDavid du Colombier 			buf[0] = *s;
12857dd7cddfSDavid du Colombier 			buf[1] = 0;
12867dd7cddfSDavid du Colombier 			if (isdigit(buf[0]))
12877dd7cddfSDavid du Colombier 				setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
12887dd7cddfSDavid du Colombier 			else
12897dd7cddfSDavid du Colombier 				setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
12907dd7cddfSDavid du Colombier 		}
12913e12c5d1SDavid du Colombier 	} else if (*s != 0) {
12923e12c5d1SDavid du Colombier 		for (;;) {
12933e12c5d1SDavid du Colombier 			n++;
12943e12c5d1SDavid du Colombier 			t = s;
12953e12c5d1SDavid du Colombier 			while (*s != sep && *s != '\n' && *s != '\0')
12963e12c5d1SDavid du Colombier 				s++;
12973e12c5d1SDavid du Colombier 			temp = *s;
12983e12c5d1SDavid du Colombier 			*s = '\0';
12997dd7cddfSDavid du Colombier 			sprintf(num, "%d", n);
13007dd7cddfSDavid du Colombier 			if (is_number(t))
13017dd7cddfSDavid du Colombier 				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
13023e12c5d1SDavid du Colombier 			else
13033e12c5d1SDavid du Colombier 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
13043e12c5d1SDavid du Colombier 			*s = temp;
13053e12c5d1SDavid du Colombier 			if (*s++ == 0)
13063e12c5d1SDavid du Colombier 				break;
13073e12c5d1SDavid du Colombier 		}
13083e12c5d1SDavid du Colombier 	}
13093e12c5d1SDavid du Colombier 	tempfree(ap);
13103e12c5d1SDavid du Colombier 	tempfree(y);
13117dd7cddfSDavid du Colombier 	if (a[2] != 0 && arg3type == STRING)
13123e12c5d1SDavid du Colombier 		tempfree(x);
13133e12c5d1SDavid du Colombier 	x = gettemp();
13143e12c5d1SDavid du Colombier 	x->tval = NUM;
13153e12c5d1SDavid du Colombier 	x->fval = n;
13163e12c5d1SDavid du Colombier 	return(x);
13173e12c5d1SDavid du Colombier }
13183e12c5d1SDavid du Colombier 
13193e12c5d1SDavid du Colombier Cell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
13203e12c5d1SDavid du Colombier {
13217dd7cddfSDavid du Colombier 	Cell *x;
13223e12c5d1SDavid du Colombier 
13233e12c5d1SDavid du Colombier 	x = execute(a[0]);
13243e12c5d1SDavid du Colombier 	if (istrue(x)) {
13253e12c5d1SDavid du Colombier 		tempfree(x);
13263e12c5d1SDavid du Colombier 		x = execute(a[1]);
13273e12c5d1SDavid du Colombier 	} else {
13283e12c5d1SDavid du Colombier 		tempfree(x);
13293e12c5d1SDavid du Colombier 		x = execute(a[2]);
13303e12c5d1SDavid du Colombier 	}
13313e12c5d1SDavid du Colombier 	return(x);
13323e12c5d1SDavid du Colombier }
13333e12c5d1SDavid du Colombier 
13343e12c5d1SDavid du Colombier Cell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
13353e12c5d1SDavid du Colombier {
13367dd7cddfSDavid du Colombier 	Cell *x;
13373e12c5d1SDavid du Colombier 
13383e12c5d1SDavid du Colombier 	x = execute(a[0]);
13393e12c5d1SDavid du Colombier 	if (istrue(x)) {
13403e12c5d1SDavid du Colombier 		tempfree(x);
13413e12c5d1SDavid du Colombier 		x = execute(a[1]);
13423e12c5d1SDavid du Colombier 	} else if (a[2] != 0) {
13433e12c5d1SDavid du Colombier 		tempfree(x);
13443e12c5d1SDavid du Colombier 		x = execute(a[2]);
13453e12c5d1SDavid du Colombier 	}
13463e12c5d1SDavid du Colombier 	return(x);
13473e12c5d1SDavid du Colombier }
13483e12c5d1SDavid du Colombier 
13493e12c5d1SDavid du Colombier Cell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
13503e12c5d1SDavid du Colombier {
13517dd7cddfSDavid du Colombier 	Cell *x;
13523e12c5d1SDavid du Colombier 
13533e12c5d1SDavid du Colombier 	for (;;) {
13543e12c5d1SDavid du Colombier 		x = execute(a[0]);
13553e12c5d1SDavid du Colombier 		if (!istrue(x))
13563e12c5d1SDavid du Colombier 			return(x);
13573e12c5d1SDavid du Colombier 		tempfree(x);
13583e12c5d1SDavid du Colombier 		x = execute(a[1]);
13593e12c5d1SDavid du Colombier 		if (isbreak(x)) {
13607dd7cddfSDavid du Colombier 			x = True;
13613e12c5d1SDavid du Colombier 			return(x);
13623e12c5d1SDavid du Colombier 		}
13633e12c5d1SDavid du Colombier 		if (isnext(x) || isexit(x) || isret(x))
13643e12c5d1SDavid du Colombier 			return(x);
13653e12c5d1SDavid du Colombier 		tempfree(x);
13663e12c5d1SDavid du Colombier 	}
13673e12c5d1SDavid du Colombier }
13683e12c5d1SDavid du Colombier 
13693e12c5d1SDavid du Colombier Cell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
13703e12c5d1SDavid du Colombier {
13717dd7cddfSDavid du Colombier 	Cell *x;
13723e12c5d1SDavid du Colombier 
13733e12c5d1SDavid du Colombier 	for (;;) {
13743e12c5d1SDavid du Colombier 		x = execute(a[0]);
13753e12c5d1SDavid du Colombier 		if (isbreak(x))
13767dd7cddfSDavid du Colombier 			return True;
13777dd7cddfSDavid du Colombier 		if (isnext(x) || isnextfile(x) || isexit(x) || isret(x))
13783e12c5d1SDavid du Colombier 			return(x);
13793e12c5d1SDavid du Colombier 		tempfree(x);
13803e12c5d1SDavid du Colombier 		x = execute(a[1]);
13813e12c5d1SDavid du Colombier 		if (!istrue(x))
13823e12c5d1SDavid du Colombier 			return(x);
13833e12c5d1SDavid du Colombier 		tempfree(x);
13843e12c5d1SDavid du Colombier 	}
13853e12c5d1SDavid du Colombier }
13863e12c5d1SDavid du Colombier 
13873e12c5d1SDavid du Colombier Cell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
13883e12c5d1SDavid du Colombier {
13897dd7cddfSDavid du Colombier 	Cell *x;
13903e12c5d1SDavid du Colombier 
13913e12c5d1SDavid du Colombier 	x = execute(a[0]);
13923e12c5d1SDavid du Colombier 	tempfree(x);
13933e12c5d1SDavid du Colombier 	for (;;) {
13943e12c5d1SDavid du Colombier 		if (a[1]!=0) {
13953e12c5d1SDavid du Colombier 			x = execute(a[1]);
13963e12c5d1SDavid du Colombier 			if (!istrue(x)) return(x);
13973e12c5d1SDavid du Colombier 			else tempfree(x);
13983e12c5d1SDavid du Colombier 		}
13993e12c5d1SDavid du Colombier 		x = execute(a[3]);
14003e12c5d1SDavid du Colombier 		if (isbreak(x))		/* turn off break */
14017dd7cddfSDavid du Colombier 			return True;
14023e12c5d1SDavid du Colombier 		if (isnext(x) || isexit(x) || isret(x))
14033e12c5d1SDavid du Colombier 			return(x);
14043e12c5d1SDavid du Colombier 		tempfree(x);
14053e12c5d1SDavid du Colombier 		x = execute(a[2]);
14063e12c5d1SDavid du Colombier 		tempfree(x);
14073e12c5d1SDavid du Colombier 	}
14083e12c5d1SDavid du Colombier }
14093e12c5d1SDavid du Colombier 
14103e12c5d1SDavid du Colombier Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
14113e12c5d1SDavid du Colombier {
14127dd7cddfSDavid du Colombier 	Cell *x, *vp, *arrayp, *cp, *ncp;
14133e12c5d1SDavid du Colombier 	Array *tp;
14143e12c5d1SDavid du Colombier 	int i;
14153e12c5d1SDavid du Colombier 
14163e12c5d1SDavid du Colombier 	vp = execute(a[0]);
14173e12c5d1SDavid du Colombier 	arrayp = execute(a[1]);
14183e12c5d1SDavid du Colombier 	if (!isarr(arrayp)) {
14197dd7cddfSDavid du Colombier 		return True;
14203e12c5d1SDavid du Colombier 	}
14213e12c5d1SDavid du Colombier 	tp = (Array *) arrayp->sval;
14223e12c5d1SDavid du Colombier 	tempfree(arrayp);
14233e12c5d1SDavid du Colombier 	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
14243e12c5d1SDavid du Colombier 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
14253e12c5d1SDavid du Colombier 			setsval(vp, cp->nval);
14263e12c5d1SDavid du Colombier 			ncp = cp->cnext;
14273e12c5d1SDavid du Colombier 			x = execute(a[2]);
14283e12c5d1SDavid du Colombier 			if (isbreak(x)) {
14293e12c5d1SDavid du Colombier 				tempfree(vp);
14307dd7cddfSDavid du Colombier 				return True;
14313e12c5d1SDavid du Colombier 			}
14323e12c5d1SDavid du Colombier 			if (isnext(x) || isexit(x) || isret(x)) {
14333e12c5d1SDavid du Colombier 				tempfree(vp);
14343e12c5d1SDavid du Colombier 				return(x);
14353e12c5d1SDavid du Colombier 			}
14363e12c5d1SDavid du Colombier 			tempfree(x);
14373e12c5d1SDavid du Colombier 		}
14383e12c5d1SDavid du Colombier 	}
14397dd7cddfSDavid du Colombier 	return True;
14403e12c5d1SDavid du Colombier }
14413e12c5d1SDavid du Colombier 
1442219b2ee8SDavid du Colombier Cell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
14433e12c5d1SDavid du Colombier {
14447dd7cddfSDavid du Colombier 	Cell *x, *y;
14453e12c5d1SDavid du Colombier 	Awkfloat u;
14467dd7cddfSDavid du Colombier 	int t;
1447219b2ee8SDavid du Colombier 	wchar_t wc;
14487dd7cddfSDavid du Colombier 	char *p, *buf;
14497dd7cddfSDavid du Colombier 	char mbc[50];
14503e12c5d1SDavid du Colombier 	Node *nextarg;
14513e12c5d1SDavid du Colombier 	FILE *fp;
14523e12c5d1SDavid du Colombier 
14537dd7cddfSDavid du Colombier 	t = ptoi(a[0]);
14543e12c5d1SDavid du Colombier 	x = execute(a[1]);
14553e12c5d1SDavid du Colombier 	nextarg = a[1]->nnext;
14563e12c5d1SDavid du Colombier 	switch (t) {
14573e12c5d1SDavid du Colombier 	case FLENGTH:
14583e12c5d1SDavid du Colombier 		p = getsval(x);
14593e12c5d1SDavid du Colombier 		u = (Awkfloat) countposn(p, strlen(p)); break;
14603e12c5d1SDavid du Colombier 	case FLOG:
14613e12c5d1SDavid du Colombier 		u = errcheck(log(getfval(x)), "log"); break;
14623e12c5d1SDavid du Colombier 	case FINT:
14633e12c5d1SDavid du Colombier 		modf(getfval(x), &u); break;
14643e12c5d1SDavid du Colombier 	case FEXP:
14653e12c5d1SDavid du Colombier 		u = errcheck(exp(getfval(x)), "exp"); break;
14663e12c5d1SDavid du Colombier 	case FSQRT:
14673e12c5d1SDavid du Colombier 		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
14683e12c5d1SDavid du Colombier 	case FSIN:
14693e12c5d1SDavid du Colombier 		u = sin(getfval(x)); break;
14703e12c5d1SDavid du Colombier 	case FCOS:
14713e12c5d1SDavid du Colombier 		u = cos(getfval(x)); break;
14723e12c5d1SDavid du Colombier 	case FATAN:
14733e12c5d1SDavid du Colombier 		if (nextarg == 0) {
14747dd7cddfSDavid du Colombier 			WARNING("atan2 requires two arguments; returning 1.0");
14753e12c5d1SDavid du Colombier 			u = 1.0;
14763e12c5d1SDavid du Colombier 		} else {
14773e12c5d1SDavid du Colombier 			y = execute(a[1]->nnext);
14783e12c5d1SDavid du Colombier 			u = atan2(getfval(x), getfval(y));
14793e12c5d1SDavid du Colombier 			tempfree(y);
14803e12c5d1SDavid du Colombier 			nextarg = nextarg->nnext;
14813e12c5d1SDavid du Colombier 		}
14823e12c5d1SDavid du Colombier 		break;
14833e12c5d1SDavid du Colombier 	case FSYSTEM:
14843e12c5d1SDavid du Colombier 		fflush(stdout);		/* in case something is buffered already */
14857dd7cddfSDavid du Colombier 		u = (Awkfloat) system(getsval(x)) / 256;   /* 256 is unix-dep */
14863e12c5d1SDavid du Colombier 		break;
14873e12c5d1SDavid du Colombier 	case FRAND:
14883e12c5d1SDavid du Colombier 		/* in principle, rand() returns something in 0..RAND_MAX */
14893e12c5d1SDavid du Colombier 		u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
14903e12c5d1SDavid du Colombier 		break;
14913e12c5d1SDavid du Colombier 	case FSRAND:
14927dd7cddfSDavid du Colombier 		if (isrec(x))	/* no argument provided */
14937dd7cddfSDavid du Colombier 			u = time((time_t *)0);
14943e12c5d1SDavid du Colombier 		else
14953e12c5d1SDavid du Colombier 			u = getfval(x);
14967dd7cddfSDavid du Colombier 		srand((unsigned int) u);
14973e12c5d1SDavid du Colombier 		break;
14983e12c5d1SDavid du Colombier 	case FTOUPPER:
14993e12c5d1SDavid du Colombier 	case FTOLOWER:
15007dd7cddfSDavid du Colombier 		buf = tostring(getsval(x));
15013e12c5d1SDavid du Colombier 		if (t == FTOUPPER) {
15023e12c5d1SDavid du Colombier 			for (p = buf; *p; p++)
15033e12c5d1SDavid du Colombier 				if (islower(*p))
15043e12c5d1SDavid du Colombier 					*p = toupper(*p);
15053e12c5d1SDavid du Colombier 		} else {
15063e12c5d1SDavid du Colombier 			for (p = buf; *p; p++)
15073e12c5d1SDavid du Colombier 				if (isupper(*p))
15083e12c5d1SDavid du Colombier 					*p = tolower(*p);
15093e12c5d1SDavid du Colombier 		}
15103e12c5d1SDavid du Colombier 		tempfree(x);
15113e12c5d1SDavid du Colombier 		x = gettemp();
15123e12c5d1SDavid du Colombier 		setsval(x, buf);
15137dd7cddfSDavid du Colombier 		free(buf);
15143e12c5d1SDavid du Colombier 		return x;
15153e12c5d1SDavid du Colombier 	case FFLUSH:
15167dd7cddfSDavid du Colombier 		if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
15173e12c5d1SDavid du Colombier 			u = EOF;
15183e12c5d1SDavid du Colombier 		else
15193e12c5d1SDavid du Colombier 			u = fflush(fp);
15203e12c5d1SDavid du Colombier 		break;
1521219b2ee8SDavid du Colombier 	case FUTF:
1522219b2ee8SDavid du Colombier 		wc = (int)getfval(x);
1523219b2ee8SDavid du Colombier 		mbc[wctomb(mbc, wc)] = 0;
1524219b2ee8SDavid du Colombier 		tempfree(x);
1525219b2ee8SDavid du Colombier 		x = gettemp();
1526219b2ee8SDavid du Colombier 		setsval(x, mbc);
1527219b2ee8SDavid du Colombier 		return x;
15283e12c5d1SDavid du Colombier 	default:	/* can't happen */
15297dd7cddfSDavid du Colombier 		FATAL("illegal function type %d", t);
15303e12c5d1SDavid du Colombier 		break;
15313e12c5d1SDavid du Colombier 	}
15323e12c5d1SDavid du Colombier 	tempfree(x);
15333e12c5d1SDavid du Colombier 	x = gettemp();
15343e12c5d1SDavid du Colombier 	setfval(x, u);
15353e12c5d1SDavid du Colombier 	if (nextarg != 0) {
15367dd7cddfSDavid du Colombier 		WARNING("warning: function has too many arguments");
15373e12c5d1SDavid du Colombier 		for ( ; nextarg; nextarg = nextarg->nnext)
15383e12c5d1SDavid du Colombier 			execute(nextarg);
15393e12c5d1SDavid du Colombier 	}
15403e12c5d1SDavid du Colombier 	return(x);
15413e12c5d1SDavid du Colombier }
15423e12c5d1SDavid du Colombier 
1543219b2ee8SDavid du Colombier Cell *printstat(Node **a, int n)	/* print a[0] */
15443e12c5d1SDavid du Colombier {
1545*05bfb676SDavid du Colombier 	int r;
15467dd7cddfSDavid du Colombier 	Node *x;
15477dd7cddfSDavid du Colombier 	Cell *y;
15483e12c5d1SDavid du Colombier 	FILE *fp;
15493e12c5d1SDavid du Colombier 
1550219b2ee8SDavid du Colombier 	if (a[1] == 0)	/* a[1] is redirection operator, a[2] is file */
15513e12c5d1SDavid du Colombier 		fp = stdout;
15523e12c5d1SDavid du Colombier 	else
15537dd7cddfSDavid du Colombier 		fp = redirect(ptoi(a[1]), a[2]);
15543e12c5d1SDavid du Colombier 	for (x = a[0]; x != NULL; x = x->nnext) {
15553e12c5d1SDavid du Colombier 		y = execute(x);
15567dd7cddfSDavid du Colombier 		fputs(getsval(y), fp);
15573e12c5d1SDavid du Colombier 		tempfree(y);
15583e12c5d1SDavid du Colombier 		if (x->nnext == NULL)
1559*05bfb676SDavid du Colombier 			r = fputs(*ORS, fp);
15603e12c5d1SDavid du Colombier 		else
1561*05bfb676SDavid du Colombier 			r = fputs(*OFS, fp);
1562*05bfb676SDavid du Colombier 		if (r == EOF)
1563*05bfb676SDavid du Colombier 			FATAL("write error on %s", filename(fp));
15643e12c5d1SDavid du Colombier 	}
15653e12c5d1SDavid du Colombier 	if (a[1] != 0)
1566*05bfb676SDavid du Colombier 		if (fflush(fp) == EOF)
15677dd7cddfSDavid du Colombier 			FATAL("write error on %s", filename(fp));
15687dd7cddfSDavid du Colombier 	return(True);
15693e12c5d1SDavid du Colombier }
15703e12c5d1SDavid du Colombier 
15713e12c5d1SDavid du Colombier Cell *nullproc(Node **a, int n)
15723e12c5d1SDavid du Colombier {
15737dd7cddfSDavid du Colombier 	n = n;
15747dd7cddfSDavid du Colombier 	a = a;
15753e12c5d1SDavid du Colombier 	return 0;
15763e12c5d1SDavid du Colombier }
15773e12c5d1SDavid du Colombier 
15783e12c5d1SDavid du Colombier 
1579219b2ee8SDavid du Colombier FILE *redirect(int a, Node *b)	/* set up all i/o redirections */
15803e12c5d1SDavid du Colombier {
15813e12c5d1SDavid du Colombier 	FILE *fp;
15823e12c5d1SDavid du Colombier 	Cell *x;
15837dd7cddfSDavid du Colombier 	char *fname;
15843e12c5d1SDavid du Colombier 
15853e12c5d1SDavid du Colombier 	x = execute(b);
15863e12c5d1SDavid du Colombier 	fname = getsval(x);
15873e12c5d1SDavid du Colombier 	fp = openfile(a, fname);
15883e12c5d1SDavid du Colombier 	if (fp == NULL)
15897dd7cddfSDavid du Colombier 		FATAL("can't open file %s", fname);
15903e12c5d1SDavid du Colombier 	tempfree(x);
15913e12c5d1SDavid du Colombier 	return fp;
15923e12c5d1SDavid du Colombier }
15933e12c5d1SDavid du Colombier 
1594219b2ee8SDavid du Colombier struct files {
1595219b2ee8SDavid du Colombier 	FILE	*fp;
15967dd7cddfSDavid du Colombier 	char	*fname;
1597219b2ee8SDavid du Colombier 	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
1598219b2ee8SDavid du Colombier } files[FOPEN_MAX] ={
15997dd7cddfSDavid du Colombier 	{ NULL,  "/dev/stdin",  LT },	/* watch out: don't free this! */
16007dd7cddfSDavid du Colombier 	{ NULL, "/dev/stdout", GT },
16017dd7cddfSDavid du Colombier 	{ NULL, "/dev/stderr", GT }
1602219b2ee8SDavid du Colombier };
1603219b2ee8SDavid du Colombier 
16047dd7cddfSDavid du Colombier void stdinit(void)	/* in case stdin, etc., are not constants */
16053e12c5d1SDavid du Colombier {
16067dd7cddfSDavid du Colombier 	files[0].fp = stdin;
16077dd7cddfSDavid du Colombier 	files[1].fp = stdout;
16087dd7cddfSDavid du Colombier 	files[2].fp = stderr;
16097dd7cddfSDavid du Colombier }
16107dd7cddfSDavid du Colombier 
16117dd7cddfSDavid du Colombier FILE *openfile(int a, char *us)
16127dd7cddfSDavid du Colombier {
16137dd7cddfSDavid du Colombier 	char *s = us;
16147dd7cddfSDavid du Colombier 	int i, m;
16157dd7cddfSDavid du Colombier 	FILE *fp = 0;
16163e12c5d1SDavid du Colombier 
16173e12c5d1SDavid du Colombier 	if (*s == '\0')
16187dd7cddfSDavid du Colombier 		FATAL("null file name in print or getline");
16193e12c5d1SDavid du Colombier 	for (i=0; i < FOPEN_MAX; i++)
16207dd7cddfSDavid du Colombier 		if (files[i].fname && strcmp(s, files[i].fname) == 0) {
16217dd7cddfSDavid du Colombier 			if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
16223e12c5d1SDavid du Colombier 				return files[i].fp;
16237dd7cddfSDavid du Colombier 			if (a == FFLUSH)
16247dd7cddfSDavid du Colombier 				return files[i].fp;
16257dd7cddfSDavid du Colombier 		}
16267dd7cddfSDavid du Colombier 	if (a == FFLUSH)	/* didn't find it, so don't create it! */
16277dd7cddfSDavid du Colombier 		return NULL;
16287dd7cddfSDavid du Colombier 
16293e12c5d1SDavid du Colombier 	for (i=0; i < FOPEN_MAX; i++)
16303e12c5d1SDavid du Colombier 		if (files[i].fp == 0)
16313e12c5d1SDavid du Colombier 			break;
16323e12c5d1SDavid du Colombier 	if (i >= FOPEN_MAX)
16337dd7cddfSDavid du Colombier 		FATAL("%s makes too many open files", s);
16343e12c5d1SDavid du Colombier 	fflush(stdout);	/* force a semblance of order */
16353e12c5d1SDavid du Colombier 	m = a;
16363e12c5d1SDavid du Colombier 	if (a == GT) {
1637219b2ee8SDavid du Colombier 		fp = fopen(s, "w");
16383e12c5d1SDavid du Colombier 	} else if (a == APPEND) {
1639219b2ee8SDavid du Colombier 		fp = fopen(s, "a");
16403e12c5d1SDavid du Colombier 		m = GT;	/* so can mix > and >> */
16413e12c5d1SDavid du Colombier 	} else if (a == '|') {	/* output pipe */
1642219b2ee8SDavid du Colombier 		fp = popen(s, "w");
16433e12c5d1SDavid du Colombier 	} else if (a == LE) {	/* input pipe */
1644219b2ee8SDavid du Colombier 		fp = popen(s, "r");
16453e12c5d1SDavid du Colombier 	} else if (a == LT) {	/* getline <file */
1646219b2ee8SDavid du Colombier 		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
16473e12c5d1SDavid du Colombier 	} else	/* can't happen */
16487dd7cddfSDavid du Colombier 		FATAL("illegal redirection %d", a);
16493e12c5d1SDavid du Colombier 	if (fp != NULL) {
16503e12c5d1SDavid du Colombier 		files[i].fname = tostring(s);
16513e12c5d1SDavid du Colombier 		files[i].fp = fp;
16523e12c5d1SDavid du Colombier 		files[i].mode = m;
16533e12c5d1SDavid du Colombier 	}
16543e12c5d1SDavid du Colombier 	return fp;
16553e12c5d1SDavid du Colombier }
16563e12c5d1SDavid du Colombier 
16577dd7cddfSDavid du Colombier char *filename(FILE *fp)
16583e12c5d1SDavid du Colombier {
16593e12c5d1SDavid du Colombier 	int i;
16603e12c5d1SDavid du Colombier 
16613e12c5d1SDavid du Colombier 	for (i = 0; i < FOPEN_MAX; i++)
16623e12c5d1SDavid du Colombier 		if (fp == files[i].fp)
16633e12c5d1SDavid du Colombier 			return files[i].fname;
1664219b2ee8SDavid du Colombier 	return "???";
16653e12c5d1SDavid du Colombier }
16663e12c5d1SDavid du Colombier 
16673e12c5d1SDavid du Colombier Cell *closefile(Node **a, int n)
16683e12c5d1SDavid du Colombier {
16697dd7cddfSDavid du Colombier 	Cell *x;
16703e12c5d1SDavid du Colombier 	int i, stat;
16713e12c5d1SDavid du Colombier 
16727dd7cddfSDavid du Colombier 	n = n;
16733e12c5d1SDavid du Colombier 	x = execute(a[0]);
16743e12c5d1SDavid du Colombier 	getsval(x);
16753e12c5d1SDavid du Colombier 	for (i = 0; i < FOPEN_MAX; i++)
16763e12c5d1SDavid du Colombier 		if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
16773e12c5d1SDavid du Colombier 			if (ferror(files[i].fp))
16787dd7cddfSDavid du Colombier 				WARNING( "i/o error occurred on %s", files[i].fname );
16793e12c5d1SDavid du Colombier 			if (files[i].mode == '|' || files[i].mode == LE)
16803e12c5d1SDavid du Colombier 				stat = pclose(files[i].fp);
16813e12c5d1SDavid du Colombier 			else
16823e12c5d1SDavid du Colombier 				stat = fclose(files[i].fp);
16833e12c5d1SDavid du Colombier 			if (stat == EOF)
16847dd7cddfSDavid du Colombier 				WARNING( "i/o error occurred closing %s", files[i].fname );
1685219b2ee8SDavid du Colombier 			if (i > 2)	/* don't do /dev/std... */
16863e12c5d1SDavid du Colombier 				xfree(files[i].fname);
16873e12c5d1SDavid du Colombier 			files[i].fname = NULL;	/* watch out for ref thru this */
16883e12c5d1SDavid du Colombier 			files[i].fp = NULL;
16893e12c5d1SDavid du Colombier 		}
16903e12c5d1SDavid du Colombier 	tempfree(x);
16917dd7cddfSDavid du Colombier 	return(True);
16923e12c5d1SDavid du Colombier }
16933e12c5d1SDavid du Colombier 
16943e12c5d1SDavid du Colombier void closeall(void)
16953e12c5d1SDavid du Colombier {
16963e12c5d1SDavid du Colombier 	int i, stat;
16973e12c5d1SDavid du Colombier 
16983e12c5d1SDavid du Colombier 	for (i = 0; i < FOPEN_MAX; i++)
16993e12c5d1SDavid du Colombier 		if (files[i].fp) {
17003e12c5d1SDavid du Colombier 			if (ferror(files[i].fp))
17017dd7cddfSDavid du Colombier 				WARNING( "i/o error occurred on %s", files[i].fname );
17023e12c5d1SDavid du Colombier 			if (files[i].mode == '|' || files[i].mode == LE)
17033e12c5d1SDavid du Colombier 				stat = pclose(files[i].fp);
17043e12c5d1SDavid du Colombier 			else
17053e12c5d1SDavid du Colombier 				stat = fclose(files[i].fp);
17063e12c5d1SDavid du Colombier 			if (stat == EOF)
17077dd7cddfSDavid du Colombier 				WARNING( "i/o error occurred while closing %s", files[i].fname );
17083e12c5d1SDavid du Colombier 		}
17093e12c5d1SDavid du Colombier }
17103e12c5d1SDavid du Colombier 
17117dd7cddfSDavid du Colombier void backsub(char **pb_ptr, char **sptr_ptr);
17123e12c5d1SDavid du Colombier 
1713219b2ee8SDavid du Colombier Cell *sub(Node **a, int nnn)	/* substitute command */
17143e12c5d1SDavid du Colombier {
17157dd7cddfSDavid du Colombier 	char *sptr, *pb, *q;
17167dd7cddfSDavid du Colombier 	Cell *x, *y, *result;
17177dd7cddfSDavid du Colombier 	char *t, *buf;
17183e12c5d1SDavid du Colombier 	void *p;
17197dd7cddfSDavid du Colombier 	int bufsz = recsize;
17203e12c5d1SDavid du Colombier 
17217dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL)
17227dd7cddfSDavid du Colombier 		FATAL("out of memory in sub");
17233e12c5d1SDavid du Colombier 	x = execute(a[3]);	/* target string */
17243e12c5d1SDavid du Colombier 	t = getsval(x);
1725219b2ee8SDavid du Colombier 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
17263e12c5d1SDavid du Colombier 		p = (void *) a[1];	/* regular expression */
17273e12c5d1SDavid du Colombier 	else {
17283e12c5d1SDavid du Colombier 		y = execute(a[1]);
17293e12c5d1SDavid du Colombier 		p = compre(getsval(y));
17303e12c5d1SDavid du Colombier 		tempfree(y);
17313e12c5d1SDavid du Colombier 	}
17323e12c5d1SDavid du Colombier 	y = execute(a[2]);	/* replacement string */
17337dd7cddfSDavid du Colombier 	result = False;
17343e12c5d1SDavid du Colombier 	if (pmatch(p, t, t)) {
17353e12c5d1SDavid du Colombier 		sptr = t;
17367dd7cddfSDavid du Colombier 		adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
17377dd7cddfSDavid du Colombier 		pb = buf;
17383e12c5d1SDavid du Colombier 		while (sptr < patbeg)
17393e12c5d1SDavid du Colombier 			*pb++ = *sptr++;
17403e12c5d1SDavid du Colombier 		sptr = getsval(y);
17417dd7cddfSDavid du Colombier 		while (*sptr != 0) {
17427dd7cddfSDavid du Colombier 			adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
17437dd7cddfSDavid du Colombier 			if (*sptr == '\\') {
17447dd7cddfSDavid du Colombier 				backsub(&pb, &sptr);
17453e12c5d1SDavid du Colombier 			} else if (*sptr == '&') {
17463e12c5d1SDavid du Colombier 				sptr++;
17477dd7cddfSDavid du Colombier 				adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
17483e12c5d1SDavid du Colombier 				for (q = patbeg; q < patbeg+patlen; )
17493e12c5d1SDavid du Colombier 					*pb++ = *q++;
17503e12c5d1SDavid du Colombier 			} else
17513e12c5d1SDavid du Colombier 				*pb++ = *sptr++;
17527dd7cddfSDavid du Colombier 		}
17533e12c5d1SDavid du Colombier 		*pb = '\0';
17547dd7cddfSDavid du Colombier 		if (pb > buf + bufsz)
17557dd7cddfSDavid du Colombier 			FATAL("sub result1 %.30s too big; can't happen", buf);
17563e12c5d1SDavid du Colombier 		sptr = patbeg + patlen;
17577dd7cddfSDavid du Colombier 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
17587dd7cddfSDavid du Colombier 			adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
17597dd7cddfSDavid du Colombier 			while ((*pb++ = *sptr++) != 0)
17603e12c5d1SDavid du Colombier 				;
17617dd7cddfSDavid du Colombier 		}
17627dd7cddfSDavid du Colombier 		if (pb > buf + bufsz)
17637dd7cddfSDavid du Colombier 			FATAL("sub result2 %.30s too big; can't happen", buf);
17647dd7cddfSDavid du Colombier 		setsval(x, buf);	/* BUG: should be able to avoid copy */
17657dd7cddfSDavid du Colombier 		result = True;;
17663e12c5d1SDavid du Colombier 	}
17673e12c5d1SDavid du Colombier 	tempfree(x);
17683e12c5d1SDavid du Colombier 	tempfree(y);
17697dd7cddfSDavid du Colombier 	free(buf);
17703e12c5d1SDavid du Colombier 	return result;
17713e12c5d1SDavid du Colombier }
17723e12c5d1SDavid du Colombier 
1773219b2ee8SDavid du Colombier Cell *gsub(Node **a, int nnn)	/* global substitute */
17743e12c5d1SDavid du Colombier {
17757dd7cddfSDavid du Colombier 	Cell *x, *y;
17767dd7cddfSDavid du Colombier 	char *rptr, *sptr, *t, *pb, *c;
17777dd7cddfSDavid du Colombier 	char *buf;
17787dd7cddfSDavid du Colombier 	void *p;
17793e12c5d1SDavid du Colombier 	int mflag, num;
17807dd7cddfSDavid du Colombier 	int bufsz = recsize;
17813e12c5d1SDavid du Colombier 
17827dd7cddfSDavid du Colombier 	if ((buf = (char *)malloc(bufsz)) == NULL)
17837dd7cddfSDavid du Colombier 		FATAL("out of memory in gsub");
17843e12c5d1SDavid du Colombier 	mflag = 0;	/* if mflag == 0, can replace empty string */
17853e12c5d1SDavid du Colombier 	num = 0;
17863e12c5d1SDavid du Colombier 	x = execute(a[3]);	/* target string */
17873e12c5d1SDavid du Colombier 	c = 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 */
17963e12c5d1SDavid du Colombier 	if (pmatch(p, t, c)) {
17973e12c5d1SDavid du Colombier 		pb = buf;
17983e12c5d1SDavid du Colombier 		rptr = getsval(y);
17993e12c5d1SDavid du Colombier 		do {
18003e12c5d1SDavid du Colombier 			if (patlen == 0 && *patbeg != 0) {	/* matched empty string */
18013e12c5d1SDavid du Colombier 				if (mflag == 0) {	/* can replace empty */
18023e12c5d1SDavid du Colombier 					num++;
18033e12c5d1SDavid du Colombier 					sptr = rptr;
18047dd7cddfSDavid du Colombier 					while (*sptr != 0) {
18057dd7cddfSDavid du Colombier 						adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
18067dd7cddfSDavid du Colombier 						if (*sptr == '\\') {
18077dd7cddfSDavid du Colombier 							backsub(&pb, &sptr);
18083e12c5d1SDavid du Colombier 						} else if (*sptr == '&') {
18097dd7cddfSDavid du Colombier 							char *q;
18103e12c5d1SDavid du Colombier 							sptr++;
18117dd7cddfSDavid du Colombier 							adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
18123e12c5d1SDavid du Colombier 							for (q = patbeg; q < patbeg+patlen; )
18133e12c5d1SDavid du Colombier 								*pb++ = *q++;
18143e12c5d1SDavid du Colombier 						} else
18153e12c5d1SDavid du Colombier 							*pb++ = *sptr++;
18163e12c5d1SDavid du Colombier 					}
18177dd7cddfSDavid du Colombier 				}
18183e12c5d1SDavid du Colombier 				if (*c == 0)	/* at end */
18193e12c5d1SDavid du Colombier 					goto done;
18207dd7cddfSDavid du Colombier 				adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
18213e12c5d1SDavid du Colombier 				*pb++ = *c++;
18227dd7cddfSDavid du Colombier 				if (pb > buf + bufsz)	/* BUG: not sure of this test */
18237dd7cddfSDavid du Colombier 					FATAL("gsub result0 %.30s too big; can't happen", buf);
18243e12c5d1SDavid du Colombier 				mflag = 0;
18253e12c5d1SDavid du Colombier 			}
18263e12c5d1SDavid du Colombier 			else {	/* matched nonempty string */
18273e12c5d1SDavid du Colombier 				num++;
18283e12c5d1SDavid du Colombier 				sptr = c;
18297dd7cddfSDavid du Colombier 				adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
18307dd7cddfSDavid du Colombier 				while (sptr < patbeg)
18313e12c5d1SDavid du Colombier 					*pb++ = *sptr++;
18323e12c5d1SDavid du Colombier 				sptr = rptr;
18337dd7cddfSDavid du Colombier 				while (*sptr != 0) {
18347dd7cddfSDavid du Colombier 					adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
18357dd7cddfSDavid du Colombier 					if (*sptr == '\\') {
18367dd7cddfSDavid du Colombier 						backsub(&pb, &sptr);
18373e12c5d1SDavid du Colombier 					} else if (*sptr == '&') {
18387dd7cddfSDavid du Colombier 						char *q;
18393e12c5d1SDavid du Colombier 						sptr++;
18407dd7cddfSDavid du Colombier 						adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
18413e12c5d1SDavid du Colombier 						for (q = patbeg; q < patbeg+patlen; )
18423e12c5d1SDavid du Colombier 							*pb++ = *q++;
18433e12c5d1SDavid du Colombier 					} else
18443e12c5d1SDavid du Colombier 						*pb++ = *sptr++;
18457dd7cddfSDavid du Colombier 				}
18463e12c5d1SDavid du Colombier 				c = patbeg + patlen;
18473e12c5d1SDavid du Colombier 				if ((c[-1] == 0) || (*c == 0))
18483e12c5d1SDavid du Colombier 					goto done;
18497dd7cddfSDavid du Colombier 				if (pb > buf + bufsz)
18507dd7cddfSDavid du Colombier 					FATAL("gsub result1 %.30s too big; can't happen", buf);
18513e12c5d1SDavid du Colombier 				mflag = 1;
18523e12c5d1SDavid du Colombier 			}
18533e12c5d1SDavid du Colombier 		} while (pmatch(p, t, c));
18543e12c5d1SDavid du Colombier 		sptr = c;
18557dd7cddfSDavid du Colombier 		adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
18567dd7cddfSDavid du Colombier 		while ((*pb++ = *sptr++) != 0)
18573e12c5d1SDavid du Colombier 			;
18587dd7cddfSDavid du Colombier 	done:	if (pb > buf + bufsz)
18597dd7cddfSDavid du Colombier 			FATAL("gsub result2 %.30s too big; can't happen", buf);
18603e12c5d1SDavid du Colombier 		*pb = '\0';
18617dd7cddfSDavid du Colombier 		setsval(x, buf);	/* BUG: should be able to avoid copy + free */
18623e12c5d1SDavid du Colombier 	}
18633e12c5d1SDavid du Colombier 	tempfree(x);
18643e12c5d1SDavid du Colombier 	tempfree(y);
18653e12c5d1SDavid du Colombier 	x = gettemp();
18663e12c5d1SDavid du Colombier 	x->tval = NUM;
18673e12c5d1SDavid du Colombier 	x->fval = num;
18687dd7cddfSDavid du Colombier 	free(buf);
18693e12c5d1SDavid du Colombier 	return(x);
18703e12c5d1SDavid du Colombier }
18717dd7cddfSDavid du Colombier 
18727dd7cddfSDavid du Colombier void backsub(char **pb_ptr, char **sptr_ptr)	/* handle \\& variations */
18737dd7cddfSDavid du Colombier {						/* sptr[0] == '\\' */
18747dd7cddfSDavid du Colombier 	char *pb = *pb_ptr, *sptr = *sptr_ptr;
18757dd7cddfSDavid du Colombier 
18767dd7cddfSDavid du Colombier 	if (sptr[1] == '\\') {
18777dd7cddfSDavid du Colombier 		if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
18787dd7cddfSDavid du Colombier 			*pb++ = '\\';
18797dd7cddfSDavid du Colombier 			*pb++ = '&';
18807dd7cddfSDavid du Colombier 			sptr += 4;
18817dd7cddfSDavid du Colombier 		} else if (sptr[2] == '&') {	/* \\& -> \ + matched */
18827dd7cddfSDavid du Colombier 			*pb++ = '\\';
18837dd7cddfSDavid du Colombier 			sptr += 2;
18847dd7cddfSDavid du Colombier 		} else {			/* \\x -> \\x */
18857dd7cddfSDavid du Colombier 			*pb++ = *sptr++;
18867dd7cddfSDavid du Colombier 			*pb++ = *sptr++;
18877dd7cddfSDavid du Colombier 		}
18887dd7cddfSDavid du Colombier 	} else if (sptr[1] == '&') {	/* literal & */
18897dd7cddfSDavid du Colombier 		sptr++;
18907dd7cddfSDavid du Colombier 		*pb++ = *sptr++;
18917dd7cddfSDavid du Colombier 	} else				/* literal \ */
18927dd7cddfSDavid du Colombier 		*pb++ = *sptr++;
18937dd7cddfSDavid du Colombier 
18947dd7cddfSDavid du Colombier 	*pb_ptr = pb;
18957dd7cddfSDavid du Colombier 	*sptr_ptr = sptr;
18967dd7cddfSDavid du Colombier }
1897