xref: /titanic_44/usr/src/cmd/awk/run.c (revision 1ee2e5fa222f6d33d1ff1c48f155973a5e146434)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate /*
24*1ee2e5faSnakanon  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
28*1ee2e5faSnakanon /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29*1ee2e5faSnakanon /*	  All Rights Reserved  	*/
307c478bd9Sstevel@tonic-gate 
31*1ee2e5faSnakanon #pragma ident	"%Z%%M%	%I%	%E% SMI"
327c478bd9Sstevel@tonic-gate 
33*1ee2e5faSnakanon #define	tempfree(x, s)	if (istemp(x)) tfree(x, s)
34*1ee2e5faSnakanon 
357c478bd9Sstevel@tonic-gate #define	execute(p) r_execute(p)
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #define	DEBUG
387c478bd9Sstevel@tonic-gate #include	"awk.h"
397c478bd9Sstevel@tonic-gate #include	<math.h>
407c478bd9Sstevel@tonic-gate #include	"y.tab.h"
417c478bd9Sstevel@tonic-gate #include	<stdio.h>
427c478bd9Sstevel@tonic-gate #include	<ctype.h>
437c478bd9Sstevel@tonic-gate #include	<setjmp.h>
447c478bd9Sstevel@tonic-gate #include	<time.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #ifndef	FOPEN_MAX
477c478bd9Sstevel@tonic-gate #define	FOPEN_MAX	15	/* max number of open files, from ANSI std. */
487c478bd9Sstevel@tonic-gate #endif
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate 
51*1ee2e5faSnakanon static jmp_buf env;
527c478bd9Sstevel@tonic-gate 
53*1ee2e5faSnakanon static	Cell	*r_execute(Node *);
54*1ee2e5faSnakanon static	Cell	*gettemp(char *), *copycell(Cell *);
55*1ee2e5faSnakanon static	FILE	*openfile(int, uchar *), *redirect(int, Node *);
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate int	paircnt;
587c478bd9Sstevel@tonic-gate Node	*winner = NULL;
59*1ee2e5faSnakanon 
60*1ee2e5faSnakanon static Cell	*tmps;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate static Cell	truecell	= { OBOOL, BTRUE, 0, 0, 1.0, NUM };
637c478bd9Sstevel@tonic-gate Cell	*true	= &truecell;
647c478bd9Sstevel@tonic-gate static Cell	falsecell	= { OBOOL, BFALSE, 0, 0, 0.0, NUM };
657c478bd9Sstevel@tonic-gate Cell	*false	= &falsecell;
667c478bd9Sstevel@tonic-gate static Cell	breakcell	= { OJUMP, JBREAK, 0, 0, 0.0, NUM };
677c478bd9Sstevel@tonic-gate Cell	*jbreak	= &breakcell;
687c478bd9Sstevel@tonic-gate static Cell	contcell	= { OJUMP, JCONT, 0, 0, 0.0, NUM };
697c478bd9Sstevel@tonic-gate Cell	*jcont	= &contcell;
707c478bd9Sstevel@tonic-gate static Cell	nextcell	= { OJUMP, JNEXT, 0, 0, 0.0, NUM };
717c478bd9Sstevel@tonic-gate Cell	*jnext	= &nextcell;
727c478bd9Sstevel@tonic-gate static Cell	exitcell	= { OJUMP, JEXIT, 0, 0, 0.0, NUM };
737c478bd9Sstevel@tonic-gate Cell	*jexit	= &exitcell;
747c478bd9Sstevel@tonic-gate static Cell	retcell		= { OJUMP, JRET, 0, 0, 0.0, NUM };
757c478bd9Sstevel@tonic-gate Cell	*jret	= &retcell;
767c478bd9Sstevel@tonic-gate static Cell	tempcell	= { OCELL, CTEMP, 0, 0, 0.0, NUM };
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate Node	*curnode = NULL;	/* the node being executed, for debugging */
797c478bd9Sstevel@tonic-gate 
80*1ee2e5faSnakanon static	void	tfree(Cell *, char *);
81*1ee2e5faSnakanon static	void	closeall(void);
82*1ee2e5faSnakanon static	double	ipow(double, int);
83*1ee2e5faSnakanon 
84*1ee2e5faSnakanon void
85*1ee2e5faSnakanon run(Node *a)
867c478bd9Sstevel@tonic-gate {
87*1ee2e5faSnakanon 	(void) execute(a);
887c478bd9Sstevel@tonic-gate 	closeall();
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate 
91*1ee2e5faSnakanon static Cell *
92*1ee2e5faSnakanon r_execute(Node *u)
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	register Cell *(*proc)();
957c478bd9Sstevel@tonic-gate 	register Cell *x;
967c478bd9Sstevel@tonic-gate 	register Node *a;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	if (u == NULL)
997c478bd9Sstevel@tonic-gate 		return (true);
1007c478bd9Sstevel@tonic-gate 	for (a = u; ; a = a->nnext) {
1017c478bd9Sstevel@tonic-gate 		curnode = a;
1027c478bd9Sstevel@tonic-gate 		if (isvalue(a)) {
1037c478bd9Sstevel@tonic-gate 			x = (Cell *) (a->narg[0]);
1047c478bd9Sstevel@tonic-gate 			if ((x->tval & FLD) && !donefld)
1057c478bd9Sstevel@tonic-gate 				fldbld();
1067c478bd9Sstevel@tonic-gate 			else if ((x->tval & REC) && !donerec)
1077c478bd9Sstevel@tonic-gate 				recbld();
1087c478bd9Sstevel@tonic-gate 			return (x);
1097c478bd9Sstevel@tonic-gate 		}
110*1ee2e5faSnakanon 		/* probably a Cell* but too risky to print */
111*1ee2e5faSnakanon 		if (notlegal(a->nobj))
1127c478bd9Sstevel@tonic-gate 			ERROR "illegal statement" FATAL;
1137c478bd9Sstevel@tonic-gate 		proc = proctab[a->nobj-FIRSTTOKEN];
1147c478bd9Sstevel@tonic-gate 		x = (*proc)(a->narg, a->nobj);
1157c478bd9Sstevel@tonic-gate 		if ((x->tval & FLD) && !donefld)
1167c478bd9Sstevel@tonic-gate 			fldbld();
1177c478bd9Sstevel@tonic-gate 		else if ((x->tval & REC) && !donerec)
1187c478bd9Sstevel@tonic-gate 			recbld();
1197c478bd9Sstevel@tonic-gate 		if (isexpr(a))
1207c478bd9Sstevel@tonic-gate 			return (x);
1217c478bd9Sstevel@tonic-gate 		/* a statement, goto next statement */
1227c478bd9Sstevel@tonic-gate 		if (isjump(x))
1237c478bd9Sstevel@tonic-gate 			return (x);
1247c478bd9Sstevel@tonic-gate 		if (a->nnext == (Node *)NULL)
1257c478bd9Sstevel@tonic-gate 			return (x);
1267c478bd9Sstevel@tonic-gate 		tempfree(x, "execute");
1277c478bd9Sstevel@tonic-gate 	}
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate 
130*1ee2e5faSnakanon /*ARGSUSED*/
131*1ee2e5faSnakanon Cell *
132*1ee2e5faSnakanon program(Node **a, int n)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate 	register Cell *x;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	if (setjmp(env) != 0)
1377c478bd9Sstevel@tonic-gate 		goto ex;
1387c478bd9Sstevel@tonic-gate 	if (a[0]) {		/* BEGIN */
1397c478bd9Sstevel@tonic-gate 		x = execute(a[0]);
1407c478bd9Sstevel@tonic-gate 		if (isexit(x))
1417c478bd9Sstevel@tonic-gate 			return (true);
142*1ee2e5faSnakanon 		if (isjump(x)) {
143*1ee2e5faSnakanon 			ERROR "illegal break, continue or next from BEGIN"
144*1ee2e5faSnakanon 			    FATAL;
145*1ee2e5faSnakanon 		}
1467c478bd9Sstevel@tonic-gate 		tempfree(x, "");
1477c478bd9Sstevel@tonic-gate 	}
1487c478bd9Sstevel@tonic-gate loop:
1497c478bd9Sstevel@tonic-gate 	if (a[1] || a[2])
150*1ee2e5faSnakanon 		while (getrec(&record, &record_size) > 0) {
1517c478bd9Sstevel@tonic-gate 			x = execute(a[1]);
1527c478bd9Sstevel@tonic-gate 			if (isexit(x))
1537c478bd9Sstevel@tonic-gate 				break;
1547c478bd9Sstevel@tonic-gate 			tempfree(x, "");
1557c478bd9Sstevel@tonic-gate 		}
1567c478bd9Sstevel@tonic-gate ex:
1577c478bd9Sstevel@tonic-gate 	if (setjmp(env) != 0)
1587c478bd9Sstevel@tonic-gate 		goto ex1;
1597c478bd9Sstevel@tonic-gate 	if (a[2]) {		/* END */
1607c478bd9Sstevel@tonic-gate 		x = execute(a[2]);
1617c478bd9Sstevel@tonic-gate 		if (iscont(x))	/* read some more */
1627c478bd9Sstevel@tonic-gate 			goto loop;
1637c478bd9Sstevel@tonic-gate 		if (isbreak(x) || isnext(x))
1647c478bd9Sstevel@tonic-gate 			ERROR "illegal break or next from END" FATAL;
1657c478bd9Sstevel@tonic-gate 		tempfree(x, "");
1667c478bd9Sstevel@tonic-gate 	}
1677c478bd9Sstevel@tonic-gate ex1:
1687c478bd9Sstevel@tonic-gate 	return (true);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate struct Frame {
1727c478bd9Sstevel@tonic-gate 	int nargs;	/* number of arguments in this call */
1737c478bd9Sstevel@tonic-gate 	Cell *fcncell;	/* pointer to Cell for function */
1747c478bd9Sstevel@tonic-gate 	Cell **args;	/* pointer to array of arguments after execute */
1757c478bd9Sstevel@tonic-gate 	Cell *retval;	/* return value */
1767c478bd9Sstevel@tonic-gate };
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate #define	NARGS	30
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
1817c478bd9Sstevel@tonic-gate int	nframe = 0;		/* number of frames allocated */
1827c478bd9Sstevel@tonic-gate struct Frame *fp = NULL;	/* frame pointer. bottom level unused */
1837c478bd9Sstevel@tonic-gate 
184*1ee2e5faSnakanon /*ARGSUSED*/
185*1ee2e5faSnakanon Cell *
186*1ee2e5faSnakanon call(Node **a, int n)
1877c478bd9Sstevel@tonic-gate {
188*1ee2e5faSnakanon 	static Cell newcopycell =
189*1ee2e5faSnakanon 		{ OCELL, CCOPY, 0, (uchar *) "", 0.0, NUM|STR|DONTFREE };
1907c478bd9Sstevel@tonic-gate 	int i, ncall, ndef, freed = 0;
1917c478bd9Sstevel@tonic-gate 	Node *x;
1927c478bd9Sstevel@tonic-gate 	Cell *args[NARGS], *oargs[NARGS], *y, *z, *fcn;
1937c478bd9Sstevel@tonic-gate 	uchar *s;
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	fcn = execute(a[0]);	/* the function itself */
1967c478bd9Sstevel@tonic-gate 	s = fcn->nval;
1977c478bd9Sstevel@tonic-gate 	if (!isfunc(fcn))
1987c478bd9Sstevel@tonic-gate 		ERROR "calling undefined function %s", s FATAL;
1997c478bd9Sstevel@tonic-gate 	if (frame == NULL) {
200*1ee2e5faSnakanon 		fp = frame = (struct Frame *)calloc(nframe += 100,
201*1ee2e5faSnakanon 		    sizeof (struct Frame));
202*1ee2e5faSnakanon 		if (frame == NULL) {
203*1ee2e5faSnakanon 			ERROR "out of space for stack frames calling %s",
204*1ee2e5faSnakanon 			    s FATAL;
205*1ee2e5faSnakanon 		}
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
2087c478bd9Sstevel@tonic-gate 		ncall++;
2097c478bd9Sstevel@tonic-gate 	ndef = (int)fcn->fval;			/* args in defn */
210*1ee2e5faSnakanon 	dprintf(("calling %s, %d args (%d in defn), fp=%d\n",
211*1ee2e5faSnakanon 	    s, ncall, ndef, fp-frame));
212*1ee2e5faSnakanon 	if (ncall > ndef) {
2137c478bd9Sstevel@tonic-gate 		ERROR "function %s called with %d args, uses only %d",
2147c478bd9Sstevel@tonic-gate 		    s, ncall, ndef WARNING;
215*1ee2e5faSnakanon 	}
216*1ee2e5faSnakanon 	if (ncall + ndef > NARGS) {
217*1ee2e5faSnakanon 		ERROR "function %s has %d arguments, limit %d",
218*1ee2e5faSnakanon 		    s, ncall+ndef, NARGS FATAL;
219*1ee2e5faSnakanon 	}
220*1ee2e5faSnakanon 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {
221*1ee2e5faSnakanon 		/* get call args */
2227c478bd9Sstevel@tonic-gate 		dprintf(("evaluate args[%d], fp=%d:\n", i, fp-frame));
2237c478bd9Sstevel@tonic-gate 		y = execute(x);
2247c478bd9Sstevel@tonic-gate 		oargs[i] = y;
2257c478bd9Sstevel@tonic-gate 		dprintf(("args[%d]: %s %f <%s>, t=%o\n",
226*1ee2e5faSnakanon 		    i, y->nval, y->fval,
227*1ee2e5faSnakanon 		    isarr(y) ? "(array)" : (char *)y->sval, y->tval));
228*1ee2e5faSnakanon 		if (isfunc(y)) {
229*1ee2e5faSnakanon 			ERROR "can't use function %s as argument in %s",
230*1ee2e5faSnakanon 			    y->nval, s FATAL;
231*1ee2e5faSnakanon 		}
2327c478bd9Sstevel@tonic-gate 		if (isarr(y))
2337c478bd9Sstevel@tonic-gate 			args[i] = y;	/* arrays by ref */
2347c478bd9Sstevel@tonic-gate 		else
2357c478bd9Sstevel@tonic-gate 			args[i] = copycell(y);
2367c478bd9Sstevel@tonic-gate 		tempfree(y, "callargs");
2377c478bd9Sstevel@tonic-gate 	}
2387c478bd9Sstevel@tonic-gate 	for (; i < ndef; i++) { /* add null args for ones not provided */
2397c478bd9Sstevel@tonic-gate 		args[i] = gettemp("nullargs");
2407c478bd9Sstevel@tonic-gate 		*args[i] = newcopycell;
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 	fp++;	/* now ok to up frame */
2437c478bd9Sstevel@tonic-gate 	if (fp >= frame + nframe) {
2447c478bd9Sstevel@tonic-gate 		int dfp = fp - frame;	/* old index */
2457c478bd9Sstevel@tonic-gate 		frame = (struct Frame *)
2467c478bd9Sstevel@tonic-gate 		    realloc(frame, (nframe += 100) * sizeof (struct Frame));
2477c478bd9Sstevel@tonic-gate 		if (frame == NULL)
2487c478bd9Sstevel@tonic-gate 			ERROR "out of space for stack frames in %s", s FATAL;
2497c478bd9Sstevel@tonic-gate 		fp = frame + dfp;
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 	fp->fcncell = fcn;
2527c478bd9Sstevel@tonic-gate 	fp->args = args;
2537c478bd9Sstevel@tonic-gate 	fp->nargs = ndef;	/* number defined with (excess are locals) */
2547c478bd9Sstevel@tonic-gate 	fp->retval = gettemp("retval");
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	dprintf(("start exec of %s, fp=%d\n", s, fp-frame));
257*1ee2e5faSnakanon 	/*LINTED align*/
2587c478bd9Sstevel@tonic-gate 	y = execute((Node *)(fcn->sval));	/* execute body */
2597c478bd9Sstevel@tonic-gate 	dprintf(("finished exec of %s, fp=%d\n", s, fp-frame));
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	for (i = 0; i < ndef; i++) {
2627c478bd9Sstevel@tonic-gate 		Cell *t = fp->args[i];
2637c478bd9Sstevel@tonic-gate 		if (isarr(t)) {
2647c478bd9Sstevel@tonic-gate 			if (t->csub == CCOPY) {
2657c478bd9Sstevel@tonic-gate 				if (i >= ncall) {
2667c478bd9Sstevel@tonic-gate 					freesymtab(t);
2677c478bd9Sstevel@tonic-gate 					t->csub = CTEMP;
2687c478bd9Sstevel@tonic-gate 				} else {
2697c478bd9Sstevel@tonic-gate 					oargs[i]->tval = t->tval;
2707c478bd9Sstevel@tonic-gate 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
2717c478bd9Sstevel@tonic-gate 					oargs[i]->sval = t->sval;
2727c478bd9Sstevel@tonic-gate 					tempfree(t, "oargsarr");
2737c478bd9Sstevel@tonic-gate 				}
2747c478bd9Sstevel@tonic-gate 			}
2757c478bd9Sstevel@tonic-gate 		} else {
2767c478bd9Sstevel@tonic-gate 			t->csub = CTEMP;
2777c478bd9Sstevel@tonic-gate 			tempfree(t, "fp->args");
2787c478bd9Sstevel@tonic-gate 			if (t == y) freed = 1;
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 	}
2817c478bd9Sstevel@tonic-gate 	tempfree(fcn, "call.fcn");
2827c478bd9Sstevel@tonic-gate 	if (isexit(y) || isnext(y))
283*1ee2e5faSnakanon 		return (y);
284*1ee2e5faSnakanon 	if (!freed)
285*1ee2e5faSnakanon 		tempfree(y, "fcn ret"); /* this can free twice! */
2867c478bd9Sstevel@tonic-gate 	z = fp->retval;			/* return value */
287*1ee2e5faSnakanon 	dprintf(("%s returns %g |%s| %o\n",
288*1ee2e5faSnakanon 	    s, getfval(z), getsval(z), z->tval));
2897c478bd9Sstevel@tonic-gate 	fp--;
2907c478bd9Sstevel@tonic-gate 	return (z);
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate 
293*1ee2e5faSnakanon static Cell *
294*1ee2e5faSnakanon copycell(Cell *x)	/* make a copy of a cell in a temp */
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate 	Cell *y;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	y = gettemp("copycell");
2997c478bd9Sstevel@tonic-gate 	y->csub = CCOPY;	/* prevents freeing until call is over */
3007c478bd9Sstevel@tonic-gate 	y->nval = x->nval;
3017c478bd9Sstevel@tonic-gate 	y->sval = x->sval ? tostring(x->sval) : NULL;
3027c478bd9Sstevel@tonic-gate 	y->fval = x->fval;
303*1ee2e5faSnakanon 	/* copy is not constant or field is DONTFREE right? */
304*1ee2e5faSnakanon 	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);
305*1ee2e5faSnakanon 	return (y);
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate 
308*1ee2e5faSnakanon /*ARGSUSED*/
309*1ee2e5faSnakanon Cell *
310*1ee2e5faSnakanon arg(Node **a, int nnn)
3117c478bd9Sstevel@tonic-gate {
3127c478bd9Sstevel@tonic-gate 	int n;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	n = (int)a[0];	/* argument number, counting from 0 */
3157c478bd9Sstevel@tonic-gate 	dprintf(("arg(%d), fp->nargs=%d\n", n, fp->nargs));
316*1ee2e5faSnakanon 	if (n+1 > fp->nargs) {
3177c478bd9Sstevel@tonic-gate 		ERROR "argument #%d of function %s was not supplied",
3187c478bd9Sstevel@tonic-gate 		    n+1, fp->fcncell->nval FATAL;
319*1ee2e5faSnakanon 	}
320*1ee2e5faSnakanon 	return (fp->args[n]);
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate 
323*1ee2e5faSnakanon Cell *
324*1ee2e5faSnakanon jump(Node **a, int n)
3257c478bd9Sstevel@tonic-gate {
3267c478bd9Sstevel@tonic-gate 	register Cell *y;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	switch (n) {
3297c478bd9Sstevel@tonic-gate 	case EXIT:
3307c478bd9Sstevel@tonic-gate 		if (a[0] != NULL) {
3317c478bd9Sstevel@tonic-gate 			y = execute(a[0]);
3327c478bd9Sstevel@tonic-gate 			errorflag = getfval(y);
3337c478bd9Sstevel@tonic-gate 			tempfree(y, "");
3347c478bd9Sstevel@tonic-gate 		}
3357c478bd9Sstevel@tonic-gate 		longjmp(env, 1);
336*1ee2e5faSnakanon 		/*NOTREACHED*/
3377c478bd9Sstevel@tonic-gate 	case RETURN:
3387c478bd9Sstevel@tonic-gate 		if (a[0] != NULL) {
3397c478bd9Sstevel@tonic-gate 			y = execute(a[0]);
3407c478bd9Sstevel@tonic-gate 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
341*1ee2e5faSnakanon 				(void) setsval(fp->retval, getsval(y));
3427c478bd9Sstevel@tonic-gate 				fp->retval->fval = getfval(y);
3437c478bd9Sstevel@tonic-gate 				fp->retval->tval |= NUM;
344*1ee2e5faSnakanon 			} else if (y->tval & STR)
345*1ee2e5faSnakanon 				(void) setsval(fp->retval, getsval(y));
3467c478bd9Sstevel@tonic-gate 			else if (y->tval & NUM)
347*1ee2e5faSnakanon 				(void) setfval(fp->retval, getfval(y));
3487c478bd9Sstevel@tonic-gate 			tempfree(y, "");
3497c478bd9Sstevel@tonic-gate 		}
3507c478bd9Sstevel@tonic-gate 		return (jret);
3517c478bd9Sstevel@tonic-gate 	case NEXT:
3527c478bd9Sstevel@tonic-gate 		return (jnext);
3537c478bd9Sstevel@tonic-gate 	case BREAK:
3547c478bd9Sstevel@tonic-gate 		return (jbreak);
3557c478bd9Sstevel@tonic-gate 	case CONTINUE:
3567c478bd9Sstevel@tonic-gate 		return (jcont);
3577c478bd9Sstevel@tonic-gate 	default:	/* can't happen */
3587c478bd9Sstevel@tonic-gate 		ERROR "illegal jump type %d", n FATAL;
3597c478bd9Sstevel@tonic-gate 	}
360*1ee2e5faSnakanon 	/*NOTREACHED*/
361*1ee2e5faSnakanon 	return (NULL);
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate 
364*1ee2e5faSnakanon Cell *
365*1ee2e5faSnakanon getline(Node **a, int n)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	/* a[0] is variable, a[1] is operator, a[2] is filename */
3687c478bd9Sstevel@tonic-gate 	register Cell *r, *x;
369*1ee2e5faSnakanon 	uchar *buf;
3707c478bd9Sstevel@tonic-gate 	FILE *fp;
371*1ee2e5faSnakanon 	size_t len;
3727c478bd9Sstevel@tonic-gate 
373*1ee2e5faSnakanon 	(void) fflush(stdout);	/* in case someone is waiting for a prompt */
3747c478bd9Sstevel@tonic-gate 	r = gettemp("");
3757c478bd9Sstevel@tonic-gate 	if (a[1] != NULL) {		/* getline < file */
3767c478bd9Sstevel@tonic-gate 		x = execute(a[2]);		/* filename */
3777c478bd9Sstevel@tonic-gate 		if ((int)a[1] == '|')	/* input pipe */
3787c478bd9Sstevel@tonic-gate 			a[1] = (Node *)LE;	/* arbitrary flag */
3797c478bd9Sstevel@tonic-gate 		fp = openfile((int)a[1], getsval(x));
3807c478bd9Sstevel@tonic-gate 		tempfree(x, "");
381*1ee2e5faSnakanon 		buf = NULL;
3827c478bd9Sstevel@tonic-gate 		if (fp == NULL)
3837c478bd9Sstevel@tonic-gate 			n = -1;
3847c478bd9Sstevel@tonic-gate 		else
385*1ee2e5faSnakanon 			n = readrec(&buf, &len, fp);
386*1ee2e5faSnakanon 		if (n > 0) {
387*1ee2e5faSnakanon 			if (a[0] != NULL) {	/* getline var <file */
388*1ee2e5faSnakanon 				(void) setsval(execute(a[0]), buf);
3897c478bd9Sstevel@tonic-gate 			} else {			/* getline <file */
3907c478bd9Sstevel@tonic-gate 				if (!(recloc->tval & DONTFREE))
3917c478bd9Sstevel@tonic-gate 					xfree(recloc->sval);
392*1ee2e5faSnakanon 				expand_buf(&record, &record_size, len);
393*1ee2e5faSnakanon 				(void) memcpy(record, buf, len);
394*1ee2e5faSnakanon 				record[len] = '\0';
3957c478bd9Sstevel@tonic-gate 				recloc->sval = record;
3967c478bd9Sstevel@tonic-gate 				recloc->tval = REC | STR | DONTFREE;
3977c478bd9Sstevel@tonic-gate 				donerec = 1; donefld = 0;
3987c478bd9Sstevel@tonic-gate 			}
399*1ee2e5faSnakanon 		}
400*1ee2e5faSnakanon 		if (buf != NULL)
401*1ee2e5faSnakanon 			free(buf);
4027c478bd9Sstevel@tonic-gate 	} else {			/* bare getline; use current input */
4037c478bd9Sstevel@tonic-gate 		if (a[0] == NULL)	/* getline */
404*1ee2e5faSnakanon 			n = getrec(&record, &record_size);
4057c478bd9Sstevel@tonic-gate 		else {			/* getline var */
406*1ee2e5faSnakanon 			init_buf(&buf, &len, LINE_INCR);
407*1ee2e5faSnakanon 			n = getrec(&buf, &len);
408*1ee2e5faSnakanon 			(void) setsval(execute(a[0]), buf);
409*1ee2e5faSnakanon 			free(buf);
4107c478bd9Sstevel@tonic-gate 		}
4117c478bd9Sstevel@tonic-gate 	}
412*1ee2e5faSnakanon 	(void) setfval(r, (Awkfloat)n);
413*1ee2e5faSnakanon 	return (r);
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate 
416*1ee2e5faSnakanon /*ARGSUSED*/
417*1ee2e5faSnakanon Cell *
418*1ee2e5faSnakanon getnf(Node **a, int n)
4197c478bd9Sstevel@tonic-gate {
4207c478bd9Sstevel@tonic-gate 	if (donefld == 0)
4217c478bd9Sstevel@tonic-gate 		fldbld();
422*1ee2e5faSnakanon 	return ((Cell *)a[0]);
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate 
425*1ee2e5faSnakanon /*ARGSUSED*/
426*1ee2e5faSnakanon Cell *
427*1ee2e5faSnakanon array(Node **a, int n)
4287c478bd9Sstevel@tonic-gate {
4297c478bd9Sstevel@tonic-gate 	register Cell *x, *y, *z;
4307c478bd9Sstevel@tonic-gate 	register uchar *s;
4317c478bd9Sstevel@tonic-gate 	register Node *np;
432*1ee2e5faSnakanon 	uchar	*buf;
433*1ee2e5faSnakanon 	size_t	bsize, tlen, len, slen;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	x = execute(a[0]);	/* Cell* for symbol table */
436*1ee2e5faSnakanon 	init_buf(&buf, &bsize, LINE_INCR);
437*1ee2e5faSnakanon 	buf[0] = '\0';
438*1ee2e5faSnakanon 	tlen = 0;
439*1ee2e5faSnakanon 	slen = strlen((char *)*SUBSEP);
4407c478bd9Sstevel@tonic-gate 	for (np = a[1]; np; np = np->nnext) {
4417c478bd9Sstevel@tonic-gate 		y = execute(np);	/* subscript */
4427c478bd9Sstevel@tonic-gate 		s = getsval(y);
443*1ee2e5faSnakanon 		len = strlen((char *)s);
444*1ee2e5faSnakanon 		expand_buf(&buf, &bsize, tlen + len + slen);
445*1ee2e5faSnakanon 		(void) memcpy(&buf[tlen], s, len);
446*1ee2e5faSnakanon 		tlen += len;
447*1ee2e5faSnakanon 		if (np->nnext) {
448*1ee2e5faSnakanon 			(void) memcpy(&buf[tlen], *SUBSEP, slen);
449*1ee2e5faSnakanon 			tlen += slen;
450*1ee2e5faSnakanon 		}
451*1ee2e5faSnakanon 		buf[tlen] = '\0';
4527c478bd9Sstevel@tonic-gate 		tempfree(y, "");
4537c478bd9Sstevel@tonic-gate 	}
4547c478bd9Sstevel@tonic-gate 	if (!isarr(x)) {
4557c478bd9Sstevel@tonic-gate 		dprintf(("making %s into an array\n", x->nval));
4567c478bd9Sstevel@tonic-gate 		if (freeable(x))
4577c478bd9Sstevel@tonic-gate 			xfree(x->sval);
4587c478bd9Sstevel@tonic-gate 		x->tval &= ~(STR|NUM|DONTFREE);
4597c478bd9Sstevel@tonic-gate 		x->tval |= ARR;
4607c478bd9Sstevel@tonic-gate 		x->sval = (uchar *) makesymtab(NSYMTAB);
4617c478bd9Sstevel@tonic-gate 	}
462*1ee2e5faSnakanon 	/*LINTED align*/
463*1ee2e5faSnakanon 	z = setsymtab(buf, (uchar *)"", 0.0, STR|NUM, (Array *)x->sval);
4647c478bd9Sstevel@tonic-gate 	z->ctype = OCELL;
4657c478bd9Sstevel@tonic-gate 	z->csub = CVAR;
4667c478bd9Sstevel@tonic-gate 	tempfree(x, "");
467*1ee2e5faSnakanon 	free(buf);
4687c478bd9Sstevel@tonic-gate 	return (z);
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate 
471*1ee2e5faSnakanon /*ARGSUSED*/
472*1ee2e5faSnakanon Cell *
473*1ee2e5faSnakanon delete(Node **a, int n)
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate 	Cell *x, *y;
4767c478bd9Sstevel@tonic-gate 	Node *np;
477*1ee2e5faSnakanon 	uchar *buf, *s;
478*1ee2e5faSnakanon 	size_t bsize, tlen, slen, len;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	x = execute(a[0]);	/* Cell* for symbol table */
4817c478bd9Sstevel@tonic-gate 	if (!isarr(x))
482*1ee2e5faSnakanon 		return (true);
483*1ee2e5faSnakanon 	init_buf(&buf, &bsize, LINE_INCR);
484*1ee2e5faSnakanon 	buf[0] = '\0';
485*1ee2e5faSnakanon 	tlen = 0;
486*1ee2e5faSnakanon 	slen = strlen((char *)*SUBSEP);
4877c478bd9Sstevel@tonic-gate 	for (np = a[1]; np; np = np->nnext) {
4887c478bd9Sstevel@tonic-gate 		y = execute(np);	/* subscript */
4897c478bd9Sstevel@tonic-gate 		s = getsval(y);
490*1ee2e5faSnakanon 		len = strlen((char *)s);
491*1ee2e5faSnakanon 		expand_buf(&buf, &bsize, tlen + len + slen);
492*1ee2e5faSnakanon 		(void) memcpy(&buf[tlen], s, len);
493*1ee2e5faSnakanon 		tlen += len;
494*1ee2e5faSnakanon 		if (np->nnext) {
495*1ee2e5faSnakanon 			(void) memcpy(&buf[tlen], *SUBSEP, slen);
496*1ee2e5faSnakanon 			tlen += slen;
497*1ee2e5faSnakanon 		}
498*1ee2e5faSnakanon 		buf[tlen] = '\0';
4997c478bd9Sstevel@tonic-gate 		tempfree(y, "");
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 	freeelem(x, buf);
5027c478bd9Sstevel@tonic-gate 	tempfree(x, "");
503*1ee2e5faSnakanon 	free(buf);
504*1ee2e5faSnakanon 	return (true);
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate 
507*1ee2e5faSnakanon /*ARGSUSED*/
508*1ee2e5faSnakanon Cell *
509*1ee2e5faSnakanon intest(Node **a, int n)
5107c478bd9Sstevel@tonic-gate {
5117c478bd9Sstevel@tonic-gate 	register Cell *x, *ap, *k;
5127c478bd9Sstevel@tonic-gate 	Node *p;
513*1ee2e5faSnakanon 	uchar *buf;
5147c478bd9Sstevel@tonic-gate 	uchar *s;
515*1ee2e5faSnakanon 	size_t bsize, tlen, slen, len;
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	ap = execute(a[1]);	/* array name */
5187c478bd9Sstevel@tonic-gate 	if (!isarr(ap))
5197c478bd9Sstevel@tonic-gate 		ERROR "%s is not an array", ap->nval FATAL;
520*1ee2e5faSnakanon 	init_buf(&buf, &bsize, LINE_INCR);
5217c478bd9Sstevel@tonic-gate 	buf[0] = 0;
522*1ee2e5faSnakanon 	tlen = 0;
523*1ee2e5faSnakanon 	slen = strlen((char *)*SUBSEP);
5247c478bd9Sstevel@tonic-gate 	for (p = a[0]; p; p = p->nnext) {
5257c478bd9Sstevel@tonic-gate 		x = execute(p);	/* expr */
5267c478bd9Sstevel@tonic-gate 		s = getsval(x);
527*1ee2e5faSnakanon 		len = strlen((char *)s);
528*1ee2e5faSnakanon 		expand_buf(&buf, &bsize, tlen + len + slen);
529*1ee2e5faSnakanon 		(void) memcpy(&buf[tlen], s, len);
530*1ee2e5faSnakanon 		tlen += len;
5317c478bd9Sstevel@tonic-gate 		tempfree(x, "");
532*1ee2e5faSnakanon 		if (p->nnext) {
533*1ee2e5faSnakanon 			(void) memcpy(&buf[tlen], *SUBSEP, slen);
534*1ee2e5faSnakanon 			tlen += slen;
5357c478bd9Sstevel@tonic-gate 		}
536*1ee2e5faSnakanon 		buf[tlen] = '\0';
537*1ee2e5faSnakanon 	}
538*1ee2e5faSnakanon 	/*LINTED align*/
5397c478bd9Sstevel@tonic-gate 	k = lookup(buf, (Array *)ap->sval);
5407c478bd9Sstevel@tonic-gate 	tempfree(ap, "");
541*1ee2e5faSnakanon 	free(buf);
5427c478bd9Sstevel@tonic-gate 	if (k == NULL)
5437c478bd9Sstevel@tonic-gate 		return (false);
5447c478bd9Sstevel@tonic-gate 	else
5457c478bd9Sstevel@tonic-gate 		return (true);
5467c478bd9Sstevel@tonic-gate }
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 
549*1ee2e5faSnakanon Cell *
550*1ee2e5faSnakanon matchop(Node **a, int n)
5517c478bd9Sstevel@tonic-gate {
5527c478bd9Sstevel@tonic-gate 	register Cell *x, *y;
5537c478bd9Sstevel@tonic-gate 	register uchar *s, *t;
5547c478bd9Sstevel@tonic-gate 	register int i;
5557c478bd9Sstevel@tonic-gate 	fa *pfa;
5567c478bd9Sstevel@tonic-gate 	int (*mf)() = match, mode = 0;
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	if (n == MATCHFCN) {
5597c478bd9Sstevel@tonic-gate 		mf = pmatch;
5607c478bd9Sstevel@tonic-gate 		mode = 1;
5617c478bd9Sstevel@tonic-gate 	}
5627c478bd9Sstevel@tonic-gate 	x = execute(a[1]);
5637c478bd9Sstevel@tonic-gate 	s = getsval(x);
5647c478bd9Sstevel@tonic-gate 	if (a[0] == 0)
5657c478bd9Sstevel@tonic-gate 		i = (*mf)(a[2], s);
5667c478bd9Sstevel@tonic-gate 	else {
5677c478bd9Sstevel@tonic-gate 		y = execute(a[2]);
5687c478bd9Sstevel@tonic-gate 		t = getsval(y);
5697c478bd9Sstevel@tonic-gate 		pfa = makedfa(t, mode);
5707c478bd9Sstevel@tonic-gate 		i = (*mf)(pfa, s);
5717c478bd9Sstevel@tonic-gate 		tempfree(y, "");
5727c478bd9Sstevel@tonic-gate 	}
5737c478bd9Sstevel@tonic-gate 	tempfree(x, "");
5747c478bd9Sstevel@tonic-gate 	if (n == MATCHFCN) {
5757c478bd9Sstevel@tonic-gate 		int start = patbeg - s + 1;
5767c478bd9Sstevel@tonic-gate 		if (patlen < 0)
5777c478bd9Sstevel@tonic-gate 			start = 0;
578*1ee2e5faSnakanon 		(void) setfval(rstartloc, (Awkfloat)start);
579*1ee2e5faSnakanon 		(void) setfval(rlengthloc, (Awkfloat)patlen);
5807c478bd9Sstevel@tonic-gate 		x = gettemp("");
5817c478bd9Sstevel@tonic-gate 		x->tval = NUM;
5827c478bd9Sstevel@tonic-gate 		x->fval = start;
583*1ee2e5faSnakanon 		return (x);
5847c478bd9Sstevel@tonic-gate 	} else if (n == MATCH && i == 1 || n == NOTMATCH && i == 0)
5857c478bd9Sstevel@tonic-gate 		return (true);
5867c478bd9Sstevel@tonic-gate 	else
5877c478bd9Sstevel@tonic-gate 		return (false);
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 
591*1ee2e5faSnakanon Cell *
592*1ee2e5faSnakanon boolop(Node **a, int n)
5937c478bd9Sstevel@tonic-gate {
5947c478bd9Sstevel@tonic-gate 	register Cell *x, *y;
5957c478bd9Sstevel@tonic-gate 	register int i;
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
5987c478bd9Sstevel@tonic-gate 	i = istrue(x);
5997c478bd9Sstevel@tonic-gate 	tempfree(x, "");
6007c478bd9Sstevel@tonic-gate 	switch (n) {
6017c478bd9Sstevel@tonic-gate 	case BOR:
602*1ee2e5faSnakanon 		if (i)
603*1ee2e5faSnakanon 			return (true);
6047c478bd9Sstevel@tonic-gate 		y = execute(a[1]);
6057c478bd9Sstevel@tonic-gate 		i = istrue(y);
6067c478bd9Sstevel@tonic-gate 		tempfree(y, "");
607*1ee2e5faSnakanon 		return (i ? true : false);
6087c478bd9Sstevel@tonic-gate 	case AND:
609*1ee2e5faSnakanon 		if (!i)
610*1ee2e5faSnakanon 			return (false);
6117c478bd9Sstevel@tonic-gate 		y = execute(a[1]);
6127c478bd9Sstevel@tonic-gate 		i = istrue(y);
6137c478bd9Sstevel@tonic-gate 		tempfree(y, "");
614*1ee2e5faSnakanon 		return (i ? true : false);
6157c478bd9Sstevel@tonic-gate 	case NOT:
616*1ee2e5faSnakanon 		return (i ? false : true);
6177c478bd9Sstevel@tonic-gate 	default:	/* can't happen */
6187c478bd9Sstevel@tonic-gate 		ERROR "unknown boolean operator %d", n FATAL;
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
621*1ee2e5faSnakanon 	return (NULL);
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate 
624*1ee2e5faSnakanon Cell *
625*1ee2e5faSnakanon relop(Node **a, int n)
6267c478bd9Sstevel@tonic-gate {
6277c478bd9Sstevel@tonic-gate 	register int i;
6287c478bd9Sstevel@tonic-gate 	register Cell *x, *y;
6297c478bd9Sstevel@tonic-gate 	Awkfloat j;
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
6327c478bd9Sstevel@tonic-gate 	y = execute(a[1]);
6337c478bd9Sstevel@tonic-gate 	if (x->tval&NUM && y->tval&NUM) {
6347c478bd9Sstevel@tonic-gate 		j = x->fval - y->fval;
6357c478bd9Sstevel@tonic-gate 		i = j < 0 ? -1: (j > 0 ? 1: 0);
6367c478bd9Sstevel@tonic-gate 	} else {
637*1ee2e5faSnakanon 		i = strcmp((char *)getsval(x), (char *)getsval(y));
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate 	tempfree(x, "");
6407c478bd9Sstevel@tonic-gate 	tempfree(y, "");
6417c478bd9Sstevel@tonic-gate 	switch (n) {
642*1ee2e5faSnakanon 	case LT:	return (i < 0 ? true : false);
643*1ee2e5faSnakanon 	case LE:	return (i <= 0 ? true : false);
644*1ee2e5faSnakanon 	case NE:	return (i != 0 ? true : false);
645*1ee2e5faSnakanon 	case EQ:	return (i == 0 ? true : false);
646*1ee2e5faSnakanon 	case GE:	return (i >= 0 ? true : false);
647*1ee2e5faSnakanon 	case GT:	return (i > 0 ? true : false);
6487c478bd9Sstevel@tonic-gate 	default:	/* can't happen */
6497c478bd9Sstevel@tonic-gate 		ERROR "unknown relational operator %d", n FATAL;
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
652*1ee2e5faSnakanon 	return (false);
6537c478bd9Sstevel@tonic-gate }
6547c478bd9Sstevel@tonic-gate 
655*1ee2e5faSnakanon static void
656*1ee2e5faSnakanon tfree(Cell *a, char *s)
6577c478bd9Sstevel@tonic-gate {
658*1ee2e5faSnakanon 	if (dbg > 1) {
659*1ee2e5faSnakanon 		(void) printf("## tfree %.8s %06lo %s\n",
660*1ee2e5faSnakanon 		    s, (ulong_t)a, a->sval ? a->sval : (uchar *)"");
661*1ee2e5faSnakanon 	}
6627c478bd9Sstevel@tonic-gate 	if (freeable(a))
6637c478bd9Sstevel@tonic-gate 		xfree(a->sval);
6647c478bd9Sstevel@tonic-gate 	if (a == tmps)
6657c478bd9Sstevel@tonic-gate 		ERROR "tempcell list is curdled" FATAL;
6667c478bd9Sstevel@tonic-gate 	a->cnext = tmps;
6677c478bd9Sstevel@tonic-gate 	tmps = a;
6687c478bd9Sstevel@tonic-gate }
6697c478bd9Sstevel@tonic-gate 
670*1ee2e5faSnakanon static Cell *
671*1ee2e5faSnakanon gettemp(char *s)
672*1ee2e5faSnakanon {
673*1ee2e5faSnakanon 	int i;
6747c478bd9Sstevel@tonic-gate 	register Cell *x;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	if (!tmps) {
6777c478bd9Sstevel@tonic-gate 		tmps = (Cell *)calloc(100, sizeof (Cell));
6787c478bd9Sstevel@tonic-gate 		if (!tmps)
6797c478bd9Sstevel@tonic-gate 			ERROR "no space for temporaries" FATAL;
6807c478bd9Sstevel@tonic-gate 		for (i = 1; i < 100; i++)
6817c478bd9Sstevel@tonic-gate 			tmps[i-1].cnext = &tmps[i];
6827c478bd9Sstevel@tonic-gate 		tmps[i-1].cnext = 0;
6837c478bd9Sstevel@tonic-gate 	}
6847c478bd9Sstevel@tonic-gate 	x = tmps;
6857c478bd9Sstevel@tonic-gate 	tmps = x->cnext;
6867c478bd9Sstevel@tonic-gate 	*x = tempcell;
687*1ee2e5faSnakanon 	if (dbg > 1)
688*1ee2e5faSnakanon 		(void) printf("## gtemp %.8s %06lo\n", s, (ulong_t)x);
6897c478bd9Sstevel@tonic-gate 	return (x);
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate 
692*1ee2e5faSnakanon /*ARGSUSED*/
693*1ee2e5faSnakanon Cell *
694*1ee2e5faSnakanon indirect(Node **a, int n)
6957c478bd9Sstevel@tonic-gate {
6967c478bd9Sstevel@tonic-gate 	register Cell *x;
6977c478bd9Sstevel@tonic-gate 	register int m;
6987c478bd9Sstevel@tonic-gate 	register uchar *s;
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
7017c478bd9Sstevel@tonic-gate 	m = getfval(x);
702*1ee2e5faSnakanon 	if (m == 0 && !is_number(s = getsval(x)))	/* suspicion! */
7037c478bd9Sstevel@tonic-gate 		ERROR "illegal field $(%s)", s FATAL;
7047c478bd9Sstevel@tonic-gate 	tempfree(x, "");
7057c478bd9Sstevel@tonic-gate 	x = fieldadr(m);
7067c478bd9Sstevel@tonic-gate 	x->ctype = OCELL;
7077c478bd9Sstevel@tonic-gate 	x->csub = CFLD;
7087c478bd9Sstevel@tonic-gate 	return (x);
7097c478bd9Sstevel@tonic-gate }
7107c478bd9Sstevel@tonic-gate 
711*1ee2e5faSnakanon /*ARGSUSED*/
712*1ee2e5faSnakanon Cell *
713*1ee2e5faSnakanon substr(Node **a, int nnn)
7147c478bd9Sstevel@tonic-gate {
7157c478bd9Sstevel@tonic-gate 	register int k, m, n;
7167c478bd9Sstevel@tonic-gate 	register uchar *s;
7177c478bd9Sstevel@tonic-gate 	int temp;
7187c478bd9Sstevel@tonic-gate 	register Cell *x, *y, *z;
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
7217c478bd9Sstevel@tonic-gate 	y = execute(a[1]);
7227c478bd9Sstevel@tonic-gate 	if (a[2] != 0)
7237c478bd9Sstevel@tonic-gate 		z = execute(a[2]);
7247c478bd9Sstevel@tonic-gate 	s = getsval(x);
725*1ee2e5faSnakanon 	k = strlen((char *)s) + 1;
7267c478bd9Sstevel@tonic-gate 	if (k <= 1) {
7277c478bd9Sstevel@tonic-gate 		tempfree(x, "");
7287c478bd9Sstevel@tonic-gate 		tempfree(y, "");
7297c478bd9Sstevel@tonic-gate 		if (a[2] != 0)
7307c478bd9Sstevel@tonic-gate 			tempfree(z, "");
7317c478bd9Sstevel@tonic-gate 		x = gettemp("");
732*1ee2e5faSnakanon 		(void) setsval(x, (uchar *)"");
7337c478bd9Sstevel@tonic-gate 		return (x);
7347c478bd9Sstevel@tonic-gate 	}
7357c478bd9Sstevel@tonic-gate 	m = getfval(y);
7367c478bd9Sstevel@tonic-gate 	if (m <= 0)
7377c478bd9Sstevel@tonic-gate 		m = 1;
7387c478bd9Sstevel@tonic-gate 	else if (m > k)
7397c478bd9Sstevel@tonic-gate 		m = k;
7407c478bd9Sstevel@tonic-gate 	tempfree(y, "");
7417c478bd9Sstevel@tonic-gate 	if (a[2] != 0) {
7427c478bd9Sstevel@tonic-gate 		n = getfval(z);
7437c478bd9Sstevel@tonic-gate 		tempfree(z, "");
7447c478bd9Sstevel@tonic-gate 	} else
7457c478bd9Sstevel@tonic-gate 		n = k - 1;
7467c478bd9Sstevel@tonic-gate 	if (n < 0)
7477c478bd9Sstevel@tonic-gate 		n = 0;
7487c478bd9Sstevel@tonic-gate 	else if (n > k - m)
7497c478bd9Sstevel@tonic-gate 		n = k - m;
7507c478bd9Sstevel@tonic-gate 	dprintf(("substr: m=%d, n=%d, s=%s\n", m, n, s));
7517c478bd9Sstevel@tonic-gate 	y = gettemp("");
7527c478bd9Sstevel@tonic-gate 	temp = s[n + m - 1];	/* with thanks to John Linderman */
7537c478bd9Sstevel@tonic-gate 	s[n + m - 1] = '\0';
754*1ee2e5faSnakanon 	(void) setsval(y, s + m - 1);
7557c478bd9Sstevel@tonic-gate 	s[n + m - 1] = temp;
7567c478bd9Sstevel@tonic-gate 	tempfree(x, "");
7577c478bd9Sstevel@tonic-gate 	return (y);
7587c478bd9Sstevel@tonic-gate }
7597c478bd9Sstevel@tonic-gate 
760*1ee2e5faSnakanon /*ARGSUSED*/
761*1ee2e5faSnakanon Cell *
762*1ee2e5faSnakanon sindex(Node **a, int nnn)
7637c478bd9Sstevel@tonic-gate {
7647c478bd9Sstevel@tonic-gate 	register Cell *x, *y, *z;
7657c478bd9Sstevel@tonic-gate 	register uchar *s1, *s2, *p1, *p2, *q;
7667c478bd9Sstevel@tonic-gate 	Awkfloat v = 0.0;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
7697c478bd9Sstevel@tonic-gate 	s1 = getsval(x);
7707c478bd9Sstevel@tonic-gate 	y = execute(a[1]);
7717c478bd9Sstevel@tonic-gate 	s2 = getsval(y);
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	z = gettemp("");
7747c478bd9Sstevel@tonic-gate 	for (p1 = s1; *p1 != '\0'; p1++) {
7757c478bd9Sstevel@tonic-gate 		for (q = p1, p2 = s2; *p2 != '\0' && *q == *p2; q++, p2++)
7767c478bd9Sstevel@tonic-gate 			;
7777c478bd9Sstevel@tonic-gate 		if (*p2 == '\0') {
7787c478bd9Sstevel@tonic-gate 			v = (Awkfloat) (p1 - s1 + 1);	/* origin 1 */
7797c478bd9Sstevel@tonic-gate 			break;
7807c478bd9Sstevel@tonic-gate 		}
7817c478bd9Sstevel@tonic-gate 	}
7827c478bd9Sstevel@tonic-gate 	tempfree(x, "");
7837c478bd9Sstevel@tonic-gate 	tempfree(y, "");
784*1ee2e5faSnakanon 	(void) setfval(z, v);
7857c478bd9Sstevel@tonic-gate 	return (z);
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate 
788*1ee2e5faSnakanon void
789*1ee2e5faSnakanon format(uchar **bufp, uchar *s, Node *a)
7907c478bd9Sstevel@tonic-gate {
791*1ee2e5faSnakanon 	uchar *fmt;
792*1ee2e5faSnakanon 	register uchar *os;
7937c478bd9Sstevel@tonic-gate 	register Cell *x;
794*1ee2e5faSnakanon 	int flag = 0, len;
795*1ee2e5faSnakanon 	uchar_t	*buf;
796*1ee2e5faSnakanon 	size_t bufsize, fmtsize, cnt, tcnt, ret;
7977c478bd9Sstevel@tonic-gate 
798*1ee2e5faSnakanon 	init_buf(&buf, &bufsize, LINE_INCR);
799*1ee2e5faSnakanon 	init_buf(&fmt, &fmtsize, LINE_INCR);
8007c478bd9Sstevel@tonic-gate 	os = s;
801*1ee2e5faSnakanon 	cnt = 0;
8027c478bd9Sstevel@tonic-gate 	while (*s) {
8037c478bd9Sstevel@tonic-gate 		if (*s != '%') {
804*1ee2e5faSnakanon 			expand_buf(&buf, &bufsize, cnt);
805*1ee2e5faSnakanon 			buf[cnt++] = *s++;
8067c478bd9Sstevel@tonic-gate 			continue;
8077c478bd9Sstevel@tonic-gate 		}
8087c478bd9Sstevel@tonic-gate 		if (*(s+1) == '%') {
809*1ee2e5faSnakanon 			expand_buf(&buf, &bufsize, cnt);
810*1ee2e5faSnakanon 			buf[cnt++] = '%';
8117c478bd9Sstevel@tonic-gate 			s += 2;
8127c478bd9Sstevel@tonic-gate 			continue;
8137c478bd9Sstevel@tonic-gate 		}
814*1ee2e5faSnakanon 		for (tcnt = 0; ; s++) {
815*1ee2e5faSnakanon 			expand_buf(&fmt, &fmtsize, tcnt);
816*1ee2e5faSnakanon 			fmt[tcnt++] = *s;
817*1ee2e5faSnakanon 			if (*s == '\0')
818*1ee2e5faSnakanon 				break;
8197c478bd9Sstevel@tonic-gate 			if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
8207c478bd9Sstevel@tonic-gate 				break;	/* the ansi panoply */
8217c478bd9Sstevel@tonic-gate 			if (*s == '*') {
8227c478bd9Sstevel@tonic-gate 				if (a == NULL) {
8237c478bd9Sstevel@tonic-gate 					ERROR
8247c478bd9Sstevel@tonic-gate 		"not enough args in printf(%s) or sprintf(%s)", os, os FATAL;
8257c478bd9Sstevel@tonic-gate 				}
8267c478bd9Sstevel@tonic-gate 				x = execute(a);
8277c478bd9Sstevel@tonic-gate 				a = a->nnext;
828*1ee2e5faSnakanon 				tcnt--;
829*1ee2e5faSnakanon 				expand_buf(&fmt, &fmtsize, tcnt + 12);
830*1ee2e5faSnakanon 				ret = sprintf((char *)&fmt[tcnt], "%d",
831*1ee2e5faSnakanon 				    (int)getfval(x));
832*1ee2e5faSnakanon 				tcnt += ret;
8337c478bd9Sstevel@tonic-gate 				tempfree(x, "");
8347c478bd9Sstevel@tonic-gate 			}
8357c478bd9Sstevel@tonic-gate 		}
836*1ee2e5faSnakanon 		fmt[tcnt] = '\0';
837*1ee2e5faSnakanon 
8387c478bd9Sstevel@tonic-gate 		switch (*s) {
8397c478bd9Sstevel@tonic-gate 		case 'f': case 'e': case 'g': case 'E': case 'G':
8407c478bd9Sstevel@tonic-gate 			flag = 1;
8417c478bd9Sstevel@tonic-gate 			break;
8427c478bd9Sstevel@tonic-gate 		case 'd': case 'i':
8437c478bd9Sstevel@tonic-gate 			flag = 2;
844*1ee2e5faSnakanon 			if (*(s-1) == 'l')
845*1ee2e5faSnakanon 				break;
846*1ee2e5faSnakanon 			fmt[tcnt - 1] = 'l';
847*1ee2e5faSnakanon 			expand_buf(&fmt, &fmtsize, tcnt);
848*1ee2e5faSnakanon 			fmt[tcnt++] = 'd';
849*1ee2e5faSnakanon 			fmt[tcnt] = '\0';
8507c478bd9Sstevel@tonic-gate 			break;
8517c478bd9Sstevel@tonic-gate 		case 'o': case 'x': case 'X': case 'u':
8527c478bd9Sstevel@tonic-gate 			flag = *(s-1) == 'l' ? 2 : 3;
8537c478bd9Sstevel@tonic-gate 			break;
8547c478bd9Sstevel@tonic-gate 		case 's':
8557c478bd9Sstevel@tonic-gate 			flag = 4;
8567c478bd9Sstevel@tonic-gate 			break;
8577c478bd9Sstevel@tonic-gate 		case 'c':
8587c478bd9Sstevel@tonic-gate 			flag = 5;
8597c478bd9Sstevel@tonic-gate 			break;
8607c478bd9Sstevel@tonic-gate 		default:
8617c478bd9Sstevel@tonic-gate 			flag = 0;
8627c478bd9Sstevel@tonic-gate 			break;
8637c478bd9Sstevel@tonic-gate 		}
8647c478bd9Sstevel@tonic-gate 		if (flag == 0) {
865*1ee2e5faSnakanon 			len = strlen((char *)fmt);
866*1ee2e5faSnakanon 			expand_buf(&buf, &bufsize, cnt + len);
867*1ee2e5faSnakanon 			(void) memcpy(&buf[cnt], fmt, len);
868*1ee2e5faSnakanon 			cnt += len;
869*1ee2e5faSnakanon 			buf[cnt] = '\0';
8707c478bd9Sstevel@tonic-gate 			continue;
8717c478bd9Sstevel@tonic-gate 		}
8727c478bd9Sstevel@tonic-gate 		if (a == NULL) {
8737c478bd9Sstevel@tonic-gate 			ERROR
8747c478bd9Sstevel@tonic-gate 	"not enough args in printf(%s) or sprintf(%s)", os, os FATAL;
8757c478bd9Sstevel@tonic-gate 		}
8767c478bd9Sstevel@tonic-gate 		x = execute(a);
8777c478bd9Sstevel@tonic-gate 		a = a->nnext;
878*1ee2e5faSnakanon 		for (;;) {
879*1ee2e5faSnakanon 			/* make sure we have at least 1 byte space */
880*1ee2e5faSnakanon 			expand_buf(&buf, &bufsize, cnt + 1);
881*1ee2e5faSnakanon 			len = bufsize - cnt;
8827c478bd9Sstevel@tonic-gate 			switch (flag) {
883*1ee2e5faSnakanon 			case 1:
884*1ee2e5faSnakanon 				/*LINTED*/
885*1ee2e5faSnakanon 				ret = snprintf((char *)&buf[cnt], len,
886*1ee2e5faSnakanon 				    (char *)fmt, getfval(x));
8877c478bd9Sstevel@tonic-gate 				break;
888*1ee2e5faSnakanon 			case 2:
889*1ee2e5faSnakanon 				/*LINTED*/
890*1ee2e5faSnakanon 				ret = snprintf((char *)&buf[cnt], len,
891*1ee2e5faSnakanon 				    (char *)fmt, (long)getfval(x));
892*1ee2e5faSnakanon 				break;
893*1ee2e5faSnakanon 			case 3:
894*1ee2e5faSnakanon 				/*LINTED*/
895*1ee2e5faSnakanon 				ret = snprintf((char *)&buf[cnt], len,
896*1ee2e5faSnakanon 				    (char *)fmt, (int)getfval(x));
897*1ee2e5faSnakanon 				break;
898*1ee2e5faSnakanon 			case 4:
899*1ee2e5faSnakanon 				/*LINTED*/
900*1ee2e5faSnakanon 				ret = snprintf((char *)&buf[cnt], len,
901*1ee2e5faSnakanon 				    (char *)fmt, getsval(x));
902*1ee2e5faSnakanon 				break;
903*1ee2e5faSnakanon 			case 5:
904*1ee2e5faSnakanon 				if (isnum(x)) {
905*1ee2e5faSnakanon 					/*LINTED*/
906*1ee2e5faSnakanon 					ret = snprintf((char *)&buf[cnt], len,
907*1ee2e5faSnakanon 					    (char *)fmt, (int)getfval(x));
908*1ee2e5faSnakanon 				} else {
909*1ee2e5faSnakanon 					/*LINTED*/
910*1ee2e5faSnakanon 					ret = snprintf((char *)&buf[cnt], len,
911*1ee2e5faSnakanon 					    (char *)fmt, getsval(x)[0]);
912*1ee2e5faSnakanon 				}
913*1ee2e5faSnakanon 				break;
914*1ee2e5faSnakanon 			default:
915*1ee2e5faSnakanon 				ret = 0;
916*1ee2e5faSnakanon 			}
917*1ee2e5faSnakanon 			if (ret < len)
918*1ee2e5faSnakanon 				break;
919*1ee2e5faSnakanon 			expand_buf(&buf, &bufsize, cnt + ret);
9207c478bd9Sstevel@tonic-gate 		}
9217c478bd9Sstevel@tonic-gate 		tempfree(x, "");
922*1ee2e5faSnakanon 		cnt += ret;
9237c478bd9Sstevel@tonic-gate 		s++;
9247c478bd9Sstevel@tonic-gate 	}
925*1ee2e5faSnakanon 	buf[cnt] = '\0';
9267c478bd9Sstevel@tonic-gate 	for (; a; a = a->nnext)	/* evaluate any remaining args */
927*1ee2e5faSnakanon 		(void) execute(a);
928*1ee2e5faSnakanon 	*bufp = tostring(buf);
929*1ee2e5faSnakanon 	free(buf);
930*1ee2e5faSnakanon 	free(fmt);
9317c478bd9Sstevel@tonic-gate }
9327c478bd9Sstevel@tonic-gate 
933*1ee2e5faSnakanon /*ARGSUSED*/
934*1ee2e5faSnakanon Cell *
935*1ee2e5faSnakanon asprintf(Node **a, int n)
9367c478bd9Sstevel@tonic-gate {
9377c478bd9Sstevel@tonic-gate 	register Cell *x;
9387c478bd9Sstevel@tonic-gate 	register Node *y;
939*1ee2e5faSnakanon 	uchar *buf;
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	y = a[0]->nnext;
9427c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
943*1ee2e5faSnakanon 	format(&buf, getsval(x), y);
9447c478bd9Sstevel@tonic-gate 	tempfree(x, "");
9457c478bd9Sstevel@tonic-gate 	x = gettemp("");
946*1ee2e5faSnakanon 	x->sval = buf;
9477c478bd9Sstevel@tonic-gate 	x->tval = STR;
9487c478bd9Sstevel@tonic-gate 	return (x);
9497c478bd9Sstevel@tonic-gate }
9507c478bd9Sstevel@tonic-gate 
951*1ee2e5faSnakanon /*ARGSUSED*/
952*1ee2e5faSnakanon Cell *
953*1ee2e5faSnakanon aprintf(Node **a, int n)
9547c478bd9Sstevel@tonic-gate {
9557c478bd9Sstevel@tonic-gate 	FILE *fp;
9567c478bd9Sstevel@tonic-gate 	register Cell *x;
9577c478bd9Sstevel@tonic-gate 	register Node *y;
958*1ee2e5faSnakanon 	uchar *buf;
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	y = a[0]->nnext;
9617c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
962*1ee2e5faSnakanon 	format(&buf, getsval(x), y);
9637c478bd9Sstevel@tonic-gate 	tempfree(x, "");
9647c478bd9Sstevel@tonic-gate 	if (a[1] == NULL)
965*1ee2e5faSnakanon 		(void) fputs((char *)buf, stdout);
9667c478bd9Sstevel@tonic-gate 	else {
9677c478bd9Sstevel@tonic-gate 		fp = redirect((int)a[1], a[2]);
968*1ee2e5faSnakanon 		(void) fputs((char *)buf, fp);
969*1ee2e5faSnakanon 		(void) fflush(fp);
9707c478bd9Sstevel@tonic-gate 	}
971*1ee2e5faSnakanon 	free(buf);
9727c478bd9Sstevel@tonic-gate 	return (true);
9737c478bd9Sstevel@tonic-gate }
9747c478bd9Sstevel@tonic-gate 
975*1ee2e5faSnakanon Cell *
976*1ee2e5faSnakanon arith(Node **a, int n)
9777c478bd9Sstevel@tonic-gate {
9787c478bd9Sstevel@tonic-gate 	Awkfloat i, j;
979*1ee2e5faSnakanon 	double v;
9807c478bd9Sstevel@tonic-gate 	register Cell *x, *y, *z;
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
9837c478bd9Sstevel@tonic-gate 	i = getfval(x);
9847c478bd9Sstevel@tonic-gate 	tempfree(x, "");
9857c478bd9Sstevel@tonic-gate 	if (n != UMINUS) {
9867c478bd9Sstevel@tonic-gate 		y = execute(a[1]);
9877c478bd9Sstevel@tonic-gate 		j = getfval(y);
9887c478bd9Sstevel@tonic-gate 		tempfree(y, "");
9897c478bd9Sstevel@tonic-gate 	}
9907c478bd9Sstevel@tonic-gate 	z = gettemp("");
9917c478bd9Sstevel@tonic-gate 	switch (n) {
9927c478bd9Sstevel@tonic-gate 	case ADD:
9937c478bd9Sstevel@tonic-gate 		i += j;
9947c478bd9Sstevel@tonic-gate 		break;
9957c478bd9Sstevel@tonic-gate 	case MINUS:
9967c478bd9Sstevel@tonic-gate 		i -= j;
9977c478bd9Sstevel@tonic-gate 		break;
9987c478bd9Sstevel@tonic-gate 	case MULT:
9997c478bd9Sstevel@tonic-gate 		i *= j;
10007c478bd9Sstevel@tonic-gate 		break;
10017c478bd9Sstevel@tonic-gate 	case DIVIDE:
10027c478bd9Sstevel@tonic-gate 		if (j == 0)
10037c478bd9Sstevel@tonic-gate 			ERROR "division by zero" FATAL;
10047c478bd9Sstevel@tonic-gate 		i /= j;
10057c478bd9Sstevel@tonic-gate 		break;
10067c478bd9Sstevel@tonic-gate 	case MOD:
10077c478bd9Sstevel@tonic-gate 		if (j == 0)
10087c478bd9Sstevel@tonic-gate 			ERROR "division by zero in mod" FATAL;
1009*1ee2e5faSnakanon 		(void) modf(i/j, &v);
10107c478bd9Sstevel@tonic-gate 		i = i - j * v;
10117c478bd9Sstevel@tonic-gate 		break;
10127c478bd9Sstevel@tonic-gate 	case UMINUS:
10137c478bd9Sstevel@tonic-gate 		i = -i;
10147c478bd9Sstevel@tonic-gate 		break;
10157c478bd9Sstevel@tonic-gate 	case POWER:
10167c478bd9Sstevel@tonic-gate 		if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
10177c478bd9Sstevel@tonic-gate 			i = ipow(i, (int)j);
10187c478bd9Sstevel@tonic-gate 		else
10197c478bd9Sstevel@tonic-gate 			i = errcheck(pow(i, j), "pow");
10207c478bd9Sstevel@tonic-gate 		break;
10217c478bd9Sstevel@tonic-gate 	default:	/* can't happen */
10227c478bd9Sstevel@tonic-gate 		ERROR "illegal arithmetic operator %d", n FATAL;
10237c478bd9Sstevel@tonic-gate 	}
1024*1ee2e5faSnakanon 	(void) setfval(z, i);
10257c478bd9Sstevel@tonic-gate 	return (z);
10267c478bd9Sstevel@tonic-gate }
10277c478bd9Sstevel@tonic-gate 
1028*1ee2e5faSnakanon static double
1029*1ee2e5faSnakanon ipow(double x, int n)
10307c478bd9Sstevel@tonic-gate {
10317c478bd9Sstevel@tonic-gate 	double v;
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	if (n <= 0)
1034*1ee2e5faSnakanon 		return (1.0);
10357c478bd9Sstevel@tonic-gate 	v = ipow(x, n/2);
10367c478bd9Sstevel@tonic-gate 	if (n % 2 == 0)
1037*1ee2e5faSnakanon 		return (v * v);
10387c478bd9Sstevel@tonic-gate 	else
1039*1ee2e5faSnakanon 		return (x * v * v);
10407c478bd9Sstevel@tonic-gate }
10417c478bd9Sstevel@tonic-gate 
1042*1ee2e5faSnakanon Cell *
1043*1ee2e5faSnakanon incrdecr(Node **a, int n)
10447c478bd9Sstevel@tonic-gate {
10457c478bd9Sstevel@tonic-gate 	register Cell *x, *z;
10467c478bd9Sstevel@tonic-gate 	register int k;
10477c478bd9Sstevel@tonic-gate 	Awkfloat xf;
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
10507c478bd9Sstevel@tonic-gate 	xf = getfval(x);
10517c478bd9Sstevel@tonic-gate 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
10527c478bd9Sstevel@tonic-gate 	if (n == PREINCR || n == PREDECR) {
1053*1ee2e5faSnakanon 		(void) setfval(x, xf + k);
10547c478bd9Sstevel@tonic-gate 		return (x);
10557c478bd9Sstevel@tonic-gate 	}
10567c478bd9Sstevel@tonic-gate 	z = gettemp("");
1057*1ee2e5faSnakanon 	(void) setfval(z, xf);
1058*1ee2e5faSnakanon 	(void) setfval(x, xf + k);
10597c478bd9Sstevel@tonic-gate 	tempfree(x, "");
10607c478bd9Sstevel@tonic-gate 	return (z);
10617c478bd9Sstevel@tonic-gate }
10627c478bd9Sstevel@tonic-gate 
1063*1ee2e5faSnakanon Cell *
1064*1ee2e5faSnakanon assign(Node **a, int n)
10657c478bd9Sstevel@tonic-gate {
10667c478bd9Sstevel@tonic-gate 	register Cell *x, *y;
10677c478bd9Sstevel@tonic-gate 	Awkfloat xf, yf;
1068*1ee2e5faSnakanon 	double v;
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 	y = execute(a[1]);
10717c478bd9Sstevel@tonic-gate 	x = execute(a[0]);	/* order reversed from before... */
10727c478bd9Sstevel@tonic-gate 	if (n == ASSIGN) {	/* ordinary assignment */
10737c478bd9Sstevel@tonic-gate 		if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1074*1ee2e5faSnakanon 			(void) setsval(x, getsval(y));
10757c478bd9Sstevel@tonic-gate 			x->fval = getfval(y);
10767c478bd9Sstevel@tonic-gate 			x->tval |= NUM;
1077*1ee2e5faSnakanon 		} else if (y->tval & STR)
1078*1ee2e5faSnakanon 			(void) setsval(x, getsval(y));
10797c478bd9Sstevel@tonic-gate 		else if (y->tval & NUM)
1080*1ee2e5faSnakanon 			(void) setfval(x, getfval(y));
10817c478bd9Sstevel@tonic-gate 		else
10827c478bd9Sstevel@tonic-gate 			funnyvar(y, "read value of");
10837c478bd9Sstevel@tonic-gate 		tempfree(y, "");
10847c478bd9Sstevel@tonic-gate 		return (x);
10857c478bd9Sstevel@tonic-gate 	}
10867c478bd9Sstevel@tonic-gate 	xf = getfval(x);
10877c478bd9Sstevel@tonic-gate 	yf = getfval(y);
10887c478bd9Sstevel@tonic-gate 	switch (n) {
10897c478bd9Sstevel@tonic-gate 	case ADDEQ:
10907c478bd9Sstevel@tonic-gate 		xf += yf;
10917c478bd9Sstevel@tonic-gate 		break;
10927c478bd9Sstevel@tonic-gate 	case SUBEQ:
10937c478bd9Sstevel@tonic-gate 		xf -= yf;
10947c478bd9Sstevel@tonic-gate 		break;
10957c478bd9Sstevel@tonic-gate 	case MULTEQ:
10967c478bd9Sstevel@tonic-gate 		xf *= yf;
10977c478bd9Sstevel@tonic-gate 		break;
10987c478bd9Sstevel@tonic-gate 	case DIVEQ:
10997c478bd9Sstevel@tonic-gate 		if (yf == 0)
11007c478bd9Sstevel@tonic-gate 			ERROR "division by zero in /=" FATAL;
11017c478bd9Sstevel@tonic-gate 		xf /= yf;
11027c478bd9Sstevel@tonic-gate 		break;
11037c478bd9Sstevel@tonic-gate 	case MODEQ:
11047c478bd9Sstevel@tonic-gate 		if (yf == 0)
11057c478bd9Sstevel@tonic-gate 			ERROR "division by zero in %%=" FATAL;
1106*1ee2e5faSnakanon 		(void) modf(xf/yf, &v);
11077c478bd9Sstevel@tonic-gate 		xf = xf - yf * v;
11087c478bd9Sstevel@tonic-gate 		break;
11097c478bd9Sstevel@tonic-gate 	case POWEQ:
11107c478bd9Sstevel@tonic-gate 		if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
11117c478bd9Sstevel@tonic-gate 			xf = ipow(xf, (int)yf);
11127c478bd9Sstevel@tonic-gate 		else
11137c478bd9Sstevel@tonic-gate 			xf = errcheck(pow(xf, yf), "pow");
11147c478bd9Sstevel@tonic-gate 		break;
11157c478bd9Sstevel@tonic-gate 	default:
11167c478bd9Sstevel@tonic-gate 		ERROR "illegal assignment operator %d", n FATAL;
11177c478bd9Sstevel@tonic-gate 		break;
11187c478bd9Sstevel@tonic-gate 	}
11197c478bd9Sstevel@tonic-gate 	tempfree(y, "");
1120*1ee2e5faSnakanon 	(void) setfval(x, xf);
11217c478bd9Sstevel@tonic-gate 	return (x);
11227c478bd9Sstevel@tonic-gate }
11237c478bd9Sstevel@tonic-gate 
1124*1ee2e5faSnakanon /*ARGSUSED*/
1125*1ee2e5faSnakanon Cell *
1126*1ee2e5faSnakanon cat(Node **a, int q)
11277c478bd9Sstevel@tonic-gate {
11287c478bd9Sstevel@tonic-gate 	register Cell *x, *y, *z;
11297c478bd9Sstevel@tonic-gate 	register int n1, n2;
11307c478bd9Sstevel@tonic-gate 	register uchar *s;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
11337c478bd9Sstevel@tonic-gate 	y = execute(a[1]);
1134*1ee2e5faSnakanon 	(void) getsval(x);
1135*1ee2e5faSnakanon 	(void) getsval(y);
1136*1ee2e5faSnakanon 	n1 = strlen((char *)x->sval);
1137*1ee2e5faSnakanon 	n2 = strlen((char *)y->sval);
11387c478bd9Sstevel@tonic-gate 	s = (uchar *)malloc(n1 + n2 + 1);
1139*1ee2e5faSnakanon 	if (s == NULL) {
11407c478bd9Sstevel@tonic-gate 		ERROR "out of space concatenating %.15s and %.15s",
11417c478bd9Sstevel@tonic-gate 		    x->sval, y->sval FATAL;
1142*1ee2e5faSnakanon 	}
1143*1ee2e5faSnakanon 	(void) strcpy((char *)s, (char *)x->sval);
1144*1ee2e5faSnakanon 	(void) strcpy((char *)s + n1, (char *)y->sval);
11457c478bd9Sstevel@tonic-gate 	tempfree(y, "");
11467c478bd9Sstevel@tonic-gate 	z = gettemp("");
11477c478bd9Sstevel@tonic-gate 	z->sval = s;
11487c478bd9Sstevel@tonic-gate 	z->tval = STR;
11497c478bd9Sstevel@tonic-gate 	tempfree(x, "");
11507c478bd9Sstevel@tonic-gate 	return (z);
11517c478bd9Sstevel@tonic-gate }
11527c478bd9Sstevel@tonic-gate 
1153*1ee2e5faSnakanon /*ARGSUSED*/
1154*1ee2e5faSnakanon Cell *
1155*1ee2e5faSnakanon pastat(Node **a, int n)
11567c478bd9Sstevel@tonic-gate {
11577c478bd9Sstevel@tonic-gate 	register Cell *x;
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	if (a[0] == 0)
11607c478bd9Sstevel@tonic-gate 		x = execute(a[1]);
11617c478bd9Sstevel@tonic-gate 	else {
11627c478bd9Sstevel@tonic-gate 		x = execute(a[0]);
11637c478bd9Sstevel@tonic-gate 		if (istrue(x)) {
11647c478bd9Sstevel@tonic-gate 			tempfree(x, "");
11657c478bd9Sstevel@tonic-gate 			x = execute(a[1]);
11667c478bd9Sstevel@tonic-gate 		}
11677c478bd9Sstevel@tonic-gate 	}
1168*1ee2e5faSnakanon 	return (x);
11697c478bd9Sstevel@tonic-gate }
11707c478bd9Sstevel@tonic-gate 
1171*1ee2e5faSnakanon /*ARGSUSED*/
1172*1ee2e5faSnakanon Cell *
1173*1ee2e5faSnakanon dopa2(Node **a, int n)
11747c478bd9Sstevel@tonic-gate {
11757c478bd9Sstevel@tonic-gate 	Cell	*x;
11767c478bd9Sstevel@tonic-gate 	int	pair;
11777c478bd9Sstevel@tonic-gate 	static int	*pairstack = NULL;
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	if (!pairstack) {
11807c478bd9Sstevel@tonic-gate 		/* first time */
11817c478bd9Sstevel@tonic-gate 		dprintf(("paircnt: %d\n", paircnt));
11827c478bd9Sstevel@tonic-gate 		pairstack = (int *)malloc(sizeof (int) * paircnt);
11837c478bd9Sstevel@tonic-gate 		if (!pairstack)
11847c478bd9Sstevel@tonic-gate 			ERROR "out of space in dopa2" FATAL;
11857c478bd9Sstevel@tonic-gate 		(void) memset(pairstack, 0, sizeof (int) * paircnt);
11867c478bd9Sstevel@tonic-gate 	}
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	pair = (int)a[3];
11897c478bd9Sstevel@tonic-gate 	if (pairstack[pair] == 0) {
11907c478bd9Sstevel@tonic-gate 		x = execute(a[0]);
11917c478bd9Sstevel@tonic-gate 		if (istrue(x))
11927c478bd9Sstevel@tonic-gate 			pairstack[pair] = 1;
11937c478bd9Sstevel@tonic-gate 		tempfree(x, "");
11947c478bd9Sstevel@tonic-gate 	}
11957c478bd9Sstevel@tonic-gate 	if (pairstack[pair] == 1) {
11967c478bd9Sstevel@tonic-gate 		x = execute(a[1]);
11977c478bd9Sstevel@tonic-gate 		if (istrue(x))
11987c478bd9Sstevel@tonic-gate 			pairstack[pair] = 0;
11997c478bd9Sstevel@tonic-gate 		tempfree(x, "");
12007c478bd9Sstevel@tonic-gate 		x = execute(a[2]);
12017c478bd9Sstevel@tonic-gate 		return (x);
12027c478bd9Sstevel@tonic-gate 	}
12037c478bd9Sstevel@tonic-gate 	return (false);
12047c478bd9Sstevel@tonic-gate }
12057c478bd9Sstevel@tonic-gate 
1206*1ee2e5faSnakanon /*ARGSUSED*/
1207*1ee2e5faSnakanon Cell *
1208*1ee2e5faSnakanon split(Node **a, int nnn)
12097c478bd9Sstevel@tonic-gate {
12107c478bd9Sstevel@tonic-gate 	Cell *x, *y, *ap;
12117c478bd9Sstevel@tonic-gate 	register uchar *s;
12127c478bd9Sstevel@tonic-gate 	register int sep;
1213*1ee2e5faSnakanon 	uchar *t, temp, num[11], *fs;
12147c478bd9Sstevel@tonic-gate 	int n, tempstat;
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	y = execute(a[0]);	/* source string */
12177c478bd9Sstevel@tonic-gate 	s = getsval(y);
12187c478bd9Sstevel@tonic-gate 	if (a[2] == 0)		/* fs string */
12197c478bd9Sstevel@tonic-gate 		fs = *FS;
12207c478bd9Sstevel@tonic-gate 	else if ((int)a[3] == STRING) {	/* split(str,arr,"string") */
12217c478bd9Sstevel@tonic-gate 		x = execute(a[2]);
12227c478bd9Sstevel@tonic-gate 		fs = getsval(x);
12237c478bd9Sstevel@tonic-gate 	} else if ((int)a[3] == REGEXPR)
12247c478bd9Sstevel@tonic-gate 		fs = (uchar *)"(regexpr)";	/* split(str,arr,/regexpr/) */
12257c478bd9Sstevel@tonic-gate 	else
12267c478bd9Sstevel@tonic-gate 		ERROR "illegal type of split()" FATAL;
12277c478bd9Sstevel@tonic-gate 	sep = *fs;
12287c478bd9Sstevel@tonic-gate 	ap = execute(a[1]);	/* array name */
12297c478bd9Sstevel@tonic-gate 	freesymtab(ap);
12307c478bd9Sstevel@tonic-gate 	dprintf(("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs));
12317c478bd9Sstevel@tonic-gate 	ap->tval &= ~STR;
12327c478bd9Sstevel@tonic-gate 	ap->tval |= ARR;
12337c478bd9Sstevel@tonic-gate 	ap->sval = (uchar *)makesymtab(NSYMTAB);
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 	n = 0;
1236*1ee2e5faSnakanon 	if (*s != '\0' && strlen((char *)fs) > 1 || (int)a[3] == REGEXPR) {
1237*1ee2e5faSnakanon 		/* reg expr */
12387c478bd9Sstevel@tonic-gate 		fa *pfa;
12397c478bd9Sstevel@tonic-gate 		if ((int)a[3] == REGEXPR) {	/* it's ready already */
12407c478bd9Sstevel@tonic-gate 			pfa = (fa *)a[2];
12417c478bd9Sstevel@tonic-gate 		} else {
12427c478bd9Sstevel@tonic-gate 			pfa = makedfa(fs, 1);
12437c478bd9Sstevel@tonic-gate 		}
12447c478bd9Sstevel@tonic-gate 		if (nematch(pfa, s)) {
12457c478bd9Sstevel@tonic-gate 			tempstat = pfa->initstat;
12467c478bd9Sstevel@tonic-gate 			pfa->initstat = 2;
12477c478bd9Sstevel@tonic-gate 			do {
12487c478bd9Sstevel@tonic-gate 				n++;
1249*1ee2e5faSnakanon 				(void) sprintf((char *)num, "%d", n);
12507c478bd9Sstevel@tonic-gate 				temp = *patbeg;
12517c478bd9Sstevel@tonic-gate 				*patbeg = '\0';
1252*1ee2e5faSnakanon 				if (is_number(s)) {
1253*1ee2e5faSnakanon 					(void) setsymtab(num, s,
1254*1ee2e5faSnakanon 					    atof((char *)s),
1255*1ee2e5faSnakanon 					    /*LINTED align*/
1256*1ee2e5faSnakanon 					    STR|NUM, (Array *)ap->sval);
1257*1ee2e5faSnakanon 				} else {
1258*1ee2e5faSnakanon 					(void) setsymtab(num, s, 0.0,
1259*1ee2e5faSnakanon 					    /*LINTED align*/
1260*1ee2e5faSnakanon 					    STR, (Array *)ap->sval);
1261*1ee2e5faSnakanon 				}
12627c478bd9Sstevel@tonic-gate 				*patbeg = temp;
12637c478bd9Sstevel@tonic-gate 				s = patbeg + patlen;
12647c478bd9Sstevel@tonic-gate 				if (*(patbeg+patlen-1) == 0 || *s == 0) {
12657c478bd9Sstevel@tonic-gate 					n++;
1266*1ee2e5faSnakanon 					(void) sprintf((char *)num, "%d", n);
1267*1ee2e5faSnakanon 					(void) setsymtab(num, (uchar *)"", 0.0,
1268*1ee2e5faSnakanon 					    /*LINTED align*/
1269*1ee2e5faSnakanon 					    STR, (Array *)ap->sval);
12707c478bd9Sstevel@tonic-gate 					pfa->initstat = tempstat;
12717c478bd9Sstevel@tonic-gate 					goto spdone;
12727c478bd9Sstevel@tonic-gate 				}
12737c478bd9Sstevel@tonic-gate 			} while (nematch(pfa, s));
12747c478bd9Sstevel@tonic-gate 		}
12757c478bd9Sstevel@tonic-gate 		n++;
1276*1ee2e5faSnakanon 		(void) sprintf((char *)num, "%d", n);
1277*1ee2e5faSnakanon 		if (is_number(s)) {
1278*1ee2e5faSnakanon 			(void) setsymtab(num, s, atof((char *)s),
1279*1ee2e5faSnakanon 			    /*LINTED align*/
1280*1ee2e5faSnakanon 			    STR|NUM, (Array *)ap->sval);
1281*1ee2e5faSnakanon 		} else {
1282*1ee2e5faSnakanon 			/*LINTED align*/
1283*1ee2e5faSnakanon 			(void) setsymtab(num, s, 0.0, STR, (Array *)ap->sval);
1284*1ee2e5faSnakanon 		}
12857c478bd9Sstevel@tonic-gate spdone:
12867c478bd9Sstevel@tonic-gate 		pfa = NULL;
12877c478bd9Sstevel@tonic-gate 	} else if (sep == ' ') {
12887c478bd9Sstevel@tonic-gate 		for (n = 0; ; ) {
12897c478bd9Sstevel@tonic-gate 			while (*s == ' ' || *s == '\t' || *s == '\n')
12907c478bd9Sstevel@tonic-gate 				s++;
12917c478bd9Sstevel@tonic-gate 			if (*s == 0)
12927c478bd9Sstevel@tonic-gate 				break;
12937c478bd9Sstevel@tonic-gate 			n++;
12947c478bd9Sstevel@tonic-gate 			t = s;
12957c478bd9Sstevel@tonic-gate 			do
12967c478bd9Sstevel@tonic-gate 				s++;
1297*1ee2e5faSnakanon 			while (*s != ' ' && *s != '\t' &&
1298*1ee2e5faSnakanon 			    *s != '\n' && *s != '\0')
1299*1ee2e5faSnakanon 				;
13007c478bd9Sstevel@tonic-gate 			temp = *s;
13017c478bd9Sstevel@tonic-gate 			*s = '\0';
1302*1ee2e5faSnakanon 			(void) sprintf((char *)num, "%d", n);
1303*1ee2e5faSnakanon 			if (is_number(t)) {
1304*1ee2e5faSnakanon 				(void) setsymtab(num, t, atof((char *)t),
1305*1ee2e5faSnakanon 				    /*LINTED align*/
1306*1ee2e5faSnakanon 				    STR|NUM, (Array *)ap->sval);
1307*1ee2e5faSnakanon 			} else {
1308*1ee2e5faSnakanon 				(void) setsymtab(num, t, 0.0,
1309*1ee2e5faSnakanon 				    /*LINTED align*/
1310*1ee2e5faSnakanon 				    STR, (Array *)ap->sval);
1311*1ee2e5faSnakanon 			}
13127c478bd9Sstevel@tonic-gate 			*s = temp;
13137c478bd9Sstevel@tonic-gate 			if (*s != 0)
13147c478bd9Sstevel@tonic-gate 				s++;
13157c478bd9Sstevel@tonic-gate 		}
13167c478bd9Sstevel@tonic-gate 	} else if (*s != 0) {
13177c478bd9Sstevel@tonic-gate 		for (;;) {
13187c478bd9Sstevel@tonic-gate 			n++;
13197c478bd9Sstevel@tonic-gate 			t = s;
13207c478bd9Sstevel@tonic-gate 			while (*s != sep && *s != '\n' && *s != '\0')
13217c478bd9Sstevel@tonic-gate 				s++;
13227c478bd9Sstevel@tonic-gate 			temp = *s;
13237c478bd9Sstevel@tonic-gate 			*s = '\0';
1324*1ee2e5faSnakanon 			(void) sprintf((char *)num, "%d", n);
1325*1ee2e5faSnakanon 			if (is_number(t)) {
1326*1ee2e5faSnakanon 				(void) setsymtab(num, t, atof((char *)t),
1327*1ee2e5faSnakanon 				    /*LINTED align*/
1328*1ee2e5faSnakanon 				    STR|NUM, (Array *)ap->sval);
1329*1ee2e5faSnakanon 			} else {
1330*1ee2e5faSnakanon 				(void) setsymtab(num, t, 0.0,
1331*1ee2e5faSnakanon 				    /*LINTED align*/
1332*1ee2e5faSnakanon 				    STR, (Array *)ap->sval);
1333*1ee2e5faSnakanon 			}
13347c478bd9Sstevel@tonic-gate 			*s = temp;
13357c478bd9Sstevel@tonic-gate 			if (*s++ == 0)
13367c478bd9Sstevel@tonic-gate 				break;
13377c478bd9Sstevel@tonic-gate 		}
13387c478bd9Sstevel@tonic-gate 	}
13397c478bd9Sstevel@tonic-gate 	tempfree(ap, "");
13407c478bd9Sstevel@tonic-gate 	tempfree(y, "");
13417c478bd9Sstevel@tonic-gate 	if (a[2] != 0 && (int)a[3] == STRING)
13427c478bd9Sstevel@tonic-gate 		tempfree(x, "");
13437c478bd9Sstevel@tonic-gate 	x = gettemp("");
13447c478bd9Sstevel@tonic-gate 	x->tval = NUM;
13457c478bd9Sstevel@tonic-gate 	x->fval = n;
13467c478bd9Sstevel@tonic-gate 	return (x);
13477c478bd9Sstevel@tonic-gate }
13487c478bd9Sstevel@tonic-gate 
1349*1ee2e5faSnakanon /*ARGSUSED*/
1350*1ee2e5faSnakanon Cell *
1351*1ee2e5faSnakanon condexpr(Node **a, int n)
13527c478bd9Sstevel@tonic-gate {
13537c478bd9Sstevel@tonic-gate 	register Cell *x;
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
13567c478bd9Sstevel@tonic-gate 	if (istrue(x)) {
13577c478bd9Sstevel@tonic-gate 		tempfree(x, "");
13587c478bd9Sstevel@tonic-gate 		x = execute(a[1]);
13597c478bd9Sstevel@tonic-gate 	} else {
13607c478bd9Sstevel@tonic-gate 		tempfree(x, "");
13617c478bd9Sstevel@tonic-gate 		x = execute(a[2]);
13627c478bd9Sstevel@tonic-gate 	}
13637c478bd9Sstevel@tonic-gate 	return (x);
13647c478bd9Sstevel@tonic-gate }
13657c478bd9Sstevel@tonic-gate 
1366*1ee2e5faSnakanon /*ARGSUSED*/
1367*1ee2e5faSnakanon Cell *
1368*1ee2e5faSnakanon ifstat(Node **a, int n)
13697c478bd9Sstevel@tonic-gate {
13707c478bd9Sstevel@tonic-gate 	register Cell *x;
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
13737c478bd9Sstevel@tonic-gate 	if (istrue(x)) {
13747c478bd9Sstevel@tonic-gate 		tempfree(x, "");
13757c478bd9Sstevel@tonic-gate 		x = execute(a[1]);
13767c478bd9Sstevel@tonic-gate 	} else if (a[2] != 0) {
13777c478bd9Sstevel@tonic-gate 		tempfree(x, "");
13787c478bd9Sstevel@tonic-gate 		x = execute(a[2]);
13797c478bd9Sstevel@tonic-gate 	}
13807c478bd9Sstevel@tonic-gate 	return (x);
13817c478bd9Sstevel@tonic-gate }
13827c478bd9Sstevel@tonic-gate 
1383*1ee2e5faSnakanon /*ARGSUSED*/
1384*1ee2e5faSnakanon Cell *
1385*1ee2e5faSnakanon whilestat(Node **a, int n)
13867c478bd9Sstevel@tonic-gate {
13877c478bd9Sstevel@tonic-gate 	register Cell *x;
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate 	for (;;) {
13907c478bd9Sstevel@tonic-gate 		x = execute(a[0]);
13917c478bd9Sstevel@tonic-gate 		if (!istrue(x))
13927c478bd9Sstevel@tonic-gate 			return (x);
13937c478bd9Sstevel@tonic-gate 		tempfree(x, "");
13947c478bd9Sstevel@tonic-gate 		x = execute(a[1]);
13957c478bd9Sstevel@tonic-gate 		if (isbreak(x)) {
13967c478bd9Sstevel@tonic-gate 			x = true;
13977c478bd9Sstevel@tonic-gate 			return (x);
13987c478bd9Sstevel@tonic-gate 		}
13997c478bd9Sstevel@tonic-gate 		if (isnext(x) || isexit(x) || isret(x))
14007c478bd9Sstevel@tonic-gate 			return (x);
14017c478bd9Sstevel@tonic-gate 		tempfree(x, "");
14027c478bd9Sstevel@tonic-gate 	}
14037c478bd9Sstevel@tonic-gate }
14047c478bd9Sstevel@tonic-gate 
1405*1ee2e5faSnakanon /*ARGSUSED*/
1406*1ee2e5faSnakanon Cell *
1407*1ee2e5faSnakanon dostat(Node **a, int n)
14087c478bd9Sstevel@tonic-gate {
14097c478bd9Sstevel@tonic-gate 	register Cell *x;
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 	for (;;) {
14127c478bd9Sstevel@tonic-gate 		x = execute(a[0]);
14137c478bd9Sstevel@tonic-gate 		if (isbreak(x))
1414*1ee2e5faSnakanon 			return (true);
14157c478bd9Sstevel@tonic-gate 		if (isnext(x) || isexit(x) || isret(x))
14167c478bd9Sstevel@tonic-gate 			return (x);
14177c478bd9Sstevel@tonic-gate 		tempfree(x, "");
14187c478bd9Sstevel@tonic-gate 		x = execute(a[1]);
14197c478bd9Sstevel@tonic-gate 		if (!istrue(x))
14207c478bd9Sstevel@tonic-gate 			return (x);
14217c478bd9Sstevel@tonic-gate 		tempfree(x, "");
14227c478bd9Sstevel@tonic-gate 	}
14237c478bd9Sstevel@tonic-gate }
14247c478bd9Sstevel@tonic-gate 
1425*1ee2e5faSnakanon /*ARGSUSED*/
1426*1ee2e5faSnakanon Cell *
1427*1ee2e5faSnakanon forstat(Node **a, int n)
14287c478bd9Sstevel@tonic-gate {
14297c478bd9Sstevel@tonic-gate 	register Cell *x;
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
14327c478bd9Sstevel@tonic-gate 	tempfree(x, "");
14337c478bd9Sstevel@tonic-gate 	for (;;) {
14347c478bd9Sstevel@tonic-gate 		if (a[1] != 0) {
14357c478bd9Sstevel@tonic-gate 			x = execute(a[1]);
1436*1ee2e5faSnakanon 			if (!istrue(x))
1437*1ee2e5faSnakanon 				return (x);
1438*1ee2e5faSnakanon 			else
1439*1ee2e5faSnakanon 				tempfree(x, "");
14407c478bd9Sstevel@tonic-gate 		}
14417c478bd9Sstevel@tonic-gate 		x = execute(a[3]);
14427c478bd9Sstevel@tonic-gate 		if (isbreak(x))		/* turn off break */
1443*1ee2e5faSnakanon 			return (true);
14447c478bd9Sstevel@tonic-gate 		if (isnext(x) || isexit(x) || isret(x))
14457c478bd9Sstevel@tonic-gate 			return (x);
14467c478bd9Sstevel@tonic-gate 		tempfree(x, "");
14477c478bd9Sstevel@tonic-gate 		x = execute(a[2]);
14487c478bd9Sstevel@tonic-gate 		tempfree(x, "");
14497c478bd9Sstevel@tonic-gate 	}
14507c478bd9Sstevel@tonic-gate }
14517c478bd9Sstevel@tonic-gate 
1452*1ee2e5faSnakanon /*ARGSUSED*/
1453*1ee2e5faSnakanon Cell *
1454*1ee2e5faSnakanon instat(Node **a, int n)
14557c478bd9Sstevel@tonic-gate {
14567c478bd9Sstevel@tonic-gate 	register Cell *x, *vp, *arrayp, *cp, *ncp;
14577c478bd9Sstevel@tonic-gate 	Array *tp;
14587c478bd9Sstevel@tonic-gate 	int i;
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	vp = execute(a[0]);
14617c478bd9Sstevel@tonic-gate 	arrayp = execute(a[1]);
14627c478bd9Sstevel@tonic-gate 	if (!isarr(arrayp))
14637c478bd9Sstevel@tonic-gate 		ERROR "%s is not an array", arrayp->nval FATAL;
1464*1ee2e5faSnakanon 	/*LINTED align*/
14657c478bd9Sstevel@tonic-gate 	tp = (Array *)arrayp->sval;
14667c478bd9Sstevel@tonic-gate 	tempfree(arrayp, "");
14677c478bd9Sstevel@tonic-gate 	for (i = 0; i < tp->size; i++) { /* this routine knows too much */
14687c478bd9Sstevel@tonic-gate 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1469*1ee2e5faSnakanon 			(void) setsval(vp, cp->nval);
14707c478bd9Sstevel@tonic-gate 			ncp = cp->cnext;
14717c478bd9Sstevel@tonic-gate 			x = execute(a[2]);
14727c478bd9Sstevel@tonic-gate 			if (isbreak(x)) {
14737c478bd9Sstevel@tonic-gate 				tempfree(vp, "");
1474*1ee2e5faSnakanon 				return (true);
14757c478bd9Sstevel@tonic-gate 			}
14767c478bd9Sstevel@tonic-gate 			if (isnext(x) || isexit(x) || isret(x)) {
14777c478bd9Sstevel@tonic-gate 				tempfree(vp, "");
14787c478bd9Sstevel@tonic-gate 				return (x);
14797c478bd9Sstevel@tonic-gate 			}
14807c478bd9Sstevel@tonic-gate 			tempfree(x, "");
14817c478bd9Sstevel@tonic-gate 		}
14827c478bd9Sstevel@tonic-gate 	}
1483*1ee2e5faSnakanon 	return (true);
14847c478bd9Sstevel@tonic-gate }
14857c478bd9Sstevel@tonic-gate 
1486*1ee2e5faSnakanon /*ARGSUSED*/
1487*1ee2e5faSnakanon Cell *
1488*1ee2e5faSnakanon bltin(Node **a, int n)
14897c478bd9Sstevel@tonic-gate {
14907c478bd9Sstevel@tonic-gate 	register Cell *x, *y;
14917c478bd9Sstevel@tonic-gate 	Awkfloat u;
14927c478bd9Sstevel@tonic-gate 	register int t;
1493*1ee2e5faSnakanon 	uchar *p, *buf;
14947c478bd9Sstevel@tonic-gate 	Node *nextarg;
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate 	t = (int)a[0];
14977c478bd9Sstevel@tonic-gate 	x = execute(a[1]);
14987c478bd9Sstevel@tonic-gate 	nextarg = a[1]->nnext;
14997c478bd9Sstevel@tonic-gate 	switch (t) {
15007c478bd9Sstevel@tonic-gate 	case FLENGTH:
1501*1ee2e5faSnakanon 		u = (Awkfloat)strlen((char *)getsval(x)); break;
15027c478bd9Sstevel@tonic-gate 	case FLOG:
15037c478bd9Sstevel@tonic-gate 		u = errcheck(log(getfval(x)), "log"); break;
15047c478bd9Sstevel@tonic-gate 	case FINT:
1505*1ee2e5faSnakanon 		(void) modf(getfval(x), &u); break;
15067c478bd9Sstevel@tonic-gate 	case FEXP:
15077c478bd9Sstevel@tonic-gate 		u = errcheck(exp(getfval(x)), "exp"); break;
15087c478bd9Sstevel@tonic-gate 	case FSQRT:
15097c478bd9Sstevel@tonic-gate 		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
15107c478bd9Sstevel@tonic-gate 	case FSIN:
15117c478bd9Sstevel@tonic-gate 		u = sin(getfval(x)); break;
15127c478bd9Sstevel@tonic-gate 	case FCOS:
15137c478bd9Sstevel@tonic-gate 		u = cos(getfval(x)); break;
15147c478bd9Sstevel@tonic-gate 	case FATAN:
15157c478bd9Sstevel@tonic-gate 		if (nextarg == 0) {
1516*1ee2e5faSnakanon 			ERROR "atan2 requires two arguments; returning 1.0"
1517*1ee2e5faSnakanon 			    WARNING;
15187c478bd9Sstevel@tonic-gate 			u = 1.0;
15197c478bd9Sstevel@tonic-gate 		} else {
15207c478bd9Sstevel@tonic-gate 			y = execute(a[1]->nnext);
15217c478bd9Sstevel@tonic-gate 			u = atan2(getfval(x), getfval(y));
15227c478bd9Sstevel@tonic-gate 			tempfree(y, "");
15237c478bd9Sstevel@tonic-gate 			nextarg = nextarg->nnext;
15247c478bd9Sstevel@tonic-gate 		}
15257c478bd9Sstevel@tonic-gate 		break;
15267c478bd9Sstevel@tonic-gate 	case FSYSTEM:
1527*1ee2e5faSnakanon 		/* in case something is buffered already */
1528*1ee2e5faSnakanon 		(void) fflush(stdout);
1529*1ee2e5faSnakanon 		/* 256 is unix-dep */
1530*1ee2e5faSnakanon 		u = (Awkfloat)system((char *)getsval(x)) / 256;
15317c478bd9Sstevel@tonic-gate 		break;
15327c478bd9Sstevel@tonic-gate 	case FRAND:
15337c478bd9Sstevel@tonic-gate 		u = (Awkfloat)(rand() % 32767) / 32767.0;
15347c478bd9Sstevel@tonic-gate 		break;
15357c478bd9Sstevel@tonic-gate 	case FSRAND:
15367c478bd9Sstevel@tonic-gate 		if (x->tval & REC)	/* no argument provided */
15377c478bd9Sstevel@tonic-gate 			u = time((time_t *)0);
15387c478bd9Sstevel@tonic-gate 		else
15397c478bd9Sstevel@tonic-gate 			u = getfval(x);
15407c478bd9Sstevel@tonic-gate 		srand((int)u); u = (int)u;
15417c478bd9Sstevel@tonic-gate 		break;
15427c478bd9Sstevel@tonic-gate 	case FTOUPPER:
15437c478bd9Sstevel@tonic-gate 	case FTOLOWER:
1544*1ee2e5faSnakanon 		buf = tostring(getsval(x));
15457c478bd9Sstevel@tonic-gate 		if (t == FTOUPPER) {
15467c478bd9Sstevel@tonic-gate 			for (p = buf; *p; p++)
15477c478bd9Sstevel@tonic-gate 				if (islower(*p))
15487c478bd9Sstevel@tonic-gate 					*p = toupper(*p);
15497c478bd9Sstevel@tonic-gate 		} else {
15507c478bd9Sstevel@tonic-gate 			for (p = buf; *p; p++)
15517c478bd9Sstevel@tonic-gate 				if (isupper(*p))
15527c478bd9Sstevel@tonic-gate 					*p = tolower(*p);
15537c478bd9Sstevel@tonic-gate 		}
15547c478bd9Sstevel@tonic-gate 		tempfree(x, "");
15557c478bd9Sstevel@tonic-gate 		x = gettemp("");
1556*1ee2e5faSnakanon 		(void) setsval(x, buf);
1557*1ee2e5faSnakanon 		free(buf);
1558*1ee2e5faSnakanon 		return (x);
15597c478bd9Sstevel@tonic-gate 	default:	/* can't happen */
15607c478bd9Sstevel@tonic-gate 		ERROR "illegal function type %d", t FATAL;
15617c478bd9Sstevel@tonic-gate 		break;
15627c478bd9Sstevel@tonic-gate 	}
15637c478bd9Sstevel@tonic-gate 	tempfree(x, "");
15647c478bd9Sstevel@tonic-gate 	x = gettemp("");
1565*1ee2e5faSnakanon 	(void) setfval(x, u);
15667c478bd9Sstevel@tonic-gate 	if (nextarg != 0) {
15677c478bd9Sstevel@tonic-gate 		ERROR "warning: function has too many arguments" WARNING;
15687c478bd9Sstevel@tonic-gate 		for (; nextarg; nextarg = nextarg->nnext)
1569*1ee2e5faSnakanon 			(void) execute(nextarg);
15707c478bd9Sstevel@tonic-gate 	}
15717c478bd9Sstevel@tonic-gate 	return (x);
15727c478bd9Sstevel@tonic-gate }
15737c478bd9Sstevel@tonic-gate 
1574*1ee2e5faSnakanon /*ARGSUSED*/
1575*1ee2e5faSnakanon Cell *
1576*1ee2e5faSnakanon print(Node **a, int n)
15777c478bd9Sstevel@tonic-gate {
15787c478bd9Sstevel@tonic-gate 	register Node *x;
15797c478bd9Sstevel@tonic-gate 	register Cell *y;
15807c478bd9Sstevel@tonic-gate 	FILE *fp;
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate 	if (a[1] == 0)
15837c478bd9Sstevel@tonic-gate 		fp = stdout;
15847c478bd9Sstevel@tonic-gate 	else
15857c478bd9Sstevel@tonic-gate 		fp = redirect((int)a[1], a[2]);
15867c478bd9Sstevel@tonic-gate 	for (x = a[0]; x != NULL; x = x->nnext) {
15877c478bd9Sstevel@tonic-gate 		y = execute(x);
1588*1ee2e5faSnakanon 		(void) fputs((char *)getsval(y), fp);
15897c478bd9Sstevel@tonic-gate 		tempfree(y, "");
15907c478bd9Sstevel@tonic-gate 		if (x->nnext == NULL)
1591*1ee2e5faSnakanon 			(void) fputs((char *)*ORS, fp);
15927c478bd9Sstevel@tonic-gate 		else
1593*1ee2e5faSnakanon 			(void) fputs((char *)*OFS, fp);
15947c478bd9Sstevel@tonic-gate 	}
15957c478bd9Sstevel@tonic-gate 	if (a[1] != 0)
1596*1ee2e5faSnakanon 		(void) fflush(fp);
15977c478bd9Sstevel@tonic-gate 	return (true);
15987c478bd9Sstevel@tonic-gate }
15997c478bd9Sstevel@tonic-gate 
1600*1ee2e5faSnakanon /*ARGSUSED*/
1601*1ee2e5faSnakanon Cell *
1602*1ee2e5faSnakanon nullproc(Node **a, int n)
16037c478bd9Sstevel@tonic-gate {
1604*1ee2e5faSnakanon 	return (0);
1605*1ee2e5faSnakanon }
1606*1ee2e5faSnakanon 
1607*1ee2e5faSnakanon struct {
16087c478bd9Sstevel@tonic-gate 	FILE	*fp;
16097c478bd9Sstevel@tonic-gate 	uchar	*fname;
16107c478bd9Sstevel@tonic-gate 	int	mode;	/* '|', 'a', 'w' */
16117c478bd9Sstevel@tonic-gate } files[FOPEN_MAX];
16127c478bd9Sstevel@tonic-gate 
1613*1ee2e5faSnakanon static FILE *
1614*1ee2e5faSnakanon redirect(int a, Node *b)
16157c478bd9Sstevel@tonic-gate {
16167c478bd9Sstevel@tonic-gate 	FILE *fp;
16177c478bd9Sstevel@tonic-gate 	Cell *x;
16187c478bd9Sstevel@tonic-gate 	uchar *fname;
16197c478bd9Sstevel@tonic-gate 
16207c478bd9Sstevel@tonic-gate 	x = execute(b);
16217c478bd9Sstevel@tonic-gate 	fname = getsval(x);
16227c478bd9Sstevel@tonic-gate 	fp = openfile(a, fname);
16237c478bd9Sstevel@tonic-gate 	if (fp == NULL)
16247c478bd9Sstevel@tonic-gate 		ERROR "can't open file %s", fname FATAL;
16257c478bd9Sstevel@tonic-gate 	tempfree(x, "");
1626*1ee2e5faSnakanon 	return (fp);
16277c478bd9Sstevel@tonic-gate }
16287c478bd9Sstevel@tonic-gate 
1629*1ee2e5faSnakanon static FILE *
1630*1ee2e5faSnakanon openfile(int a, uchar *s)
16317c478bd9Sstevel@tonic-gate {
16327c478bd9Sstevel@tonic-gate 	register int i, m;
16337c478bd9Sstevel@tonic-gate 	register FILE *fp;
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate 	if (*s == '\0')
16367c478bd9Sstevel@tonic-gate 		ERROR "null file name in print or getline" FATAL;
1637*1ee2e5faSnakanon 	for (i = 0; i < FOPEN_MAX; i++) {
1638*1ee2e5faSnakanon 		if (files[i].fname &&
1639*1ee2e5faSnakanon 		    strcmp((char *)s, (char *)files[i].fname) == 0) {
1640*1ee2e5faSnakanon 			if (a == files[i].mode ||
1641*1ee2e5faSnakanon 			    a == APPEND && files[i].mode == GT) {
1642*1ee2e5faSnakanon 				return (files[i].fp);
1643*1ee2e5faSnakanon 			}
1644*1ee2e5faSnakanon 		}
1645*1ee2e5faSnakanon 	}
1646*1ee2e5faSnakanon 	for (i = 0; i < FOPEN_MAX; i++) {
16477c478bd9Sstevel@tonic-gate 		if (files[i].fp == 0)
16487c478bd9Sstevel@tonic-gate 			break;
1649*1ee2e5faSnakanon 	}
16507c478bd9Sstevel@tonic-gate 	if (i >= FOPEN_MAX)
16517c478bd9Sstevel@tonic-gate 		ERROR "%s makes too many open files", s FATAL;
1652*1ee2e5faSnakanon 	(void) fflush(stdout);	/* force a semblance of order */
16537c478bd9Sstevel@tonic-gate 	m = a;
16547c478bd9Sstevel@tonic-gate 	if (a == GT) {
16557c478bd9Sstevel@tonic-gate 		fp = fopen((char *)s, "w");
16567c478bd9Sstevel@tonic-gate 	} else if (a == APPEND) {
16577c478bd9Sstevel@tonic-gate 		fp = fopen((char *)s, "a");
16587c478bd9Sstevel@tonic-gate 		m = GT;	/* so can mix > and >> */
16597c478bd9Sstevel@tonic-gate 	} else if (a == '|') {	/* output pipe */
16607c478bd9Sstevel@tonic-gate 		fp = popen((char *)s, "w");
16617c478bd9Sstevel@tonic-gate 	} else if (a == LE) {	/* input pipe */
16627c478bd9Sstevel@tonic-gate 		fp = popen((char *)s, "r");
16637c478bd9Sstevel@tonic-gate 	} else if (a == LT) {	/* getline <file */
1664*1ee2e5faSnakanon 		fp = strcmp((char *)s, "-") == 0 ?
1665*1ee2e5faSnakanon 		    stdin : fopen((char *)s, "r");	/* "-" is stdin */
16667c478bd9Sstevel@tonic-gate 	} else	/* can't happen */
16677c478bd9Sstevel@tonic-gate 		ERROR "illegal redirection" FATAL;
16687c478bd9Sstevel@tonic-gate 	if (fp != NULL) {
16697c478bd9Sstevel@tonic-gate 		files[i].fname = tostring(s);
16707c478bd9Sstevel@tonic-gate 		files[i].fp = fp;
16717c478bd9Sstevel@tonic-gate 		files[i].mode = m;
16727c478bd9Sstevel@tonic-gate 	}
1673*1ee2e5faSnakanon 	return (fp);
16747c478bd9Sstevel@tonic-gate }
16757c478bd9Sstevel@tonic-gate 
1676*1ee2e5faSnakanon /*ARGSUSED*/
1677*1ee2e5faSnakanon Cell *
1678*1ee2e5faSnakanon closefile(Node **a, int n)
16797c478bd9Sstevel@tonic-gate {
16807c478bd9Sstevel@tonic-gate 	register Cell *x;
16817c478bd9Sstevel@tonic-gate 	int i, stat;
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
1684*1ee2e5faSnakanon 	(void) getsval(x);
1685*1ee2e5faSnakanon 	for (i = 0; i < FOPEN_MAX; i++) {
1686*1ee2e5faSnakanon 		if (files[i].fname &&
1687*1ee2e5faSnakanon 		    strcmp((char *)x->sval, (char *)files[i].fname) == 0) {
1688*1ee2e5faSnakanon 			if (ferror(files[i].fp)) {
1689*1ee2e5faSnakanon 				ERROR "i/o error occurred on %s",
1690*1ee2e5faSnakanon 				    files[i].fname WARNING;
1691*1ee2e5faSnakanon 			}
16927c478bd9Sstevel@tonic-gate 			if (files[i].mode == '|' || files[i].mode == LE)
16937c478bd9Sstevel@tonic-gate 				stat = pclose(files[i].fp);
16947c478bd9Sstevel@tonic-gate 			else
16957c478bd9Sstevel@tonic-gate 				stat = fclose(files[i].fp);
1696*1ee2e5faSnakanon 			if (stat == EOF) {
1697*1ee2e5faSnakanon 				ERROR "i/o error occurred closing %s",
1698*1ee2e5faSnakanon 				    files[i].fname WARNING;
1699*1ee2e5faSnakanon 			}
17007c478bd9Sstevel@tonic-gate 			xfree(files[i].fname);
1701*1ee2e5faSnakanon 			/* watch out for ref thru this */
1702*1ee2e5faSnakanon 			files[i].fname = NULL;
17037c478bd9Sstevel@tonic-gate 			files[i].fp = NULL;
17047c478bd9Sstevel@tonic-gate 		}
1705*1ee2e5faSnakanon 	}
17067c478bd9Sstevel@tonic-gate 	tempfree(x, "close");
17077c478bd9Sstevel@tonic-gate 	return (true);
17087c478bd9Sstevel@tonic-gate }
17097c478bd9Sstevel@tonic-gate 
1710*1ee2e5faSnakanon static void
1711*1ee2e5faSnakanon closeall(void)
17127c478bd9Sstevel@tonic-gate {
17137c478bd9Sstevel@tonic-gate 	int i, stat;
17147c478bd9Sstevel@tonic-gate 
1715*1ee2e5faSnakanon 	for (i = 0; i < FOPEN_MAX; i++) {
17167c478bd9Sstevel@tonic-gate 		if (files[i].fp) {
1717*1ee2e5faSnakanon 			if (ferror(files[i].fp)) {
1718*1ee2e5faSnakanon 				ERROR "i/o error occurred on %s",
1719*1ee2e5faSnakanon 				    files[i].fname WARNING;
1720*1ee2e5faSnakanon 			}
17217c478bd9Sstevel@tonic-gate 			if (files[i].mode == '|' || files[i].mode == LE)
17227c478bd9Sstevel@tonic-gate 				stat = pclose(files[i].fp);
17237c478bd9Sstevel@tonic-gate 			else
17247c478bd9Sstevel@tonic-gate 				stat = fclose(files[i].fp);
1725*1ee2e5faSnakanon 			if (stat == EOF) {
1726*1ee2e5faSnakanon 				ERROR "i/o error occurred while closing %s",
1727*1ee2e5faSnakanon 				    files[i].fname WARNING;
1728*1ee2e5faSnakanon 			}
1729*1ee2e5faSnakanon 		}
17307c478bd9Sstevel@tonic-gate 	}
17317c478bd9Sstevel@tonic-gate }
17327c478bd9Sstevel@tonic-gate 
1733*1ee2e5faSnakanon /*ARGSUSED*/
1734*1ee2e5faSnakanon Cell *
1735*1ee2e5faSnakanon sub(Node **a, int nnn)
17367c478bd9Sstevel@tonic-gate {
1737*1ee2e5faSnakanon 	register uchar *sptr;
17387c478bd9Sstevel@tonic-gate 	register Cell *x, *y, *result;
1739*1ee2e5faSnakanon 	uchar *buf, *t;
17407c478bd9Sstevel@tonic-gate 	fa *pfa;
1741*1ee2e5faSnakanon 	size_t	bsize, cnt, len;
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate 	x = execute(a[3]);	/* target string */
17447c478bd9Sstevel@tonic-gate 	t = getsval(x);
17457c478bd9Sstevel@tonic-gate 	if (a[0] == 0)
17467c478bd9Sstevel@tonic-gate 		pfa = (fa *)a[1];	/* regular expression */
17477c478bd9Sstevel@tonic-gate 	else {
17487c478bd9Sstevel@tonic-gate 		y = execute(a[1]);
17497c478bd9Sstevel@tonic-gate 		pfa = makedfa(getsval(y), 1);
17507c478bd9Sstevel@tonic-gate 		tempfree(y, "");
17517c478bd9Sstevel@tonic-gate 	}
17527c478bd9Sstevel@tonic-gate 	y = execute(a[2]);	/* replacement string */
17537c478bd9Sstevel@tonic-gate 	result = false;
17547c478bd9Sstevel@tonic-gate 	if (pmatch(pfa, t)) {
1755*1ee2e5faSnakanon 		init_buf(&buf, &bsize, LINE_INCR);
1756*1ee2e5faSnakanon 		cnt = 0;
17577c478bd9Sstevel@tonic-gate 		sptr = t;
1758*1ee2e5faSnakanon 		len = patbeg - sptr;
1759*1ee2e5faSnakanon 		if (len > 0) {
1760*1ee2e5faSnakanon 			expand_buf(&buf, &bsize, cnt + len);
1761*1ee2e5faSnakanon 			(void) memcpy(buf, sptr, len);
1762*1ee2e5faSnakanon 			cnt += len;
1763*1ee2e5faSnakanon 		}
17647c478bd9Sstevel@tonic-gate 		sptr = getsval(y);
1765*1ee2e5faSnakanon 		while (*sptr != 0) {
1766*1ee2e5faSnakanon 			expand_buf(&buf, &bsize, cnt);
17677c478bd9Sstevel@tonic-gate 			if (*sptr == '\\' && *(sptr+1) == '&') {
17687c478bd9Sstevel@tonic-gate 				sptr++;		/* skip \, */
1769*1ee2e5faSnakanon 				buf[cnt++] = *sptr++; /* add & */
17707c478bd9Sstevel@tonic-gate 			} else if (*sptr == '&') {
1771*1ee2e5faSnakanon 				expand_buf(&buf, &bsize, cnt + patlen);
17727c478bd9Sstevel@tonic-gate 				sptr++;
1773*1ee2e5faSnakanon 				(void) memcpy(&buf[cnt], patbeg, patlen);
1774*1ee2e5faSnakanon 				cnt += patlen;
1775*1ee2e5faSnakanon 			} else {
1776*1ee2e5faSnakanon 				buf[cnt++] = *sptr++;
1777*1ee2e5faSnakanon 			}
1778*1ee2e5faSnakanon 		}
17797c478bd9Sstevel@tonic-gate 		sptr = patbeg + patlen;
1780*1ee2e5faSnakanon 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1781*1ee2e5faSnakanon 			len = strlen((char *)sptr);
1782*1ee2e5faSnakanon 			expand_buf(&buf, &bsize, cnt + len);
1783*1ee2e5faSnakanon 			(void) memcpy(&buf[cnt], sptr, len);
1784*1ee2e5faSnakanon 			cnt += len;
1785*1ee2e5faSnakanon 		}
1786*1ee2e5faSnakanon 		buf[cnt] = '\0';
1787*1ee2e5faSnakanon 		(void) setsval(x, buf);
1788*1ee2e5faSnakanon 		free(buf);
1789*1ee2e5faSnakanon 		result = true;
17907c478bd9Sstevel@tonic-gate 	}
17917c478bd9Sstevel@tonic-gate 	tempfree(x, "");
17927c478bd9Sstevel@tonic-gate 	tempfree(y, "");
1793*1ee2e5faSnakanon 	return (result);
17947c478bd9Sstevel@tonic-gate }
17957c478bd9Sstevel@tonic-gate 
1796*1ee2e5faSnakanon /*ARGSUSED*/
1797*1ee2e5faSnakanon Cell *
1798*1ee2e5faSnakanon gsub(Node **a, int nnn)
17997c478bd9Sstevel@tonic-gate {
18007c478bd9Sstevel@tonic-gate 	register Cell *x, *y;
1801*1ee2e5faSnakanon 	register uchar *rptr, *sptr, *t;
1802*1ee2e5faSnakanon 	uchar *buf;
18037c478bd9Sstevel@tonic-gate 	register fa *pfa;
18047c478bd9Sstevel@tonic-gate 	int mflag, tempstat, num;
1805*1ee2e5faSnakanon 	size_t	bsize, cnt, len;
18067c478bd9Sstevel@tonic-gate 
18077c478bd9Sstevel@tonic-gate 	mflag = 0;	/* if mflag == 0, can replace empty string */
18087c478bd9Sstevel@tonic-gate 	num = 0;
18097c478bd9Sstevel@tonic-gate 	x = execute(a[3]);	/* target string */
18107c478bd9Sstevel@tonic-gate 	t = getsval(x);
18117c478bd9Sstevel@tonic-gate 	if (a[0] == 0)
18127c478bd9Sstevel@tonic-gate 		pfa = (fa *) a[1];	/* regular expression */
18137c478bd9Sstevel@tonic-gate 	else {
18147c478bd9Sstevel@tonic-gate 		y = execute(a[1]);
18157c478bd9Sstevel@tonic-gate 		pfa = makedfa(getsval(y), 1);
18167c478bd9Sstevel@tonic-gate 		tempfree(y, "");
18177c478bd9Sstevel@tonic-gate 	}
18187c478bd9Sstevel@tonic-gate 	y = execute(a[2]);	/* replacement string */
18197c478bd9Sstevel@tonic-gate 	if (pmatch(pfa, t)) {
18207c478bd9Sstevel@tonic-gate 		tempstat = pfa->initstat;
18217c478bd9Sstevel@tonic-gate 		pfa->initstat = 2;
1822*1ee2e5faSnakanon 		init_buf(&buf, &bsize, LINE_INCR);
18237c478bd9Sstevel@tonic-gate 		rptr = getsval(y);
1824*1ee2e5faSnakanon 		cnt = 0;
18257c478bd9Sstevel@tonic-gate 		do {
1826*1ee2e5faSnakanon 			if (patlen == 0 && *patbeg != 0) {
1827*1ee2e5faSnakanon 				/* matched empty string */
18287c478bd9Sstevel@tonic-gate 				if (mflag == 0) {	/* can replace empty */
18297c478bd9Sstevel@tonic-gate 					num++;
18307c478bd9Sstevel@tonic-gate 					sptr = rptr;
1831*1ee2e5faSnakanon 					while (*sptr != 0) {
1832*1ee2e5faSnakanon 						expand_buf(&buf, &bsize, cnt);
1833*1ee2e5faSnakanon 						if (*sptr == '\\' &&
1834*1ee2e5faSnakanon 						    *(sptr+1) == '&') {
18357c478bd9Sstevel@tonic-gate 							sptr++;
1836*1ee2e5faSnakanon 							buf[cnt++] = *sptr++;
18377c478bd9Sstevel@tonic-gate 						} else if (*sptr == '&') {
1838*1ee2e5faSnakanon 							expand_buf(&buf,
1839*1ee2e5faSnakanon 							    &bsize,
1840*1ee2e5faSnakanon 							    cnt + patlen);
18417c478bd9Sstevel@tonic-gate 							sptr++;
1842*1ee2e5faSnakanon 							(void) memcpy(&buf[cnt],
1843*1ee2e5faSnakanon 							    patbeg, patlen);
1844*1ee2e5faSnakanon 							cnt += patlen;
1845*1ee2e5faSnakanon 						} else {
1846*1ee2e5faSnakanon 							buf[cnt++] = *sptr++;
1847*1ee2e5faSnakanon 						}
1848*1ee2e5faSnakanon 					}
18497c478bd9Sstevel@tonic-gate 				}
18507c478bd9Sstevel@tonic-gate 				if (*t == 0)	/* at end */
18517c478bd9Sstevel@tonic-gate 					goto done;
1852*1ee2e5faSnakanon 				expand_buf(&buf, &bsize, cnt);
1853*1ee2e5faSnakanon 				buf[cnt++] = *t++;
18547c478bd9Sstevel@tonic-gate 				mflag = 0;
1855*1ee2e5faSnakanon 			} else {	/* matched nonempty string */
18567c478bd9Sstevel@tonic-gate 				num++;
18577c478bd9Sstevel@tonic-gate 				sptr = t;
1858*1ee2e5faSnakanon 				len = patbeg - sptr;
1859*1ee2e5faSnakanon 				if (len > 0) {
1860*1ee2e5faSnakanon 					expand_buf(&buf, &bsize, cnt + len);
1861*1ee2e5faSnakanon 					(void) memcpy(&buf[cnt], sptr, len);
1862*1ee2e5faSnakanon 					cnt += len;
1863*1ee2e5faSnakanon 				}
18647c478bd9Sstevel@tonic-gate 				sptr = rptr;
1865*1ee2e5faSnakanon 				while (*sptr != 0) {
1866*1ee2e5faSnakanon 					expand_buf(&buf, &bsize, cnt);
18677c478bd9Sstevel@tonic-gate 					if (*sptr == '\\' && *(sptr+1) == '&') {
18687c478bd9Sstevel@tonic-gate 						sptr++;
1869*1ee2e5faSnakanon 						buf[cnt++] = *sptr++;
18707c478bd9Sstevel@tonic-gate 					} else if (*sptr == '&') {
1871*1ee2e5faSnakanon 						expand_buf(&buf, &bsize,
1872*1ee2e5faSnakanon 						    cnt + patlen);
18737c478bd9Sstevel@tonic-gate 						sptr++;
1874*1ee2e5faSnakanon 						(void) memcpy(&buf[cnt],
1875*1ee2e5faSnakanon 						    patbeg, patlen);
1876*1ee2e5faSnakanon 						cnt += patlen;
1877*1ee2e5faSnakanon 					} else {
1878*1ee2e5faSnakanon 						buf[cnt++] = *sptr++;
1879*1ee2e5faSnakanon 					}
1880*1ee2e5faSnakanon 				}
18817c478bd9Sstevel@tonic-gate 				t = patbeg + patlen;
18827c478bd9Sstevel@tonic-gate 				if ((*(t-1) == 0) || (*t == 0))
18837c478bd9Sstevel@tonic-gate 					goto done;
18847c478bd9Sstevel@tonic-gate 				mflag = 1;
18857c478bd9Sstevel@tonic-gate 			}
18867c478bd9Sstevel@tonic-gate 		} while (pmatch(pfa, t));
18877c478bd9Sstevel@tonic-gate 		sptr = t;
1888*1ee2e5faSnakanon 		len = strlen((char *)sptr);
1889*1ee2e5faSnakanon 		expand_buf(&buf, &bsize, len + cnt);
1890*1ee2e5faSnakanon 		(void) memcpy(&buf[cnt], sptr, len);
1891*1ee2e5faSnakanon 		cnt += len;
1892*1ee2e5faSnakanon 	done:
1893*1ee2e5faSnakanon 		buf[cnt] = '\0';
1894*1ee2e5faSnakanon 		(void) setsval(x, buf);
1895*1ee2e5faSnakanon 		free(buf);
18967c478bd9Sstevel@tonic-gate 		pfa->initstat = tempstat;
18977c478bd9Sstevel@tonic-gate 	}
18987c478bd9Sstevel@tonic-gate 	tempfree(x, "");
18997c478bd9Sstevel@tonic-gate 	tempfree(y, "");
19007c478bd9Sstevel@tonic-gate 	x = gettemp("");
19017c478bd9Sstevel@tonic-gate 	x->tval = NUM;
19027c478bd9Sstevel@tonic-gate 	x->fval = num;
19037c478bd9Sstevel@tonic-gate 	return (x);
19047c478bd9Sstevel@tonic-gate }
1905