xref: /dflybsd-src/contrib/awk/run.c (revision 1d48fce09e070b7fb0180fe19e991a6b7edcd14c)
14b588458SPeter Avalos /****************************************************************
24b588458SPeter Avalos Copyright (C) Lucent Technologies 1997
34b588458SPeter Avalos All Rights Reserved
44b588458SPeter Avalos 
54b588458SPeter Avalos Permission to use, copy, modify, and distribute this software and
64b588458SPeter Avalos its documentation for any purpose and without fee is hereby
74b588458SPeter Avalos granted, provided that the above copyright notice appear in all
84b588458SPeter Avalos copies and that both that the copyright notice and this
94b588458SPeter Avalos permission notice and warranty disclaimer appear in supporting
104b588458SPeter Avalos documentation, and that the name Lucent Technologies or any of
114b588458SPeter Avalos its entities not be used in advertising or publicity pertaining
124b588458SPeter Avalos to distribution of the software without specific, written prior
134b588458SPeter Avalos permission.
144b588458SPeter Avalos 
154b588458SPeter Avalos LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
164b588458SPeter Avalos INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
174b588458SPeter Avalos IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
184b588458SPeter Avalos SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
194b588458SPeter Avalos WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
204b588458SPeter Avalos IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
214b588458SPeter Avalos ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
224b588458SPeter Avalos THIS SOFTWARE.
234b588458SPeter Avalos ****************************************************************/
244b588458SPeter Avalos 
254b588458SPeter Avalos #define DEBUG
264b588458SPeter Avalos #include <stdio.h>
274b588458SPeter Avalos #include <ctype.h>
28*1d48fce0SDaniel Fojt #include <errno.h>
29*1d48fce0SDaniel Fojt #include <wchar.h>
30*1d48fce0SDaniel Fojt #include <wctype.h>
31*1d48fce0SDaniel Fojt #include <fcntl.h>
324b588458SPeter Avalos #include <setjmp.h>
334b588458SPeter Avalos #include <limits.h>
344b588458SPeter Avalos #include <math.h>
354b588458SPeter Avalos #include <string.h>
364b588458SPeter Avalos #include <stdlib.h>
374b588458SPeter Avalos #include <time.h>
38*1d48fce0SDaniel Fojt #include <sys/types.h>
39*1d48fce0SDaniel Fojt #include <sys/wait.h>
404b588458SPeter Avalos #include "awk.h"
414b588458SPeter Avalos #include "ytab.h"
424b588458SPeter Avalos 
43*1d48fce0SDaniel Fojt static void stdinit(void);
44*1d48fce0SDaniel Fojt static void flush_all(void);
454b588458SPeter Avalos 
46*1d48fce0SDaniel Fojt #if 1
47*1d48fce0SDaniel Fojt #define tempfree(x)	do { if (istemp(x)) tfree(x); } while (/*CONSTCOND*/0)
48*1d48fce0SDaniel Fojt #else
494b588458SPeter Avalos void tempfree(Cell *p) {
504b588458SPeter Avalos 	if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
514b588458SPeter Avalos 		WARNING("bad csub %d in Cell %d %s",
524b588458SPeter Avalos 			p->csub, p->ctype, p->sval);
534b588458SPeter Avalos 	}
544b588458SPeter Avalos 	if (istemp(p))
554b588458SPeter Avalos 		tfree(p);
564b588458SPeter Avalos }
57*1d48fce0SDaniel Fojt #endif
584b588458SPeter Avalos 
594b588458SPeter Avalos /* do we really need these? */
604b588458SPeter Avalos /* #ifdef _NFILE */
614b588458SPeter Avalos /* #ifndef FOPEN_MAX */
624b588458SPeter Avalos /* #define FOPEN_MAX _NFILE */
634b588458SPeter Avalos /* #endif */
644b588458SPeter Avalos /* #endif */
654b588458SPeter Avalos /*  */
664b588458SPeter Avalos /* #ifndef	FOPEN_MAX */
674b588458SPeter Avalos /* #define	FOPEN_MAX	40 */	/* max number of open files */
684b588458SPeter Avalos /* #endif */
694b588458SPeter Avalos /*  */
704b588458SPeter Avalos /* #ifndef RAND_MAX */
714b588458SPeter Avalos /* #define RAND_MAX	32767 */	/* all that ansi guarantees */
724b588458SPeter Avalos /* #endif */
734b588458SPeter Avalos 
744b588458SPeter Avalos jmp_buf env;
754b588458SPeter Avalos extern	int	pairstack[];
760020174dSPeter Avalos extern	Awkfloat	srand_seed;
774b588458SPeter Avalos 
784b588458SPeter Avalos Node	*winner = NULL;	/* root of parse tree */
794b588458SPeter Avalos Cell	*tmps;		/* free temporary cells for execution */
804b588458SPeter Avalos 
81*1d48fce0SDaniel Fojt static Cell	truecell	={ OBOOL, BTRUE, 0, 0, 1.0, NUM, NULL, NULL };
824b588458SPeter Avalos Cell	*True	= &truecell;
83*1d48fce0SDaniel Fojt static Cell	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM, NULL, NULL };
844b588458SPeter Avalos Cell	*False	= &falsecell;
85*1d48fce0SDaniel Fojt static Cell	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM, NULL, NULL };
864b588458SPeter Avalos Cell	*jbreak	= &breakcell;
87*1d48fce0SDaniel Fojt static Cell	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM, NULL, NULL };
884b588458SPeter Avalos Cell	*jcont	= &contcell;
89*1d48fce0SDaniel Fojt static Cell	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM, NULL, NULL };
904b588458SPeter Avalos Cell	*jnext	= &nextcell;
91*1d48fce0SDaniel Fojt static Cell	nextfilecell	={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM, NULL, NULL };
924b588458SPeter Avalos Cell	*jnextfile	= &nextfilecell;
93*1d48fce0SDaniel Fojt static Cell	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM, NULL, NULL };
944b588458SPeter Avalos Cell	*jexit	= &exitcell;
95*1d48fce0SDaniel Fojt static Cell	retcell		={ OJUMP, JRET, 0, 0, 0.0, NUM, NULL, NULL };
964b588458SPeter Avalos Cell	*jret	= &retcell;
97*1d48fce0SDaniel Fojt static Cell	tempcell	={ OCELL, CTEMP, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL, NULL };
984b588458SPeter Avalos 
994b588458SPeter Avalos Node	*curnode = NULL;	/* the node being executed, for debugging */
1004b588458SPeter Avalos 
1014b588458SPeter Avalos /* buffer memory management */
1024b588458SPeter Avalos int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
1034b588458SPeter Avalos 	const char *whatrtn)
1044b588458SPeter Avalos /* pbuf:    address of pointer to buffer being managed
1054b588458SPeter Avalos  * psiz:    address of buffer size variable
1064b588458SPeter Avalos  * minlen:  minimum length of buffer needed
1074b588458SPeter Avalos  * quantum: buffer size quantum
1084b588458SPeter Avalos  * pbptr:   address of movable pointer into buffer, or 0 if none
1094b588458SPeter Avalos  * whatrtn: name of the calling routine if failure should cause fatal error
1104b588458SPeter Avalos  *
1114b588458SPeter Avalos  * return   0 for realloc failure, !=0 for success
1124b588458SPeter Avalos  */
1134b588458SPeter Avalos {
1144b588458SPeter Avalos 	if (minlen > *psiz) {
1154b588458SPeter Avalos 		char *tbuf;
1164b588458SPeter Avalos 		int rminlen = quantum ? minlen % quantum : 0;
1174b588458SPeter Avalos 		int boff = pbptr ? *pbptr - *pbuf : 0;
1184b588458SPeter Avalos 		/* round up to next multiple of quantum */
1194b588458SPeter Avalos 		if (rminlen)
1204b588458SPeter Avalos 			minlen += quantum - rminlen;
121*1d48fce0SDaniel Fojt 		tbuf = realloc(*pbuf, minlen);
1224b588458SPeter Avalos 		dprintf( ("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, *pbuf, tbuf) );
1234b588458SPeter Avalos 		if (tbuf == NULL) {
1244b588458SPeter Avalos 			if (whatrtn)
1254b588458SPeter Avalos 				FATAL("out of memory in %s", whatrtn);
1264b588458SPeter Avalos 			return 0;
1274b588458SPeter Avalos 		}
1284b588458SPeter Avalos 		*pbuf = tbuf;
1294b588458SPeter Avalos 		*psiz = minlen;
1304b588458SPeter Avalos 		if (pbptr)
1314b588458SPeter Avalos 			*pbptr = tbuf + boff;
1324b588458SPeter Avalos 	}
1334b588458SPeter Avalos 	return 1;
1344b588458SPeter Avalos }
1354b588458SPeter Avalos 
1364b588458SPeter Avalos void run(Node *a)	/* execution of parse tree starts here */
1374b588458SPeter Avalos {
1384b588458SPeter Avalos 
1394b588458SPeter Avalos 	stdinit();
1404b588458SPeter Avalos 	execute(a);
1414b588458SPeter Avalos 	closeall();
1424b588458SPeter Avalos }
1434b588458SPeter Avalos 
1444b588458SPeter Avalos Cell *execute(Node *u)	/* execute a node of the parse tree */
1454b588458SPeter Avalos {
1464b588458SPeter Avalos 	Cell *(*proc)(Node **, int);
1474b588458SPeter Avalos 	Cell *x;
1484b588458SPeter Avalos 	Node *a;
1494b588458SPeter Avalos 
1504b588458SPeter Avalos 	if (u == NULL)
1514b588458SPeter Avalos 		return(True);
1524b588458SPeter Avalos 	for (a = u; ; a = a->nnext) {
1534b588458SPeter Avalos 		curnode = a;
1544b588458SPeter Avalos 		if (isvalue(a)) {
1554b588458SPeter Avalos 			x = (Cell *) (a->narg[0]);
1564b588458SPeter Avalos 			if (isfld(x) && !donefld)
1574b588458SPeter Avalos 				fldbld();
1584b588458SPeter Avalos 			else if (isrec(x) && !donerec)
1594b588458SPeter Avalos 				recbld();
1604b588458SPeter Avalos 			return(x);
1614b588458SPeter Avalos 		}
1624b588458SPeter Avalos 		if (notlegal(a->nobj))	/* probably a Cell* but too risky to print */
1634b588458SPeter Avalos 			FATAL("illegal statement");
1644b588458SPeter Avalos 		proc = proctab[a->nobj-FIRSTTOKEN];
1654b588458SPeter Avalos 		x = (*proc)(a->narg, a->nobj);
1664b588458SPeter Avalos 		if (isfld(x) && !donefld)
1674b588458SPeter Avalos 			fldbld();
1684b588458SPeter Avalos 		else if (isrec(x) && !donerec)
1694b588458SPeter Avalos 			recbld();
1704b588458SPeter Avalos 		if (isexpr(a))
1714b588458SPeter Avalos 			return(x);
1724b588458SPeter Avalos 		if (isjump(x))
1734b588458SPeter Avalos 			return(x);
1744b588458SPeter Avalos 		if (a->nnext == NULL)
1754b588458SPeter Avalos 			return(x);
1764b588458SPeter Avalos 		tempfree(x);
1774b588458SPeter Avalos 	}
1784b588458SPeter Avalos }
1794b588458SPeter Avalos 
1804b588458SPeter Avalos 
1814b588458SPeter Avalos Cell *program(Node **a, int n)	/* execute an awk program */
1824b588458SPeter Avalos {				/* a[0] = BEGIN, a[1] = body, a[2] = END */
1834b588458SPeter Avalos 	Cell *x;
1844b588458SPeter Avalos 
1854b588458SPeter Avalos 	if (setjmp(env) != 0)
1864b588458SPeter Avalos 		goto ex;
1874b588458SPeter Avalos 	if (a[0]) {		/* BEGIN */
1884b588458SPeter Avalos 		x = execute(a[0]);
1894b588458SPeter Avalos 		if (isexit(x))
1904b588458SPeter Avalos 			return(True);
1914b588458SPeter Avalos 		if (isjump(x))
1924b588458SPeter Avalos 			FATAL("illegal break, continue, next or nextfile from BEGIN");
1934b588458SPeter Avalos 		tempfree(x);
1944b588458SPeter Avalos 	}
1954b588458SPeter Avalos 	if (a[1] || a[2])
196*1d48fce0SDaniel Fojt 		while (getrec(&record, &recsize, true) > 0) {
1974b588458SPeter Avalos 			x = execute(a[1]);
1984b588458SPeter Avalos 			if (isexit(x))
1994b588458SPeter Avalos 				break;
2004b588458SPeter Avalos 			tempfree(x);
2014b588458SPeter Avalos 		}
2024b588458SPeter Avalos   ex:
2034b588458SPeter Avalos 	if (setjmp(env) != 0)	/* handles exit within END */
2044b588458SPeter Avalos 		goto ex1;
2054b588458SPeter Avalos 	if (a[2]) {		/* END */
2064b588458SPeter Avalos 		x = execute(a[2]);
2074b588458SPeter Avalos 		if (isbreak(x) || isnext(x) || iscont(x))
2084b588458SPeter Avalos 			FATAL("illegal break, continue, next or nextfile from END");
2094b588458SPeter Avalos 		tempfree(x);
2104b588458SPeter Avalos 	}
2114b588458SPeter Avalos   ex1:
2124b588458SPeter Avalos 	return(True);
2134b588458SPeter Avalos }
2144b588458SPeter Avalos 
2154b588458SPeter Avalos struct Frame {	/* stack frame for awk function calls */
2164b588458SPeter Avalos 	int nargs;	/* number of arguments in this call */
2174b588458SPeter Avalos 	Cell *fcncell;	/* pointer to Cell for function */
2184b588458SPeter Avalos 	Cell **args;	/* pointer to array of arguments after execute */
2194b588458SPeter Avalos 	Cell *retval;	/* return value */
2204b588458SPeter Avalos };
2214b588458SPeter Avalos 
2224b588458SPeter Avalos #define	NARGS	50	/* max args in a call */
2234b588458SPeter Avalos 
2244b588458SPeter Avalos struct Frame *frame = NULL;	/* base of stack frames; dynamically allocated */
2254b588458SPeter Avalos int	nframe = 0;		/* number of frames allocated */
226*1d48fce0SDaniel Fojt struct Frame *frp = NULL;	/* frame pointer. bottom level unused */
2274b588458SPeter Avalos 
2284b588458SPeter Avalos Cell *call(Node **a, int n)	/* function call.  very kludgy and fragile */
2294b588458SPeter Avalos {
230*1d48fce0SDaniel Fojt 	static const Cell newcopycell = { OCELL, CCOPY, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL, NULL };
2314b588458SPeter Avalos 	int i, ncall, ndef;
2324b588458SPeter Avalos 	int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */
2334b588458SPeter Avalos 	Node *x;
2344b588458SPeter Avalos 	Cell *args[NARGS], *oargs[NARGS];	/* BUG: fixed size arrays */
2354b588458SPeter Avalos 	Cell *y, *z, *fcn;
2364b588458SPeter Avalos 	char *s;
2374b588458SPeter Avalos 
2384b588458SPeter Avalos 	fcn = execute(a[0]);	/* the function itself */
2394b588458SPeter Avalos 	s = fcn->nval;
2404b588458SPeter Avalos 	if (!isfcn(fcn))
2414b588458SPeter Avalos 		FATAL("calling undefined function %s", s);
2424b588458SPeter Avalos 	if (frame == NULL) {
243*1d48fce0SDaniel Fojt 		frp = frame = calloc(nframe += 100, sizeof(*frame));
2444b588458SPeter Avalos 		if (frame == NULL)
2454b588458SPeter Avalos 			FATAL("out of space for stack frames calling %s", s);
2464b588458SPeter Avalos 	}
2474b588458SPeter Avalos 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)	/* args in call */
2484b588458SPeter Avalos 		ncall++;
2494b588458SPeter Avalos 	ndef = (int) fcn->fval;			/* args in defn */
250*1d48fce0SDaniel Fojt 	   dprintf( ("calling %s, %d args (%d in defn), frp=%d\n", s, ncall, ndef, (int) (frp-frame)) );
2514b588458SPeter Avalos 	if (ncall > ndef)
2524b588458SPeter Avalos 		WARNING("function %s called with %d args, uses only %d",
2534b588458SPeter Avalos 			s, ncall, ndef);
2544b588458SPeter Avalos 	if (ncall + ndef > NARGS)
2554b588458SPeter Avalos 		FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
2564b588458SPeter Avalos 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {	/* get call args */
257*1d48fce0SDaniel Fojt 		   dprintf( ("evaluate args[%d], frp=%d:\n", i, (int) (frp-frame)) );
2584b588458SPeter Avalos 		y = execute(x);
2594b588458SPeter Avalos 		oargs[i] = y;
2604b588458SPeter Avalos 		   dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
2614b588458SPeter Avalos 			   i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval) );
2624b588458SPeter Avalos 		if (isfcn(y))
2634b588458SPeter Avalos 			FATAL("can't use function %s as argument in %s", y->nval, s);
2644b588458SPeter Avalos 		if (isarr(y))
2654b588458SPeter Avalos 			args[i] = y;	/* arrays by ref */
2664b588458SPeter Avalos 		else
2674b588458SPeter Avalos 			args[i] = copycell(y);
2684b588458SPeter Avalos 		tempfree(y);
2694b588458SPeter Avalos 	}
2704b588458SPeter Avalos 	for ( ; i < ndef; i++) {	/* add null args for ones not provided */
2714b588458SPeter Avalos 		args[i] = gettemp();
2724b588458SPeter Avalos 		*args[i] = newcopycell;
2734b588458SPeter Avalos 	}
274*1d48fce0SDaniel Fojt 	frp++;	/* now ok to up frame */
275*1d48fce0SDaniel Fojt 	if (frp >= frame + nframe) {
276*1d48fce0SDaniel Fojt 		int dfp = frp - frame;	/* old index */
277*1d48fce0SDaniel Fojt 		frame = realloc(frame, (nframe += 100) * sizeof(*frame));
2784b588458SPeter Avalos 		if (frame == NULL)
2794b588458SPeter Avalos 			FATAL("out of space for stack frames in %s", s);
280*1d48fce0SDaniel Fojt 		frp = frame + dfp;
2814b588458SPeter Avalos 	}
282*1d48fce0SDaniel Fojt 	frp->fcncell = fcn;
283*1d48fce0SDaniel Fojt 	frp->args = args;
284*1d48fce0SDaniel Fojt 	frp->nargs = ndef;	/* number defined with (excess are locals) */
285*1d48fce0SDaniel Fojt 	frp->retval = gettemp();
2864b588458SPeter Avalos 
287*1d48fce0SDaniel Fojt 	   dprintf( ("start exec of %s, frp=%d\n", s, (int) (frp-frame)) );
2884b588458SPeter Avalos 	y = execute((Node *)(fcn->sval));	/* execute body */
289*1d48fce0SDaniel Fojt 	   dprintf( ("finished exec of %s, frp=%d\n", s, (int) (frp-frame)) );
2904b588458SPeter Avalos 
2914b588458SPeter Avalos 	for (i = 0; i < ndef; i++) {
292*1d48fce0SDaniel Fojt 		Cell *t = frp->args[i];
2934b588458SPeter Avalos 		if (isarr(t)) {
2944b588458SPeter Avalos 			if (t->csub == CCOPY) {
2954b588458SPeter Avalos 				if (i >= ncall) {
2964b588458SPeter Avalos 					freesymtab(t);
2974b588458SPeter Avalos 					t->csub = CTEMP;
2984b588458SPeter Avalos 					tempfree(t);
2994b588458SPeter Avalos 				} else {
3004b588458SPeter Avalos 					oargs[i]->tval = t->tval;
3014b588458SPeter Avalos 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
3024b588458SPeter Avalos 					oargs[i]->sval = t->sval;
3034b588458SPeter Avalos 					tempfree(t);
3044b588458SPeter Avalos 				}
3054b588458SPeter Avalos 			}
3064b588458SPeter Avalos 		} else if (t != y) {	/* kludge to prevent freeing twice */
3074b588458SPeter Avalos 			t->csub = CTEMP;
3084b588458SPeter Avalos 			tempfree(t);
3094b588458SPeter Avalos 		} else if (t == y && t->csub == CCOPY) {
3104b588458SPeter Avalos 			t->csub = CTEMP;
3114b588458SPeter Avalos 			tempfree(t);
3124b588458SPeter Avalos 			freed = 1;
3134b588458SPeter Avalos 		}
3144b588458SPeter Avalos 	}
3154b588458SPeter Avalos 	tempfree(fcn);
3164b588458SPeter Avalos 	if (isexit(y) || isnext(y))
3174b588458SPeter Avalos 		return y;
3184b588458SPeter Avalos 	if (freed == 0) {
3194b588458SPeter Avalos 		tempfree(y);	/* don't free twice! */
3204b588458SPeter Avalos 	}
321*1d48fce0SDaniel Fojt 	z = frp->retval;			/* return value */
3224b588458SPeter Avalos 	   dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
323*1d48fce0SDaniel Fojt 	frp--;
3244b588458SPeter Avalos 	return(z);
3254b588458SPeter Avalos }
3264b588458SPeter Avalos 
3274b588458SPeter Avalos Cell *copycell(Cell *x)	/* make a copy of a cell in a temp */
3284b588458SPeter Avalos {
3294b588458SPeter Avalos 	Cell *y;
3304b588458SPeter Avalos 
331*1d48fce0SDaniel Fojt 	/* copy is not constant or field */
332*1d48fce0SDaniel Fojt 
3334b588458SPeter Avalos 	y = gettemp();
334*1d48fce0SDaniel Fojt 	y->tval = x->tval & ~(CON|FLD|REC);
3354b588458SPeter Avalos 	y->csub = CCOPY;	/* prevents freeing until call is over */
3364b588458SPeter Avalos 	y->nval = x->nval;	/* BUG? */
337*1d48fce0SDaniel Fojt 	if (isstr(x) /* || x->ctype == OCELL */) {
3384b588458SPeter Avalos 		y->sval = tostring(x->sval);
339*1d48fce0SDaniel Fojt 		y->tval &= ~DONTFREE;
340*1d48fce0SDaniel Fojt 	} else
341*1d48fce0SDaniel Fojt 		y->tval |= DONTFREE;
3424b588458SPeter Avalos 	y->fval = x->fval;
3434b588458SPeter Avalos 	return y;
3444b588458SPeter Avalos }
3454b588458SPeter Avalos 
3464b588458SPeter Avalos Cell *arg(Node **a, int n)	/* nth argument of a function */
3474b588458SPeter Avalos {
3484b588458SPeter Avalos 
3494b588458SPeter Avalos 	n = ptoi(a[0]);	/* argument number, counting from 0 */
350*1d48fce0SDaniel Fojt 	   dprintf( ("arg(%d), frp->nargs=%d\n", n, frp->nargs) );
351*1d48fce0SDaniel Fojt 	if (n+1 > frp->nargs)
3524b588458SPeter Avalos 		FATAL("argument #%d of function %s was not supplied",
353*1d48fce0SDaniel Fojt 			n+1, frp->fcncell->nval);
354*1d48fce0SDaniel Fojt 	return frp->args[n];
3554b588458SPeter Avalos }
3564b588458SPeter Avalos 
3574b588458SPeter Avalos Cell *jump(Node **a, int n)	/* break, continue, next, nextfile, return */
3584b588458SPeter Avalos {
3594b588458SPeter Avalos 	Cell *y;
3604b588458SPeter Avalos 
3614b588458SPeter Avalos 	switch (n) {
3624b588458SPeter Avalos 	case EXIT:
3634b588458SPeter Avalos 		if (a[0] != NULL) {
3644b588458SPeter Avalos 			y = execute(a[0]);
3654b588458SPeter Avalos 			errorflag = (int) getfval(y);
3664b588458SPeter Avalos 			tempfree(y);
3674b588458SPeter Avalos 		}
3684b588458SPeter Avalos 		longjmp(env, 1);
3694b588458SPeter Avalos 	case RETURN:
3704b588458SPeter Avalos 		if (a[0] != NULL) {
3714b588458SPeter Avalos 			y = execute(a[0]);
3724b588458SPeter Avalos 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
373*1d48fce0SDaniel Fojt 				setsval(frp->retval, getsval(y));
374*1d48fce0SDaniel Fojt 				frp->retval->fval = getfval(y);
375*1d48fce0SDaniel Fojt 				frp->retval->tval |= NUM;
3764b588458SPeter Avalos 			}
3774b588458SPeter Avalos 			else if (y->tval & STR)
378*1d48fce0SDaniel Fojt 				setsval(frp->retval, getsval(y));
3794b588458SPeter Avalos 			else if (y->tval & NUM)
380*1d48fce0SDaniel Fojt 				setfval(frp->retval, getfval(y));
3814b588458SPeter Avalos 			else		/* can't happen */
3824b588458SPeter Avalos 				FATAL("bad type variable %d", y->tval);
3834b588458SPeter Avalos 			tempfree(y);
3844b588458SPeter Avalos 		}
3854b588458SPeter Avalos 		return(jret);
3864b588458SPeter Avalos 	case NEXT:
3874b588458SPeter Avalos 		return(jnext);
3884b588458SPeter Avalos 	case NEXTFILE:
3894b588458SPeter Avalos 		nextfile();
3904b588458SPeter Avalos 		return(jnextfile);
3914b588458SPeter Avalos 	case BREAK:
3924b588458SPeter Avalos 		return(jbreak);
3934b588458SPeter Avalos 	case CONTINUE:
3944b588458SPeter Avalos 		return(jcont);
3954b588458SPeter Avalos 	default:	/* can't happen */
3964b588458SPeter Avalos 		FATAL("illegal jump type %d", n);
3974b588458SPeter Avalos 	}
3984b588458SPeter Avalos 	return 0;	/* not reached */
3994b588458SPeter Avalos }
4004b588458SPeter Avalos 
4014b588458SPeter Avalos Cell *awkgetline(Node **a, int n)	/* get next line from specific input */
4024b588458SPeter Avalos {		/* a[0] is variable, a[1] is operator, a[2] is filename */
4034b588458SPeter Avalos 	Cell *r, *x;
4044b588458SPeter Avalos 	extern Cell **fldtab;
4054b588458SPeter Avalos 	FILE *fp;
4064b588458SPeter Avalos 	char *buf;
4074b588458SPeter Avalos 	int bufsize = recsize;
4084b588458SPeter Avalos 	int mode;
409*1d48fce0SDaniel Fojt 	bool newflag;
4104b588458SPeter Avalos 
411*1d48fce0SDaniel Fojt 	if ((buf = malloc(bufsize)) == NULL)
4124b588458SPeter Avalos 		FATAL("out of memory in getline");
4134b588458SPeter Avalos 
4144b588458SPeter Avalos 	fflush(stdout);	/* in case someone is waiting for a prompt */
4154b588458SPeter Avalos 	r = gettemp();
4164b588458SPeter Avalos 	if (a[1] != NULL) {		/* getline < file */
4174b588458SPeter Avalos 		x = execute(a[2]);		/* filename */
4184b588458SPeter Avalos 		mode = ptoi(a[1]);
4194b588458SPeter Avalos 		if (mode == '|')		/* input pipe */
4204b588458SPeter Avalos 			mode = LE;	/* arbitrary flag */
421*1d48fce0SDaniel Fojt 		fp = openfile(mode, getsval(x), &newflag);
4224b588458SPeter Avalos 		tempfree(x);
4234b588458SPeter Avalos 		if (fp == NULL)
4244b588458SPeter Avalos 			n = -1;
4254b588458SPeter Avalos 		else
426*1d48fce0SDaniel Fojt 			n = readrec(&buf, &bufsize, fp, newflag);
4274b588458SPeter Avalos 		if (n <= 0) {
4284b588458SPeter Avalos 			;
4294b588458SPeter Avalos 		} else if (a[0] != NULL) {	/* getline var <file */
4304b588458SPeter Avalos 			x = execute(a[0]);
4314b588458SPeter Avalos 			setsval(x, buf);
432*1d48fce0SDaniel Fojt 			if (is_number(x->sval)) {
433*1d48fce0SDaniel Fojt 				x->fval = atof(x->sval);
434*1d48fce0SDaniel Fojt 				x->tval |= NUM;
435*1d48fce0SDaniel Fojt 			}
4364b588458SPeter Avalos 			tempfree(x);
4374b588458SPeter Avalos 		} else {			/* getline <file */
4384b588458SPeter Avalos 			setsval(fldtab[0], buf);
4394b588458SPeter Avalos 			if (is_number(fldtab[0]->sval)) {
4404b588458SPeter Avalos 				fldtab[0]->fval = atof(fldtab[0]->sval);
4414b588458SPeter Avalos 				fldtab[0]->tval |= NUM;
4424b588458SPeter Avalos 			}
4434b588458SPeter Avalos 		}
4444b588458SPeter Avalos 	} else {			/* bare getline; use current input */
4454b588458SPeter Avalos 		if (a[0] == NULL)	/* getline */
446*1d48fce0SDaniel Fojt 			n = getrec(&record, &recsize, true);
4474b588458SPeter Avalos 		else {			/* getline var */
448*1d48fce0SDaniel Fojt 			n = getrec(&buf, &bufsize, false);
4494b588458SPeter Avalos 			x = execute(a[0]);
4504b588458SPeter Avalos 			setsval(x, buf);
451*1d48fce0SDaniel Fojt 			if (is_number(x->sval)) {
452*1d48fce0SDaniel Fojt 				x->fval = atof(x->sval);
453*1d48fce0SDaniel Fojt 				x->tval |= NUM;
454*1d48fce0SDaniel Fojt 			}
4554b588458SPeter Avalos 			tempfree(x);
4564b588458SPeter Avalos 		}
4574b588458SPeter Avalos 	}
4584b588458SPeter Avalos 	setfval(r, (Awkfloat) n);
4594b588458SPeter Avalos 	free(buf);
4604b588458SPeter Avalos 	return r;
4614b588458SPeter Avalos }
4624b588458SPeter Avalos 
4634b588458SPeter Avalos Cell *getnf(Node **a, int n)	/* get NF */
4644b588458SPeter Avalos {
465*1d48fce0SDaniel Fojt 	if (!donefld)
4664b588458SPeter Avalos 		fldbld();
4674b588458SPeter Avalos 	return (Cell *) a[0];
4684b588458SPeter Avalos }
4694b588458SPeter Avalos 
470*1d48fce0SDaniel Fojt static char *
471*1d48fce0SDaniel Fojt makearraystring(Node *p, const char *func)
4724b588458SPeter Avalos {
4734b588458SPeter Avalos 	char *buf;
4744b588458SPeter Avalos 	int bufsz = recsize;
475*1d48fce0SDaniel Fojt 	size_t blen, seplen;
4764b588458SPeter Avalos 
477*1d48fce0SDaniel Fojt 	if ((buf = malloc(bufsz)) == NULL) {
478*1d48fce0SDaniel Fojt 		FATAL("%s: out of memory", func);
479*1d48fce0SDaniel Fojt 	}
480*1d48fce0SDaniel Fojt 
481*1d48fce0SDaniel Fojt 	blen = 0;
482*1d48fce0SDaniel Fojt 	buf[blen] = '\0';
483*1d48fce0SDaniel Fojt 	seplen = strlen(getsval(subseploc));
484*1d48fce0SDaniel Fojt 
485*1d48fce0SDaniel Fojt 	for (; p; p = p->nnext) {
486*1d48fce0SDaniel Fojt 		Cell *x = execute(p);	/* expr */
487*1d48fce0SDaniel Fojt 		char *s = getsval(x);
488*1d48fce0SDaniel Fojt 		size_t nsub = p->nnext ? seplen : 0;
489*1d48fce0SDaniel Fojt 		size_t slen = strlen(s);
490*1d48fce0SDaniel Fojt 		size_t tlen = blen + slen + nsub;
491*1d48fce0SDaniel Fojt 
492*1d48fce0SDaniel Fojt 		if (!adjbuf(&buf, &bufsz, tlen + 1, recsize, 0, func)) {
493*1d48fce0SDaniel Fojt 			FATAL("%s: out of memory %s[%s...]",
494*1d48fce0SDaniel Fojt 			    func, x->nval, buf);
495*1d48fce0SDaniel Fojt 		}
496*1d48fce0SDaniel Fojt 		memcpy(buf + blen, s, slen);
497*1d48fce0SDaniel Fojt 		if (nsub) {
498*1d48fce0SDaniel Fojt 			memcpy(buf + blen + slen, *SUBSEP, nsub);
499*1d48fce0SDaniel Fojt 		}
500*1d48fce0SDaniel Fojt 		buf[tlen] = '\0';
501*1d48fce0SDaniel Fojt 		blen = tlen;
502*1d48fce0SDaniel Fojt 		tempfree(x);
503*1d48fce0SDaniel Fojt 	}
504*1d48fce0SDaniel Fojt 	return buf;
505*1d48fce0SDaniel Fojt }
506*1d48fce0SDaniel Fojt 
507*1d48fce0SDaniel Fojt Cell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
508*1d48fce0SDaniel Fojt {
509*1d48fce0SDaniel Fojt 	Cell *x, *z;
510*1d48fce0SDaniel Fojt 	char *buf;
5114b588458SPeter Avalos 
5124b588458SPeter Avalos 	x = execute(a[0]);	/* Cell* for symbol table */
513*1d48fce0SDaniel Fojt 	buf = makearraystring(a[1], __func__);
5144b588458SPeter Avalos 	if (!isarr(x)) {
5154b588458SPeter Avalos 		   dprintf( ("making %s into an array\n", NN(x->nval)) );
5164b588458SPeter Avalos 		if (freeable(x))
5174b588458SPeter Avalos 			xfree(x->sval);
5184b588458SPeter Avalos 		x->tval &= ~(STR|NUM|DONTFREE);
5194b588458SPeter Avalos 		x->tval |= ARR;
5204b588458SPeter Avalos 		x->sval = (char *) makesymtab(NSYMTAB);
5214b588458SPeter Avalos 	}
5224b588458SPeter Avalos 	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
5234b588458SPeter Avalos 	z->ctype = OCELL;
5244b588458SPeter Avalos 	z->csub = CVAR;
5254b588458SPeter Avalos 	tempfree(x);
5264b588458SPeter Avalos 	free(buf);
5274b588458SPeter Avalos 	return(z);
5284b588458SPeter Avalos }
5294b588458SPeter Avalos 
5304b588458SPeter Avalos Cell *awkdelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
5314b588458SPeter Avalos {
532*1d48fce0SDaniel Fojt 	Cell *x;
5334b588458SPeter Avalos 
5344b588458SPeter Avalos 	x = execute(a[0]);	/* Cell* for symbol table */
535*1d48fce0SDaniel Fojt 	if (x == symtabloc) {
536*1d48fce0SDaniel Fojt 		FATAL("cannot delete SYMTAB or its elements");
537*1d48fce0SDaniel Fojt 	}
5384b588458SPeter Avalos 	if (!isarr(x))
5394b588458SPeter Avalos 		return True;
540*1d48fce0SDaniel Fojt 	if (a[1] == NULL) {	/* delete the elements, not the table */
5414b588458SPeter Avalos 		freesymtab(x);
5424b588458SPeter Avalos 		x->tval &= ~STR;
5434b588458SPeter Avalos 		x->tval |= ARR;
5444b588458SPeter Avalos 		x->sval = (char *) makesymtab(NSYMTAB);
5454b588458SPeter Avalos 	} else {
546*1d48fce0SDaniel Fojt 		char *buf = makearraystring(a[1], __func__);
5474b588458SPeter Avalos 		freeelem(x, buf);
5484b588458SPeter Avalos 		free(buf);
5494b588458SPeter Avalos 	}
5504b588458SPeter Avalos 	tempfree(x);
5514b588458SPeter Avalos 	return True;
5524b588458SPeter Avalos }
5534b588458SPeter Avalos 
5544b588458SPeter Avalos Cell *intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
5554b588458SPeter Avalos {
556*1d48fce0SDaniel Fojt 	Cell *ap, *k;
5574b588458SPeter Avalos 	char *buf;
5584b588458SPeter Avalos 
5594b588458SPeter Avalos 	ap = execute(a[1]);	/* array name */
5604b588458SPeter Avalos 	if (!isarr(ap)) {
5614b588458SPeter Avalos 		   dprintf( ("making %s into an array\n", ap->nval) );
5624b588458SPeter Avalos 		if (freeable(ap))
5634b588458SPeter Avalos 			xfree(ap->sval);
5644b588458SPeter Avalos 		ap->tval &= ~(STR|NUM|DONTFREE);
5654b588458SPeter Avalos 		ap->tval |= ARR;
5664b588458SPeter Avalos 		ap->sval = (char *) makesymtab(NSYMTAB);
5674b588458SPeter Avalos 	}
568*1d48fce0SDaniel Fojt 	buf = makearraystring(a[0], __func__);
5694b588458SPeter Avalos 	k = lookup(buf, (Array *) ap->sval);
5704b588458SPeter Avalos 	tempfree(ap);
5714b588458SPeter Avalos 	free(buf);
5724b588458SPeter Avalos 	if (k == NULL)
5734b588458SPeter Avalos 		return(False);
5744b588458SPeter Avalos 	else
5754b588458SPeter Avalos 		return(True);
5764b588458SPeter Avalos }
5774b588458SPeter Avalos 
5784b588458SPeter Avalos 
5794b588458SPeter Avalos Cell *matchop(Node **a, int n)	/* ~ and match() */
5804b588458SPeter Avalos {
5814b588458SPeter Avalos 	Cell *x, *y;
5824b588458SPeter Avalos 	char *s, *t;
5834b588458SPeter Avalos 	int i;
5844b588458SPeter Avalos 	fa *pfa;
5854b588458SPeter Avalos 	int (*mf)(fa *, const char *) = match, mode = 0;
5864b588458SPeter Avalos 
5874b588458SPeter Avalos 	if (n == MATCHFCN) {
5884b588458SPeter Avalos 		mf = pmatch;
5894b588458SPeter Avalos 		mode = 1;
5904b588458SPeter Avalos 	}
5914b588458SPeter Avalos 	x = execute(a[1]);	/* a[1] = target text */
5924b588458SPeter Avalos 	s = getsval(x);
593*1d48fce0SDaniel Fojt 	if (a[0] == NULL)	/* a[1] == 0: already-compiled reg expr */
5944b588458SPeter Avalos 		i = (*mf)((fa *) a[2], s);
5954b588458SPeter Avalos 	else {
5964b588458SPeter Avalos 		y = execute(a[2]);	/* a[2] = regular expr */
5974b588458SPeter Avalos 		t = getsval(y);
5984b588458SPeter Avalos 		pfa = makedfa(t, mode);
5994b588458SPeter Avalos 		i = (*mf)(pfa, s);
6004b588458SPeter Avalos 		tempfree(y);
6014b588458SPeter Avalos 	}
6024b588458SPeter Avalos 	tempfree(x);
6034b588458SPeter Avalos 	if (n == MATCHFCN) {
6044b588458SPeter Avalos 		int start = patbeg - s + 1;
6054b588458SPeter Avalos 		if (patlen < 0)
6064b588458SPeter Avalos 			start = 0;
6074b588458SPeter Avalos 		setfval(rstartloc, (Awkfloat) start);
6084b588458SPeter Avalos 		setfval(rlengthloc, (Awkfloat) patlen);
6094b588458SPeter Avalos 		x = gettemp();
6104b588458SPeter Avalos 		x->tval = NUM;
6114b588458SPeter Avalos 		x->fval = start;
6124b588458SPeter Avalos 		return x;
6134b588458SPeter Avalos 	} else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
6144b588458SPeter Avalos 		return(True);
6154b588458SPeter Avalos 	else
6164b588458SPeter Avalos 		return(False);
6174b588458SPeter Avalos }
6184b588458SPeter Avalos 
6194b588458SPeter Avalos 
6204b588458SPeter Avalos Cell *boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
6214b588458SPeter Avalos {
6224b588458SPeter Avalos 	Cell *x, *y;
6234b588458SPeter Avalos 	int i;
6244b588458SPeter Avalos 
6254b588458SPeter Avalos 	x = execute(a[0]);
6264b588458SPeter Avalos 	i = istrue(x);
6274b588458SPeter Avalos 	tempfree(x);
6284b588458SPeter Avalos 	switch (n) {
6294b588458SPeter Avalos 	case BOR:
6304b588458SPeter Avalos 		if (i) return(True);
6314b588458SPeter Avalos 		y = execute(a[1]);
6324b588458SPeter Avalos 		i = istrue(y);
6334b588458SPeter Avalos 		tempfree(y);
6344b588458SPeter Avalos 		if (i) return(True);
6354b588458SPeter Avalos 		else return(False);
6364b588458SPeter Avalos 	case AND:
6374b588458SPeter Avalos 		if ( !i ) return(False);
6384b588458SPeter Avalos 		y = execute(a[1]);
6394b588458SPeter Avalos 		i = istrue(y);
6404b588458SPeter Avalos 		tempfree(y);
6414b588458SPeter Avalos 		if (i) return(True);
6424b588458SPeter Avalos 		else return(False);
6434b588458SPeter Avalos 	case NOT:
6444b588458SPeter Avalos 		if (i) return(False);
6454b588458SPeter Avalos 		else return(True);
6464b588458SPeter Avalos 	default:	/* can't happen */
6474b588458SPeter Avalos 		FATAL("unknown boolean operator %d", n);
6484b588458SPeter Avalos 	}
6494b588458SPeter Avalos 	return 0;	/*NOTREACHED*/
6504b588458SPeter Avalos }
6514b588458SPeter Avalos 
6524b588458SPeter Avalos Cell *relop(Node **a, int n)	/* a[0 < a[1], etc. */
6534b588458SPeter Avalos {
6544b588458SPeter Avalos 	int i;
6554b588458SPeter Avalos 	Cell *x, *y;
6564b588458SPeter Avalos 	Awkfloat j;
6574b588458SPeter Avalos 
6584b588458SPeter Avalos 	x = execute(a[0]);
6594b588458SPeter Avalos 	y = execute(a[1]);
6604b588458SPeter Avalos 	if (x->tval&NUM && y->tval&NUM) {
6614b588458SPeter Avalos 		j = x->fval - y->fval;
6624b588458SPeter Avalos 		i = j<0? -1: (j>0? 1: 0);
6634b588458SPeter Avalos 	} else {
6644b588458SPeter Avalos 		i = strcmp(getsval(x), getsval(y));
6654b588458SPeter Avalos 	}
6664b588458SPeter Avalos 	tempfree(x);
6674b588458SPeter Avalos 	tempfree(y);
6684b588458SPeter Avalos 	switch (n) {
6694b588458SPeter Avalos 	case LT:	if (i<0) return(True);
6704b588458SPeter Avalos 			else return(False);
6714b588458SPeter Avalos 	case LE:	if (i<=0) return(True);
6724b588458SPeter Avalos 			else return(False);
6734b588458SPeter Avalos 	case NE:	if (i!=0) return(True);
6744b588458SPeter Avalos 			else return(False);
6754b588458SPeter Avalos 	case EQ:	if (i == 0) return(True);
6764b588458SPeter Avalos 			else return(False);
6774b588458SPeter Avalos 	case GE:	if (i>=0) return(True);
6784b588458SPeter Avalos 			else return(False);
6794b588458SPeter Avalos 	case GT:	if (i>0) return(True);
6804b588458SPeter Avalos 			else return(False);
6814b588458SPeter Avalos 	default:	/* can't happen */
6824b588458SPeter Avalos 		FATAL("unknown relational operator %d", n);
6834b588458SPeter Avalos 	}
6844b588458SPeter Avalos 	return 0;	/*NOTREACHED*/
6854b588458SPeter Avalos }
6864b588458SPeter Avalos 
6874b588458SPeter Avalos void tfree(Cell *a)	/* free a tempcell */
6884b588458SPeter Avalos {
6894b588458SPeter Avalos 	if (freeable(a)) {
6904b588458SPeter Avalos 		   dprintf( ("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval) );
6914b588458SPeter Avalos 		xfree(a->sval);
6924b588458SPeter Avalos 	}
6934b588458SPeter Avalos 	if (a == tmps)
6944b588458SPeter Avalos 		FATAL("tempcell list is curdled");
6954b588458SPeter Avalos 	a->cnext = tmps;
6964b588458SPeter Avalos 	tmps = a;
6974b588458SPeter Avalos }
6984b588458SPeter Avalos 
6994b588458SPeter Avalos Cell *gettemp(void)	/* get a tempcell */
7004b588458SPeter Avalos {	int i;
7014b588458SPeter Avalos 	Cell *x;
7024b588458SPeter Avalos 
7034b588458SPeter Avalos 	if (!tmps) {
704*1d48fce0SDaniel Fojt 		tmps = calloc(100, sizeof(*tmps));
7054b588458SPeter Avalos 		if (!tmps)
7064b588458SPeter Avalos 			FATAL("out of space for temporaries");
7074b588458SPeter Avalos 		for (i = 1; i < 100; i++)
7084b588458SPeter Avalos 			tmps[i-1].cnext = &tmps[i];
709*1d48fce0SDaniel Fojt 		tmps[i-1].cnext = NULL;
7104b588458SPeter Avalos 	}
7114b588458SPeter Avalos 	x = tmps;
7124b588458SPeter Avalos 	tmps = x->cnext;
7134b588458SPeter Avalos 	*x = tempcell;
7144b588458SPeter Avalos 	return(x);
7154b588458SPeter Avalos }
7164b588458SPeter Avalos 
7174b588458SPeter Avalos Cell *indirect(Node **a, int n)	/* $( a[0] ) */
7184b588458SPeter Avalos {
7194b588458SPeter Avalos 	Awkfloat val;
7204b588458SPeter Avalos 	Cell *x;
7214b588458SPeter Avalos 	int m;
7224b588458SPeter Avalos 	char *s;
7234b588458SPeter Avalos 
7244b588458SPeter Avalos 	x = execute(a[0]);
7254b588458SPeter Avalos 	val = getfval(x);	/* freebsd: defend against super large field numbers */
7264b588458SPeter Avalos 	if ((Awkfloat)INT_MAX < val)
7274b588458SPeter Avalos 		FATAL("trying to access out of range field %s", x->nval);
7284b588458SPeter Avalos 	m = (int) val;
7294b588458SPeter Avalos 	if (m == 0 && !is_number(s = getsval(x)))	/* suspicion! */
7304b588458SPeter Avalos 		FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
7314b588458SPeter Avalos 		/* BUG: can x->nval ever be null??? */
7324b588458SPeter Avalos 	tempfree(x);
7334b588458SPeter Avalos 	x = fieldadr(m);
7344b588458SPeter Avalos 	x->ctype = OCELL;	/* BUG?  why are these needed? */
7354b588458SPeter Avalos 	x->csub = CFLD;
7364b588458SPeter Avalos 	return(x);
7374b588458SPeter Avalos }
7384b588458SPeter Avalos 
7394b588458SPeter Avalos Cell *substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
7404b588458SPeter Avalos {
7414b588458SPeter Avalos 	int k, m, n;
7424b588458SPeter Avalos 	char *s;
7434b588458SPeter Avalos 	int temp;
744*1d48fce0SDaniel Fojt 	Cell *x, *y, *z = NULL;
7454b588458SPeter Avalos 
7464b588458SPeter Avalos 	x = execute(a[0]);
7474b588458SPeter Avalos 	y = execute(a[1]);
748*1d48fce0SDaniel Fojt 	if (a[2] != NULL)
7494b588458SPeter Avalos 		z = execute(a[2]);
7504b588458SPeter Avalos 	s = getsval(x);
7514b588458SPeter Avalos 	k = strlen(s) + 1;
7524b588458SPeter Avalos 	if (k <= 1) {
7534b588458SPeter Avalos 		tempfree(x);
7544b588458SPeter Avalos 		tempfree(y);
755*1d48fce0SDaniel Fojt 		if (a[2] != NULL) {
7564b588458SPeter Avalos 			tempfree(z);
7574b588458SPeter Avalos 		}
7584b588458SPeter Avalos 		x = gettemp();
7594b588458SPeter Avalos 		setsval(x, "");
7604b588458SPeter Avalos 		return(x);
7614b588458SPeter Avalos 	}
7624b588458SPeter Avalos 	m = (int) getfval(y);
7634b588458SPeter Avalos 	if (m <= 0)
7644b588458SPeter Avalos 		m = 1;
7654b588458SPeter Avalos 	else if (m > k)
7664b588458SPeter Avalos 		m = k;
7674b588458SPeter Avalos 	tempfree(y);
768*1d48fce0SDaniel Fojt 	if (a[2] != NULL) {
7694b588458SPeter Avalos 		n = (int) getfval(z);
7704b588458SPeter Avalos 		tempfree(z);
7714b588458SPeter Avalos 	} else
7724b588458SPeter Avalos 		n = k - 1;
7734b588458SPeter Avalos 	if (n < 0)
7744b588458SPeter Avalos 		n = 0;
7754b588458SPeter Avalos 	else if (n > k - m)
7764b588458SPeter Avalos 		n = k - m;
7774b588458SPeter Avalos 	   dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
7784b588458SPeter Avalos 	y = gettemp();
7794b588458SPeter Avalos 	temp = s[n+m-1];	/* with thanks to John Linderman */
7804b588458SPeter Avalos 	s[n+m-1] = '\0';
7814b588458SPeter Avalos 	setsval(y, s + m - 1);
7824b588458SPeter Avalos 	s[n+m-1] = temp;
7834b588458SPeter Avalos 	tempfree(x);
7844b588458SPeter Avalos 	return(y);
7854b588458SPeter Avalos }
7864b588458SPeter Avalos 
7874b588458SPeter Avalos Cell *sindex(Node **a, int nnn)		/* index(a[0], a[1]) */
7884b588458SPeter Avalos {
7894b588458SPeter Avalos 	Cell *x, *y, *z;
7904b588458SPeter Avalos 	char *s1, *s2, *p1, *p2, *q;
7914b588458SPeter Avalos 	Awkfloat v = 0.0;
7924b588458SPeter Avalos 
7934b588458SPeter Avalos 	x = execute(a[0]);
7944b588458SPeter Avalos 	s1 = getsval(x);
7954b588458SPeter Avalos 	y = execute(a[1]);
7964b588458SPeter Avalos 	s2 = getsval(y);
7974b588458SPeter Avalos 
7984b588458SPeter Avalos 	z = gettemp();
7994b588458SPeter Avalos 	for (p1 = s1; *p1 != '\0'; p1++) {
8004b588458SPeter Avalos 		for (q = p1, p2 = s2; *p2 != '\0' && *q == *p2; q++, p2++)
801*1d48fce0SDaniel Fojt 			continue;
8024b588458SPeter Avalos 		if (*p2 == '\0') {
8034b588458SPeter Avalos 			v = (Awkfloat) (p1 - s1 + 1);	/* origin 1 */
8044b588458SPeter Avalos 			break;
8054b588458SPeter Avalos 		}
8064b588458SPeter Avalos 	}
8074b588458SPeter Avalos 	tempfree(x);
8084b588458SPeter Avalos 	tempfree(y);
8094b588458SPeter Avalos 	setfval(z, v);
8104b588458SPeter Avalos 	return(z);
8114b588458SPeter Avalos }
8124b588458SPeter Avalos 
8134b588458SPeter Avalos #define	MAXNUMSIZE	50
8144b588458SPeter Avalos 
8154b588458SPeter Avalos int format(char **pbuf, int *pbufsize, const char *s, Node *a)	/* printf-like conversions */
8164b588458SPeter Avalos {
8174b588458SPeter Avalos 	char *fmt;
8184b588458SPeter Avalos 	char *p, *t;
8194b588458SPeter Avalos 	const char *os;
8204b588458SPeter Avalos 	Cell *x;
8214b588458SPeter Avalos 	int flag = 0, n;
8224b588458SPeter Avalos 	int fmtwd; /* format width */
8234b588458SPeter Avalos 	int fmtsz = recsize;
8244b588458SPeter Avalos 	char *buf = *pbuf;
8254b588458SPeter Avalos 	int bufsize = *pbufsize;
826*1d48fce0SDaniel Fojt #define FMTSZ(a)   (fmtsz - ((a) - fmt))
827*1d48fce0SDaniel Fojt #define BUFSZ(a)   (bufsize - ((a) - buf))
828*1d48fce0SDaniel Fojt 
829*1d48fce0SDaniel Fojt 	static bool first = true;
830*1d48fce0SDaniel Fojt 	static bool have_a_format = false;
831*1d48fce0SDaniel Fojt 
832*1d48fce0SDaniel Fojt 	if (first) {
833*1d48fce0SDaniel Fojt 		char xbuf[100];
834*1d48fce0SDaniel Fojt 
835*1d48fce0SDaniel Fojt 		snprintf(xbuf, sizeof(xbuf), "%a", 42.0);
836*1d48fce0SDaniel Fojt 		have_a_format = (strcmp(xbuf, "0x1.5p+5") == 0);
837*1d48fce0SDaniel Fojt 		first = false;
838*1d48fce0SDaniel Fojt 	}
8394b588458SPeter Avalos 
8404b588458SPeter Avalos 	os = s;
8414b588458SPeter Avalos 	p = buf;
842*1d48fce0SDaniel Fojt 	if ((fmt = malloc(fmtsz)) == NULL)
8434b588458SPeter Avalos 		FATAL("out of memory in format()");
8444b588458SPeter Avalos 	while (*s) {
8454b588458SPeter Avalos 		adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1");
8464b588458SPeter Avalos 		if (*s != '%') {
8474b588458SPeter Avalos 			*p++ = *s++;
8484b588458SPeter Avalos 			continue;
8494b588458SPeter Avalos 		}
8504b588458SPeter Avalos 		if (*(s+1) == '%') {
8514b588458SPeter Avalos 			*p++ = '%';
8524b588458SPeter Avalos 			s += 2;
8534b588458SPeter Avalos 			continue;
8544b588458SPeter Avalos 		}
8554b588458SPeter Avalos 		/* have to be real careful in case this is a huge number, eg, %100000d */
8564b588458SPeter Avalos 		fmtwd = atoi(s+1);
8574b588458SPeter Avalos 		if (fmtwd < 0)
8584b588458SPeter Avalos 			fmtwd = -fmtwd;
8594b588458SPeter Avalos 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format2");
8604b588458SPeter Avalos 		for (t = fmt; (*t++ = *s) != '\0'; s++) {
8614b588458SPeter Avalos 			if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3"))
8624b588458SPeter Avalos 				FATAL("format item %.30s... ran format() out of memory", os);
863*1d48fce0SDaniel Fojt 			/* Ignore size specifiers */
864*1d48fce0SDaniel Fojt 			if (strchr("hjLlqtz", *s) != NULL) {	/* the ansi panoply */
865*1d48fce0SDaniel Fojt 				t--;
866*1d48fce0SDaniel Fojt 				continue;
867*1d48fce0SDaniel Fojt 			}
868*1d48fce0SDaniel Fojt 			if (isalpha((uschar)*s))
869*1d48fce0SDaniel Fojt 				break;
870*1d48fce0SDaniel Fojt 			if (*s == '$') {
871*1d48fce0SDaniel Fojt 				FATAL("'$' not permitted in awk formats");
872*1d48fce0SDaniel Fojt 			}
8734b588458SPeter Avalos 			if (*s == '*') {
874*1d48fce0SDaniel Fojt 				if (a == NULL) {
875*1d48fce0SDaniel Fojt 					FATAL("not enough args in printf(%s)", os);
876*1d48fce0SDaniel Fojt 				}
8774b588458SPeter Avalos 				x = execute(a);
8784b588458SPeter Avalos 				a = a->nnext;
879*1d48fce0SDaniel Fojt 				snprintf(t - 1, FMTSZ(t - 1),
880*1d48fce0SDaniel Fojt 				    "%d", fmtwd=(int) getfval(x));
8814b588458SPeter Avalos 				if (fmtwd < 0)
8824b588458SPeter Avalos 					fmtwd = -fmtwd;
8834b588458SPeter Avalos 				adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
8844b588458SPeter Avalos 				t = fmt + strlen(fmt);
8854b588458SPeter Avalos 				tempfree(x);
8864b588458SPeter Avalos 			}
8874b588458SPeter Avalos 		}
8884b588458SPeter Avalos 		*t = '\0';
8894b588458SPeter Avalos 		if (fmtwd < 0)
8904b588458SPeter Avalos 			fmtwd = -fmtwd;
8914b588458SPeter Avalos 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format4");
8924b588458SPeter Avalos 		switch (*s) {
893*1d48fce0SDaniel Fojt 		case 'a': case 'A':
894*1d48fce0SDaniel Fojt 			if (have_a_format)
895*1d48fce0SDaniel Fojt 				flag = *s;
896*1d48fce0SDaniel Fojt 			else
897*1d48fce0SDaniel Fojt 				flag = 'f';
898*1d48fce0SDaniel Fojt 			break;
8994b588458SPeter Avalos 		case 'f': case 'e': case 'g': case 'E': case 'G':
9004b588458SPeter Avalos 			flag = 'f';
9014b588458SPeter Avalos 			break;
902*1d48fce0SDaniel Fojt 		case 'd': case 'i': case 'o': case 'x': case 'X': case 'u':
903*1d48fce0SDaniel Fojt 			flag = (*s == 'd' || *s == 'i') ? 'd' : 'u';
904*1d48fce0SDaniel Fojt 			*(t-1) = 'j';
905*1d48fce0SDaniel Fojt 			*t = *s;
9064b588458SPeter Avalos 			*++t = '\0';
9074b588458SPeter Avalos 			break;
9084b588458SPeter Avalos 		case 's':
9094b588458SPeter Avalos 			flag = 's';
9104b588458SPeter Avalos 			break;
9114b588458SPeter Avalos 		case 'c':
9124b588458SPeter Avalos 			flag = 'c';
9134b588458SPeter Avalos 			break;
9144b588458SPeter Avalos 		default:
9154b588458SPeter Avalos 			WARNING("weird printf conversion %s", fmt);
9164b588458SPeter Avalos 			flag = '?';
9174b588458SPeter Avalos 			break;
9184b588458SPeter Avalos 		}
9194b588458SPeter Avalos 		if (a == NULL)
9204b588458SPeter Avalos 			FATAL("not enough args in printf(%s)", os);
9214b588458SPeter Avalos 		x = execute(a);
9224b588458SPeter Avalos 		a = a->nnext;
9234b588458SPeter Avalos 		n = MAXNUMSIZE;
9244b588458SPeter Avalos 		if (fmtwd > n)
9254b588458SPeter Avalos 			n = fmtwd;
9264b588458SPeter Avalos 		adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5");
9274b588458SPeter Avalos 		switch (flag) {
928*1d48fce0SDaniel Fojt 		case '?':	snprintf(p, BUFSZ(p), "%s", fmt);	/* unknown, so dump it too */
9294b588458SPeter Avalos 			t = getsval(x);
9304b588458SPeter Avalos 			n = strlen(t);
9314b588458SPeter Avalos 			if (fmtwd > n)
9324b588458SPeter Avalos 				n = fmtwd;
9334b588458SPeter Avalos 			adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6");
9344b588458SPeter Avalos 			p += strlen(p);
935*1d48fce0SDaniel Fojt 			snprintf(p, BUFSZ(p), "%s", t);
9364b588458SPeter Avalos 			break;
937*1d48fce0SDaniel Fojt 		case 'a':
938*1d48fce0SDaniel Fojt 		case 'A':
939*1d48fce0SDaniel Fojt 		case 'f':	snprintf(p, BUFSZ(p), fmt, getfval(x)); break;
940*1d48fce0SDaniel Fojt 		case 'd':	snprintf(p, BUFSZ(p), fmt, (intmax_t) getfval(x)); break;
941*1d48fce0SDaniel Fojt 		case 'u':	snprintf(p, BUFSZ(p), fmt, (uintmax_t) getfval(x)); break;
9424b588458SPeter Avalos 		case 's':
9434b588458SPeter Avalos 			t = getsval(x);
9444b588458SPeter Avalos 			n = strlen(t);
9454b588458SPeter Avalos 			if (fmtwd > n)
9464b588458SPeter Avalos 				n = fmtwd;
9474b588458SPeter Avalos 			if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7"))
9484b588458SPeter Avalos 				FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
949*1d48fce0SDaniel Fojt 			snprintf(p, BUFSZ(p), fmt, t);
9504b588458SPeter Avalos 			break;
9514b588458SPeter Avalos 		case 'c':
9524b588458SPeter Avalos 			if (isnum(x)) {
953*1d48fce0SDaniel Fojt 				if ((int)getfval(x))
954*1d48fce0SDaniel Fojt 					snprintf(p, BUFSZ(p), fmt, (int) getfval(x));
9554b588458SPeter Avalos 				else {
9564b588458SPeter Avalos 					*p++ = '\0'; /* explicit null byte */
9574b588458SPeter Avalos 					*p = '\0';   /* next output will start here */
9584b588458SPeter Avalos 				}
9594b588458SPeter Avalos 			} else
960*1d48fce0SDaniel Fojt 				snprintf(p, BUFSZ(p), fmt, getsval(x)[0]);
9614b588458SPeter Avalos 			break;
9624b588458SPeter Avalos 		default:
9634b588458SPeter Avalos 			FATAL("can't happen: bad conversion %c in format()", flag);
9644b588458SPeter Avalos 		}
9654b588458SPeter Avalos 		tempfree(x);
9664b588458SPeter Avalos 		p += strlen(p);
9674b588458SPeter Avalos 		s++;
9684b588458SPeter Avalos 	}
9694b588458SPeter Avalos 	*p = '\0';
9704b588458SPeter Avalos 	free(fmt);
9714b588458SPeter Avalos 	for ( ; a; a = a->nnext)		/* evaluate any remaining args */
9724b588458SPeter Avalos 		execute(a);
9734b588458SPeter Avalos 	*pbuf = buf;
9744b588458SPeter Avalos 	*pbufsize = bufsize;
9754b588458SPeter Avalos 	return p - buf;
9764b588458SPeter Avalos }
9774b588458SPeter Avalos 
9784b588458SPeter Avalos Cell *awksprintf(Node **a, int n)		/* sprintf(a[0]) */
9794b588458SPeter Avalos {
9804b588458SPeter Avalos 	Cell *x;
9814b588458SPeter Avalos 	Node *y;
9824b588458SPeter Avalos 	char *buf;
9834b588458SPeter Avalos 	int bufsz=3*recsize;
9844b588458SPeter Avalos 
985*1d48fce0SDaniel Fojt 	if ((buf = malloc(bufsz)) == NULL)
9864b588458SPeter Avalos 		FATAL("out of memory in awksprintf");
9874b588458SPeter Avalos 	y = a[0]->nnext;
9884b588458SPeter Avalos 	x = execute(a[0]);
9894b588458SPeter Avalos 	if (format(&buf, &bufsz, getsval(x), y) == -1)
9904b588458SPeter Avalos 		FATAL("sprintf string %.30s... too long.  can't happen.", buf);
9914b588458SPeter Avalos 	tempfree(x);
9924b588458SPeter Avalos 	x = gettemp();
9934b588458SPeter Avalos 	x->sval = buf;
9944b588458SPeter Avalos 	x->tval = STR;
9954b588458SPeter Avalos 	return(x);
9964b588458SPeter Avalos }
9974b588458SPeter Avalos 
9984b588458SPeter Avalos Cell *awkprintf(Node **a, int n)		/* printf */
9994b588458SPeter Avalos {	/* a[0] is list of args, starting with format string */
10004b588458SPeter Avalos 	/* a[1] is redirection operator, a[2] is redirection file */
10014b588458SPeter Avalos 	FILE *fp;
10024b588458SPeter Avalos 	Cell *x;
10034b588458SPeter Avalos 	Node *y;
10044b588458SPeter Avalos 	char *buf;
10054b588458SPeter Avalos 	int len;
10064b588458SPeter Avalos 	int bufsz=3*recsize;
10074b588458SPeter Avalos 
1008*1d48fce0SDaniel Fojt 	if ((buf = malloc(bufsz)) == NULL)
10094b588458SPeter Avalos 		FATAL("out of memory in awkprintf");
10104b588458SPeter Avalos 	y = a[0]->nnext;
10114b588458SPeter Avalos 	x = execute(a[0]);
10124b588458SPeter Avalos 	if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
10134b588458SPeter Avalos 		FATAL("printf string %.30s... too long.  can't happen.", buf);
10144b588458SPeter Avalos 	tempfree(x);
10154b588458SPeter Avalos 	if (a[1] == NULL) {
10164b588458SPeter Avalos 		/* fputs(buf, stdout); */
10174b588458SPeter Avalos 		fwrite(buf, len, 1, stdout);
10184b588458SPeter Avalos 		if (ferror(stdout))
10194b588458SPeter Avalos 			FATAL("write error on stdout");
10204b588458SPeter Avalos 	} else {
10214b588458SPeter Avalos 		fp = redirect(ptoi(a[1]), a[2]);
10224b588458SPeter Avalos 		/* fputs(buf, fp); */
10234b588458SPeter Avalos 		fwrite(buf, len, 1, fp);
10244b588458SPeter Avalos 		fflush(fp);
10254b588458SPeter Avalos 		if (ferror(fp))
10264b588458SPeter Avalos 			FATAL("write error on %s", filename(fp));
10274b588458SPeter Avalos 	}
10284b588458SPeter Avalos 	free(buf);
10294b588458SPeter Avalos 	return(True);
10304b588458SPeter Avalos }
10314b588458SPeter Avalos 
10324b588458SPeter Avalos Cell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
10334b588458SPeter Avalos {
10344b588458SPeter Avalos 	Awkfloat i, j = 0;
10354b588458SPeter Avalos 	double v;
10364b588458SPeter Avalos 	Cell *x, *y, *z;
10374b588458SPeter Avalos 
10384b588458SPeter Avalos 	x = execute(a[0]);
10394b588458SPeter Avalos 	i = getfval(x);
10404b588458SPeter Avalos 	tempfree(x);
1041*1d48fce0SDaniel Fojt 	if (n != UMINUS && n != UPLUS) {
10424b588458SPeter Avalos 		y = execute(a[1]);
10434b588458SPeter Avalos 		j = getfval(y);
10444b588458SPeter Avalos 		tempfree(y);
10454b588458SPeter Avalos 	}
10464b588458SPeter Avalos 	z = gettemp();
10474b588458SPeter Avalos 	switch (n) {
10484b588458SPeter Avalos 	case ADD:
10494b588458SPeter Avalos 		i += j;
10504b588458SPeter Avalos 		break;
10514b588458SPeter Avalos 	case MINUS:
10524b588458SPeter Avalos 		i -= j;
10534b588458SPeter Avalos 		break;
10544b588458SPeter Avalos 	case MULT:
10554b588458SPeter Avalos 		i *= j;
10564b588458SPeter Avalos 		break;
10574b588458SPeter Avalos 	case DIVIDE:
10584b588458SPeter Avalos 		if (j == 0)
10594b588458SPeter Avalos 			FATAL("division by zero");
10604b588458SPeter Avalos 		i /= j;
10614b588458SPeter Avalos 		break;
10624b588458SPeter Avalos 	case MOD:
10634b588458SPeter Avalos 		if (j == 0)
10644b588458SPeter Avalos 			FATAL("division by zero in mod");
10654b588458SPeter Avalos 		modf(i/j, &v);
10664b588458SPeter Avalos 		i = i - j * v;
10674b588458SPeter Avalos 		break;
10684b588458SPeter Avalos 	case UMINUS:
10694b588458SPeter Avalos 		i = -i;
10704b588458SPeter Avalos 		break;
1071*1d48fce0SDaniel Fojt 	case UPLUS: /* handled by getfval(), above */
1072*1d48fce0SDaniel Fojt 		break;
10734b588458SPeter Avalos 	case POWER:
10744b588458SPeter Avalos 		if (j >= 0 && modf(j, &v) == 0.0)	/* pos integer exponent */
10754b588458SPeter Avalos 			i = ipow(i, (int) j);
1076*1d48fce0SDaniel Fojt                else {
1077*1d48fce0SDaniel Fojt 			errno = 0;
10784b588458SPeter Avalos 			i = errcheck(pow(i, j), "pow");
1079*1d48fce0SDaniel Fojt                }
10804b588458SPeter Avalos 		break;
10814b588458SPeter Avalos 	default:	/* can't happen */
10824b588458SPeter Avalos 		FATAL("illegal arithmetic operator %d", n);
10834b588458SPeter Avalos 	}
10844b588458SPeter Avalos 	setfval(z, i);
10854b588458SPeter Avalos 	return(z);
10864b588458SPeter Avalos }
10874b588458SPeter Avalos 
10884b588458SPeter Avalos double ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
10894b588458SPeter Avalos {
10904b588458SPeter Avalos 	double v;
10914b588458SPeter Avalos 
10924b588458SPeter Avalos 	if (n <= 0)
10934b588458SPeter Avalos 		return 1;
10944b588458SPeter Avalos 	v = ipow(x, n/2);
10954b588458SPeter Avalos 	if (n % 2 == 0)
10964b588458SPeter Avalos 		return v * v;
10974b588458SPeter Avalos 	else
10984b588458SPeter Avalos 		return x * v * v;
10994b588458SPeter Avalos }
11004b588458SPeter Avalos 
11014b588458SPeter Avalos Cell *incrdecr(Node **a, int n)		/* a[0]++, etc. */
11024b588458SPeter Avalos {
11034b588458SPeter Avalos 	Cell *x, *z;
11044b588458SPeter Avalos 	int k;
11054b588458SPeter Avalos 	Awkfloat xf;
11064b588458SPeter Avalos 
11074b588458SPeter Avalos 	x = execute(a[0]);
11084b588458SPeter Avalos 	xf = getfval(x);
11094b588458SPeter Avalos 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
11104b588458SPeter Avalos 	if (n == PREINCR || n == PREDECR) {
11114b588458SPeter Avalos 		setfval(x, xf + k);
11124b588458SPeter Avalos 		return(x);
11134b588458SPeter Avalos 	}
11144b588458SPeter Avalos 	z = gettemp();
11154b588458SPeter Avalos 	setfval(z, xf);
11164b588458SPeter Avalos 	setfval(x, xf + k);
11174b588458SPeter Avalos 	tempfree(x);
11184b588458SPeter Avalos 	return(z);
11194b588458SPeter Avalos }
11204b588458SPeter Avalos 
11214b588458SPeter Avalos Cell *assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
11224b588458SPeter Avalos {		/* this is subtle; don't muck with it. */
11234b588458SPeter Avalos 	Cell *x, *y;
11244b588458SPeter Avalos 	Awkfloat xf, yf;
11254b588458SPeter Avalos 	double v;
11264b588458SPeter Avalos 
11274b588458SPeter Avalos 	y = execute(a[1]);
11284b588458SPeter Avalos 	x = execute(a[0]);
11294b588458SPeter Avalos 	if (n == ASSIGN) {	/* ordinary assignment */
1130*1d48fce0SDaniel Fojt 		if (x == y && !(x->tval & (FLD|REC)) && x != nfloc)
1131*1d48fce0SDaniel Fojt 			;	/* self-assignment: leave alone unless it's a field or NF */
11324b588458SPeter Avalos 		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
11334b588458SPeter Avalos 			setsval(x, getsval(y));
11344b588458SPeter Avalos 			x->fval = getfval(y);
11354b588458SPeter Avalos 			x->tval |= NUM;
11364b588458SPeter Avalos 		}
11374b588458SPeter Avalos 		else if (isstr(y))
11384b588458SPeter Avalos 			setsval(x, getsval(y));
11394b588458SPeter Avalos 		else if (isnum(y))
11404b588458SPeter Avalos 			setfval(x, getfval(y));
11414b588458SPeter Avalos 		else
11424b588458SPeter Avalos 			funnyvar(y, "read value of");
11434b588458SPeter Avalos 		tempfree(y);
11444b588458SPeter Avalos 		return(x);
11454b588458SPeter Avalos 	}
11464b588458SPeter Avalos 	xf = getfval(x);
11474b588458SPeter Avalos 	yf = getfval(y);
11484b588458SPeter Avalos 	switch (n) {
11494b588458SPeter Avalos 	case ADDEQ:
11504b588458SPeter Avalos 		xf += yf;
11514b588458SPeter Avalos 		break;
11524b588458SPeter Avalos 	case SUBEQ:
11534b588458SPeter Avalos 		xf -= yf;
11544b588458SPeter Avalos 		break;
11554b588458SPeter Avalos 	case MULTEQ:
11564b588458SPeter Avalos 		xf *= yf;
11574b588458SPeter Avalos 		break;
11584b588458SPeter Avalos 	case DIVEQ:
11594b588458SPeter Avalos 		if (yf == 0)
11604b588458SPeter Avalos 			FATAL("division by zero in /=");
11614b588458SPeter Avalos 		xf /= yf;
11624b588458SPeter Avalos 		break;
11634b588458SPeter Avalos 	case MODEQ:
11644b588458SPeter Avalos 		if (yf == 0)
11654b588458SPeter Avalos 			FATAL("division by zero in %%=");
11664b588458SPeter Avalos 		modf(xf/yf, &v);
11674b588458SPeter Avalos 		xf = xf - yf * v;
11684b588458SPeter Avalos 		break;
11694b588458SPeter Avalos 	case POWEQ:
11704b588458SPeter Avalos 		if (yf >= 0 && modf(yf, &v) == 0.0)	/* pos integer exponent */
11714b588458SPeter Avalos 			xf = ipow(xf, (int) yf);
1172*1d48fce0SDaniel Fojt                else {
1173*1d48fce0SDaniel Fojt 			errno = 0;
11744b588458SPeter Avalos 			xf = errcheck(pow(xf, yf), "pow");
1175*1d48fce0SDaniel Fojt                }
11764b588458SPeter Avalos 		break;
11774b588458SPeter Avalos 	default:
11784b588458SPeter Avalos 		FATAL("illegal assignment operator %d", n);
11794b588458SPeter Avalos 		break;
11804b588458SPeter Avalos 	}
11814b588458SPeter Avalos 	tempfree(y);
11824b588458SPeter Avalos 	setfval(x, xf);
11834b588458SPeter Avalos 	return(x);
11844b588458SPeter Avalos }
11854b588458SPeter Avalos 
11864b588458SPeter Avalos Cell *cat(Node **a, int q)	/* a[0] cat a[1] */
11874b588458SPeter Avalos {
11884b588458SPeter Avalos 	Cell *x, *y, *z;
11894b588458SPeter Avalos 	int n1, n2;
1190*1d48fce0SDaniel Fojt 	char *s = NULL;
1191*1d48fce0SDaniel Fojt 	int ssz = 0;
11924b588458SPeter Avalos 
11934b588458SPeter Avalos 	x = execute(a[0]);
1194*1d48fce0SDaniel Fojt 	n1 = strlen(getsval(x));
1195*1d48fce0SDaniel Fojt 
11964b588458SPeter Avalos 	y = execute(a[1]);
1197*1d48fce0SDaniel Fojt 	n2 = strlen(getsval(y));
1198*1d48fce0SDaniel Fojt 
1199*1d48fce0SDaniel Fojt 	adjbuf(&s, &ssz, n1 + n2 + 1, recsize, 0, "cat");
1200*1d48fce0SDaniel Fojt 	memcpy(s, x->sval, n1);
1201*1d48fce0SDaniel Fojt 	memcpy(s + n1, y->sval, n2);
1202*1d48fce0SDaniel Fojt 	s[n1 + n2] = '\0';
1203*1d48fce0SDaniel Fojt 
12044b588458SPeter Avalos 	tempfree(x);
12054b588458SPeter Avalos 	tempfree(y);
1206*1d48fce0SDaniel Fojt 
12074b588458SPeter Avalos 	z = gettemp();
12084b588458SPeter Avalos 	z->sval = s;
12094b588458SPeter Avalos 	z->tval = STR;
1210*1d48fce0SDaniel Fojt 
12114b588458SPeter Avalos 	return(z);
12124b588458SPeter Avalos }
12134b588458SPeter Avalos 
12144b588458SPeter Avalos Cell *pastat(Node **a, int n)	/* a[0] { a[1] } */
12154b588458SPeter Avalos {
12164b588458SPeter Avalos 	Cell *x;
12174b588458SPeter Avalos 
1218*1d48fce0SDaniel Fojt 	if (a[0] == NULL)
12194b588458SPeter Avalos 		x = execute(a[1]);
12204b588458SPeter Avalos 	else {
12214b588458SPeter Avalos 		x = execute(a[0]);
12224b588458SPeter Avalos 		if (istrue(x)) {
12234b588458SPeter Avalos 			tempfree(x);
12244b588458SPeter Avalos 			x = execute(a[1]);
12254b588458SPeter Avalos 		}
12264b588458SPeter Avalos 	}
12274b588458SPeter Avalos 	return x;
12284b588458SPeter Avalos }
12294b588458SPeter Avalos 
12304b588458SPeter Avalos Cell *dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
12314b588458SPeter Avalos {
12324b588458SPeter Avalos 	Cell *x;
12334b588458SPeter Avalos 	int pair;
12344b588458SPeter Avalos 
12354b588458SPeter Avalos 	pair = ptoi(a[3]);
12364b588458SPeter Avalos 	if (pairstack[pair] == 0) {
12374b588458SPeter Avalos 		x = execute(a[0]);
12384b588458SPeter Avalos 		if (istrue(x))
12394b588458SPeter Avalos 			pairstack[pair] = 1;
12404b588458SPeter Avalos 		tempfree(x);
12414b588458SPeter Avalos 	}
12424b588458SPeter Avalos 	if (pairstack[pair] == 1) {
12434b588458SPeter Avalos 		x = execute(a[1]);
12444b588458SPeter Avalos 		if (istrue(x))
12454b588458SPeter Avalos 			pairstack[pair] = 0;
12464b588458SPeter Avalos 		tempfree(x);
12474b588458SPeter Avalos 		x = execute(a[2]);
12484b588458SPeter Avalos 		return(x);
12494b588458SPeter Avalos 	}
12504b588458SPeter Avalos 	return(False);
12514b588458SPeter Avalos }
12524b588458SPeter Avalos 
12534b588458SPeter Avalos Cell *split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
12544b588458SPeter Avalos {
1255*1d48fce0SDaniel Fojt 	Cell *x = NULL, *y, *ap;
1256*1d48fce0SDaniel Fojt 	const char *s, *origs, *t;
1257*1d48fce0SDaniel Fojt 	const char *fs = NULL;
1258*1d48fce0SDaniel Fojt 	char *origfs = NULL;
12594b588458SPeter Avalos 	int sep;
1260*1d48fce0SDaniel Fojt 	char temp, num[50];
12614b588458SPeter Avalos 	int n, tempstat, arg3type;
12624b588458SPeter Avalos 
12634b588458SPeter Avalos 	y = execute(a[0]);	/* source string */
12642078c1f0SJohn Marino 	origs = s = strdup(getsval(y));
12654b588458SPeter Avalos 	arg3type = ptoi(a[3]);
1266*1d48fce0SDaniel Fojt 	if (a[2] == NULL)		/* fs string */
1267*1d48fce0SDaniel Fojt 		fs = getsval(fsloc);
12684b588458SPeter Avalos 	else if (arg3type == STRING) {	/* split(str,arr,"string") */
12694b588458SPeter Avalos 		x = execute(a[2]);
1270*1d48fce0SDaniel Fojt 		fs = origfs = strdup(getsval(x));
1271*1d48fce0SDaniel Fojt 		tempfree(x);
12724b588458SPeter Avalos 	} else if (arg3type == REGEXPR)
12734b588458SPeter Avalos 		fs = "(regexpr)";	/* split(str,arr,/regexpr/) */
12744b588458SPeter Avalos 	else
12754b588458SPeter Avalos 		FATAL("illegal type of split");
12764b588458SPeter Avalos 	sep = *fs;
12774b588458SPeter Avalos 	ap = execute(a[1]);	/* array name */
12784b588458SPeter Avalos 	freesymtab(ap);
12794b588458SPeter Avalos 	   dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs) );
12804b588458SPeter Avalos 	ap->tval &= ~STR;
12814b588458SPeter Avalos 	ap->tval |= ARR;
12824b588458SPeter Avalos 	ap->sval = (char *) makesymtab(NSYMTAB);
12834b588458SPeter Avalos 
12844b588458SPeter Avalos 	n = 0;
1285b12bae18SSascha Wildner         if (arg3type == REGEXPR && strlen((char*)((fa*)a[2])->restr) == 0) {
1286b12bae18SSascha Wildner 		/* split(s, a, //); have to arrange that it looks like empty sep */
1287b12bae18SSascha Wildner 		arg3type = 0;
1288b12bae18SSascha Wildner 		fs = "";
1289b12bae18SSascha Wildner 		sep = 0;
1290b12bae18SSascha Wildner 	}
12914b588458SPeter Avalos 	if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) {	/* reg expr */
12924b588458SPeter Avalos 		fa *pfa;
12934b588458SPeter Avalos 		if (arg3type == REGEXPR) {	/* it's ready already */
12944b588458SPeter Avalos 			pfa = (fa *) a[2];
12954b588458SPeter Avalos 		} else {
12964b588458SPeter Avalos 			pfa = makedfa(fs, 1);
12974b588458SPeter Avalos 		}
12984b588458SPeter Avalos 		if (nematch(pfa,s)) {
12994b588458SPeter Avalos 			tempstat = pfa->initstat;
13004b588458SPeter Avalos 			pfa->initstat = 2;
13014b588458SPeter Avalos 			do {
13024b588458SPeter Avalos 				n++;
1303*1d48fce0SDaniel Fojt 				snprintf(num, sizeof(num), "%d", n);
13044b588458SPeter Avalos 				temp = *patbeg;
1305*1d48fce0SDaniel Fojt 				setptr(patbeg, '\0');
13064b588458SPeter Avalos 				if (is_number(s))
13074b588458SPeter Avalos 					setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
13084b588458SPeter Avalos 				else
13094b588458SPeter Avalos 					setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1310*1d48fce0SDaniel Fojt 				setptr(patbeg, temp);
13114b588458SPeter Avalos 				s = patbeg + patlen;
1312*1d48fce0SDaniel Fojt 				if (*(patbeg+patlen-1) == '\0' || *s == '\0') {
13134b588458SPeter Avalos 					n++;
1314*1d48fce0SDaniel Fojt 					snprintf(num, sizeof(num), "%d", n);
13154b588458SPeter Avalos 					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
13164b588458SPeter Avalos 					pfa->initstat = tempstat;
13174b588458SPeter Avalos 					goto spdone;
13184b588458SPeter Avalos 				}
13194b588458SPeter Avalos 			} while (nematch(pfa,s));
13204b588458SPeter Avalos 			pfa->initstat = tempstat; 	/* bwk: has to be here to reset */
13214b588458SPeter Avalos 							/* cf gsub and refldbld */
13224b588458SPeter Avalos 		}
13234b588458SPeter Avalos 		n++;
1324*1d48fce0SDaniel Fojt 		snprintf(num, sizeof(num), "%d", n);
13254b588458SPeter Avalos 		if (is_number(s))
13264b588458SPeter Avalos 			setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
13274b588458SPeter Avalos 		else
13284b588458SPeter Avalos 			setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
13294b588458SPeter Avalos   spdone:
13304b588458SPeter Avalos 		pfa = NULL;
13314b588458SPeter Avalos 	} else if (sep == ' ') {
13324b588458SPeter Avalos 		for (n = 0; ; ) {
1333*1d48fce0SDaniel Fojt #define ISWS(c)	((c) == ' ' || (c) == '\t' || (c) == '\n')
1334*1d48fce0SDaniel Fojt 			while (ISWS(*s))
13354b588458SPeter Avalos 				s++;
1336*1d48fce0SDaniel Fojt 			if (*s == '\0')
13374b588458SPeter Avalos 				break;
13384b588458SPeter Avalos 			n++;
13394b588458SPeter Avalos 			t = s;
13404b588458SPeter Avalos 			do
13414b588458SPeter Avalos 				s++;
1342*1d48fce0SDaniel Fojt 			while (*s != '\0' && !ISWS(*s));
13434b588458SPeter Avalos 			temp = *s;
1344*1d48fce0SDaniel Fojt 			setptr(s, '\0');
1345*1d48fce0SDaniel Fojt 			snprintf(num, sizeof(num), "%d", n);
13464b588458SPeter Avalos 			if (is_number(t))
13474b588458SPeter Avalos 				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
13484b588458SPeter Avalos 			else
13494b588458SPeter Avalos 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1350*1d48fce0SDaniel Fojt 			setptr(s, temp);
1351*1d48fce0SDaniel Fojt 			if (*s != '\0')
13524b588458SPeter Avalos 				s++;
13534b588458SPeter Avalos 		}
13544b588458SPeter Avalos 	} else if (sep == 0) {	/* new: split(s, a, "") => 1 char/elem */
1355*1d48fce0SDaniel Fojt 		for (n = 0; *s != '\0'; s++) {
13564b588458SPeter Avalos 			char buf[2];
13574b588458SPeter Avalos 			n++;
1358*1d48fce0SDaniel Fojt 			snprintf(num, sizeof(num), "%d", n);
13594b588458SPeter Avalos 			buf[0] = *s;
1360*1d48fce0SDaniel Fojt 			buf[1] = '\0';
13614b588458SPeter Avalos 			if (isdigit((uschar)buf[0]))
13624b588458SPeter Avalos 				setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
13634b588458SPeter Avalos 			else
13644b588458SPeter Avalos 				setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
13654b588458SPeter Avalos 		}
1366*1d48fce0SDaniel Fojt 	} else if (*s != '\0') {
13674b588458SPeter Avalos 		for (;;) {
13684b588458SPeter Avalos 			n++;
13694b588458SPeter Avalos 			t = s;
13704b588458SPeter Avalos 			while (*s != sep && *s != '\n' && *s != '\0')
13714b588458SPeter Avalos 				s++;
13724b588458SPeter Avalos 			temp = *s;
1373*1d48fce0SDaniel Fojt 			setptr(s, '\0');
1374*1d48fce0SDaniel Fojt 			snprintf(num, sizeof(num), "%d", n);
13754b588458SPeter Avalos 			if (is_number(t))
13764b588458SPeter Avalos 				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
13774b588458SPeter Avalos 			else
13784b588458SPeter Avalos 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1379*1d48fce0SDaniel Fojt 			setptr(s, temp);
1380*1d48fce0SDaniel Fojt 			if (*s++ == '\0')
13814b588458SPeter Avalos 				break;
13824b588458SPeter Avalos 		}
13834b588458SPeter Avalos 	}
13844b588458SPeter Avalos 	tempfree(ap);
13854b588458SPeter Avalos 	tempfree(y);
1386*1d48fce0SDaniel Fojt 	xfree(origs);
1387*1d48fce0SDaniel Fojt 	xfree(origfs);
13884b588458SPeter Avalos 	x = gettemp();
13894b588458SPeter Avalos 	x->tval = NUM;
13904b588458SPeter Avalos 	x->fval = n;
13914b588458SPeter Avalos 	return(x);
13924b588458SPeter Avalos }
13934b588458SPeter Avalos 
13944b588458SPeter Avalos Cell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
13954b588458SPeter Avalos {
13964b588458SPeter Avalos 	Cell *x;
13974b588458SPeter Avalos 
13984b588458SPeter Avalos 	x = execute(a[0]);
13994b588458SPeter Avalos 	if (istrue(x)) {
14004b588458SPeter Avalos 		tempfree(x);
14014b588458SPeter Avalos 		x = execute(a[1]);
14024b588458SPeter Avalos 	} else {
14034b588458SPeter Avalos 		tempfree(x);
14044b588458SPeter Avalos 		x = execute(a[2]);
14054b588458SPeter Avalos 	}
14064b588458SPeter Avalos 	return(x);
14074b588458SPeter Avalos }
14084b588458SPeter Avalos 
14094b588458SPeter Avalos Cell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
14104b588458SPeter Avalos {
14114b588458SPeter Avalos 	Cell *x;
14124b588458SPeter Avalos 
14134b588458SPeter Avalos 	x = execute(a[0]);
14144b588458SPeter Avalos 	if (istrue(x)) {
14154b588458SPeter Avalos 		tempfree(x);
14164b588458SPeter Avalos 		x = execute(a[1]);
1417*1d48fce0SDaniel Fojt 	} else if (a[2] != NULL) {
14184b588458SPeter Avalos 		tempfree(x);
14194b588458SPeter Avalos 		x = execute(a[2]);
14204b588458SPeter Avalos 	}
14214b588458SPeter Avalos 	return(x);
14224b588458SPeter Avalos }
14234b588458SPeter Avalos 
14244b588458SPeter Avalos Cell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
14254b588458SPeter Avalos {
14264b588458SPeter Avalos 	Cell *x;
14274b588458SPeter Avalos 
14284b588458SPeter Avalos 	for (;;) {
14294b588458SPeter Avalos 		x = execute(a[0]);
14304b588458SPeter Avalos 		if (!istrue(x))
14314b588458SPeter Avalos 			return(x);
14324b588458SPeter Avalos 		tempfree(x);
14334b588458SPeter Avalos 		x = execute(a[1]);
14344b588458SPeter Avalos 		if (isbreak(x)) {
14354b588458SPeter Avalos 			x = True;
14364b588458SPeter Avalos 			return(x);
14374b588458SPeter Avalos 		}
14384b588458SPeter Avalos 		if (isnext(x) || isexit(x) || isret(x))
14394b588458SPeter Avalos 			return(x);
14404b588458SPeter Avalos 		tempfree(x);
14414b588458SPeter Avalos 	}
14424b588458SPeter Avalos }
14434b588458SPeter Avalos 
14444b588458SPeter Avalos Cell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
14454b588458SPeter Avalos {
14464b588458SPeter Avalos 	Cell *x;
14474b588458SPeter Avalos 
14484b588458SPeter Avalos 	for (;;) {
14494b588458SPeter Avalos 		x = execute(a[0]);
14504b588458SPeter Avalos 		if (isbreak(x))
14514b588458SPeter Avalos 			return True;
14524b588458SPeter Avalos 		if (isnext(x) || isexit(x) || isret(x))
14534b588458SPeter Avalos 			return(x);
14544b588458SPeter Avalos 		tempfree(x);
14554b588458SPeter Avalos 		x = execute(a[1]);
14564b588458SPeter Avalos 		if (!istrue(x))
14574b588458SPeter Avalos 			return(x);
14584b588458SPeter Avalos 		tempfree(x);
14594b588458SPeter Avalos 	}
14604b588458SPeter Avalos }
14614b588458SPeter Avalos 
14624b588458SPeter Avalos Cell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
14634b588458SPeter Avalos {
14644b588458SPeter Avalos 	Cell *x;
14654b588458SPeter Avalos 
14664b588458SPeter Avalos 	x = execute(a[0]);
14674b588458SPeter Avalos 	tempfree(x);
14684b588458SPeter Avalos 	for (;;) {
1469*1d48fce0SDaniel Fojt 		if (a[1]!=NULL) {
14704b588458SPeter Avalos 			x = execute(a[1]);
14714b588458SPeter Avalos 			if (!istrue(x)) return(x);
14724b588458SPeter Avalos 			else tempfree(x);
14734b588458SPeter Avalos 		}
14744b588458SPeter Avalos 		x = execute(a[3]);
14754b588458SPeter Avalos 		if (isbreak(x))		/* turn off break */
14764b588458SPeter Avalos 			return True;
14774b588458SPeter Avalos 		if (isnext(x) || isexit(x) || isret(x))
14784b588458SPeter Avalos 			return(x);
14794b588458SPeter Avalos 		tempfree(x);
14804b588458SPeter Avalos 		x = execute(a[2]);
14814b588458SPeter Avalos 		tempfree(x);
14824b588458SPeter Avalos 	}
14834b588458SPeter Avalos }
14844b588458SPeter Avalos 
14854b588458SPeter Avalos Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
14864b588458SPeter Avalos {
14874b588458SPeter Avalos 	Cell *x, *vp, *arrayp, *cp, *ncp;
14884b588458SPeter Avalos 	Array *tp;
14894b588458SPeter Avalos 	int i;
14904b588458SPeter Avalos 
14914b588458SPeter Avalos 	vp = execute(a[0]);
14924b588458SPeter Avalos 	arrayp = execute(a[1]);
14934b588458SPeter Avalos 	if (!isarr(arrayp)) {
14944b588458SPeter Avalos 		return True;
14954b588458SPeter Avalos 	}
14964b588458SPeter Avalos 	tp = (Array *) arrayp->sval;
14974b588458SPeter Avalos 	tempfree(arrayp);
14984b588458SPeter Avalos 	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
14994b588458SPeter Avalos 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
15004b588458SPeter Avalos 			setsval(vp, cp->nval);
15014b588458SPeter Avalos 			ncp = cp->cnext;
15024b588458SPeter Avalos 			x = execute(a[2]);
15034b588458SPeter Avalos 			if (isbreak(x)) {
15044b588458SPeter Avalos 				tempfree(vp);
15054b588458SPeter Avalos 				return True;
15064b588458SPeter Avalos 			}
15074b588458SPeter Avalos 			if (isnext(x) || isexit(x) || isret(x)) {
15084b588458SPeter Avalos 				tempfree(vp);
15094b588458SPeter Avalos 				return(x);
15104b588458SPeter Avalos 			}
15114b588458SPeter Avalos 			tempfree(x);
15124b588458SPeter Avalos 		}
15134b588458SPeter Avalos 	}
15144b588458SPeter Avalos 	return True;
15154b588458SPeter Avalos }
15164b588458SPeter Avalos 
1517*1d48fce0SDaniel Fojt static char *nawk_convert(const char *s, int (*fun_c)(int),
1518*1d48fce0SDaniel Fojt     wint_t (*fun_wc)(wint_t))
1519*1d48fce0SDaniel Fojt {
1520*1d48fce0SDaniel Fojt 	char *buf      = NULL;
1521*1d48fce0SDaniel Fojt 	char *pbuf     = NULL;
1522*1d48fce0SDaniel Fojt 	const char *ps = NULL;
1523*1d48fce0SDaniel Fojt 	size_t n       = 0;
1524*1d48fce0SDaniel Fojt 	mbstate_t mbs, mbs2;
1525*1d48fce0SDaniel Fojt 	wchar_t wc;
1526*1d48fce0SDaniel Fojt 	size_t sz = MB_CUR_MAX;
1527*1d48fce0SDaniel Fojt 
1528*1d48fce0SDaniel Fojt 	if (sz == 1) {
1529*1d48fce0SDaniel Fojt 		buf = tostring(s);
1530*1d48fce0SDaniel Fojt 
1531*1d48fce0SDaniel Fojt 		for (pbuf = buf; *pbuf; pbuf++)
1532*1d48fce0SDaniel Fojt 			*pbuf = fun_c((uschar)*pbuf);
1533*1d48fce0SDaniel Fojt 
1534*1d48fce0SDaniel Fojt 		return buf;
1535*1d48fce0SDaniel Fojt 	} else {
1536*1d48fce0SDaniel Fojt 		/* upper/lower character may be shorter/longer */
1537*1d48fce0SDaniel Fojt 		buf = tostringN(s, strlen(s) * sz + 1);
1538*1d48fce0SDaniel Fojt 
1539*1d48fce0SDaniel Fojt 		memset(&mbs,  0, sizeof(mbs));
1540*1d48fce0SDaniel Fojt 		memset(&mbs2, 0, sizeof(mbs2));
1541*1d48fce0SDaniel Fojt 
1542*1d48fce0SDaniel Fojt 		ps   = s;
1543*1d48fce0SDaniel Fojt 		pbuf = buf;
1544*1d48fce0SDaniel Fojt 		while (n = mbrtowc(&wc, ps, sz, &mbs),
1545*1d48fce0SDaniel Fojt 		       n > 0 && n != (size_t)-1 && n != (size_t)-2)
1546*1d48fce0SDaniel Fojt 		{
1547*1d48fce0SDaniel Fojt 			ps += n;
1548*1d48fce0SDaniel Fojt 
1549*1d48fce0SDaniel Fojt 			n = wcrtomb(pbuf, fun_wc(wc), &mbs2);
1550*1d48fce0SDaniel Fojt 			if (n == (size_t)-1)
1551*1d48fce0SDaniel Fojt 				FATAL("illegal wide character %s", s);
1552*1d48fce0SDaniel Fojt 
1553*1d48fce0SDaniel Fojt 			pbuf += n;
1554*1d48fce0SDaniel Fojt 		}
1555*1d48fce0SDaniel Fojt 
1556*1d48fce0SDaniel Fojt 		*pbuf = '\0';
1557*1d48fce0SDaniel Fojt 
1558*1d48fce0SDaniel Fojt 		if (n)
1559*1d48fce0SDaniel Fojt 			FATAL("illegal byte sequence %s", s);
1560*1d48fce0SDaniel Fojt 
1561*1d48fce0SDaniel Fojt 		return buf;
1562*1d48fce0SDaniel Fojt 	}
1563*1d48fce0SDaniel Fojt }
1564*1d48fce0SDaniel Fojt 
1565*1d48fce0SDaniel Fojt static char *nawk_toupper(const char *s)
1566*1d48fce0SDaniel Fojt {
1567*1d48fce0SDaniel Fojt 	return nawk_convert(s, toupper, towupper);
1568*1d48fce0SDaniel Fojt }
1569*1d48fce0SDaniel Fojt 
1570*1d48fce0SDaniel Fojt static char *nawk_tolower(const char *s)
1571*1d48fce0SDaniel Fojt {
1572*1d48fce0SDaniel Fojt 	return nawk_convert(s, tolower, towlower);
1573*1d48fce0SDaniel Fojt }
1574*1d48fce0SDaniel Fojt 
15754b588458SPeter Avalos Cell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
15764b588458SPeter Avalos {
15774b588458SPeter Avalos 	Cell *x, *y;
15784b588458SPeter Avalos 	Awkfloat u;
15794b588458SPeter Avalos 	int t;
15800020174dSPeter Avalos 	Awkfloat tmp;
1581*1d48fce0SDaniel Fojt 	char *buf;
15824b588458SPeter Avalos 	Node *nextarg;
15834b588458SPeter Avalos 	FILE *fp;
1584*1d48fce0SDaniel Fojt 	int status = 0;
15854b588458SPeter Avalos 
15864b588458SPeter Avalos 	t = ptoi(a[0]);
15874b588458SPeter Avalos 	x = execute(a[1]);
15884b588458SPeter Avalos 	nextarg = a[1]->nnext;
15894b588458SPeter Avalos 	switch (t) {
15904b588458SPeter Avalos 	case FLENGTH:
15914b588458SPeter Avalos 		if (isarr(x))
15924b588458SPeter Avalos 			u = ((Array *) x->sval)->nelem;	/* GROT.  should be function*/
15934b588458SPeter Avalos 		else
15944b588458SPeter Avalos 			u = strlen(getsval(x));
15954b588458SPeter Avalos 		break;
15964b588458SPeter Avalos 	case FLOG:
1597*1d48fce0SDaniel Fojt 		errno = 0;
1598*1d48fce0SDaniel Fojt 		u = errcheck(log(getfval(x)), "log");
1599*1d48fce0SDaniel Fojt 		break;
16004b588458SPeter Avalos 	case FINT:
16014b588458SPeter Avalos 		modf(getfval(x), &u); break;
16024b588458SPeter Avalos 	case FEXP:
1603*1d48fce0SDaniel Fojt 		errno = 0;
1604*1d48fce0SDaniel Fojt 		u = errcheck(exp(getfval(x)), "exp");
1605*1d48fce0SDaniel Fojt 		break;
16064b588458SPeter Avalos 	case FSQRT:
1607*1d48fce0SDaniel Fojt 		errno = 0;
1608*1d48fce0SDaniel Fojt 		u = errcheck(sqrt(getfval(x)), "sqrt");
1609*1d48fce0SDaniel Fojt 		break;
16104b588458SPeter Avalos 	case FSIN:
16114b588458SPeter Avalos 		u = sin(getfval(x)); break;
16124b588458SPeter Avalos 	case FCOS:
16134b588458SPeter Avalos 		u = cos(getfval(x)); break;
16144b588458SPeter Avalos 	case FATAN:
1615*1d48fce0SDaniel Fojt 		if (nextarg == NULL) {
16164b588458SPeter Avalos 			WARNING("atan2 requires two arguments; returning 1.0");
16174b588458SPeter Avalos 			u = 1.0;
16184b588458SPeter Avalos 		} else {
16194b588458SPeter Avalos 			y = execute(a[1]->nnext);
16204b588458SPeter Avalos 			u = atan2(getfval(x), getfval(y));
16214b588458SPeter Avalos 			tempfree(y);
16224b588458SPeter Avalos 			nextarg = nextarg->nnext;
16234b588458SPeter Avalos 		}
16244b588458SPeter Avalos 		break;
16254b588458SPeter Avalos 	case FSYSTEM:
16264b588458SPeter Avalos 		fflush(stdout);		/* in case something is buffered already */
1627*1d48fce0SDaniel Fojt 		status = system(getsval(x));
1628*1d48fce0SDaniel Fojt 		u = status;
1629*1d48fce0SDaniel Fojt 		if (status != -1) {
1630*1d48fce0SDaniel Fojt 			if (WIFEXITED(status)) {
1631*1d48fce0SDaniel Fojt 				u = WEXITSTATUS(status);
1632*1d48fce0SDaniel Fojt 			} else if (WIFSIGNALED(status)) {
1633*1d48fce0SDaniel Fojt 				u = WTERMSIG(status) + 256;
1634*1d48fce0SDaniel Fojt #ifdef WCOREDUMP
1635*1d48fce0SDaniel Fojt 				if (WCOREDUMP(status))
1636*1d48fce0SDaniel Fojt 					u += 256;
1637*1d48fce0SDaniel Fojt #endif
1638*1d48fce0SDaniel Fojt 			} else	/* something else?!? */
1639*1d48fce0SDaniel Fojt 				u = 0;
1640*1d48fce0SDaniel Fojt 		}
16414b588458SPeter Avalos 		break;
16424b588458SPeter Avalos 	case FRAND:
1643*1d48fce0SDaniel Fojt 		/* random() returns numbers in [0..2^31-1]
1644*1d48fce0SDaniel Fojt 		 * in order to get a number in [0, 1), divide it by 2^31
1645*1d48fce0SDaniel Fojt 		 */
1646*1d48fce0SDaniel Fojt 		u = (Awkfloat) random() / (0x7fffffffL + 0x1UL);
16474b588458SPeter Avalos 		break;
16484b588458SPeter Avalos 	case FSRAND:
16494b588458SPeter Avalos 		if (isrec(x))	/* no argument provided */
16504b588458SPeter Avalos 			u = time((time_t *)0);
16514b588458SPeter Avalos 		else
16524b588458SPeter Avalos 			u = getfval(x);
16530020174dSPeter Avalos 		tmp = u;
1654*1d48fce0SDaniel Fojt 		srandom((unsigned long) u);
16550020174dSPeter Avalos 		u = srand_seed;
16560020174dSPeter Avalos 		srand_seed = tmp;
16574b588458SPeter Avalos 		break;
16584b588458SPeter Avalos 	case FTOUPPER:
16594b588458SPeter Avalos 	case FTOLOWER:
1660*1d48fce0SDaniel Fojt 		if (t == FTOUPPER)
1661*1d48fce0SDaniel Fojt 			buf = nawk_toupper(getsval(x));
1662*1d48fce0SDaniel Fojt 		else
1663*1d48fce0SDaniel Fojt 			buf = nawk_tolower(getsval(x));
16644b588458SPeter Avalos 		tempfree(x);
16654b588458SPeter Avalos 		x = gettemp();
16664b588458SPeter Avalos 		setsval(x, buf);
16674b588458SPeter Avalos 		free(buf);
16684b588458SPeter Avalos 		return x;
16694b588458SPeter Avalos 	case FFLUSH:
16704b588458SPeter Avalos 		if (isrec(x) || strlen(getsval(x)) == 0) {
16714b588458SPeter Avalos 			flush_all();	/* fflush() or fflush("") -> all */
16724b588458SPeter Avalos 			u = 0;
1673*1d48fce0SDaniel Fojt 		} else if ((fp = openfile(FFLUSH, getsval(x), NULL)) == NULL)
16744b588458SPeter Avalos 			u = EOF;
16754b588458SPeter Avalos 		else
16764b588458SPeter Avalos 			u = fflush(fp);
16774b588458SPeter Avalos 		break;
16784b588458SPeter Avalos 	default:	/* can't happen */
16794b588458SPeter Avalos 		FATAL("illegal function type %d", t);
16804b588458SPeter Avalos 		break;
16814b588458SPeter Avalos 	}
16824b588458SPeter Avalos 	tempfree(x);
16834b588458SPeter Avalos 	x = gettemp();
16844b588458SPeter Avalos 	setfval(x, u);
1685*1d48fce0SDaniel Fojt 	if (nextarg != NULL) {
16864b588458SPeter Avalos 		WARNING("warning: function has too many arguments");
16874b588458SPeter Avalos 		for ( ; nextarg; nextarg = nextarg->nnext)
16884b588458SPeter Avalos 			execute(nextarg);
16894b588458SPeter Avalos 	}
16904b588458SPeter Avalos 	return(x);
16914b588458SPeter Avalos }
16924b588458SPeter Avalos 
16934b588458SPeter Avalos Cell *printstat(Node **a, int n)	/* print a[0] */
16944b588458SPeter Avalos {
16954b588458SPeter Avalos 	Node *x;
16964b588458SPeter Avalos 	Cell *y;
16974b588458SPeter Avalos 	FILE *fp;
16984b588458SPeter Avalos 
1699*1d48fce0SDaniel Fojt 	if (a[1] == NULL)	/* a[1] is redirection operator, a[2] is file */
17004b588458SPeter Avalos 		fp = stdout;
17014b588458SPeter Avalos 	else
17024b588458SPeter Avalos 		fp = redirect(ptoi(a[1]), a[2]);
17034b588458SPeter Avalos 	for (x = a[0]; x != NULL; x = x->nnext) {
17044b588458SPeter Avalos 		y = execute(x);
17054b588458SPeter Avalos 		fputs(getpssval(y), fp);
17064b588458SPeter Avalos 		tempfree(y);
17074b588458SPeter Avalos 		if (x->nnext == NULL)
1708*1d48fce0SDaniel Fojt 			fputs(getsval(orsloc), fp);
17094b588458SPeter Avalos 		else
1710*1d48fce0SDaniel Fojt 			fputs(getsval(ofsloc), fp);
17114b588458SPeter Avalos 	}
1712*1d48fce0SDaniel Fojt 	if (a[1] != NULL)
17134b588458SPeter Avalos 		fflush(fp);
17144b588458SPeter Avalos 	if (ferror(fp))
17154b588458SPeter Avalos 		FATAL("write error on %s", filename(fp));
17164b588458SPeter Avalos 	return(True);
17174b588458SPeter Avalos }
17184b588458SPeter Avalos 
17194b588458SPeter Avalos Cell *nullproc(Node **a, int n)
17204b588458SPeter Avalos {
17214b588458SPeter Avalos 	return 0;
17224b588458SPeter Avalos }
17234b588458SPeter Avalos 
17244b588458SPeter Avalos 
17254b588458SPeter Avalos FILE *redirect(int a, Node *b)	/* set up all i/o redirections */
17264b588458SPeter Avalos {
17274b588458SPeter Avalos 	FILE *fp;
17284b588458SPeter Avalos 	Cell *x;
17294b588458SPeter Avalos 	char *fname;
17304b588458SPeter Avalos 
17314b588458SPeter Avalos 	x = execute(b);
17324b588458SPeter Avalos 	fname = getsval(x);
1733*1d48fce0SDaniel Fojt 	fp = openfile(a, fname, NULL);
17344b588458SPeter Avalos 	if (fp == NULL)
17354b588458SPeter Avalos 		FATAL("can't open file %s", fname);
17364b588458SPeter Avalos 	tempfree(x);
17374b588458SPeter Avalos 	return fp;
17384b588458SPeter Avalos }
17394b588458SPeter Avalos 
17404b588458SPeter Avalos struct files {
17414b588458SPeter Avalos 	FILE	*fp;
17424b588458SPeter Avalos 	const char	*fname;
17434b588458SPeter Avalos 	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
1744b12bae18SSascha Wildner } *files;
1745b12bae18SSascha Wildner 
1746*1d48fce0SDaniel Fojt size_t nfiles;
17474b588458SPeter Avalos 
1748*1d48fce0SDaniel Fojt static void stdinit(void)	/* in case stdin, etc., are not constants */
17494b588458SPeter Avalos {
1750b12bae18SSascha Wildner 	nfiles = FOPEN_MAX;
1751b12bae18SSascha Wildner 	files = calloc(nfiles, sizeof(*files));
1752b12bae18SSascha Wildner 	if (files == NULL)
1753*1d48fce0SDaniel Fojt 		FATAL("can't allocate file memory for %zu files", nfiles);
17544b588458SPeter Avalos         files[0].fp = stdin;
1755b12bae18SSascha Wildner 	files[0].fname = "/dev/stdin";
1756b12bae18SSascha Wildner 	files[0].mode = LT;
17574b588458SPeter Avalos         files[1].fp = stdout;
1758b12bae18SSascha Wildner 	files[1].fname = "/dev/stdout";
1759b12bae18SSascha Wildner 	files[1].mode = GT;
17604b588458SPeter Avalos         files[2].fp = stderr;
1761b12bae18SSascha Wildner 	files[2].fname = "/dev/stderr";
1762b12bae18SSascha Wildner 	files[2].mode = GT;
17634b588458SPeter Avalos }
17644b588458SPeter Avalos 
1765*1d48fce0SDaniel Fojt FILE *openfile(int a, const char *us, bool *pnewflag)
17664b588458SPeter Avalos {
17674b588458SPeter Avalos 	const char *s = us;
1768*1d48fce0SDaniel Fojt 	size_t i;
1769*1d48fce0SDaniel Fojt 	int m;
1770*1d48fce0SDaniel Fojt 	FILE *fp = NULL;
17714b588458SPeter Avalos 
17724b588458SPeter Avalos 	if (*s == '\0')
17734b588458SPeter Avalos 		FATAL("null file name in print or getline");
1774b12bae18SSascha Wildner 	for (i = 0; i < nfiles; i++)
1775*1d48fce0SDaniel Fojt 		if (files[i].fname && strcmp(s, files[i].fname) == 0 &&
1776*1d48fce0SDaniel Fojt 		    (a == files[i].mode || (a==APPEND && files[i].mode==GT) ||
1777*1d48fce0SDaniel Fojt 		     a == FFLUSH)) {
1778*1d48fce0SDaniel Fojt 			if (pnewflag)
1779*1d48fce0SDaniel Fojt 				*pnewflag = false;
17804b588458SPeter Avalos 			return files[i].fp;
17814b588458SPeter Avalos 		}
17824b588458SPeter Avalos 	if (a == FFLUSH)	/* didn't find it, so don't create it! */
17834b588458SPeter Avalos 		return NULL;
17844b588458SPeter Avalos 
1785b12bae18SSascha Wildner 	for (i = 0; i < nfiles; i++)
1786*1d48fce0SDaniel Fojt 		if (files[i].fp == NULL)
17874b588458SPeter Avalos 			break;
1788b12bae18SSascha Wildner 	if (i >= nfiles) {
1789b12bae18SSascha Wildner 		struct files *nf;
1790*1d48fce0SDaniel Fojt 		size_t nnf = nfiles + FOPEN_MAX;
1791b12bae18SSascha Wildner 		nf = realloc(files, nnf * sizeof(*nf));
1792b12bae18SSascha Wildner 		if (nf == NULL)
1793*1d48fce0SDaniel Fojt 			FATAL("cannot grow files for %s and %zu files", s, nnf);
1794b12bae18SSascha Wildner 		memset(&nf[nfiles], 0, FOPEN_MAX * sizeof(*nf));
1795b12bae18SSascha Wildner 		nfiles = nnf;
1796b12bae18SSascha Wildner 		files = nf;
1797b12bae18SSascha Wildner 	}
17984b588458SPeter Avalos 	fflush(stdout);	/* force a semblance of order */
17994b588458SPeter Avalos 	m = a;
18004b588458SPeter Avalos 	if (a == GT) {
18014b588458SPeter Avalos 		fp = fopen(s, "w");
18024b588458SPeter Avalos 	} else if (a == APPEND) {
18034b588458SPeter Avalos 		fp = fopen(s, "a");
18044b588458SPeter Avalos 		m = GT;	/* so can mix > and >> */
18054b588458SPeter Avalos 	} else if (a == '|') {	/* output pipe */
18064b588458SPeter Avalos 		fp = popen(s, "w");
18074b588458SPeter Avalos 	} else if (a == LE) {	/* input pipe */
18084b588458SPeter Avalos 		fp = popen(s, "r");
18094b588458SPeter Avalos 	} else if (a == LT) {	/* getline <file */
18104b588458SPeter Avalos 		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
18114b588458SPeter Avalos 	} else	/* can't happen */
18124b588458SPeter Avalos 		FATAL("illegal redirection %d", a);
18134b588458SPeter Avalos 	if (fp != NULL) {
18144b588458SPeter Avalos 		files[i].fname = tostring(s);
18154b588458SPeter Avalos 		files[i].fp = fp;
18164b588458SPeter Avalos 		files[i].mode = m;
1817*1d48fce0SDaniel Fojt 		if (pnewflag)
1818*1d48fce0SDaniel Fojt 			*pnewflag = true;
1819*1d48fce0SDaniel Fojt 		if (fp != stdin && fp != stdout && fp != stderr)
1820*1d48fce0SDaniel Fojt 			(void) fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
18214b588458SPeter Avalos 	}
18224b588458SPeter Avalos 	return fp;
18234b588458SPeter Avalos }
18244b588458SPeter Avalos 
18254b588458SPeter Avalos const char *filename(FILE *fp)
18264b588458SPeter Avalos {
1827*1d48fce0SDaniel Fojt 	size_t i;
18284b588458SPeter Avalos 
1829b12bae18SSascha Wildner 	for (i = 0; i < nfiles; i++)
18304b588458SPeter Avalos 		if (fp == files[i].fp)
18314b588458SPeter Avalos 			return files[i].fname;
18324b588458SPeter Avalos 	return "???";
18334b588458SPeter Avalos }
18344b588458SPeter Avalos 
18354b588458SPeter Avalos  Cell *closefile(Node **a, int n)
18364b588458SPeter Avalos  {
18374b588458SPeter Avalos  	Cell *x;
1838*1d48fce0SDaniel Fojt 	size_t i;
1839*1d48fce0SDaniel Fojt 	bool stat;
18404b588458SPeter Avalos 
18414b588458SPeter Avalos  	x = execute(a[0]);
18424b588458SPeter Avalos  	getsval(x);
1843*1d48fce0SDaniel Fojt 	stat = true;
1844b12bae18SSascha Wildner  	for (i = 0; i < nfiles; i++) {
1845*1d48fce0SDaniel Fojt 		if (!files[i].fname || strcmp(x->sval, files[i].fname) != 0)
1846*1d48fce0SDaniel Fojt 			continue;
18474b588458SPeter Avalos 		if (ferror(files[i].fp))
1848*1d48fce0SDaniel Fojt 			FATAL("i/o error occurred on %s", files[i].fname);
18494b588458SPeter Avalos 		if (files[i].mode == '|' || files[i].mode == LE)
1850*1d48fce0SDaniel Fojt 			stat = pclose(files[i].fp) == -1;
18514b588458SPeter Avalos 		else
1852*1d48fce0SDaniel Fojt 			stat = fclose(files[i].fp) == EOF;
1853*1d48fce0SDaniel Fojt 		if (stat)
1854*1d48fce0SDaniel Fojt 			FATAL("i/o error occurred closing %s", files[i].fname);
18554b588458SPeter Avalos 		if (i > 2)	/* don't do /dev/std... */
18564b588458SPeter Avalos 			xfree(files[i].fname);
18574b588458SPeter Avalos 		files[i].fname = NULL;	/* watch out for ref thru this */
18584b588458SPeter Avalos 		files[i].fp = NULL;
18594b588458SPeter Avalos  	}
18604b588458SPeter Avalos  	tempfree(x);
18614b588458SPeter Avalos  	x = gettemp();
1862*1d48fce0SDaniel Fojt 	setfval(x, (Awkfloat) (stat ? -1 : 0));
18634b588458SPeter Avalos  	return(x);
18644b588458SPeter Avalos  }
18654b588458SPeter Avalos 
18664b588458SPeter Avalos void closeall(void)
18674b588458SPeter Avalos {
1868*1d48fce0SDaniel Fojt 	size_t i;
1869*1d48fce0SDaniel Fojt 	bool stat = false;
18704b588458SPeter Avalos 
1871*1d48fce0SDaniel Fojt 	for (i = 0; i < nfiles; i++) {
1872*1d48fce0SDaniel Fojt 		if (! files[i].fp)
1873*1d48fce0SDaniel Fojt 			continue;
18744b588458SPeter Avalos 		if (ferror(files[i].fp))
1875*1d48fce0SDaniel Fojt 			FATAL( "i/o error occurred on %s", files[i].fname );
18764b588458SPeter Avalos 		if (files[i].mode == '|' || files[i].mode == LE)
1877*1d48fce0SDaniel Fojt 			stat = pclose(files[i].fp) == -1;
18784b588458SPeter Avalos 		else
1879*1d48fce0SDaniel Fojt 			stat = fclose(files[i].fp) == EOF;
1880*1d48fce0SDaniel Fojt 		if (stat)
1881*1d48fce0SDaniel Fojt 			FATAL( "i/o error occurred while closing %s", files[i].fname );
18824b588458SPeter Avalos 	}
18834b588458SPeter Avalos }
18844b588458SPeter Avalos 
1885*1d48fce0SDaniel Fojt static void flush_all(void)
18864b588458SPeter Avalos {
1887*1d48fce0SDaniel Fojt 	size_t i;
18884b588458SPeter Avalos 
1889b12bae18SSascha Wildner 	for (i = 0; i < nfiles; i++)
18904b588458SPeter Avalos 		if (files[i].fp)
18914b588458SPeter Avalos 			fflush(files[i].fp);
18924b588458SPeter Avalos }
18934b588458SPeter Avalos 
1894*1d48fce0SDaniel Fojt void backsub(char **pb_ptr, const char **sptr_ptr);
18954b588458SPeter Avalos 
18964b588458SPeter Avalos Cell *sub(Node **a, int nnn)	/* substitute command */
18974b588458SPeter Avalos {
1898*1d48fce0SDaniel Fojt 	const char *sptr, *q;
18994b588458SPeter Avalos 	Cell *x, *y, *result;
1900*1d48fce0SDaniel Fojt 	char *t, *buf, *pb;
19014b588458SPeter Avalos 	fa *pfa;
19024b588458SPeter Avalos 	int bufsz = recsize;
19034b588458SPeter Avalos 
1904*1d48fce0SDaniel Fojt 	if ((buf = malloc(bufsz)) == NULL)
19054b588458SPeter Avalos 		FATAL("out of memory in sub");
19064b588458SPeter Avalos 	x = execute(a[3]);	/* target string */
19074b588458SPeter Avalos 	t = getsval(x);
1908*1d48fce0SDaniel Fojt 	if (a[0] == NULL)	/* 0 => a[1] is already-compiled regexpr */
19094b588458SPeter Avalos 		pfa = (fa *) a[1];	/* regular expression */
19104b588458SPeter Avalos 	else {
19114b588458SPeter Avalos 		y = execute(a[1]);
19124b588458SPeter Avalos 		pfa = makedfa(getsval(y), 1);
19134b588458SPeter Avalos 		tempfree(y);
19144b588458SPeter Avalos 	}
19154b588458SPeter Avalos 	y = execute(a[2]);	/* replacement string */
19164b588458SPeter Avalos 	result = False;
19174b588458SPeter Avalos 	if (pmatch(pfa, t)) {
19184b588458SPeter Avalos 		sptr = t;
19194b588458SPeter Avalos 		adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
19204b588458SPeter Avalos 		pb = buf;
19214b588458SPeter Avalos 		while (sptr < patbeg)
19224b588458SPeter Avalos 			*pb++ = *sptr++;
19234b588458SPeter Avalos 		sptr = getsval(y);
1924*1d48fce0SDaniel Fojt 		while (*sptr != '\0') {
19254b588458SPeter Avalos 			adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
19264b588458SPeter Avalos 			if (*sptr == '\\') {
19274b588458SPeter Avalos 				backsub(&pb, &sptr);
19284b588458SPeter Avalos 			} else if (*sptr == '&') {
19294b588458SPeter Avalos 				sptr++;
19304b588458SPeter Avalos 				adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
19314b588458SPeter Avalos 				for (q = patbeg; q < patbeg+patlen; )
19324b588458SPeter Avalos 					*pb++ = *q++;
19334b588458SPeter Avalos 			} else
19344b588458SPeter Avalos 				*pb++ = *sptr++;
19354b588458SPeter Avalos 		}
19364b588458SPeter Avalos 		*pb = '\0';
19374b588458SPeter Avalos 		if (pb > buf + bufsz)
19384b588458SPeter Avalos 			FATAL("sub result1 %.30s too big; can't happen", buf);
19394b588458SPeter Avalos 		sptr = patbeg + patlen;
19404b588458SPeter Avalos 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
19414b588458SPeter Avalos 			adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1942*1d48fce0SDaniel Fojt 			while ((*pb++ = *sptr++) != '\0')
1943*1d48fce0SDaniel Fojt 				continue;
19444b588458SPeter Avalos 		}
19454b588458SPeter Avalos 		if (pb > buf + bufsz)
19464b588458SPeter Avalos 			FATAL("sub result2 %.30s too big; can't happen", buf);
19474b588458SPeter Avalos 		setsval(x, buf);	/* BUG: should be able to avoid copy */
1948*1d48fce0SDaniel Fojt 		result = True;
19494b588458SPeter Avalos 	}
19504b588458SPeter Avalos 	tempfree(x);
19514b588458SPeter Avalos 	tempfree(y);
19524b588458SPeter Avalos 	free(buf);
19534b588458SPeter Avalos 	return result;
19544b588458SPeter Avalos }
19554b588458SPeter Avalos 
19564b588458SPeter Avalos Cell *gsub(Node **a, int nnn)	/* global substitute */
19574b588458SPeter Avalos {
19584b588458SPeter Avalos 	Cell *x, *y;
1959*1d48fce0SDaniel Fojt 	char *rptr, *pb;
1960*1d48fce0SDaniel Fojt 	const char *q, *t, *sptr;
19614b588458SPeter Avalos 	char *buf;
19624b588458SPeter Avalos 	fa *pfa;
19634b588458SPeter Avalos 	int mflag, tempstat, num;
19644b588458SPeter Avalos 	int bufsz = recsize;
19654b588458SPeter Avalos 
1966*1d48fce0SDaniel Fojt 	if ((buf = malloc(bufsz)) == NULL)
19674b588458SPeter Avalos 		FATAL("out of memory in gsub");
19684b588458SPeter Avalos 	mflag = 0;	/* if mflag == 0, can replace empty string */
19694b588458SPeter Avalos 	num = 0;
19704b588458SPeter Avalos 	x = execute(a[3]);	/* target string */
19714b588458SPeter Avalos 	t = getsval(x);
1972*1d48fce0SDaniel Fojt 	if (a[0] == NULL)	/* 0 => a[1] is already-compiled regexpr */
19734b588458SPeter Avalos 		pfa = (fa *) a[1];	/* regular expression */
19744b588458SPeter Avalos 	else {
19754b588458SPeter Avalos 		y = execute(a[1]);
19764b588458SPeter Avalos 		pfa = makedfa(getsval(y), 1);
19774b588458SPeter Avalos 		tempfree(y);
19784b588458SPeter Avalos 	}
19794b588458SPeter Avalos 	y = execute(a[2]);	/* replacement string */
19804b588458SPeter Avalos 	if (pmatch(pfa, t)) {
19814b588458SPeter Avalos 		tempstat = pfa->initstat;
19824b588458SPeter Avalos 		pfa->initstat = 2;
19834b588458SPeter Avalos 		pb = buf;
19844b588458SPeter Avalos 		rptr = getsval(y);
19854b588458SPeter Avalos 		do {
1986*1d48fce0SDaniel Fojt 			if (patlen == 0 && *patbeg != '\0') {	/* matched empty string */
19874b588458SPeter Avalos 				if (mflag == 0) {	/* can replace empty */
19884b588458SPeter Avalos 					num++;
19894b588458SPeter Avalos 					sptr = rptr;
1990*1d48fce0SDaniel Fojt 					while (*sptr != '\0') {
19914b588458SPeter Avalos 						adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
19924b588458SPeter Avalos 						if (*sptr == '\\') {
19934b588458SPeter Avalos 							backsub(&pb, &sptr);
19944b588458SPeter Avalos 						} else if (*sptr == '&') {
19954b588458SPeter Avalos 							sptr++;
19964b588458SPeter Avalos 							adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
19974b588458SPeter Avalos 							for (q = patbeg; q < patbeg+patlen; )
19984b588458SPeter Avalos 								*pb++ = *q++;
19994b588458SPeter Avalos 						} else
20004b588458SPeter Avalos 							*pb++ = *sptr++;
20014b588458SPeter Avalos 					}
20024b588458SPeter Avalos 				}
2003*1d48fce0SDaniel Fojt 				if (*t == '\0')	/* at end */
20044b588458SPeter Avalos 					goto done;
20054b588458SPeter Avalos 				adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
20064b588458SPeter Avalos 				*pb++ = *t++;
20074b588458SPeter Avalos 				if (pb > buf + bufsz)	/* BUG: not sure of this test */
20084b588458SPeter Avalos 					FATAL("gsub result0 %.30s too big; can't happen", buf);
20094b588458SPeter Avalos 				mflag = 0;
20104b588458SPeter Avalos 			}
20114b588458SPeter Avalos 			else {	/* matched nonempty string */
20124b588458SPeter Avalos 				num++;
20134b588458SPeter Avalos 				sptr = t;
20144b588458SPeter Avalos 				adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
20154b588458SPeter Avalos 				while (sptr < patbeg)
20164b588458SPeter Avalos 					*pb++ = *sptr++;
20174b588458SPeter Avalos 				sptr = rptr;
2018*1d48fce0SDaniel Fojt 				while (*sptr != '\0') {
20194b588458SPeter Avalos 					adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
20204b588458SPeter Avalos 					if (*sptr == '\\') {
20214b588458SPeter Avalos 						backsub(&pb, &sptr);
20224b588458SPeter Avalos 					} else if (*sptr == '&') {
20234b588458SPeter Avalos 						sptr++;
20244b588458SPeter Avalos 						adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
20254b588458SPeter Avalos 						for (q = patbeg; q < patbeg+patlen; )
20264b588458SPeter Avalos 							*pb++ = *q++;
20274b588458SPeter Avalos 					} else
20284b588458SPeter Avalos 						*pb++ = *sptr++;
20294b588458SPeter Avalos 				}
20304b588458SPeter Avalos 				t = patbeg + patlen;
2031*1d48fce0SDaniel Fojt 				if (patlen == 0 || *t == '\0' || *(t-1) == '\0')
20324b588458SPeter Avalos 					goto done;
20334b588458SPeter Avalos 				if (pb > buf + bufsz)
20344b588458SPeter Avalos 					FATAL("gsub result1 %.30s too big; can't happen", buf);
20354b588458SPeter Avalos 				mflag = 1;
20364b588458SPeter Avalos 			}
20374b588458SPeter Avalos 		} while (pmatch(pfa,t));
20384b588458SPeter Avalos 		sptr = t;
20394b588458SPeter Avalos 		adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
2040*1d48fce0SDaniel Fojt 		while ((*pb++ = *sptr++) != '\0')
2041*1d48fce0SDaniel Fojt 			continue;
20424b588458SPeter Avalos 	done:	if (pb < buf + bufsz)
20434b588458SPeter Avalos 			*pb = '\0';
20444b588458SPeter Avalos 		else if (*(pb-1) != '\0')
20454b588458SPeter Avalos 			FATAL("gsub result2 %.30s truncated; can't happen", buf);
20464b588458SPeter Avalos 		setsval(x, buf);	/* BUG: should be able to avoid copy + free */
20474b588458SPeter Avalos 		pfa->initstat = tempstat;
20484b588458SPeter Avalos 	}
20494b588458SPeter Avalos 	tempfree(x);
20504b588458SPeter Avalos 	tempfree(y);
20514b588458SPeter Avalos 	x = gettemp();
20524b588458SPeter Avalos 	x->tval = NUM;
20534b588458SPeter Avalos 	x->fval = num;
20544b588458SPeter Avalos 	free(buf);
20554b588458SPeter Avalos 	return(x);
20564b588458SPeter Avalos }
20574b588458SPeter Avalos 
2058*1d48fce0SDaniel Fojt void backsub(char **pb_ptr, const char **sptr_ptr)	/* handle \\& variations */
20594b588458SPeter Avalos {						/* sptr[0] == '\\' */
2060*1d48fce0SDaniel Fojt 	char *pb = *pb_ptr;
2061*1d48fce0SDaniel Fojt 	const char *sptr = *sptr_ptr;
2062*1d48fce0SDaniel Fojt 	static bool first = true;
2063*1d48fce0SDaniel Fojt 	static bool do_posix = false;
2064*1d48fce0SDaniel Fojt 
2065*1d48fce0SDaniel Fojt 	if (first) {
2066*1d48fce0SDaniel Fojt 		first = false;
2067*1d48fce0SDaniel Fojt 		do_posix = (getenv("POSIXLY_CORRECT") != NULL);
2068*1d48fce0SDaniel Fojt 	}
20694b588458SPeter Avalos 
20704b588458SPeter Avalos 	if (sptr[1] == '\\') {
20714b588458SPeter Avalos 		if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
20724b588458SPeter Avalos 			*pb++ = '\\';
20734b588458SPeter Avalos 			*pb++ = '&';
20744b588458SPeter Avalos 			sptr += 4;
20754b588458SPeter Avalos 		} else if (sptr[2] == '&') {	/* \\& -> \ + matched */
20764b588458SPeter Avalos 			*pb++ = '\\';
20774b588458SPeter Avalos 			sptr += 2;
2078*1d48fce0SDaniel Fojt 		} else if (do_posix) {		/* \\x -> \x */
2079*1d48fce0SDaniel Fojt 			sptr++;
2080*1d48fce0SDaniel Fojt 			*pb++ = *sptr++;
20814b588458SPeter Avalos 		} else {			/* \\x -> \\x */
20824b588458SPeter Avalos 			*pb++ = *sptr++;
20834b588458SPeter Avalos 			*pb++ = *sptr++;
20844b588458SPeter Avalos 		}
20854b588458SPeter Avalos 	} else if (sptr[1] == '&') {	/* literal & */
20864b588458SPeter Avalos 		sptr++;
20874b588458SPeter Avalos 		*pb++ = *sptr++;
20884b588458SPeter Avalos 	} else				/* literal \ */
20894b588458SPeter Avalos 		*pb++ = *sptr++;
20904b588458SPeter Avalos 
20914b588458SPeter Avalos 	*pb_ptr = pb;
20924b588458SPeter Avalos 	*sptr_ptr = sptr;
20934b588458SPeter Avalos }
2094