xref: /plan9/sys/src/cmd/awk/run.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier Copyright (c) 1989 AT&T
33e12c5d1SDavid du Colombier 	All Rights Reserved
43e12c5d1SDavid du Colombier 
53e12c5d1SDavid du Colombier THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.
63e12c5d1SDavid du Colombier 
73e12c5d1SDavid du Colombier The copyright notice above does not evidence any
83e12c5d1SDavid du Colombier actual or intended publication of such source code.
93e12c5d1SDavid du Colombier */
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier #define tempfree(x)	if (istemp(x)) tfree(x); else
123e12c5d1SDavid du Colombier 
133e12c5d1SDavid du Colombier #define DEBUG
143e12c5d1SDavid du Colombier #include <stdio.h>
153e12c5d1SDavid du Colombier #include <ctype.h>
163e12c5d1SDavid du Colombier #include <setjmp.h>
173e12c5d1SDavid du Colombier #include <math.h>
183e12c5d1SDavid du Colombier #include <string.h>
193e12c5d1SDavid du Colombier #include <stdlib.h>
203e12c5d1SDavid du Colombier #include <time.h>
213e12c5d1SDavid du Colombier #include <libv.h>
223e12c5d1SDavid du Colombier #include "awk.h"
233e12c5d1SDavid du Colombier #include "y.tab.h"
243e12c5d1SDavid du Colombier 
253e12c5d1SDavid du Colombier #ifdef _NFILE
263e12c5d1SDavid du Colombier #ifndef FOPEN_MAX
273e12c5d1SDavid du Colombier #define FOPEN_MAX _NFILE
283e12c5d1SDavid du Colombier #endif
293e12c5d1SDavid du Colombier #endif
303e12c5d1SDavid du Colombier 
313e12c5d1SDavid du Colombier #ifndef	FOPEN_MAX
323e12c5d1SDavid du Colombier #define	FOPEN_MAX	40	/* max number of open files */
333e12c5d1SDavid du Colombier #endif
343e12c5d1SDavid du Colombier 
353e12c5d1SDavid du Colombier #ifndef RAND_MAX
363e12c5d1SDavid du Colombier #define RAND_MAX	32767	/* all that ansi guarantees */
373e12c5d1SDavid du Colombier #endif
383e12c5d1SDavid du Colombier 
393e12c5d1SDavid du Colombier jmp_buf env;
403e12c5d1SDavid du Colombier 
41*219b2ee8SDavid du Colombier /* an attempt to go a bit faster: */
42*219b2ee8SDavid du Colombier 
43*219b2ee8SDavid du Colombier /* #define	execute(p)	(isvalue(p) ? (Cell *)((p)->narg[0]) : r_execute(p)) */
44*219b2ee8SDavid du Colombier #define	execute(p) r_execute(p)
45*219b2ee8SDavid du Colombier 
463e12c5d1SDavid du Colombier #define	getfval(p)	(((p)->tval & (ARR|FLD|REC|NUM)) == NUM ? (p)->fval : r_getfval(p))
473e12c5d1SDavid du Colombier #define	getsval(p)	(((p)->tval & (ARR|FLD|REC|STR)) == STR ? (p)->sval : r_getsval(p))
483e12c5d1SDavid du Colombier 
493e12c5d1SDavid du Colombier 
50*219b2ee8SDavid du Colombier #define PA2NUM	29	/* max number of pat,pat patterns allowed */
51*219b2ee8SDavid du Colombier int	paircnt;		/* number of them in use */
52*219b2ee8SDavid du Colombier int	pairstack[PA2NUM];	/* state of each pat,pat */
53*219b2ee8SDavid du Colombier 
54*219b2ee8SDavid du Colombier Node	*winner = NULL;	/* root of parse tree */
55*219b2ee8SDavid du Colombier Cell	*tmps;		/* free temporary cells for execution */
563e12c5d1SDavid du Colombier 
573e12c5d1SDavid du Colombier static Cell	truecell	={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
583e12c5d1SDavid du Colombier Cell	*true	= &truecell;
593e12c5d1SDavid du Colombier static Cell	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
603e12c5d1SDavid du Colombier Cell	*false	= &falsecell;
613e12c5d1SDavid du Colombier static Cell	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
623e12c5d1SDavid du Colombier Cell	*jbreak	= &breakcell;
633e12c5d1SDavid du Colombier static Cell	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM };
643e12c5d1SDavid du Colombier Cell	*jcont	= &contcell;
653e12c5d1SDavid du Colombier static Cell	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
663e12c5d1SDavid du Colombier Cell	*jnext	= &nextcell;
673e12c5d1SDavid du Colombier static Cell	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
683e12c5d1SDavid du Colombier Cell	*jexit	= &exitcell;
693e12c5d1SDavid du Colombier static Cell	retcell		={ OJUMP, JRET, 0, 0, 0.0, NUM };
703e12c5d1SDavid du Colombier Cell	*jret	= &retcell;
713e12c5d1SDavid du Colombier static Cell	tempcell	={ OCELL, CTEMP, 0, 0, 0.0, NUM };
723e12c5d1SDavid du Colombier 
733e12c5d1SDavid du Colombier Node	*curnode = NULL;	/* the node being executed, for debugging */
743e12c5d1SDavid du Colombier 
75*219b2ee8SDavid du Colombier void run(Node *a)	/* execution of parse tree starts here */
763e12c5d1SDavid du Colombier {
773e12c5d1SDavid du Colombier 	execute(a);
783e12c5d1SDavid du Colombier 	closeall();
793e12c5d1SDavid du Colombier }
803e12c5d1SDavid du Colombier 
81*219b2ee8SDavid du Colombier Cell *r_execute(Node *u)	/* execute a node of the parse tree */
823e12c5d1SDavid du Colombier {
833e12c5d1SDavid du Colombier 	register Cell *(*proc)(Node **, int);
843e12c5d1SDavid du Colombier 	register Cell *x;
853e12c5d1SDavid du Colombier 	register Node *a;
863e12c5d1SDavid du Colombier 
873e12c5d1SDavid du Colombier 	if (u == NULL)
883e12c5d1SDavid du Colombier 		return(true);
893e12c5d1SDavid du Colombier 	for (a = u; ; a = a->nnext) {
903e12c5d1SDavid du Colombier 		curnode = a;
913e12c5d1SDavid du Colombier 		if (isvalue(a)) {
923e12c5d1SDavid du Colombier 			x = (Cell *) (a->narg[0]);
933e12c5d1SDavid du Colombier 			if ((x->tval & FLD) && !donefld)
943e12c5d1SDavid du Colombier 				fldbld();
953e12c5d1SDavid du Colombier 			else if ((x->tval & REC) && !donerec)
963e12c5d1SDavid du Colombier 				recbld();
973e12c5d1SDavid du Colombier 			return(x);
983e12c5d1SDavid du Colombier 		}
993e12c5d1SDavid du Colombier 		if (notlegal(a->nobj))	/* probably a Cell* but too risky to print */
1003e12c5d1SDavid du Colombier 			ERROR "illegal statement" FATAL;
1013e12c5d1SDavid du Colombier 		proc = proctab[a->nobj-FIRSTTOKEN];
1023e12c5d1SDavid du Colombier 		x = (*proc)(a->narg, a->nobj);
1033e12c5d1SDavid du Colombier 		if ((x->tval & FLD) && !donefld)
1043e12c5d1SDavid du Colombier 			fldbld();
1053e12c5d1SDavid du Colombier 		else if ((x->tval & REC) && !donerec)
1063e12c5d1SDavid du Colombier 			recbld();
1073e12c5d1SDavid du Colombier 		if (isexpr(a))
1083e12c5d1SDavid du Colombier 			return(x);
1093e12c5d1SDavid du Colombier 		if (isjump(x))
1103e12c5d1SDavid du Colombier 			return(x);
1113e12c5d1SDavid du Colombier 		if (a->nnext == NULL)
1123e12c5d1SDavid du Colombier 			return(x);
1133e12c5d1SDavid du Colombier 		tempfree(x);
1143e12c5d1SDavid du Colombier 	}
1153e12c5d1SDavid du Colombier }
1163e12c5d1SDavid du Colombier 
1173e12c5d1SDavid du Colombier 
118*219b2ee8SDavid du Colombier Cell *program(Node **a, int n)	/* execute an awk program */
119*219b2ee8SDavid du Colombier {				/* a[0] = BEGIN, a[1] = body, a[2] = END */
1203e12c5d1SDavid du Colombier 	register Cell *x;
1213e12c5d1SDavid du Colombier 
1223e12c5d1SDavid du Colombier 	if (setjmp(env) != 0)
1233e12c5d1SDavid du Colombier 		goto ex;
1243e12c5d1SDavid du Colombier 	if (a[0]) {		/* BEGIN */
1253e12c5d1SDavid du Colombier 		x = execute(a[0]);
1263e12c5d1SDavid du Colombier 		if (isexit(x))
1273e12c5d1SDavid du Colombier 			return(true);
1283e12c5d1SDavid du Colombier 		if (isjump(x))
1293e12c5d1SDavid du Colombier 			ERROR "illegal break, continue or next from BEGIN" FATAL;
1303e12c5d1SDavid du Colombier 		tempfree(x);
1313e12c5d1SDavid du Colombier 	}
1323e12c5d1SDavid du Colombier   loop:
1333e12c5d1SDavid du Colombier 	if (a[1] || a[2])
1343e12c5d1SDavid du Colombier 		while (getrec(record) > 0) {
1353e12c5d1SDavid du Colombier 			x = execute(a[1]);
1363e12c5d1SDavid du Colombier 			if (isexit(x))
1373e12c5d1SDavid du Colombier 				break;
1383e12c5d1SDavid du Colombier 			tempfree(x);
1393e12c5d1SDavid du Colombier 		}
1403e12c5d1SDavid du Colombier   ex:
1413e12c5d1SDavid du Colombier 	if (setjmp(env) != 0)	/* handles exit within END */
1423e12c5d1SDavid du Colombier 		goto ex1;
1433e12c5d1SDavid du Colombier 	if (a[2]) {		/* END */
1443e12c5d1SDavid du Colombier 		x = execute(a[2]);
1453e12c5d1SDavid du Colombier 		if (isbreak(x) || isnext(x) || iscont(x))
1463e12c5d1SDavid du Colombier 			ERROR "illegal break, next, or continue from END" FATAL;
1473e12c5d1SDavid du Colombier 		tempfree(x);
1483e12c5d1SDavid du Colombier 	}
1493e12c5d1SDavid du Colombier   ex1:
1503e12c5d1SDavid du Colombier 	return(true);
1513e12c5d1SDavid du Colombier }
1523e12c5d1SDavid du Colombier 
153*219b2ee8SDavid du Colombier struct Frame {	/* stack frame for awk function calls */
1543e12c5d1SDavid du Colombier 	int nargs;	/* number of arguments in this call */
1553e12c5d1SDavid du Colombier 	Cell *fcncell;	/* pointer to Cell for function */
1563e12c5d1SDavid du Colombier 	Cell **args;	/* pointer to array of arguments after execute */
1573e12c5d1SDavid du Colombier 	Cell *retval;	/* return value */
1583e12c5d1SDavid du Colombier };
1593e12c5d1SDavid du Colombier 
160*219b2ee8SDavid du Colombier #define	NARGS	50	/* max args in a call */
1613e12c5d1SDavid du Colombier 
1623e12c5d1SDavid du Colombier struct Frame *frame = NULL;	/* base of stack frames; dynamically allocated */
1633e12c5d1SDavid du Colombier int	nframe = 0;		/* number of frames allocated */
1643e12c5d1SDavid du Colombier struct Frame *fp = NULL;	/* frame pointer. bottom level unused */
1653e12c5d1SDavid du Colombier 
166*219b2ee8SDavid du Colombier Cell *call(Node **a, int n)	/* function call.  very kludgy and fragile */
1673e12c5d1SDavid du Colombier {
1683e12c5d1SDavid du Colombier 	static Cell newcopycell = { OCELL, CCOPY, 0, (uchar *) "", 0.0, NUM|STR|DONTFREE };
1693e12c5d1SDavid du Colombier 	int i, ncall, ndef;
1703e12c5d1SDavid du Colombier 	Node *x;
1713e12c5d1SDavid du Colombier 	Cell *args[NARGS], *oargs[NARGS], *y, *z, *fcn;
1723e12c5d1SDavid du Colombier 	uchar *s;
1733e12c5d1SDavid du Colombier 
1743e12c5d1SDavid du Colombier 	fcn = execute(a[0]);	/* the function itself */
1753e12c5d1SDavid du Colombier 	s = fcn->nval;
1763e12c5d1SDavid du Colombier 	if (!isfunc(fcn))
1773e12c5d1SDavid du Colombier 		ERROR "calling undefined function %s", s FATAL;
1783e12c5d1SDavid du Colombier 	if (frame == NULL) {
1793e12c5d1SDavid du Colombier 		fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
1803e12c5d1SDavid du Colombier 		if (frame == NULL)
1813e12c5d1SDavid du Colombier 			ERROR "out of space for stack frames calling %s", s FATAL;
1823e12c5d1SDavid du Colombier 	}
1833e12c5d1SDavid du Colombier 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)	/* args in call */
1843e12c5d1SDavid du Colombier 		ncall++;
1853e12c5d1SDavid du Colombier 	ndef = (int) fcn->fval;			/* args in defn */
1863e12c5d1SDavid du Colombier 	dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, fp-frame) );
1873e12c5d1SDavid du Colombier 	if (ncall > ndef)
1883e12c5d1SDavid du Colombier 		ERROR "function %s called with %d args, uses only %d",
1893e12c5d1SDavid du Colombier 			s, ncall, ndef WARNING;
1903e12c5d1SDavid du Colombier 	if (ncall + ndef > NARGS)
1913e12c5d1SDavid du Colombier 		ERROR "function %s has %d arguments, limit %d", s, ncall+ndef, NARGS FATAL;
1923e12c5d1SDavid du Colombier 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {	/* get call args */
1933e12c5d1SDavid du Colombier 		dprintf( ("evaluate args[%d], fp=%d:\n", i, fp-frame) );
1943e12c5d1SDavid du Colombier 		y = execute(x);
1953e12c5d1SDavid du Colombier 		oargs[i] = y;
1963e12c5d1SDavid du Colombier 		dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
1973e12c5d1SDavid du Colombier 			   i, y->nval, y->fval, isarr(y) ? "(array)" : (char*) y->sval, y->tval) );
1983e12c5d1SDavid du Colombier 		if (isfunc(y))
1993e12c5d1SDavid du Colombier 			ERROR "can't use function %s as argument in %s", y->nval, s FATAL;
2003e12c5d1SDavid du Colombier 		if (isarr(y))
2013e12c5d1SDavid du Colombier 			args[i] = y;	/* arrays by ref */
2023e12c5d1SDavid du Colombier 		else
2033e12c5d1SDavid du Colombier 			args[i] = copycell(y);
2043e12c5d1SDavid du Colombier 		tempfree(y);
2053e12c5d1SDavid du Colombier 	}
2063e12c5d1SDavid du Colombier 	for ( ; i < ndef; i++) {	/* add null args for ones not provided */
2073e12c5d1SDavid du Colombier 		args[i] = gettemp();
2083e12c5d1SDavid du Colombier 		*args[i] = newcopycell;
2093e12c5d1SDavid du Colombier 	}
2103e12c5d1SDavid du Colombier 	fp++;	/* now ok to up frame */
2113e12c5d1SDavid du Colombier 	if (fp >= frame + nframe) {
2123e12c5d1SDavid du Colombier 		int dfp = fp - frame;	/* old index */
2133e12c5d1SDavid du Colombier 		frame = (struct Frame *)
214*219b2ee8SDavid du Colombier 			realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
2153e12c5d1SDavid du Colombier 		if (frame == NULL)
2163e12c5d1SDavid du Colombier 			ERROR "out of space for stack frames in %s", s FATAL;
2173e12c5d1SDavid du Colombier 		fp = frame + dfp;
2183e12c5d1SDavid du Colombier 	}
2193e12c5d1SDavid du Colombier 	fp->fcncell = fcn;
2203e12c5d1SDavid du Colombier 	fp->args = args;
2213e12c5d1SDavid du Colombier 	fp->nargs = ndef;	/* number defined with (excess are locals) */
2223e12c5d1SDavid du Colombier 	fp->retval = gettemp();
2233e12c5d1SDavid du Colombier 
2243e12c5d1SDavid du Colombier 	dprintf( ("start exec of %s, fp=%d\n", s, fp-frame) );
2253e12c5d1SDavid du Colombier 	y = execute((Node *)(fcn->sval));	/* execute body */
2263e12c5d1SDavid du Colombier 	dprintf( ("finished exec of %s, fp=%d\n", s, fp-frame) );
2273e12c5d1SDavid du Colombier 
2283e12c5d1SDavid du Colombier 	for (i = 0; i < ndef; i++) {
2293e12c5d1SDavid du Colombier 		Cell *t = fp->args[i];
2303e12c5d1SDavid du Colombier 		if (isarr(t)) {
2313e12c5d1SDavid du Colombier 			if (t->csub == CCOPY) {
2323e12c5d1SDavid du Colombier 				if (i >= ncall) {
2333e12c5d1SDavid du Colombier 					freesymtab(t);
2343e12c5d1SDavid du Colombier 					t->csub = CTEMP;
2353e12c5d1SDavid du Colombier 				} else {
2363e12c5d1SDavid du Colombier 					oargs[i]->tval = t->tval;
2373e12c5d1SDavid du Colombier 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
2383e12c5d1SDavid du Colombier 					oargs[i]->sval = t->sval;
2393e12c5d1SDavid du Colombier 					tempfree(t);
2403e12c5d1SDavid du Colombier 				}
2413e12c5d1SDavid du Colombier 			}
2423e12c5d1SDavid du Colombier 		} else if (t != y) {	/* kludge to prevent freeing twice */
2433e12c5d1SDavid du Colombier 			t->csub = CTEMP;
2443e12c5d1SDavid du Colombier 			tempfree(t);
2453e12c5d1SDavid du Colombier 		}
2463e12c5d1SDavid du Colombier 	}
2473e12c5d1SDavid du Colombier 	tempfree(fcn);
2483e12c5d1SDavid du Colombier 	if (isexit(y) || isnext(y))
2493e12c5d1SDavid du Colombier 		return y;
2503e12c5d1SDavid du Colombier 	tempfree(y);		/* this can free twice! */
2513e12c5d1SDavid du Colombier 	z = fp->retval;			/* return value */
2523e12c5d1SDavid du Colombier 	dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
2533e12c5d1SDavid du Colombier 	fp--;
2543e12c5d1SDavid du Colombier 	return(z);
2553e12c5d1SDavid du Colombier }
2563e12c5d1SDavid du Colombier 
2573e12c5d1SDavid du Colombier Cell *copycell(Cell *x)	/* make a copy of a cell in a temp */
2583e12c5d1SDavid du Colombier {
2593e12c5d1SDavid du Colombier 	Cell *y;
2603e12c5d1SDavid du Colombier 
2613e12c5d1SDavid du Colombier 	y = gettemp();
2623e12c5d1SDavid du Colombier 	y->csub = CCOPY;	/* prevents freeing until call is over */
2633e12c5d1SDavid du Colombier 	y->nval = x->nval;
2643e12c5d1SDavid du Colombier 	y->sval = x->sval ? tostring(x->sval) : NULL;
2653e12c5d1SDavid du Colombier 	y->fval = x->fval;
2663e12c5d1SDavid du Colombier 	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);	/* copy is not constant or field */
2673e12c5d1SDavid du Colombier 							/* is DONTFREE right? */
2683e12c5d1SDavid du Colombier 	return y;
2693e12c5d1SDavid du Colombier }
2703e12c5d1SDavid du Colombier 
271*219b2ee8SDavid du Colombier Cell *arg(Node **a, int n)	/* nth argument of a function */
2723e12c5d1SDavid du Colombier {
2733e12c5d1SDavid du Colombier 
2743e12c5d1SDavid du Colombier 	n = (int) a[0];	/* argument number, counting from 0 */
2753e12c5d1SDavid du Colombier 	dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
2763e12c5d1SDavid du Colombier 	if (n+1 > fp->nargs)
2773e12c5d1SDavid du Colombier 		ERROR "argument #%d of function %s was not supplied",
2783e12c5d1SDavid du Colombier 			n+1, fp->fcncell->nval FATAL;
2793e12c5d1SDavid du Colombier 	return fp->args[n];
2803e12c5d1SDavid du Colombier }
2813e12c5d1SDavid du Colombier 
282*219b2ee8SDavid du Colombier Cell *jump(Node **a, int n)	/* break, continue, next, continue, return */
2833e12c5d1SDavid du Colombier {
2843e12c5d1SDavid du Colombier 	register Cell *y;
2853e12c5d1SDavid du Colombier 
2863e12c5d1SDavid du Colombier 	switch (n) {
2873e12c5d1SDavid du Colombier 	case EXIT:
2883e12c5d1SDavid du Colombier 		if (a[0] != NULL) {
2893e12c5d1SDavid du Colombier 			y = execute(a[0]);
2903e12c5d1SDavid du Colombier 			errorflag = getfval(y);
2913e12c5d1SDavid du Colombier 			tempfree(y);
2923e12c5d1SDavid du Colombier 		}
2933e12c5d1SDavid du Colombier 		longjmp(env, 1);
2943e12c5d1SDavid du Colombier 	case RETURN:
2953e12c5d1SDavid du Colombier 		if (a[0] != NULL) {
2963e12c5d1SDavid du Colombier 			y = execute(a[0]);
2973e12c5d1SDavid du Colombier 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
2983e12c5d1SDavid du Colombier 				setsval(fp->retval, getsval(y));
2993e12c5d1SDavid du Colombier 				fp->retval->fval = getfval(y);
3003e12c5d1SDavid du Colombier 				fp->retval->tval |= NUM;
3013e12c5d1SDavid du Colombier 			}
3023e12c5d1SDavid du Colombier 			else if (y->tval & STR)
3033e12c5d1SDavid du Colombier 				setsval(fp->retval, getsval(y));
3043e12c5d1SDavid du Colombier 			else if (y->tval & NUM)
3053e12c5d1SDavid du Colombier 				setfval(fp->retval, getfval(y));
3063e12c5d1SDavid du Colombier 			else		/* can't happen */
3073e12c5d1SDavid du Colombier 				ERROR "bad type variable %d", y->tval FATAL;
3083e12c5d1SDavid du Colombier 			tempfree(y);
3093e12c5d1SDavid du Colombier 		}
3103e12c5d1SDavid du Colombier 		return(jret);
3113e12c5d1SDavid du Colombier 	case NEXT:
3123e12c5d1SDavid du Colombier 		return(jnext);
3133e12c5d1SDavid du Colombier 	case BREAK:
3143e12c5d1SDavid du Colombier 		return(jbreak);
3153e12c5d1SDavid du Colombier 	case CONTINUE:
3163e12c5d1SDavid du Colombier 		return(jcont);
3173e12c5d1SDavid du Colombier 	default:	/* can't happen */
3183e12c5d1SDavid du Colombier 		ERROR "illegal jump type %d", n FATAL;
3193e12c5d1SDavid du Colombier 	}
3203e12c5d1SDavid du Colombier 	return 0;	/* not reached */
3213e12c5d1SDavid du Colombier }
3223e12c5d1SDavid du Colombier 
323*219b2ee8SDavid du Colombier Cell *getline(Node **a, int n)	/* get next line from specific input */
324*219b2ee8SDavid du Colombier {		/* a[0] is variable, a[1] is operator, a[2] is filename */
3253e12c5d1SDavid du Colombier 	register Cell *r, *x;
3263e12c5d1SDavid du Colombier 	uchar buf[RECSIZE];
3273e12c5d1SDavid du Colombier 	FILE *fp;
3283e12c5d1SDavid du Colombier 
3293e12c5d1SDavid du Colombier 	fflush(stdout);	/* in case someone is waiting for a prompt */
3303e12c5d1SDavid du Colombier 	r = gettemp();
3313e12c5d1SDavid du Colombier 	if (a[1] != NULL) {		/* getline < file */
3323e12c5d1SDavid du Colombier 		x = execute(a[2]);		/* filename */
3333e12c5d1SDavid du Colombier 		if ((int) a[1] == '|')	/* input pipe */
3343e12c5d1SDavid du Colombier 			a[1] = (Node *) LE;	/* arbitrary flag */
3353e12c5d1SDavid du Colombier 		fp = openfile((int) a[1], getsval(x));
3363e12c5d1SDavid du Colombier 		tempfree(x);
3373e12c5d1SDavid du Colombier 		if (fp == NULL)
3383e12c5d1SDavid du Colombier 			n = -1;
3393e12c5d1SDavid du Colombier 		else
3403e12c5d1SDavid du Colombier 			n = readrec(buf, sizeof(buf), fp);
3413e12c5d1SDavid du Colombier 		if (n <= 0) {
3423e12c5d1SDavid du Colombier 			;
3433e12c5d1SDavid du Colombier 		} else if (a[0] != NULL) {	/* getline var <file */
3443e12c5d1SDavid du Colombier 			setsval(execute(a[0]), buf);
3453e12c5d1SDavid du Colombier 		} else {			/* getline <file */
3463e12c5d1SDavid du Colombier 			if (!(recloc->tval & DONTFREE))
3473e12c5d1SDavid du Colombier 				xfree(recloc->sval);
3483e12c5d1SDavid du Colombier 			strcpy(record, buf);
3493e12c5d1SDavid du Colombier 			recloc->sval = record;
3503e12c5d1SDavid du Colombier 			recloc->tval = REC | STR | DONTFREE;
3513e12c5d1SDavid du Colombier 			if (isnumber(recloc->sval)) {
3523e12c5d1SDavid du Colombier 				recloc->fval = atof(recloc->sval);
3533e12c5d1SDavid du Colombier 				recloc->tval |= NUM;
3543e12c5d1SDavid du Colombier 			}
3553e12c5d1SDavid du Colombier 			donerec = 1; donefld = 0;
3563e12c5d1SDavid du Colombier 		}
3573e12c5d1SDavid du Colombier 	} else {			/* bare getline; use current input */
3583e12c5d1SDavid du Colombier 		if (a[0] == NULL)	/* getline */
3593e12c5d1SDavid du Colombier 			n = getrec(record);
3603e12c5d1SDavid du Colombier 		else {			/* getline var */
3613e12c5d1SDavid du Colombier 			n = getrec(buf);
3623e12c5d1SDavid du Colombier 			setsval(execute(a[0]), buf);
3633e12c5d1SDavid du Colombier 		}
3643e12c5d1SDavid du Colombier 	}
3653e12c5d1SDavid du Colombier 	setfval(r, (Awkfloat) n);
3663e12c5d1SDavid du Colombier 	return r;
3673e12c5d1SDavid du Colombier }
3683e12c5d1SDavid du Colombier 
369*219b2ee8SDavid du Colombier Cell *getnf(Node **a, int n)	/* get NF */
3703e12c5d1SDavid du Colombier {
3713e12c5d1SDavid du Colombier 	if (donefld == 0)
3723e12c5d1SDavid du Colombier 		fldbld();
3733e12c5d1SDavid du Colombier 	return (Cell *) a[0];
3743e12c5d1SDavid du Colombier }
3753e12c5d1SDavid du Colombier 
376*219b2ee8SDavid du Colombier Cell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
3773e12c5d1SDavid du Colombier {
3783e12c5d1SDavid du Colombier 	register Cell *x, *y, *z;
3793e12c5d1SDavid du Colombier 	register uchar *s;
3803e12c5d1SDavid du Colombier 	register Node *np;
3813e12c5d1SDavid du Colombier 	uchar buf[RECSIZE];
3823e12c5d1SDavid du Colombier 
3833e12c5d1SDavid du Colombier 	x = execute(a[0]);	/* Cell* for symbol table */
3843e12c5d1SDavid du Colombier 	buf[0] = 0;
3853e12c5d1SDavid du Colombier 	for (np = a[1]; np; np = np->nnext) {
3863e12c5d1SDavid du Colombier 		y = execute(np);	/* subscript */
3873e12c5d1SDavid du Colombier 		s = getsval(y);
3883e12c5d1SDavid du Colombier 		strcat(buf, s);
3893e12c5d1SDavid du Colombier 		if (np->nnext)
3903e12c5d1SDavid du Colombier 			strcat(buf, *SUBSEP);
3913e12c5d1SDavid du Colombier 		tempfree(y);
3923e12c5d1SDavid du Colombier 	}
3933e12c5d1SDavid du Colombier 	if (!isarr(x)) {
3943e12c5d1SDavid du Colombier 		dprintf( ("making %s into an array\n", x->nval) );
3953e12c5d1SDavid du Colombier 		if (freeable(x))
3963e12c5d1SDavid du Colombier 			xfree(x->sval);
3973e12c5d1SDavid du Colombier 		x->tval &= ~(STR|NUM|DONTFREE);
3983e12c5d1SDavid du Colombier 		x->tval |= ARR;
3993e12c5d1SDavid du Colombier 		x->sval = (uchar *) makesymtab(NSYMTAB);
4003e12c5d1SDavid du Colombier 	}
4013e12c5d1SDavid du Colombier 	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
4023e12c5d1SDavid du Colombier 	z->ctype = OCELL;
4033e12c5d1SDavid du Colombier 	z->csub = CVAR;
4043e12c5d1SDavid du Colombier 	tempfree(x);
4053e12c5d1SDavid du Colombier 	return(z);
4063e12c5d1SDavid du Colombier }
4073e12c5d1SDavid du Colombier 
408*219b2ee8SDavid du Colombier Cell *adelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
4093e12c5d1SDavid du Colombier {
4103e12c5d1SDavid du Colombier 	Cell *x, *y;
4113e12c5d1SDavid du Colombier 	Node *np;
4123e12c5d1SDavid du Colombier 	uchar buf[RECSIZE], *s;
4133e12c5d1SDavid du Colombier 
4143e12c5d1SDavid du Colombier 	x = execute(a[0]);	/* Cell* for symbol table */
4153e12c5d1SDavid du Colombier 	if (!isarr(x))
4163e12c5d1SDavid du Colombier 		return true;
4173e12c5d1SDavid du Colombier 	buf[0] = 0;
4183e12c5d1SDavid du Colombier 	for (np = a[1]; np; np = np->nnext) {
4193e12c5d1SDavid du Colombier 		y = execute(np);	/* subscript */
4203e12c5d1SDavid du Colombier 		s = getsval(y);
4213e12c5d1SDavid du Colombier 		strcat(buf, s);
4223e12c5d1SDavid du Colombier 		if (np->nnext)
4233e12c5d1SDavid du Colombier 			strcat(buf, *SUBSEP);
4243e12c5d1SDavid du Colombier 		tempfree(y);
4253e12c5d1SDavid du Colombier 	}
4263e12c5d1SDavid du Colombier 	freeelem(x, buf);
4273e12c5d1SDavid du Colombier 	tempfree(x);
4283e12c5d1SDavid du Colombier 	return true;
4293e12c5d1SDavid du Colombier }
4303e12c5d1SDavid du Colombier 
431*219b2ee8SDavid du Colombier Cell *intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
4323e12c5d1SDavid du Colombier {
4333e12c5d1SDavid du Colombier 	register Cell *x, *ap, *k;
4343e12c5d1SDavid du Colombier 	Node *p;
4353e12c5d1SDavid du Colombier 	char buf[RECSIZE];
4363e12c5d1SDavid du Colombier 	uchar *s;
4373e12c5d1SDavid du Colombier 
4383e12c5d1SDavid du Colombier 	ap = execute(a[1]);	/* array name */
4393e12c5d1SDavid du Colombier 	if (!isarr(ap)) {
4403e12c5d1SDavid du Colombier 		dprintf( ("making %s into an array\n", ap->nval) );
4413e12c5d1SDavid du Colombier 		if (freeable(ap))
4423e12c5d1SDavid du Colombier 			xfree(ap->sval);
4433e12c5d1SDavid du Colombier 		ap->tval &= ~(STR|NUM|DONTFREE);
4443e12c5d1SDavid du Colombier 		ap->tval |= ARR;
4453e12c5d1SDavid du Colombier 		ap->sval = (uchar *) makesymtab(NSYMTAB);
4463e12c5d1SDavid du Colombier 	}
4473e12c5d1SDavid du Colombier 	buf[0] = 0;
4483e12c5d1SDavid du Colombier 	for (p = a[0]; p; p = p->nnext) {
4493e12c5d1SDavid du Colombier 		x = execute(p);	/* expr */
4503e12c5d1SDavid du Colombier 		s = getsval(x);
4513e12c5d1SDavid du Colombier 		strcat(buf, s);
4523e12c5d1SDavid du Colombier 		tempfree(x);
4533e12c5d1SDavid du Colombier 		if (p->nnext)
4543e12c5d1SDavid du Colombier 			strcat(buf, *SUBSEP);
4553e12c5d1SDavid du Colombier 	}
4563e12c5d1SDavid du Colombier 	k = lookup(buf, (Array *) ap->sval);
4573e12c5d1SDavid du Colombier 	tempfree(ap);
4583e12c5d1SDavid du Colombier 	if (k == NULL)
4593e12c5d1SDavid du Colombier 		return(false);
4603e12c5d1SDavid du Colombier 	else
4613e12c5d1SDavid du Colombier 		return(true);
4623e12c5d1SDavid du Colombier }
4633e12c5d1SDavid du Colombier 
4643e12c5d1SDavid du Colombier 
465*219b2ee8SDavid du Colombier Cell *matchop(Node **a, int n)	/* ~ and match() */
4663e12c5d1SDavid du Colombier {
4673e12c5d1SDavid du Colombier 	register Cell *x, *y;
4683e12c5d1SDavid du Colombier 	register uchar *s, *t;
4693e12c5d1SDavid du Colombier 	register int i;
4703e12c5d1SDavid du Colombier 	void *p;
4713e12c5d1SDavid du Colombier 
472*219b2ee8SDavid du Colombier 	x = execute(a[1]);	/* a[1] = target text */
4733e12c5d1SDavid du Colombier 	s = getsval(x);
474*219b2ee8SDavid du Colombier 	if (a[0] == 0)		/* a[1] == 0: already-compiled reg expr */
4753e12c5d1SDavid du Colombier 		p = (void *) a[2];
4763e12c5d1SDavid du Colombier 	else {
477*219b2ee8SDavid du Colombier 		y = execute(a[2]);	/* a[2] = regular expr */
4783e12c5d1SDavid du Colombier 		t = getsval(y);
4793e12c5d1SDavid du Colombier 		p = compre(t);
4803e12c5d1SDavid du Colombier 		tempfree(y);
4813e12c5d1SDavid du Colombier 	}
4823e12c5d1SDavid du Colombier 	if (n == MATCHFCN)
4833e12c5d1SDavid du Colombier 		i = pmatch(p, s, s);
4843e12c5d1SDavid du Colombier 	else
4853e12c5d1SDavid du Colombier 		i = match(p, s, s);
4863e12c5d1SDavid du Colombier 	tempfree(x);
4873e12c5d1SDavid du Colombier 	if (n == MATCHFCN) {
4883e12c5d1SDavid du Colombier 		int start = patbeg - s + 1;
4893e12c5d1SDavid du Colombier 		if (patlen < 0)
4903e12c5d1SDavid du Colombier 			start = 0;
4913e12c5d1SDavid du Colombier 		setfval(rstartloc, (Awkfloat) start);
4923e12c5d1SDavid du Colombier 		setfval(rlengthloc, (Awkfloat) countposn(patbeg, patlen));
4933e12c5d1SDavid du Colombier 		x = gettemp();
4943e12c5d1SDavid du Colombier 		x->tval = NUM;
4953e12c5d1SDavid du Colombier 		x->fval = start;
4963e12c5d1SDavid du Colombier 		return x;
4973e12c5d1SDavid du Colombier 	} else if (n == MATCH && i == 1 || n == NOTMATCH && i == 0)
4983e12c5d1SDavid du Colombier 		return(true);
4993e12c5d1SDavid du Colombier 	else
5003e12c5d1SDavid du Colombier 		return(false);
5013e12c5d1SDavid du Colombier }
5023e12c5d1SDavid du Colombier 
5033e12c5d1SDavid du Colombier 
504*219b2ee8SDavid du Colombier Cell *boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
5053e12c5d1SDavid du Colombier {
5063e12c5d1SDavid du Colombier 	register Cell *x, *y;
5073e12c5d1SDavid du Colombier 	register int i;
5083e12c5d1SDavid du Colombier 
5093e12c5d1SDavid du Colombier 	x = execute(a[0]);
5103e12c5d1SDavid du Colombier 	i = istrue(x);
5113e12c5d1SDavid du Colombier 	tempfree(x);
5123e12c5d1SDavid du Colombier 	switch (n) {
5133e12c5d1SDavid du Colombier 	case BOR:
5143e12c5d1SDavid du Colombier 		if (i) return(true);
5153e12c5d1SDavid du Colombier 		y = execute(a[1]);
5163e12c5d1SDavid du Colombier 		i = istrue(y);
5173e12c5d1SDavid du Colombier 		tempfree(y);
5183e12c5d1SDavid du Colombier 		if (i) return(true);
5193e12c5d1SDavid du Colombier 		else return(false);
5203e12c5d1SDavid du Colombier 	case AND:
5213e12c5d1SDavid du Colombier 		if ( !i ) return(false);
5223e12c5d1SDavid du Colombier 		y = execute(a[1]);
5233e12c5d1SDavid du Colombier 		i = istrue(y);
5243e12c5d1SDavid du Colombier 		tempfree(y);
5253e12c5d1SDavid du Colombier 		if (i) return(true);
5263e12c5d1SDavid du Colombier 		else return(false);
5273e12c5d1SDavid du Colombier 	case NOT:
5283e12c5d1SDavid du Colombier 		if (i) return(false);
5293e12c5d1SDavid du Colombier 		else return(true);
5303e12c5d1SDavid du Colombier 	default:	/* can't happen */
5313e12c5d1SDavid du Colombier 		ERROR "unknown boolean operator %d", n FATAL;
5323e12c5d1SDavid du Colombier 	}
5333e12c5d1SDavid du Colombier 	return 0;	/*NOTREACHED*/
5343e12c5d1SDavid du Colombier }
5353e12c5d1SDavid du Colombier 
536*219b2ee8SDavid du Colombier Cell *relop(Node **a, int n)	/* a[0 < a[1], etc. */
5373e12c5d1SDavid du Colombier {
5383e12c5d1SDavid du Colombier 	register int i;
5393e12c5d1SDavid du Colombier 	register Cell *x, *y;
5403e12c5d1SDavid du Colombier 	Awkfloat j;
5413e12c5d1SDavid du Colombier 
5423e12c5d1SDavid du Colombier 	x = execute(a[0]);
5433e12c5d1SDavid du Colombier 	y = execute(a[1]);
5443e12c5d1SDavid du Colombier 	if (x->tval&NUM && y->tval&NUM) {
5453e12c5d1SDavid du Colombier 		j = x->fval - y->fval;
5463e12c5d1SDavid du Colombier 		i = j<0? -1: (j>0? 1: 0);
5473e12c5d1SDavid du Colombier 	} else {
5483e12c5d1SDavid du Colombier 		i = strcmp(getsval(x), getsval(y));
5493e12c5d1SDavid du Colombier 	}
5503e12c5d1SDavid du Colombier 	tempfree(x);
5513e12c5d1SDavid du Colombier 	tempfree(y);
5523e12c5d1SDavid du Colombier 	switch (n) {
5533e12c5d1SDavid du Colombier 	case LT:	if (i<0) return(true);
5543e12c5d1SDavid du Colombier 			else return(false);
5553e12c5d1SDavid du Colombier 	case LE:	if (i<=0) return(true);
5563e12c5d1SDavid du Colombier 			else return(false);
5573e12c5d1SDavid du Colombier 	case NE:	if (i!=0) return(true);
5583e12c5d1SDavid du Colombier 			else return(false);
5593e12c5d1SDavid du Colombier 	case EQ:	if (i == 0) return(true);
5603e12c5d1SDavid du Colombier 			else return(false);
5613e12c5d1SDavid du Colombier 	case GE:	if (i>=0) return(true);
5623e12c5d1SDavid du Colombier 			else return(false);
5633e12c5d1SDavid du Colombier 	case GT:	if (i>0) return(true);
5643e12c5d1SDavid du Colombier 			else return(false);
5653e12c5d1SDavid du Colombier 	default:	/* can't happen */
5663e12c5d1SDavid du Colombier 		ERROR "unknown relational operator %d", n FATAL;
5673e12c5d1SDavid du Colombier 	}
5683e12c5d1SDavid du Colombier 	return 0;	/*NOTREACHED*/
5693e12c5d1SDavid du Colombier }
5703e12c5d1SDavid du Colombier 
571*219b2ee8SDavid du Colombier void tfree(Cell *a)	/* free a tempcell */
5723e12c5d1SDavid du Colombier {
5733e12c5d1SDavid du Colombier 	if (freeable(a))
5743e12c5d1SDavid du Colombier 		xfree(a->sval);
5753e12c5d1SDavid du Colombier 	if (a == tmps)
5763e12c5d1SDavid du Colombier 		ERROR "tempcell list is curdled" FATAL;
5773e12c5d1SDavid du Colombier 	a->cnext = tmps;
5783e12c5d1SDavid du Colombier 	tmps = a;
5793e12c5d1SDavid du Colombier }
5803e12c5d1SDavid du Colombier 
581*219b2ee8SDavid du Colombier Cell *gettemp(void)	/* get a tempcell */
5823e12c5d1SDavid du Colombier {	int i;
5833e12c5d1SDavid du Colombier 	register Cell *x;
5843e12c5d1SDavid du Colombier 
5853e12c5d1SDavid du Colombier 	if (!tmps) {
5863e12c5d1SDavid du Colombier 		tmps = (Cell *) calloc(100, sizeof(Cell));
5873e12c5d1SDavid du Colombier 		if (!tmps)
588*219b2ee8SDavid du Colombier 			ERROR "out of space for temporaries" FATAL;
5893e12c5d1SDavid du Colombier 		for(i = 1; i < 100; i++)
5903e12c5d1SDavid du Colombier 			tmps[i-1].cnext = &tmps[i];
5913e12c5d1SDavid du Colombier 		tmps[i-1].cnext = 0;
5923e12c5d1SDavid du Colombier 	}
5933e12c5d1SDavid du Colombier 	x = tmps;
5943e12c5d1SDavid du Colombier 	tmps = x->cnext;
5953e12c5d1SDavid du Colombier 	*x = tempcell;
5963e12c5d1SDavid du Colombier 	return(x);
5973e12c5d1SDavid du Colombier }
5983e12c5d1SDavid du Colombier 
599*219b2ee8SDavid du Colombier Cell *indirect(Node **a, int n)	/* $( a[0] ) */
6003e12c5d1SDavid du Colombier {
6013e12c5d1SDavid du Colombier 	register Cell *x;
6023e12c5d1SDavid du Colombier 	register int m;
6033e12c5d1SDavid du Colombier 	register uchar *s;
6043e12c5d1SDavid du Colombier 
6053e12c5d1SDavid du Colombier 	x = execute(a[0]);
6063e12c5d1SDavid du Colombier 	m = getfval(x);
6073e12c5d1SDavid du Colombier 	if (m == 0 && !isnumber(s = getsval(x)))	/* suspicion! */
608*219b2ee8SDavid du Colombier 		ERROR "illegal field $(%s), name \"%s\"", s, x->nval FATAL;
609*219b2ee8SDavid du Colombier   /* can x->nval ever be null??? */
610*219b2ee8SDavid du Colombier 		/* ERROR "illegal field $(%s)", s FATAL; */
6113e12c5d1SDavid du Colombier 	tempfree(x);
6123e12c5d1SDavid du Colombier 	x = fieldadr(m);
6133e12c5d1SDavid du Colombier 	x->ctype = OCELL;
6143e12c5d1SDavid du Colombier 	x->csub = CFLD;
6153e12c5d1SDavid du Colombier 	return(x);
6163e12c5d1SDavid du Colombier }
6173e12c5d1SDavid du Colombier 
618*219b2ee8SDavid du Colombier Cell *substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
6193e12c5d1SDavid du Colombier {
6203e12c5d1SDavid du Colombier 	register int k, m, n;
6213e12c5d1SDavid du Colombier 	register uchar *s, *p;
6223e12c5d1SDavid du Colombier 	int temp;
6233e12c5d1SDavid du Colombier 	register Cell *x, *y, *z;
6243e12c5d1SDavid du Colombier 
6253e12c5d1SDavid du Colombier 	x = execute(a[0]);
6263e12c5d1SDavid du Colombier 	y = execute(a[1]);
6273e12c5d1SDavid du Colombier 	if (a[2] != 0)
6283e12c5d1SDavid du Colombier 		z = execute(a[2]);
6293e12c5d1SDavid du Colombier 	s = getsval(x);
6303e12c5d1SDavid du Colombier 	k = countposn(s, strlen(s)) + 1;
6313e12c5d1SDavid du Colombier 	if (k <= 1) {
6323e12c5d1SDavid du Colombier 		tempfree(x);
6333e12c5d1SDavid du Colombier 		tempfree(y);
6343e12c5d1SDavid du Colombier 		if (a[2] != 0)
6353e12c5d1SDavid du Colombier 			tempfree(z);
6363e12c5d1SDavid du Colombier 		x = gettemp();
6373e12c5d1SDavid du Colombier 		setsval(x, "");
6383e12c5d1SDavid du Colombier 		return(x);
6393e12c5d1SDavid du Colombier 	}
6403e12c5d1SDavid du Colombier 	m = getfval(y);
6413e12c5d1SDavid du Colombier 	if (m <= 0)
6423e12c5d1SDavid du Colombier 		m = 1;
6433e12c5d1SDavid du Colombier 	else if (m > k)
6443e12c5d1SDavid du Colombier 		m = k;
6453e12c5d1SDavid du Colombier 	tempfree(y);
6463e12c5d1SDavid du Colombier 	if (a[2] != 0) {
6473e12c5d1SDavid du Colombier 		n = getfval(z);
6483e12c5d1SDavid du Colombier 		tempfree(z);
6493e12c5d1SDavid du Colombier 	} else
6503e12c5d1SDavid du Colombier 		n = k - 1;
6513e12c5d1SDavid du Colombier 	if (n < 0)
6523e12c5d1SDavid du Colombier 		n = 0;
6533e12c5d1SDavid du Colombier 	else if (n > k - m)
6543e12c5d1SDavid du Colombier 		n = k - m;
6553e12c5d1SDavid du Colombier 	dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
6563e12c5d1SDavid du Colombier 	y = gettemp();
6573e12c5d1SDavid du Colombier 	while (*s && --m)
6583e12c5d1SDavid du Colombier 		 s += mblen(s, k);
6593e12c5d1SDavid du Colombier 	for (p = s; *p && n--; p += mblen(p, k))
6603e12c5d1SDavid du Colombier 			;
6613e12c5d1SDavid du Colombier 	temp = *p;	/* with thanks to John Linderman */
6623e12c5d1SDavid du Colombier 	*p = '\0';
6633e12c5d1SDavid du Colombier 	setsval(y, s);
6643e12c5d1SDavid du Colombier 	*p = temp;
6653e12c5d1SDavid du Colombier 	tempfree(x);
6663e12c5d1SDavid du Colombier 	return(y);
6673e12c5d1SDavid du Colombier }
6683e12c5d1SDavid du Colombier 
669*219b2ee8SDavid du Colombier Cell *sindex(Node **a, int nnn)		/* index(a[0], a[1]) */
6703e12c5d1SDavid du Colombier {
6713e12c5d1SDavid du Colombier 	register Cell *x, *y, *z;
6723e12c5d1SDavid du Colombier 	register uchar *s1, *s2, *p1, *p2, *q;
6733e12c5d1SDavid du Colombier 	Awkfloat v = 0.0;
6743e12c5d1SDavid du Colombier 
6753e12c5d1SDavid du Colombier 	x = execute(a[0]);
6763e12c5d1SDavid du Colombier 	s1 = getsval(x);
6773e12c5d1SDavid du Colombier 	y = execute(a[1]);
6783e12c5d1SDavid du Colombier 	s2 = getsval(y);
6793e12c5d1SDavid du Colombier 
6803e12c5d1SDavid du Colombier 	z = gettemp();
6813e12c5d1SDavid du Colombier 	for (p1 = s1; *p1 != '\0'; p1++) {
6823e12c5d1SDavid du Colombier 		for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
6833e12c5d1SDavid du Colombier 			;
6843e12c5d1SDavid du Colombier 		if (*p2 == '\0') {
6853e12c5d1SDavid du Colombier 			v = (Awkfloat) countposn(s1, p1-s1) + 1;/* origin 1 */
6863e12c5d1SDavid du Colombier 			break;
6873e12c5d1SDavid du Colombier 		}
6883e12c5d1SDavid du Colombier 	}
6893e12c5d1SDavid du Colombier 	tempfree(x);
6903e12c5d1SDavid du Colombier 	tempfree(y);
6913e12c5d1SDavid du Colombier 	setfval(z, v);
6923e12c5d1SDavid du Colombier 	return(z);
6933e12c5d1SDavid du Colombier }
6943e12c5d1SDavid du Colombier 
695*219b2ee8SDavid du Colombier double
696*219b2ee8SDavid du Colombier boundfloat(Cell *x)
697*219b2ee8SDavid du Colombier {
698*219b2ee8SDavid du Colombier 	double v;
699*219b2ee8SDavid du Colombier 
700*219b2ee8SDavid du Colombier 	v = getfval(x);
701*219b2ee8SDavid du Colombier 	if(v > 2147483647.0)
702*219b2ee8SDavid du Colombier 		return 2147483647.0;
703*219b2ee8SDavid du Colombier 	if(v < -2147483647.0)
704*219b2ee8SDavid du Colombier 		return -2147483647.0;
705*219b2ee8SDavid du Colombier 	return v;
706*219b2ee8SDavid du Colombier }
707*219b2ee8SDavid du Colombier 
708*219b2ee8SDavid du Colombier format(uchar *buf, int bufsize, uchar *s, Node *a)	/* printf-like conversions */
7093e12c5d1SDavid du Colombier {
7103e12c5d1SDavid du Colombier 	uchar fmt[RECSIZE];
7113e12c5d1SDavid du Colombier 	register uchar *p, *t, *os;
7123e12c5d1SDavid du Colombier 	register Cell *x;
7133e12c5d1SDavid du Colombier 	int flag = 0, n;
7143e12c5d1SDavid du Colombier 
7153e12c5d1SDavid du Colombier 	os = s;
7163e12c5d1SDavid du Colombier 	p = buf;
7173e12c5d1SDavid du Colombier 	while (*s) {
7183e12c5d1SDavid du Colombier 		if (p - buf >= bufsize)
7193e12c5d1SDavid du Colombier 			return -1;
7203e12c5d1SDavid du Colombier 		if (*s != '%') {
7213e12c5d1SDavid du Colombier 			*p++ = *s++;
7223e12c5d1SDavid du Colombier 			continue;
7233e12c5d1SDavid du Colombier 		}
7243e12c5d1SDavid du Colombier 		if (*(s+1) == '%') {
7253e12c5d1SDavid du Colombier 			*p++ = '%';
7263e12c5d1SDavid du Colombier 			s += 2;
7273e12c5d1SDavid du Colombier 			continue;
7283e12c5d1SDavid du Colombier 		}
7293e12c5d1SDavid du Colombier 		for (t=fmt; (*t++ = *s) != '\0'; s++) {
7303e12c5d1SDavid du Colombier 			if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
7313e12c5d1SDavid du Colombier 				break;	/* the ansi panoply */
7323e12c5d1SDavid du Colombier 			if (*s == '*') {
7333e12c5d1SDavid du Colombier 				x = execute(a);
7343e12c5d1SDavid du Colombier 				a = a->nnext;
7353e12c5d1SDavid du Colombier 				sprintf((char *)t-1, "%d", (int) getfval(x));
7363e12c5d1SDavid du Colombier 				t = fmt + strlen(fmt);
7373e12c5d1SDavid du Colombier 				tempfree(x);
7383e12c5d1SDavid du Colombier 			}
7393e12c5d1SDavid du Colombier 		}
7403e12c5d1SDavid du Colombier 		*t = '\0';
7413e12c5d1SDavid du Colombier 		if (t >= fmt + sizeof(fmt))
742*219b2ee8SDavid du Colombier 			ERROR "format item %.30s... too long", os FATAL;
7433e12c5d1SDavid du Colombier 		switch (*s) {
7443e12c5d1SDavid du Colombier 		case 'f': case 'e': case 'g': case 'E': case 'G':
7453e12c5d1SDavid du Colombier 			flag = 1;
7463e12c5d1SDavid du Colombier 			break;
7473e12c5d1SDavid du Colombier 		case 'd': case 'i':
7483e12c5d1SDavid du Colombier 			flag = 2;
7493e12c5d1SDavid du Colombier 			if(*(s-1) == 'l') break;
7503e12c5d1SDavid du Colombier 			*(t-1) = 'l';
7513e12c5d1SDavid du Colombier 			*t = 'd';
7523e12c5d1SDavid du Colombier 			*++t = '\0';
7533e12c5d1SDavid du Colombier 			break;
7543e12c5d1SDavid du Colombier 		case 'o': case 'x': case 'X': case 'u':
7553e12c5d1SDavid du Colombier 			flag = *(s-1) == 'l' ? 2 : 3;
7563e12c5d1SDavid du Colombier 			break;
7573e12c5d1SDavid du Colombier 		case 's':
7583e12c5d1SDavid du Colombier 			flag = 4;
7593e12c5d1SDavid du Colombier 			break;
7603e12c5d1SDavid du Colombier 		case 'c':
7613e12c5d1SDavid du Colombier 			flag = 5;
7623e12c5d1SDavid du Colombier 			break;
7633e12c5d1SDavid du Colombier 		default:
7643e12c5d1SDavid du Colombier 			ERROR "weird printf conversion %s", fmt WARNING;
7653e12c5d1SDavid du Colombier 			flag = 0;
7663e12c5d1SDavid du Colombier 			break;
7673e12c5d1SDavid du Colombier 		}
7683e12c5d1SDavid du Colombier 		if (a == NULL)
7693e12c5d1SDavid du Colombier 			ERROR "not enough args in printf(%s)", os FATAL;
7703e12c5d1SDavid du Colombier 		x = execute(a);
7713e12c5d1SDavid du Colombier 		a = a->nnext;
7723e12c5d1SDavid du Colombier 		switch (flag) {
7733e12c5d1SDavid du Colombier 		case 0:	sprintf((char *)p, "%s", fmt);	/* unknown, so dump it too */
7743e12c5d1SDavid du Colombier 			p += strlen(p);
7753e12c5d1SDavid du Colombier 			sprintf((char *)p, "%s", getsval(x));
7763e12c5d1SDavid du Colombier 			break;
7773e12c5d1SDavid du Colombier 		case 1:	sprintf((char *)p, (char *)fmt, getfval(x)); break;
778*219b2ee8SDavid du Colombier 		case 2:	sprintf((char *)p, (char *)fmt, (long) boundfloat(x));
779*219b2ee8SDavid du Colombier 			break;
780*219b2ee8SDavid du Colombier 		case 3:	sprintf((char *)p, (char *)fmt, (int) boundfloat(x)); break;
7813e12c5d1SDavid du Colombier 		case 4:
7823e12c5d1SDavid du Colombier 			t = getsval(x);
7833e12c5d1SDavid du Colombier 			n = strlen(t);
7843e12c5d1SDavid du Colombier 			if (n >= bufsize)
7853e12c5d1SDavid du Colombier 				ERROR "huge string (%d chars) in printf %.30s...",
7863e12c5d1SDavid du Colombier 					n, t FATAL;
7873e12c5d1SDavid du Colombier 			sprintf((char *)p, (char *)fmt, t);
7883e12c5d1SDavid du Colombier 			break;
789*219b2ee8SDavid du Colombier 		case 5:
790*219b2ee8SDavid du Colombier 			isnum(x) ? sprintf((char *)p, (char *)fmt, (int) boundfloat(x))
7913e12c5d1SDavid du Colombier 				 : sprintf((char *)p, (char *)fmt, getsval(x)[0]);
7923e12c5d1SDavid du Colombier 			break;
7933e12c5d1SDavid du Colombier 		}
7943e12c5d1SDavid du Colombier 		tempfree(x);
7953e12c5d1SDavid du Colombier 		p += strlen(p);
7963e12c5d1SDavid du Colombier 		s++;
7973e12c5d1SDavid du Colombier 	}
7983e12c5d1SDavid du Colombier 	*p = '\0';
7993e12c5d1SDavid du Colombier 	for ( ; a; a = a->nnext)		/* evaluate any remaining args */
8003e12c5d1SDavid du Colombier 		execute(a);
8013e12c5d1SDavid du Colombier 	return 0;
8023e12c5d1SDavid du Colombier }
8033e12c5d1SDavid du Colombier 
804*219b2ee8SDavid du Colombier Cell *asprintf(Node **a, int n)		/* sprintf(a[0]) */
8053e12c5d1SDavid du Colombier {
8063e12c5d1SDavid du Colombier 	register Cell *x;
8073e12c5d1SDavid du Colombier 	register Node *y;
8083e12c5d1SDavid du Colombier 	uchar buf[3*RECSIZE];
8093e12c5d1SDavid du Colombier 
8103e12c5d1SDavid du Colombier 	y = a[0]->nnext;
8113e12c5d1SDavid du Colombier 	x = execute(a[0]);
8123e12c5d1SDavid du Colombier 	if (format(buf, sizeof buf, getsval(x), y) == -1)
813*219b2ee8SDavid du Colombier 		ERROR "sprintf string %.30s... too long", buf FATAL;
8143e12c5d1SDavid du Colombier 	tempfree(x);
8153e12c5d1SDavid du Colombier 	x = gettemp();
8163e12c5d1SDavid du Colombier 	x->sval = tostring(buf);
8173e12c5d1SDavid du Colombier 	x->tval = STR;
8183e12c5d1SDavid du Colombier 	return(x);
8193e12c5d1SDavid du Colombier }
8203e12c5d1SDavid du Colombier 
821*219b2ee8SDavid du Colombier Cell *aprintf(Node **a, int n)		/* printf */
822*219b2ee8SDavid du Colombier {	/* a[0] is list of args, starting with format string */
823*219b2ee8SDavid du Colombier 	/* a[1] is redirection operator, a[2] is redirection file */
8243e12c5d1SDavid du Colombier 	FILE *fp;
8253e12c5d1SDavid du Colombier 	register Cell *x;
8263e12c5d1SDavid du Colombier 	register Node *y;
8273e12c5d1SDavid du Colombier 	uchar buf[3*RECSIZE];
8283e12c5d1SDavid du Colombier 
8293e12c5d1SDavid du Colombier 	y = a[0]->nnext;
8303e12c5d1SDavid du Colombier 	x = execute(a[0]);
8313e12c5d1SDavid du Colombier 	if (format(buf, sizeof buf, getsval(x), y) == -1)
832*219b2ee8SDavid du Colombier 		ERROR "printf string %.30s... too long", buf FATAL;
8333e12c5d1SDavid du Colombier 	tempfree(x);
8343e12c5d1SDavid du Colombier 	if (a[1] == NULL) {
8353e12c5d1SDavid du Colombier 		fputs((char *)buf, stdout);
8363e12c5d1SDavid du Colombier 		if (ferror(stdout))
8373e12c5d1SDavid du Colombier 			ERROR "write error on stdout" FATAL;
8383e12c5d1SDavid du Colombier 	} else {
8393e12c5d1SDavid du Colombier 		fp = redirect((int)a[1], a[2]);
8403e12c5d1SDavid du Colombier 		fputs((char *)buf, fp);
8413e12c5d1SDavid du Colombier 		fflush(fp);
8423e12c5d1SDavid du Colombier 		if (ferror(fp))
8433e12c5d1SDavid du Colombier 			ERROR "write error on %s", filename(fp) FATAL;
8443e12c5d1SDavid du Colombier 	}
8453e12c5d1SDavid du Colombier 	return(true);
8463e12c5d1SDavid du Colombier }
8473e12c5d1SDavid du Colombier 
848*219b2ee8SDavid du Colombier Cell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
8493e12c5d1SDavid du Colombier {
8503e12c5d1SDavid du Colombier 	Awkfloat i, j;
8513e12c5d1SDavid du Colombier 	double v;
8523e12c5d1SDavid du Colombier 	register Cell *x, *y, *z;
8533e12c5d1SDavid du Colombier 
8543e12c5d1SDavid du Colombier 	x = execute(a[0]);
8553e12c5d1SDavid du Colombier 	i = getfval(x);
8563e12c5d1SDavid du Colombier 	tempfree(x);
8573e12c5d1SDavid du Colombier 	if (n != UMINUS) {
8583e12c5d1SDavid du Colombier 		y = execute(a[1]);
8593e12c5d1SDavid du Colombier 		j = getfval(y);
8603e12c5d1SDavid du Colombier 		tempfree(y);
8613e12c5d1SDavid du Colombier 	}
8623e12c5d1SDavid du Colombier 	z = gettemp();
8633e12c5d1SDavid du Colombier 	switch (n) {
8643e12c5d1SDavid du Colombier 	case ADD:
8653e12c5d1SDavid du Colombier 		i += j;
8663e12c5d1SDavid du Colombier 		break;
8673e12c5d1SDavid du Colombier 	case MINUS:
8683e12c5d1SDavid du Colombier 		i -= j;
8693e12c5d1SDavid du Colombier 		break;
8703e12c5d1SDavid du Colombier 	case MULT:
8713e12c5d1SDavid du Colombier 		i *= j;
8723e12c5d1SDavid du Colombier 		break;
8733e12c5d1SDavid du Colombier 	case DIVIDE:
8743e12c5d1SDavid du Colombier 		if (j == 0)
8753e12c5d1SDavid du Colombier 			ERROR "division by zero" FATAL;
8763e12c5d1SDavid du Colombier 		i /= j;
8773e12c5d1SDavid du Colombier 		break;
8783e12c5d1SDavid du Colombier 	case MOD:
8793e12c5d1SDavid du Colombier 		if (j == 0)
8803e12c5d1SDavid du Colombier 			ERROR "division by zero in mod" FATAL;
8813e12c5d1SDavid du Colombier 		modf(i/j, &v);
8823e12c5d1SDavid du Colombier 		i = i - j * v;
8833e12c5d1SDavid du Colombier 		break;
8843e12c5d1SDavid du Colombier 	case UMINUS:
8853e12c5d1SDavid du Colombier 		i = -i;
8863e12c5d1SDavid du Colombier 		break;
8873e12c5d1SDavid du Colombier 	case POWER:
8883e12c5d1SDavid du Colombier 		if (j >= 0 && modf(j, &v) == 0.0)	/* pos integer exponent */
8893e12c5d1SDavid du Colombier 			i = ipow(i, (int) j);
8903e12c5d1SDavid du Colombier 		else
8913e12c5d1SDavid du Colombier 			i = errcheck(pow(i, j), "pow");
8923e12c5d1SDavid du Colombier 		break;
8933e12c5d1SDavid du Colombier 	default:	/* can't happen */
8943e12c5d1SDavid du Colombier 		ERROR "illegal arithmetic operator %d", n FATAL;
8953e12c5d1SDavid du Colombier 	}
8963e12c5d1SDavid du Colombier 	setfval(z, i);
8973e12c5d1SDavid du Colombier 	return(z);
8983e12c5d1SDavid du Colombier }
8993e12c5d1SDavid du Colombier 
900*219b2ee8SDavid du Colombier double ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
9013e12c5d1SDavid du Colombier {
9023e12c5d1SDavid du Colombier 	double v;
9033e12c5d1SDavid du Colombier 
9043e12c5d1SDavid du Colombier 	if (n <= 0)
9053e12c5d1SDavid du Colombier 		return 1;
9063e12c5d1SDavid du Colombier 	v = ipow(x, n/2);
9073e12c5d1SDavid du Colombier 	if (n % 2 == 0)
9083e12c5d1SDavid du Colombier 		return v * v;
9093e12c5d1SDavid du Colombier 	else
9103e12c5d1SDavid du Colombier 		return x * v * v;
9113e12c5d1SDavid du Colombier }
9123e12c5d1SDavid du Colombier 
913*219b2ee8SDavid du Colombier Cell *incrdecr(Node **a, int n)		/* a[0]++, etc. */
9143e12c5d1SDavid du Colombier {
9153e12c5d1SDavid du Colombier 	register Cell *x, *z;
9163e12c5d1SDavid du Colombier 	register int k;
9173e12c5d1SDavid du Colombier 	Awkfloat xf;
9183e12c5d1SDavid du Colombier 
9193e12c5d1SDavid du Colombier 	x = execute(a[0]);
9203e12c5d1SDavid du Colombier 	xf = getfval(x);
9213e12c5d1SDavid du Colombier 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
9223e12c5d1SDavid du Colombier 	if (n == PREINCR || n == PREDECR) {
9233e12c5d1SDavid du Colombier 		setfval(x, xf + k);
9243e12c5d1SDavid du Colombier 		return(x);
9253e12c5d1SDavid du Colombier 	}
9263e12c5d1SDavid du Colombier 	z = gettemp();
9273e12c5d1SDavid du Colombier 	setfval(z, xf);
9283e12c5d1SDavid du Colombier 	setfval(x, xf + k);
9293e12c5d1SDavid du Colombier 	tempfree(x);
9303e12c5d1SDavid du Colombier 	return(z);
9313e12c5d1SDavid du Colombier }
9323e12c5d1SDavid du Colombier 
933*219b2ee8SDavid du Colombier Cell *assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
934*219b2ee8SDavid du Colombier {		/* this is subtle; don't muck with it. */
9353e12c5d1SDavid du Colombier 	register Cell *x, *y;
9363e12c5d1SDavid du Colombier 	Awkfloat xf, yf;
9373e12c5d1SDavid du Colombier 	double v;
9383e12c5d1SDavid du Colombier 
9393e12c5d1SDavid du Colombier 	y = execute(a[1]);
9403e12c5d1SDavid du Colombier 	x = execute(a[0]);
9413e12c5d1SDavid du Colombier 	if (n == ASSIGN) {	/* ordinary assignment */
942*219b2ee8SDavid du Colombier 		if (x == y && !(x->tval & (FLD|REC)))	/* self-assignment: */
943*219b2ee8SDavid du Colombier 			;		/* leave alone unless it's a field */
9443e12c5d1SDavid du Colombier 		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
9453e12c5d1SDavid du Colombier 			setsval(x, getsval(y));
9463e12c5d1SDavid du Colombier 			x->fval = getfval(y);
9473e12c5d1SDavid du Colombier 			x->tval |= NUM;
9483e12c5d1SDavid du Colombier 		}
9493e12c5d1SDavid du Colombier 		else if (y->tval & STR)
9503e12c5d1SDavid du Colombier 			setsval(x, getsval(y));
9513e12c5d1SDavid du Colombier 		else if (y->tval & NUM)
9523e12c5d1SDavid du Colombier 			setfval(x, getfval(y));
9533e12c5d1SDavid du Colombier 		else
9543e12c5d1SDavid du Colombier 			funnyvar(y, "read value of");
9553e12c5d1SDavid du Colombier 		tempfree(y);
9563e12c5d1SDavid du Colombier 		return(x);
9573e12c5d1SDavid du Colombier 	}
9583e12c5d1SDavid du Colombier 	xf = getfval(x);
9593e12c5d1SDavid du Colombier 	yf = getfval(y);
9603e12c5d1SDavid du Colombier 	switch (n) {
9613e12c5d1SDavid du Colombier 	case ADDEQ:
9623e12c5d1SDavid du Colombier 		xf += yf;
9633e12c5d1SDavid du Colombier 		break;
9643e12c5d1SDavid du Colombier 	case SUBEQ:
9653e12c5d1SDavid du Colombier 		xf -= yf;
9663e12c5d1SDavid du Colombier 		break;
9673e12c5d1SDavid du Colombier 	case MULTEQ:
9683e12c5d1SDavid du Colombier 		xf *= yf;
9693e12c5d1SDavid du Colombier 		break;
9703e12c5d1SDavid du Colombier 	case DIVEQ:
9713e12c5d1SDavid du Colombier 		if (yf == 0)
9723e12c5d1SDavid du Colombier 			ERROR "division by zero in /=" FATAL;
9733e12c5d1SDavid du Colombier 		xf /= yf;
9743e12c5d1SDavid du Colombier 		break;
9753e12c5d1SDavid du Colombier 	case MODEQ:
9763e12c5d1SDavid du Colombier 		if (yf == 0)
9773e12c5d1SDavid du Colombier 			ERROR "division by zero in %%=" FATAL;
9783e12c5d1SDavid du Colombier 		modf(xf/yf, &v);
9793e12c5d1SDavid du Colombier 		xf = xf - yf * v;
9803e12c5d1SDavid du Colombier 		break;
9813e12c5d1SDavid du Colombier 	case POWEQ:
9823e12c5d1SDavid du Colombier 		if (yf >= 0 && modf(yf, &v) == 0.0)	/* pos integer exponent */
9833e12c5d1SDavid du Colombier 			xf = ipow(xf, (int) yf);
9843e12c5d1SDavid du Colombier 		else
9853e12c5d1SDavid du Colombier 			xf = errcheck(pow(xf, yf), "pow");
9863e12c5d1SDavid du Colombier 		break;
9873e12c5d1SDavid du Colombier 	default:
9883e12c5d1SDavid du Colombier 		ERROR "illegal assignment operator %d", n FATAL;
9893e12c5d1SDavid du Colombier 		break;
9903e12c5d1SDavid du Colombier 	}
9913e12c5d1SDavid du Colombier 	tempfree(y);
9923e12c5d1SDavid du Colombier 	setfval(x, xf);
9933e12c5d1SDavid du Colombier 	return(x);
9943e12c5d1SDavid du Colombier }
9953e12c5d1SDavid du Colombier 
996*219b2ee8SDavid du Colombier Cell *cat(Node **a, int q)	/* a[0] cat a[1] */
9973e12c5d1SDavid du Colombier {
9983e12c5d1SDavid du Colombier 	register Cell *x, *y, *z;
9993e12c5d1SDavid du Colombier 	register int n1, n2;
10003e12c5d1SDavid du Colombier 	register uchar *s;
10013e12c5d1SDavid du Colombier 
10023e12c5d1SDavid du Colombier 	x = execute(a[0]);
10033e12c5d1SDavid du Colombier 	y = execute(a[1]);
10043e12c5d1SDavid du Colombier 	getsval(x);
10053e12c5d1SDavid du Colombier 	getsval(y);
10063e12c5d1SDavid du Colombier 	n1 = strlen(x->sval);
10073e12c5d1SDavid du Colombier 	n2 = strlen(y->sval);
10083e12c5d1SDavid du Colombier 	s = (uchar *) malloc(n1 + n2 + 1);
10093e12c5d1SDavid du Colombier 	if (s == NULL)
1010*219b2ee8SDavid du Colombier 		ERROR "out of space concatenating %.15s... and %.15s...",
10113e12c5d1SDavid du Colombier 			x->sval, y->sval FATAL;
10123e12c5d1SDavid du Colombier 	strcpy(s, x->sval);
10133e12c5d1SDavid du Colombier 	strcpy(s+n1, y->sval);
10143e12c5d1SDavid du Colombier 	tempfree(y);
10153e12c5d1SDavid du Colombier 	z = gettemp();
10163e12c5d1SDavid du Colombier 	z->sval = s;
10173e12c5d1SDavid du Colombier 	z->tval = STR;
10183e12c5d1SDavid du Colombier 	tempfree(x);
10193e12c5d1SDavid du Colombier 	return(z);
10203e12c5d1SDavid du Colombier }
10213e12c5d1SDavid du Colombier 
10223e12c5d1SDavid du Colombier Cell *pastat(Node **a, int n)	/* a[0] { a[1] } */
10233e12c5d1SDavid du Colombier {
10243e12c5d1SDavid du Colombier 	register Cell *x;
10253e12c5d1SDavid du Colombier 
10263e12c5d1SDavid du Colombier 	if (a[0] == 0)
10273e12c5d1SDavid du Colombier 		x = execute(a[1]);
10283e12c5d1SDavid du Colombier 	else {
10293e12c5d1SDavid du Colombier 		x = execute(a[0]);
10303e12c5d1SDavid du Colombier 		if (istrue(x)) {
10313e12c5d1SDavid du Colombier 			tempfree(x);
10323e12c5d1SDavid du Colombier 			x = execute(a[1]);
10333e12c5d1SDavid du Colombier 		}
10343e12c5d1SDavid du Colombier 	}
10353e12c5d1SDavid du Colombier 	return x;
10363e12c5d1SDavid du Colombier }
10373e12c5d1SDavid du Colombier 
10383e12c5d1SDavid du Colombier Cell *dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
10393e12c5d1SDavid du Colombier {
10403e12c5d1SDavid du Colombier 	register Cell *x;
10413e12c5d1SDavid du Colombier 	register int pair;
10423e12c5d1SDavid du Colombier 
10433e12c5d1SDavid du Colombier 	pair = (int) a[3];
10443e12c5d1SDavid du Colombier 	if (pairstack[pair] == 0) {
10453e12c5d1SDavid du Colombier 		x = execute(a[0]);
10463e12c5d1SDavid du Colombier 		if (istrue(x))
10473e12c5d1SDavid du Colombier 			pairstack[pair] = 1;
10483e12c5d1SDavid du Colombier 		tempfree(x);
10493e12c5d1SDavid du Colombier 	}
10503e12c5d1SDavid du Colombier 	if (pairstack[pair] == 1) {
10513e12c5d1SDavid du Colombier 		x = execute(a[1]);
10523e12c5d1SDavid du Colombier 		if (istrue(x))
10533e12c5d1SDavid du Colombier 			pairstack[pair] = 0;
10543e12c5d1SDavid du Colombier 		tempfree(x);
10553e12c5d1SDavid du Colombier 		x = execute(a[2]);
10563e12c5d1SDavid du Colombier 		return(x);
10573e12c5d1SDavid du Colombier 	}
10583e12c5d1SDavid du Colombier 	return(false);
10593e12c5d1SDavid du Colombier }
10603e12c5d1SDavid du Colombier 
10613e12c5d1SDavid du Colombier Cell *split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
10623e12c5d1SDavid du Colombier {
10633e12c5d1SDavid du Colombier 	Cell *x, *y, *ap;
10643e12c5d1SDavid du Colombier 	register uchar *s;
10653e12c5d1SDavid du Colombier 	register int sep;
1066*219b2ee8SDavid du Colombier 	uchar *t, temp, num[10], *fs;
10673e12c5d1SDavid du Colombier 	int n;
10683e12c5d1SDavid du Colombier 
10693e12c5d1SDavid du Colombier 	y = execute(a[0]);	/* source string */
10703e12c5d1SDavid du Colombier 	s = getsval(y);
10713e12c5d1SDavid du Colombier 	if (a[2] == 0)		/* fs string */
10723e12c5d1SDavid du Colombier 		fs = *FS;
10733e12c5d1SDavid du Colombier 	else if ((int) a[3] == STRING) {	/* split(str,arr,"string") */
10743e12c5d1SDavid du Colombier 		x = execute(a[2]);
10753e12c5d1SDavid du Colombier 		fs = getsval(x);
10763e12c5d1SDavid du Colombier 	} else if ((int) a[3] == REGEXPR)
10773e12c5d1SDavid du Colombier 		fs = (uchar*) "(regexpr)";	/* split(str,arr,/regexpr/) */
10783e12c5d1SDavid du Colombier 	else
10793e12c5d1SDavid du Colombier 		ERROR "illegal type of split()" FATAL;
10803e12c5d1SDavid du Colombier 	sep = *fs;
10813e12c5d1SDavid du Colombier 	ap = execute(a[1]);	/* array name */
10823e12c5d1SDavid du Colombier 	freesymtab(ap);
10833e12c5d1SDavid du Colombier 	dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
10843e12c5d1SDavid du Colombier 	ap->tval &= ~STR;
10853e12c5d1SDavid du Colombier 	ap->tval |= ARR;
10863e12c5d1SDavid du Colombier 	ap->sval = (uchar *) makesymtab(NSYMTAB);
10873e12c5d1SDavid du Colombier 
10883e12c5d1SDavid du Colombier 	n = 0;
10893e12c5d1SDavid du Colombier 	if (*s != '\0' && strlen(fs) > 1 || (int) a[3] == REGEXPR) {	/* reg expr */
10903e12c5d1SDavid du Colombier 		void *p;
10913e12c5d1SDavid du Colombier 		if ((int) a[3] == REGEXPR) {	/* it's ready already */
10923e12c5d1SDavid du Colombier 			p = (void *) a[2];
10933e12c5d1SDavid du Colombier 		} else {
10943e12c5d1SDavid du Colombier 			p = compre(fs);
10953e12c5d1SDavid du Colombier 		}
10963e12c5d1SDavid du Colombier 		t = s;
10973e12c5d1SDavid du Colombier 		if (nematch(p,s,t)) {
10983e12c5d1SDavid du Colombier 			do {
10993e12c5d1SDavid du Colombier 				n++;
11003e12c5d1SDavid du Colombier 				sprintf((char *)num, "%d", n);
11013e12c5d1SDavid du Colombier 				temp = *patbeg;
11023e12c5d1SDavid du Colombier 				*patbeg = '\0';
11033e12c5d1SDavid du Colombier 				if (isnumber(t))
11043e12c5d1SDavid du Colombier 					setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
11053e12c5d1SDavid du Colombier 				else
11063e12c5d1SDavid du Colombier 					setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
11073e12c5d1SDavid du Colombier 				*patbeg = temp;
11083e12c5d1SDavid du Colombier 				t = patbeg + patlen;
11093e12c5d1SDavid du Colombier 				if (t[-1] == 0 || *t == 0) {
11103e12c5d1SDavid du Colombier 					n++;
11113e12c5d1SDavid du Colombier 					sprintf((char *)num, "%d", n);
11123e12c5d1SDavid du Colombier 					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
11133e12c5d1SDavid du Colombier 					goto spdone;
11143e12c5d1SDavid du Colombier 				}
11153e12c5d1SDavid du Colombier 			} while (nematch(p,s,t));
11163e12c5d1SDavid du Colombier 		}
11173e12c5d1SDavid du Colombier 		n++;
11183e12c5d1SDavid du Colombier 		sprintf((char *)num, "%d", n);
11193e12c5d1SDavid du Colombier 		if (isnumber(t))
11203e12c5d1SDavid du Colombier 			setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
11213e12c5d1SDavid du Colombier 		else
11223e12c5d1SDavid du Colombier 			setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
11233e12c5d1SDavid du Colombier   spdone:
11243e12c5d1SDavid du Colombier 		p = NULL;
11253e12c5d1SDavid du Colombier 	} else if (sep == ' ') {
11263e12c5d1SDavid du Colombier 		for (n = 0; ; ) {
11273e12c5d1SDavid du Colombier 			while (*s == ' ' || *s == '\t' || *s == '\n')
11283e12c5d1SDavid du Colombier 				s++;
11293e12c5d1SDavid du Colombier 			if (*s == 0)
11303e12c5d1SDavid du Colombier 				break;
11313e12c5d1SDavid du Colombier 			n++;
11323e12c5d1SDavid du Colombier 			t = s;
11333e12c5d1SDavid du Colombier 			do
11343e12c5d1SDavid du Colombier 				s++;
11353e12c5d1SDavid du Colombier 			while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
11363e12c5d1SDavid du Colombier 			temp = *s;
11373e12c5d1SDavid du Colombier 			*s = '\0';
11383e12c5d1SDavid du Colombier 			sprintf((char *)num, "%d", n);
11393e12c5d1SDavid du Colombier 			if (isnumber(t))
11403e12c5d1SDavid du Colombier 				setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
11413e12c5d1SDavid du Colombier 			else
11423e12c5d1SDavid du Colombier 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
11433e12c5d1SDavid du Colombier 			*s = temp;
11443e12c5d1SDavid du Colombier 			if (*s != 0)
11453e12c5d1SDavid du Colombier 				s++;
11463e12c5d1SDavid du Colombier 		}
11473e12c5d1SDavid du Colombier 	} else if (*s != 0) {
11483e12c5d1SDavid du Colombier 		for (;;) {
11493e12c5d1SDavid du Colombier 			n++;
11503e12c5d1SDavid du Colombier 			t = s;
11513e12c5d1SDavid du Colombier 			while (*s != sep && *s != '\n' && *s != '\0')
11523e12c5d1SDavid du Colombier 				s++;
11533e12c5d1SDavid du Colombier 			temp = *s;
11543e12c5d1SDavid du Colombier 			*s = '\0';
11553e12c5d1SDavid du Colombier 			sprintf((char *)num, "%d", n);
11563e12c5d1SDavid du Colombier 			if (isnumber(t))
11573e12c5d1SDavid du Colombier 				setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
11583e12c5d1SDavid du Colombier 			else
11593e12c5d1SDavid du Colombier 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
11603e12c5d1SDavid du Colombier 			*s = temp;
11613e12c5d1SDavid du Colombier 			if (*s++ == 0)
11623e12c5d1SDavid du Colombier 				break;
11633e12c5d1SDavid du Colombier 		}
11643e12c5d1SDavid du Colombier 	}
11653e12c5d1SDavid du Colombier 	tempfree(ap);
11663e12c5d1SDavid du Colombier 	tempfree(y);
11673e12c5d1SDavid du Colombier 	if (a[2] != 0 && (int) a[3] == STRING)
11683e12c5d1SDavid du Colombier 		tempfree(x);
11693e12c5d1SDavid du Colombier 	x = gettemp();
11703e12c5d1SDavid du Colombier 	x->tval = NUM;
11713e12c5d1SDavid du Colombier 	x->fval = n;
11723e12c5d1SDavid du Colombier 	return(x);
11733e12c5d1SDavid du Colombier }
11743e12c5d1SDavid du Colombier 
11753e12c5d1SDavid du Colombier Cell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
11763e12c5d1SDavid du Colombier {
11773e12c5d1SDavid du Colombier 	register Cell *x;
11783e12c5d1SDavid du Colombier 
11793e12c5d1SDavid du Colombier 	x = execute(a[0]);
11803e12c5d1SDavid du Colombier 	if (istrue(x)) {
11813e12c5d1SDavid du Colombier 		tempfree(x);
11823e12c5d1SDavid du Colombier 		x = execute(a[1]);
11833e12c5d1SDavid du Colombier 	} else {
11843e12c5d1SDavid du Colombier 		tempfree(x);
11853e12c5d1SDavid du Colombier 		x = execute(a[2]);
11863e12c5d1SDavid du Colombier 	}
11873e12c5d1SDavid du Colombier 	return(x);
11883e12c5d1SDavid du Colombier }
11893e12c5d1SDavid du Colombier 
11903e12c5d1SDavid du Colombier Cell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
11913e12c5d1SDavid du Colombier {
11923e12c5d1SDavid du Colombier 	register Cell *x;
11933e12c5d1SDavid du Colombier 
11943e12c5d1SDavid du Colombier 	x = execute(a[0]);
11953e12c5d1SDavid du Colombier 	if (istrue(x)) {
11963e12c5d1SDavid du Colombier 		tempfree(x);
11973e12c5d1SDavid du Colombier 		x = execute(a[1]);
11983e12c5d1SDavid du Colombier 	} else if (a[2] != 0) {
11993e12c5d1SDavid du Colombier 		tempfree(x);
12003e12c5d1SDavid du Colombier 		x = execute(a[2]);
12013e12c5d1SDavid du Colombier 	}
12023e12c5d1SDavid du Colombier 	return(x);
12033e12c5d1SDavid du Colombier }
12043e12c5d1SDavid du Colombier 
12053e12c5d1SDavid du Colombier Cell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
12063e12c5d1SDavid du Colombier {
12073e12c5d1SDavid du Colombier 	register Cell *x;
12083e12c5d1SDavid du Colombier 
12093e12c5d1SDavid du Colombier 	for (;;) {
12103e12c5d1SDavid du Colombier 		x = execute(a[0]);
12113e12c5d1SDavid du Colombier 		if (!istrue(x))
12123e12c5d1SDavid du Colombier 			return(x);
12133e12c5d1SDavid du Colombier 		tempfree(x);
12143e12c5d1SDavid du Colombier 		x = execute(a[1]);
12153e12c5d1SDavid du Colombier 		if (isbreak(x)) {
12163e12c5d1SDavid du Colombier 			x = true;
12173e12c5d1SDavid du Colombier 			return(x);
12183e12c5d1SDavid du Colombier 		}
12193e12c5d1SDavid du Colombier 		if (isnext(x) || isexit(x) || isret(x))
12203e12c5d1SDavid du Colombier 			return(x);
12213e12c5d1SDavid du Colombier 		tempfree(x);
12223e12c5d1SDavid du Colombier 	}
12233e12c5d1SDavid du Colombier }
12243e12c5d1SDavid du Colombier 
12253e12c5d1SDavid du Colombier Cell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
12263e12c5d1SDavid du Colombier {
12273e12c5d1SDavid du Colombier 	register Cell *x;
12283e12c5d1SDavid du Colombier 
12293e12c5d1SDavid du Colombier 	for (;;) {
12303e12c5d1SDavid du Colombier 		x = execute(a[0]);
12313e12c5d1SDavid du Colombier 		if (isbreak(x))
12323e12c5d1SDavid du Colombier 			return true;
12333e12c5d1SDavid du Colombier 		if (isnext(x) || isexit(x) || isret(x))
12343e12c5d1SDavid du Colombier 			return(x);
12353e12c5d1SDavid du Colombier 		tempfree(x);
12363e12c5d1SDavid du Colombier 		x = execute(a[1]);
12373e12c5d1SDavid du Colombier 		if (!istrue(x))
12383e12c5d1SDavid du Colombier 			return(x);
12393e12c5d1SDavid du Colombier 		tempfree(x);
12403e12c5d1SDavid du Colombier 	}
12413e12c5d1SDavid du Colombier }
12423e12c5d1SDavid du Colombier 
12433e12c5d1SDavid du Colombier Cell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
12443e12c5d1SDavid du Colombier {
12453e12c5d1SDavid du Colombier 	register Cell *x;
12463e12c5d1SDavid du Colombier 
12473e12c5d1SDavid du Colombier 	x = execute(a[0]);
12483e12c5d1SDavid du Colombier 	tempfree(x);
12493e12c5d1SDavid du Colombier 	for (;;) {
12503e12c5d1SDavid du Colombier 		if (a[1]!=0) {
12513e12c5d1SDavid du Colombier 			x = execute(a[1]);
12523e12c5d1SDavid du Colombier 			if (!istrue(x)) return(x);
12533e12c5d1SDavid du Colombier 			else tempfree(x);
12543e12c5d1SDavid du Colombier 		}
12553e12c5d1SDavid du Colombier 		x = execute(a[3]);
12563e12c5d1SDavid du Colombier 		if (isbreak(x))		/* turn off break */
12573e12c5d1SDavid du Colombier 			return true;
12583e12c5d1SDavid du Colombier 		if (isnext(x) || isexit(x) || isret(x))
12593e12c5d1SDavid du Colombier 			return(x);
12603e12c5d1SDavid du Colombier 		tempfree(x);
12613e12c5d1SDavid du Colombier 		x = execute(a[2]);
12623e12c5d1SDavid du Colombier 		tempfree(x);
12633e12c5d1SDavid du Colombier 	}
12643e12c5d1SDavid du Colombier }
12653e12c5d1SDavid du Colombier 
12663e12c5d1SDavid du Colombier Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
12673e12c5d1SDavid du Colombier {
12683e12c5d1SDavid du Colombier 	register Cell *x, *vp, *arrayp, *cp, *ncp;
12693e12c5d1SDavid du Colombier 	Array *tp;
12703e12c5d1SDavid du Colombier 	int i;
12713e12c5d1SDavid du Colombier 
12723e12c5d1SDavid du Colombier 	vp = execute(a[0]);
12733e12c5d1SDavid du Colombier 	arrayp = execute(a[1]);
12743e12c5d1SDavid du Colombier 	if (!isarr(arrayp)) {
12753e12c5d1SDavid du Colombier 		return true;
12763e12c5d1SDavid du Colombier 	}
12773e12c5d1SDavid du Colombier 	tp = (Array *) arrayp->sval;
12783e12c5d1SDavid du Colombier 	tempfree(arrayp);
12793e12c5d1SDavid du Colombier 	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
12803e12c5d1SDavid du Colombier 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
12813e12c5d1SDavid du Colombier 			setsval(vp, cp->nval);
12823e12c5d1SDavid du Colombier 			ncp = cp->cnext;
12833e12c5d1SDavid du Colombier 			x = execute(a[2]);
12843e12c5d1SDavid du Colombier 			if (isbreak(x)) {
12853e12c5d1SDavid du Colombier 				tempfree(vp);
12863e12c5d1SDavid du Colombier 				return true;
12873e12c5d1SDavid du Colombier 			}
12883e12c5d1SDavid du Colombier 			if (isnext(x) || isexit(x) || isret(x)) {
12893e12c5d1SDavid du Colombier 				tempfree(vp);
12903e12c5d1SDavid du Colombier 				return(x);
12913e12c5d1SDavid du Colombier 			}
12923e12c5d1SDavid du Colombier 			tempfree(x);
12933e12c5d1SDavid du Colombier 		}
12943e12c5d1SDavid du Colombier 	}
12953e12c5d1SDavid du Colombier 	return true;
12963e12c5d1SDavid du Colombier }
12973e12c5d1SDavid du Colombier 
1298*219b2ee8SDavid du Colombier /* if someone ever wants to run over the arrays in sorted order, */
1299*219b2ee8SDavid du Colombier /* here it is.  but it will likely run slower, not faster. */
13003e12c5d1SDavid du Colombier 
13013e12c5d1SDavid du Colombier /*
13023e12c5d1SDavid du Colombier  *int qstrcmp(p, q)
13033e12c5d1SDavid du Colombier  *	uchar **p, **q;
13043e12c5d1SDavid du Colombier  *{
13053e12c5d1SDavid du Colombier  *	return strcmp(*p, *q);
13063e12c5d1SDavid du Colombier  *}
13073e12c5d1SDavid du Colombier  */
13083e12c5d1SDavid du Colombier 
13093e12c5d1SDavid du Colombier /*Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
13103e12c5d1SDavid du Colombier /*{
13113e12c5d1SDavid du Colombier /*	register Cell *x, *vp, *arrayp, *cp, *ncp, *ret;
13123e12c5d1SDavid du Colombier /*	Array *tp;
13133e12c5d1SDavid du Colombier /*	int i, ne;
13143e12c5d1SDavid du Colombier /*#define BIGENOUGH 1000
13153e12c5d1SDavid du Colombier /*	uchar *elems[BIGENOUGH], **ep;
13163e12c5d1SDavid du Colombier /*
13173e12c5d1SDavid du Colombier /*	vp = execute(a[0]);
13183e12c5d1SDavid du Colombier /*	arrayp = execute(a[1]);
13193e12c5d1SDavid du Colombier /*	if (!isarr(arrayp))
13203e12c5d1SDavid du Colombier /*		ERROR "%s is not an array", arrayp->nval FATAL;
13213e12c5d1SDavid du Colombier /*	tp = (Array *) arrayp->sval;
13223e12c5d1SDavid du Colombier /*	tempfree(arrayp);
13233e12c5d1SDavid du Colombier /*	ep = elems;
13243e12c5d1SDavid du Colombier /*	ret = true;
13253e12c5d1SDavid du Colombier /*	if (tp->nelem >= BIGENOUGH)
13263e12c5d1SDavid du Colombier /*		ep = (uchar **) malloc(tp->nelem * sizeof(char *));
13273e12c5d1SDavid du Colombier /*
13283e12c5d1SDavid du Colombier /*	for (i = ne = 0; i < tp->size; i++)
13293e12c5d1SDavid du Colombier /*		for (cp = tp->tab[i]; cp != NULL; cp = cp->cnext)
13303e12c5d1SDavid du Colombier /*			ep[ne++] = cp->nval;
13313e12c5d1SDavid du Colombier /*	if (ne != tp->nelem)
13323e12c5d1SDavid du Colombier /*		ERROR "can't happen: lost elems %d vs. %d", ne, tp->nelem FATAL;
13333e12c5d1SDavid du Colombier /*	qsort(ep, ne, sizeof(char *), qstrcmp);
13343e12c5d1SDavid du Colombier /*	for (i = 0; i < ne; i++) {
13353e12c5d1SDavid du Colombier /*		setsval(vp, ep[i]);
13363e12c5d1SDavid du Colombier /*		x = execute(a[2]);
13373e12c5d1SDavid du Colombier /*		if (isbreak(x)) {
13383e12c5d1SDavid du Colombier /*			tempfree(vp);
13393e12c5d1SDavid du Colombier /*			break;
13403e12c5d1SDavid du Colombier /*		}
13413e12c5d1SDavid du Colombier /*		if (isnext(x) || isexit(x) || isret(x)) {
13423e12c5d1SDavid du Colombier /*			tempfree(vp);
13433e12c5d1SDavid du Colombier /*			ret = x;
13443e12c5d1SDavid du Colombier /*			break;
13453e12c5d1SDavid du Colombier /*		}
13463e12c5d1SDavid du Colombier /*		tempfree(x);
13473e12c5d1SDavid du Colombier /*	}
13483e12c5d1SDavid du Colombier /*	if (ep != elems)
13493e12c5d1SDavid du Colombier /*		free(ep);
13503e12c5d1SDavid du Colombier /*	return ret;
13513e12c5d1SDavid du Colombier /*}
13523e12c5d1SDavid du Colombier */
13533e12c5d1SDavid du Colombier 
13543e12c5d1SDavid du Colombier 
1355*219b2ee8SDavid du Colombier Cell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
13563e12c5d1SDavid du Colombier {
13573e12c5d1SDavid du Colombier 	register Cell *x, *y;
13583e12c5d1SDavid du Colombier 	Awkfloat u;
13593e12c5d1SDavid du Colombier 	register int t;
1360*219b2ee8SDavid du Colombier 	wchar_t wc;
13613e12c5d1SDavid du Colombier 	uchar *p, buf[RECSIZE];
1362*219b2ee8SDavid du Colombier 	char mbc[10];
13633e12c5d1SDavid du Colombier 	Node *nextarg;
13643e12c5d1SDavid du Colombier 	FILE *fp;
13653e12c5d1SDavid du Colombier 
13663e12c5d1SDavid du Colombier 	t = (int) a[0];
13673e12c5d1SDavid du Colombier 	x = execute(a[1]);
13683e12c5d1SDavid du Colombier 	nextarg = a[1]->nnext;
13693e12c5d1SDavid du Colombier 	switch (t) {
13703e12c5d1SDavid du Colombier 	case FLENGTH:
13713e12c5d1SDavid du Colombier 		p = getsval(x);
13723e12c5d1SDavid du Colombier 		u = (Awkfloat) countposn(p, strlen(p)); break;
13733e12c5d1SDavid du Colombier 	case FLOG:
13743e12c5d1SDavid du Colombier 		u = errcheck(log(getfval(x)), "log"); break;
13753e12c5d1SDavid du Colombier 	case FINT:
13763e12c5d1SDavid du Colombier 		modf(getfval(x), &u); break;
13773e12c5d1SDavid du Colombier 	case FEXP:
13783e12c5d1SDavid du Colombier 		u = errcheck(exp(getfval(x)), "exp"); break;
13793e12c5d1SDavid du Colombier 	case FSQRT:
13803e12c5d1SDavid du Colombier 		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
13813e12c5d1SDavid du Colombier 	case FSIN:
13823e12c5d1SDavid du Colombier 		u = sin(getfval(x)); break;
13833e12c5d1SDavid du Colombier 	case FCOS:
13843e12c5d1SDavid du Colombier 		u = cos(getfval(x)); break;
13853e12c5d1SDavid du Colombier 	case FATAN:
13863e12c5d1SDavid du Colombier 		if (nextarg == 0) {
13873e12c5d1SDavid du Colombier 			ERROR "atan2 requires two arguments; returning 1.0" WARNING;
13883e12c5d1SDavid du Colombier 			u = 1.0;
13893e12c5d1SDavid du Colombier 		} else {
13903e12c5d1SDavid du Colombier 			y = execute(a[1]->nnext);
13913e12c5d1SDavid du Colombier 			u = atan2(getfval(x), getfval(y));
13923e12c5d1SDavid du Colombier 			tempfree(y);
13933e12c5d1SDavid du Colombier 			nextarg = nextarg->nnext;
13943e12c5d1SDavid du Colombier 		}
13953e12c5d1SDavid du Colombier 		break;
13963e12c5d1SDavid du Colombier 	case FSYSTEM:
13973e12c5d1SDavid du Colombier 		fflush(stdout);		/* in case something is buffered already */
13983e12c5d1SDavid du Colombier 		u = (Awkfloat) system((char *)getsval(x)) / 256;   /* 256 is unix-dep */
13993e12c5d1SDavid du Colombier 		break;
14003e12c5d1SDavid du Colombier 	case FRAND:
14013e12c5d1SDavid du Colombier 		/* in principle, rand() returns something in 0..RAND_MAX */
14023e12c5d1SDavid du Colombier 		u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
14033e12c5d1SDavid du Colombier 		break;
14043e12c5d1SDavid du Colombier 	case FSRAND:
14053e12c5d1SDavid du Colombier 		if (x->tval & REC)	/* no argument provided */
14063e12c5d1SDavid du Colombier 			u = time((long *)0);
14073e12c5d1SDavid du Colombier 		else
14083e12c5d1SDavid du Colombier 			u = getfval(x);
14093e12c5d1SDavid du Colombier 		srand((int) u); u = (int) u;
14103e12c5d1SDavid du Colombier 		break;
14113e12c5d1SDavid du Colombier 	case FTOUPPER:
14123e12c5d1SDavid du Colombier 	case FTOLOWER:
14133e12c5d1SDavid du Colombier 		strcpy(buf, getsval(x));
14143e12c5d1SDavid du Colombier 		if (t == FTOUPPER) {
14153e12c5d1SDavid du Colombier 			for (p = buf; *p; p++)
14163e12c5d1SDavid du Colombier 				if (islower(*p))
14173e12c5d1SDavid du Colombier 					*p = toupper(*p);
14183e12c5d1SDavid du Colombier 		} else {
14193e12c5d1SDavid du Colombier 			for (p = buf; *p; p++)
14203e12c5d1SDavid du Colombier 				if (isupper(*p))
14213e12c5d1SDavid du Colombier 					*p = tolower(*p);
14223e12c5d1SDavid du Colombier 		}
14233e12c5d1SDavid du Colombier 		tempfree(x);
14243e12c5d1SDavid du Colombier 		x = gettemp();
14253e12c5d1SDavid du Colombier 		setsval(x, buf);
14263e12c5d1SDavid du Colombier 		return x;
14273e12c5d1SDavid du Colombier 	case FFLUSH:
14283e12c5d1SDavid du Colombier 		if ((fp = openfile(GT, getsval(x))) == NULL)
14293e12c5d1SDavid du Colombier 			u = EOF;
14303e12c5d1SDavid du Colombier 		else
14313e12c5d1SDavid du Colombier 			u = fflush(fp);
14323e12c5d1SDavid du Colombier 		break;
1433*219b2ee8SDavid du Colombier 	case FUTF:
1434*219b2ee8SDavid du Colombier 		wc = (int)getfval(x);
1435*219b2ee8SDavid du Colombier 		mbc[wctomb(mbc, wc)] = 0;
1436*219b2ee8SDavid du Colombier 		tempfree(x);
1437*219b2ee8SDavid du Colombier 		x = gettemp();
1438*219b2ee8SDavid du Colombier 		setsval(x, mbc);
1439*219b2ee8SDavid du Colombier 		return x;
14403e12c5d1SDavid du Colombier 	default:	/* can't happen */
14413e12c5d1SDavid du Colombier 		ERROR "illegal function type %d", t FATAL;
14423e12c5d1SDavid du Colombier 		break;
14433e12c5d1SDavid du Colombier 	}
14443e12c5d1SDavid du Colombier 	tempfree(x);
14453e12c5d1SDavid du Colombier 	x = gettemp();
14463e12c5d1SDavid du Colombier 	setfval(x, u);
14473e12c5d1SDavid du Colombier 	if (nextarg != 0) {
14483e12c5d1SDavid du Colombier 		ERROR "warning: function has too many arguments" WARNING;
14493e12c5d1SDavid du Colombier 		for ( ; nextarg; nextarg = nextarg->nnext)
14503e12c5d1SDavid du Colombier 			execute(nextarg);
14513e12c5d1SDavid du Colombier 	}
14523e12c5d1SDavid du Colombier 	return(x);
14533e12c5d1SDavid du Colombier }
14543e12c5d1SDavid du Colombier 
1455*219b2ee8SDavid du Colombier Cell *printstat(Node **a, int n)	/* print a[0] */
14563e12c5d1SDavid du Colombier {
14573e12c5d1SDavid du Colombier 	register Node *x;
14583e12c5d1SDavid du Colombier 	register Cell *y;
14593e12c5d1SDavid du Colombier 	FILE *fp;
14603e12c5d1SDavid du Colombier 
1461*219b2ee8SDavid du Colombier 	if (a[1] == 0)	/* a[1] is redirection operator, a[2] is file */
14623e12c5d1SDavid du Colombier 		fp = stdout;
14633e12c5d1SDavid du Colombier 	else
14643e12c5d1SDavid du Colombier 		fp = redirect((int)a[1], a[2]);
14653e12c5d1SDavid du Colombier 	for (x = a[0]; x != NULL; x = x->nnext) {
14663e12c5d1SDavid du Colombier 		y = execute(x);
14673e12c5d1SDavid du Colombier 		fputs((char *)getsval(y), fp);
14683e12c5d1SDavid du Colombier 		tempfree(y);
14693e12c5d1SDavid du Colombier 		if (x->nnext == NULL)
14703e12c5d1SDavid du Colombier 			fputs((char *)*ORS, fp);
14713e12c5d1SDavid du Colombier 		else
14723e12c5d1SDavid du Colombier 			fputs((char *)*OFS, fp);
14733e12c5d1SDavid du Colombier 	}
14743e12c5d1SDavid du Colombier 	if (a[1] != 0)
14753e12c5d1SDavid du Colombier 		fflush(fp);
14763e12c5d1SDavid du Colombier 	if (ferror(fp))
14773e12c5d1SDavid du Colombier 		ERROR "write error on %s", filename(fp) FATAL;
14783e12c5d1SDavid du Colombier 	return(true);
14793e12c5d1SDavid du Colombier }
14803e12c5d1SDavid du Colombier 
14813e12c5d1SDavid du Colombier Cell *nullproc(Node **a, int n)
14823e12c5d1SDavid du Colombier {
14833e12c5d1SDavid du Colombier 	n;
14843e12c5d1SDavid du Colombier 	a;
14853e12c5d1SDavid du Colombier 	return 0;
14863e12c5d1SDavid du Colombier }
14873e12c5d1SDavid du Colombier 
14883e12c5d1SDavid du Colombier 
1489*219b2ee8SDavid du Colombier FILE *redirect(int a, Node *b)	/* set up all i/o redirections */
14903e12c5d1SDavid du Colombier {
14913e12c5d1SDavid du Colombier 	FILE *fp;
14923e12c5d1SDavid du Colombier 	Cell *x;
14933e12c5d1SDavid du Colombier 	uchar *fname;
14943e12c5d1SDavid du Colombier 
14953e12c5d1SDavid du Colombier 	x = execute(b);
14963e12c5d1SDavid du Colombier 	fname = getsval(x);
14973e12c5d1SDavid du Colombier 	fp = openfile(a, fname);
14983e12c5d1SDavid du Colombier 	if (fp == NULL)
14993e12c5d1SDavid du Colombier 		ERROR "can't open file %s", fname FATAL;
15003e12c5d1SDavid du Colombier 	tempfree(x);
15013e12c5d1SDavid du Colombier 	return fp;
15023e12c5d1SDavid du Colombier }
15033e12c5d1SDavid du Colombier 
1504*219b2ee8SDavid du Colombier struct files {
1505*219b2ee8SDavid du Colombier 	FILE	*fp;
1506*219b2ee8SDavid du Colombier 	uchar	*fname;
1507*219b2ee8SDavid du Colombier 	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
1508*219b2ee8SDavid du Colombier } files[FOPEN_MAX] ={
1509*219b2ee8SDavid du Colombier 	{ stdin,  "/dev/stdin",  LT },	/* watch out: don't free this! */
1510*219b2ee8SDavid du Colombier 	{ stdout, "/dev/stdout", GT },
1511*219b2ee8SDavid du Colombier 	{ stderr, "/dev/stderr", GT }
1512*219b2ee8SDavid du Colombier };
1513*219b2ee8SDavid du Colombier 
15143e12c5d1SDavid du Colombier FILE *openfile(int a, uchar *s)
15153e12c5d1SDavid du Colombier {
15163e12c5d1SDavid du Colombier 	register int i, m;
15173e12c5d1SDavid du Colombier 	register FILE *fp;
15183e12c5d1SDavid du Colombier 
15193e12c5d1SDavid du Colombier 	if (*s == '\0')
15203e12c5d1SDavid du Colombier 		ERROR "null file name in print or getline" FATAL;
15213e12c5d1SDavid du Colombier 	for (i=0; i < FOPEN_MAX; i++)
15223e12c5d1SDavid du Colombier 		if (files[i].fname && strcmp(s, files[i].fname) == 0)
1523*219b2ee8SDavid du Colombier 			if (a == files[i].mode || a==APPEND && files[i].mode==GT)
15243e12c5d1SDavid du Colombier 				return files[i].fp;
15253e12c5d1SDavid du Colombier 	for (i=0; i < FOPEN_MAX; i++)
15263e12c5d1SDavid du Colombier 		if (files[i].fp == 0)
15273e12c5d1SDavid du Colombier 			break;
15283e12c5d1SDavid du Colombier 	if (i >= FOPEN_MAX)
15293e12c5d1SDavid du Colombier 		ERROR "%s makes too many open files", s FATAL;
15303e12c5d1SDavid du Colombier 	fflush(stdout);	/* force a semblance of order */
15313e12c5d1SDavid du Colombier 	m = a;
15323e12c5d1SDavid du Colombier 	if (a == GT) {
1533*219b2ee8SDavid du Colombier 		fp = fopen(s, "w");
15343e12c5d1SDavid du Colombier 	} else if (a == APPEND) {
1535*219b2ee8SDavid du Colombier 		fp = fopen(s, "a");
15363e12c5d1SDavid du Colombier 		m = GT;	/* so can mix > and >> */
15373e12c5d1SDavid du Colombier 	} else if (a == '|') {	/* output pipe */
1538*219b2ee8SDavid du Colombier 		fp = popen(s, "w");
15393e12c5d1SDavid du Colombier 	} else if (a == LE) {	/* input pipe */
1540*219b2ee8SDavid du Colombier 		fp = popen(s, "r");
15413e12c5d1SDavid du Colombier 	} else if (a == LT) {	/* getline <file */
1542*219b2ee8SDavid du Colombier 		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
15433e12c5d1SDavid du Colombier 	} else	/* can't happen */
15443e12c5d1SDavid du Colombier 		ERROR "illegal redirection %d", a FATAL;
15453e12c5d1SDavid du Colombier 	if (fp != NULL) {
15463e12c5d1SDavid du Colombier 		files[i].fname = tostring(s);
15473e12c5d1SDavid du Colombier 		files[i].fp = fp;
15483e12c5d1SDavid du Colombier 		files[i].mode = m;
15493e12c5d1SDavid du Colombier 	}
15503e12c5d1SDavid du Colombier 	return fp;
15513e12c5d1SDavid du Colombier }
15523e12c5d1SDavid du Colombier 
15533e12c5d1SDavid du Colombier uchar *filename(FILE *fp)
15543e12c5d1SDavid du Colombier {
15553e12c5d1SDavid du Colombier 	int i;
15563e12c5d1SDavid du Colombier 
15573e12c5d1SDavid du Colombier 	for (i = 0; i < FOPEN_MAX; i++)
15583e12c5d1SDavid du Colombier 		if (fp == files[i].fp)
15593e12c5d1SDavid du Colombier 			return files[i].fname;
1560*219b2ee8SDavid du Colombier 	return "???";
15613e12c5d1SDavid du Colombier }
15623e12c5d1SDavid du Colombier 
15633e12c5d1SDavid du Colombier Cell *closefile(Node **a, int n)
15643e12c5d1SDavid du Colombier {
15653e12c5d1SDavid du Colombier 	register Cell *x;
15663e12c5d1SDavid du Colombier 	int i, stat;
15673e12c5d1SDavid du Colombier 
15683e12c5d1SDavid du Colombier 	n;
15693e12c5d1SDavid du Colombier 	x = execute(a[0]);
15703e12c5d1SDavid du Colombier 	getsval(x);
15713e12c5d1SDavid du Colombier 	for (i = 0; i < FOPEN_MAX; i++)
15723e12c5d1SDavid du Colombier 		if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
15733e12c5d1SDavid du Colombier 			if (ferror(files[i].fp))
15743e12c5d1SDavid du Colombier 				ERROR "i/o error occurred on %s", files[i].fname WARNING;
15753e12c5d1SDavid du Colombier 			if (files[i].mode == '|' || files[i].mode == LE)
15763e12c5d1SDavid du Colombier 				stat = pclose(files[i].fp);
15773e12c5d1SDavid du Colombier 			else
15783e12c5d1SDavid du Colombier 				stat = fclose(files[i].fp);
15793e12c5d1SDavid du Colombier 			if (stat == EOF)
15803e12c5d1SDavid du Colombier 				ERROR "i/o error occurred closing %s", files[i].fname WARNING;
1581*219b2ee8SDavid du Colombier 			if (i > 2)	/* don't do /dev/std... */
15823e12c5d1SDavid du Colombier 				xfree(files[i].fname);
15833e12c5d1SDavid du Colombier 			files[i].fname = NULL;	/* watch out for ref thru this */
15843e12c5d1SDavid du Colombier 			files[i].fp = NULL;
15853e12c5d1SDavid du Colombier 		}
15863e12c5d1SDavid du Colombier 	tempfree(x);
15873e12c5d1SDavid du Colombier 	return(true);
15883e12c5d1SDavid du Colombier }
15893e12c5d1SDavid du Colombier 
15903e12c5d1SDavid du Colombier void closeall(void)
15913e12c5d1SDavid du Colombier {
15923e12c5d1SDavid du Colombier 	int i, stat;
15933e12c5d1SDavid du Colombier 
15943e12c5d1SDavid du Colombier 	for (i = 0; i < FOPEN_MAX; i++)
15953e12c5d1SDavid du Colombier 		if (files[i].fp) {
15963e12c5d1SDavid du Colombier 			if (ferror(files[i].fp))
15973e12c5d1SDavid du Colombier 				ERROR "i/o error occurred on %s", files[i].fname WARNING;
15983e12c5d1SDavid du Colombier 			if (files[i].mode == '|' || files[i].mode == LE)
15993e12c5d1SDavid du Colombier 				stat = pclose(files[i].fp);
16003e12c5d1SDavid du Colombier 			else
16013e12c5d1SDavid du Colombier 				stat = fclose(files[i].fp);
16023e12c5d1SDavid du Colombier 			if (stat == EOF)
16033e12c5d1SDavid du Colombier 				ERROR "i/o error occurred while closing %s", files[i].fname WARNING;
16043e12c5d1SDavid du Colombier 		}
16053e12c5d1SDavid du Colombier }
16063e12c5d1SDavid du Colombier 
16073e12c5d1SDavid du Colombier #define	SUBSIZE	(20 * RECSIZE)
16083e12c5d1SDavid du Colombier 
1609*219b2ee8SDavid du Colombier Cell *sub(Node **a, int nnn)	/* substitute command */
16103e12c5d1SDavid du Colombier {
16113e12c5d1SDavid du Colombier 	register uchar *sptr, *pb, *q;
16123e12c5d1SDavid du Colombier 	register Cell *x, *y, *result;
16133e12c5d1SDavid du Colombier 	uchar buf[SUBSIZE], *t;
16143e12c5d1SDavid du Colombier 	void *p;
16153e12c5d1SDavid du Colombier 
16163e12c5d1SDavid du Colombier 	x = execute(a[3]);	/* target string */
16173e12c5d1SDavid du Colombier 	t = getsval(x);
1618*219b2ee8SDavid du Colombier 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
16193e12c5d1SDavid du Colombier 		p = (void *) a[1];	/* regular expression */
16203e12c5d1SDavid du Colombier 	else {
16213e12c5d1SDavid du Colombier 		y = execute(a[1]);
16223e12c5d1SDavid du Colombier 		p = compre(getsval(y));
16233e12c5d1SDavid du Colombier 		tempfree(y);
16243e12c5d1SDavid du Colombier 	}
16253e12c5d1SDavid du Colombier 	y = execute(a[2]);	/* replacement string */
16263e12c5d1SDavid du Colombier 	result = false;
16273e12c5d1SDavid du Colombier 	if (pmatch(p, t, t)) {
16283e12c5d1SDavid du Colombier 		pb = buf;
16293e12c5d1SDavid du Colombier 		sptr = t;
16303e12c5d1SDavid du Colombier 		while (sptr < patbeg)
16313e12c5d1SDavid du Colombier 			*pb++ = *sptr++;
16323e12c5d1SDavid du Colombier 		sptr = getsval(y);
16333e12c5d1SDavid du Colombier 		while (*sptr != 0 && pb < buf + SUBSIZE - 1)
16343e12c5d1SDavid du Colombier 			if (*sptr == '\\' && *(sptr+1) == '&') {
16353e12c5d1SDavid du Colombier 				sptr++;		/* skip \, */
16363e12c5d1SDavid du Colombier 				*pb++ = *sptr++; /* add & */
16373e12c5d1SDavid du Colombier 			} else if (*sptr == '&') {
16383e12c5d1SDavid du Colombier 				sptr++;
16393e12c5d1SDavid du Colombier 				for (q = patbeg; q < patbeg+patlen; )
16403e12c5d1SDavid du Colombier 					*pb++ = *q++;
16413e12c5d1SDavid du Colombier 			} else
16423e12c5d1SDavid du Colombier 				*pb++ = *sptr++;
16433e12c5d1SDavid du Colombier 		*pb = '\0';
16443e12c5d1SDavid du Colombier 		if (pb >= buf + SUBSIZE)
1645*219b2ee8SDavid du Colombier 			ERROR "sub() result %.30s too big", buf FATAL;
16463e12c5d1SDavid du Colombier 		sptr = patbeg + patlen;
16473e12c5d1SDavid du Colombier 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1)))
16483e12c5d1SDavid du Colombier 			while (*pb++ = *sptr++)
16493e12c5d1SDavid du Colombier 				;
16503e12c5d1SDavid du Colombier 		if (pb >= buf + SUBSIZE)
1651*219b2ee8SDavid du Colombier 			ERROR "sub() result %.30s too big", buf FATAL;
16523e12c5d1SDavid du Colombier 		setsval(x, buf);
16533e12c5d1SDavid du Colombier 		result = true;;
16543e12c5d1SDavid du Colombier 	}
16553e12c5d1SDavid du Colombier 	tempfree(x);
16563e12c5d1SDavid du Colombier 	tempfree(y);
16573e12c5d1SDavid du Colombier 	return result;
16583e12c5d1SDavid du Colombier }
16593e12c5d1SDavid du Colombier 
1660*219b2ee8SDavid du Colombier Cell *gsub(Node **a, int nnn)	/* global substitute */
16613e12c5d1SDavid du Colombier {
16623e12c5d1SDavid du Colombier 	register Cell *x, *y;
16633e12c5d1SDavid du Colombier 	register uchar *rptr, *sptr, *t, *pb, *c;
16643e12c5d1SDavid du Colombier 	uchar buf[SUBSIZE];
16653e12c5d1SDavid du Colombier 	register void *p;
16663e12c5d1SDavid du Colombier 	int mflag, num;
16673e12c5d1SDavid du Colombier 
16683e12c5d1SDavid du Colombier 	mflag = 0;	/* if mflag == 0, can replace empty string */
16693e12c5d1SDavid du Colombier 	num = 0;
16703e12c5d1SDavid du Colombier 	x = execute(a[3]);	/* target string */
16713e12c5d1SDavid du Colombier 	c = t = getsval(x);
1672*219b2ee8SDavid du Colombier 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
16733e12c5d1SDavid du Colombier 		p = (void *) a[1];	/* regular expression */
16743e12c5d1SDavid du Colombier 	else {
16753e12c5d1SDavid du Colombier 		y = execute(a[1]);
16763e12c5d1SDavid du Colombier 		p = compre(getsval(y));
16773e12c5d1SDavid du Colombier 		tempfree(y);
16783e12c5d1SDavid du Colombier 	}
16793e12c5d1SDavid du Colombier 	y = execute(a[2]);	/* replacement string */
16803e12c5d1SDavid du Colombier 	if (pmatch(p, t, c)) {
16813e12c5d1SDavid du Colombier 		pb = buf;
16823e12c5d1SDavid du Colombier 		rptr = getsval(y);
16833e12c5d1SDavid du Colombier 		do {
16843e12c5d1SDavid du Colombier 			/*
16853e12c5d1SDavid du Colombier 			uchar *p;
16863e12c5d1SDavid du Colombier 			int i;
16873e12c5d1SDavid du Colombier 			printf("target string: %s, *patbeg = %o, patlen = %d\n",
16883e12c5d1SDavid du Colombier 				t, *patbeg, patlen);
16893e12c5d1SDavid du Colombier 			printf("	match found: ");
16903e12c5d1SDavid du Colombier 			p=patbeg;
16913e12c5d1SDavid du Colombier 			for (i=0; i<patlen; i++)
16923e12c5d1SDavid du Colombier 				printf("%c", *p++);
16933e12c5d1SDavid du Colombier 			printf("\n");
16943e12c5d1SDavid du Colombier 			*/
16953e12c5d1SDavid du Colombier 			if (patlen == 0 && *patbeg != 0) {	/* matched empty string */
16963e12c5d1SDavid du Colombier 				if (mflag == 0) {	/* can replace empty */
16973e12c5d1SDavid du Colombier 					num++;
16983e12c5d1SDavid du Colombier 					sptr = rptr;
16993e12c5d1SDavid du Colombier 					while (*sptr != 0 && pb < buf + SUBSIZE-1)
17003e12c5d1SDavid du Colombier 						if (*sptr == '\\' && *(sptr+1) == '&') {
17013e12c5d1SDavid du Colombier 							sptr++;
17023e12c5d1SDavid du Colombier 							*pb++ = *sptr++;
17033e12c5d1SDavid du Colombier 						} else if (*sptr == '&') {
17043e12c5d1SDavid du Colombier 							uchar *q;
17053e12c5d1SDavid du Colombier 							sptr++;
17063e12c5d1SDavid du Colombier 							for (q = patbeg; q < patbeg+patlen; )
17073e12c5d1SDavid du Colombier 								*pb++ = *q++;
17083e12c5d1SDavid du Colombier 						} else
17093e12c5d1SDavid du Colombier 							*pb++ = *sptr++;
17103e12c5d1SDavid du Colombier 				}
17113e12c5d1SDavid du Colombier 				if (*c == 0)	/* at end */
17123e12c5d1SDavid du Colombier 					goto done;
17133e12c5d1SDavid du Colombier 				*pb++ = *c++;
17143e12c5d1SDavid du Colombier 				if (pb >= buf + SUBSIZE-1)
1715*219b2ee8SDavid du Colombier 					ERROR "gsub() result %.30s too big", buf FATAL;
17163e12c5d1SDavid du Colombier 				mflag = 0;
17173e12c5d1SDavid du Colombier 			}
17183e12c5d1SDavid du Colombier 			else {	/* matched nonempty string */
17193e12c5d1SDavid du Colombier 				num++;
17203e12c5d1SDavid du Colombier 				sptr = c;
17213e12c5d1SDavid du Colombier 				while (sptr < patbeg && pb < buf + SUBSIZE-1)
17223e12c5d1SDavid du Colombier 					*pb++ = *sptr++;
17233e12c5d1SDavid du Colombier 				sptr = rptr;
17243e12c5d1SDavid du Colombier 				while (*sptr != 0 && pb < buf + SUBSIZE-1)
17253e12c5d1SDavid du Colombier 					if (*sptr == '\\' && *(sptr+1) == '&') {
17263e12c5d1SDavid du Colombier 						sptr++;
17273e12c5d1SDavid du Colombier 						*pb++ = *sptr++;
17283e12c5d1SDavid du Colombier 					} else if (*sptr == '&') {
17293e12c5d1SDavid du Colombier 						uchar *q;
17303e12c5d1SDavid du Colombier 						sptr++;
17313e12c5d1SDavid du Colombier 						for (q = patbeg; q < patbeg+patlen; )
17323e12c5d1SDavid du Colombier 							*pb++ = *q++;
17333e12c5d1SDavid du Colombier 					} else
17343e12c5d1SDavid du Colombier 						*pb++ = *sptr++;
17353e12c5d1SDavid du Colombier 				c = patbeg + patlen;
17363e12c5d1SDavid du Colombier 				if ((c[-1] == 0) || (*c == 0))
17373e12c5d1SDavid du Colombier 					goto done;
17383e12c5d1SDavid du Colombier 				if (pb >= buf + SUBSIZE-1)
1739*219b2ee8SDavid du Colombier 					ERROR "gsub() result %.30s too big", buf FATAL;
17403e12c5d1SDavid du Colombier 				mflag = 1;
17413e12c5d1SDavid du Colombier 			}
17423e12c5d1SDavid du Colombier 		} while (pmatch(p, t, c));
17433e12c5d1SDavid du Colombier 		sptr = c;
17443e12c5d1SDavid du Colombier 		while (*pb++ = *sptr++)
17453e12c5d1SDavid du Colombier 			;
17463e12c5d1SDavid du Colombier 	done:	if (pb >= buf + SUBSIZE-1)
1747*219b2ee8SDavid du Colombier 			ERROR "gsub() result %.30s too big", buf FATAL;
17483e12c5d1SDavid du Colombier 		*pb = '\0';
17493e12c5d1SDavid du Colombier 		setsval(x, buf);
17503e12c5d1SDavid du Colombier 	}
17513e12c5d1SDavid du Colombier 	tempfree(x);
17523e12c5d1SDavid du Colombier 	tempfree(y);
17533e12c5d1SDavid du Colombier 	x = gettemp();
17543e12c5d1SDavid du Colombier 	x->tval = NUM;
17553e12c5d1SDavid du Colombier 	x->fval = num;
17563e12c5d1SDavid du Colombier 	return(x);
17573e12c5d1SDavid du Colombier }
1758