xref: /minix3/external/historical/nawk/dist/run.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
15ea9e707SThomas Veerman /****************************************************************
25ea9e707SThomas Veerman Copyright (C) Lucent Technologies 1997
35ea9e707SThomas Veerman All Rights Reserved
45ea9e707SThomas Veerman 
55ea9e707SThomas Veerman Permission to use, copy, modify, and distribute this software and
65ea9e707SThomas Veerman its documentation for any purpose and without fee is hereby
75ea9e707SThomas Veerman granted, provided that the above copyright notice appear in all
85ea9e707SThomas Veerman copies and that both that the copyright notice and this
95ea9e707SThomas Veerman permission notice and warranty disclaimer appear in supporting
105ea9e707SThomas Veerman documentation, and that the name Lucent Technologies or any of
115ea9e707SThomas Veerman its entities not be used in advertising or publicity pertaining
125ea9e707SThomas Veerman to distribution of the software without specific, written prior
135ea9e707SThomas Veerman permission.
145ea9e707SThomas Veerman 
155ea9e707SThomas Veerman LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
165ea9e707SThomas Veerman INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
175ea9e707SThomas Veerman IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
185ea9e707SThomas Veerman SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
195ea9e707SThomas Veerman WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
205ea9e707SThomas Veerman IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
215ea9e707SThomas Veerman ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
225ea9e707SThomas Veerman THIS SOFTWARE.
235ea9e707SThomas Veerman ****************************************************************/
245ea9e707SThomas Veerman 
255ea9e707SThomas Veerman #if HAVE_NBTOOL_CONFIG_H
265ea9e707SThomas Veerman #include "nbtool_config.h"
275ea9e707SThomas Veerman #endif
285ea9e707SThomas Veerman 
295ea9e707SThomas Veerman #define DEBUG
305ea9e707SThomas Veerman #include <stdio.h>
315ea9e707SThomas Veerman #include <ctype.h>
325ea9e707SThomas Veerman #include <wchar.h>
335ea9e707SThomas Veerman #include <wctype.h>
345ea9e707SThomas Veerman #include <setjmp.h>
355ea9e707SThomas Veerman #include <limits.h>
365ea9e707SThomas Veerman #include <math.h>
375ea9e707SThomas Veerman #include <string.h>
385ea9e707SThomas Veerman #include <stdlib.h>
395ea9e707SThomas Veerman #include <time.h>
405ea9e707SThomas Veerman #include <stdint.h>
415ea9e707SThomas Veerman #include "awk.h"
425ea9e707SThomas Veerman #include "awkgram.h"
435ea9e707SThomas Veerman 
445ea9e707SThomas Veerman #define tempfree(x)	do { if (istemp(x)) tfree(x); } while (/*CONSTCOND*/0)
455ea9e707SThomas Veerman 
465ea9e707SThomas Veerman void stdinit(void);
475ea9e707SThomas Veerman 
485ea9e707SThomas Veerman /*
495ea9e707SThomas Veerman #undef tempfree
505ea9e707SThomas Veerman 
515ea9e707SThomas Veerman void tempfree(Cell *p) {
525ea9e707SThomas Veerman 	if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
535ea9e707SThomas Veerman 		WARNING("bad csub %d in Cell %d %s",
545ea9e707SThomas Veerman 			p->csub, p->ctype, p->sval);
555ea9e707SThomas Veerman 	}
565ea9e707SThomas Veerman 	if (istemp(p))
575ea9e707SThomas Veerman 		tfree(p);
585ea9e707SThomas Veerman }
595ea9e707SThomas Veerman */
605ea9e707SThomas Veerman 
615ea9e707SThomas Veerman /* do we really need these? */
625ea9e707SThomas Veerman /* #ifdef _NFILE */
635ea9e707SThomas Veerman /* #ifndef FOPEN_MAX */
645ea9e707SThomas Veerman /* #define FOPEN_MAX _NFILE */
655ea9e707SThomas Veerman /* #endif */
665ea9e707SThomas Veerman /* #endif */
675ea9e707SThomas Veerman /*  */
685ea9e707SThomas Veerman /* #ifndef	FOPEN_MAX */
695ea9e707SThomas Veerman /* #define	FOPEN_MAX	40 */	/* max number of open files */
705ea9e707SThomas Veerman /* #endif */
715ea9e707SThomas Veerman /*  */
725ea9e707SThomas Veerman /* #ifndef RAND_MAX */
735ea9e707SThomas Veerman /* #define RAND_MAX	32767 */	/* all that ansi guarantees */
745ea9e707SThomas Veerman /* #endif */
755ea9e707SThomas Veerman 
765ea9e707SThomas Veerman jmp_buf env;
775ea9e707SThomas Veerman extern	int	pairstack[];
785ea9e707SThomas Veerman extern	unsigned int srand_seed;
795ea9e707SThomas Veerman 
805ea9e707SThomas Veerman Node	*winner = NULL;	/* root of parse tree */
815ea9e707SThomas Veerman Cell	*tmps;		/* free temporary cells for execution */
825ea9e707SThomas Veerman 
835ea9e707SThomas Veerman static Cell	truecell	={ OBOOL, BTRUE, 0, 0, 1.0, NUM, NULL };
845ea9e707SThomas Veerman Cell	*True	= &truecell;
855ea9e707SThomas Veerman static Cell	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM, NULL };
865ea9e707SThomas Veerman Cell	*False	= &falsecell;
875ea9e707SThomas Veerman static Cell	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM, NULL };
885ea9e707SThomas Veerman Cell	*jbreak	= &breakcell;
895ea9e707SThomas Veerman static Cell	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM, NULL };
905ea9e707SThomas Veerman Cell	*jcont	= &contcell;
915ea9e707SThomas Veerman static Cell	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM, NULL };
925ea9e707SThomas Veerman Cell	*jnext	= &nextcell;
935ea9e707SThomas Veerman static Cell	nextfilecell	={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM, NULL};
945ea9e707SThomas Veerman Cell	*jnextfile	= &nextfilecell;
955ea9e707SThomas Veerman static Cell	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM, NULL };
965ea9e707SThomas Veerman Cell	*jexit	= &exitcell;
975ea9e707SThomas Veerman static Cell	retcell		={ OJUMP, JRET, 0, 0, 0.0, NUM, NULL };
985ea9e707SThomas Veerman Cell	*jret	= &retcell;
995ea9e707SThomas Veerman static Cell	tempcell	={ OCELL, CTEMP, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL };
1005ea9e707SThomas Veerman 
1015ea9e707SThomas Veerman Node	*curnode = NULL;	/* the node being executed, for debugging */
1025ea9e707SThomas Veerman 
1035ea9e707SThomas Veerman /* buffer memory management */
adjbuf(uschar ** pbuf,int * psiz,int minlen,int quantum,uschar ** pbptr,const char * whatrtn)1045ea9e707SThomas Veerman int adjbuf(uschar **pbuf, int *psiz, int minlen, int quantum, uschar **pbptr,
1055ea9e707SThomas Veerman 	const char *whatrtn)
1065ea9e707SThomas Veerman /* pbuf:    address of pointer to buffer being managed
1075ea9e707SThomas Veerman  * psiz:    address of buffer size variable
1085ea9e707SThomas Veerman  * minlen:  minimum length of buffer needed
1095ea9e707SThomas Veerman  * quantum: buffer size quantum
1105ea9e707SThomas Veerman  * pbptr:   address of movable pointer into buffer, or 0 if none
1115ea9e707SThomas Veerman  * whatrtn: name of the calling routine if failure should cause fatal error
1125ea9e707SThomas Veerman  *
1135ea9e707SThomas Veerman  * return   0 for realloc failure, !=0 for success
1145ea9e707SThomas Veerman  */
1155ea9e707SThomas Veerman {
1165ea9e707SThomas Veerman 	if (minlen > *psiz) {
1175ea9e707SThomas Veerman 		char *tbuf;
1185ea9e707SThomas Veerman 		int rminlen = quantum ? minlen % quantum : 0;
1195ea9e707SThomas Veerman 		int boff = pbptr ? *pbptr - *pbuf : 0;
1205ea9e707SThomas Veerman 		/* round up to next multiple of quantum */
1215ea9e707SThomas Veerman 		if (rminlen)
1225ea9e707SThomas Veerman 			minlen += quantum - rminlen;
1235ea9e707SThomas Veerman 		tbuf = realloc(*pbuf, minlen);
1245ea9e707SThomas Veerman 		dprintf( ("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, *pbuf, tbuf) );
1255ea9e707SThomas Veerman 		if (tbuf == NULL) {
1265ea9e707SThomas Veerman 			if (whatrtn)
1275ea9e707SThomas Veerman 				FATAL("out of memory in %s", whatrtn);
1285ea9e707SThomas Veerman 			return 0;
1295ea9e707SThomas Veerman 		}
1305ea9e707SThomas Veerman 		*pbuf = tbuf;
1315ea9e707SThomas Veerman 		*psiz = minlen;
1325ea9e707SThomas Veerman 		if (pbptr)
1335ea9e707SThomas Veerman 			*pbptr = tbuf + boff;
1345ea9e707SThomas Veerman 	}
1355ea9e707SThomas Veerman 	return 1;
1365ea9e707SThomas Veerman }
1375ea9e707SThomas Veerman 
run(Node * a)1385ea9e707SThomas Veerman void run(Node *a)	/* execution of parse tree starts here */
1395ea9e707SThomas Veerman {
1405ea9e707SThomas Veerman 	stdinit();
1415ea9e707SThomas Veerman 	execute(a);
1425ea9e707SThomas Veerman 	closeall();
1435ea9e707SThomas Veerman }
1445ea9e707SThomas Veerman 
execute(Node * u)1455ea9e707SThomas Veerman Cell *execute(Node *u)	/* execute a node of the parse tree */
1465ea9e707SThomas Veerman {
1475ea9e707SThomas Veerman 	Cell *(*proc)(Node **, int);
1485ea9e707SThomas Veerman 	Cell *x;
1495ea9e707SThomas Veerman 	Node *a;
1505ea9e707SThomas Veerman 
1515ea9e707SThomas Veerman 	if (u == NULL)
1525ea9e707SThomas Veerman 		return(True);
1535ea9e707SThomas Veerman 	for (a = u; ; a = a->nnext) {
1545ea9e707SThomas Veerman 		curnode = a;
1555ea9e707SThomas Veerman 		if (isvalue(a)) {
1565ea9e707SThomas Veerman 			x = (Cell *) (a->narg[0]);
1575ea9e707SThomas Veerman 			if (isfld(x) && !donefld)
1585ea9e707SThomas Veerman 				fldbld();
1595ea9e707SThomas Veerman 			else if (isrec(x) && !donerec)
1605ea9e707SThomas Veerman 				recbld();
1615ea9e707SThomas Veerman 			return(x);
1625ea9e707SThomas Veerman 		}
1635ea9e707SThomas Veerman 		if (notlegal(a->nobj))	/* probably a Cell* but too risky to print */
1645ea9e707SThomas Veerman 			FATAL("illegal statement");
1655ea9e707SThomas Veerman 		proc = proctab[a->nobj-FIRSTTOKEN];
1665ea9e707SThomas Veerman 		x = (*proc)(a->narg, a->nobj);
1675ea9e707SThomas Veerman 		if (isfld(x) && !donefld)
1685ea9e707SThomas Veerman 			fldbld();
1695ea9e707SThomas Veerman 		else if (isrec(x) && !donerec)
1705ea9e707SThomas Veerman 			recbld();
1715ea9e707SThomas Veerman 		if (isexpr(a))
1725ea9e707SThomas Veerman 			return(x);
1735ea9e707SThomas Veerman 		if (isjump(x))
1745ea9e707SThomas Veerman 			return(x);
1755ea9e707SThomas Veerman 		if (a->nnext == NULL)
1765ea9e707SThomas Veerman 			return(x);
1775ea9e707SThomas Veerman 		tempfree(x);
1785ea9e707SThomas Veerman 	}
1795ea9e707SThomas Veerman }
1805ea9e707SThomas Veerman 
1815ea9e707SThomas Veerman 
program(Node ** a,int n)1825ea9e707SThomas Veerman Cell *program(Node **a, int n)	/* execute an awk program */
1835ea9e707SThomas Veerman {				/* a[0] = BEGIN, a[1] = body, a[2] = END */
1845ea9e707SThomas Veerman 	Cell *x;
1855ea9e707SThomas Veerman 
1865ea9e707SThomas Veerman 	if (setjmp(env) != 0)
1875ea9e707SThomas Veerman 		goto ex;
1885ea9e707SThomas Veerman 	if (a[0]) {		/* BEGIN */
1895ea9e707SThomas Veerman 		x = execute(a[0]);
1905ea9e707SThomas Veerman 		if (isexit(x))
1915ea9e707SThomas Veerman 			return(True);
1925ea9e707SThomas Veerman 		if (isjump(x))
1935ea9e707SThomas Veerman 			FATAL("illegal break, continue, next or nextfile from BEGIN");
1945ea9e707SThomas Veerman 		tempfree(x);
1955ea9e707SThomas Veerman 	}
1965ea9e707SThomas Veerman 	if (a[1] || a[2])
1975ea9e707SThomas Veerman 		while (getrec(&record, &recsize, 1) > 0) {
1985ea9e707SThomas Veerman 			x = execute(a[1]);
1995ea9e707SThomas Veerman 			if (isexit(x))
2005ea9e707SThomas Veerman 				break;
2015ea9e707SThomas Veerman 			tempfree(x);
2025ea9e707SThomas Veerman 		}
2035ea9e707SThomas Veerman   ex:
2045ea9e707SThomas Veerman 	if (setjmp(env) != 0)	/* handles exit within END */
2055ea9e707SThomas Veerman 		goto ex1;
2065ea9e707SThomas Veerman 	if (a[2]) {		/* END */
2075ea9e707SThomas Veerman 		x = execute(a[2]);
2085ea9e707SThomas Veerman 		if (isbreak(x) || isnext(x) || iscont(x))
2095ea9e707SThomas Veerman 			FATAL("illegal break, continue, next or nextfile from END");
2105ea9e707SThomas Veerman 		tempfree(x);
2115ea9e707SThomas Veerman 	}
2125ea9e707SThomas Veerman   ex1:
2135ea9e707SThomas Veerman 	return(True);
2145ea9e707SThomas Veerman }
2155ea9e707SThomas Veerman 
2165ea9e707SThomas Veerman struct Frame {	/* stack frame for awk function calls */
2175ea9e707SThomas Veerman 	int nargs;	/* number of arguments in this call */
2185ea9e707SThomas Veerman 	Cell *fcncell;	/* pointer to Cell for function */
2195ea9e707SThomas Veerman 	Cell **args;	/* pointer to array of arguments after execute */
2205ea9e707SThomas Veerman 	Cell *retval;	/* return value */
2215ea9e707SThomas Veerman };
2225ea9e707SThomas Veerman 
2235ea9e707SThomas Veerman #define	NARGS	50	/* max args in a call */
2245ea9e707SThomas Veerman 
2255ea9e707SThomas Veerman struct Frame *frame = NULL;	/* base of stack frames; dynamically allocated */
2265ea9e707SThomas Veerman int	nframe = 0;		/* number of frames allocated */
2275ea9e707SThomas Veerman struct Frame *frp = NULL;	/* frame pointer. bottom level unused */
2285ea9e707SThomas Veerman 
call(Node ** a,int n)2295ea9e707SThomas Veerman Cell *call(Node **a, int n)	/* function call.  very kludgy and fragile */
2305ea9e707SThomas Veerman {
2315ea9e707SThomas Veerman 	static const Cell newcopycell = { OCELL, CCOPY, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL };
2325ea9e707SThomas Veerman 	int i, ncall, ndef;
2335ea9e707SThomas Veerman 	int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */
2345ea9e707SThomas Veerman 	Node *x;
2355ea9e707SThomas Veerman 	Cell *args[NARGS], *oargs[NARGS];	/* BUG: fixed size arrays */
2365ea9e707SThomas Veerman 	Cell *y, *z, *fcn;
2375ea9e707SThomas Veerman 	char *s;
2385ea9e707SThomas Veerman 
2395ea9e707SThomas Veerman 	fcn = execute(a[0]);	/* the function itself */
2405ea9e707SThomas Veerman 	s = fcn->nval;
2415ea9e707SThomas Veerman 	if (!isfcn(fcn))
2425ea9e707SThomas Veerman 		FATAL("calling undefined function %s", s);
2435ea9e707SThomas Veerman 	if (frame == NULL) {
2445ea9e707SThomas Veerman 		frp = frame = calloc(nframe += 100, sizeof(*frp));
2455ea9e707SThomas Veerman 		if (frame == NULL)
2465ea9e707SThomas Veerman 			FATAL("out of space for stack frames calling %s", s);
2475ea9e707SThomas Veerman 	}
2485ea9e707SThomas Veerman 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)	/* args in call */
2495ea9e707SThomas Veerman 		ncall++;
2505ea9e707SThomas Veerman 	ndef = (int) fcn->fval;			/* args in defn */
2515ea9e707SThomas Veerman 	   dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (frp-frame)) );
2525ea9e707SThomas Veerman 	if (ncall > ndef)
2535ea9e707SThomas Veerman 		WARNING("function %s called with %d args, uses only %d",
2545ea9e707SThomas Veerman 			s, ncall, ndef);
2555ea9e707SThomas Veerman 	if (ncall + ndef > NARGS)
2565ea9e707SThomas Veerman 		FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
2575ea9e707SThomas Veerman 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {	/* get call args */
2585ea9e707SThomas Veerman 		   dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (frp-frame)) );
2595ea9e707SThomas Veerman 		y = execute(x);
2605ea9e707SThomas Veerman 		oargs[i] = y;
2615ea9e707SThomas Veerman 		   dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
2625ea9e707SThomas Veerman 			   i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval) );
2635ea9e707SThomas Veerman 		if (isfcn(y))
2645ea9e707SThomas Veerman 			FATAL("can't use function %s as argument in %s", y->nval, s);
2655ea9e707SThomas Veerman 		if (isarr(y))
2665ea9e707SThomas Veerman 			args[i] = y;	/* arrays by ref */
2675ea9e707SThomas Veerman 		else
2685ea9e707SThomas Veerman 			args[i] = copycell(y);
2695ea9e707SThomas Veerman 		tempfree(y);
2705ea9e707SThomas Veerman 	}
2715ea9e707SThomas Veerman 	for ( ; i < ndef; i++) {	/* add null args for ones not provided */
2725ea9e707SThomas Veerman 		args[i] = gettemp();
2735ea9e707SThomas Veerman 		*args[i] = newcopycell;
2745ea9e707SThomas Veerman 	}
2755ea9e707SThomas Veerman 	frp++;	/* now ok to up frame */
2765ea9e707SThomas Veerman 	if (frp >= frame + nframe) {
2775ea9e707SThomas Veerman 		int dfp = frp - frame;	/* old index */
2785ea9e707SThomas Veerman 		frame = realloc(frame, (nframe += 100) * sizeof(*frame));
2795ea9e707SThomas Veerman 		if (frame == NULL)
2805ea9e707SThomas Veerman 			FATAL("out of space for stack frames in %s", s);
2815ea9e707SThomas Veerman 		frp = frame + dfp;
2825ea9e707SThomas Veerman 	}
2835ea9e707SThomas Veerman 	frp->fcncell = fcn;
2845ea9e707SThomas Veerman 	frp->args = args;
2855ea9e707SThomas Veerman 	frp->nargs = ndef;	/* number defined with (excess are locals) */
2865ea9e707SThomas Veerman 	frp->retval = gettemp();
2875ea9e707SThomas Veerman 
2885ea9e707SThomas Veerman 	   dprintf( ("start exec of %s, fp=%d\n", s, (int) (frp-frame)) );
2895ea9e707SThomas Veerman 	y = execute((Node *)(fcn->sval));	/* execute body */
2905ea9e707SThomas Veerman 	   dprintf( ("finished exec of %s, fp=%d\n", s, (int) (frp-frame)) );
2915ea9e707SThomas Veerman 
2925ea9e707SThomas Veerman 	for (i = 0; i < ndef; i++) {
2935ea9e707SThomas Veerman 		Cell *t = frp->args[i];
2945ea9e707SThomas Veerman 		if (isarr(t)) {
2955ea9e707SThomas Veerman 			if (t->csub == CCOPY) {
2965ea9e707SThomas Veerman 				if (i >= ncall) {
2975ea9e707SThomas Veerman 					freesymtab(t);
2985ea9e707SThomas Veerman 					t->csub = CTEMP;
2995ea9e707SThomas Veerman 					tempfree(t);
3005ea9e707SThomas Veerman 				} else {
3015ea9e707SThomas Veerman 					oargs[i]->tval = t->tval;
3025ea9e707SThomas Veerman 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
3035ea9e707SThomas Veerman 					oargs[i]->sval = t->sval;
3045ea9e707SThomas Veerman 					tempfree(t);
3055ea9e707SThomas Veerman 				}
3065ea9e707SThomas Veerman 			}
3075ea9e707SThomas Veerman 		} else if (t != y) {	/* kludge to prevent freeing twice */
3085ea9e707SThomas Veerman 			t->csub = CTEMP;
3095ea9e707SThomas Veerman 			tempfree(t);
3105ea9e707SThomas Veerman 		} else if (t == y && t->csub == CCOPY) {
3115ea9e707SThomas Veerman 			t->csub = CTEMP;
3125ea9e707SThomas Veerman 			tempfree(t);
3135ea9e707SThomas Veerman 			freed = 1;
3145ea9e707SThomas Veerman 		}
3155ea9e707SThomas Veerman 	}
3165ea9e707SThomas Veerman 	tempfree(fcn);
3175ea9e707SThomas Veerman 	if (isexit(y) || isnext(y))
3185ea9e707SThomas Veerman 		return y;
3195ea9e707SThomas Veerman 	if (freed == 0) {
3205ea9e707SThomas Veerman 		tempfree(y);	/* don't free twice! */
3215ea9e707SThomas Veerman 	}
3225ea9e707SThomas Veerman 	z = frp->retval;			/* return value */
3235ea9e707SThomas Veerman 	   dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
3245ea9e707SThomas Veerman 	frp--;
3255ea9e707SThomas Veerman 	return(z);
3265ea9e707SThomas Veerman }
3275ea9e707SThomas Veerman 
copycell(Cell * x)3285ea9e707SThomas Veerman Cell *copycell(Cell *x)	/* make a copy of a cell in a temp */
3295ea9e707SThomas Veerman {
3305ea9e707SThomas Veerman 	Cell *y;
3315ea9e707SThomas Veerman 
3325ea9e707SThomas Veerman 	/* copy is not constant or field */
3335ea9e707SThomas Veerman 
3345ea9e707SThomas Veerman 	y = gettemp();
3355ea9e707SThomas Veerman 	y->tval = x->tval & ~(CON|FLD|REC);
3365ea9e707SThomas Veerman 	y->csub = CCOPY;	/* prevents freeing until call is over */
3375ea9e707SThomas Veerman 	y->nval = x->nval;	/* BUG? */
3385ea9e707SThomas Veerman 	if (isstr(x) /* || x->ctype == OCELL */) {
3395ea9e707SThomas Veerman 		y->sval = tostring(x->sval);
3405ea9e707SThomas Veerman 		y->tval &= ~DONTFREE;
3415ea9e707SThomas Veerman 	} else
3425ea9e707SThomas Veerman 		y->tval |= DONTFREE;
3435ea9e707SThomas Veerman 	y->fval = x->fval;
3445ea9e707SThomas Veerman 	return y;
3455ea9e707SThomas Veerman }
3465ea9e707SThomas Veerman 
arg(Node ** a,int n)3475ea9e707SThomas Veerman Cell *arg(Node **a, int n)	/* nth argument of a function */
3485ea9e707SThomas Veerman {
3495ea9e707SThomas Veerman 
3505ea9e707SThomas Veerman 	n = ptoi(a[0]);	/* argument number, counting from 0 */
3515ea9e707SThomas Veerman 	   dprintf( ("arg(%d), fp->nargs=%d\n", n, frp->nargs) );
3525ea9e707SThomas Veerman 	if (n+1 > frp->nargs)
3535ea9e707SThomas Veerman 		FATAL("argument #%d of function %s was not supplied",
3545ea9e707SThomas Veerman 			n+1, frp->fcncell->nval);
3555ea9e707SThomas Veerman 	return frp->args[n];
3565ea9e707SThomas Veerman }
3575ea9e707SThomas Veerman 
jump(Node ** a,int n)3585ea9e707SThomas Veerman Cell *jump(Node **a, int n)	/* break, continue, next, nextfile, return */
3595ea9e707SThomas Veerman {
3605ea9e707SThomas Veerman 	Cell *y;
3615ea9e707SThomas Veerman 
3625ea9e707SThomas Veerman 	switch (n) {
3635ea9e707SThomas Veerman 	case EXIT:
3645ea9e707SThomas Veerman 		if (a[0] != NULL) {
3655ea9e707SThomas Veerman 			y = execute(a[0]);
3665ea9e707SThomas Veerman 			errorflag = (int) getfval(y);
3675ea9e707SThomas Veerman 			tempfree(y);
3685ea9e707SThomas Veerman 		}
3695ea9e707SThomas Veerman 		longjmp(env, 1);
3705ea9e707SThomas Veerman 	case RETURN:
3715ea9e707SThomas Veerman 		if (a[0] != NULL) {
3725ea9e707SThomas Veerman 			y = execute(a[0]);
3735ea9e707SThomas Veerman 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
3745ea9e707SThomas Veerman 				setsval(frp->retval, getsval(y));
3755ea9e707SThomas Veerman 				frp->retval->fval = getfval(y);
3765ea9e707SThomas Veerman 				frp->retval->tval |= NUM;
3775ea9e707SThomas Veerman 			}
3785ea9e707SThomas Veerman 			else if (y->tval & STR)
3795ea9e707SThomas Veerman 				setsval(frp->retval, getsval(y));
3805ea9e707SThomas Veerman 			else if (y->tval & NUM)
3815ea9e707SThomas Veerman 				setfval(frp->retval, getfval(y));
3825ea9e707SThomas Veerman 			else		/* can't happen */
3835ea9e707SThomas Veerman 				FATAL("bad type variable %d", y->tval);
3845ea9e707SThomas Veerman 			tempfree(y);
3855ea9e707SThomas Veerman 		}
3865ea9e707SThomas Veerman 		return(jret);
3875ea9e707SThomas Veerman 	case NEXT:
3885ea9e707SThomas Veerman 		return(jnext);
3895ea9e707SThomas Veerman 	case NEXTFILE:
3905ea9e707SThomas Veerman 		nextfile();
3915ea9e707SThomas Veerman 		return(jnextfile);
3925ea9e707SThomas Veerman 	case BREAK:
3935ea9e707SThomas Veerman 		return(jbreak);
3945ea9e707SThomas Veerman 	case CONTINUE:
3955ea9e707SThomas Veerman 		return(jcont);
3965ea9e707SThomas Veerman 	default:	/* can't happen */
3975ea9e707SThomas Veerman 		FATAL("illegal jump type %d", n);
3985ea9e707SThomas Veerman 	}
3995ea9e707SThomas Veerman 	return 0;	/* not reached */
4005ea9e707SThomas Veerman }
4015ea9e707SThomas Veerman 
awkgetline(Node ** a,int n)4025ea9e707SThomas Veerman Cell *awkgetline(Node **a, int n)	/* get next line from specific input */
4035ea9e707SThomas Veerman {		/* a[0] is variable, a[1] is operator, a[2] is filename */
4045ea9e707SThomas Veerman 	Cell *r, *x;
4055ea9e707SThomas Veerman 	extern Cell **fldtab;
4065ea9e707SThomas Veerman 	FILE *fp;
4075ea9e707SThomas Veerman 	uschar *buf;
4085ea9e707SThomas Veerman 	int bufsize = recsize;
4095ea9e707SThomas Veerman 	int mode, newflag;
4105ea9e707SThomas Veerman 
4115ea9e707SThomas Veerman 	if ((buf = malloc(bufsize)) == NULL)
4125ea9e707SThomas Veerman 		FATAL("out of memory in getline");
4135ea9e707SThomas Veerman 
4145ea9e707SThomas Veerman 	fflush(stdout);	/* in case someone is waiting for a prompt */
4155ea9e707SThomas Veerman 	r = gettemp();
4165ea9e707SThomas Veerman 	if (a[1] != NULL) {		/* getline < file */
4175ea9e707SThomas Veerman 		x = execute(a[2]);		/* filename */
4185ea9e707SThomas Veerman 		mode = ptoi(a[1]);
4195ea9e707SThomas Veerman 		if (mode == '|')		/* input pipe */
4205ea9e707SThomas Veerman 			mode = LE;	/* arbitrary flag */
4215ea9e707SThomas Veerman 		fp = openfile(mode, getsval(x), &newflag);
4225ea9e707SThomas Veerman 		tempfree(x);
4235ea9e707SThomas Veerman 		if (fp == NULL)
4245ea9e707SThomas Veerman 			n = -1;
4255ea9e707SThomas Veerman 		else
4265ea9e707SThomas Veerman 			n = readrec(&buf, &bufsize, fp, newflag);
4275ea9e707SThomas Veerman 		if (n <= 0) {
4285ea9e707SThomas Veerman 			;
4295ea9e707SThomas Veerman 		} else if (a[0] != NULL) {	/* getline var <file */
4305ea9e707SThomas Veerman 			x = execute(a[0]);
4315ea9e707SThomas Veerman 			setsval(x, buf);
4325ea9e707SThomas Veerman 			tempfree(x);
4335ea9e707SThomas Veerman 		} else {			/* getline <file */
4345ea9e707SThomas Veerman 			setsval(fldtab[0], buf);
4355ea9e707SThomas Veerman 			if (is_number(fldtab[0]->sval)) {
4365ea9e707SThomas Veerman 				fldtab[0]->fval = atof(fldtab[0]->sval);
4375ea9e707SThomas Veerman 				fldtab[0]->tval |= NUM;
4385ea9e707SThomas Veerman 			}
4395ea9e707SThomas Veerman 		}
4405ea9e707SThomas Veerman 	} else {			/* bare getline; use current input */
4415ea9e707SThomas Veerman 		if (a[0] == NULL)	/* getline */
4425ea9e707SThomas Veerman 			n = getrec(&record, &recsize, 1);
4435ea9e707SThomas Veerman 		else {			/* getline var */
4445ea9e707SThomas Veerman 			n = getrec(&buf, &bufsize, 0);
4455ea9e707SThomas Veerman 			x = execute(a[0]);
4465ea9e707SThomas Veerman 			setsval(x, buf);
4475ea9e707SThomas Veerman 			tempfree(x);
4485ea9e707SThomas Veerman 		}
4495ea9e707SThomas Veerman 	}
4505ea9e707SThomas Veerman 	setfval(r, (Awkfloat) n);
4515ea9e707SThomas Veerman 	free(buf);
4525ea9e707SThomas Veerman 	return r;
4535ea9e707SThomas Veerman }
4545ea9e707SThomas Veerman 
getnf(Node ** a,int n)4555ea9e707SThomas Veerman Cell *getnf(Node **a, int n)	/* get NF */
4565ea9e707SThomas Veerman {
4575ea9e707SThomas Veerman 	if (donefld == 0)
4585ea9e707SThomas Veerman 		fldbld();
4595ea9e707SThomas Veerman 	return (Cell *) a[0];
4605ea9e707SThomas Veerman }
4615ea9e707SThomas Veerman 
array(Node ** a,int n)4625ea9e707SThomas Veerman Cell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
4635ea9e707SThomas Veerman {
4645ea9e707SThomas Veerman 	Cell *x, *y, *z;
4655ea9e707SThomas Veerman 	char *s;
4665ea9e707SThomas Veerman 	Node *np;
4675ea9e707SThomas Veerman 	uschar *buf;
4685ea9e707SThomas Veerman 	int bufsz = recsize;
4695ea9e707SThomas Veerman 	int nsub = strlen(*SUBSEP);
4705ea9e707SThomas Veerman 
4715ea9e707SThomas Veerman 	if ((buf = malloc(bufsz)) == NULL)
4725ea9e707SThomas Veerman 		FATAL("out of memory in array");
4735ea9e707SThomas Veerman 
4745ea9e707SThomas Veerman 	x = execute(a[0]);	/* Cell* for symbol table */
4755ea9e707SThomas Veerman 	buf[0] = 0;
4765ea9e707SThomas Veerman 	for (np = a[1]; np; np = np->nnext) {
4775ea9e707SThomas Veerman 		y = execute(np);	/* subscript */
4785ea9e707SThomas Veerman 		s = getsval(y);
4795ea9e707SThomas Veerman 		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "array"))
4805ea9e707SThomas Veerman 			FATAL("out of memory for %s[%s...]", x->nval, buf);
4815ea9e707SThomas Veerman 		strlcat(buf, s, bufsz);
4825ea9e707SThomas Veerman 		if (np->nnext)
4835ea9e707SThomas Veerman 			strlcat(buf, *SUBSEP, bufsz);
4845ea9e707SThomas Veerman 		tempfree(y);
4855ea9e707SThomas Veerman 	}
4865ea9e707SThomas Veerman 	if (!isarr(x)) {
4875ea9e707SThomas Veerman 		   dprintf( ("making %s into an array\n", NN(x->nval)) );
4885ea9e707SThomas Veerman 		if (freeable(x))
4895ea9e707SThomas Veerman 			xfree(x->sval);
4905ea9e707SThomas Veerman 		x->tval &= ~(STR|NUM|DONTFREE);
4915ea9e707SThomas Veerman 		x->tval |= ARR;
4925ea9e707SThomas Veerman 		x->sval = (char *) makesymtab(NSYMTAB);
4935ea9e707SThomas Veerman 	}
4945ea9e707SThomas Veerman 	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
4955ea9e707SThomas Veerman 	z->ctype = OCELL;
4965ea9e707SThomas Veerman 	z->csub = CVAR;
4975ea9e707SThomas Veerman 	tempfree(x);
4985ea9e707SThomas Veerman 	free(buf);
4995ea9e707SThomas Veerman 	return(z);
5005ea9e707SThomas Veerman }
5015ea9e707SThomas Veerman 
awkdelete(Node ** a,int n)5025ea9e707SThomas Veerman Cell *awkdelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
5035ea9e707SThomas Veerman {
5045ea9e707SThomas Veerman 	Cell *x, *y;
5055ea9e707SThomas Veerman 	Node *np;
5065ea9e707SThomas Veerman 	uschar *s;
5075ea9e707SThomas Veerman 	int nsub = strlen(*SUBSEP);
5085ea9e707SThomas Veerman 
5095ea9e707SThomas Veerman 	x = execute(a[0]);	/* Cell* for symbol table */
5105ea9e707SThomas Veerman 	if (!isarr(x))
5115ea9e707SThomas Veerman 		return True;
5125ea9e707SThomas Veerman 	if (a[1] == 0) {	/* delete the elements, not the table */
5135ea9e707SThomas Veerman 		freesymtab(x);
5145ea9e707SThomas Veerman 		x->tval &= ~STR;
5155ea9e707SThomas Veerman 		x->tval |= ARR;
5165ea9e707SThomas Veerman 		x->sval = (char *) makesymtab(NSYMTAB);
5175ea9e707SThomas Veerman 	} else {
5185ea9e707SThomas Veerman 		int bufsz = recsize;
5195ea9e707SThomas Veerman 		uschar *buf;
5205ea9e707SThomas Veerman 		if ((buf = malloc(bufsz)) == NULL)
5215ea9e707SThomas Veerman 			FATAL("out of memory in adelete");
5225ea9e707SThomas Veerman 		buf[0] = 0;
5235ea9e707SThomas Veerman 		for (np = a[1]; np; np = np->nnext) {
5245ea9e707SThomas Veerman 			y = execute(np);	/* subscript */
5255ea9e707SThomas Veerman 			s = getsval(y);
5265ea9e707SThomas Veerman 			if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "awkdelete"))
5275ea9e707SThomas Veerman 				FATAL("out of memory deleting %s[%s...]", x->nval, buf);
5285ea9e707SThomas Veerman 			strlcat(buf, s, bufsz);
5295ea9e707SThomas Veerman 			if (np->nnext)
5305ea9e707SThomas Veerman 				strlcat(buf, *SUBSEP, bufsz);
5315ea9e707SThomas Veerman 			tempfree(y);
5325ea9e707SThomas Veerman 		}
5335ea9e707SThomas Veerman 		freeelem(x, buf);
5345ea9e707SThomas Veerman 		free(buf);
5355ea9e707SThomas Veerman 	}
5365ea9e707SThomas Veerman 	tempfree(x);
5375ea9e707SThomas Veerman 	return True;
5385ea9e707SThomas Veerman }
5395ea9e707SThomas Veerman 
intest(Node ** a,int n)5405ea9e707SThomas Veerman Cell *intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
5415ea9e707SThomas Veerman {
5425ea9e707SThomas Veerman 	Cell *x, *ap, *k;
5435ea9e707SThomas Veerman 	Node *p;
5445ea9e707SThomas Veerman 	uschar *buf;
5455ea9e707SThomas Veerman 	char *s;
5465ea9e707SThomas Veerman 	int bufsz = recsize;
5475ea9e707SThomas Veerman 	int nsub = strlen(*SUBSEP);
5485ea9e707SThomas Veerman 
5495ea9e707SThomas Veerman 	ap = execute(a[1]);	/* array name */
5505ea9e707SThomas Veerman 	if (!isarr(ap)) {
5515ea9e707SThomas Veerman 		   dprintf( ("making %s into an array\n", ap->nval) );
5525ea9e707SThomas Veerman 		if (freeable(ap))
5535ea9e707SThomas Veerman 			xfree(ap->sval);
5545ea9e707SThomas Veerman 		ap->tval &= ~(STR|NUM|DONTFREE);
5555ea9e707SThomas Veerman 		ap->tval |= ARR;
5565ea9e707SThomas Veerman 		ap->sval = (char *) makesymtab(NSYMTAB);
5575ea9e707SThomas Veerman 	}
5585ea9e707SThomas Veerman 	if ((buf = malloc(bufsz)) == NULL) {
5595ea9e707SThomas Veerman 		FATAL("out of memory in intest");
5605ea9e707SThomas Veerman 	}
5615ea9e707SThomas Veerman 	buf[0] = 0;
5625ea9e707SThomas Veerman 	for (p = a[0]; p; p = p->nnext) {
5635ea9e707SThomas Veerman 		x = execute(p);	/* expr */
5645ea9e707SThomas Veerman 		s = getsval(x);
5655ea9e707SThomas Veerman 		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "intest"))
5665ea9e707SThomas Veerman 			FATAL("out of memory deleting %s[%s...]", x->nval, buf);
5675ea9e707SThomas Veerman 		strcat(buf, s);
5685ea9e707SThomas Veerman 		tempfree(x);
5695ea9e707SThomas Veerman 		if (p->nnext)
5705ea9e707SThomas Veerman 			strcat(buf, *SUBSEP);
5715ea9e707SThomas Veerman 	}
5725ea9e707SThomas Veerman 	k = lookup(buf, (Array *) ap->sval);
5735ea9e707SThomas Veerman 	tempfree(ap);
5745ea9e707SThomas Veerman 	free(buf);
5755ea9e707SThomas Veerman 	if (k == NULL)
5765ea9e707SThomas Veerman 		return(False);
5775ea9e707SThomas Veerman 	else
5785ea9e707SThomas Veerman 		return(True);
5795ea9e707SThomas Veerman }
5805ea9e707SThomas Veerman 
5815ea9e707SThomas Veerman 
matchop(Node ** a,int n)5825ea9e707SThomas Veerman Cell *matchop(Node **a, int n)	/* ~ and match() */
5835ea9e707SThomas Veerman {
5845ea9e707SThomas Veerman 	Cell *x, *y;
5855ea9e707SThomas Veerman 	uschar *s;
5865ea9e707SThomas Veerman 	char *t;
5875ea9e707SThomas Veerman 	int i;
5885ea9e707SThomas Veerman 	fa *pfa;
5895ea9e707SThomas Veerman 	int (*mf)(fa *, const char *) = match, mode = 0;
5905ea9e707SThomas Veerman 
5915ea9e707SThomas Veerman 	if (n == MATCHFCN) {
5925ea9e707SThomas Veerman 		mf = pmatch;
5935ea9e707SThomas Veerman 		mode = 1;
5945ea9e707SThomas Veerman 	}
5955ea9e707SThomas Veerman 	x = execute(a[1]);	/* a[1] = target text */
5965ea9e707SThomas Veerman 	s = getsval(x);
5975ea9e707SThomas Veerman 	if (a[0] == 0)		/* a[1] == 0: already-compiled reg expr */
5985ea9e707SThomas Veerman 		i = (*mf)((fa *) a[2], s);
5995ea9e707SThomas Veerman 	else {
6005ea9e707SThomas Veerman 		y = execute(a[2]);	/* a[2] = regular expr */
6015ea9e707SThomas Veerman 		t = getsval(y);
6025ea9e707SThomas Veerman 		pfa = makedfa(t, mode);
6035ea9e707SThomas Veerman 		i = (*mf)(pfa, s);
6045ea9e707SThomas Veerman 		tempfree(y);
6055ea9e707SThomas Veerman 	}
6065ea9e707SThomas Veerman 	tempfree(x);
6075ea9e707SThomas Veerman 	if (n == MATCHFCN) {
6085ea9e707SThomas Veerman 		int start = patbeg - s + 1;
6095ea9e707SThomas Veerman 		if (patlen < 0)
6105ea9e707SThomas Veerman 			start = 0;
6115ea9e707SThomas Veerman 		setfval(rstartloc, (Awkfloat) start);
6125ea9e707SThomas Veerman 		setfval(rlengthloc, (Awkfloat) patlen);
6135ea9e707SThomas Veerman 		x = gettemp();
6145ea9e707SThomas Veerman 		x->tval = NUM;
6155ea9e707SThomas Veerman 		x->fval = start;
6165ea9e707SThomas Veerman 		return x;
6175ea9e707SThomas Veerman 	} else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
6185ea9e707SThomas Veerman 		return(True);
6195ea9e707SThomas Veerman 	else
6205ea9e707SThomas Veerman 		return(False);
6215ea9e707SThomas Veerman }
6225ea9e707SThomas Veerman 
6235ea9e707SThomas Veerman 
boolop(Node ** a,int n)6245ea9e707SThomas Veerman Cell *boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
6255ea9e707SThomas Veerman {
6265ea9e707SThomas Veerman 	Cell *x, *y;
6275ea9e707SThomas Veerman 	int i;
6285ea9e707SThomas Veerman 
6295ea9e707SThomas Veerman 	x = execute(a[0]);
6305ea9e707SThomas Veerman 	i = istrue(x);
6315ea9e707SThomas Veerman 	tempfree(x);
6325ea9e707SThomas Veerman 	switch (n) {
6335ea9e707SThomas Veerman 	case BOR:
6345ea9e707SThomas Veerman 		if (i) return(True);
6355ea9e707SThomas Veerman 		y = execute(a[1]);
6365ea9e707SThomas Veerman 		i = istrue(y);
6375ea9e707SThomas Veerman 		tempfree(y);
6385ea9e707SThomas Veerman 		if (i) return(True);
6395ea9e707SThomas Veerman 		else return(False);
6405ea9e707SThomas Veerman 	case AND:
6415ea9e707SThomas Veerman 		if ( !i ) return(False);
6425ea9e707SThomas Veerman 		y = execute(a[1]);
6435ea9e707SThomas Veerman 		i = istrue(y);
6445ea9e707SThomas Veerman 		tempfree(y);
6455ea9e707SThomas Veerman 		if (i) return(True);
6465ea9e707SThomas Veerman 		else return(False);
6475ea9e707SThomas Veerman 	case NOT:
6485ea9e707SThomas Veerman 		if (i) return(False);
6495ea9e707SThomas Veerman 		else return(True);
6505ea9e707SThomas Veerman 	default:	/* can't happen */
6515ea9e707SThomas Veerman 		FATAL("unknown boolean operator %d", n);
6525ea9e707SThomas Veerman 	}
6535ea9e707SThomas Veerman 	return 0;	/*NOTREACHED*/
6545ea9e707SThomas Veerman }
6555ea9e707SThomas Veerman 
relop(Node ** a,int n)6565ea9e707SThomas Veerman Cell *relop(Node **a, int n)	/* a[0 < a[1], etc. */
6575ea9e707SThomas Veerman {
6585ea9e707SThomas Veerman 	int i;
6595ea9e707SThomas Veerman 	Cell *x, *y;
6605ea9e707SThomas Veerman 	Awkfloat j;
6615ea9e707SThomas Veerman 
6625ea9e707SThomas Veerman 	x = execute(a[0]);
6635ea9e707SThomas Veerman 	y = execute(a[1]);
6645ea9e707SThomas Veerman 	if (x->tval&NUM && y->tval&NUM) {
6655ea9e707SThomas Veerman 		j = x->fval - y->fval;
6665ea9e707SThomas Veerman 		i = j<0? -1: (j>0? 1: 0);
6675ea9e707SThomas Veerman 	} else {
6685ea9e707SThomas Veerman 		i = strcmp(getsval(x), getsval(y));
6695ea9e707SThomas Veerman 	}
6705ea9e707SThomas Veerman 	tempfree(x);
6715ea9e707SThomas Veerman 	tempfree(y);
6725ea9e707SThomas Veerman 	switch (n) {
6735ea9e707SThomas Veerman 	case LT:	if (i<0) return(True);
6745ea9e707SThomas Veerman 			else return(False);
6755ea9e707SThomas Veerman 	case LE:	if (i<=0) return(True);
6765ea9e707SThomas Veerman 			else return(False);
6775ea9e707SThomas Veerman 	case NE:	if (i!=0) return(True);
6785ea9e707SThomas Veerman 			else return(False);
6795ea9e707SThomas Veerman 	case EQ:	if (i == 0) return(True);
6805ea9e707SThomas Veerman 			else return(False);
6815ea9e707SThomas Veerman 	case GE:	if (i>=0) return(True);
6825ea9e707SThomas Veerman 			else return(False);
6835ea9e707SThomas Veerman 	case GT:	if (i>0) return(True);
6845ea9e707SThomas Veerman 			else return(False);
6855ea9e707SThomas Veerman 	default:	/* can't happen */
6865ea9e707SThomas Veerman 		FATAL("unknown relational operator %d", n);
6875ea9e707SThomas Veerman 	}
6885ea9e707SThomas Veerman 	return 0;	/*NOTREACHED*/
6895ea9e707SThomas Veerman }
6905ea9e707SThomas Veerman 
tfree(Cell * a)6915ea9e707SThomas Veerman void tfree(Cell *a)	/* free a tempcell */
6925ea9e707SThomas Veerman {
6935ea9e707SThomas Veerman 	if (freeable(a)) {
6945ea9e707SThomas Veerman 		   dprintf( ("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval) );
6955ea9e707SThomas Veerman 		xfree(a->sval);
6965ea9e707SThomas Veerman 	}
6975ea9e707SThomas Veerman 	if (a == tmps)
6985ea9e707SThomas Veerman 		FATAL("tempcell list is curdled");
6995ea9e707SThomas Veerman 	a->cnext = tmps;
7005ea9e707SThomas Veerman 	tmps = a;
7015ea9e707SThomas Veerman }
7025ea9e707SThomas Veerman 
gettemp(void)7035ea9e707SThomas Veerman Cell *gettemp(void)	/* get a tempcell */
7045ea9e707SThomas Veerman {	int i;
7055ea9e707SThomas Veerman 	Cell *x;
7065ea9e707SThomas Veerman 
7075ea9e707SThomas Veerman 	if (!tmps) {
7085ea9e707SThomas Veerman 		tmps = calloc(100, sizeof(*tmps));
7095ea9e707SThomas Veerman 		if (!tmps)
7105ea9e707SThomas Veerman 			FATAL("out of space for temporaries");
7115ea9e707SThomas Veerman 		for(i = 1; i < 100; i++)
7125ea9e707SThomas Veerman 			tmps[i-1].cnext = &tmps[i];
7135ea9e707SThomas Veerman 		tmps[i-1].cnext = 0;
7145ea9e707SThomas Veerman 	}
7155ea9e707SThomas Veerman 	x = tmps;
7165ea9e707SThomas Veerman 	tmps = x->cnext;
7175ea9e707SThomas Veerman 	*x = tempcell;
7185ea9e707SThomas Veerman 	return(x);
7195ea9e707SThomas Veerman }
7205ea9e707SThomas Veerman 
indirect(Node ** a,int n)7215ea9e707SThomas Veerman Cell *indirect(Node **a, int n)	/* $( a[0] ) */
7225ea9e707SThomas Veerman {
7235ea9e707SThomas Veerman 	Awkfloat val;
7245ea9e707SThomas Veerman 	Cell *x;
7255ea9e707SThomas Veerman 	int m;
7265ea9e707SThomas Veerman 	char *s;
7275ea9e707SThomas Veerman 
7285ea9e707SThomas Veerman 	x = execute(a[0]);
7295ea9e707SThomas Veerman 	val = getfval(x);	/* freebsd: defend against super large field numbers */
7305ea9e707SThomas Veerman 	if ((Awkfloat)INT_MAX < val)
7315ea9e707SThomas Veerman 		FATAL("trying to access out of range field %s", x->nval);
7325ea9e707SThomas Veerman 	m = (int) val;
7335ea9e707SThomas Veerman 	if (m == 0 && !is_number(s = getsval(x)))	/* suspicion! */
7345ea9e707SThomas Veerman 		FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
7355ea9e707SThomas Veerman 		/* BUG: can x->nval ever be null??? */
7365ea9e707SThomas Veerman 	tempfree(x);
7375ea9e707SThomas Veerman 	x = fieldadr(m);
7385ea9e707SThomas Veerman 	x->ctype = OCELL;	/* BUG?  why are these needed? */
7395ea9e707SThomas Veerman 	x->csub = CFLD;
7405ea9e707SThomas Veerman 	return(x);
7415ea9e707SThomas Veerman }
7425ea9e707SThomas Veerman 
substr(Node ** a,int nnn)7435ea9e707SThomas Veerman Cell *substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
7445ea9e707SThomas Veerman {
7455ea9e707SThomas Veerman 	int k, m, n;
7465ea9e707SThomas Veerman 	char *s;
7475ea9e707SThomas Veerman 	int temp;
7485ea9e707SThomas Veerman 	Cell *x, *y, *z = 0;
7495ea9e707SThomas Veerman 
7505ea9e707SThomas Veerman 	x = execute(a[0]);
7515ea9e707SThomas Veerman 	y = execute(a[1]);
7525ea9e707SThomas Veerman 	if (a[2] != 0)
7535ea9e707SThomas Veerman 		z = execute(a[2]);
7545ea9e707SThomas Veerman 	s = getsval(x);
7555ea9e707SThomas Veerman 	k = strlen(s) + 1;
7565ea9e707SThomas Veerman 	if (k <= 1) {
7575ea9e707SThomas Veerman 		tempfree(x);
7585ea9e707SThomas Veerman 		tempfree(y);
7595ea9e707SThomas Veerman 		if (a[2] != 0) {
7605ea9e707SThomas Veerman 			tempfree(z);
7615ea9e707SThomas Veerman 		}
7625ea9e707SThomas Veerman 		x = gettemp();
7635ea9e707SThomas Veerman 		setsval(x, "");
7645ea9e707SThomas Veerman 		return(x);
7655ea9e707SThomas Veerman 	}
7665ea9e707SThomas Veerman 	m = (int) getfval(y);
7675ea9e707SThomas Veerman 	if (m <= 0)
7685ea9e707SThomas Veerman 		m = 1;
7695ea9e707SThomas Veerman 	else if (m > k)
7705ea9e707SThomas Veerman 		m = k;
7715ea9e707SThomas Veerman 	tempfree(y);
7725ea9e707SThomas Veerman 	if (a[2] != 0) {
7735ea9e707SThomas Veerman 		n = (int) getfval(z);
7745ea9e707SThomas Veerman 		tempfree(z);
7755ea9e707SThomas Veerman 	} else
7765ea9e707SThomas Veerman 		n = k - 1;
7775ea9e707SThomas Veerman 	if (n < 0)
7785ea9e707SThomas Veerman 		n = 0;
7795ea9e707SThomas Veerman 	else if (n > k - m)
7805ea9e707SThomas Veerman 		n = k - m;
7815ea9e707SThomas Veerman 	   dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
7825ea9e707SThomas Veerman 	y = gettemp();
7835ea9e707SThomas Veerman 	temp = s[n+m-1];	/* with thanks to John Linderman */
7845ea9e707SThomas Veerman 	s[n+m-1] = '\0';
7855ea9e707SThomas Veerman 	setsval(y, s + m - 1);
7865ea9e707SThomas Veerman 	s[n+m-1] = temp;
7875ea9e707SThomas Veerman 	tempfree(x);
7885ea9e707SThomas Veerman 	return(y);
7895ea9e707SThomas Veerman }
7905ea9e707SThomas Veerman 
sindex(Node ** a,int nnn)7915ea9e707SThomas Veerman Cell *sindex(Node **a, int nnn)		/* index(a[0], a[1]) */
7925ea9e707SThomas Veerman {
7935ea9e707SThomas Veerman 	Cell *x, *y, *z;
7945ea9e707SThomas Veerman 	char *s1, *s2, *p1, *p2, *q;
7955ea9e707SThomas Veerman 	Awkfloat v = 0.0;
7965ea9e707SThomas Veerman 
7975ea9e707SThomas Veerman 	x = execute(a[0]);
7985ea9e707SThomas Veerman 	s1 = getsval(x);
7995ea9e707SThomas Veerman 	y = execute(a[1]);
8005ea9e707SThomas Veerman 	s2 = getsval(y);
8015ea9e707SThomas Veerman 
8025ea9e707SThomas Veerman 	z = gettemp();
8035ea9e707SThomas Veerman 	for (p1 = s1; *p1 != '\0'; p1++) {
8045ea9e707SThomas Veerman 		for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
8055ea9e707SThomas Veerman 			;
8065ea9e707SThomas Veerman 		if (*p2 == '\0') {
8075ea9e707SThomas Veerman 			v = (Awkfloat) (p1 - s1 + 1);	/* origin 1 */
8085ea9e707SThomas Veerman 			break;
8095ea9e707SThomas Veerman 		}
8105ea9e707SThomas Veerman 	}
8115ea9e707SThomas Veerman 	tempfree(x);
8125ea9e707SThomas Veerman 	tempfree(y);
8135ea9e707SThomas Veerman 	setfval(z, v);
8145ea9e707SThomas Veerman 	return(z);
8155ea9e707SThomas Veerman }
8165ea9e707SThomas Veerman 
8175ea9e707SThomas Veerman #define	MAXNUMSIZE	50
8185ea9e707SThomas Veerman 
format(char ** pbuf,int * pbufsize,const char * s,Node * a)8195ea9e707SThomas Veerman int format(char **pbuf, int *pbufsize, const char *s, Node *a)	/* printf-like conversions */
8205ea9e707SThomas Veerman {
8215ea9e707SThomas Veerman 	uschar *fmt, *p, *t;
8225ea9e707SThomas Veerman 	const char *os;
8235ea9e707SThomas Veerman 	Cell *x;
8245ea9e707SThomas Veerman 	int flag = 0, n;
8255ea9e707SThomas Veerman 	int fmtwd; /* format width */
8265ea9e707SThomas Veerman 	int fmtsz = recsize;
8275ea9e707SThomas Veerman 	uschar *buf = *pbuf;
8285ea9e707SThomas Veerman 	int bufsize = *pbufsize;
8295ea9e707SThomas Veerman #define FMTSZ(a)   (fmtsz - ((a) - fmt))
8305ea9e707SThomas Veerman #define BUFSZ(a)   (bufsize - ((a) - buf))
8315ea9e707SThomas Veerman 
8325ea9e707SThomas Veerman 	os = s;
8335ea9e707SThomas Veerman 	p = buf;
8345ea9e707SThomas Veerman 	if ((fmt = malloc(fmtsz)) == NULL)
8355ea9e707SThomas Veerman 		FATAL("out of memory in format()");
8365ea9e707SThomas Veerman 	while (*s) {
8375ea9e707SThomas Veerman 		adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1");
8385ea9e707SThomas Veerman 		if (*s != '%') {
8395ea9e707SThomas Veerman 			*p++ = *s++;
8405ea9e707SThomas Veerman 			continue;
8415ea9e707SThomas Veerman 		}
8425ea9e707SThomas Veerman 		if (*(s+1) == '%') {
8435ea9e707SThomas Veerman 			*p++ = '%';
8445ea9e707SThomas Veerman 			s += 2;
8455ea9e707SThomas Veerman 			continue;
8465ea9e707SThomas Veerman 		}
8475ea9e707SThomas Veerman 		/* have to be real careful in case this is a huge number, eg, %100000d */
8485ea9e707SThomas Veerman 		fmtwd = atoi(s+1);
8495ea9e707SThomas Veerman 		if (fmtwd < 0)
8505ea9e707SThomas Veerman 			fmtwd = -fmtwd;
8515ea9e707SThomas Veerman 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format2");
8525ea9e707SThomas Veerman 		for (t = fmt; (*t++ = *s) != '\0'; s++) {
8535ea9e707SThomas Veerman 			if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3"))
8545ea9e707SThomas Veerman 				FATAL("format item %.30s... ran format() out of memory", os);
8555ea9e707SThomas Veerman 			if (*s == 'l' || *s == 'h' || *s == 'L')
8565ea9e707SThomas Veerman 				goto weird;
8575ea9e707SThomas Veerman 			if (isalpha((uschar)*s))
8585ea9e707SThomas Veerman 				break;	/* the ansi panoply */
8595ea9e707SThomas Veerman 			if (*s == '*') {
8605ea9e707SThomas Veerman 				if (a == NULL)
8615ea9e707SThomas Veerman 					FATAL("not enough args in printf("
8625ea9e707SThomas Veerman 					    "\"%.30s\")", os);
8635ea9e707SThomas Veerman 				x = execute(a);
8645ea9e707SThomas Veerman 				a = a->nnext;
8655ea9e707SThomas Veerman 				snprintf(t - 1, FMTSZ(t - 1),
8665ea9e707SThomas Veerman 				    "%d", fmtwd=(int) getfval(x));
8675ea9e707SThomas Veerman 				if (fmtwd < 0)
8685ea9e707SThomas Veerman 					fmtwd = -fmtwd;
8695ea9e707SThomas Veerman 				adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
8705ea9e707SThomas Veerman 				t = fmt + strlen(fmt);
8715ea9e707SThomas Veerman 				tempfree(x);
8725ea9e707SThomas Veerman 			}
8735ea9e707SThomas Veerman 		}
8745ea9e707SThomas Veerman 		*t = '\0';
8755ea9e707SThomas Veerman 		if (fmtwd < 0)
8765ea9e707SThomas Veerman 			fmtwd = -fmtwd;
8775ea9e707SThomas Veerman 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format4");
8785ea9e707SThomas Veerman 
8795ea9e707SThomas Veerman 		switch (*s) {
8805ea9e707SThomas Veerman 		case 'f': case 'e': case 'g': case 'E': case 'G':
8815ea9e707SThomas Veerman 			flag = 'f';
8825ea9e707SThomas Veerman 			break;
8835ea9e707SThomas Veerman 		case 'd': case 'i':
8845ea9e707SThomas Veerman 			flag = 'd';
8855ea9e707SThomas Veerman 			if(*(s-1) == 'l') break;
8865ea9e707SThomas Veerman 			*(t-1) = 'j';
8875ea9e707SThomas Veerman 			*t = 'd';
8885ea9e707SThomas Veerman 			*++t = '\0';
8895ea9e707SThomas Veerman 			break;
8905ea9e707SThomas Veerman 		case 'o': case 'x': case 'X': case 'u':
8915ea9e707SThomas Veerman 			flag = *(s-1) == 'l' ? 'd' : 'u';
8925ea9e707SThomas Veerman 			*(t-1) = 'j';
8935ea9e707SThomas Veerman 			*t = *s;
8945ea9e707SThomas Veerman 			*++t = '\0';
8955ea9e707SThomas Veerman 			break;
8965ea9e707SThomas Veerman 		case 's':
8975ea9e707SThomas Veerman 			flag = 's';
8985ea9e707SThomas Veerman 			break;
8995ea9e707SThomas Veerman 		case 'c':
9005ea9e707SThomas Veerman 			flag = 'c';
9015ea9e707SThomas Veerman 			break;
9025ea9e707SThomas Veerman 		default:
9035ea9e707SThomas Veerman 		weird:
9045ea9e707SThomas Veerman 			WARNING("weird printf conversion %s", fmt);
9055ea9e707SThomas Veerman 			flag = '?';
9065ea9e707SThomas Veerman 			break;
9075ea9e707SThomas Veerman 		}
9085ea9e707SThomas Veerman 		if (a == NULL)
9095ea9e707SThomas Veerman 			FATAL("not enough args in printf(%s)", os);
9105ea9e707SThomas Veerman 		x = execute(a);
9115ea9e707SThomas Veerman 		a = a->nnext;
9125ea9e707SThomas Veerman 		n = MAXNUMSIZE;
9135ea9e707SThomas Veerman 		if (fmtwd > n)
9145ea9e707SThomas Veerman 			n = fmtwd;
9155ea9e707SThomas Veerman 		adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5");
9165ea9e707SThomas Veerman 		switch (flag) {
9175ea9e707SThomas Veerman 		case '?':	snprintf(p, BUFSZ(p), "%s", fmt);	/* unknown, so dump it too */
9185ea9e707SThomas Veerman 			t = getsval(x);
9195ea9e707SThomas Veerman 			n = strlen(t);
9205ea9e707SThomas Veerman 			if (fmtwd > n)
9215ea9e707SThomas Veerman 				n = fmtwd;
9225ea9e707SThomas Veerman 			adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6");
9235ea9e707SThomas Veerman 			p += strlen(p);
9245ea9e707SThomas Veerman 			snprintf(p, BUFSZ(p), "%s", t);
9255ea9e707SThomas Veerman 			break;
9265ea9e707SThomas Veerman 		case 'f':	snprintf(p, BUFSZ(p), fmt, getfval(x)); break;
9275ea9e707SThomas Veerman 		case 'd':	snprintf(p, BUFSZ(p), fmt, (intmax_t) getfval(x)); break;
9285ea9e707SThomas Veerman 		case 'u':	snprintf(p, BUFSZ(p), fmt, (uintmax_t) getfval(x)); break;
9295ea9e707SThomas Veerman 		case 's':
9305ea9e707SThomas Veerman 			t = getsval(x);
9315ea9e707SThomas Veerman 			n = strlen(t);
9325ea9e707SThomas Veerman 			if (fmtwd > n)
9335ea9e707SThomas Veerman 				n = fmtwd;
9345ea9e707SThomas Veerman 			if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7"))
9355ea9e707SThomas Veerman 				FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
9365ea9e707SThomas Veerman 			snprintf(p, BUFSZ(p), fmt, t);
9375ea9e707SThomas Veerman 			break;
9385ea9e707SThomas Veerman 		case 'c':
9395ea9e707SThomas Veerman 			if (isnum(x)) {
9405ea9e707SThomas Veerman 				if (getfval(x))
9415ea9e707SThomas Veerman 					snprintf(p, BUFSZ(p), fmt, (int) getfval(x));
9425ea9e707SThomas Veerman 				else {
9435ea9e707SThomas Veerman 					*p++ = '\0'; /* explicit null byte */
9445ea9e707SThomas Veerman 					*p = '\0';   /* next output will start here */
9455ea9e707SThomas Veerman 				}
9465ea9e707SThomas Veerman 			} else
9475ea9e707SThomas Veerman 				snprintf(p, BUFSZ(p), fmt, getsval(x)[0]);
9485ea9e707SThomas Veerman 			break;
9495ea9e707SThomas Veerman 		default:
9505ea9e707SThomas Veerman 			FATAL("can't happen: bad conversion %c in format()", flag);
9515ea9e707SThomas Veerman 		}
9525ea9e707SThomas Veerman 		tempfree(x);
9535ea9e707SThomas Veerman 		p += strlen(p);
9545ea9e707SThomas Veerman 		s++;
9555ea9e707SThomas Veerman 	}
9565ea9e707SThomas Veerman 	*p = '\0';
9575ea9e707SThomas Veerman 	free(fmt);
9585ea9e707SThomas Veerman 	for ( ; a; a = a->nnext)		/* evaluate any remaining args */
9595ea9e707SThomas Veerman 		execute(a);
9605ea9e707SThomas Veerman 	*pbuf = buf;
9615ea9e707SThomas Veerman 	*pbufsize = bufsize;
9625ea9e707SThomas Veerman 	return p - buf;
9635ea9e707SThomas Veerman }
9645ea9e707SThomas Veerman 
awksprintf(Node ** a,int n)9655ea9e707SThomas Veerman Cell *awksprintf(Node **a, int n)		/* sprintf(a[0]) */
9665ea9e707SThomas Veerman {
9675ea9e707SThomas Veerman 	Cell *x;
9685ea9e707SThomas Veerman 	Node *y;
9695ea9e707SThomas Veerman 	char *buf;
9705ea9e707SThomas Veerman 	int bufsz=3*recsize;
9715ea9e707SThomas Veerman 
9725ea9e707SThomas Veerman 	if ((buf = malloc(bufsz)) == NULL)
9735ea9e707SThomas Veerman 		FATAL("out of memory in awksprintf");
9745ea9e707SThomas Veerman 	y = a[0]->nnext;
9755ea9e707SThomas Veerman 	x = execute(a[0]);
9765ea9e707SThomas Veerman 	if (format(&buf, &bufsz, getsval(x), y) == -1)
9775ea9e707SThomas Veerman 		FATAL("sprintf string %.30s... too long.  can't happen.", buf);
9785ea9e707SThomas Veerman 	tempfree(x);
9795ea9e707SThomas Veerman 	x = gettemp();
9805ea9e707SThomas Veerman 	x->sval = buf;
9815ea9e707SThomas Veerman 	x->tval = STR;
9825ea9e707SThomas Veerman 	return(x);
9835ea9e707SThomas Veerman }
9845ea9e707SThomas Veerman 
awkprintf(Node ** a,int n)9855ea9e707SThomas Veerman Cell *awkprintf(Node **a, int n)		/* printf */
9865ea9e707SThomas Veerman {	/* a[0] is list of args, starting with format string */
9875ea9e707SThomas Veerman 	/* a[1] is redirection operator, a[2] is redirection file */
9885ea9e707SThomas Veerman 	FILE *fp;
9895ea9e707SThomas Veerman 	Cell *x;
9905ea9e707SThomas Veerman 	Node *y;
9915ea9e707SThomas Veerman 	char *buf;
9925ea9e707SThomas Veerman 	int len;
9935ea9e707SThomas Veerman 	int bufsz=3*recsize;
9945ea9e707SThomas Veerman 
9955ea9e707SThomas Veerman 	if ((buf = malloc(bufsz)) == NULL)
9965ea9e707SThomas Veerman 		FATAL("out of memory in awkprintf");
9975ea9e707SThomas Veerman 	y = a[0]->nnext;
9985ea9e707SThomas Veerman 	x = execute(a[0]);
9995ea9e707SThomas Veerman 	if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
10005ea9e707SThomas Veerman 		FATAL("printf string %.30s... too long.  can't happen.", buf);
10015ea9e707SThomas Veerman 	tempfree(x);
10025ea9e707SThomas Veerman 	if (a[1] == NULL) {
10035ea9e707SThomas Veerman 		/* fputs(buf, stdout); */
10045ea9e707SThomas Veerman 		fwrite(buf, len, 1, stdout);
10055ea9e707SThomas Veerman 		if (ferror(stdout))
10065ea9e707SThomas Veerman 			FATAL("write error on stdout");
10075ea9e707SThomas Veerman 	} else {
10085ea9e707SThomas Veerman 		fp = redirect(ptoi(a[1]), a[2]);
10095ea9e707SThomas Veerman 		/* fputs(buf, fp); */
10105ea9e707SThomas Veerman 		fwrite(buf, len, 1, fp);
10115ea9e707SThomas Veerman 		fflush(fp);
10125ea9e707SThomas Veerman 		if (ferror(fp))
10135ea9e707SThomas Veerman 			FATAL("write error on %s", filename(fp));
10145ea9e707SThomas Veerman 	}
10155ea9e707SThomas Veerman 	free(buf);
10165ea9e707SThomas Veerman 	return(True);
10175ea9e707SThomas Veerman }
10185ea9e707SThomas Veerman 
arith(Node ** a,int n)10195ea9e707SThomas Veerman Cell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
10205ea9e707SThomas Veerman {
10215ea9e707SThomas Veerman 	Awkfloat i, j = 0;
10225ea9e707SThomas Veerman 	double v;
10235ea9e707SThomas Veerman 	Cell *x, *y, *z;
10245ea9e707SThomas Veerman 
10255ea9e707SThomas Veerman 	x = execute(a[0]);
10265ea9e707SThomas Veerman 	i = getfval(x);
10275ea9e707SThomas Veerman 	tempfree(x);
10285ea9e707SThomas Veerman 	if (n != UMINUS) {
10295ea9e707SThomas Veerman 		y = execute(a[1]);
10305ea9e707SThomas Veerman 		j = getfval(y);
10315ea9e707SThomas Veerman 		tempfree(y);
10325ea9e707SThomas Veerman 	}
10335ea9e707SThomas Veerman 	z = gettemp();
10345ea9e707SThomas Veerman 	switch (n) {
10355ea9e707SThomas Veerman 	case ADD:
10365ea9e707SThomas Veerman 		i += j;
10375ea9e707SThomas Veerman 		break;
10385ea9e707SThomas Veerman 	case MINUS:
10395ea9e707SThomas Veerman 		i -= j;
10405ea9e707SThomas Veerman 		break;
10415ea9e707SThomas Veerman 	case MULT:
10425ea9e707SThomas Veerman 		i *= j;
10435ea9e707SThomas Veerman 		break;
10445ea9e707SThomas Veerman 	case DIVIDE:
10455ea9e707SThomas Veerman 		if (j == 0)
10465ea9e707SThomas Veerman 			FATAL("division by zero");
10475ea9e707SThomas Veerman 		i /= j;
10485ea9e707SThomas Veerman 		break;
10495ea9e707SThomas Veerman 	case MOD:
10505ea9e707SThomas Veerman 		if (j == 0)
10515ea9e707SThomas Veerman 			FATAL("division by zero in mod");
10525ea9e707SThomas Veerman 		modf(i/j, &v);
10535ea9e707SThomas Veerman 		i = i - j * v;
10545ea9e707SThomas Veerman 		break;
10555ea9e707SThomas Veerman 	case UMINUS:
10565ea9e707SThomas Veerman 		i = -i;
10575ea9e707SThomas Veerman 		break;
10585ea9e707SThomas Veerman 	case POWER:
10595ea9e707SThomas Veerman 		if (j >= 0 && modf(j, &v) == 0.0)	/* pos integer exponent */
10605ea9e707SThomas Veerman 			i = ipow(i, (int) j);
10615ea9e707SThomas Veerman 		else
10625ea9e707SThomas Veerman 			i = errcheck(pow(i, j), "pow");
10635ea9e707SThomas Veerman 		break;
10645ea9e707SThomas Veerman 	default:	/* can't happen */
10655ea9e707SThomas Veerman 		FATAL("illegal arithmetic operator %d", n);
10665ea9e707SThomas Veerman 	}
10675ea9e707SThomas Veerman 	setfval(z, i);
10685ea9e707SThomas Veerman 	return(z);
10695ea9e707SThomas Veerman }
10705ea9e707SThomas Veerman 
ipow(double x,int n)10715ea9e707SThomas Veerman double ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
10725ea9e707SThomas Veerman {
10735ea9e707SThomas Veerman 	double v;
10745ea9e707SThomas Veerman 
10755ea9e707SThomas Veerman 	if (n <= 0)
10765ea9e707SThomas Veerman 		return 1;
10775ea9e707SThomas Veerman 	v = ipow(x, n/2);
10785ea9e707SThomas Veerman 	if (n % 2 == 0)
10795ea9e707SThomas Veerman 		return v * v;
10805ea9e707SThomas Veerman 	else
10815ea9e707SThomas Veerman 		return x * v * v;
10825ea9e707SThomas Veerman }
10835ea9e707SThomas Veerman 
incrdecr(Node ** a,int n)10845ea9e707SThomas Veerman Cell *incrdecr(Node **a, int n)		/* a[0]++, etc. */
10855ea9e707SThomas Veerman {
10865ea9e707SThomas Veerman 	Cell *x, *z;
10875ea9e707SThomas Veerman 	int k;
10885ea9e707SThomas Veerman 	Awkfloat xf;
10895ea9e707SThomas Veerman 
10905ea9e707SThomas Veerman 	x = execute(a[0]);
10915ea9e707SThomas Veerman 	xf = getfval(x);
10925ea9e707SThomas Veerman 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
10935ea9e707SThomas Veerman 	if (n == PREINCR || n == PREDECR) {
10945ea9e707SThomas Veerman 		setfval(x, xf + k);
10955ea9e707SThomas Veerman 		return(x);
10965ea9e707SThomas Veerman 	}
10975ea9e707SThomas Veerman 	z = gettemp();
10985ea9e707SThomas Veerman 	setfval(z, xf);
10995ea9e707SThomas Veerman 	setfval(x, xf + k);
11005ea9e707SThomas Veerman 	tempfree(x);
11015ea9e707SThomas Veerman 	return(z);
11025ea9e707SThomas Veerman }
11035ea9e707SThomas Veerman 
assign(Node ** a,int n)11045ea9e707SThomas Veerman Cell *assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
11055ea9e707SThomas Veerman {		/* this is subtle; don't muck with it. */
11065ea9e707SThomas Veerman 	Cell *x, *y;
11075ea9e707SThomas Veerman 	Awkfloat xf, yf;
11085ea9e707SThomas Veerman 	double v;
11095ea9e707SThomas Veerman 
11105ea9e707SThomas Veerman 	y = execute(a[1]);
11115ea9e707SThomas Veerman 	x = execute(a[0]);
11125ea9e707SThomas Veerman 	if (n == ASSIGN) {	/* ordinary assignment */
11135ea9e707SThomas Veerman 		if (x == y && !(x->tval & (FLD|REC)))	/* self-assignment: */
11145ea9e707SThomas Veerman 			;		/* leave alone unless it's a field */
11155ea9e707SThomas Veerman 		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
11165ea9e707SThomas Veerman 			setsval(x, getsval(y));
11175ea9e707SThomas Veerman 			x->fval = getfval(y);
11185ea9e707SThomas Veerman 			x->tval |= NUM;
11195ea9e707SThomas Veerman 		}
11205ea9e707SThomas Veerman 		else if (isstr(y))
11215ea9e707SThomas Veerman 			setsval(x, getsval(y));
11225ea9e707SThomas Veerman 		else if (isnum(y))
11235ea9e707SThomas Veerman 			setfval(x, getfval(y));
11245ea9e707SThomas Veerman 		else
11255ea9e707SThomas Veerman 			funnyvar(y, "read value of");
11265ea9e707SThomas Veerman 		tempfree(y);
11275ea9e707SThomas Veerman 		return(x);
11285ea9e707SThomas Veerman 	}
11295ea9e707SThomas Veerman 	xf = getfval(x);
11305ea9e707SThomas Veerman 	yf = getfval(y);
11315ea9e707SThomas Veerman 	switch (n) {
11325ea9e707SThomas Veerman 	case ADDEQ:
11335ea9e707SThomas Veerman 		xf += yf;
11345ea9e707SThomas Veerman 		break;
11355ea9e707SThomas Veerman 	case SUBEQ:
11365ea9e707SThomas Veerman 		xf -= yf;
11375ea9e707SThomas Veerman 		break;
11385ea9e707SThomas Veerman 	case MULTEQ:
11395ea9e707SThomas Veerman 		xf *= yf;
11405ea9e707SThomas Veerman 		break;
11415ea9e707SThomas Veerman 	case DIVEQ:
11425ea9e707SThomas Veerman 		if (yf == 0)
11435ea9e707SThomas Veerman 			FATAL("division by zero in /=");
11445ea9e707SThomas Veerman 		xf /= yf;
11455ea9e707SThomas Veerman 		break;
11465ea9e707SThomas Veerman 	case MODEQ:
11475ea9e707SThomas Veerman 		if (yf == 0)
11485ea9e707SThomas Veerman 			FATAL("division by zero in %%=");
11495ea9e707SThomas Veerman 		modf(xf/yf, &v);
11505ea9e707SThomas Veerman 		xf = xf - yf * v;
11515ea9e707SThomas Veerman 		break;
11525ea9e707SThomas Veerman 	case POWEQ:
11535ea9e707SThomas Veerman 		if (yf >= 0 && modf(yf, &v) == 0.0)	/* pos integer exponent */
11545ea9e707SThomas Veerman 			xf = ipow(xf, (int) yf);
11555ea9e707SThomas Veerman 		else
11565ea9e707SThomas Veerman 			xf = errcheck(pow(xf, yf), "pow");
11575ea9e707SThomas Veerman 		break;
11585ea9e707SThomas Veerman 	default:
11595ea9e707SThomas Veerman 		FATAL("illegal assignment operator %d", n);
11605ea9e707SThomas Veerman 		break;
11615ea9e707SThomas Veerman 	}
11625ea9e707SThomas Veerman 	tempfree(y);
11635ea9e707SThomas Veerman 	setfval(x, xf);
11645ea9e707SThomas Veerman 	return(x);
11655ea9e707SThomas Veerman }
11665ea9e707SThomas Veerman 
cat(Node ** a,int q)11675ea9e707SThomas Veerman Cell *cat(Node **a, int q)	/* a[0] cat a[1] */
11685ea9e707SThomas Veerman {
11695ea9e707SThomas Veerman 	Cell *x, *y, *z;
11705ea9e707SThomas Veerman 	int n1, n2;
11715ea9e707SThomas Veerman 	char *s;
11725ea9e707SThomas Veerman 
11735ea9e707SThomas Veerman 	x = execute(a[0]);
11745ea9e707SThomas Veerman 	y = execute(a[1]);
11755ea9e707SThomas Veerman 	getsval(x);
11765ea9e707SThomas Veerman 	getsval(y);
11775ea9e707SThomas Veerman 	n1 = strlen(x->sval);
11785ea9e707SThomas Veerman 	n2 = strlen(y->sval);
11795ea9e707SThomas Veerman 	s = malloc(n1 + n2 + 1);
11805ea9e707SThomas Veerman 	if (s == NULL)
11815ea9e707SThomas Veerman 		FATAL("out of space concatenating %.15s... and %.15s...",
11825ea9e707SThomas Veerman 			x->sval, y->sval);
11835ea9e707SThomas Veerman 	strcpy(s, x->sval);
11845ea9e707SThomas Veerman 	strcpy(s+n1, y->sval);
11855ea9e707SThomas Veerman 	tempfree(x);
11865ea9e707SThomas Veerman 	tempfree(y);
11875ea9e707SThomas Veerman 	z = gettemp();
11885ea9e707SThomas Veerman 	z->sval = s;
11895ea9e707SThomas Veerman 	z->tval = STR;
11905ea9e707SThomas Veerman 	return(z);
11915ea9e707SThomas Veerman }
11925ea9e707SThomas Veerman 
pastat(Node ** a,int n)11935ea9e707SThomas Veerman Cell *pastat(Node **a, int n)	/* a[0] { a[1] } */
11945ea9e707SThomas Veerman {
11955ea9e707SThomas Veerman 	Cell *x;
11965ea9e707SThomas Veerman 
11975ea9e707SThomas Veerman 	if (a[0] == 0)
11985ea9e707SThomas Veerman 		x = execute(a[1]);
11995ea9e707SThomas Veerman 	else {
12005ea9e707SThomas Veerman 		x = execute(a[0]);
12015ea9e707SThomas Veerman 		if (istrue(x)) {
12025ea9e707SThomas Veerman 			tempfree(x);
12035ea9e707SThomas Veerman 			x = execute(a[1]);
12045ea9e707SThomas Veerman 		}
12055ea9e707SThomas Veerman 	}
12065ea9e707SThomas Veerman 	return x;
12075ea9e707SThomas Veerman }
12085ea9e707SThomas Veerman 
dopa2(Node ** a,int n)12095ea9e707SThomas Veerman Cell *dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
12105ea9e707SThomas Veerman {
12115ea9e707SThomas Veerman 	Cell *x;
12125ea9e707SThomas Veerman 	int pair;
12135ea9e707SThomas Veerman 
12145ea9e707SThomas Veerman 	pair = ptoi(a[3]);
12155ea9e707SThomas Veerman 	if (pairstack[pair] == 0) {
12165ea9e707SThomas Veerman 		x = execute(a[0]);
12175ea9e707SThomas Veerman 		if (istrue(x))
12185ea9e707SThomas Veerman 			pairstack[pair] = 1;
12195ea9e707SThomas Veerman 		tempfree(x);
12205ea9e707SThomas Veerman 	}
12215ea9e707SThomas Veerman 	if (pairstack[pair] == 1) {
12225ea9e707SThomas Veerman 		x = execute(a[1]);
12235ea9e707SThomas Veerman 		if (istrue(x))
12245ea9e707SThomas Veerman 			pairstack[pair] = 0;
12255ea9e707SThomas Veerman 		tempfree(x);
12265ea9e707SThomas Veerman 		x = execute(a[2]);
12275ea9e707SThomas Veerman 		return(x);
12285ea9e707SThomas Veerman 	}
12295ea9e707SThomas Veerman 	return(False);
12305ea9e707SThomas Veerman }
12315ea9e707SThomas Veerman 
12325ea9e707SThomas Veerman static char regexpr[] = "(regexpr)";
split(Node ** a,int nnn)12335ea9e707SThomas Veerman Cell *split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
12345ea9e707SThomas Veerman {
12355ea9e707SThomas Veerman 	Cell *x = 0, *y, *ap;
123684d9c625SLionel Sambuc 	char *s, *origs;
12375ea9e707SThomas Veerman 	int sep;
12385ea9e707SThomas Veerman 	char *t, temp, num[50], *fs = 0;
12395ea9e707SThomas Veerman 	int n, tempstat, arg3type;
12405ea9e707SThomas Veerman 
12415ea9e707SThomas Veerman 	y = execute(a[0]);	/* source string */
124284d9c625SLionel Sambuc 	origs = s = strdup(getsval(y));
12435ea9e707SThomas Veerman 	arg3type = ptoi(a[3]);
12445ea9e707SThomas Veerman 	if (a[2] == 0)		/* fs string */
12455ea9e707SThomas Veerman 		fs = *FS;
12465ea9e707SThomas Veerman 	else if (arg3type == STRING) {	/* split(str,arr,"string") */
12475ea9e707SThomas Veerman 		x = execute(a[2]);
12485ea9e707SThomas Veerman 		fs = getsval(x);
12495ea9e707SThomas Veerman 	} else if (arg3type == REGEXPR)
12505ea9e707SThomas Veerman 		fs = regexpr;	/* split(str,arr,/regexpr/) */
12515ea9e707SThomas Veerman 	else
12525ea9e707SThomas Veerman 		FATAL("illegal type of split");
12535ea9e707SThomas Veerman 	sep = *fs;
12545ea9e707SThomas Veerman 	ap = execute(a[1]);	/* array name */
12555ea9e707SThomas Veerman 	freesymtab(ap);
12565ea9e707SThomas Veerman 	   dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs) );
12575ea9e707SThomas Veerman 	ap->tval &= ~STR;
12585ea9e707SThomas Veerman 	ap->tval |= ARR;
12595ea9e707SThomas Veerman 	ap->sval = (char *) makesymtab(NSYMTAB);
12605ea9e707SThomas Veerman 
12615ea9e707SThomas Veerman 	n = 0;
126284d9c625SLionel Sambuc         if (arg3type == REGEXPR && strlen((char*)((fa*)a[2])->restr) == 0) {
126384d9c625SLionel Sambuc 		/* split(s, a, //); have to arrange that it looks like empty sep */
126484d9c625SLionel Sambuc 		arg3type = 0;
126584d9c625SLionel Sambuc 		fs = EMPTY;
126684d9c625SLionel Sambuc 		sep = 0;
126784d9c625SLionel Sambuc 	}
12685ea9e707SThomas Veerman 	if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) {	/* reg expr */
12695ea9e707SThomas Veerman 		fa *pfa;
12705ea9e707SThomas Veerman 		if (arg3type == REGEXPR) {	/* it's ready already */
12715ea9e707SThomas Veerman 			pfa = (fa *) a[2];
12725ea9e707SThomas Veerman 		} else {
12735ea9e707SThomas Veerman 			pfa = makedfa(fs, 1);
12745ea9e707SThomas Veerman 		}
12755ea9e707SThomas Veerman 		if (nematch(pfa,s)) {
12765ea9e707SThomas Veerman 			tempstat = pfa->initstat;
12775ea9e707SThomas Veerman 			pfa->initstat = 2;
12785ea9e707SThomas Veerman 			do {
12795ea9e707SThomas Veerman 				n++;
12805ea9e707SThomas Veerman 				snprintf(num, sizeof(num), "%d", n);
12815ea9e707SThomas Veerman 				temp = *patbeg;
12825ea9e707SThomas Veerman 				*patbeg = '\0';
12835ea9e707SThomas Veerman 				if (is_number(s))
12845ea9e707SThomas Veerman 					setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
12855ea9e707SThomas Veerman 				else
12865ea9e707SThomas Veerman 					setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
12875ea9e707SThomas Veerman 				*patbeg = temp;
12885ea9e707SThomas Veerman 				s = patbeg + patlen;
12895ea9e707SThomas Veerman 				if (*(patbeg+patlen-1) == 0 || *s == 0) {
12905ea9e707SThomas Veerman 					n++;
12915ea9e707SThomas Veerman 					snprintf(num, sizeof(num), "%d", n);
12925ea9e707SThomas Veerman 					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
12935ea9e707SThomas Veerman 					pfa->initstat = tempstat;
12945ea9e707SThomas Veerman 					goto spdone;
12955ea9e707SThomas Veerman 				}
12965ea9e707SThomas Veerman 			} while (nematch(pfa,s));
12975ea9e707SThomas Veerman 			pfa->initstat = tempstat; 	/* bwk: has to be here to reset */
12985ea9e707SThomas Veerman 							/* cf gsub and refldbld */
12995ea9e707SThomas Veerman 		}
13005ea9e707SThomas Veerman 		n++;
13015ea9e707SThomas Veerman 		snprintf(num, sizeof(num), "%d", n);
13025ea9e707SThomas Veerman 		if (is_number(s))
13035ea9e707SThomas Veerman 			setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
13045ea9e707SThomas Veerman 		else
13055ea9e707SThomas Veerman 			setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
13065ea9e707SThomas Veerman   spdone:
13075ea9e707SThomas Veerman 		pfa = NULL;
13085ea9e707SThomas Veerman 	} else if (sep == ' ') {
13095ea9e707SThomas Veerman 		for (n = 0; ; ) {
13105ea9e707SThomas Veerman 			while (*s == ' ' || *s == '\t' || *s == '\n')
13115ea9e707SThomas Veerman 				s++;
13125ea9e707SThomas Veerman 			if (*s == 0)
13135ea9e707SThomas Veerman 				break;
13145ea9e707SThomas Veerman 			n++;
13155ea9e707SThomas Veerman 			t = s;
13165ea9e707SThomas Veerman 			do
13175ea9e707SThomas Veerman 				s++;
13185ea9e707SThomas Veerman 			while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
13195ea9e707SThomas Veerman 			temp = *s;
13205ea9e707SThomas Veerman 			*s = '\0';
13215ea9e707SThomas Veerman 			snprintf(num, sizeof(num), "%d", n);
13225ea9e707SThomas Veerman 			if (is_number(t))
13235ea9e707SThomas Veerman 				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
13245ea9e707SThomas Veerman 			else
13255ea9e707SThomas Veerman 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
13265ea9e707SThomas Veerman 			*s = temp;
13275ea9e707SThomas Veerman 			if (*s != 0)
13285ea9e707SThomas Veerman 				s++;
13295ea9e707SThomas Veerman 		}
13305ea9e707SThomas Veerman 	} else if (sep == 0) {	/* new: split(s, a, "") => 1 char/elem */
13315ea9e707SThomas Veerman 		for (n = 0; *s != 0; s++) {
13325ea9e707SThomas Veerman 			char buf[2];
13335ea9e707SThomas Veerman 			n++;
13345ea9e707SThomas Veerman 			snprintf(num, sizeof(num), "%d", n);
13355ea9e707SThomas Veerman 			buf[0] = *s;
13365ea9e707SThomas Veerman 			buf[1] = 0;
13375ea9e707SThomas Veerman 			if (isdigit((uschar)buf[0]))
13385ea9e707SThomas Veerman 				setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
13395ea9e707SThomas Veerman 			else
13405ea9e707SThomas Veerman 				setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
13415ea9e707SThomas Veerman 		}
13425ea9e707SThomas Veerman 	} else if (*s != 0) {
13435ea9e707SThomas Veerman 		for (;;) {
13445ea9e707SThomas Veerman 			n++;
13455ea9e707SThomas Veerman 			t = s;
13465ea9e707SThomas Veerman 			while (*s != sep && *s != '\n' && *s != '\0')
13475ea9e707SThomas Veerman 				s++;
13485ea9e707SThomas Veerman 			temp = *s;
13495ea9e707SThomas Veerman 			*s = '\0';
13505ea9e707SThomas Veerman 			snprintf(num, sizeof(num), "%d", n);
13515ea9e707SThomas Veerman 			if (is_number(t))
13525ea9e707SThomas Veerman 				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
13535ea9e707SThomas Veerman 			else
13545ea9e707SThomas Veerman 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
13555ea9e707SThomas Veerman 			*s = temp;
13565ea9e707SThomas Veerman 			if (*s++ == 0)
13575ea9e707SThomas Veerman 				break;
13585ea9e707SThomas Veerman 		}
13595ea9e707SThomas Veerman 	}
13605ea9e707SThomas Veerman 	tempfree(ap);
13615ea9e707SThomas Veerman 	tempfree(y);
136284d9c625SLionel Sambuc 	free(origs);
13635ea9e707SThomas Veerman 	if (a[2] != 0 && arg3type == STRING) {
13645ea9e707SThomas Veerman 		tempfree(x);
13655ea9e707SThomas Veerman 	}
13665ea9e707SThomas Veerman 	x = gettemp();
13675ea9e707SThomas Veerman 	x->tval = NUM;
13685ea9e707SThomas Veerman 	x->fval = n;
13695ea9e707SThomas Veerman 	return(x);
13705ea9e707SThomas Veerman }
13715ea9e707SThomas Veerman 
condexpr(Node ** a,int n)13725ea9e707SThomas Veerman Cell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
13735ea9e707SThomas Veerman {
13745ea9e707SThomas Veerman 	Cell *x;
13755ea9e707SThomas Veerman 
13765ea9e707SThomas Veerman 	x = execute(a[0]);
13775ea9e707SThomas Veerman 	if (istrue(x)) {
13785ea9e707SThomas Veerman 		tempfree(x);
13795ea9e707SThomas Veerman 		x = execute(a[1]);
13805ea9e707SThomas Veerman 	} else {
13815ea9e707SThomas Veerman 		tempfree(x);
13825ea9e707SThomas Veerman 		x = execute(a[2]);
13835ea9e707SThomas Veerman 	}
13845ea9e707SThomas Veerman 	return(x);
13855ea9e707SThomas Veerman }
13865ea9e707SThomas Veerman 
ifstat(Node ** a,int n)13875ea9e707SThomas Veerman Cell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
13885ea9e707SThomas Veerman {
13895ea9e707SThomas Veerman 	Cell *x;
13905ea9e707SThomas Veerman 
13915ea9e707SThomas Veerman 	x = execute(a[0]);
13925ea9e707SThomas Veerman 	if (istrue(x)) {
13935ea9e707SThomas Veerman 		tempfree(x);
13945ea9e707SThomas Veerman 		x = execute(a[1]);
13955ea9e707SThomas Veerman 	} else if (a[2] != 0) {
13965ea9e707SThomas Veerman 		tempfree(x);
13975ea9e707SThomas Veerman 		x = execute(a[2]);
13985ea9e707SThomas Veerman 	}
13995ea9e707SThomas Veerman 	return(x);
14005ea9e707SThomas Veerman }
14015ea9e707SThomas Veerman 
whilestat(Node ** a,int n)14025ea9e707SThomas Veerman Cell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
14035ea9e707SThomas Veerman {
14045ea9e707SThomas Veerman 	Cell *x;
14055ea9e707SThomas Veerman 
14065ea9e707SThomas Veerman 	for (;;) {
14075ea9e707SThomas Veerman 		x = execute(a[0]);
14085ea9e707SThomas Veerman 		if (!istrue(x))
14095ea9e707SThomas Veerman 			return(x);
14105ea9e707SThomas Veerman 		tempfree(x);
14115ea9e707SThomas Veerman 		x = execute(a[1]);
14125ea9e707SThomas Veerman 		if (isbreak(x)) {
14135ea9e707SThomas Veerman 			x = True;
14145ea9e707SThomas Veerman 			return(x);
14155ea9e707SThomas Veerman 		}
14165ea9e707SThomas Veerman 		if (isnext(x) || isexit(x) || isret(x))
14175ea9e707SThomas Veerman 			return(x);
14185ea9e707SThomas Veerman 		tempfree(x);
14195ea9e707SThomas Veerman 	}
14205ea9e707SThomas Veerman }
14215ea9e707SThomas Veerman 
dostat(Node ** a,int n)14225ea9e707SThomas Veerman Cell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
14235ea9e707SThomas Veerman {
14245ea9e707SThomas Veerman 	Cell *x;
14255ea9e707SThomas Veerman 
14265ea9e707SThomas Veerman 	for (;;) {
14275ea9e707SThomas Veerman 		x = execute(a[0]);
14285ea9e707SThomas Veerman 		if (isbreak(x))
14295ea9e707SThomas Veerman 			return True;
14305ea9e707SThomas Veerman 		if (isnext(x) || isexit(x) || isret(x))
14315ea9e707SThomas Veerman 			return(x);
14325ea9e707SThomas Veerman 		tempfree(x);
14335ea9e707SThomas Veerman 		x = execute(a[1]);
14345ea9e707SThomas Veerman 		if (!istrue(x))
14355ea9e707SThomas Veerman 			return(x);
14365ea9e707SThomas Veerman 		tempfree(x);
14375ea9e707SThomas Veerman 	}
14385ea9e707SThomas Veerman }
14395ea9e707SThomas Veerman 
forstat(Node ** a,int n)14405ea9e707SThomas Veerman Cell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
14415ea9e707SThomas Veerman {
14425ea9e707SThomas Veerman 	Cell *x;
14435ea9e707SThomas Veerman 
14445ea9e707SThomas Veerman 	x = execute(a[0]);
14455ea9e707SThomas Veerman 	tempfree(x);
14465ea9e707SThomas Veerman 	for (;;) {
14475ea9e707SThomas Veerman 		if (a[1]!=0) {
14485ea9e707SThomas Veerman 			x = execute(a[1]);
14495ea9e707SThomas Veerman 			if (!istrue(x)) return(x);
14505ea9e707SThomas Veerman 			else tempfree(x);
14515ea9e707SThomas Veerman 		}
14525ea9e707SThomas Veerman 		x = execute(a[3]);
14535ea9e707SThomas Veerman 		if (isbreak(x))		/* turn off break */
14545ea9e707SThomas Veerman 			return True;
14555ea9e707SThomas Veerman 		if (isnext(x) || isexit(x) || isret(x))
14565ea9e707SThomas Veerman 			return(x);
14575ea9e707SThomas Veerman 		tempfree(x);
14585ea9e707SThomas Veerman 		x = execute(a[2]);
14595ea9e707SThomas Veerman 		tempfree(x);
14605ea9e707SThomas Veerman 	}
14615ea9e707SThomas Veerman }
14625ea9e707SThomas Veerman 
instat(Node ** a,int n)14635ea9e707SThomas Veerman Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
14645ea9e707SThomas Veerman {
14655ea9e707SThomas Veerman 	Cell *x, *vp, *arrayp, *cp, *ncp;
14665ea9e707SThomas Veerman 	Array *tp;
14675ea9e707SThomas Veerman 	int i;
14685ea9e707SThomas Veerman 
14695ea9e707SThomas Veerman 	vp = execute(a[0]);
14705ea9e707SThomas Veerman 	arrayp = execute(a[1]);
14715ea9e707SThomas Veerman 	if (!isarr(arrayp)) {
14725ea9e707SThomas Veerman 		return True;
14735ea9e707SThomas Veerman 	}
14745ea9e707SThomas Veerman 	tp = (Array *) arrayp->sval;
14755ea9e707SThomas Veerman 	tempfree(arrayp);
14765ea9e707SThomas Veerman 	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
14775ea9e707SThomas Veerman 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
14785ea9e707SThomas Veerman 			setsval(vp, cp->nval);
14795ea9e707SThomas Veerman 			ncp = cp->cnext;
14805ea9e707SThomas Veerman 			x = execute(a[2]);
14815ea9e707SThomas Veerman 			if (isbreak(x)) {
14825ea9e707SThomas Veerman 				tempfree(vp);
14835ea9e707SThomas Veerman 				return True;
14845ea9e707SThomas Veerman 			}
14855ea9e707SThomas Veerman 			if (isnext(x) || isexit(x) || isret(x)) {
14865ea9e707SThomas Veerman 				tempfree(vp);
14875ea9e707SThomas Veerman 				return(x);
14885ea9e707SThomas Veerman 			}
14895ea9e707SThomas Veerman 			tempfree(x);
14905ea9e707SThomas Veerman 		}
14915ea9e707SThomas Veerman 	}
14925ea9e707SThomas Veerman 	return True;
14935ea9e707SThomas Veerman }
14945ea9e707SThomas Veerman 
14955ea9e707SThomas Veerman void flush_all(void);
14965ea9e707SThomas Veerman 
nawk_toXXX(const char * s,int (* fun_c)(int),wint_t (* fun_wc)(wint_t))14975ea9e707SThomas Veerman static char *nawk_toXXX(const char *s,
14985ea9e707SThomas Veerman 			int (*fun_c)(int),
14995ea9e707SThomas Veerman 			wint_t (*fun_wc)(wint_t))
15005ea9e707SThomas Veerman {
15015ea9e707SThomas Veerman 	char *buf      = NULL;
15025ea9e707SThomas Veerman 	char *pbuf     = NULL;
15035ea9e707SThomas Veerman 	const char *ps = NULL;
15045ea9e707SThomas Veerman 	size_t n       = 0;
15055ea9e707SThomas Veerman 	mbstate_t mbs, mbs2;
15065ea9e707SThomas Veerman 	wchar_t wc;
15075ea9e707SThomas Veerman 	size_t sz = MB_CUR_MAX;
15085ea9e707SThomas Veerman 
15095ea9e707SThomas Veerman 	if (sz == 1) {
15105ea9e707SThomas Veerman 		buf = tostring(s);
15115ea9e707SThomas Veerman 
15125ea9e707SThomas Veerman 		for (pbuf = buf; *pbuf; pbuf++)
15135ea9e707SThomas Veerman 			*pbuf = fun_c((uschar)*pbuf);
15145ea9e707SThomas Veerman 
15155ea9e707SThomas Veerman 		return buf;
15165ea9e707SThomas Veerman 	} else {
15175ea9e707SThomas Veerman 		/* upper/lower character may be shorter/longer */
15185ea9e707SThomas Veerman 		buf = tostringN(s, strlen(s) * sz + 1);
15195ea9e707SThomas Veerman 
15205ea9e707SThomas Veerman 		memset(&mbs,  0, sizeof(mbs));
15215ea9e707SThomas Veerman 		memset(&mbs2, 0, sizeof(mbs2));
15225ea9e707SThomas Veerman 
15235ea9e707SThomas Veerman 		ps   = s;
15245ea9e707SThomas Veerman 		pbuf = buf;
15255ea9e707SThomas Veerman 		while (n = mbrtowc(&wc, ps, sz, &mbs),
15265ea9e707SThomas Veerman 		       n > 0 && n != (size_t)-1 && n != (size_t)-2)
15275ea9e707SThomas Veerman 		{
15285ea9e707SThomas Veerman 			ps += n;
15295ea9e707SThomas Veerman 
15305ea9e707SThomas Veerman 			n = wcrtomb(pbuf, fun_wc(wc), &mbs2);
15315ea9e707SThomas Veerman 			if (n == (size_t)-1)
15325ea9e707SThomas Veerman 				FATAL("illegal wide character %s", s);
15335ea9e707SThomas Veerman 
15345ea9e707SThomas Veerman 			pbuf += n;
15355ea9e707SThomas Veerman 		}
15365ea9e707SThomas Veerman 
15375ea9e707SThomas Veerman 		*pbuf = 0;
15385ea9e707SThomas Veerman 
15395ea9e707SThomas Veerman 		if (n)
15405ea9e707SThomas Veerman 			FATAL("illegal byte sequence %s", s);
15415ea9e707SThomas Veerman 
15425ea9e707SThomas Veerman 		return buf;
15435ea9e707SThomas Veerman 	}
15445ea9e707SThomas Veerman }
15455ea9e707SThomas Veerman 
nawk_toupper(const char * s)15465ea9e707SThomas Veerman static char *nawk_toupper(const char *s)
15475ea9e707SThomas Veerman {
15485ea9e707SThomas Veerman 	return nawk_toXXX(s, toupper, towupper);
15495ea9e707SThomas Veerman }
15505ea9e707SThomas Veerman 
nawk_tolower(const char * s)15515ea9e707SThomas Veerman static char *nawk_tolower(const char *s)
15525ea9e707SThomas Veerman {
15535ea9e707SThomas Veerman 	return nawk_toXXX(s, tolower, towlower);
15545ea9e707SThomas Veerman }
15555ea9e707SThomas Veerman 
bltin(Node ** a,int n)15565ea9e707SThomas Veerman Cell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
15575ea9e707SThomas Veerman {
15585ea9e707SThomas Veerman 	Cell *x, *y;
15595ea9e707SThomas Veerman 	Awkfloat u;
15605ea9e707SThomas Veerman 	int t, sz;
15615ea9e707SThomas Veerman 	unsigned int tmp;
15625ea9e707SThomas Veerman 	char *buf, *fmt;
15635ea9e707SThomas Veerman 	Node *nextarg;
15645ea9e707SThomas Veerman 	FILE *fp;
15655ea9e707SThomas Veerman 	time_t tv;
15665ea9e707SThomas Veerman 	struct tm *tm;
15675ea9e707SThomas Veerman 
15685ea9e707SThomas Veerman 	t = ptoi(a[0]);
15695ea9e707SThomas Veerman 	x = execute(a[1]);
15705ea9e707SThomas Veerman 	nextarg = a[1]->nnext;
15715ea9e707SThomas Veerman 	switch (t) {
15725ea9e707SThomas Veerman 	case FLENGTH:
15735ea9e707SThomas Veerman 		if (isarr(x))
15745ea9e707SThomas Veerman 			u = ((Array *) x->sval)->nelem;	/* GROT.  should be function*/
15755ea9e707SThomas Veerman 		else
15765ea9e707SThomas Veerman 			u = strlen(getsval(x));
15775ea9e707SThomas Veerman 		break;
15785ea9e707SThomas Veerman 	case FLOG:
15795ea9e707SThomas Veerman 		u = errcheck(log(getfval(x)), "log"); break;
15805ea9e707SThomas Veerman 	case FINT:
15815ea9e707SThomas Veerman 		modf(getfval(x), &u); break;
15825ea9e707SThomas Veerman 	case FEXP:
15835ea9e707SThomas Veerman 		u = errcheck(exp(getfval(x)), "exp"); break;
15845ea9e707SThomas Veerman 	case FSQRT:
15855ea9e707SThomas Veerman 		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
15865ea9e707SThomas Veerman 	case FSIN:
15875ea9e707SThomas Veerman 		u = sin(getfval(x)); break;
15885ea9e707SThomas Veerman 	case FCOS:
15895ea9e707SThomas Veerman 		u = cos(getfval(x)); break;
15905ea9e707SThomas Veerman 	case FATAN:
15915ea9e707SThomas Veerman 		if (nextarg == 0) {
15925ea9e707SThomas Veerman 			WARNING("atan2 requires two arguments; returning 1.0");
15935ea9e707SThomas Veerman 			u = 1.0;
15945ea9e707SThomas Veerman 		} else {
15955ea9e707SThomas Veerman 			y = execute(a[1]->nnext);
15965ea9e707SThomas Veerman 			u = atan2(getfval(x), getfval(y));
15975ea9e707SThomas Veerman 			tempfree(y);
15985ea9e707SThomas Veerman 			nextarg = nextarg->nnext;
15995ea9e707SThomas Veerman 		}
16005ea9e707SThomas Veerman 		break;
16015ea9e707SThomas Veerman 	case FSYSTEM:
16025ea9e707SThomas Veerman 		fflush(stdout);		/* in case something is buffered already */
16035ea9e707SThomas Veerman 		u = (Awkfloat) system(getsval(x)) / 256;   /* 256 is unix-dep */
16045ea9e707SThomas Veerman 		break;
16055ea9e707SThomas Veerman 	case FRAND:
16065ea9e707SThomas Veerman 		/* in principle, rand() returns something in 0..RAND_MAX */
16075ea9e707SThomas Veerman 		u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
16085ea9e707SThomas Veerman 		break;
16095ea9e707SThomas Veerman 	case FSRAND:
16105ea9e707SThomas Veerman 		if (isrec(x))	/* no argument provided */
16115ea9e707SThomas Veerman 			u = time((time_t *)0);
16125ea9e707SThomas Veerman 		else
16135ea9e707SThomas Veerman 			u = getfval(x);
161484d9c625SLionel Sambuc 		tmp = (unsigned int) u;
161584d9c625SLionel Sambuc 		srand(tmp);
16165ea9e707SThomas Veerman 		u = srand_seed;
16175ea9e707SThomas Veerman 		srand_seed = tmp;
16185ea9e707SThomas Veerman 		break;
16195ea9e707SThomas Veerman 	case FTOUPPER:
16205ea9e707SThomas Veerman 	case FTOLOWER:
16215ea9e707SThomas Veerman 		if (t == FTOUPPER)
16225ea9e707SThomas Veerman 			buf = nawk_toupper(getsval(x));
16235ea9e707SThomas Veerman 		else
16245ea9e707SThomas Veerman 			buf = nawk_tolower(getsval(x));
16255ea9e707SThomas Veerman 		tempfree(x);
16265ea9e707SThomas Veerman 		x = gettemp();
16275ea9e707SThomas Veerman 		setsval(x, buf);
16285ea9e707SThomas Veerman 		free(buf);
16295ea9e707SThomas Veerman 		return x;
16305ea9e707SThomas Veerman 	case FFLUSH:
16315ea9e707SThomas Veerman 		if (isrec(x) || strlen(getsval(x)) == 0) {
16325ea9e707SThomas Veerman 			flush_all();	/* fflush() or fflush("") -> all */
16335ea9e707SThomas Veerman 			u = 0;
16345ea9e707SThomas Veerman 		} else if ((fp = openfile(FFLUSH, getsval(x), NULL)) == NULL)
16355ea9e707SThomas Veerman 			u = -1;
16365ea9e707SThomas Veerman 		else
16375ea9e707SThomas Veerman 			u = fflush(fp);
16385ea9e707SThomas Veerman 		break;
16395ea9e707SThomas Veerman 	case FSYSTIME:
16405ea9e707SThomas Veerman 		u = time((time_t *) 0); break;
16415ea9e707SThomas Veerman 	case FSTRFTIME:
16425ea9e707SThomas Veerman 		/* strftime([format [,timestamp]]) */
16435ea9e707SThomas Veerman 		if (nextarg) {
16445ea9e707SThomas Veerman 			y = execute(nextarg), nextarg = nextarg->nnext;
16455ea9e707SThomas Veerman 			tv = (time_t) getfval(y);
16465ea9e707SThomas Veerman 			tempfree(y);
16475ea9e707SThomas Veerman 		} else
16485ea9e707SThomas Veerman 			tv = time((time_t *) 0);
16495ea9e707SThomas Veerman 		tm = localtime(&tv);
1650*0a6a1f1dSLionel Sambuc 		if (tm == NULL)
1651*0a6a1f1dSLionel Sambuc 			FATAL("bad time %jd", (intmax_t)tv);
16525ea9e707SThomas Veerman 
16535ea9e707SThomas Veerman 		if (isrec(x)) {
16545ea9e707SThomas Veerman 			/* format argument not provided, use default */
16555ea9e707SThomas Veerman 			fmt = tostring("%a %b %d %H:%M:%S %Z %Y");
16565ea9e707SThomas Veerman 		} else
16575ea9e707SThomas Veerman 			fmt = tostring(getsval(x));
16585ea9e707SThomas Veerman 
16595ea9e707SThomas Veerman 		sz = 32, buf = NULL;
16605ea9e707SThomas Veerman 		do {
16615ea9e707SThomas Veerman 			if ((buf = realloc(buf, (sz *= 2))) == NULL)
16625ea9e707SThomas Veerman 				FATAL("out of memory in strftime");
16635ea9e707SThomas Veerman 		} while(strftime(buf, sz, fmt, tm) == 0);
16645ea9e707SThomas Veerman 
16655ea9e707SThomas Veerman 		y = gettemp();
16665ea9e707SThomas Veerman 		setsval(y, buf);
16675ea9e707SThomas Veerman 		free(fmt);
16685ea9e707SThomas Veerman 		free(buf);
16695ea9e707SThomas Veerman 
16705ea9e707SThomas Veerman 		return y;
16715ea9e707SThomas Veerman 	default:	/* can't happen */
16725ea9e707SThomas Veerman 		FATAL("illegal function type %d", t);
16735ea9e707SThomas Veerman 		break;
16745ea9e707SThomas Veerman 	}
16755ea9e707SThomas Veerman 	tempfree(x);
16765ea9e707SThomas Veerman 	x = gettemp();
16775ea9e707SThomas Veerman 	setfval(x, u);
16785ea9e707SThomas Veerman 	if (nextarg != 0) {
16795ea9e707SThomas Veerman 		WARNING("warning: function has too many arguments");
16805ea9e707SThomas Veerman 		for ( ; nextarg; nextarg = nextarg->nnext)
16815ea9e707SThomas Veerman 			execute(nextarg);
16825ea9e707SThomas Veerman 	}
16835ea9e707SThomas Veerman 	return(x);
16845ea9e707SThomas Veerman }
16855ea9e707SThomas Veerman 
printstat(Node ** a,int n)16865ea9e707SThomas Veerman Cell *printstat(Node **a, int n)	/* print a[0] */
16875ea9e707SThomas Veerman {
16885ea9e707SThomas Veerman 	Node *x;
16895ea9e707SThomas Veerman 	Cell *y;
16905ea9e707SThomas Veerman 	FILE *fp;
16915ea9e707SThomas Veerman 
16925ea9e707SThomas Veerman 	if (a[1] == 0)	/* a[1] is redirection operator, a[2] is file */
16935ea9e707SThomas Veerman 		fp = stdout;
16945ea9e707SThomas Veerman 	else
16955ea9e707SThomas Veerman 		fp = redirect(ptoi(a[1]), a[2]);
16965ea9e707SThomas Veerman 	for (x = a[0]; x != NULL; x = x->nnext) {
16975ea9e707SThomas Veerman 		y = execute(x);
16985ea9e707SThomas Veerman 		fputs(getpssval(y), fp);
16995ea9e707SThomas Veerman 		tempfree(y);
17005ea9e707SThomas Veerman 		if (x->nnext == NULL)
17015ea9e707SThomas Veerman 			fputs(*ORS, fp);
17025ea9e707SThomas Veerman 		else
17035ea9e707SThomas Veerman 			fputs(*OFS, fp);
17045ea9e707SThomas Veerman 	}
17055ea9e707SThomas Veerman 	if (a[1] != 0)
17065ea9e707SThomas Veerman 		fflush(fp);
17075ea9e707SThomas Veerman 	if (ferror(fp))
17085ea9e707SThomas Veerman 		FATAL("write error on %s", filename(fp));
17095ea9e707SThomas Veerman 	return(True);
17105ea9e707SThomas Veerman }
17115ea9e707SThomas Veerman 
nullproc(Node ** a,int n)17125ea9e707SThomas Veerman Cell *nullproc(Node **a, int n)
17135ea9e707SThomas Veerman {
17145ea9e707SThomas Veerman 	n = n;
17155ea9e707SThomas Veerman 	a = a;
17165ea9e707SThomas Veerman 	return 0;
17175ea9e707SThomas Veerman }
17185ea9e707SThomas Veerman 
17195ea9e707SThomas Veerman 
redirect(int a,Node * b)17205ea9e707SThomas Veerman FILE *redirect(int a, Node *b)	/* set up all i/o redirections */
17215ea9e707SThomas Veerman {
17225ea9e707SThomas Veerman 	FILE *fp;
17235ea9e707SThomas Veerman 	Cell *x;
17245ea9e707SThomas Veerman 	char *fname;
17255ea9e707SThomas Veerman 
17265ea9e707SThomas Veerman 	x = execute(b);
17275ea9e707SThomas Veerman 	fname = getsval(x);
17285ea9e707SThomas Veerman 	fp = openfile(a, fname, NULL);
17295ea9e707SThomas Veerman 	if (fp == NULL)
17305ea9e707SThomas Veerman 		FATAL("can't open file %s", fname);
17315ea9e707SThomas Veerman 	tempfree(x);
17325ea9e707SThomas Veerman 	return fp;
17335ea9e707SThomas Veerman }
17345ea9e707SThomas Veerman 
17355ea9e707SThomas Veerman struct files {
17365ea9e707SThomas Veerman 	FILE	*fp;
17375ea9e707SThomas Veerman 	const char	*fname;
17385ea9e707SThomas Veerman 	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
17395ea9e707SThomas Veerman } *files;
174084d9c625SLionel Sambuc 
17415ea9e707SThomas Veerman size_t nfiles;
17425ea9e707SThomas Veerman 
stdinit(void)17435ea9e707SThomas Veerman void stdinit(void)	/* in case stdin, etc., are not constants */
17445ea9e707SThomas Veerman {
17455ea9e707SThomas Veerman 	nfiles = FOPEN_MAX;
17465ea9e707SThomas Veerman 	files = calloc(nfiles, sizeof(*files));
17475ea9e707SThomas Veerman 	if (files == NULL)
17485ea9e707SThomas Veerman 		FATAL("can't allocate file memory for %zu files", nfiles);
17495ea9e707SThomas Veerman 	files[0].fp = stdin;
17505ea9e707SThomas Veerman 	files[0].fname = "/dev/stdin";
17515ea9e707SThomas Veerman 	files[0].mode = LT;
17525ea9e707SThomas Veerman 	files[1].fp = stdout;
17535ea9e707SThomas Veerman 	files[1].fname = "/dev/stdout";
17545ea9e707SThomas Veerman 	files[1].mode = GT;
17555ea9e707SThomas Veerman 	files[2].fp = stderr;
17565ea9e707SThomas Veerman 	files[2].fname = "/dev/stderr";
17575ea9e707SThomas Veerman 	files[2].mode = GT;
17585ea9e707SThomas Veerman }
17595ea9e707SThomas Veerman 
openfile(int a,const char * us,int * pnewflag)17605ea9e707SThomas Veerman FILE *openfile(int a, const char *us, int *pnewflag)
17615ea9e707SThomas Veerman {
17625ea9e707SThomas Veerman 	const char *s = us;
17635ea9e707SThomas Veerman 	size_t i;
17645ea9e707SThomas Veerman 	int m;
17655ea9e707SThomas Veerman 	FILE *fp = 0;
17665ea9e707SThomas Veerman 
17675ea9e707SThomas Veerman 	if (*s == '\0')
17685ea9e707SThomas Veerman 		FATAL("null file name in print or getline");
17695ea9e707SThomas Veerman 	for (i = 0; i < nfiles; i++)
17705ea9e707SThomas Veerman 		if (files[i].fname && strcmp(s, files[i].fname) == 0 &&
17715ea9e707SThomas Veerman 		    (a == files[i].mode || (a==APPEND && files[i].mode==GT) ||
17725ea9e707SThomas Veerman 		     a == FFLUSH)) {
17735ea9e707SThomas Veerman 			if (pnewflag)
17745ea9e707SThomas Veerman 				*pnewflag = 0;
17755ea9e707SThomas Veerman 			return files[i].fp;
17765ea9e707SThomas Veerman 		}
17775ea9e707SThomas Veerman 	if (a == FFLUSH)	/* didn't find it, so don't create it! */
17785ea9e707SThomas Veerman 		return NULL;
17795ea9e707SThomas Veerman 
17805ea9e707SThomas Veerman 	for (i = 0; i < nfiles; i++)
17815ea9e707SThomas Veerman 		if (files[i].fp == NULL)
17825ea9e707SThomas Veerman 			break;
17835ea9e707SThomas Veerman 	if (i >= nfiles) {
17845ea9e707SThomas Veerman 		struct files *nf;
17855ea9e707SThomas Veerman 		size_t nnf = nfiles + FOPEN_MAX;
17865ea9e707SThomas Veerman 		nf = realloc(files, nnf * sizeof(*nf));
17875ea9e707SThomas Veerman 		if (nf == NULL)
17885ea9e707SThomas Veerman 			FATAL("cannot grow files for %s and %zu files", s, nnf);
17895ea9e707SThomas Veerman 		(void)memset(&nf[nfiles], 0, FOPEN_MAX * sizeof(*nf));
17905ea9e707SThomas Veerman 		nfiles = nnf;
17915ea9e707SThomas Veerman 		files = nf;
17925ea9e707SThomas Veerman 	}
17935ea9e707SThomas Veerman 	fflush(stdout);	/* force a semblance of order */
17945ea9e707SThomas Veerman 	m = a;
17955ea9e707SThomas Veerman 	if (a == GT) {
17965ea9e707SThomas Veerman 		fp = fopen(s, "w");
17975ea9e707SThomas Veerman 	} else if (a == APPEND) {
17985ea9e707SThomas Veerman 		fp = fopen(s, "a");
17995ea9e707SThomas Veerman 		m = GT;	/* so can mix > and >> */
18005ea9e707SThomas Veerman 	} else if (a == '|') {	/* output pipe */
18015ea9e707SThomas Veerman 		fp = popen(s, "w");
18025ea9e707SThomas Veerman 	} else if (a == LE) {	/* input pipe */
18035ea9e707SThomas Veerman 		fp = popen(s, "r");
18045ea9e707SThomas Veerman 	} else if (a == LT) {	/* getline <file */
18055ea9e707SThomas Veerman 		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
18065ea9e707SThomas Veerman 	} else	/* can't happen */
18075ea9e707SThomas Veerman 		FATAL("illegal redirection %d", a);
18085ea9e707SThomas Veerman 	if (fp != NULL) {
18095ea9e707SThomas Veerman 		files[i].fname = tostring(s);
18105ea9e707SThomas Veerman 		files[i].fp = fp;
18115ea9e707SThomas Veerman 		files[i].mode = m;
18125ea9e707SThomas Veerman 		if (pnewflag)
18135ea9e707SThomas Veerman 			*pnewflag = 1;
18145ea9e707SThomas Veerman 	}
18155ea9e707SThomas Veerman 	return fp;
18165ea9e707SThomas Veerman }
18175ea9e707SThomas Veerman 
filename(FILE * fp)18185ea9e707SThomas Veerman const char *filename(FILE *fp)
18195ea9e707SThomas Veerman {
18205ea9e707SThomas Veerman 	size_t i;
18215ea9e707SThomas Veerman 
18225ea9e707SThomas Veerman 	for (i = 0; i < nfiles; i++)
18235ea9e707SThomas Veerman 		if (fp == files[i].fp)
18245ea9e707SThomas Veerman 			return files[i].fname;
18255ea9e707SThomas Veerman 	return "???";
18265ea9e707SThomas Veerman }
18275ea9e707SThomas Veerman 
closefile(Node ** a,int n)18285ea9e707SThomas Veerman Cell *closefile(Node **a, int n)
18295ea9e707SThomas Veerman {
18305ea9e707SThomas Veerman 	Cell *x;
18315ea9e707SThomas Veerman 	size_t i;
18325ea9e707SThomas Veerman 	int stat;
18335ea9e707SThomas Veerman 
18345ea9e707SThomas Veerman 	n = n;
18355ea9e707SThomas Veerman 	x = execute(a[0]);
18365ea9e707SThomas Veerman 	getsval(x);
18375ea9e707SThomas Veerman 	stat = -1;
18385ea9e707SThomas Veerman 	for (i = 0; i < nfiles; i++) {
18395ea9e707SThomas Veerman 		if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
18405ea9e707SThomas Veerman 			if (ferror(files[i].fp))
18415ea9e707SThomas Veerman 				WARNING( "i/o error occurred on %s", files[i].fname );
18425ea9e707SThomas Veerman 			if (files[i].mode == '|' || files[i].mode == LE)
18435ea9e707SThomas Veerman 				stat = pclose(files[i].fp) == -1;
18445ea9e707SThomas Veerman 			else
18455ea9e707SThomas Veerman 				stat = fclose(files[i].fp) == EOF;
18465ea9e707SThomas Veerman 			if (stat) {
18475ea9e707SThomas Veerman 				stat = -1;
18485ea9e707SThomas Veerman 				WARNING( "i/o error occurred closing %s",
18495ea9e707SThomas Veerman 				    files[i].fname );
18505ea9e707SThomas Veerman 			}
18515ea9e707SThomas Veerman 			if (i > 2)	/* don't do /dev/std... */
18525ea9e707SThomas Veerman 				free(__UNCONST(files[i].fname));
18535ea9e707SThomas Veerman 			files[i].fname = NULL;	/* watch out for ref thru this */
18545ea9e707SThomas Veerman 			files[i].fp = NULL;
18555ea9e707SThomas Veerman 		}
18565ea9e707SThomas Veerman 	}
18575ea9e707SThomas Veerman 	tempfree(x);
18585ea9e707SThomas Veerman 	x = gettemp();
18595ea9e707SThomas Veerman 	setfval(x, (Awkfloat) stat);
18605ea9e707SThomas Veerman 	return(x);
18615ea9e707SThomas Veerman }
18625ea9e707SThomas Veerman 
closeall(void)18635ea9e707SThomas Veerman void closeall(void)
18645ea9e707SThomas Veerman {
18655ea9e707SThomas Veerman 	size_t i;
18665ea9e707SThomas Veerman 	int stat;
18675ea9e707SThomas Veerman 
18685ea9e707SThomas Veerman 	for (i = 0; i < nfiles; i++) {
18695ea9e707SThomas Veerman 		if (files[i].fp) {
18705ea9e707SThomas Veerman 			if (ferror(files[i].fp))
18715ea9e707SThomas Veerman 				WARNING( "i/o error occurred on %s", files[i].fname );
18725ea9e707SThomas Veerman 			if (i == 0)
18735ea9e707SThomas Veerman 				stat = fpurge(files[i].fp) == EOF;
18745ea9e707SThomas Veerman 			else if (i <= 2)
18755ea9e707SThomas Veerman 				stat = fflush(files[i].fp) == EOF;
18765ea9e707SThomas Veerman 			else if (files[i].mode == '|' || files[i].mode == LE)
18775ea9e707SThomas Veerman 				stat = pclose(files[i].fp) == -1;
18785ea9e707SThomas Veerman 			else
18795ea9e707SThomas Veerman 				stat = fclose(files[i].fp) == EOF;
18805ea9e707SThomas Veerman 			if (stat)
18815ea9e707SThomas Veerman 				WARNING( "i/o error occurred while closing %s", files[i].fname );
18825ea9e707SThomas Veerman 		}
18835ea9e707SThomas Veerman 	}
18845ea9e707SThomas Veerman }
18855ea9e707SThomas Veerman 
flush_all(void)18865ea9e707SThomas Veerman void flush_all(void)
18875ea9e707SThomas Veerman {
18885ea9e707SThomas Veerman 	size_t i;
18895ea9e707SThomas Veerman 
18905ea9e707SThomas Veerman 	for (i = 0; i < nfiles; i++)
18915ea9e707SThomas Veerman 		if (files[i].fp)
18925ea9e707SThomas Veerman 			fflush(files[i].fp);
18935ea9e707SThomas Veerman }
18945ea9e707SThomas Veerman 
18955ea9e707SThomas Veerman void backsub(uschar **pb_ptr, const uschar **sptr_ptr);
18965ea9e707SThomas Veerman 
sub(Node ** a,int nnn)18975ea9e707SThomas Veerman Cell *sub(Node **a, int nnn)	/* substitute command */
18985ea9e707SThomas Veerman {
18995ea9e707SThomas Veerman 	const uschar *sptr;
19005ea9e707SThomas Veerman 	uschar *q;
19015ea9e707SThomas Veerman 	Cell *x, *y, *result;
19025ea9e707SThomas Veerman 	uschar *t, *buf, *pb;
19035ea9e707SThomas Veerman 	fa *pfa;
19045ea9e707SThomas Veerman 	int bufsz = recsize;
19055ea9e707SThomas Veerman 
19065ea9e707SThomas Veerman 	if ((buf = malloc(bufsz)) == NULL)
19075ea9e707SThomas Veerman 		FATAL("out of memory in sub");
19085ea9e707SThomas Veerman 	x = execute(a[3]);	/* target string */
19095ea9e707SThomas Veerman 	t = getsval(x);
19105ea9e707SThomas Veerman 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
19115ea9e707SThomas Veerman 		pfa = (fa *) a[1];	/* regular expression */
19125ea9e707SThomas Veerman 	else {
19135ea9e707SThomas Veerman 		y = execute(a[1]);
19145ea9e707SThomas Veerman 		pfa = makedfa(getsval(y), 1);
19155ea9e707SThomas Veerman 		tempfree(y);
19165ea9e707SThomas Veerman 	}
19175ea9e707SThomas Veerman 	y = execute(a[2]);	/* replacement string */
19185ea9e707SThomas Veerman 	result = False;
19195ea9e707SThomas Veerman 	if (pmatch(pfa, t)) {
19205ea9e707SThomas Veerman 		sptr = t;
19215ea9e707SThomas Veerman 		adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
19225ea9e707SThomas Veerman 		pb = buf;
19235ea9e707SThomas Veerman 		while (sptr < patbeg)
19245ea9e707SThomas Veerman 			*pb++ = *sptr++;
19255ea9e707SThomas Veerman 		sptr = getsval(y);
19265ea9e707SThomas Veerman 		while (*sptr != 0) {
19275ea9e707SThomas Veerman 			adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
19285ea9e707SThomas Veerman 			if (*sptr == '\\') {
19295ea9e707SThomas Veerman 				backsub(&pb, &sptr);
19305ea9e707SThomas Veerman 			} else if (*sptr == '&') {
19315ea9e707SThomas Veerman 				sptr++;
19325ea9e707SThomas Veerman 				adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
19335ea9e707SThomas Veerman 				for (q = patbeg; q < patbeg+patlen; )
19345ea9e707SThomas Veerman 					*pb++ = *q++;
19355ea9e707SThomas Veerman 			} else
19365ea9e707SThomas Veerman 				*pb++ = *sptr++;
19375ea9e707SThomas Veerman 		}
19385ea9e707SThomas Veerman 		*pb = '\0';
19395ea9e707SThomas Veerman 		if (pb > buf + bufsz)
19405ea9e707SThomas Veerman 			FATAL("sub result1 %.30s too big; can't happen", buf);
19415ea9e707SThomas Veerman 		sptr = patbeg + patlen;
19425ea9e707SThomas Veerman 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
19435ea9e707SThomas Veerman 			adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
19445ea9e707SThomas Veerman 			while ((*pb++ = *sptr++) != 0)
19455ea9e707SThomas Veerman 				;
19465ea9e707SThomas Veerman 		}
19475ea9e707SThomas Veerman 		if (pb > buf + bufsz)
19485ea9e707SThomas Veerman 			FATAL("sub result2 %.30s too big; can't happen", buf);
19495ea9e707SThomas Veerman 		setsval(x, buf);	/* BUG: should be able to avoid copy */
19505ea9e707SThomas Veerman 		result = True;;
19515ea9e707SThomas Veerman 	}
19525ea9e707SThomas Veerman 	tempfree(x);
19535ea9e707SThomas Veerman 	tempfree(y);
19545ea9e707SThomas Veerman 	free(buf);
19555ea9e707SThomas Veerman 	return result;
19565ea9e707SThomas Veerman }
19575ea9e707SThomas Veerman 
gsub(Node ** a,int nnn)19585ea9e707SThomas Veerman Cell *gsub(Node **a, int nnn)	/* global substitute */
19595ea9e707SThomas Veerman {
19605ea9e707SThomas Veerman 	Cell *x, *y;
19615ea9e707SThomas Veerman 	const char *rptr;
19625ea9e707SThomas Veerman 	const uschar *sptr;
19635ea9e707SThomas Veerman 	uschar *t, *q;
19645ea9e707SThomas Veerman 	uschar *pb, *buf;
19655ea9e707SThomas Veerman 	fa *pfa;
19665ea9e707SThomas Veerman 	int mflag, tempstat, num;
19675ea9e707SThomas Veerman 	int bufsz = recsize;
19685ea9e707SThomas Veerman 
19695ea9e707SThomas Veerman 	if ((buf = malloc(bufsz)) == NULL)
19705ea9e707SThomas Veerman 		FATAL("out of memory in gsub");
19715ea9e707SThomas Veerman 	mflag = 0;	/* if mflag == 0, can replace empty string */
19725ea9e707SThomas Veerman 	num = 0;
19735ea9e707SThomas Veerman 	x = execute(a[3]);	/* target string */
19745ea9e707SThomas Veerman 	t = getsval(x);
19755ea9e707SThomas Veerman 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
19765ea9e707SThomas Veerman 		pfa = (fa *) a[1];	/* regular expression */
19775ea9e707SThomas Veerman 	else {
19785ea9e707SThomas Veerman 		y = execute(a[1]);
19795ea9e707SThomas Veerman 		pfa = makedfa(getsval(y), 1);
19805ea9e707SThomas Veerman 		tempfree(y);
19815ea9e707SThomas Veerman 	}
19825ea9e707SThomas Veerman 	y = execute(a[2]);	/* replacement string */
19835ea9e707SThomas Veerman 	if (pmatch(pfa, t)) {
19845ea9e707SThomas Veerman 		tempstat = pfa->initstat;
19855ea9e707SThomas Veerman 		pfa->initstat = 2;
19865ea9e707SThomas Veerman 		pb = buf;
19875ea9e707SThomas Veerman 		rptr = getsval(y);
19885ea9e707SThomas Veerman 		do {
19895ea9e707SThomas Veerman 			if (patlen == 0 && *patbeg != 0) {	/* matched empty string */
19905ea9e707SThomas Veerman 				if (mflag == 0) {	/* can replace empty */
19915ea9e707SThomas Veerman 					num++;
19925ea9e707SThomas Veerman 					sptr = rptr;
19935ea9e707SThomas Veerman 					while (*sptr != 0) {
19945ea9e707SThomas Veerman 						adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
19955ea9e707SThomas Veerman 						if (*sptr == '\\') {
19965ea9e707SThomas Veerman 							backsub(&pb, &sptr);
19975ea9e707SThomas Veerman 						} else if (*sptr == '&') {
19985ea9e707SThomas Veerman 							sptr++;
19995ea9e707SThomas Veerman 							adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
20005ea9e707SThomas Veerman 							for (q = patbeg; q < patbeg+patlen; )
20015ea9e707SThomas Veerman 								*pb++ = *q++;
20025ea9e707SThomas Veerman 						} else
20035ea9e707SThomas Veerman 							*pb++ = *sptr++;
20045ea9e707SThomas Veerman 					}
20055ea9e707SThomas Veerman 				}
20065ea9e707SThomas Veerman 				if (*t == 0)	/* at end */
20075ea9e707SThomas Veerman 					goto done;
20085ea9e707SThomas Veerman 				adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
20095ea9e707SThomas Veerman 				*pb++ = *t++;
20105ea9e707SThomas Veerman 				if (pb > buf + bufsz)	/* BUG: not sure of this test */
20115ea9e707SThomas Veerman 					FATAL("gsub result0 %.30s too big; can't happen", buf);
20125ea9e707SThomas Veerman 				mflag = 0;
20135ea9e707SThomas Veerman 			}
20145ea9e707SThomas Veerman 			else {	/* matched nonempty string */
20155ea9e707SThomas Veerman 				num++;
20165ea9e707SThomas Veerman 				sptr = t;
20175ea9e707SThomas Veerman 				adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
20185ea9e707SThomas Veerman 				while (sptr < patbeg)
20195ea9e707SThomas Veerman 					*pb++ = *sptr++;
20205ea9e707SThomas Veerman 				sptr = rptr;
20215ea9e707SThomas Veerman 				while (*sptr != 0) {
20225ea9e707SThomas Veerman 					adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
20235ea9e707SThomas Veerman 					if (*sptr == '\\') {
20245ea9e707SThomas Veerman 						backsub(&pb, &sptr);
20255ea9e707SThomas Veerman 					} else if (*sptr == '&') {
20265ea9e707SThomas Veerman 						sptr++;
20275ea9e707SThomas Veerman 						adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
20285ea9e707SThomas Veerman 						for (q = patbeg; q < patbeg+patlen; )
20295ea9e707SThomas Veerman 							*pb++ = *q++;
20305ea9e707SThomas Veerman 					} else
20315ea9e707SThomas Veerman 						*pb++ = *sptr++;
20325ea9e707SThomas Veerman 				}
20335ea9e707SThomas Veerman 				t = patbeg + patlen;
20345ea9e707SThomas Veerman 				if (patlen == 0 || *t == 0 || *(t-1) == 0)
20355ea9e707SThomas Veerman 					goto done;
20365ea9e707SThomas Veerman 				if (pb > buf + bufsz)
20375ea9e707SThomas Veerman 					FATAL("gsub result1 %.30s too big; can't happen", buf);
20385ea9e707SThomas Veerman 				mflag = 1;
20395ea9e707SThomas Veerman 			}
20405ea9e707SThomas Veerman 		} while (pmatch(pfa,t));
20415ea9e707SThomas Veerman 		sptr = t;
20425ea9e707SThomas Veerman 		adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
20435ea9e707SThomas Veerman 		while ((*pb++ = *sptr++) != 0)
20445ea9e707SThomas Veerman 			;
20455ea9e707SThomas Veerman 	done:	if (pb < buf + bufsz)
20465ea9e707SThomas Veerman 			*pb = '\0';
20475ea9e707SThomas Veerman 		else if (*(pb-1) != '\0')
20485ea9e707SThomas Veerman 			FATAL("gsub result2 %.30s truncated; can't happen", buf);
20495ea9e707SThomas Veerman 		setsval(x, buf);	/* BUG: should be able to avoid copy + free */
20505ea9e707SThomas Veerman 		pfa->initstat = tempstat;
20515ea9e707SThomas Veerman 	}
20525ea9e707SThomas Veerman 	tempfree(x);
20535ea9e707SThomas Veerman 	tempfree(y);
20545ea9e707SThomas Veerman 	x = gettemp();
20555ea9e707SThomas Veerman 	x->tval = NUM;
20565ea9e707SThomas Veerman 	x->fval = num;
20575ea9e707SThomas Veerman 	free(buf);
20585ea9e707SThomas Veerman 	return(x);
20595ea9e707SThomas Veerman }
20605ea9e707SThomas Veerman 
gensub(Node ** a,int nnn)20615ea9e707SThomas Veerman Cell *gensub(Node **a, int nnn)	/* global selective substitute */
20625ea9e707SThomas Veerman 	/* XXX incomplete - doesn't support backreferences \0 ... \9 */
20635ea9e707SThomas Veerman {
20645ea9e707SThomas Veerman 	Cell *x, *y, *res, *h;
20655ea9e707SThomas Veerman 	char *rptr;
20665ea9e707SThomas Veerman 	const uschar *sptr;
20675ea9e707SThomas Veerman 	uschar *q, *pb, *t, *buf;
20685ea9e707SThomas Veerman 	fa *pfa;
20695ea9e707SThomas Veerman 	int mflag, tempstat, num, whichm;
20705ea9e707SThomas Veerman 	int bufsz = recsize;
20715ea9e707SThomas Veerman 
20725ea9e707SThomas Veerman 	if ((buf = malloc(bufsz)) == NULL)
20735ea9e707SThomas Veerman 		FATAL("out of memory in gensub");
20745ea9e707SThomas Veerman 	mflag = 0;	/* if mflag == 0, can replace empty string */
20755ea9e707SThomas Veerman 	num = 0;
20765ea9e707SThomas Veerman 	x = execute(a[4]);	/* source string */
20775ea9e707SThomas Veerman 	t = getsval(x);
20785ea9e707SThomas Veerman 	res = copycell(x);	/* target string - initially copy of source */
207984d9c625SLionel Sambuc 	res->csub = CTEMP;	/* result values are temporary */
20805ea9e707SThomas Veerman 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
20815ea9e707SThomas Veerman 		pfa = (fa *) a[1];	/* regular expression */
20825ea9e707SThomas Veerman 	else {
20835ea9e707SThomas Veerman 		y = execute(a[1]);
20845ea9e707SThomas Veerman 		pfa = makedfa(getsval(y), 1);
20855ea9e707SThomas Veerman 		tempfree(y);
20865ea9e707SThomas Veerman 	}
20875ea9e707SThomas Veerman 	y = execute(a[2]);	/* replacement string */
20885ea9e707SThomas Veerman 	h = execute(a[3]);	/* which matches should be replaced */
20895ea9e707SThomas Veerman 	sptr = getsval(h);
20905ea9e707SThomas Veerman 	if (sptr[0] == 'g' || sptr[0] == 'G')
20915ea9e707SThomas Veerman 		whichm = -1;
20925ea9e707SThomas Veerman 	else {
20935ea9e707SThomas Veerman 		/*
20945ea9e707SThomas Veerman 		 * The specified number is index of replacement, starting
20955ea9e707SThomas Veerman 		 * from 1. GNU awk treats index lower than 0 same as
20965ea9e707SThomas Veerman 		 * 1, we do same for compatibility.
20975ea9e707SThomas Veerman 		 */
20985ea9e707SThomas Veerman 		whichm = (int) getfval(h) - 1;
20995ea9e707SThomas Veerman 		if (whichm < 0)
21005ea9e707SThomas Veerman 			whichm = 0;
21015ea9e707SThomas Veerman 	}
21025ea9e707SThomas Veerman 	tempfree(h);
21035ea9e707SThomas Veerman 
21045ea9e707SThomas Veerman 	if (pmatch(pfa, t)) {
21055ea9e707SThomas Veerman 		char *sl;
21065ea9e707SThomas Veerman 
21075ea9e707SThomas Veerman 		tempstat = pfa->initstat;
21085ea9e707SThomas Veerman 		pfa->initstat = 2;
21095ea9e707SThomas Veerman 		pb = buf;
21105ea9e707SThomas Veerman 		rptr = getsval(y);
21115ea9e707SThomas Veerman 		/*
21125ea9e707SThomas Veerman 		 * XXX if there are any backreferences in subst string,
21135ea9e707SThomas Veerman 		 * complain now.
21145ea9e707SThomas Veerman 		 */
21155ea9e707SThomas Veerman 		for(sl=rptr; (sl = strchr(sl, '\\')) && sl[1]; sl++) {
21165ea9e707SThomas Veerman 			if (strchr("0123456789", sl[1])) {
21175ea9e707SThomas Veerman 				FATAL("gensub doesn't support backreferences (subst \"%s\")", rptr);
21185ea9e707SThomas Veerman 			}
21195ea9e707SThomas Veerman 		}
21205ea9e707SThomas Veerman 
21215ea9e707SThomas Veerman 		do {
21225ea9e707SThomas Veerman 			if (whichm >= 0 && whichm != num) {
21235ea9e707SThomas Veerman 				num++;
21245ea9e707SThomas Veerman 				adjbuf(&buf, &bufsz, (pb - buf) + (patbeg - t) + patlen, recsize, &pb, "gensub");
21255ea9e707SThomas Veerman 
21265ea9e707SThomas Veerman 				/* copy the part of string up to and including
21275ea9e707SThomas Veerman 				 * match to output buffer */
21285ea9e707SThomas Veerman 				while (t < patbeg + patlen)
21295ea9e707SThomas Veerman 					*pb++ = *t++;
21305ea9e707SThomas Veerman 				continue;
21315ea9e707SThomas Veerman 			}
21325ea9e707SThomas Veerman 
21335ea9e707SThomas Veerman 			if (patlen == 0 && *patbeg != 0) {	/* matched empty string */
21345ea9e707SThomas Veerman 				if (mflag == 0) {	/* can replace empty */
21355ea9e707SThomas Veerman 					num++;
21365ea9e707SThomas Veerman 					sptr = rptr;
21375ea9e707SThomas Veerman 					while (*sptr != 0) {
21385ea9e707SThomas Veerman 						adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gensub");
21395ea9e707SThomas Veerman 						if (*sptr == '\\') {
21405ea9e707SThomas Veerman 							backsub(&pb, &sptr);
21415ea9e707SThomas Veerman 						} else if (*sptr == '&') {
21425ea9e707SThomas Veerman 							sptr++;
21435ea9e707SThomas Veerman 							adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gensub");
21445ea9e707SThomas Veerman 							for (q = patbeg; q < patbeg+patlen; )
21455ea9e707SThomas Veerman 								*pb++ = *q++;
21465ea9e707SThomas Veerman 						} else
21475ea9e707SThomas Veerman 							*pb++ = *sptr++;
21485ea9e707SThomas Veerman 					}
21495ea9e707SThomas Veerman 				}
21505ea9e707SThomas Veerman 				if (*t == 0)	/* at end */
21515ea9e707SThomas Veerman 					goto done;
21525ea9e707SThomas Veerman 				adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gensub");
21535ea9e707SThomas Veerman 				*pb++ = *t++;
21545ea9e707SThomas Veerman 				if (pb > buf + bufsz)	/* BUG: not sure of this test */
21555ea9e707SThomas Veerman 					FATAL("gensub result0 %.30s too big; can't happen", buf);
21565ea9e707SThomas Veerman 				mflag = 0;
21575ea9e707SThomas Veerman 			}
21585ea9e707SThomas Veerman 			else {	/* matched nonempty string */
21595ea9e707SThomas Veerman 				num++;
21605ea9e707SThomas Veerman 				sptr = t;
21615ea9e707SThomas Veerman 				adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gensub");
21625ea9e707SThomas Veerman 				while (sptr < patbeg)
21635ea9e707SThomas Veerman 					*pb++ = *sptr++;
21645ea9e707SThomas Veerman 				sptr = rptr;
21655ea9e707SThomas Veerman 				while (*sptr != 0) {
21665ea9e707SThomas Veerman 					adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gensub");
21675ea9e707SThomas Veerman 					if (*sptr == '\\') {
21685ea9e707SThomas Veerman 						backsub(&pb, &sptr);
21695ea9e707SThomas Veerman 					} else if (*sptr == '&') {
21705ea9e707SThomas Veerman 						sptr++;
21715ea9e707SThomas Veerman 						adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gensub");
21725ea9e707SThomas Veerman 						for (q = patbeg; q < patbeg+patlen; )
21735ea9e707SThomas Veerman 							*pb++ = *q++;
21745ea9e707SThomas Veerman 					} else
21755ea9e707SThomas Veerman 						*pb++ = *sptr++;
21765ea9e707SThomas Veerman 				}
21775ea9e707SThomas Veerman 				t = patbeg + patlen;
21785ea9e707SThomas Veerman 				if (patlen == 0 || *t == 0 || *(t-1) == 0)
21795ea9e707SThomas Veerman 					goto done;
21805ea9e707SThomas Veerman 				if (pb > buf + bufsz)
21815ea9e707SThomas Veerman 					FATAL("gensub result1 %.30s too big; can't happen", buf);
21825ea9e707SThomas Veerman 				mflag = 1;
21835ea9e707SThomas Veerman 			}
21845ea9e707SThomas Veerman 		} while (pmatch(pfa,t));
21855ea9e707SThomas Veerman 		sptr = t;
21865ea9e707SThomas Veerman 		adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gensub");
21875ea9e707SThomas Veerman 		while ((*pb++ = *sptr++) != 0)
21885ea9e707SThomas Veerman 			;
21895ea9e707SThomas Veerman 	done:	if (pb > buf + bufsz)
21905ea9e707SThomas Veerman 			FATAL("gensub result2 %.30s too big; can't happen", buf);
21915ea9e707SThomas Veerman 		*pb = '\0';
21925ea9e707SThomas Veerman 		setsval(res, buf);
21935ea9e707SThomas Veerman 		pfa->initstat = tempstat;
21945ea9e707SThomas Veerman 	}
21955ea9e707SThomas Veerman 	tempfree(x);
21965ea9e707SThomas Veerman 	tempfree(y);
21975ea9e707SThomas Veerman 	free(buf);
21985ea9e707SThomas Veerman 	return(res);
21995ea9e707SThomas Veerman }
22005ea9e707SThomas Veerman 
backsub(uschar ** pb_ptr,const uschar ** sptr_ptr)22015ea9e707SThomas Veerman void backsub(uschar **pb_ptr, const uschar **sptr_ptr)/* handle \\& variations */
22025ea9e707SThomas Veerman {						/* sptr[0] == '\\' */
22035ea9e707SThomas Veerman 	uschar *pb = *pb_ptr;
22045ea9e707SThomas Veerman 	const uschar *sptr = *sptr_ptr;
22055ea9e707SThomas Veerman 
22065ea9e707SThomas Veerman 	if (sptr[1] == '\\') {
22075ea9e707SThomas Veerman 		if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
22085ea9e707SThomas Veerman 			*pb++ = '\\';
22095ea9e707SThomas Veerman 			*pb++ = '&';
22105ea9e707SThomas Veerman 			sptr += 4;
22115ea9e707SThomas Veerman 		} else if (sptr[2] == '&') {	/* \\& -> \ + matched */
22125ea9e707SThomas Veerman 			*pb++ = '\\';
22135ea9e707SThomas Veerman 			sptr += 2;
22145ea9e707SThomas Veerman 		} else {			/* \\x -> \\x */
22155ea9e707SThomas Veerman 			*pb++ = *sptr++;
22165ea9e707SThomas Veerman 			*pb++ = *sptr++;
22175ea9e707SThomas Veerman 		}
22185ea9e707SThomas Veerman 	} else if (sptr[1] == '&') {	/* literal & */
22195ea9e707SThomas Veerman 		sptr++;
22205ea9e707SThomas Veerman 		*pb++ = *sptr++;
22215ea9e707SThomas Veerman 	} else				/* literal \ */
22225ea9e707SThomas Veerman 		*pb++ = *sptr++;
22235ea9e707SThomas Veerman 
22245ea9e707SThomas Veerman 	*pb_ptr = pb;
22255ea9e707SThomas Veerman 	*sptr_ptr = sptr;
22265ea9e707SThomas Veerman }
2227