xref: /plan9/sys/src/cmd/awk/run.c (revision 4eeb7838088f142e2f04f339bee572170b6e8c6b)
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>
33535404a9SDavid du Colombier #include <utf.h>
343e12c5d1SDavid du Colombier #include "awk.h"
353e12c5d1SDavid du Colombier #include "y.tab.h"
363e12c5d1SDavid du Colombier 
377dd7cddfSDavid du Colombier #define tempfree(x)	if (istemp(x)) tfree(x); else
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier /*
407dd7cddfSDavid du Colombier #undef tempfree
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier void tempfree(Cell *p) {
437dd7cddfSDavid du Colombier 	if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
447dd7cddfSDavid du Colombier 		WARNING("bad csub %d in Cell %d %s",
457dd7cddfSDavid du Colombier 			p->csub, p->ctype, p->sval);
467dd7cddfSDavid du Colombier 	}
477dd7cddfSDavid du Colombier 	if (istemp(p))
487dd7cddfSDavid du Colombier 		tfree(p);
497dd7cddfSDavid du Colombier }
507dd7cddfSDavid du Colombier */
517dd7cddfSDavid du Colombier 
523e12c5d1SDavid du Colombier #ifdef _NFILE
533e12c5d1SDavid du Colombier #ifndef FOPEN_MAX
543e12c5d1SDavid du Colombier #define FOPEN_MAX _NFILE
553e12c5d1SDavid du Colombier #endif
563e12c5d1SDavid du Colombier #endif
573e12c5d1SDavid du Colombier 
583e12c5d1SDavid du Colombier #ifndef	FOPEN_MAX
593e12c5d1SDavid du Colombier #define	FOPEN_MAX	40	/* max number of open files */
603e12c5d1SDavid du Colombier #endif
613e12c5d1SDavid du Colombier 
623e12c5d1SDavid du Colombier #ifndef RAND_MAX
633e12c5d1SDavid du Colombier #define RAND_MAX	32767	/* all that ansi guarantees */
643e12c5d1SDavid du Colombier #endif
653e12c5d1SDavid du Colombier 
663e12c5d1SDavid du Colombier jmp_buf env;
677dd7cddfSDavid du Colombier extern	int	pairstack[];
68219b2ee8SDavid du Colombier 
69219b2ee8SDavid du Colombier Node	*winner = NULL;	/* root of parse tree */
70219b2ee8SDavid du Colombier Cell	*tmps;		/* free temporary cells for execution */
713e12c5d1SDavid du Colombier 
723e12c5d1SDavid du Colombier static Cell	truecell	={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
737dd7cddfSDavid du Colombier Cell	*True	= &truecell;
743e12c5d1SDavid du Colombier static Cell	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
757dd7cddfSDavid du Colombier Cell	*False	= &falsecell;
763e12c5d1SDavid du Colombier static Cell	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
773e12c5d1SDavid du Colombier Cell	*jbreak	= &breakcell;
783e12c5d1SDavid du Colombier static Cell	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM };
793e12c5d1SDavid du Colombier Cell	*jcont	= &contcell;
803e12c5d1SDavid du Colombier static Cell	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
813e12c5d1SDavid du Colombier Cell	*jnext	= &nextcell;
827dd7cddfSDavid du Colombier static Cell	nextfilecell	={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
837dd7cddfSDavid du Colombier Cell	*jnextfile	= &nextfilecell;
843e12c5d1SDavid du Colombier static Cell	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
853e12c5d1SDavid du Colombier Cell	*jexit	= &exitcell;
863e12c5d1SDavid du Colombier static Cell	retcell		={ OJUMP, JRET, 0, 0, 0.0, NUM };
873e12c5d1SDavid du Colombier Cell	*jret	= &retcell;
887dd7cddfSDavid du Colombier static Cell	tempcell	={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
893e12c5d1SDavid du Colombier 
903e12c5d1SDavid du Colombier Node	*curnode = NULL;	/* the node being executed, for debugging */
913e12c5d1SDavid du Colombier 
927dd7cddfSDavid du Colombier /* buffer memory management */
adjbuf(char ** pbuf,int * psiz,int minlen,int quantum,char ** pbptr,char * whatrtn)937dd7cddfSDavid du Colombier int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
947dd7cddfSDavid du Colombier 	char *whatrtn)
957dd7cddfSDavid du Colombier /* pbuf:    address of pointer to buffer being managed
967dd7cddfSDavid du Colombier  * psiz:    address of buffer size variable
977dd7cddfSDavid du Colombier  * minlen:  minimum length of buffer needed
987dd7cddfSDavid du Colombier  * quantum: buffer size quantum
997dd7cddfSDavid du Colombier  * pbptr:   address of movable pointer into buffer, or 0 if none
1007dd7cddfSDavid du Colombier  * whatrtn: name of the calling routine if failure should cause fatal error
1017dd7cddfSDavid du Colombier  *
1027dd7cddfSDavid du Colombier  * return   0 for realloc failure, !=0 for success
1037dd7cddfSDavid du Colombier  */
1047dd7cddfSDavid du Colombier {
1057dd7cddfSDavid du Colombier 	if (minlen > *psiz) {
1067dd7cddfSDavid du Colombier 		char *tbuf;
1077dd7cddfSDavid du Colombier 		int rminlen = quantum ? minlen % quantum : 0;
1087dd7cddfSDavid du Colombier 		int boff = pbptr ? *pbptr - *pbuf : 0;
1097dd7cddfSDavid du Colombier 		/* round up to next multiple of quantum */
1107dd7cddfSDavid du Colombier 		if (rminlen)
1117dd7cddfSDavid du Colombier 			minlen += quantum - rminlen;
1127dd7cddfSDavid du Colombier 		tbuf = (char *) realloc(*pbuf, minlen);
1137dd7cddfSDavid du Colombier 		if (tbuf == NULL) {
1147dd7cddfSDavid du Colombier 			if (whatrtn)
1157dd7cddfSDavid du Colombier 				FATAL("out of memory in %s", whatrtn);
1167dd7cddfSDavid du Colombier 			return 0;
1177dd7cddfSDavid du Colombier 		}
1187dd7cddfSDavid du Colombier 		*pbuf = tbuf;
1197dd7cddfSDavid du Colombier 		*psiz = minlen;
1207dd7cddfSDavid du Colombier 		if (pbptr)
1217dd7cddfSDavid du Colombier 			*pbptr = tbuf + boff;
1227dd7cddfSDavid du Colombier 	}
1237dd7cddfSDavid du Colombier 	return 1;
1247dd7cddfSDavid du Colombier }
1257dd7cddfSDavid du Colombier 
run(Node * a)126219b2ee8SDavid du Colombier void run(Node *a)	/* execution of parse tree starts here */
1273e12c5d1SDavid du Colombier {
1287dd7cddfSDavid du Colombier 	extern void stdinit(void);
1297dd7cddfSDavid du Colombier 
1307dd7cddfSDavid du Colombier 	stdinit();
1313e12c5d1SDavid du Colombier 	execute(a);
1323e12c5d1SDavid du Colombier 	closeall();
1333e12c5d1SDavid du Colombier }
1343e12c5d1SDavid du Colombier 
execute(Node * u)1357dd7cddfSDavid du Colombier Cell *execute(Node *u)	/* execute a node of the parse tree */
1363e12c5d1SDavid du Colombier {
13705bfb676SDavid du Colombier 	int nobj;
1387dd7cddfSDavid du Colombier 	Cell *(*proc)(Node **, int);
1397dd7cddfSDavid du Colombier 	Cell *x;
1407dd7cddfSDavid du Colombier 	Node *a;
1413e12c5d1SDavid du Colombier 
1423e12c5d1SDavid du Colombier 	if (u == NULL)
1437dd7cddfSDavid du Colombier 		return(True);
1443e12c5d1SDavid du Colombier 	for (a = u; ; a = a->nnext) {
1453e12c5d1SDavid du Colombier 		curnode = a;
1463e12c5d1SDavid du Colombier 		if (isvalue(a)) {
1473e12c5d1SDavid du Colombier 			x = (Cell *) (a->narg[0]);
1487dd7cddfSDavid du Colombier 			if (isfld(x) && !donefld)
1493e12c5d1SDavid du Colombier 				fldbld();
1507dd7cddfSDavid du Colombier 			else if (isrec(x) && !donerec)
1513e12c5d1SDavid du Colombier 				recbld();
1523e12c5d1SDavid du Colombier 			return(x);
1533e12c5d1SDavid du Colombier 		}
15405bfb676SDavid du Colombier 		nobj = a->nobj;
15505bfb676SDavid du Colombier 		if (notlegal(nobj))	/* probably a Cell* but too risky to print */
1567dd7cddfSDavid du Colombier 			FATAL("illegal statement");
15705bfb676SDavid du Colombier 		proc = proctab[nobj-FIRSTTOKEN];
15805bfb676SDavid du Colombier 		x = (*proc)(a->narg, nobj);
1597dd7cddfSDavid du Colombier 		if (isfld(x) && !donefld)
1603e12c5d1SDavid du Colombier 			fldbld();
1617dd7cddfSDavid du Colombier 		else if (isrec(x) && !donerec)
1623e12c5d1SDavid du Colombier 			recbld();
1633e12c5d1SDavid du Colombier 		if (isexpr(a))
1643e12c5d1SDavid du Colombier 			return(x);
1653e12c5d1SDavid du Colombier 		if (isjump(x))
1663e12c5d1SDavid du Colombier 			return(x);
1673e12c5d1SDavid du Colombier 		if (a->nnext == NULL)
1683e12c5d1SDavid du Colombier 			return(x);
1693e12c5d1SDavid du Colombier 		tempfree(x);
1703e12c5d1SDavid du Colombier 	}
1713e12c5d1SDavid du Colombier }
1723e12c5d1SDavid du Colombier 
1733e12c5d1SDavid du Colombier 
program(Node ** a,int n)174219b2ee8SDavid du Colombier Cell *program(Node **a, int n)	/* execute an awk program */
175219b2ee8SDavid du Colombier {				/* a[0] = BEGIN, a[1] = body, a[2] = END */
1767dd7cddfSDavid du Colombier 	Cell *x;
1773e12c5d1SDavid du Colombier 
1783e12c5d1SDavid du Colombier 	if (setjmp(env) != 0)
1793e12c5d1SDavid du Colombier 		goto ex;
1803e12c5d1SDavid du Colombier 	if (a[0]) {		/* BEGIN */
1813e12c5d1SDavid du Colombier 		x = execute(a[0]);
1823e12c5d1SDavid du Colombier 		if (isexit(x))
1837dd7cddfSDavid du Colombier 			return(True);
1843e12c5d1SDavid du Colombier 		if (isjump(x))
1857dd7cddfSDavid du Colombier 			FATAL("illegal break, continue, next or nextfile from BEGIN");
1863e12c5d1SDavid du Colombier 		tempfree(x);
1873e12c5d1SDavid du Colombier 	}
1883e12c5d1SDavid du Colombier 	if (a[1] || a[2])
1897dd7cddfSDavid du Colombier 		while (getrec(&record, &recsize, 1) > 0) {
1903e12c5d1SDavid du Colombier 			x = execute(a[1]);
1913e12c5d1SDavid du Colombier 			if (isexit(x))
1923e12c5d1SDavid du Colombier 				break;
1933e12c5d1SDavid du Colombier 			tempfree(x);
1943e12c5d1SDavid du Colombier 		}
1953e12c5d1SDavid du Colombier   ex:
1963e12c5d1SDavid du Colombier 	if (setjmp(env) != 0)	/* handles exit within END */
1973e12c5d1SDavid du Colombier 		goto ex1;
1983e12c5d1SDavid du Colombier 	if (a[2]) {		/* END */
1993e12c5d1SDavid du Colombier 		x = execute(a[2]);
2003e12c5d1SDavid du Colombier 		if (isbreak(x) || isnext(x) || iscont(x))
2017dd7cddfSDavid du Colombier 			FATAL("illegal break, continue, next or nextfile from END");
2023e12c5d1SDavid du Colombier 		tempfree(x);
2033e12c5d1SDavid du Colombier 	}
2043e12c5d1SDavid du Colombier   ex1:
2057dd7cddfSDavid du Colombier 	return(True);
2063e12c5d1SDavid du Colombier }
2073e12c5d1SDavid du Colombier 
208219b2ee8SDavid du Colombier struct Frame {	/* stack frame for awk function calls */
2093e12c5d1SDavid du Colombier 	int nargs;	/* number of arguments in this call */
2103e12c5d1SDavid du Colombier 	Cell *fcncell;	/* pointer to Cell for function */
2113e12c5d1SDavid du Colombier 	Cell **args;	/* pointer to array of arguments after execute */
2123e12c5d1SDavid du Colombier 	Cell *retval;	/* return value */
2133e12c5d1SDavid du Colombier };
2143e12c5d1SDavid du Colombier 
215219b2ee8SDavid du Colombier #define	NARGS	50	/* max args in a call */
2163e12c5d1SDavid du Colombier 
2173e12c5d1SDavid du Colombier struct Frame *frame = NULL;	/* base of stack frames; dynamically allocated */
2183e12c5d1SDavid du Colombier int	nframe = 0;		/* number of frames allocated */
2193e12c5d1SDavid du Colombier struct Frame *fp = NULL;	/* frame pointer. bottom level unused */
2203e12c5d1SDavid du Colombier 
call(Node ** a,int n)221219b2ee8SDavid du Colombier Cell *call(Node **a, int n)	/* function call.  very kludgy and fragile */
2223e12c5d1SDavid du Colombier {
2237dd7cddfSDavid du Colombier 	static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
2243e12c5d1SDavid du Colombier 	int i, ncall, ndef;
2253e12c5d1SDavid du Colombier 	Node *x;
2267dd7cddfSDavid du Colombier 	Cell *args[NARGS], *oargs[NARGS];	/* BUG: fixed size arrays */
2277dd7cddfSDavid du Colombier 	Cell *y, *z, *fcn;
2287dd7cddfSDavid du Colombier 	char *s;
2293e12c5d1SDavid du Colombier 
2303e12c5d1SDavid du Colombier 	fcn = execute(a[0]);	/* the function itself */
2313e12c5d1SDavid du Colombier 	s = fcn->nval;
2327dd7cddfSDavid du Colombier 	if (!isfcn(fcn))
2337dd7cddfSDavid du Colombier 		FATAL("calling undefined function %s", s);
2343e12c5d1SDavid du Colombier 	if (frame == NULL) {
2353e12c5d1SDavid du Colombier 		fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
2363e12c5d1SDavid du Colombier 		if (frame == NULL)
2377dd7cddfSDavid du Colombier 			FATAL("out of space for stack frames calling %s", s);
2383e12c5d1SDavid du Colombier 	}
2393e12c5d1SDavid du Colombier 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)	/* args in call */
2403e12c5d1SDavid du Colombier 		ncall++;
2413e12c5d1SDavid du Colombier 	ndef = (int) fcn->fval;			/* args in defn */
2427dd7cddfSDavid du Colombier 	   dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
2433e12c5d1SDavid du Colombier 	if (ncall > ndef)
2447dd7cddfSDavid du Colombier 		WARNING("function %s called with %d args, uses only %d",
2457dd7cddfSDavid du Colombier 			s, ncall, ndef);
2463e12c5d1SDavid du Colombier 	if (ncall + ndef > NARGS)
2477dd7cddfSDavid du Colombier 		FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
2483e12c5d1SDavid du Colombier 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {	/* get call args */
2497dd7cddfSDavid du Colombier 		   dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
2503e12c5d1SDavid du Colombier 		y = execute(x);
2513e12c5d1SDavid du Colombier 		oargs[i] = y;
2523e12c5d1SDavid du Colombier 		   dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
2537dd7cddfSDavid du Colombier 			   i, y->nval, y->fval, isarr(y) ? "(array)" : y->sval, y->tval) );
2547dd7cddfSDavid du Colombier 		if (isfcn(y))
2557dd7cddfSDavid du Colombier 			FATAL("can't use function %s as argument in %s", y->nval, s);
2563e12c5d1SDavid du Colombier 		if (isarr(y))
2573e12c5d1SDavid du Colombier 			args[i] = y;	/* arrays by ref */
2583e12c5d1SDavid du Colombier 		else
2593e12c5d1SDavid du Colombier 			args[i] = copycell(y);
2603e12c5d1SDavid du Colombier 		tempfree(y);
2613e12c5d1SDavid du Colombier 	}
2623e12c5d1SDavid du Colombier 	for ( ; i < ndef; i++) {	/* add null args for ones not provided */
2633e12c5d1SDavid du Colombier 		args[i] = gettemp();
2643e12c5d1SDavid du Colombier 		*args[i] = newcopycell;
2653e12c5d1SDavid du Colombier 	}
2663e12c5d1SDavid du Colombier 	fp++;	/* now ok to up frame */
2673e12c5d1SDavid du Colombier 	if (fp >= frame + nframe) {
2683e12c5d1SDavid du Colombier 		int dfp = fp - frame;	/* old index */
2693e12c5d1SDavid du Colombier 		frame = (struct Frame *)
270219b2ee8SDavid du Colombier 			realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
2713e12c5d1SDavid du Colombier 		if (frame == NULL)
2727dd7cddfSDavid du Colombier 			FATAL("out of space for stack frames in %s", s);
2733e12c5d1SDavid du Colombier 		fp = frame + dfp;
2743e12c5d1SDavid du Colombier 	}
2753e12c5d1SDavid du Colombier 	fp->fcncell = fcn;
2763e12c5d1SDavid du Colombier 	fp->args = args;
2773e12c5d1SDavid du Colombier 	fp->nargs = ndef;	/* number defined with (excess are locals) */
2783e12c5d1SDavid du Colombier 	fp->retval = gettemp();
2793e12c5d1SDavid du Colombier 
2807dd7cddfSDavid du Colombier 	   dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
2813e12c5d1SDavid du Colombier 	y = execute((Node *)(fcn->sval));	/* execute body */
2827dd7cddfSDavid du Colombier 	   dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
2833e12c5d1SDavid du Colombier 
2843e12c5d1SDavid du Colombier 	for (i = 0; i < ndef; i++) {
2853e12c5d1SDavid du Colombier 		Cell *t = fp->args[i];
2863e12c5d1SDavid du Colombier 		if (isarr(t)) {
2873e12c5d1SDavid du Colombier 			if (t->csub == CCOPY) {
2883e12c5d1SDavid du Colombier 				if (i >= ncall) {
2893e12c5d1SDavid du Colombier 					freesymtab(t);
2903e12c5d1SDavid du Colombier 					t->csub = CTEMP;
2917dd7cddfSDavid du Colombier 					tempfree(t);
2923e12c5d1SDavid du Colombier 				} else {
2933e12c5d1SDavid du Colombier 					oargs[i]->tval = t->tval;
2943e12c5d1SDavid du Colombier 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
2953e12c5d1SDavid du Colombier 					oargs[i]->sval = t->sval;
2963e12c5d1SDavid du Colombier 					tempfree(t);
2973e12c5d1SDavid du Colombier 				}
2983e12c5d1SDavid du Colombier 			}
2993e12c5d1SDavid du Colombier 		} else if (t != y) {	/* kludge to prevent freeing twice */
3003e12c5d1SDavid du Colombier 			t->csub = CTEMP;
3013e12c5d1SDavid du Colombier 			tempfree(t);
3023e12c5d1SDavid du Colombier 		}
3033e12c5d1SDavid du Colombier 	}
3043e12c5d1SDavid du Colombier 	tempfree(fcn);
3057dd7cddfSDavid du Colombier 	if (isexit(y) || isnext(y) || isnextfile(y))
3063e12c5d1SDavid du Colombier 		return y;
3073e12c5d1SDavid du Colombier 	tempfree(y);		/* this can free twice! */
3083e12c5d1SDavid du Colombier 	z = fp->retval;			/* return value */
3093e12c5d1SDavid du Colombier 	   dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
3103e12c5d1SDavid du Colombier 	fp--;
3113e12c5d1SDavid du Colombier 	return(z);
3123e12c5d1SDavid du Colombier }
3133e12c5d1SDavid du Colombier 
copycell(Cell * x)3143e12c5d1SDavid du Colombier Cell *copycell(Cell *x)	/* make a copy of a cell in a temp */
3153e12c5d1SDavid du Colombier {
3163e12c5d1SDavid du Colombier 	Cell *y;
3173e12c5d1SDavid du Colombier 
3183e12c5d1SDavid du Colombier 	y = gettemp();
3193e12c5d1SDavid du Colombier 	y->csub = CCOPY;	/* prevents freeing until call is over */
3207dd7cddfSDavid du Colombier 	y->nval = x->nval;	/* BUG? */
3213e12c5d1SDavid du Colombier 	y->sval = x->sval ? tostring(x->sval) : NULL;
3223e12c5d1SDavid du Colombier 	y->fval = x->fval;
3233e12c5d1SDavid du Colombier 	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);	/* copy is not constant or field */
3243e12c5d1SDavid du Colombier 							/* is DONTFREE right? */
3253e12c5d1SDavid du Colombier 	return y;
3263e12c5d1SDavid du Colombier }
3273e12c5d1SDavid du Colombier 
arg(Node ** a,int n)328219b2ee8SDavid du Colombier Cell *arg(Node **a, int n)	/* nth argument of a function */
3293e12c5d1SDavid du Colombier {
3303e12c5d1SDavid du Colombier 
3317dd7cddfSDavid du Colombier 	n = ptoi(a[0]);	/* argument number, counting from 0 */
3323e12c5d1SDavid du Colombier 	   dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
3333e12c5d1SDavid du Colombier 	if (n+1 > fp->nargs)
3347dd7cddfSDavid du Colombier 		FATAL("argument #%d of function %s was not supplied",
3357dd7cddfSDavid du Colombier 			n+1, fp->fcncell->nval);
3363e12c5d1SDavid du Colombier 	return fp->args[n];
3373e12c5d1SDavid du Colombier }
3383e12c5d1SDavid du Colombier 
jump(Node ** a,int n)3397dd7cddfSDavid du Colombier Cell *jump(Node **a, int n)	/* break, continue, next, nextfile, return */
3403e12c5d1SDavid du Colombier {
3417dd7cddfSDavid du Colombier 	Cell *y;
3423e12c5d1SDavid du Colombier 
3433e12c5d1SDavid du Colombier 	switch (n) {
3443e12c5d1SDavid du Colombier 	case EXIT:
3453e12c5d1SDavid du Colombier 		if (a[0] != NULL) {
3463e12c5d1SDavid du Colombier 			y = execute(a[0]);
3477dd7cddfSDavid du Colombier 			errorflag = (int) getfval(y);
3483e12c5d1SDavid du Colombier 			tempfree(y);
3493e12c5d1SDavid du Colombier 		}
3503e12c5d1SDavid du Colombier 		longjmp(env, 1);
3513e12c5d1SDavid du Colombier 	case RETURN:
3523e12c5d1SDavid du Colombier 		if (a[0] != NULL) {
3533e12c5d1SDavid du Colombier 			y = execute(a[0]);
3543e12c5d1SDavid du Colombier 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
3553e12c5d1SDavid du Colombier 				setsval(fp->retval, getsval(y));
3563e12c5d1SDavid du Colombier 				fp->retval->fval = getfval(y);
3573e12c5d1SDavid du Colombier 				fp->retval->tval |= NUM;
3583e12c5d1SDavid du Colombier 			}
3593e12c5d1SDavid du Colombier 			else if (y->tval & STR)
3603e12c5d1SDavid du Colombier 				setsval(fp->retval, getsval(y));
3613e12c5d1SDavid du Colombier 			else if (y->tval & NUM)
3623e12c5d1SDavid du Colombier 				setfval(fp->retval, getfval(y));
3633e12c5d1SDavid du Colombier 			else		/* can't happen */
3647dd7cddfSDavid du Colombier 				FATAL("bad type variable %d", y->tval);
3653e12c5d1SDavid du Colombier 			tempfree(y);
3663e12c5d1SDavid du Colombier 		}
3673e12c5d1SDavid du Colombier 		return(jret);
3683e12c5d1SDavid du Colombier 	case NEXT:
3693e12c5d1SDavid du Colombier 		return(jnext);
3707dd7cddfSDavid du Colombier 	case NEXTFILE:
3717dd7cddfSDavid du Colombier 		nextfile();
3727dd7cddfSDavid du Colombier 		return(jnextfile);
3733e12c5d1SDavid du Colombier 	case BREAK:
3743e12c5d1SDavid du Colombier 		return(jbreak);
3753e12c5d1SDavid du Colombier 	case CONTINUE:
3763e12c5d1SDavid du Colombier 		return(jcont);
3773e12c5d1SDavid du Colombier 	default:	/* can't happen */
3787dd7cddfSDavid du Colombier 		FATAL("illegal jump type %d", n);
3793e12c5d1SDavid du Colombier 	}
3803e12c5d1SDavid du Colombier 	return 0;	/* not reached */
3813e12c5d1SDavid du Colombier }
3823e12c5d1SDavid du Colombier 
getline(Node ** a,int n)383219b2ee8SDavid du Colombier Cell *getline(Node **a, int n)	/* get next line from specific input */
384219b2ee8SDavid du Colombier {		/* a[0] is variable, a[1] is operator, a[2] is filename */
3857dd7cddfSDavid du Colombier 	Cell *r, *x;
3867dd7cddfSDavid du Colombier 	extern Cell **fldtab;
3873e12c5d1SDavid du Colombier 	FILE *fp;
3887dd7cddfSDavid du Colombier 	char *buf;
3897dd7cddfSDavid du Colombier 	int bufsize = recsize;
3907dd7cddfSDavid du Colombier 	int mode;
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsize)) == NULL)
3937dd7cddfSDavid du Colombier 		FATAL("out of memory in getline");
3943e12c5d1SDavid du Colombier 
3953e12c5d1SDavid du Colombier 	fflush(stdout);	/* in case someone is waiting for a prompt */
3963e12c5d1SDavid du Colombier 	r = gettemp();
3973e12c5d1SDavid du Colombier 	if (a[1] != NULL) {		/* getline < file */
3983e12c5d1SDavid du Colombier 		x = execute(a[2]);		/* filename */
3997dd7cddfSDavid du Colombier 		mode = ptoi(a[1]);
4007dd7cddfSDavid du Colombier 		if (mode == '|')		/* input pipe */
4017dd7cddfSDavid du Colombier 			mode = LE;	/* arbitrary flag */
4027dd7cddfSDavid du Colombier 		fp = openfile(mode, getsval(x));
4033e12c5d1SDavid du Colombier 		tempfree(x);
4043e12c5d1SDavid du Colombier 		if (fp == NULL)
4053e12c5d1SDavid du Colombier 			n = -1;
4063e12c5d1SDavid du Colombier 		else
4077dd7cddfSDavid du Colombier 			n = readrec(&buf, &bufsize, fp);
4083e12c5d1SDavid du Colombier 		if (n <= 0) {
4093e12c5d1SDavid du Colombier 			;
4103e12c5d1SDavid du Colombier 		} else if (a[0] != NULL) {	/* getline var <file */
4117dd7cddfSDavid du Colombier 			x = execute(a[0]);
4127dd7cddfSDavid du Colombier 			setsval(x, buf);
4137dd7cddfSDavid du Colombier 			tempfree(x);
4143e12c5d1SDavid du Colombier 		} else {			/* getline <file */
4157dd7cddfSDavid du Colombier 			setsval(fldtab[0], buf);
4167dd7cddfSDavid du Colombier 			if (is_number(fldtab[0]->sval)) {
4177dd7cddfSDavid du Colombier 				fldtab[0]->fval = atof(fldtab[0]->sval);
4187dd7cddfSDavid du Colombier 				fldtab[0]->tval |= NUM;
4193e12c5d1SDavid du Colombier 			}
4203e12c5d1SDavid du Colombier 		}
4213e12c5d1SDavid du Colombier 	} else {			/* bare getline; use current input */
4223e12c5d1SDavid du Colombier 		if (a[0] == NULL)	/* getline */
4237dd7cddfSDavid du Colombier 			n = getrec(&record, &recsize, 1);
4243e12c5d1SDavid du Colombier 		else {			/* getline var */
4257dd7cddfSDavid du Colombier 			n = getrec(&buf, &bufsize, 0);
4267dd7cddfSDavid du Colombier 			x = execute(a[0]);
4277dd7cddfSDavid du Colombier 			setsval(x, buf);
4287dd7cddfSDavid du Colombier 			tempfree(x);
4293e12c5d1SDavid du Colombier 		}
4303e12c5d1SDavid du Colombier 	}
4313e12c5d1SDavid du Colombier 	setfval(r, (Awkfloat) n);
4327dd7cddfSDavid du Colombier 	free(buf);
4333e12c5d1SDavid du Colombier 	return r;
4343e12c5d1SDavid du Colombier }
4353e12c5d1SDavid du Colombier 
getnf(Node ** a,int n)436219b2ee8SDavid du Colombier Cell *getnf(Node **a, int n)	/* get NF */
4373e12c5d1SDavid du Colombier {
4383e12c5d1SDavid du Colombier 	if (donefld == 0)
4393e12c5d1SDavid du Colombier 		fldbld();
4403e12c5d1SDavid du Colombier 	return (Cell *) a[0];
4413e12c5d1SDavid du Colombier }
4423e12c5d1SDavid du Colombier 
array(Node ** a,int n)443219b2ee8SDavid du Colombier Cell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
4443e12c5d1SDavid du Colombier {
4457dd7cddfSDavid du Colombier 	Cell *x, *y, *z;
4467dd7cddfSDavid du Colombier 	char *s;
4477dd7cddfSDavid du Colombier 	Node *np;
4487dd7cddfSDavid du Colombier 	char *buf;
4497dd7cddfSDavid du Colombier 	int bufsz = recsize;
4507dd7cddfSDavid du Colombier 	int nsub = strlen(*SUBSEP);
4517dd7cddfSDavid du Colombier 
4527dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL)
4537dd7cddfSDavid du Colombier 		FATAL("out of memory in array");
4543e12c5d1SDavid du Colombier 
4553e12c5d1SDavid du Colombier 	x = execute(a[0]);	/* Cell* for symbol table */
4563e12c5d1SDavid du Colombier 	buf[0] = 0;
4573e12c5d1SDavid du Colombier 	for (np = a[1]; np; np = np->nnext) {
4583e12c5d1SDavid du Colombier 		y = execute(np);	/* subscript */
4593e12c5d1SDavid du Colombier 		s = getsval(y);
4607dd7cddfSDavid du Colombier 		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
4617dd7cddfSDavid du Colombier 			FATAL("out of memory for %s[%s...]", x->nval, buf);
4623e12c5d1SDavid du Colombier 		strcat(buf, s);
4633e12c5d1SDavid du Colombier 		if (np->nnext)
4643e12c5d1SDavid du Colombier 			strcat(buf, *SUBSEP);
4653e12c5d1SDavid du Colombier 		tempfree(y);
4663e12c5d1SDavid du Colombier 	}
4673e12c5d1SDavid du Colombier 	if (!isarr(x)) {
4683e12c5d1SDavid du Colombier 		   dprintf( ("making %s into an array\n", x->nval) );
4693e12c5d1SDavid du Colombier 		if (freeable(x))
4703e12c5d1SDavid du Colombier 			xfree(x->sval);
4713e12c5d1SDavid du Colombier 		x->tval &= ~(STR|NUM|DONTFREE);
4723e12c5d1SDavid du Colombier 		x->tval |= ARR;
4737dd7cddfSDavid du Colombier 		x->sval = (char *) makesymtab(NSYMTAB);
4743e12c5d1SDavid du Colombier 	}
4753e12c5d1SDavid du Colombier 	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
4763e12c5d1SDavid du Colombier 	z->ctype = OCELL;
4773e12c5d1SDavid du Colombier 	z->csub = CVAR;
4783e12c5d1SDavid du Colombier 	tempfree(x);
4797dd7cddfSDavid du Colombier 	free(buf);
4803e12c5d1SDavid du Colombier 	return(z);
4813e12c5d1SDavid du Colombier }
4823e12c5d1SDavid du Colombier 
awkdelete(Node ** a,int n)4837dd7cddfSDavid du Colombier Cell *awkdelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
4843e12c5d1SDavid du Colombier {
4853e12c5d1SDavid du Colombier 	Cell *x, *y;
4863e12c5d1SDavid du Colombier 	Node *np;
4877dd7cddfSDavid du Colombier 	char *s;
4887dd7cddfSDavid du Colombier 	int nsub = strlen(*SUBSEP);
4893e12c5d1SDavid du Colombier 
4903e12c5d1SDavid du Colombier 	x = execute(a[0]);	/* Cell* for symbol table */
4913e12c5d1SDavid du Colombier 	if (!isarr(x))
4927dd7cddfSDavid du Colombier 		return True;
4937dd7cddfSDavid du Colombier 	if (a[1] == 0) {	/* delete the elements, not the table */
4947dd7cddfSDavid du Colombier 		freesymtab(x);
4957dd7cddfSDavid du Colombier 		x->tval &= ~STR;
4967dd7cddfSDavid du Colombier 		x->tval |= ARR;
4977dd7cddfSDavid du Colombier 		x->sval = (char *) makesymtab(NSYMTAB);
4987dd7cddfSDavid du Colombier 	} else {
4997dd7cddfSDavid du Colombier 		int bufsz = recsize;
5007dd7cddfSDavid du Colombier 		char *buf;
5017dd7cddfSDavid du Colombier 		if ((buf = (char *) malloc(bufsz)) == NULL)
5027dd7cddfSDavid du Colombier 			FATAL("out of memory in adelete");
5033e12c5d1SDavid du Colombier 		buf[0] = 0;
5043e12c5d1SDavid du Colombier 		for (np = a[1]; np; np = np->nnext) {
5053e12c5d1SDavid du Colombier 			y = execute(np);	/* subscript */
5063e12c5d1SDavid du Colombier 			s = getsval(y);
5077dd7cddfSDavid du Colombier 			if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
5087dd7cddfSDavid du Colombier 				FATAL("out of memory deleting %s[%s...]", x->nval, buf);
5093e12c5d1SDavid du Colombier 			strcat(buf, s);
5103e12c5d1SDavid du Colombier 			if (np->nnext)
5113e12c5d1SDavid du Colombier 				strcat(buf, *SUBSEP);
5123e12c5d1SDavid du Colombier 			tempfree(y);
5133e12c5d1SDavid du Colombier 		}
5143e12c5d1SDavid du Colombier 		freeelem(x, buf);
5157dd7cddfSDavid du Colombier 		free(buf);
5167dd7cddfSDavid du Colombier 	}
5173e12c5d1SDavid du Colombier 	tempfree(x);
5187dd7cddfSDavid du Colombier 	return True;
5193e12c5d1SDavid du Colombier }
5203e12c5d1SDavid du Colombier 
intest(Node ** a,int n)521219b2ee8SDavid du Colombier Cell *intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
5223e12c5d1SDavid du Colombier {
5237dd7cddfSDavid du Colombier 	Cell *x, *ap, *k;
5243e12c5d1SDavid du Colombier 	Node *p;
5257dd7cddfSDavid du Colombier 	char *buf;
5267dd7cddfSDavid du Colombier 	char *s;
5277dd7cddfSDavid du Colombier 	int bufsz = recsize;
5287dd7cddfSDavid du Colombier 	int nsub = strlen(*SUBSEP);
5293e12c5d1SDavid du Colombier 
5303e12c5d1SDavid du Colombier 	ap = execute(a[1]);	/* array name */
5313e12c5d1SDavid du Colombier 	if (!isarr(ap)) {
5323e12c5d1SDavid du Colombier 		   dprintf( ("making %s into an array\n", ap->nval) );
5333e12c5d1SDavid du Colombier 		if (freeable(ap))
5343e12c5d1SDavid du Colombier 			xfree(ap->sval);
5353e12c5d1SDavid du Colombier 		ap->tval &= ~(STR|NUM|DONTFREE);
5363e12c5d1SDavid du Colombier 		ap->tval |= ARR;
5377dd7cddfSDavid du Colombier 		ap->sval = (char *) makesymtab(NSYMTAB);
5387dd7cddfSDavid du Colombier 	}
5397dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL) {
5407dd7cddfSDavid du Colombier 		FATAL("out of memory in intest");
5413e12c5d1SDavid du Colombier 	}
5423e12c5d1SDavid du Colombier 	buf[0] = 0;
5433e12c5d1SDavid du Colombier 	for (p = a[0]; p; p = p->nnext) {
5443e12c5d1SDavid du Colombier 		x = execute(p);	/* expr */
5453e12c5d1SDavid du Colombier 		s = getsval(x);
5467dd7cddfSDavid du Colombier 		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
5477dd7cddfSDavid du Colombier 			FATAL("out of memory deleting %s[%s...]", x->nval, buf);
5483e12c5d1SDavid du Colombier 		strcat(buf, s);
5493e12c5d1SDavid du Colombier 		tempfree(x);
5503e12c5d1SDavid du Colombier 		if (p->nnext)
5513e12c5d1SDavid du Colombier 			strcat(buf, *SUBSEP);
5523e12c5d1SDavid du Colombier 	}
5533e12c5d1SDavid du Colombier 	k = lookup(buf, (Array *) ap->sval);
5543e12c5d1SDavid du Colombier 	tempfree(ap);
5557dd7cddfSDavid du Colombier 	free(buf);
5563e12c5d1SDavid du Colombier 	if (k == NULL)
5577dd7cddfSDavid du Colombier 		return(False);
5583e12c5d1SDavid du Colombier 	else
5597dd7cddfSDavid du Colombier 		return(True);
5603e12c5d1SDavid du Colombier }
5613e12c5d1SDavid du Colombier 
5623e12c5d1SDavid du Colombier 
matchop(Node ** a,int n)563219b2ee8SDavid du Colombier Cell *matchop(Node **a, int n)	/* ~ and match() */
5643e12c5d1SDavid du Colombier {
5657dd7cddfSDavid du Colombier 	Cell *x, *y;
5667dd7cddfSDavid du Colombier 	char *s, *t;
5677dd7cddfSDavid du Colombier 	int i;
5683e12c5d1SDavid du Colombier 	void *p;
5693e12c5d1SDavid du Colombier 
570219b2ee8SDavid du Colombier 	x = execute(a[1]);	/* a[1] = target text */
5713e12c5d1SDavid du Colombier 	s = getsval(x);
572219b2ee8SDavid du Colombier 	if (a[0] == 0)		/* a[1] == 0: already-compiled reg expr */
5733e12c5d1SDavid du Colombier 		p = (void *) a[2];
5743e12c5d1SDavid du Colombier 	else {
575219b2ee8SDavid du Colombier 		y = execute(a[2]);	/* a[2] = regular expr */
5763e12c5d1SDavid du Colombier 		t = getsval(y);
5773e12c5d1SDavid du Colombier 		p = compre(t);
5783e12c5d1SDavid du Colombier 		tempfree(y);
5793e12c5d1SDavid du Colombier 	}
5803e12c5d1SDavid du Colombier 	if (n == MATCHFCN)
5813e12c5d1SDavid du Colombier 		i = pmatch(p, s, s);
5823e12c5d1SDavid du Colombier 	else
5833e12c5d1SDavid du Colombier 		i = match(p, s, s);
5843e12c5d1SDavid du Colombier 	tempfree(x);
5853e12c5d1SDavid du Colombier 	if (n == MATCHFCN) {
586d9306527SDavid du Colombier 		int start = countposn(s, patbeg-s)+1;
5873e12c5d1SDavid du Colombier 		if (patlen < 0)
5883e12c5d1SDavid du Colombier 			start = 0;
5893e12c5d1SDavid du Colombier 		setfval(rstartloc, (Awkfloat) start);
5903e12c5d1SDavid du Colombier 		setfval(rlengthloc, (Awkfloat) countposn(patbeg, patlen));
5913e12c5d1SDavid du Colombier 		x = gettemp();
5923e12c5d1SDavid du Colombier 		x->tval = NUM;
5933e12c5d1SDavid du Colombier 		x->fval = start;
5943e12c5d1SDavid du Colombier 		return x;
5957dd7cddfSDavid du Colombier 	} else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
5967dd7cddfSDavid du Colombier 		return(True);
5973e12c5d1SDavid du Colombier 	else
5987dd7cddfSDavid du Colombier 		return(False);
5993e12c5d1SDavid du Colombier }
6003e12c5d1SDavid du Colombier 
6013e12c5d1SDavid du Colombier 
boolop(Node ** a,int n)602219b2ee8SDavid du Colombier Cell *boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
6033e12c5d1SDavid du Colombier {
6047dd7cddfSDavid du Colombier 	Cell *x, *y;
6057dd7cddfSDavid du Colombier 	int i;
6063e12c5d1SDavid du Colombier 
6073e12c5d1SDavid du Colombier 	x = execute(a[0]);
6083e12c5d1SDavid du Colombier 	i = istrue(x);
6093e12c5d1SDavid du Colombier 	tempfree(x);
6103e12c5d1SDavid du Colombier 	switch (n) {
6113e12c5d1SDavid du Colombier 	case BOR:
6127dd7cddfSDavid du Colombier 		if (i) return(True);
6133e12c5d1SDavid du Colombier 		y = execute(a[1]);
6143e12c5d1SDavid du Colombier 		i = istrue(y);
6153e12c5d1SDavid du Colombier 		tempfree(y);
6167dd7cddfSDavid du Colombier 		if (i) return(True);
6177dd7cddfSDavid du Colombier 		else return(False);
6183e12c5d1SDavid du Colombier 	case AND:
6197dd7cddfSDavid du Colombier 		if ( !i ) return(False);
6203e12c5d1SDavid du Colombier 		y = execute(a[1]);
6213e12c5d1SDavid du Colombier 		i = istrue(y);
6223e12c5d1SDavid du Colombier 		tempfree(y);
6237dd7cddfSDavid du Colombier 		if (i) return(True);
6247dd7cddfSDavid du Colombier 		else return(False);
6253e12c5d1SDavid du Colombier 	case NOT:
6267dd7cddfSDavid du Colombier 		if (i) return(False);
6277dd7cddfSDavid du Colombier 		else return(True);
6283e12c5d1SDavid du Colombier 	default:	/* can't happen */
6297dd7cddfSDavid du Colombier 		FATAL("unknown boolean operator %d", n);
6303e12c5d1SDavid du Colombier 	}
6313e12c5d1SDavid du Colombier 	return 0;	/*NOTREACHED*/
6323e12c5d1SDavid du Colombier }
6333e12c5d1SDavid du Colombier 
relop(Node ** a,int n)634219b2ee8SDavid du Colombier Cell *relop(Node **a, int n)	/* a[0 < a[1], etc. */
6353e12c5d1SDavid du Colombier {
6367dd7cddfSDavid du Colombier 	int i;
6377dd7cddfSDavid du Colombier 	Cell *x, *y;
6383e12c5d1SDavid du Colombier 	Awkfloat j;
6393e12c5d1SDavid du Colombier 
6403e12c5d1SDavid du Colombier 	x = execute(a[0]);
6413e12c5d1SDavid du Colombier 	y = execute(a[1]);
6423e12c5d1SDavid du Colombier 	if (x->tval&NUM && y->tval&NUM) {
6433e12c5d1SDavid du Colombier 		j = x->fval - y->fval;
6443e12c5d1SDavid du Colombier 		i = j<0? -1: (j>0? 1: 0);
6453e12c5d1SDavid du Colombier 	} else {
6463e12c5d1SDavid du Colombier 		i = strcmp(getsval(x), getsval(y));
6473e12c5d1SDavid du Colombier 	}
6483e12c5d1SDavid du Colombier 	tempfree(x);
6493e12c5d1SDavid du Colombier 	tempfree(y);
6503e12c5d1SDavid du Colombier 	switch (n) {
6517dd7cddfSDavid du Colombier 	case LT:	if (i<0) return(True);
6527dd7cddfSDavid du Colombier 			else return(False);
6537dd7cddfSDavid du Colombier 	case LE:	if (i<=0) return(True);
6547dd7cddfSDavid du Colombier 			else return(False);
6557dd7cddfSDavid du Colombier 	case NE:	if (i!=0) return(True);
6567dd7cddfSDavid du Colombier 			else return(False);
6577dd7cddfSDavid du Colombier 	case EQ:	if (i == 0) return(True);
6587dd7cddfSDavid du Colombier 			else return(False);
6597dd7cddfSDavid du Colombier 	case GE:	if (i>=0) return(True);
6607dd7cddfSDavid du Colombier 			else return(False);
6617dd7cddfSDavid du Colombier 	case GT:	if (i>0) return(True);
6627dd7cddfSDavid du Colombier 			else return(False);
6633e12c5d1SDavid du Colombier 	default:	/* can't happen */
6647dd7cddfSDavid du Colombier 		FATAL("unknown relational operator %d", n);
6653e12c5d1SDavid du Colombier 	}
6663e12c5d1SDavid du Colombier 	return 0;	/*NOTREACHED*/
6673e12c5d1SDavid du Colombier }
6683e12c5d1SDavid du Colombier 
tfree(Cell * a)669219b2ee8SDavid du Colombier void tfree(Cell *a)	/* free a tempcell */
6703e12c5d1SDavid du Colombier {
6717dd7cddfSDavid du Colombier 	if (freeable(a)) {
6727dd7cddfSDavid du Colombier 		   dprintf( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) );
6733e12c5d1SDavid du Colombier 		xfree(a->sval);
6747dd7cddfSDavid du Colombier 	}
6753e12c5d1SDavid du Colombier 	if (a == tmps)
6767dd7cddfSDavid du Colombier 		FATAL("tempcell list is curdled");
6773e12c5d1SDavid du Colombier 	a->cnext = tmps;
6783e12c5d1SDavid du Colombier 	tmps = a;
6793e12c5d1SDavid du Colombier }
6803e12c5d1SDavid du Colombier 
gettemp(void)681219b2ee8SDavid du Colombier Cell *gettemp(void)	/* get a tempcell */
6823e12c5d1SDavid du Colombier {	int i;
6837dd7cddfSDavid du Colombier 	Cell *x;
6843e12c5d1SDavid du Colombier 
6853e12c5d1SDavid du Colombier 	if (!tmps) {
6863e12c5d1SDavid du Colombier 		tmps = (Cell *) calloc(100, sizeof(Cell));
6873e12c5d1SDavid du Colombier 		if (!tmps)
6887dd7cddfSDavid du Colombier 			FATAL("out of space for temporaries");
6893e12c5d1SDavid du Colombier 		for(i = 1; i < 100; i++)
6903e12c5d1SDavid du Colombier 			tmps[i-1].cnext = &tmps[i];
6913e12c5d1SDavid du Colombier 		tmps[i-1].cnext = 0;
6923e12c5d1SDavid du Colombier 	}
6933e12c5d1SDavid du Colombier 	x = tmps;
6943e12c5d1SDavid du Colombier 	tmps = x->cnext;
6953e12c5d1SDavid du Colombier 	*x = tempcell;
6963e12c5d1SDavid du Colombier 	return(x);
6973e12c5d1SDavid du Colombier }
6983e12c5d1SDavid du Colombier 
indirect(Node ** a,int n)699219b2ee8SDavid du Colombier Cell *indirect(Node **a, int n)	/* $( a[0] ) */
7003e12c5d1SDavid du Colombier {
7017dd7cddfSDavid du Colombier 	Cell *x;
7027dd7cddfSDavid du Colombier 	int m;
7037dd7cddfSDavid du Colombier 	char *s;
7043e12c5d1SDavid du Colombier 
7053e12c5d1SDavid du Colombier 	x = execute(a[0]);
7067dd7cddfSDavid du Colombier 	m = (int) getfval(x);
7077dd7cddfSDavid du Colombier 	if (m == 0 && !is_number(s = getsval(x)))	/* suspicion! */
7087dd7cddfSDavid du Colombier 		FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
7097dd7cddfSDavid du Colombier 		/* BUG: can x->nval ever be null??? */
7103e12c5d1SDavid du Colombier 	tempfree(x);
7113e12c5d1SDavid du Colombier 	x = fieldadr(m);
7127dd7cddfSDavid du Colombier 	x->ctype = OCELL;	/* BUG?  why are these needed? */
7133e12c5d1SDavid du Colombier 	x->csub = CFLD;
7143e12c5d1SDavid du Colombier 	return(x);
7153e12c5d1SDavid du Colombier }
7163e12c5d1SDavid du Colombier 
substr(Node ** a,int nnn)717219b2ee8SDavid du Colombier Cell *substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
7183e12c5d1SDavid du Colombier {
7197dd7cddfSDavid du Colombier 	int k, m, n;
7207dd7cddfSDavid du Colombier 	char *s, *p;
7213e12c5d1SDavid du Colombier 	int temp;
7227dd7cddfSDavid du Colombier 	Cell *x, *y, *z = 0;
7233e12c5d1SDavid du Colombier 
7243e12c5d1SDavid du Colombier 	x = execute(a[0]);
7253e12c5d1SDavid du Colombier 	y = execute(a[1]);
7263e12c5d1SDavid du Colombier 	if (a[2] != 0)
7273e12c5d1SDavid du Colombier 		z = execute(a[2]);
7283e12c5d1SDavid du Colombier 	s = getsval(x);
7293e12c5d1SDavid du Colombier 	k = countposn(s, strlen(s)) + 1;
7303e12c5d1SDavid du Colombier 	if (k <= 1) {
7313e12c5d1SDavid du Colombier 		tempfree(x);
7323e12c5d1SDavid du Colombier 		tempfree(y);
7333e12c5d1SDavid du Colombier 		if (a[2] != 0)
7343e12c5d1SDavid du Colombier 			tempfree(z);
7353e12c5d1SDavid du Colombier 		x = gettemp();
7363e12c5d1SDavid du Colombier 		setsval(x, "");
7373e12c5d1SDavid du Colombier 		return(x);
7383e12c5d1SDavid du Colombier 	}
7397dd7cddfSDavid du Colombier 	m = (int) getfval(y);
7403e12c5d1SDavid du Colombier 	if (m <= 0)
7413e12c5d1SDavid du Colombier 		m = 1;
7423e12c5d1SDavid du Colombier 	else if (m > k)
7433e12c5d1SDavid du Colombier 		m = k;
7443e12c5d1SDavid du Colombier 	tempfree(y);
7453e12c5d1SDavid du Colombier 	if (a[2] != 0) {
7467dd7cddfSDavid du Colombier 		n = (int) getfval(z);
7473e12c5d1SDavid du Colombier 		tempfree(z);
7483e12c5d1SDavid du Colombier 	} else
7493e12c5d1SDavid du Colombier 		n = k - 1;
7503e12c5d1SDavid du Colombier 	if (n < 0)
7513e12c5d1SDavid du Colombier 		n = 0;
7523e12c5d1SDavid du Colombier 	else if (n > k - m)
7533e12c5d1SDavid du Colombier 		n = k - m;
7543e12c5d1SDavid du Colombier 	   dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
7553e12c5d1SDavid du Colombier 	y = gettemp();
7563e12c5d1SDavid du Colombier 	while (*s && --m)
7573e12c5d1SDavid du Colombier 		 s += mblen(s, k);
7583e12c5d1SDavid du Colombier 	for (p = s; *p && n--; p += mblen(p, k))
7593e12c5d1SDavid du Colombier 			;
7603e12c5d1SDavid du Colombier 	temp = *p;	/* with thanks to John Linderman */
7613e12c5d1SDavid du Colombier 	*p = '\0';
7623e12c5d1SDavid du Colombier 	setsval(y, s);
7633e12c5d1SDavid du Colombier 	*p = temp;
7643e12c5d1SDavid du Colombier 	tempfree(x);
7653e12c5d1SDavid du Colombier 	return(y);
7663e12c5d1SDavid du Colombier }
7673e12c5d1SDavid du Colombier 
sindex(Node ** a,int nnn)768219b2ee8SDavid du Colombier Cell *sindex(Node **a, int nnn)		/* index(a[0], a[1]) */
7693e12c5d1SDavid du Colombier {
7707dd7cddfSDavid du Colombier 	Cell *x, *y, *z;
7717dd7cddfSDavid du Colombier 	char *s1, *s2, *p1, *p2, *q;
7723e12c5d1SDavid du Colombier 	Awkfloat v = 0.0;
7733e12c5d1SDavid du Colombier 
7743e12c5d1SDavid du Colombier 	x = execute(a[0]);
7753e12c5d1SDavid du Colombier 	s1 = getsval(x);
7763e12c5d1SDavid du Colombier 	y = execute(a[1]);
7773e12c5d1SDavid du Colombier 	s2 = getsval(y);
7783e12c5d1SDavid du Colombier 
7793e12c5d1SDavid du Colombier 	z = gettemp();
7803e12c5d1SDavid du Colombier 	for (p1 = s1; *p1 != '\0'; p1++) {
7813e12c5d1SDavid du Colombier 		for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
7823e12c5d1SDavid du Colombier 			;
7833e12c5d1SDavid du Colombier 		if (*p2 == '\0') {
7843e12c5d1SDavid du Colombier 			v = (Awkfloat) countposn(s1, p1-s1) + 1;	/* origin 1 */
7853e12c5d1SDavid du Colombier 			break;
7863e12c5d1SDavid du Colombier 		}
7873e12c5d1SDavid du Colombier 	}
7883e12c5d1SDavid du Colombier 	tempfree(x);
7893e12c5d1SDavid du Colombier 	tempfree(y);
7903e12c5d1SDavid du Colombier 	setfval(z, v);
7913e12c5d1SDavid du Colombier 	return(z);
7923e12c5d1SDavid du Colombier }
7933e12c5d1SDavid du Colombier 
7947dd7cddfSDavid du Colombier #define	MAXNUMSIZE	50
795219b2ee8SDavid du Colombier 
format(char ** pbuf,int * pbufsize,char * s,Node * a)7967dd7cddfSDavid du Colombier int format(char **pbuf, int *pbufsize, char *s, Node *a)	/* printf-like conversions */
7973e12c5d1SDavid du Colombier {
7987dd7cddfSDavid du Colombier 	char *fmt;
7997dd7cddfSDavid du Colombier 	char *p, *t, *os;
8007dd7cddfSDavid du Colombier 	Cell *x;
8013e12c5d1SDavid du Colombier 	int flag = 0, n;
8027dd7cddfSDavid du Colombier 	int fmtwd; /* format width */
8037dd7cddfSDavid du Colombier 	int fmtsz = recsize;
8047dd7cddfSDavid du Colombier 	char *buf = *pbuf;
8057dd7cddfSDavid du Colombier 	int bufsize = *pbufsize;
8063e12c5d1SDavid du Colombier 
8073e12c5d1SDavid du Colombier 	os = s;
8083e12c5d1SDavid du Colombier 	p = buf;
8097dd7cddfSDavid du Colombier 	if ((fmt = (char *) malloc(fmtsz)) == NULL)
8107dd7cddfSDavid du Colombier 		FATAL("out of memory in format()");
8113e12c5d1SDavid du Colombier 	while (*s) {
8127dd7cddfSDavid du Colombier 		adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format");
8133e12c5d1SDavid du Colombier 		if (*s != '%') {
8143e12c5d1SDavid du Colombier 			*p++ = *s++;
8153e12c5d1SDavid du Colombier 			continue;
8163e12c5d1SDavid du Colombier 		}
8173e12c5d1SDavid du Colombier 		if (*(s+1) == '%') {
8183e12c5d1SDavid du Colombier 			*p++ = '%';
8193e12c5d1SDavid du Colombier 			s += 2;
8203e12c5d1SDavid du Colombier 			continue;
8213e12c5d1SDavid du Colombier 		}
8227dd7cddfSDavid du Colombier 		/* have to be real careful in case this is a huge number, eg, %100000d */
8237dd7cddfSDavid du Colombier 		fmtwd = atoi(s+1);
8247dd7cddfSDavid du Colombier 		if (fmtwd < 0)
8257dd7cddfSDavid du Colombier 			fmtwd = -fmtwd;
8267dd7cddfSDavid du Colombier 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
8273e12c5d1SDavid du Colombier 		for (t = fmt; (*t++ = *s) != '\0'; s++) {
8287dd7cddfSDavid du Colombier 			if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0))
8297dd7cddfSDavid du Colombier 				FATAL("format item %.30s... ran format() out of memory", os);
8303e12c5d1SDavid du Colombier 			if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
8313e12c5d1SDavid du Colombier 				break;	/* the ansi panoply */
8323e12c5d1SDavid du Colombier 			if (*s == '*') {
8333e12c5d1SDavid du Colombier 				x = execute(a);
8343e12c5d1SDavid du Colombier 				a = a->nnext;
8357dd7cddfSDavid du Colombier 				sprintf(t-1, "%d", fmtwd=(int) getfval(x));
8367dd7cddfSDavid du Colombier 				if (fmtwd < 0)
8377dd7cddfSDavid du Colombier 					fmtwd = -fmtwd;
8387dd7cddfSDavid du Colombier 				adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
8393e12c5d1SDavid du Colombier 				t = fmt + strlen(fmt);
8403e12c5d1SDavid du Colombier 				tempfree(x);
8413e12c5d1SDavid du Colombier 			}
8423e12c5d1SDavid du Colombier 		}
8433e12c5d1SDavid du Colombier 		*t = '\0';
8447dd7cddfSDavid du Colombier 		if (fmtwd < 0)
8457dd7cddfSDavid du Colombier 			fmtwd = -fmtwd;
8467dd7cddfSDavid du Colombier 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
8477dd7cddfSDavid du Colombier 
8483e12c5d1SDavid du Colombier 		switch (*s) {
8493e12c5d1SDavid du Colombier 		case 'f': case 'e': case 'g': case 'E': case 'G':
8503e12c5d1SDavid du Colombier 			flag = 1;
8513e12c5d1SDavid du Colombier 			break;
8523e12c5d1SDavid du Colombier 		case 'd': case 'i':
8533e12c5d1SDavid du Colombier 			flag = 2;
8543e12c5d1SDavid du Colombier 			if(*(s-1) == 'l') break;
8553e12c5d1SDavid du Colombier 			*(t-1) = 'l';
8563e12c5d1SDavid du Colombier 			*t = 'd';
8573e12c5d1SDavid du Colombier 			*++t = '\0';
8583e12c5d1SDavid du Colombier 			break;
8593e12c5d1SDavid du Colombier 		case 'o': case 'x': case 'X': case 'u':
8603e12c5d1SDavid du Colombier 			flag = *(s-1) == 'l' ? 2 : 3;
8613e12c5d1SDavid du Colombier 			break;
8623e12c5d1SDavid du Colombier 		case 's':
8633e12c5d1SDavid du Colombier 			flag = 4;
8643e12c5d1SDavid du Colombier 			break;
8653e12c5d1SDavid du Colombier 		case 'c':
8663e12c5d1SDavid du Colombier 			flag = 5;
8673e12c5d1SDavid du Colombier 			break;
8683e12c5d1SDavid du Colombier 		default:
8697dd7cddfSDavid du Colombier 			WARNING("weird printf conversion %s", fmt);
8703e12c5d1SDavid du Colombier 			flag = 0;
8713e12c5d1SDavid du Colombier 			break;
8723e12c5d1SDavid du Colombier 		}
8733e12c5d1SDavid du Colombier 		if (a == NULL)
8747dd7cddfSDavid du Colombier 			FATAL("not enough args in printf(%s)", os);
8753e12c5d1SDavid du Colombier 		x = execute(a);
8763e12c5d1SDavid du Colombier 		a = a->nnext;
8777dd7cddfSDavid du Colombier 		n = MAXNUMSIZE;
8787dd7cddfSDavid du Colombier 		if (fmtwd > n)
8797dd7cddfSDavid du Colombier 			n = fmtwd;
8807dd7cddfSDavid du Colombier 		adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
8813e12c5d1SDavid du Colombier 		switch (flag) {
8827dd7cddfSDavid du Colombier 		case 0:	sprintf(p, "%s", fmt);	/* unknown, so dump it too */
8837dd7cddfSDavid du Colombier 			t = getsval(x);
8847dd7cddfSDavid du Colombier 			n = strlen(t);
8857dd7cddfSDavid du Colombier 			if (fmtwd > n)
8867dd7cddfSDavid du Colombier 				n = fmtwd;
8877dd7cddfSDavid du Colombier 			adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
8883e12c5d1SDavid du Colombier 			p += strlen(p);
8897dd7cddfSDavid du Colombier 			sprintf(p, "%s", t);
8903e12c5d1SDavid du Colombier 			break;
8917dd7cddfSDavid du Colombier 		case 1:	sprintf(p, fmt, getfval(x)); break;
8927dd7cddfSDavid du Colombier 		case 2:	sprintf(p, fmt, (long) getfval(x)); break;
8937dd7cddfSDavid du Colombier 		case 3:	sprintf(p, fmt, (int) getfval(x)); break;
8943e12c5d1SDavid du Colombier 		case 4:
8953e12c5d1SDavid du Colombier 			t = getsval(x);
8963e12c5d1SDavid du Colombier 			n = strlen(t);
8977dd7cddfSDavid du Colombier 			if (fmtwd > n)
8987dd7cddfSDavid du Colombier 				n = fmtwd;
8997dd7cddfSDavid du Colombier 			if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
9007dd7cddfSDavid du Colombier 				FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
9017dd7cddfSDavid du Colombier 			sprintf(p, fmt, t);
9023e12c5d1SDavid du Colombier 			break;
903219b2ee8SDavid du Colombier 		case 5:
9047dd7cddfSDavid du Colombier 			if (isnum(x)) {
9057dd7cddfSDavid du Colombier 				if (getfval(x))
9067dd7cddfSDavid du Colombier 					sprintf(p, fmt, (int) getfval(x));
90776f6a3b8SDavid du Colombier 				else{
9087dd7cddfSDavid du Colombier 					*p++ = '\0';
90976f6a3b8SDavid du Colombier 					*p = '\0';
91076f6a3b8SDavid du Colombier 				}
9117dd7cddfSDavid du Colombier 			} else
9127dd7cddfSDavid du Colombier 				sprintf(p, fmt, getsval(x)[0]);
9133e12c5d1SDavid du Colombier 			break;
9143e12c5d1SDavid du Colombier 		}
9153e12c5d1SDavid du Colombier 		tempfree(x);
9163e12c5d1SDavid du Colombier 		p += strlen(p);
9173e12c5d1SDavid du Colombier 		s++;
9183e12c5d1SDavid du Colombier 	}
9193e12c5d1SDavid du Colombier 	*p = '\0';
9207dd7cddfSDavid du Colombier 	free(fmt);
9213e12c5d1SDavid du Colombier 	for ( ; a; a = a->nnext)		/* evaluate any remaining args */
9223e12c5d1SDavid du Colombier 		execute(a);
9237dd7cddfSDavid du Colombier 	*pbuf = buf;
9247dd7cddfSDavid du Colombier 	*pbufsize = bufsize;
9257dd7cddfSDavid du Colombier 	return p - buf;
9263e12c5d1SDavid du Colombier }
9273e12c5d1SDavid du Colombier 
awksprintf(Node ** a,int n)9287dd7cddfSDavid du Colombier Cell *awksprintf(Node **a, int n)		/* sprintf(a[0]) */
9293e12c5d1SDavid du Colombier {
9307dd7cddfSDavid du Colombier 	Cell *x;
9317dd7cddfSDavid du Colombier 	Node *y;
9327dd7cddfSDavid du Colombier 	char *buf;
9337dd7cddfSDavid du Colombier 	int bufsz=3*recsize;
9343e12c5d1SDavid du Colombier 
9357dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL)
9367dd7cddfSDavid du Colombier 		FATAL("out of memory in awksprintf");
9373e12c5d1SDavid du Colombier 	y = a[0]->nnext;
9383e12c5d1SDavid du Colombier 	x = execute(a[0]);
9397dd7cddfSDavid du Colombier 	if (format(&buf, &bufsz, getsval(x), y) == -1)
9407dd7cddfSDavid du Colombier 		FATAL("sprintf string %.30s... too long.  can't happen.", buf);
9413e12c5d1SDavid du Colombier 	tempfree(x);
9423e12c5d1SDavid du Colombier 	x = gettemp();
9437dd7cddfSDavid du Colombier 	x->sval = buf;
9443e12c5d1SDavid du Colombier 	x->tval = STR;
9453e12c5d1SDavid du Colombier 	return(x);
9463e12c5d1SDavid du Colombier }
9473e12c5d1SDavid du Colombier 
awkprintf(Node ** a,int n)9487dd7cddfSDavid du Colombier Cell *awkprintf(Node **a, int n)		/* printf */
949219b2ee8SDavid du Colombier {	/* a[0] is list of args, starting with format string */
950219b2ee8SDavid du Colombier 	/* a[1] is redirection operator, a[2] is redirection file */
9513e12c5d1SDavid du Colombier 	FILE *fp;
9527dd7cddfSDavid du Colombier 	Cell *x;
9537dd7cddfSDavid du Colombier 	Node *y;
9547dd7cddfSDavid du Colombier 	char *buf;
9557dd7cddfSDavid du Colombier 	int len;
9567dd7cddfSDavid du Colombier 	int bufsz=3*recsize;
9573e12c5d1SDavid du Colombier 
9587dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL)
9597dd7cddfSDavid du Colombier 		FATAL("out of memory in awkprintf");
9603e12c5d1SDavid du Colombier 	y = a[0]->nnext;
9613e12c5d1SDavid du Colombier 	x = execute(a[0]);
9627dd7cddfSDavid du Colombier 	if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
9637dd7cddfSDavid du Colombier 		FATAL("printf string %.30s... too long.  can't happen.", buf);
9643e12c5d1SDavid du Colombier 	tempfree(x);
9653e12c5d1SDavid du Colombier 	if (a[1] == NULL) {
9667dd7cddfSDavid du Colombier 		/* fputs(buf, stdout); */
9677dd7cddfSDavid du Colombier 		fwrite(buf, len, 1, stdout);
9683e12c5d1SDavid du Colombier 		if (ferror(stdout))
9697dd7cddfSDavid du Colombier 			FATAL("write error on stdout");
9703e12c5d1SDavid du Colombier 	} else {
9717dd7cddfSDavid du Colombier 		fp = redirect(ptoi(a[1]), a[2]);
9727dd7cddfSDavid du Colombier 		/* fputs(buf, fp); */
9737dd7cddfSDavid du Colombier 		fwrite(buf, len, 1, fp);
9743e12c5d1SDavid du Colombier 		fflush(fp);
9753e12c5d1SDavid du Colombier 		if (ferror(fp))
9767dd7cddfSDavid du Colombier 			FATAL("write error on %s", filename(fp));
9773e12c5d1SDavid du Colombier 	}
9787dd7cddfSDavid du Colombier 	free(buf);
9797dd7cddfSDavid du Colombier 	return(True);
9803e12c5d1SDavid du Colombier }
9813e12c5d1SDavid du Colombier 
arith(Node ** a,int n)982219b2ee8SDavid du Colombier Cell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
9833e12c5d1SDavid du Colombier {
9847dd7cddfSDavid du Colombier 	Awkfloat i, j = 0;
9853e12c5d1SDavid du Colombier 	double v;
9867dd7cddfSDavid du Colombier 	Cell *x, *y, *z;
9873e12c5d1SDavid du Colombier 
9883e12c5d1SDavid du Colombier 	x = execute(a[0]);
9893e12c5d1SDavid du Colombier 	i = getfval(x);
9903e12c5d1SDavid du Colombier 	tempfree(x);
9913e12c5d1SDavid du Colombier 	if (n != UMINUS) {
9923e12c5d1SDavid du Colombier 		y = execute(a[1]);
9933e12c5d1SDavid du Colombier 		j = getfval(y);
9943e12c5d1SDavid du Colombier 		tempfree(y);
9953e12c5d1SDavid du Colombier 	}
9963e12c5d1SDavid du Colombier 	z = gettemp();
9973e12c5d1SDavid du Colombier 	switch (n) {
9983e12c5d1SDavid du Colombier 	case ADD:
9993e12c5d1SDavid du Colombier 		i += j;
10003e12c5d1SDavid du Colombier 		break;
10013e12c5d1SDavid du Colombier 	case MINUS:
10023e12c5d1SDavid du Colombier 		i -= j;
10033e12c5d1SDavid du Colombier 		break;
10043e12c5d1SDavid du Colombier 	case MULT:
10053e12c5d1SDavid du Colombier 		i *= j;
10063e12c5d1SDavid du Colombier 		break;
10073e12c5d1SDavid du Colombier 	case DIVIDE:
10083e12c5d1SDavid du Colombier 		if (j == 0)
10097dd7cddfSDavid du Colombier 			FATAL("division by zero");
10103e12c5d1SDavid du Colombier 		i /= j;
10113e12c5d1SDavid du Colombier 		break;
10123e12c5d1SDavid du Colombier 	case MOD:
10133e12c5d1SDavid du Colombier 		if (j == 0)
10147dd7cddfSDavid du Colombier 			FATAL("division by zero in mod");
10153e12c5d1SDavid du Colombier 		modf(i/j, &v);
10163e12c5d1SDavid du Colombier 		i = i - j * v;
10173e12c5d1SDavid du Colombier 		break;
10183e12c5d1SDavid du Colombier 	case UMINUS:
10193e12c5d1SDavid du Colombier 		i = -i;
10203e12c5d1SDavid du Colombier 		break;
10213e12c5d1SDavid du Colombier 	case POWER:
10223e12c5d1SDavid du Colombier 		if (j >= 0 && modf(j, &v) == 0.0)	/* pos integer exponent */
10233e12c5d1SDavid du Colombier 			i = ipow(i, (int) j);
10243e12c5d1SDavid du Colombier 		else
10253e12c5d1SDavid du Colombier 			i = errcheck(pow(i, j), "pow");
10263e12c5d1SDavid du Colombier 		break;
10273e12c5d1SDavid du Colombier 	default:	/* can't happen */
10287dd7cddfSDavid du Colombier 		FATAL("illegal arithmetic operator %d", n);
10293e12c5d1SDavid du Colombier 	}
10303e12c5d1SDavid du Colombier 	setfval(z, i);
10313e12c5d1SDavid du Colombier 	return(z);
10323e12c5d1SDavid du Colombier }
10333e12c5d1SDavid du Colombier 
ipow(double x,int n)1034219b2ee8SDavid du Colombier double ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
10353e12c5d1SDavid du Colombier {
10363e12c5d1SDavid du Colombier 	double v;
10373e12c5d1SDavid du Colombier 
10383e12c5d1SDavid du Colombier 	if (n <= 0)
10393e12c5d1SDavid du Colombier 		return 1;
10403e12c5d1SDavid du Colombier 	v = ipow(x, n/2);
10413e12c5d1SDavid du Colombier 	if (n % 2 == 0)
10423e12c5d1SDavid du Colombier 		return v * v;
10433e12c5d1SDavid du Colombier 	else
10443e12c5d1SDavid du Colombier 		return x * v * v;
10453e12c5d1SDavid du Colombier }
10463e12c5d1SDavid du Colombier 
incrdecr(Node ** a,int n)1047219b2ee8SDavid du Colombier Cell *incrdecr(Node **a, int n)		/* a[0]++, etc. */
10483e12c5d1SDavid du Colombier {
10497dd7cddfSDavid du Colombier 	Cell *x, *z;
10507dd7cddfSDavid du Colombier 	int k;
10513e12c5d1SDavid du Colombier 	Awkfloat xf;
10523e12c5d1SDavid du Colombier 
10533e12c5d1SDavid du Colombier 	x = execute(a[0]);
10543e12c5d1SDavid du Colombier 	xf = getfval(x);
10553e12c5d1SDavid du Colombier 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
10563e12c5d1SDavid du Colombier 	if (n == PREINCR || n == PREDECR) {
10573e12c5d1SDavid du Colombier 		setfval(x, xf + k);
10583e12c5d1SDavid du Colombier 		return(x);
10593e12c5d1SDavid du Colombier 	}
10603e12c5d1SDavid du Colombier 	z = gettemp();
10613e12c5d1SDavid du Colombier 	setfval(z, xf);
10623e12c5d1SDavid du Colombier 	setfval(x, xf + k);
10633e12c5d1SDavid du Colombier 	tempfree(x);
10643e12c5d1SDavid du Colombier 	return(z);
10653e12c5d1SDavid du Colombier }
10663e12c5d1SDavid du Colombier 
assign(Node ** a,int n)1067219b2ee8SDavid du Colombier Cell *assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
1068219b2ee8SDavid du Colombier {		/* this is subtle; don't muck with it. */
10697dd7cddfSDavid du Colombier 	Cell *x, *y;
10703e12c5d1SDavid du Colombier 	Awkfloat xf, yf;
10713e12c5d1SDavid du Colombier 	double v;
10723e12c5d1SDavid du Colombier 
10733e12c5d1SDavid du Colombier 	y = execute(a[1]);
10743e12c5d1SDavid du Colombier 	x = execute(a[0]);
10753e12c5d1SDavid du Colombier 	if (n == ASSIGN) {	/* ordinary assignment */
1076219b2ee8SDavid du Colombier 		if (x == y && !(x->tval & (FLD|REC)))	/* self-assignment: */
1077219b2ee8SDavid du Colombier 			;		/* leave alone unless it's a field */
10783e12c5d1SDavid du Colombier 		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
10793e12c5d1SDavid du Colombier 			setsval(x, getsval(y));
10803e12c5d1SDavid du Colombier 			x->fval = getfval(y);
10813e12c5d1SDavid du Colombier 			x->tval |= NUM;
10823e12c5d1SDavid du Colombier 		}
10837dd7cddfSDavid du Colombier 		else if (isstr(y))
10843e12c5d1SDavid du Colombier 			setsval(x, getsval(y));
10857dd7cddfSDavid du Colombier 		else if (isnum(y))
10863e12c5d1SDavid du Colombier 			setfval(x, getfval(y));
10873e12c5d1SDavid du Colombier 		else
10883e12c5d1SDavid du Colombier 			funnyvar(y, "read value of");
10893e12c5d1SDavid du Colombier 		tempfree(y);
10903e12c5d1SDavid du Colombier 		return(x);
10913e12c5d1SDavid du Colombier 	}
10923e12c5d1SDavid du Colombier 	xf = getfval(x);
10933e12c5d1SDavid du Colombier 	yf = getfval(y);
10943e12c5d1SDavid du Colombier 	switch (n) {
10953e12c5d1SDavid du Colombier 	case ADDEQ:
10963e12c5d1SDavid du Colombier 		xf += yf;
10973e12c5d1SDavid du Colombier 		break;
10983e12c5d1SDavid du Colombier 	case SUBEQ:
10993e12c5d1SDavid du Colombier 		xf -= yf;
11003e12c5d1SDavid du Colombier 		break;
11013e12c5d1SDavid du Colombier 	case MULTEQ:
11023e12c5d1SDavid du Colombier 		xf *= yf;
11033e12c5d1SDavid du Colombier 		break;
11043e12c5d1SDavid du Colombier 	case DIVEQ:
11053e12c5d1SDavid du Colombier 		if (yf == 0)
11067dd7cddfSDavid du Colombier 			FATAL("division by zero in /=");
11073e12c5d1SDavid du Colombier 		xf /= yf;
11083e12c5d1SDavid du Colombier 		break;
11093e12c5d1SDavid du Colombier 	case MODEQ:
11103e12c5d1SDavid du Colombier 		if (yf == 0)
11117dd7cddfSDavid du Colombier 			FATAL("division by zero in %%=");
11123e12c5d1SDavid du Colombier 		modf(xf/yf, &v);
11133e12c5d1SDavid du Colombier 		xf = xf - yf * v;
11143e12c5d1SDavid du Colombier 		break;
11153e12c5d1SDavid du Colombier 	case POWEQ:
11163e12c5d1SDavid du Colombier 		if (yf >= 0 && modf(yf, &v) == 0.0)	/* pos integer exponent */
11173e12c5d1SDavid du Colombier 			xf = ipow(xf, (int) yf);
11183e12c5d1SDavid du Colombier 		else
11193e12c5d1SDavid du Colombier 			xf = errcheck(pow(xf, yf), "pow");
11203e12c5d1SDavid du Colombier 		break;
11213e12c5d1SDavid du Colombier 	default:
11227dd7cddfSDavid du Colombier 		FATAL("illegal assignment operator %d", n);
11233e12c5d1SDavid du Colombier 		break;
11243e12c5d1SDavid du Colombier 	}
11253e12c5d1SDavid du Colombier 	tempfree(y);
11263e12c5d1SDavid du Colombier 	setfval(x, xf);
11273e12c5d1SDavid du Colombier 	return(x);
11283e12c5d1SDavid du Colombier }
11293e12c5d1SDavid du Colombier 
cat(Node ** a,int q)1130219b2ee8SDavid du Colombier Cell *cat(Node **a, int q)	/* a[0] cat a[1] */
11313e12c5d1SDavid du Colombier {
11327dd7cddfSDavid du Colombier 	Cell *x, *y, *z;
11337dd7cddfSDavid du Colombier 	int n1, n2;
11347dd7cddfSDavid du Colombier 	char *s;
11353e12c5d1SDavid du Colombier 
11363e12c5d1SDavid du Colombier 	x = execute(a[0]);
11373e12c5d1SDavid du Colombier 	y = execute(a[1]);
11383e12c5d1SDavid du Colombier 	getsval(x);
11393e12c5d1SDavid du Colombier 	getsval(y);
11403e12c5d1SDavid du Colombier 	n1 = strlen(x->sval);
11413e12c5d1SDavid du Colombier 	n2 = strlen(y->sval);
11427dd7cddfSDavid du Colombier 	s = (char *) malloc(n1 + n2 + 1);
11433e12c5d1SDavid du Colombier 	if (s == NULL)
11447dd7cddfSDavid du Colombier 		FATAL("out of space concatenating %.15s... and %.15s...",
11457dd7cddfSDavid du Colombier 			x->sval, y->sval);
11463e12c5d1SDavid du Colombier 	strcpy(s, x->sval);
11473e12c5d1SDavid du Colombier 	strcpy(s+n1, y->sval);
11483e12c5d1SDavid du Colombier 	tempfree(y);
11493e12c5d1SDavid du Colombier 	z = gettemp();
11503e12c5d1SDavid du Colombier 	z->sval = s;
11513e12c5d1SDavid du Colombier 	z->tval = STR;
11523e12c5d1SDavid du Colombier 	tempfree(x);
11533e12c5d1SDavid du Colombier 	return(z);
11543e12c5d1SDavid du Colombier }
11553e12c5d1SDavid du Colombier 
pastat(Node ** a,int n)11563e12c5d1SDavid du Colombier Cell *pastat(Node **a, int n)	/* a[0] { a[1] } */
11573e12c5d1SDavid du Colombier {
11587dd7cddfSDavid du Colombier 	Cell *x;
11593e12c5d1SDavid du Colombier 
11603e12c5d1SDavid du Colombier 	if (a[0] == 0)
11613e12c5d1SDavid du Colombier 		x = execute(a[1]);
11623e12c5d1SDavid du Colombier 	else {
11633e12c5d1SDavid du Colombier 		x = execute(a[0]);
11643e12c5d1SDavid du Colombier 		if (istrue(x)) {
11653e12c5d1SDavid du Colombier 			tempfree(x);
11663e12c5d1SDavid du Colombier 			x = execute(a[1]);
11673e12c5d1SDavid du Colombier 		}
11683e12c5d1SDavid du Colombier 	}
11693e12c5d1SDavid du Colombier 	return x;
11703e12c5d1SDavid du Colombier }
11713e12c5d1SDavid du Colombier 
dopa2(Node ** a,int n)11723e12c5d1SDavid du Colombier Cell *dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
11733e12c5d1SDavid du Colombier {
11747dd7cddfSDavid du Colombier 	Cell *x;
11757dd7cddfSDavid du Colombier 	int pair;
11763e12c5d1SDavid du Colombier 
11777dd7cddfSDavid du Colombier 	pair = ptoi(a[3]);
11783e12c5d1SDavid du Colombier 	if (pairstack[pair] == 0) {
11793e12c5d1SDavid du Colombier 		x = execute(a[0]);
11803e12c5d1SDavid du Colombier 		if (istrue(x))
11813e12c5d1SDavid du Colombier 			pairstack[pair] = 1;
11823e12c5d1SDavid du Colombier 		tempfree(x);
11833e12c5d1SDavid du Colombier 	}
11843e12c5d1SDavid du Colombier 	if (pairstack[pair] == 1) {
11853e12c5d1SDavid du Colombier 		x = execute(a[1]);
11863e12c5d1SDavid du Colombier 		if (istrue(x))
11873e12c5d1SDavid du Colombier 			pairstack[pair] = 0;
11883e12c5d1SDavid du Colombier 		tempfree(x);
11893e12c5d1SDavid du Colombier 		x = execute(a[2]);
11903e12c5d1SDavid du Colombier 		return(x);
11913e12c5d1SDavid du Colombier 	}
11927dd7cddfSDavid du Colombier 	return(False);
11933e12c5d1SDavid du Colombier }
11943e12c5d1SDavid du Colombier 
split(Node ** a,int nnn)11953e12c5d1SDavid du Colombier Cell *split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
11963e12c5d1SDavid du Colombier {
11977dd7cddfSDavid du Colombier 	Cell *x = 0, *y, *ap;
1198535404a9SDavid du Colombier 	char *s, *t, *fs = 0;
1199535404a9SDavid du Colombier 	char temp, num[50];
1200535404a9SDavid du Colombier 	int n, nb, sep, tempstat, arg3type;
12013e12c5d1SDavid du Colombier 
12023e12c5d1SDavid du Colombier 	y = execute(a[0]);	/* source string */
12033e12c5d1SDavid du Colombier 	s = getsval(y);
12047dd7cddfSDavid du Colombier 	arg3type = ptoi(a[3]);
12053e12c5d1SDavid du Colombier 	if (a[2] == 0)		/* fs string */
12063e12c5d1SDavid du Colombier 		fs = *FS;
12077dd7cddfSDavid du Colombier 	else if (arg3type == STRING) {	/* split(str,arr,"string") */
12083e12c5d1SDavid du Colombier 		x = execute(a[2]);
12093e12c5d1SDavid du Colombier 		fs = getsval(x);
12107dd7cddfSDavid du Colombier 	} else if (arg3type == REGEXPR)
12117dd7cddfSDavid du Colombier 		fs = "(regexpr)";	/* split(str,arr,/regexpr/) */
12123e12c5d1SDavid du Colombier 	else
12137dd7cddfSDavid du Colombier 		FATAL("illegal type of split");
12143e12c5d1SDavid du Colombier 	sep = *fs;
12153e12c5d1SDavid du Colombier 	ap = execute(a[1]);	/* array name */
12163e12c5d1SDavid du Colombier 	freesymtab(ap);
12173e12c5d1SDavid du Colombier 	   dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
12183e12c5d1SDavid du Colombier 	ap->tval &= ~STR;
12193e12c5d1SDavid du Colombier 	ap->tval |= ARR;
12207dd7cddfSDavid du Colombier 	ap->sval = (char *) makesymtab(NSYMTAB);
12213e12c5d1SDavid du Colombier 
12223e12c5d1SDavid du Colombier 	n = 0;
12237dd7cddfSDavid du Colombier 	if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) {	/* reg expr */
12243e12c5d1SDavid du Colombier 		void *p;
12257dd7cddfSDavid du Colombier 		if (arg3type == REGEXPR) {	/* it's ready already */
12263e12c5d1SDavid du Colombier 			p = (void *) a[2];
12273e12c5d1SDavid du Colombier 		} else {
12283e12c5d1SDavid du Colombier 			p = compre(fs);
12293e12c5d1SDavid du Colombier 		}
12303e12c5d1SDavid du Colombier 		t = s;
12313e12c5d1SDavid du Colombier 		if (nematch(p,s,t)) {
12323e12c5d1SDavid du Colombier 			do {
12333e12c5d1SDavid du Colombier 				n++;
12347dd7cddfSDavid du Colombier 				sprintf(num, "%d", n);
12353e12c5d1SDavid du Colombier 				temp = *patbeg;
12363e12c5d1SDavid du Colombier 				*patbeg = '\0';
12377dd7cddfSDavid du Colombier 				if (is_number(t))
12387dd7cddfSDavid du Colombier 					setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
12393e12c5d1SDavid du Colombier 				else
12403e12c5d1SDavid du Colombier 					setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
12413e12c5d1SDavid du Colombier 				*patbeg = temp;
12423e12c5d1SDavid du Colombier 				t = patbeg + patlen;
12433e12c5d1SDavid du Colombier 				if (t[-1] == 0 || *t == 0) {
12443e12c5d1SDavid du Colombier 					n++;
12457dd7cddfSDavid du Colombier 					sprintf(num, "%d", n);
12463e12c5d1SDavid du Colombier 					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
12473e12c5d1SDavid du Colombier 					goto spdone;
12483e12c5d1SDavid du Colombier 				}
12493e12c5d1SDavid du Colombier 			} while (nematch(p,s,t));
12503e12c5d1SDavid du Colombier 		}
12513e12c5d1SDavid du Colombier 		n++;
12527dd7cddfSDavid du Colombier 		sprintf(num, "%d", n);
12537dd7cddfSDavid du Colombier 		if (is_number(t))
12547dd7cddfSDavid du Colombier 			setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
12553e12c5d1SDavid du Colombier 		else
12563e12c5d1SDavid du Colombier 			setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
12573e12c5d1SDavid du Colombier   spdone:
12583e12c5d1SDavid du Colombier 		p = NULL;
12593e12c5d1SDavid du Colombier 	} else if (sep == ' ') {
12603e12c5d1SDavid du Colombier 		for (n = 0; ; ) {
12613e12c5d1SDavid du Colombier 			while (*s == ' ' || *s == '\t' || *s == '\n')
12623e12c5d1SDavid du Colombier 				s++;
12633e12c5d1SDavid du Colombier 			if (*s == 0)
12643e12c5d1SDavid du Colombier 				break;
12653e12c5d1SDavid du Colombier 			n++;
12663e12c5d1SDavid du Colombier 			t = s;
12673e12c5d1SDavid du Colombier 			do
12683e12c5d1SDavid du Colombier 				s++;
12693e12c5d1SDavid du Colombier 			while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
12703e12c5d1SDavid du Colombier 			temp = *s;
12713e12c5d1SDavid du Colombier 			*s = '\0';
12727dd7cddfSDavid du Colombier 			sprintf(num, "%d", n);
12737dd7cddfSDavid du Colombier 			if (is_number(t))
12747dd7cddfSDavid du Colombier 				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
12753e12c5d1SDavid du Colombier 			else
12763e12c5d1SDavid du Colombier 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
12773e12c5d1SDavid du Colombier 			*s = temp;
12783e12c5d1SDavid du Colombier 			if (*s != 0)
12793e12c5d1SDavid du Colombier 				s++;
12803e12c5d1SDavid du Colombier 		}
12817dd7cddfSDavid du Colombier 	} else if (sep == 0) {	/* new: split(s, a, "") => 1 char/elem */
1282535404a9SDavid du Colombier 		for (n = 0; *s != 0; s += nb) {
1283535404a9SDavid du Colombier 			Rune r;
1284535404a9SDavid du Colombier 			char buf[UTFmax+1];
1285535404a9SDavid du Colombier 
12867dd7cddfSDavid du Colombier 			n++;
1287535404a9SDavid du Colombier 			snprintf(num, sizeof num, "%d", n);
1288535404a9SDavid du Colombier 			nb = chartorune(&r, s);
1289535404a9SDavid du Colombier 			memmove(buf, s, nb);
1290535404a9SDavid du Colombier 			buf[nb] = '\0';
12917dd7cddfSDavid du Colombier 			if (isdigit(buf[0]))
12927dd7cddfSDavid du Colombier 				setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
12937dd7cddfSDavid du Colombier 			else
12947dd7cddfSDavid du Colombier 				setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
12957dd7cddfSDavid du Colombier 		}
12963e12c5d1SDavid du Colombier 	} else if (*s != 0) {
12973e12c5d1SDavid du Colombier 		for (;;) {
12983e12c5d1SDavid du Colombier 			n++;
12993e12c5d1SDavid du Colombier 			t = s;
13003e12c5d1SDavid du Colombier 			while (*s != sep && *s != '\n' && *s != '\0')
13013e12c5d1SDavid du Colombier 				s++;
13023e12c5d1SDavid du Colombier 			temp = *s;
13033e12c5d1SDavid du Colombier 			*s = '\0';
13047dd7cddfSDavid du Colombier 			sprintf(num, "%d", n);
13057dd7cddfSDavid du Colombier 			if (is_number(t))
13067dd7cddfSDavid du Colombier 				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
13073e12c5d1SDavid du Colombier 			else
13083e12c5d1SDavid du Colombier 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
13093e12c5d1SDavid du Colombier 			*s = temp;
13103e12c5d1SDavid du Colombier 			if (*s++ == 0)
13113e12c5d1SDavid du Colombier 				break;
13123e12c5d1SDavid du Colombier 		}
13133e12c5d1SDavid du Colombier 	}
13143e12c5d1SDavid du Colombier 	tempfree(ap);
13153e12c5d1SDavid du Colombier 	tempfree(y);
13167dd7cddfSDavid du Colombier 	if (a[2] != 0 && arg3type == STRING)
13173e12c5d1SDavid du Colombier 		tempfree(x);
13183e12c5d1SDavid du Colombier 	x = gettemp();
13193e12c5d1SDavid du Colombier 	x->tval = NUM;
13203e12c5d1SDavid du Colombier 	x->fval = n;
13213e12c5d1SDavid du Colombier 	return(x);
13223e12c5d1SDavid du Colombier }
13233e12c5d1SDavid du Colombier 
condexpr(Node ** a,int n)13243e12c5d1SDavid du Colombier Cell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
13253e12c5d1SDavid du Colombier {
13267dd7cddfSDavid du Colombier 	Cell *x;
13273e12c5d1SDavid du Colombier 
13283e12c5d1SDavid du Colombier 	x = execute(a[0]);
13293e12c5d1SDavid du Colombier 	if (istrue(x)) {
13303e12c5d1SDavid du Colombier 		tempfree(x);
13313e12c5d1SDavid du Colombier 		x = execute(a[1]);
13323e12c5d1SDavid du Colombier 	} else {
13333e12c5d1SDavid du Colombier 		tempfree(x);
13343e12c5d1SDavid du Colombier 		x = execute(a[2]);
13353e12c5d1SDavid du Colombier 	}
13363e12c5d1SDavid du Colombier 	return(x);
13373e12c5d1SDavid du Colombier }
13383e12c5d1SDavid du Colombier 
ifstat(Node ** a,int n)13393e12c5d1SDavid du Colombier Cell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
13403e12c5d1SDavid du Colombier {
13417dd7cddfSDavid du Colombier 	Cell *x;
13423e12c5d1SDavid du Colombier 
13433e12c5d1SDavid du Colombier 	x = execute(a[0]);
13443e12c5d1SDavid du Colombier 	if (istrue(x)) {
13453e12c5d1SDavid du Colombier 		tempfree(x);
13463e12c5d1SDavid du Colombier 		x = execute(a[1]);
13473e12c5d1SDavid du Colombier 	} else if (a[2] != 0) {
13483e12c5d1SDavid du Colombier 		tempfree(x);
13493e12c5d1SDavid du Colombier 		x = execute(a[2]);
13503e12c5d1SDavid du Colombier 	}
13513e12c5d1SDavid du Colombier 	return(x);
13523e12c5d1SDavid du Colombier }
13533e12c5d1SDavid du Colombier 
whilestat(Node ** a,int n)13543e12c5d1SDavid du Colombier Cell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
13553e12c5d1SDavid du Colombier {
13567dd7cddfSDavid du Colombier 	Cell *x;
13573e12c5d1SDavid du Colombier 
13583e12c5d1SDavid du Colombier 	for (;;) {
13593e12c5d1SDavid du Colombier 		x = execute(a[0]);
13603e12c5d1SDavid du Colombier 		if (!istrue(x))
13613e12c5d1SDavid du Colombier 			return(x);
13623e12c5d1SDavid du Colombier 		tempfree(x);
13633e12c5d1SDavid du Colombier 		x = execute(a[1]);
13643e12c5d1SDavid du Colombier 		if (isbreak(x)) {
13657dd7cddfSDavid du Colombier 			x = True;
13663e12c5d1SDavid du Colombier 			return(x);
13673e12c5d1SDavid du Colombier 		}
13683e12c5d1SDavid du Colombier 		if (isnext(x) || isexit(x) || isret(x))
13693e12c5d1SDavid du Colombier 			return(x);
13703e12c5d1SDavid du Colombier 		tempfree(x);
13713e12c5d1SDavid du Colombier 	}
13723e12c5d1SDavid du Colombier }
13733e12c5d1SDavid du Colombier 
dostat(Node ** a,int n)13743e12c5d1SDavid du Colombier Cell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
13753e12c5d1SDavid du Colombier {
13767dd7cddfSDavid du Colombier 	Cell *x;
13773e12c5d1SDavid du Colombier 
13783e12c5d1SDavid du Colombier 	for (;;) {
13793e12c5d1SDavid du Colombier 		x = execute(a[0]);
13803e12c5d1SDavid du Colombier 		if (isbreak(x))
13817dd7cddfSDavid du Colombier 			return True;
13827dd7cddfSDavid du Colombier 		if (isnext(x) || isnextfile(x) || isexit(x) || isret(x))
13833e12c5d1SDavid du Colombier 			return(x);
13843e12c5d1SDavid du Colombier 		tempfree(x);
13853e12c5d1SDavid du Colombier 		x = execute(a[1]);
13863e12c5d1SDavid du Colombier 		if (!istrue(x))
13873e12c5d1SDavid du Colombier 			return(x);
13883e12c5d1SDavid du Colombier 		tempfree(x);
13893e12c5d1SDavid du Colombier 	}
13903e12c5d1SDavid du Colombier }
13913e12c5d1SDavid du Colombier 
forstat(Node ** a,int n)13923e12c5d1SDavid du Colombier Cell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
13933e12c5d1SDavid du Colombier {
13947dd7cddfSDavid du Colombier 	Cell *x;
13953e12c5d1SDavid du Colombier 
13963e12c5d1SDavid du Colombier 	x = execute(a[0]);
13973e12c5d1SDavid du Colombier 	tempfree(x);
13983e12c5d1SDavid du Colombier 	for (;;) {
13993e12c5d1SDavid du Colombier 		if (a[1]!=0) {
14003e12c5d1SDavid du Colombier 			x = execute(a[1]);
14013e12c5d1SDavid du Colombier 			if (!istrue(x)) return(x);
14023e12c5d1SDavid du Colombier 			else tempfree(x);
14033e12c5d1SDavid du Colombier 		}
14043e12c5d1SDavid du Colombier 		x = execute(a[3]);
14053e12c5d1SDavid du Colombier 		if (isbreak(x))		/* turn off break */
14067dd7cddfSDavid du Colombier 			return True;
14073e12c5d1SDavid du Colombier 		if (isnext(x) || isexit(x) || isret(x))
14083e12c5d1SDavid du Colombier 			return(x);
14093e12c5d1SDavid du Colombier 		tempfree(x);
14103e12c5d1SDavid du Colombier 		x = execute(a[2]);
14113e12c5d1SDavid du Colombier 		tempfree(x);
14123e12c5d1SDavid du Colombier 	}
14133e12c5d1SDavid du Colombier }
14143e12c5d1SDavid du Colombier 
instat(Node ** a,int n)14153e12c5d1SDavid du Colombier Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
14163e12c5d1SDavid du Colombier {
14177dd7cddfSDavid du Colombier 	Cell *x, *vp, *arrayp, *cp, *ncp;
14183e12c5d1SDavid du Colombier 	Array *tp;
14193e12c5d1SDavid du Colombier 	int i;
14203e12c5d1SDavid du Colombier 
14213e12c5d1SDavid du Colombier 	vp = execute(a[0]);
14223e12c5d1SDavid du Colombier 	arrayp = execute(a[1]);
14233e12c5d1SDavid du Colombier 	if (!isarr(arrayp)) {
14247dd7cddfSDavid du Colombier 		return True;
14253e12c5d1SDavid du Colombier 	}
14263e12c5d1SDavid du Colombier 	tp = (Array *) arrayp->sval;
14273e12c5d1SDavid du Colombier 	tempfree(arrayp);
14283e12c5d1SDavid du Colombier 	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
14293e12c5d1SDavid du Colombier 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
14303e12c5d1SDavid du Colombier 			setsval(vp, cp->nval);
14313e12c5d1SDavid du Colombier 			ncp = cp->cnext;
14323e12c5d1SDavid du Colombier 			x = execute(a[2]);
14333e12c5d1SDavid du Colombier 			if (isbreak(x)) {
14343e12c5d1SDavid du Colombier 				tempfree(vp);
14357dd7cddfSDavid du Colombier 				return True;
14363e12c5d1SDavid du Colombier 			}
14373e12c5d1SDavid du Colombier 			if (isnext(x) || isexit(x) || isret(x)) {
14383e12c5d1SDavid du Colombier 				tempfree(vp);
14393e12c5d1SDavid du Colombier 				return(x);
14403e12c5d1SDavid du Colombier 			}
14413e12c5d1SDavid du Colombier 			tempfree(x);
14423e12c5d1SDavid du Colombier 		}
14433e12c5d1SDavid du Colombier 	}
14447dd7cddfSDavid du Colombier 	return True;
14453e12c5d1SDavid du Colombier }
14463e12c5d1SDavid du Colombier 
bltin(Node ** a,int n)1447219b2ee8SDavid du Colombier Cell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
14483e12c5d1SDavid du Colombier {
14497dd7cddfSDavid du Colombier 	Cell *x, *y;
14503e12c5d1SDavid du Colombier 	Awkfloat u;
14517dd7cddfSDavid du Colombier 	int t;
1452219b2ee8SDavid du Colombier 	wchar_t wc;
14537dd7cddfSDavid du Colombier 	char *p, *buf;
14547dd7cddfSDavid du Colombier 	char mbc[50];
14553e12c5d1SDavid du Colombier 	Node *nextarg;
14563e12c5d1SDavid du Colombier 	FILE *fp;
1457*4eeb7838SDavid du Colombier 	void flush_all(void);
14583e12c5d1SDavid du Colombier 
14597dd7cddfSDavid du Colombier 	t = ptoi(a[0]);
14603e12c5d1SDavid du Colombier 	x = execute(a[1]);
14613e12c5d1SDavid du Colombier 	nextarg = a[1]->nnext;
14623e12c5d1SDavid du Colombier 	switch (t) {
14633e12c5d1SDavid du Colombier 	case FLENGTH:
1464*4eeb7838SDavid du Colombier 		if (isarr(x))
1465*4eeb7838SDavid du Colombier 			u = ((Array *) x->sval)->nelem;	/* GROT. should be function*/
1466*4eeb7838SDavid du Colombier 		else {
14673e12c5d1SDavid du Colombier 			p = getsval(x);
1468*4eeb7838SDavid du Colombier 			u = (Awkfloat) countposn(p, strlen(p));
1469*4eeb7838SDavid du Colombier 		}
1470*4eeb7838SDavid du Colombier 		break;
14713e12c5d1SDavid du Colombier 	case FLOG:
14723e12c5d1SDavid du Colombier 		u = errcheck(log(getfval(x)), "log"); break;
14733e12c5d1SDavid du Colombier 	case FINT:
14743e12c5d1SDavid du Colombier 		modf(getfval(x), &u); break;
14753e12c5d1SDavid du Colombier 	case FEXP:
14763e12c5d1SDavid du Colombier 		u = errcheck(exp(getfval(x)), "exp"); break;
14773e12c5d1SDavid du Colombier 	case FSQRT:
14783e12c5d1SDavid du Colombier 		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
14793e12c5d1SDavid du Colombier 	case FSIN:
14803e12c5d1SDavid du Colombier 		u = sin(getfval(x)); break;
14813e12c5d1SDavid du Colombier 	case FCOS:
14823e12c5d1SDavid du Colombier 		u = cos(getfval(x)); break;
14833e12c5d1SDavid du Colombier 	case FATAN:
14843e12c5d1SDavid du Colombier 		if (nextarg == 0) {
14857dd7cddfSDavid du Colombier 			WARNING("atan2 requires two arguments; returning 1.0");
14863e12c5d1SDavid du Colombier 			u = 1.0;
14873e12c5d1SDavid du Colombier 		} else {
14883e12c5d1SDavid du Colombier 			y = execute(a[1]->nnext);
14893e12c5d1SDavid du Colombier 			u = atan2(getfval(x), getfval(y));
14903e12c5d1SDavid du Colombier 			tempfree(y);
14913e12c5d1SDavid du Colombier 			nextarg = nextarg->nnext;
14923e12c5d1SDavid du Colombier 		}
14933e12c5d1SDavid du Colombier 		break;
14943e12c5d1SDavid du Colombier 	case FSYSTEM:
14953e12c5d1SDavid du Colombier 		fflush(stdout);		/* in case something is buffered already */
14967dd7cddfSDavid du Colombier 		u = (Awkfloat) system(getsval(x)) / 256;   /* 256 is unix-dep */
14973e12c5d1SDavid du Colombier 		break;
14983e12c5d1SDavid du Colombier 	case FRAND:
14993e12c5d1SDavid du Colombier 		/* in principle, rand() returns something in 0..RAND_MAX */
15003e12c5d1SDavid du Colombier 		u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
15013e12c5d1SDavid du Colombier 		break;
15023e12c5d1SDavid du Colombier 	case FSRAND:
15037dd7cddfSDavid du Colombier 		if (isrec(x))	/* no argument provided */
15047dd7cddfSDavid du Colombier 			u = time((time_t *)0);
15053e12c5d1SDavid du Colombier 		else
15063e12c5d1SDavid du Colombier 			u = getfval(x);
15077dd7cddfSDavid du Colombier 		srand((unsigned int) u);
15083e12c5d1SDavid du Colombier 		break;
15093e12c5d1SDavid du Colombier 	case FTOUPPER:
15103e12c5d1SDavid du Colombier 	case FTOLOWER:
15117dd7cddfSDavid du Colombier 		buf = tostring(getsval(x));
15123e12c5d1SDavid du Colombier 		if (t == FTOUPPER) {
15133e12c5d1SDavid du Colombier 			for (p = buf; *p; p++)
15143e12c5d1SDavid du Colombier 				if (islower(*p))
15153e12c5d1SDavid du Colombier 					*p = toupper(*p);
15163e12c5d1SDavid du Colombier 		} else {
15173e12c5d1SDavid du Colombier 			for (p = buf; *p; p++)
15183e12c5d1SDavid du Colombier 				if (isupper(*p))
15193e12c5d1SDavid du Colombier 					*p = tolower(*p);
15203e12c5d1SDavid du Colombier 		}
15213e12c5d1SDavid du Colombier 		tempfree(x);
15223e12c5d1SDavid du Colombier 		x = gettemp();
15233e12c5d1SDavid du Colombier 		setsval(x, buf);
15247dd7cddfSDavid du Colombier 		free(buf);
15253e12c5d1SDavid du Colombier 		return x;
15263e12c5d1SDavid du Colombier 	case FFLUSH:
1527*4eeb7838SDavid du Colombier 		if (isrec(x) || strlen(getsval(x)) == 0) {
1528*4eeb7838SDavid du Colombier 			flush_all();	/* fflush() or fflush("") -> all */
1529*4eeb7838SDavid du Colombier 			u = 0;
1530*4eeb7838SDavid du Colombier 		} else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
15313e12c5d1SDavid du Colombier 			u = EOF;
15323e12c5d1SDavid du Colombier 		else
15333e12c5d1SDavid du Colombier 			u = fflush(fp);
15343e12c5d1SDavid du Colombier 		break;
1535219b2ee8SDavid du Colombier 	case FUTF:
1536219b2ee8SDavid du Colombier 		wc = (int)getfval(x);
1537219b2ee8SDavid du Colombier 		mbc[wctomb(mbc, wc)] = 0;
1538219b2ee8SDavid du Colombier 		tempfree(x);
1539219b2ee8SDavid du Colombier 		x = gettemp();
1540219b2ee8SDavid du Colombier 		setsval(x, mbc);
1541219b2ee8SDavid du Colombier 		return x;
15423e12c5d1SDavid du Colombier 	default:	/* can't happen */
15437dd7cddfSDavid du Colombier 		FATAL("illegal function type %d", t);
15443e12c5d1SDavid du Colombier 		break;
15453e12c5d1SDavid du Colombier 	}
15463e12c5d1SDavid du Colombier 	tempfree(x);
15473e12c5d1SDavid du Colombier 	x = gettemp();
15483e12c5d1SDavid du Colombier 	setfval(x, u);
15493e12c5d1SDavid du Colombier 	if (nextarg != 0) {
15507dd7cddfSDavid du Colombier 		WARNING("warning: function has too many arguments");
15513e12c5d1SDavid du Colombier 		for ( ; nextarg; nextarg = nextarg->nnext)
15523e12c5d1SDavid du Colombier 			execute(nextarg);
15533e12c5d1SDavid du Colombier 	}
15543e12c5d1SDavid du Colombier 	return(x);
15553e12c5d1SDavid du Colombier }
15563e12c5d1SDavid du Colombier 
printstat(Node ** a,int n)1557219b2ee8SDavid du Colombier Cell *printstat(Node **a, int n)	/* print a[0] */
15583e12c5d1SDavid du Colombier {
155905bfb676SDavid du Colombier 	int r;
15607dd7cddfSDavid du Colombier 	Node *x;
15617dd7cddfSDavid du Colombier 	Cell *y;
15623e12c5d1SDavid du Colombier 	FILE *fp;
15633e12c5d1SDavid du Colombier 
1564219b2ee8SDavid du Colombier 	if (a[1] == 0)	/* a[1] is redirection operator, a[2] is file */
15653e12c5d1SDavid du Colombier 		fp = stdout;
15663e12c5d1SDavid du Colombier 	else
15677dd7cddfSDavid du Colombier 		fp = redirect(ptoi(a[1]), a[2]);
15683e12c5d1SDavid du Colombier 	for (x = a[0]; x != NULL; x = x->nnext) {
15693e12c5d1SDavid du Colombier 		y = execute(x);
15707dd7cddfSDavid du Colombier 		fputs(getsval(y), fp);
15713e12c5d1SDavid du Colombier 		tempfree(y);
15723e12c5d1SDavid du Colombier 		if (x->nnext == NULL)
157305bfb676SDavid du Colombier 			r = fputs(*ORS, fp);
15743e12c5d1SDavid du Colombier 		else
157505bfb676SDavid du Colombier 			r = fputs(*OFS, fp);
157605bfb676SDavid du Colombier 		if (r == EOF)
157705bfb676SDavid du Colombier 			FATAL("write error on %s", filename(fp));
15783e12c5d1SDavid du Colombier 	}
15793e12c5d1SDavid du Colombier 	if (a[1] != 0)
158005bfb676SDavid du Colombier 		if (fflush(fp) == EOF)
15817dd7cddfSDavid du Colombier 			FATAL("write error on %s", filename(fp));
15827dd7cddfSDavid du Colombier 	return(True);
15833e12c5d1SDavid du Colombier }
15843e12c5d1SDavid du Colombier 
nullproc(Node ** a,int n)15853e12c5d1SDavid du Colombier Cell *nullproc(Node **a, int n)
15863e12c5d1SDavid du Colombier {
15877dd7cddfSDavid du Colombier 	n = n;
15887dd7cddfSDavid du Colombier 	a = a;
15893e12c5d1SDavid du Colombier 	return 0;
15903e12c5d1SDavid du Colombier }
15913e12c5d1SDavid du Colombier 
15923e12c5d1SDavid du Colombier 
redirect(int a,Node * b)1593219b2ee8SDavid du Colombier FILE *redirect(int a, Node *b)	/* set up all i/o redirections */
15943e12c5d1SDavid du Colombier {
15953e12c5d1SDavid du Colombier 	FILE *fp;
15963e12c5d1SDavid du Colombier 	Cell *x;
15977dd7cddfSDavid du Colombier 	char *fname;
15983e12c5d1SDavid du Colombier 
15993e12c5d1SDavid du Colombier 	x = execute(b);
16003e12c5d1SDavid du Colombier 	fname = getsval(x);
16013e12c5d1SDavid du Colombier 	fp = openfile(a, fname);
16023e12c5d1SDavid du Colombier 	if (fp == NULL)
16037dd7cddfSDavid du Colombier 		FATAL("can't open file %s", fname);
16043e12c5d1SDavid du Colombier 	tempfree(x);
16053e12c5d1SDavid du Colombier 	return fp;
16063e12c5d1SDavid du Colombier }
16073e12c5d1SDavid du Colombier 
1608219b2ee8SDavid du Colombier struct files {
1609219b2ee8SDavid du Colombier 	FILE	*fp;
16107dd7cddfSDavid du Colombier 	char	*fname;
1611219b2ee8SDavid du Colombier 	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
1612219b2ee8SDavid du Colombier } files[FOPEN_MAX] ={
16137dd7cddfSDavid du Colombier 	{ NULL,  "/dev/stdin",  LT },	/* watch out: don't free this! */
16147dd7cddfSDavid du Colombier 	{ NULL, "/dev/stdout", GT },
16157dd7cddfSDavid du Colombier 	{ NULL, "/dev/stderr", GT }
1616219b2ee8SDavid du Colombier };
1617219b2ee8SDavid du Colombier 
stdinit(void)16187dd7cddfSDavid du Colombier void stdinit(void)	/* in case stdin, etc., are not constants */
16193e12c5d1SDavid du Colombier {
16207dd7cddfSDavid du Colombier 	files[0].fp = stdin;
16217dd7cddfSDavid du Colombier 	files[1].fp = stdout;
16227dd7cddfSDavid du Colombier 	files[2].fp = stderr;
16237dd7cddfSDavid du Colombier }
16247dd7cddfSDavid du Colombier 
openfile(int a,char * us)16257dd7cddfSDavid du Colombier FILE *openfile(int a, char *us)
16267dd7cddfSDavid du Colombier {
16277dd7cddfSDavid du Colombier 	char *s = us;
16287dd7cddfSDavid du Colombier 	int i, m;
16297dd7cddfSDavid du Colombier 	FILE *fp = 0;
16303e12c5d1SDavid du Colombier 
16313e12c5d1SDavid du Colombier 	if (*s == '\0')
16327dd7cddfSDavid du Colombier 		FATAL("null file name in print or getline");
16333e12c5d1SDavid du Colombier 	for (i=0; i < FOPEN_MAX; i++)
16347dd7cddfSDavid du Colombier 		if (files[i].fname && strcmp(s, files[i].fname) == 0) {
16357dd7cddfSDavid du Colombier 			if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
16363e12c5d1SDavid du Colombier 				return files[i].fp;
16377dd7cddfSDavid du Colombier 			if (a == FFLUSH)
16387dd7cddfSDavid du Colombier 				return files[i].fp;
16397dd7cddfSDavid du Colombier 		}
16407dd7cddfSDavid du Colombier 	if (a == FFLUSH)	/* didn't find it, so don't create it! */
16417dd7cddfSDavid du Colombier 		return NULL;
16427dd7cddfSDavid du Colombier 
16433e12c5d1SDavid du Colombier 	for (i=0; i < FOPEN_MAX; i++)
16443e12c5d1SDavid du Colombier 		if (files[i].fp == 0)
16453e12c5d1SDavid du Colombier 			break;
16463e12c5d1SDavid du Colombier 	if (i >= FOPEN_MAX)
16477dd7cddfSDavid du Colombier 		FATAL("%s makes too many open files", s);
16483e12c5d1SDavid du Colombier 	fflush(stdout);	/* force a semblance of order */
16493e12c5d1SDavid du Colombier 	m = a;
16503e12c5d1SDavid du Colombier 	if (a == GT) {
1651219b2ee8SDavid du Colombier 		fp = fopen(s, "w");
16523e12c5d1SDavid du Colombier 	} else if (a == APPEND) {
1653219b2ee8SDavid du Colombier 		fp = fopen(s, "a");
16543e12c5d1SDavid du Colombier 		m = GT;	/* so can mix > and >> */
16553e12c5d1SDavid du Colombier 	} else if (a == '|') {	/* output pipe */
1656219b2ee8SDavid du Colombier 		fp = popen(s, "w");
16573e12c5d1SDavid du Colombier 	} else if (a == LE) {	/* input pipe */
1658219b2ee8SDavid du Colombier 		fp = popen(s, "r");
16593e12c5d1SDavid du Colombier 	} else if (a == LT) {	/* getline <file */
1660219b2ee8SDavid du Colombier 		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
16613e12c5d1SDavid du Colombier 	} else	/* can't happen */
16627dd7cddfSDavid du Colombier 		FATAL("illegal redirection %d", a);
16633e12c5d1SDavid du Colombier 	if (fp != NULL) {
16643e12c5d1SDavid du Colombier 		files[i].fname = tostring(s);
16653e12c5d1SDavid du Colombier 		files[i].fp = fp;
16663e12c5d1SDavid du Colombier 		files[i].mode = m;
16673e12c5d1SDavid du Colombier 	}
16683e12c5d1SDavid du Colombier 	return fp;
16693e12c5d1SDavid du Colombier }
16703e12c5d1SDavid du Colombier 
filename(FILE * fp)16717dd7cddfSDavid du Colombier char *filename(FILE *fp)
16723e12c5d1SDavid du Colombier {
16733e12c5d1SDavid du Colombier 	int i;
16743e12c5d1SDavid du Colombier 
16753e12c5d1SDavid du Colombier 	for (i = 0; i < FOPEN_MAX; i++)
16763e12c5d1SDavid du Colombier 		if (fp == files[i].fp)
16773e12c5d1SDavid du Colombier 			return files[i].fname;
1678219b2ee8SDavid du Colombier 	return "???";
16793e12c5d1SDavid du Colombier }
16803e12c5d1SDavid du Colombier 
closefile(Node ** a,int n)16813e12c5d1SDavid du Colombier Cell *closefile(Node **a, int n)
16823e12c5d1SDavid du Colombier {
16837dd7cddfSDavid du Colombier 	Cell *x;
16843e12c5d1SDavid du Colombier 	int i, stat;
16853e12c5d1SDavid du Colombier 
16867dd7cddfSDavid du Colombier 	n = n;
16873e12c5d1SDavid du Colombier 	x = execute(a[0]);
16883e12c5d1SDavid du Colombier 	getsval(x);
16893e12c5d1SDavid du Colombier 	for (i = 0; i < FOPEN_MAX; i++)
16903e12c5d1SDavid du Colombier 		if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
16913e12c5d1SDavid du Colombier 			if (ferror(files[i].fp))
16927dd7cddfSDavid du Colombier 				WARNING( "i/o error occurred on %s", files[i].fname );
16933e12c5d1SDavid du Colombier 			if (files[i].mode == '|' || files[i].mode == LE)
16943e12c5d1SDavid du Colombier 				stat = pclose(files[i].fp);
16953e12c5d1SDavid du Colombier 			else
16963e12c5d1SDavid du Colombier 				stat = fclose(files[i].fp);
16973e12c5d1SDavid du Colombier 			if (stat == EOF)
16987dd7cddfSDavid du Colombier 				WARNING( "i/o error occurred closing %s", files[i].fname );
1699219b2ee8SDavid du Colombier 			if (i > 2)	/* don't do /dev/std... */
17003e12c5d1SDavid du Colombier 				xfree(files[i].fname);
17013e12c5d1SDavid du Colombier 			files[i].fname = NULL;	/* watch out for ref thru this */
17023e12c5d1SDavid du Colombier 			files[i].fp = NULL;
17033e12c5d1SDavid du Colombier 		}
17043e12c5d1SDavid du Colombier 	tempfree(x);
17057dd7cddfSDavid du Colombier 	return(True);
17063e12c5d1SDavid du Colombier }
17073e12c5d1SDavid du Colombier 
closeall(void)17083e12c5d1SDavid du Colombier void closeall(void)
17093e12c5d1SDavid du Colombier {
17103e12c5d1SDavid du Colombier 	int i, stat;
17113e12c5d1SDavid du Colombier 
17123e12c5d1SDavid du Colombier 	for (i = 0; i < FOPEN_MAX; i++)
17133e12c5d1SDavid du Colombier 		if (files[i].fp) {
17143e12c5d1SDavid du Colombier 			if (ferror(files[i].fp))
17157dd7cddfSDavid du Colombier 				WARNING( "i/o error occurred on %s", files[i].fname );
17163e12c5d1SDavid du Colombier 			if (files[i].mode == '|' || files[i].mode == LE)
17173e12c5d1SDavid du Colombier 				stat = pclose(files[i].fp);
17183e12c5d1SDavid du Colombier 			else
17193e12c5d1SDavid du Colombier 				stat = fclose(files[i].fp);
17203e12c5d1SDavid du Colombier 			if (stat == EOF)
17217dd7cddfSDavid du Colombier 				WARNING( "i/o error occurred while closing %s", files[i].fname );
17223e12c5d1SDavid du Colombier 		}
17233e12c5d1SDavid du Colombier }
17243e12c5d1SDavid du Colombier 
flush_all(void)1725*4eeb7838SDavid du Colombier void flush_all(void)
1726*4eeb7838SDavid du Colombier {
1727*4eeb7838SDavid du Colombier 	int i;
1728*4eeb7838SDavid du Colombier 
1729*4eeb7838SDavid du Colombier 	for (i = 0; i < FOPEN_MAX; i++)
1730*4eeb7838SDavid du Colombier 		if (files[i].fp)
1731*4eeb7838SDavid du Colombier 			fflush(files[i].fp);
1732*4eeb7838SDavid du Colombier }
1733*4eeb7838SDavid du Colombier 
17347dd7cddfSDavid du Colombier void backsub(char **pb_ptr, char **sptr_ptr);
17353e12c5d1SDavid du Colombier 
sub(Node ** a,int nnn)1736219b2ee8SDavid du Colombier Cell *sub(Node **a, int nnn)	/* substitute command */
17373e12c5d1SDavid du Colombier {
17387dd7cddfSDavid du Colombier 	char *sptr, *pb, *q;
17397dd7cddfSDavid du Colombier 	Cell *x, *y, *result;
17407dd7cddfSDavid du Colombier 	char *t, *buf;
17413e12c5d1SDavid du Colombier 	void *p;
17427dd7cddfSDavid du Colombier 	int bufsz = recsize;
17433e12c5d1SDavid du Colombier 
17447dd7cddfSDavid du Colombier 	if ((buf = (char *) malloc(bufsz)) == NULL)
17457dd7cddfSDavid du Colombier 		FATAL("out of memory in sub");
17463e12c5d1SDavid du Colombier 	x = execute(a[3]);	/* target string */
17473e12c5d1SDavid du Colombier 	t = getsval(x);
1748219b2ee8SDavid du Colombier 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
17493e12c5d1SDavid du Colombier 		p = (void *) a[1];	/* regular expression */
17503e12c5d1SDavid du Colombier 	else {
17513e12c5d1SDavid du Colombier 		y = execute(a[1]);
17523e12c5d1SDavid du Colombier 		p = compre(getsval(y));
17533e12c5d1SDavid du Colombier 		tempfree(y);
17543e12c5d1SDavid du Colombier 	}
17553e12c5d1SDavid du Colombier 	y = execute(a[2]);	/* replacement string */
17567dd7cddfSDavid du Colombier 	result = False;
17573e12c5d1SDavid du Colombier 	if (pmatch(p, t, t)) {
17583e12c5d1SDavid du Colombier 		sptr = t;
17597dd7cddfSDavid du Colombier 		adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
17607dd7cddfSDavid du Colombier 		pb = buf;
17613e12c5d1SDavid du Colombier 		while (sptr < patbeg)
17623e12c5d1SDavid du Colombier 			*pb++ = *sptr++;
17633e12c5d1SDavid du Colombier 		sptr = getsval(y);
17647dd7cddfSDavid du Colombier 		while (*sptr != 0) {
17657dd7cddfSDavid du Colombier 			adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
17667dd7cddfSDavid du Colombier 			if (*sptr == '\\') {
17677dd7cddfSDavid du Colombier 				backsub(&pb, &sptr);
17683e12c5d1SDavid du Colombier 			} else if (*sptr == '&') {
17693e12c5d1SDavid du Colombier 				sptr++;
17707dd7cddfSDavid du Colombier 				adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
17713e12c5d1SDavid du Colombier 				for (q = patbeg; q < patbeg+patlen; )
17723e12c5d1SDavid du Colombier 					*pb++ = *q++;
17733e12c5d1SDavid du Colombier 			} else
17743e12c5d1SDavid du Colombier 				*pb++ = *sptr++;
17757dd7cddfSDavid du Colombier 		}
17763e12c5d1SDavid du Colombier 		*pb = '\0';
17777dd7cddfSDavid du Colombier 		if (pb > buf + bufsz)
17787dd7cddfSDavid du Colombier 			FATAL("sub result1 %.30s too big; can't happen", buf);
17793e12c5d1SDavid du Colombier 		sptr = patbeg + patlen;
17807dd7cddfSDavid du Colombier 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
17817dd7cddfSDavid du Colombier 			adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
17827dd7cddfSDavid du Colombier 			while ((*pb++ = *sptr++) != 0)
17833e12c5d1SDavid du Colombier 				;
17847dd7cddfSDavid du Colombier 		}
17857dd7cddfSDavid du Colombier 		if (pb > buf + bufsz)
17867dd7cddfSDavid du Colombier 			FATAL("sub result2 %.30s too big; can't happen", buf);
17877dd7cddfSDavid du Colombier 		setsval(x, buf);	/* BUG: should be able to avoid copy */
17887dd7cddfSDavid du Colombier 		result = True;;
17893e12c5d1SDavid du Colombier 	}
17903e12c5d1SDavid du Colombier 	tempfree(x);
17913e12c5d1SDavid du Colombier 	tempfree(y);
17927dd7cddfSDavid du Colombier 	free(buf);
17933e12c5d1SDavid du Colombier 	return result;
17943e12c5d1SDavid du Colombier }
17953e12c5d1SDavid du Colombier 
gsub(Node ** a,int nnn)1796219b2ee8SDavid du Colombier Cell *gsub(Node **a, int nnn)	/* global substitute */
17973e12c5d1SDavid du Colombier {
17987dd7cddfSDavid du Colombier 	Cell *x, *y;
17997dd7cddfSDavid du Colombier 	char *rptr, *sptr, *t, *pb, *c;
18007dd7cddfSDavid du Colombier 	char *buf;
18017dd7cddfSDavid du Colombier 	void *p;
18023e12c5d1SDavid du Colombier 	int mflag, num;
18037dd7cddfSDavid du Colombier 	int bufsz = recsize;
18043e12c5d1SDavid du Colombier 
18057dd7cddfSDavid du Colombier 	if ((buf = (char *)malloc(bufsz)) == NULL)
18067dd7cddfSDavid du Colombier 		FATAL("out of memory in gsub");
18073e12c5d1SDavid du Colombier 	mflag = 0;	/* if mflag == 0, can replace empty string */
18083e12c5d1SDavid du Colombier 	num = 0;
18093e12c5d1SDavid du Colombier 	x = execute(a[3]);	/* target string */
18103e12c5d1SDavid du Colombier 	c = t = getsval(x);
1811219b2ee8SDavid du Colombier 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
18123e12c5d1SDavid du Colombier 		p = (void *) a[1];	/* regular expression */
18133e12c5d1SDavid du Colombier 	else {
18143e12c5d1SDavid du Colombier 		y = execute(a[1]);
18153e12c5d1SDavid du Colombier 		p = compre(getsval(y));
18163e12c5d1SDavid du Colombier 		tempfree(y);
18173e12c5d1SDavid du Colombier 	}
18183e12c5d1SDavid du Colombier 	y = execute(a[2]);	/* replacement string */
18193e12c5d1SDavid du Colombier 	if (pmatch(p, t, c)) {
18203e12c5d1SDavid du Colombier 		pb = buf;
18213e12c5d1SDavid du Colombier 		rptr = getsval(y);
18223e12c5d1SDavid du Colombier 		do {
18233e12c5d1SDavid du Colombier 			if (patlen == 0 && *patbeg != 0) {	/* matched empty string */
18243e12c5d1SDavid du Colombier 				if (mflag == 0) {	/* can replace empty */
18253e12c5d1SDavid du Colombier 					num++;
18263e12c5d1SDavid du Colombier 					sptr = rptr;
18277dd7cddfSDavid du Colombier 					while (*sptr != 0) {
18287dd7cddfSDavid du Colombier 						adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
18297dd7cddfSDavid du Colombier 						if (*sptr == '\\') {
18307dd7cddfSDavid du Colombier 							backsub(&pb, &sptr);
18313e12c5d1SDavid du Colombier 						} else if (*sptr == '&') {
18327dd7cddfSDavid du Colombier 							char *q;
18333e12c5d1SDavid du Colombier 							sptr++;
18347dd7cddfSDavid du Colombier 							adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
18353e12c5d1SDavid du Colombier 							for (q = patbeg; q < patbeg+patlen; )
18363e12c5d1SDavid du Colombier 								*pb++ = *q++;
18373e12c5d1SDavid du Colombier 						} else
18383e12c5d1SDavid du Colombier 							*pb++ = *sptr++;
18393e12c5d1SDavid du Colombier 					}
18407dd7cddfSDavid du Colombier 				}
18413e12c5d1SDavid du Colombier 				if (*c == 0)	/* at end */
18423e12c5d1SDavid du Colombier 					goto done;
18437dd7cddfSDavid du Colombier 				adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
18443e12c5d1SDavid du Colombier 				*pb++ = *c++;
18457dd7cddfSDavid du Colombier 				if (pb > buf + bufsz)	/* BUG: not sure of this test */
18467dd7cddfSDavid du Colombier 					FATAL("gsub result0 %.30s too big; can't happen", buf);
18473e12c5d1SDavid du Colombier 				mflag = 0;
18483e12c5d1SDavid du Colombier 			}
18493e12c5d1SDavid du Colombier 			else {	/* matched nonempty string */
18503e12c5d1SDavid du Colombier 				num++;
18513e12c5d1SDavid du Colombier 				sptr = c;
18527dd7cddfSDavid du Colombier 				adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
18537dd7cddfSDavid du Colombier 				while (sptr < patbeg)
18543e12c5d1SDavid du Colombier 					*pb++ = *sptr++;
18553e12c5d1SDavid du Colombier 				sptr = rptr;
18567dd7cddfSDavid du Colombier 				while (*sptr != 0) {
18577dd7cddfSDavid du Colombier 					adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
18587dd7cddfSDavid du Colombier 					if (*sptr == '\\') {
18597dd7cddfSDavid du Colombier 						backsub(&pb, &sptr);
18603e12c5d1SDavid du Colombier 					} else if (*sptr == '&') {
18617dd7cddfSDavid du Colombier 						char *q;
18623e12c5d1SDavid du Colombier 						sptr++;
18637dd7cddfSDavid du Colombier 						adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
18643e12c5d1SDavid du Colombier 						for (q = patbeg; q < patbeg+patlen; )
18653e12c5d1SDavid du Colombier 							*pb++ = *q++;
18663e12c5d1SDavid du Colombier 					} else
18673e12c5d1SDavid du Colombier 						*pb++ = *sptr++;
18687dd7cddfSDavid du Colombier 				}
18693e12c5d1SDavid du Colombier 				c = patbeg + patlen;
18703e12c5d1SDavid du Colombier 				if ((c[-1] == 0) || (*c == 0))
18713e12c5d1SDavid du Colombier 					goto done;
18727dd7cddfSDavid du Colombier 				if (pb > buf + bufsz)
18737dd7cddfSDavid du Colombier 					FATAL("gsub result1 %.30s too big; can't happen", buf);
18743e12c5d1SDavid du Colombier 				mflag = 1;
18753e12c5d1SDavid du Colombier 			}
18763e12c5d1SDavid du Colombier 		} while (pmatch(p, t, c));
18773e12c5d1SDavid du Colombier 		sptr = c;
18787dd7cddfSDavid du Colombier 		adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
18797dd7cddfSDavid du Colombier 		while ((*pb++ = *sptr++) != 0)
18803e12c5d1SDavid du Colombier 			;
18817dd7cddfSDavid du Colombier 	done:	if (pb > buf + bufsz)
18827dd7cddfSDavid du Colombier 			FATAL("gsub result2 %.30s too big; can't happen", buf);
18833e12c5d1SDavid du Colombier 		*pb = '\0';
18847dd7cddfSDavid du Colombier 		setsval(x, buf);	/* BUG: should be able to avoid copy + free */
18853e12c5d1SDavid du Colombier 	}
18863e12c5d1SDavid du Colombier 	tempfree(x);
18873e12c5d1SDavid du Colombier 	tempfree(y);
18883e12c5d1SDavid du Colombier 	x = gettemp();
18893e12c5d1SDavid du Colombier 	x->tval = NUM;
18903e12c5d1SDavid du Colombier 	x->fval = num;
18917dd7cddfSDavid du Colombier 	free(buf);
18923e12c5d1SDavid du Colombier 	return(x);
18933e12c5d1SDavid du Colombier }
18947dd7cddfSDavid du Colombier 
backsub(char ** pb_ptr,char ** sptr_ptr)18957dd7cddfSDavid du Colombier void backsub(char **pb_ptr, char **sptr_ptr)	/* handle \\& variations */
18967dd7cddfSDavid du Colombier {						/* sptr[0] == '\\' */
18977dd7cddfSDavid du Colombier 	char *pb = *pb_ptr, *sptr = *sptr_ptr;
18987dd7cddfSDavid du Colombier 
18997dd7cddfSDavid du Colombier 	if (sptr[1] == '\\') {
19007dd7cddfSDavid du Colombier 		if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
19017dd7cddfSDavid du Colombier 			*pb++ = '\\';
19027dd7cddfSDavid du Colombier 			*pb++ = '&';
19037dd7cddfSDavid du Colombier 			sptr += 4;
19047dd7cddfSDavid du Colombier 		} else if (sptr[2] == '&') {	/* \\& -> \ + matched */
19057dd7cddfSDavid du Colombier 			*pb++ = '\\';
19067dd7cddfSDavid du Colombier 			sptr += 2;
19077dd7cddfSDavid du Colombier 		} else {			/* \\x -> \\x */
19087dd7cddfSDavid du Colombier 			*pb++ = *sptr++;
19097dd7cddfSDavid du Colombier 			*pb++ = *sptr++;
19107dd7cddfSDavid du Colombier 		}
19117dd7cddfSDavid du Colombier 	} else if (sptr[1] == '&') {	/* literal & */
19127dd7cddfSDavid du Colombier 		sptr++;
19137dd7cddfSDavid du Colombier 		*pb++ = *sptr++;
19147dd7cddfSDavid du Colombier 	} else				/* literal \ */
19157dd7cddfSDavid du Colombier 		*pb++ = *sptr++;
19167dd7cddfSDavid du Colombier 
19177dd7cddfSDavid du Colombier 	*pb_ptr = pb;
19187dd7cddfSDavid du Colombier 	*sptr_ptr = sptr;
19197dd7cddfSDavid du Colombier }
1920