xref: /illumos-gate/usr/src/cmd/awk/run.c (revision 3ee4fc2a)
1*3ee4fc2aSCody Peter Mello /*
2*3ee4fc2aSCody Peter Mello  * Copyright (C) Lucent Technologies 1997
3*3ee4fc2aSCody Peter Mello  * All Rights Reserved
4*3ee4fc2aSCody Peter Mello  *
5*3ee4fc2aSCody Peter Mello  * Permission to use, copy, modify, and distribute this software and
6*3ee4fc2aSCody Peter Mello  * its documentation for any purpose and without fee is hereby
7*3ee4fc2aSCody Peter Mello  * granted, provided that the above copyright notice appear in all
8*3ee4fc2aSCody Peter Mello  * copies and that both that the copyright notice and this
9*3ee4fc2aSCody Peter Mello  * permission notice and warranty disclaimer appear in supporting
10*3ee4fc2aSCody Peter Mello  * documentation, and that the name Lucent Technologies or any of
11*3ee4fc2aSCody Peter Mello  * its entities not be used in advertising or publicity pertaining
12*3ee4fc2aSCody Peter Mello  * to distribution of the software without specific, written prior
13*3ee4fc2aSCody Peter Mello  * permission.
14*3ee4fc2aSCody Peter Mello  *
15*3ee4fc2aSCody Peter Mello  * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16*3ee4fc2aSCody Peter Mello  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17*3ee4fc2aSCody Peter Mello  * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18*3ee4fc2aSCody Peter Mello  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19*3ee4fc2aSCody Peter Mello  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20*3ee4fc2aSCody Peter Mello  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21*3ee4fc2aSCody Peter Mello  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22*3ee4fc2aSCody Peter Mello  * THIS SOFTWARE.
23*3ee4fc2aSCody Peter Mello  */
24*3ee4fc2aSCody Peter Mello 
257c478bd9Sstevel@tonic-gate /*
267c478bd9Sstevel@tonic-gate  * CDDL HEADER START
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
2983efe03bScf  * Common Development and Distribution License (the "License").
3083efe03bScf  * You may not use this file except in compliance with the License.
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
337c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
347c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
357c478bd9Sstevel@tonic-gate  * and limitations under the License.
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
387c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
397c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
407c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
417c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
427c478bd9Sstevel@tonic-gate  *
437c478bd9Sstevel@tonic-gate  * CDDL HEADER END
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /*
4723a1cceaSRoger A. Faulkner  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate 
501ee2e5faSnakanon /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
511ee2e5faSnakanon /*	  All Rights Reserved  	*/
521ee2e5faSnakanon 
531ee2e5faSnakanon #define	DEBUG
547c478bd9Sstevel@tonic-gate #include	<stdio.h>
557c478bd9Sstevel@tonic-gate #include	<ctype.h>
567c478bd9Sstevel@tonic-gate #include	<setjmp.h>
57*3ee4fc2aSCody Peter Mello #include	<math.h>
587c478bd9Sstevel@tonic-gate #include	<time.h>
59*3ee4fc2aSCody Peter Mello #include	<sys/wait.h>
60*3ee4fc2aSCody Peter Mello #include	"awk.h"
61*3ee4fc2aSCody Peter Mello #include	"y.tab.h"
627c478bd9Sstevel@tonic-gate 
63*3ee4fc2aSCody Peter Mello #define	tempfree(x)	if (istemp(x)) tfree(x)
647c478bd9Sstevel@tonic-gate 
651ee2e5faSnakanon static jmp_buf env;
66*3ee4fc2aSCody Peter Mello extern	Awkfloat	srand_seed;
677c478bd9Sstevel@tonic-gate 
68*3ee4fc2aSCody Peter Mello static	Cell	*execute(Node *);
69*3ee4fc2aSCody Peter Mello static	Cell	*gettemp(void), *copycell(Cell *);
70*3ee4fc2aSCody Peter Mello static	FILE	*openfile(int, const char *), *redirect(int, Node *);
717c478bd9Sstevel@tonic-gate 
72*3ee4fc2aSCody Peter Mello Node	*winner = NULL;		/* root of parse tree */
73*3ee4fc2aSCody Peter Mello static Cell	*tmps;		/* free temporary cells for execution */
741ee2e5faSnakanon 
75*3ee4fc2aSCody Peter Mello static Cell	truecell	= { OBOOL, BTRUE, NULL, NULL, 1.0, NUM, NULL };
76*3ee4fc2aSCody Peter Mello Cell	*True	= &truecell;
77*3ee4fc2aSCody Peter Mello static Cell	falsecell	= { OBOOL, BFALSE, NULL, NULL, 0.0, NUM, NULL };
78*3ee4fc2aSCody Peter Mello Cell	*False	= &falsecell;
79*3ee4fc2aSCody Peter Mello static Cell	breakcell	= { OJUMP, JBREAK, NULL, NULL, 0.0, NUM, NULL };
807c478bd9Sstevel@tonic-gate Cell	*jbreak	= &breakcell;
81*3ee4fc2aSCody Peter Mello static Cell	contcell	= { OJUMP, JCONT, NULL, NULL, 0.0, NUM, NULL };
827c478bd9Sstevel@tonic-gate Cell	*jcont	= &contcell;
83*3ee4fc2aSCody Peter Mello static Cell	nextcell	= { OJUMP, JNEXT, NULL, NULL, 0.0, NUM, NULL };
847c478bd9Sstevel@tonic-gate Cell	*jnext	= &nextcell;
85*3ee4fc2aSCody Peter Mello static Cell	nextfilecell	= { OJUMP, JNEXTFILE, NULL, NULL, 0.0,
86*3ee4fc2aSCody Peter Mello 				    NUM, NULL };
87*3ee4fc2aSCody Peter Mello Cell	*jnextfile	= &nextfilecell;
88*3ee4fc2aSCody Peter Mello static Cell	exitcell	= { OJUMP, JEXIT, NULL, NULL, 0.0, NUM, NULL };
897c478bd9Sstevel@tonic-gate Cell	*jexit	= &exitcell;
90*3ee4fc2aSCody Peter Mello static Cell	retcell		= { OJUMP, JRET, NULL, NULL, 0.0, NUM, NULL };
917c478bd9Sstevel@tonic-gate Cell	*jret	= &retcell;
92*3ee4fc2aSCody Peter Mello static Cell	tempcell	= { OCELL, CTEMP, NULL, "", 0.0,
93*3ee4fc2aSCody Peter Mello 				    NUM|STR|DONTFREE, NULL };
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate Node	*curnode = NULL;	/* the node being executed, for debugging */
967c478bd9Sstevel@tonic-gate 
97*3ee4fc2aSCody Peter Mello static	void	tfree(Cell *);
981ee2e5faSnakanon static	void	closeall(void);
991ee2e5faSnakanon static	double	ipow(double, int);
100*3ee4fc2aSCody Peter Mello static	void	backsub(char **pb_ptr, char **sptr_ptr);
101*3ee4fc2aSCody Peter Mello 
102*3ee4fc2aSCody Peter Mello 
103*3ee4fc2aSCody Peter Mello /*
104*3ee4fc2aSCody Peter Mello  * buffer memory management
105*3ee4fc2aSCody Peter Mello  *
106*3ee4fc2aSCody Peter Mello  * pbuf:    address of pointer to buffer being managed
107*3ee4fc2aSCody Peter Mello  * psiz:    address of buffer size variable
108*3ee4fc2aSCody Peter Mello  * minlen:  minimum length of buffer needed
109*3ee4fc2aSCody Peter Mello  * quantum: buffer size quantum
110*3ee4fc2aSCody Peter Mello  * pbptr:   address of movable pointer into buffer, or 0 if none
111*3ee4fc2aSCody Peter Mello  * whatrtn: name of the calling routine if failure should cause fatal error
112*3ee4fc2aSCody Peter Mello  *
113*3ee4fc2aSCody Peter Mello  * return   0 for realloc failure, !=0 for success
114*3ee4fc2aSCody Peter Mello  */
115*3ee4fc2aSCody Peter Mello int
adjbuf(char ** pbuf,size_t * psiz,size_t minlen,size_t quantum,char ** pbptr,const char * whatrtn)116*3ee4fc2aSCody Peter Mello adjbuf(char **pbuf, size_t *psiz, size_t minlen, size_t quantum, char **pbptr,
117*3ee4fc2aSCody Peter Mello     const char *whatrtn)
118*3ee4fc2aSCody Peter Mello {
119*3ee4fc2aSCody Peter Mello 	if (minlen > *psiz) {
120*3ee4fc2aSCody Peter Mello 		char *tbuf;
121*3ee4fc2aSCody Peter Mello 		int rminlen = quantum ? minlen % quantum : 0;
122*3ee4fc2aSCody Peter Mello 		int boff = pbptr ? *pbptr - *pbuf : 0;
123*3ee4fc2aSCody Peter Mello 		/* round up to next multiple of quantum */
124*3ee4fc2aSCody Peter Mello 		if (rminlen)
125*3ee4fc2aSCody Peter Mello 			minlen += quantum - rminlen;
126*3ee4fc2aSCody Peter Mello 		tbuf = (char *)realloc(*pbuf, minlen);
127*3ee4fc2aSCody Peter Mello 		dprintf(("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn,
128*3ee4fc2aSCody Peter Mello 		    *psiz, minlen, (void *)*pbuf, (void *)tbuf));
129*3ee4fc2aSCody Peter Mello 		if (tbuf == NULL) {
130*3ee4fc2aSCody Peter Mello 			if (whatrtn)
131*3ee4fc2aSCody Peter Mello 				FATAL("out of memory in %s", whatrtn);
132*3ee4fc2aSCody Peter Mello 			return (0);
133*3ee4fc2aSCody Peter Mello 		}
134*3ee4fc2aSCody Peter Mello 		*pbuf = tbuf;
135*3ee4fc2aSCody Peter Mello 		*psiz = minlen;
136*3ee4fc2aSCody Peter Mello 		if (pbptr)
137*3ee4fc2aSCody Peter Mello 			*pbptr = tbuf + boff;
138*3ee4fc2aSCody Peter Mello 	}
139*3ee4fc2aSCody Peter Mello 	return (1);
140*3ee4fc2aSCody Peter Mello }
1411ee2e5faSnakanon 
1421ee2e5faSnakanon void
run(Node * a)143*3ee4fc2aSCody Peter Mello run(Node *a)	/* execution of parse tree starts here */
1447c478bd9Sstevel@tonic-gate {
145*3ee4fc2aSCody Peter Mello 	extern void stdinit(void);
146*3ee4fc2aSCody Peter Mello 
147*3ee4fc2aSCody Peter Mello 	stdinit();
1481ee2e5faSnakanon 	(void) execute(a);
1497c478bd9Sstevel@tonic-gate 	closeall();
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1521ee2e5faSnakanon static Cell *
execute(Node * u)153*3ee4fc2aSCody Peter Mello execute(Node *u)	/* execute a node of the parse tree */
1547c478bd9Sstevel@tonic-gate {
155*3ee4fc2aSCody Peter Mello 	Cell *(*proc)(Node **, int);
156*3ee4fc2aSCody Peter Mello 	Cell *x;
157*3ee4fc2aSCody Peter Mello 	Node *a;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	if (u == NULL)
160*3ee4fc2aSCody Peter Mello 		return (True);
1617c478bd9Sstevel@tonic-gate 	for (a = u; ; a = a->nnext) {
1627c478bd9Sstevel@tonic-gate 		curnode = a;
1637c478bd9Sstevel@tonic-gate 		if (isvalue(a)) {
1647c478bd9Sstevel@tonic-gate 			x = (Cell *) (a->narg[0]);
165*3ee4fc2aSCody Peter Mello 			if (isfld(x) && !donefld)
1667c478bd9Sstevel@tonic-gate 				fldbld();
167*3ee4fc2aSCody Peter Mello 			else if (isrec(x) && !donerec)
1687c478bd9Sstevel@tonic-gate 				recbld();
1691ee2e5faSnakanon 			return (x);
1707c478bd9Sstevel@tonic-gate 		}
1711ee2e5faSnakanon 		/* probably a Cell* but too risky to print */
1721ee2e5faSnakanon 		if (notlegal(a->nobj))
173*3ee4fc2aSCody Peter Mello 			FATAL("illegal statement");
1747c478bd9Sstevel@tonic-gate 		proc = proctab[a->nobj-FIRSTTOKEN];
1757c478bd9Sstevel@tonic-gate 		x = (*proc)(a->narg, a->nobj);
176*3ee4fc2aSCody Peter Mello 		if (isfld(x) && !donefld)
1777c478bd9Sstevel@tonic-gate 			fldbld();
178*3ee4fc2aSCody Peter Mello 		else if (isrec(x) && !donerec)
1797c478bd9Sstevel@tonic-gate 			recbld();
1807c478bd9Sstevel@tonic-gate 		if (isexpr(a))
1811ee2e5faSnakanon 			return (x);
1827c478bd9Sstevel@tonic-gate 		/* a statement, goto next statement */
1837c478bd9Sstevel@tonic-gate 		if (isjump(x))
1841ee2e5faSnakanon 			return (x);
185*3ee4fc2aSCody Peter Mello 		if (a->nnext == NULL)
1861ee2e5faSnakanon 			return (x);
187*3ee4fc2aSCody Peter Mello 		tempfree(x);
1887c478bd9Sstevel@tonic-gate 	}
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate 
191*3ee4fc2aSCody Peter Mello /* execute an awk program */
192*3ee4fc2aSCody Peter Mello /* a[0] = BEGIN, a[1] = body, a[2] = END */
1931ee2e5faSnakanon /*ARGSUSED*/
1941ee2e5faSnakanon Cell *
program(Node ** a,int n)1951ee2e5faSnakanon program(Node **a, int n)
1967c478bd9Sstevel@tonic-gate {
197*3ee4fc2aSCody Peter Mello 	Cell *x;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	if (setjmp(env) != 0)
2007c478bd9Sstevel@tonic-gate 		goto ex;
2017c478bd9Sstevel@tonic-gate 	if (a[0]) {		/* BEGIN */
2027c478bd9Sstevel@tonic-gate 		x = execute(a[0]);
2037c478bd9Sstevel@tonic-gate 		if (isexit(x))
204*3ee4fc2aSCody Peter Mello 			return (True);
2051ee2e5faSnakanon 		if (isjump(x)) {
206*3ee4fc2aSCody Peter Mello 			FATAL("illegal break, continue, next or nextfile "
207*3ee4fc2aSCody Peter Mello 			    "from BEGIN");
2081ee2e5faSnakanon 		}
209*3ee4fc2aSCody Peter Mello 		tempfree(x);
2107c478bd9Sstevel@tonic-gate 	}
2117c478bd9Sstevel@tonic-gate 	if (a[1] || a[2])
212*3ee4fc2aSCody Peter Mello 		while (getrec(&record, &recsize, 1) > 0) {
2137c478bd9Sstevel@tonic-gate 			x = execute(a[1]);
2147c478bd9Sstevel@tonic-gate 			if (isexit(x))
2157c478bd9Sstevel@tonic-gate 				break;
216*3ee4fc2aSCody Peter Mello 			tempfree(x);
2177c478bd9Sstevel@tonic-gate 		}
2181ee2e5faSnakanon ex:
219*3ee4fc2aSCody Peter Mello 	if (setjmp(env) != 0)	/* handles exit within END */
2207c478bd9Sstevel@tonic-gate 		goto ex1;
2217c478bd9Sstevel@tonic-gate 	if (a[2]) {		/* END */
2227c478bd9Sstevel@tonic-gate 		x = execute(a[2]);
223*3ee4fc2aSCody Peter Mello 		if (isbreak(x) || isnext(x) || iscont(x))
224*3ee4fc2aSCody Peter Mello 			FATAL("illegal break, continue, next or nextfile "
225*3ee4fc2aSCody Peter Mello 			    "from END");
226*3ee4fc2aSCody Peter Mello 		tempfree(x);
2277c478bd9Sstevel@tonic-gate 	}
2281ee2e5faSnakanon ex1:
229*3ee4fc2aSCody Peter Mello 	return (True);
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate 
232*3ee4fc2aSCody Peter Mello struct Frame {	/* stack frame for awk function calls */
2337c478bd9Sstevel@tonic-gate 	int nargs;	/* number of arguments in this call */
2347c478bd9Sstevel@tonic-gate 	Cell *fcncell;	/* pointer to Cell for function */
2357c478bd9Sstevel@tonic-gate 	Cell **args;	/* pointer to array of arguments after execute */
2367c478bd9Sstevel@tonic-gate 	Cell *retval;	/* return value */
2377c478bd9Sstevel@tonic-gate };
2387c478bd9Sstevel@tonic-gate 
239*3ee4fc2aSCody Peter Mello #define	NARGS	50	/* max args in a call */
2407c478bd9Sstevel@tonic-gate 
241*3ee4fc2aSCody Peter Mello struct Frame *frame = NULL;	/* base of stack frames; dynamically alloc'd */
2427c478bd9Sstevel@tonic-gate int	nframe = 0;		/* number of frames allocated */
2437c478bd9Sstevel@tonic-gate struct Frame *fp = NULL;	/* frame pointer. bottom level unused */
2447c478bd9Sstevel@tonic-gate 
2451ee2e5faSnakanon /*ARGSUSED*/
2461ee2e5faSnakanon Cell *
call(Node ** a,int n)247*3ee4fc2aSCody Peter Mello call(Node **a, int n)	/* function call.  very kludgy and fragile */
2487c478bd9Sstevel@tonic-gate {
2491ee2e5faSnakanon 	static Cell newcopycell =
250*3ee4fc2aSCody Peter Mello 		{ OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE, NULL };
251*3ee4fc2aSCody Peter Mello 	int i, ncall, ndef;
252*3ee4fc2aSCody Peter Mello 	/* handles potential double freeing when fcn & param share a tempcell */
253*3ee4fc2aSCody Peter Mello 	int freed = 0;
2547c478bd9Sstevel@tonic-gate 	Node *x;
255*3ee4fc2aSCody Peter Mello 	Cell *args[NARGS], *oargs[NARGS];	/* BUG: fixed size arrays */
256*3ee4fc2aSCody Peter Mello 	Cell *y, *z, *fcn;
257*3ee4fc2aSCody Peter Mello 	char *s;
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	fcn = execute(a[0]);	/* the function itself */
2607c478bd9Sstevel@tonic-gate 	s = fcn->nval;
261*3ee4fc2aSCody Peter Mello 	if (!isfcn(fcn))
262*3ee4fc2aSCody Peter Mello 		FATAL("calling undefined function %s", s);
2637c478bd9Sstevel@tonic-gate 	if (frame == NULL) {
2641ee2e5faSnakanon 		fp = frame = (struct Frame *)calloc(nframe += 100,
2651ee2e5faSnakanon 		    sizeof (struct Frame));
2661ee2e5faSnakanon 		if (frame == NULL) {
267*3ee4fc2aSCody Peter Mello 			FATAL("out of space for stack frames calling %s", s);
2681ee2e5faSnakanon 		}
2697c478bd9Sstevel@tonic-gate 	}
2701ee2e5faSnakanon 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
2717c478bd9Sstevel@tonic-gate 		ncall++;
2721ee2e5faSnakanon 	ndef = (int)fcn->fval;			/* args in defn */
2731ee2e5faSnakanon 	dprintf(("calling %s, %d args (%d in defn), fp=%d\n",
2741ee2e5faSnakanon 	    s, ncall, ndef, fp-frame));
2751ee2e5faSnakanon 	if (ncall > ndef) {
276*3ee4fc2aSCody Peter Mello 		WARNING("function %s called with %d args, uses only %d",
277*3ee4fc2aSCody Peter Mello 		    s, ncall, ndef);
2781ee2e5faSnakanon 	}
2791ee2e5faSnakanon 	if (ncall + ndef > NARGS) {
280*3ee4fc2aSCody Peter Mello 		FATAL("function %s has %d arguments, limit %d",
281*3ee4fc2aSCody Peter Mello 		    s, ncall+ndef, NARGS);
2821ee2e5faSnakanon 	}
2831ee2e5faSnakanon 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {
2841ee2e5faSnakanon 		/* get call args */
2851ee2e5faSnakanon 		dprintf(("evaluate args[%d], fp=%d:\n", i, fp-frame));
2867c478bd9Sstevel@tonic-gate 		y = execute(x);
2877c478bd9Sstevel@tonic-gate 		oargs[i] = y;
2881ee2e5faSnakanon 		dprintf(("args[%d]: %s %f <%s>, t=%o\n",
289*3ee4fc2aSCody Peter Mello 		    i, NN(y->nval), y->fval,
290*3ee4fc2aSCody Peter Mello 		    isarr(y) ? "(array)" : NN(y->sval), y->tval));
291*3ee4fc2aSCody Peter Mello 		if (isfcn(y)) {
292*3ee4fc2aSCody Peter Mello 			FATAL("can't use function %s as argument in %s",
293*3ee4fc2aSCody Peter Mello 			    y->nval, s);
2941ee2e5faSnakanon 		}
2957c478bd9Sstevel@tonic-gate 		if (isarr(y))
2967c478bd9Sstevel@tonic-gate 			args[i] = y;	/* arrays by ref */
2977c478bd9Sstevel@tonic-gate 		else
2987c478bd9Sstevel@tonic-gate 			args[i] = copycell(y);
299*3ee4fc2aSCody Peter Mello 		tempfree(y);
3007c478bd9Sstevel@tonic-gate 	}
301*3ee4fc2aSCody Peter Mello 	for (; i < ndef; i++) {	/* add null args for ones not provided */
302*3ee4fc2aSCody Peter Mello 		args[i] = gettemp();
3037c478bd9Sstevel@tonic-gate 		*args[i] = newcopycell;
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 	fp++;	/* now ok to up frame */
3067c478bd9Sstevel@tonic-gate 	if (fp >= frame + nframe) {
3077c478bd9Sstevel@tonic-gate 		int dfp = fp - frame;	/* old index */
3087c478bd9Sstevel@tonic-gate 		frame = (struct Frame *)
3091ee2e5faSnakanon 		    realloc(frame, (nframe += 100) * sizeof (struct Frame));
3107c478bd9Sstevel@tonic-gate 		if (frame == NULL)
311*3ee4fc2aSCody Peter Mello 			FATAL("out of space for stack frames in %s", s);
3127c478bd9Sstevel@tonic-gate 		fp = frame + dfp;
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 	fp->fcncell = fcn;
3157c478bd9Sstevel@tonic-gate 	fp->args = args;
3167c478bd9Sstevel@tonic-gate 	fp->nargs = ndef;	/* number defined with (excess are locals) */
317*3ee4fc2aSCody Peter Mello 	fp->retval = gettemp();
3187c478bd9Sstevel@tonic-gate 
3191ee2e5faSnakanon 	dprintf(("start exec of %s, fp=%d\n", s, fp-frame));
3201ee2e5faSnakanon 	/*LINTED align*/
3217c478bd9Sstevel@tonic-gate 	y = execute((Node *)(fcn->sval));	/* execute body */
3221ee2e5faSnakanon 	dprintf(("finished exec of %s, fp=%d\n", s, fp-frame));
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	for (i = 0; i < ndef; i++) {
3257c478bd9Sstevel@tonic-gate 		Cell *t = fp->args[i];
3267c478bd9Sstevel@tonic-gate 		if (isarr(t)) {
3277c478bd9Sstevel@tonic-gate 			if (t->csub == CCOPY) {
3287c478bd9Sstevel@tonic-gate 				if (i >= ncall) {
3297c478bd9Sstevel@tonic-gate 					freesymtab(t);
3307c478bd9Sstevel@tonic-gate 					t->csub = CTEMP;
331*3ee4fc2aSCody Peter Mello 					tempfree(t);
3327c478bd9Sstevel@tonic-gate 				} else {
3337c478bd9Sstevel@tonic-gate 					oargs[i]->tval = t->tval;
3347c478bd9Sstevel@tonic-gate 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
3357c478bd9Sstevel@tonic-gate 					oargs[i]->sval = t->sval;
336*3ee4fc2aSCody Peter Mello 					tempfree(t);
3377c478bd9Sstevel@tonic-gate 				}
3387c478bd9Sstevel@tonic-gate 			}
339*3ee4fc2aSCody Peter Mello 		} else if (t != y) {	/* kludge to prevent freeing twice */
3407c478bd9Sstevel@tonic-gate 			t->csub = CTEMP;
341*3ee4fc2aSCody Peter Mello 			tempfree(t);
342*3ee4fc2aSCody Peter Mello 		} else if (t == y && t->csub == CCOPY) {
343*3ee4fc2aSCody Peter Mello 			t->csub = CTEMP;
344*3ee4fc2aSCody Peter Mello 			tempfree(t);
345*3ee4fc2aSCody Peter Mello 			freed = 1;
3467c478bd9Sstevel@tonic-gate 		}
3477c478bd9Sstevel@tonic-gate 	}
348*3ee4fc2aSCody Peter Mello 	tempfree(fcn);
3497c478bd9Sstevel@tonic-gate 	if (isexit(y) || isnext(y))
3501ee2e5faSnakanon 		return (y);
351*3ee4fc2aSCody Peter Mello 	if (freed == 0) {
352*3ee4fc2aSCody Peter Mello 		tempfree(y);	/* don't free twice! */
353*3ee4fc2aSCody Peter Mello 	}
3547c478bd9Sstevel@tonic-gate 	z = fp->retval;			/* return value */
3551ee2e5faSnakanon 	dprintf(("%s returns %g |%s| %o\n",
3561ee2e5faSnakanon 	    s, getfval(z), getsval(z), z->tval));
3577c478bd9Sstevel@tonic-gate 	fp--;
3581ee2e5faSnakanon 	return (z);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate 
3611ee2e5faSnakanon static Cell *
copycell(Cell * x)3621ee2e5faSnakanon copycell(Cell *x)	/* make a copy of a cell in a temp */
3637c478bd9Sstevel@tonic-gate {
3647c478bd9Sstevel@tonic-gate 	Cell *y;
3657c478bd9Sstevel@tonic-gate 
366*3ee4fc2aSCody Peter Mello 	/* copy is not constant or field */
367*3ee4fc2aSCody Peter Mello 
368*3ee4fc2aSCody Peter Mello 	y = gettemp();
369*3ee4fc2aSCody Peter Mello 	y->tval = x->tval & ~(CON|FLD|REC);
3707c478bd9Sstevel@tonic-gate 	y->csub = CCOPY;	/* prevents freeing until call is over */
371*3ee4fc2aSCody Peter Mello 	y->nval = x->nval;	/* BUG? */
372*3ee4fc2aSCody Peter Mello 	if (isstr(x)) {
373*3ee4fc2aSCody Peter Mello 		y->sval = tostring(x->sval);
374*3ee4fc2aSCody Peter Mello 		y->tval &= ~DONTFREE;
375*3ee4fc2aSCody Peter Mello 	} else
376*3ee4fc2aSCody Peter Mello 		y->tval |= DONTFREE;
3777c478bd9Sstevel@tonic-gate 	y->fval = x->fval;
3781ee2e5faSnakanon 	return (y);
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate 
3811ee2e5faSnakanon /*ARGSUSED*/
3821ee2e5faSnakanon Cell *
arg(Node ** a,int nnn)383*3ee4fc2aSCody Peter Mello arg(Node **a, int nnn)	/* nth argument of a function */
3847c478bd9Sstevel@tonic-gate {
3857c478bd9Sstevel@tonic-gate 	int n;
3867c478bd9Sstevel@tonic-gate 
387*3ee4fc2aSCody Peter Mello 	n = ptoi(a[0]);	/* argument number, counting from 0 */
3881ee2e5faSnakanon 	dprintf(("arg(%d), fp->nargs=%d\n", n, fp->nargs));
3891ee2e5faSnakanon 	if (n+1 > fp->nargs) {
390*3ee4fc2aSCody Peter Mello 		FATAL("argument #%d of function %s was not supplied",
391*3ee4fc2aSCody Peter Mello 		    n+1, fp->fcncell->nval);
3921ee2e5faSnakanon 	}
3931ee2e5faSnakanon 	return (fp->args[n]);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate 
3961ee2e5faSnakanon Cell *
jump(Node ** a,int n)397*3ee4fc2aSCody Peter Mello jump(Node **a, int n)	/* break, continue, next, nextfile, return */
3987c478bd9Sstevel@tonic-gate {
399*3ee4fc2aSCody Peter Mello 	Cell *y;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	switch (n) {
4027c478bd9Sstevel@tonic-gate 	case EXIT:
4037c478bd9Sstevel@tonic-gate 		if (a[0] != NULL) {
4047c478bd9Sstevel@tonic-gate 			y = execute(a[0]);
40512809310Snakanon 			errorflag = (int)getfval(y);
406*3ee4fc2aSCody Peter Mello 			tempfree(y);
4077c478bd9Sstevel@tonic-gate 		}
4087c478bd9Sstevel@tonic-gate 		longjmp(env, 1);
4091ee2e5faSnakanon 		/*NOTREACHED*/
4107c478bd9Sstevel@tonic-gate 	case RETURN:
4117c478bd9Sstevel@tonic-gate 		if (a[0] != NULL) {
4127c478bd9Sstevel@tonic-gate 			y = execute(a[0]);
4137c478bd9Sstevel@tonic-gate 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
4141ee2e5faSnakanon 				(void) setsval(fp->retval, getsval(y));
4157c478bd9Sstevel@tonic-gate 				fp->retval->fval = getfval(y);
4167c478bd9Sstevel@tonic-gate 				fp->retval->tval |= NUM;
4171ee2e5faSnakanon 			} else if (y->tval & STR)
4181ee2e5faSnakanon 				(void) setsval(fp->retval, getsval(y));
4197c478bd9Sstevel@tonic-gate 			else if (y->tval & NUM)
4201ee2e5faSnakanon 				(void) setfval(fp->retval, getfval(y));
421*3ee4fc2aSCody Peter Mello 			else		/* can't happen */
422*3ee4fc2aSCody Peter Mello 				FATAL("bad type variable %d", y->tval);
423*3ee4fc2aSCody Peter Mello 			tempfree(y);
4247c478bd9Sstevel@tonic-gate 		}
4251ee2e5faSnakanon 		return (jret);
4267c478bd9Sstevel@tonic-gate 	case NEXT:
4271ee2e5faSnakanon 		return (jnext);
428*3ee4fc2aSCody Peter Mello 	case NEXTFILE:
429*3ee4fc2aSCody Peter Mello 		nextfile();
430*3ee4fc2aSCody Peter Mello 		return (jnextfile);
4317c478bd9Sstevel@tonic-gate 	case BREAK:
4321ee2e5faSnakanon 		return (jbreak);
4337c478bd9Sstevel@tonic-gate 	case CONTINUE:
4341ee2e5faSnakanon 		return (jcont);
4357c478bd9Sstevel@tonic-gate 	default:	/* can't happen */
436*3ee4fc2aSCody Peter Mello 		FATAL("illegal jump type %d", n);
4377c478bd9Sstevel@tonic-gate 	}
4381ee2e5faSnakanon 	/*NOTREACHED*/
4391ee2e5faSnakanon 	return (NULL);
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
4421ee2e5faSnakanon Cell *
awkgetline(Node ** a,int n)443*3ee4fc2aSCody Peter Mello awkgetline(Node **a, int n)	/* get next line from specific input */
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate 	/* a[0] is variable, a[1] is operator, a[2] is filename */
446*3ee4fc2aSCody Peter Mello 	Cell *r, *x;
4477c478bd9Sstevel@tonic-gate 	FILE *fp;
448*3ee4fc2aSCody Peter Mello 	char *buf;
449*3ee4fc2aSCody Peter Mello 	size_t bufsize = recsize;
450*3ee4fc2aSCody Peter Mello 	int mode;
451*3ee4fc2aSCody Peter Mello 
452*3ee4fc2aSCody Peter Mello 	if ((buf = (char *)malloc(bufsize)) == NULL)
453*3ee4fc2aSCody Peter Mello 		FATAL("out of memory in getline");
4547c478bd9Sstevel@tonic-gate 
4551ee2e5faSnakanon 	(void) fflush(stdout);	/* in case someone is waiting for a prompt */
456*3ee4fc2aSCody Peter Mello 	r = gettemp();
4577c478bd9Sstevel@tonic-gate 	if (a[1] != NULL) {		/* getline < file */
4587c478bd9Sstevel@tonic-gate 		x = execute(a[2]);		/* filename */
459*3ee4fc2aSCody Peter Mello 		mode = ptoi(a[1]);
460*3ee4fc2aSCody Peter Mello 		if (mode == '|')	/* input pipe */
461*3ee4fc2aSCody Peter Mello 			mode = LE;	/* arbitrary flag */
462*3ee4fc2aSCody Peter Mello 		fp = openfile(mode, getsval(x));
463*3ee4fc2aSCody Peter Mello 		tempfree(x);
4647c478bd9Sstevel@tonic-gate 		if (fp == NULL)
4657c478bd9Sstevel@tonic-gate 			n = -1;
4667c478bd9Sstevel@tonic-gate 		else
467*3ee4fc2aSCody Peter Mello 			n = readrec(&buf, &bufsize, fp);
468*3ee4fc2aSCody Peter Mello 		/*LINTED if*/
469*3ee4fc2aSCody Peter Mello 		if (n <= 0) {
470*3ee4fc2aSCody Peter Mello 			;
471*3ee4fc2aSCody Peter Mello 		} else if (a[0] != NULL) {	/* getline var <file */
472*3ee4fc2aSCody Peter Mello 			x = execute(a[0]);
473*3ee4fc2aSCody Peter Mello 			(void) setsval(x, buf);
474*3ee4fc2aSCody Peter Mello 			tempfree(x);
475*3ee4fc2aSCody Peter Mello 		} else {			/* getline <file */
476*3ee4fc2aSCody Peter Mello 			(void) setsval(recloc, buf);
477*3ee4fc2aSCody Peter Mello 			if (is_number(recloc->sval)) {
478*3ee4fc2aSCody Peter Mello 				recloc->fval = atof(recloc->sval);
479*3ee4fc2aSCody Peter Mello 				recloc->tval |= NUM;
4801ee2e5faSnakanon 			}
4817c478bd9Sstevel@tonic-gate 		}
4827c478bd9Sstevel@tonic-gate 	} else {			/* bare getline; use current input */
4837c478bd9Sstevel@tonic-gate 		if (a[0] == NULL)	/* getline */
484*3ee4fc2aSCody Peter Mello 			n = getrec(&record, &recsize, 1);
4857c478bd9Sstevel@tonic-gate 		else {			/* getline var */
486*3ee4fc2aSCody Peter Mello 			n = getrec(&buf, &bufsize, 0);
487*3ee4fc2aSCody Peter Mello 			x = execute(a[0]);
488*3ee4fc2aSCody Peter Mello 			(void) setsval(x, buf);
489*3ee4fc2aSCody Peter Mello 			tempfree(x);
4907c478bd9Sstevel@tonic-gate 		}
4917c478bd9Sstevel@tonic-gate 	}
4921ee2e5faSnakanon 	(void) setfval(r, (Awkfloat)n);
493*3ee4fc2aSCody Peter Mello 	free(buf);
4941ee2e5faSnakanon 	return (r);
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate 
4971ee2e5faSnakanon /*ARGSUSED*/
4981ee2e5faSnakanon Cell *
getnf(Node ** a,int n)499*3ee4fc2aSCody Peter Mello getnf(Node **a, int n)	/* get NF */
5007c478bd9Sstevel@tonic-gate {
5017c478bd9Sstevel@tonic-gate 	if (donefld == 0)
5027c478bd9Sstevel@tonic-gate 		fldbld();
5031ee2e5faSnakanon 	return ((Cell *)a[0]);
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate 
5061ee2e5faSnakanon /*ARGSUSED*/
5071ee2e5faSnakanon Cell *
array(Node ** a,int n)508*3ee4fc2aSCody Peter Mello array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
5097c478bd9Sstevel@tonic-gate {
510*3ee4fc2aSCody Peter Mello 	Cell *x, *y, *z;
511*3ee4fc2aSCody Peter Mello 	char *s;
512*3ee4fc2aSCody Peter Mello 	Node *np;
513*3ee4fc2aSCody Peter Mello 	char *buf;
514*3ee4fc2aSCody Peter Mello 	size_t bufsz = recsize;
515*3ee4fc2aSCody Peter Mello 	size_t tlen = 0, len, nsub;
516*3ee4fc2aSCody Peter Mello 
517*3ee4fc2aSCody Peter Mello 	if ((buf = (char *)malloc(bufsz)) == NULL)
518*3ee4fc2aSCody Peter Mello 		FATAL("out of memory in array");
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	x = execute(a[0]);	/* Cell* for symbol table */
5211ee2e5faSnakanon 	buf[0] = '\0';
522*3ee4fc2aSCody Peter Mello 	for (np = a[1]; np != NULL; np = np->nnext) {
5237c478bd9Sstevel@tonic-gate 		y = execute(np);	/* subscript */
5247c478bd9Sstevel@tonic-gate 		s = getsval(y);
525*3ee4fc2aSCody Peter Mello 		len = strlen(s);
526*3ee4fc2aSCody Peter Mello 		nsub = strlen(getsval(subseploc));
527*3ee4fc2aSCody Peter Mello 		(void) adjbuf(&buf, &bufsz, tlen + len + nsub + 1,
528*3ee4fc2aSCody Peter Mello 		    recsize, 0, "array");
5291ee2e5faSnakanon 		(void) memcpy(&buf[tlen], s, len);
5301ee2e5faSnakanon 		tlen += len;
5311ee2e5faSnakanon 		if (np->nnext) {
532*3ee4fc2aSCody Peter Mello 			(void) memcpy(&buf[tlen], *SUBSEP, nsub);
533*3ee4fc2aSCody Peter Mello 			tlen += nsub;
5341ee2e5faSnakanon 		}
5351ee2e5faSnakanon 		buf[tlen] = '\0';
536*3ee4fc2aSCody Peter Mello 		tempfree(y);
5377c478bd9Sstevel@tonic-gate 	}
5387c478bd9Sstevel@tonic-gate 	if (!isarr(x)) {
539*3ee4fc2aSCody Peter Mello 		dprintf(("making %s into an array\n", NN(x->nval)));
5407c478bd9Sstevel@tonic-gate 		if (freeable(x))
5417c478bd9Sstevel@tonic-gate 			xfree(x->sval);
5427c478bd9Sstevel@tonic-gate 		x->tval &= ~(STR|NUM|DONTFREE);
5437c478bd9Sstevel@tonic-gate 		x->tval |= ARR;
544*3ee4fc2aSCody Peter Mello 		x->sval = (char *)makesymtab(NSYMTAB);
5457c478bd9Sstevel@tonic-gate 	}
5461ee2e5faSnakanon 	/*LINTED align*/
547*3ee4fc2aSCody Peter Mello 	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *)x->sval);
5487c478bd9Sstevel@tonic-gate 	z->ctype = OCELL;
5497c478bd9Sstevel@tonic-gate 	z->csub = CVAR;
550*3ee4fc2aSCody Peter Mello 	tempfree(x);
5511ee2e5faSnakanon 	free(buf);
5521ee2e5faSnakanon 	return (z);
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate 
5551ee2e5faSnakanon /*ARGSUSED*/
5561ee2e5faSnakanon Cell *
awkdelete(Node ** a,int n)557*3ee4fc2aSCody Peter Mello awkdelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
5587c478bd9Sstevel@tonic-gate {
5597c478bd9Sstevel@tonic-gate 	Cell *x, *y;
5607c478bd9Sstevel@tonic-gate 	Node *np;
561*3ee4fc2aSCody Peter Mello 	char *s;
562*3ee4fc2aSCody Peter Mello 	size_t nsub;
563*3ee4fc2aSCody Peter Mello 	size_t tlen = 0, len;
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	x = execute(a[0]);	/* Cell* for symbol table */
566*3ee4fc2aSCody Peter Mello 	if (x == symtabloc) {
567*3ee4fc2aSCody Peter Mello 		FATAL("cannot delete SYMTAB or its elements");
568*3ee4fc2aSCody Peter Mello 	}
569*3ee4fc2aSCody Peter Mello 	if (!isarr(x)) {
570*3ee4fc2aSCody Peter Mello 		dprintf(("making %s into an array\n", x->nval));
571*3ee4fc2aSCody Peter Mello 		if (freeable(x))
572*3ee4fc2aSCody Peter Mello 			xfree(x->sval);
573*3ee4fc2aSCody Peter Mello 		x->tval &= ~(STR|NUM|DONTFREE);
574*3ee4fc2aSCody Peter Mello 		x->tval |= ARR;
575*3ee4fc2aSCody Peter Mello 		x->sval = (char *)makesymtab(NSYMTAB);
576*3ee4fc2aSCody Peter Mello 	}
577*3ee4fc2aSCody Peter Mello 	if (a[1] == NULL) {	/* delete the elements, not the table */
578*3ee4fc2aSCody Peter Mello 		freesymtab(x);
579*3ee4fc2aSCody Peter Mello 		x->tval &= ~STR;
580*3ee4fc2aSCody Peter Mello 		x->tval |= ARR;
581*3ee4fc2aSCody Peter Mello 		x->sval = (char *)makesymtab(NSYMTAB);
582*3ee4fc2aSCody Peter Mello 	} else {
583*3ee4fc2aSCody Peter Mello 		size_t bufsz = recsize;
584*3ee4fc2aSCody Peter Mello 		char *buf;
585*3ee4fc2aSCody Peter Mello 		if ((buf = (char *)malloc(bufsz)) == NULL)
586*3ee4fc2aSCody Peter Mello 			FATAL("out of memory in awkdelete");
587*3ee4fc2aSCody Peter Mello 		buf[0] = '\0';
588*3ee4fc2aSCody Peter Mello 		for (np = a[1]; np != NULL; np = np->nnext) {
589*3ee4fc2aSCody Peter Mello 			y = execute(np);	/* subscript */
590*3ee4fc2aSCody Peter Mello 			s = getsval(y);
591*3ee4fc2aSCody Peter Mello 			len = strlen(s);
592*3ee4fc2aSCody Peter Mello 			nsub = strlen(getsval(subseploc));
593*3ee4fc2aSCody Peter Mello 			(void) adjbuf(&buf, &bufsz, tlen + len + nsub + 1,
594*3ee4fc2aSCody Peter Mello 			    recsize, 0, "awkdelete");
595*3ee4fc2aSCody Peter Mello 			(void) memcpy(&buf[tlen], s, len);
596*3ee4fc2aSCody Peter Mello 			tlen += len;
597*3ee4fc2aSCody Peter Mello 			if (np->nnext) {
598*3ee4fc2aSCody Peter Mello 				(void) memcpy(&buf[tlen], *SUBSEP, nsub);
599*3ee4fc2aSCody Peter Mello 				tlen += nsub;
600*3ee4fc2aSCody Peter Mello 			}
601*3ee4fc2aSCody Peter Mello 			buf[tlen] = '\0';
602*3ee4fc2aSCody Peter Mello 			tempfree(y);
6031ee2e5faSnakanon 		}
604*3ee4fc2aSCody Peter Mello 		freeelem(x, buf);
605*3ee4fc2aSCody Peter Mello 		free(buf);
6067c478bd9Sstevel@tonic-gate 	}
607*3ee4fc2aSCody Peter Mello 	tempfree(x);
608*3ee4fc2aSCody Peter Mello 	return (True);
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate 
6111ee2e5faSnakanon /*ARGSUSED*/
6121ee2e5faSnakanon Cell *
intest(Node ** a,int n)613*3ee4fc2aSCody Peter Mello intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
6147c478bd9Sstevel@tonic-gate {
615*3ee4fc2aSCody Peter Mello 	Cell *x, *ap, *k;
6167c478bd9Sstevel@tonic-gate 	Node *p;
617*3ee4fc2aSCody Peter Mello 	char *buf;
618*3ee4fc2aSCody Peter Mello 	char *s;
619*3ee4fc2aSCody Peter Mello 	size_t bufsz = recsize;
620*3ee4fc2aSCody Peter Mello 	size_t nsub;
621*3ee4fc2aSCody Peter Mello 	size_t tlen = 0, len;
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	ap = execute(a[1]);	/* array name */
624*3ee4fc2aSCody Peter Mello 	if (!isarr(ap)) {
625*3ee4fc2aSCody Peter Mello 		dprintf(("making %s into an array\n", ap->nval));
626*3ee4fc2aSCody Peter Mello 		if (freeable(ap))
627*3ee4fc2aSCody Peter Mello 			xfree(ap->sval);
628*3ee4fc2aSCody Peter Mello 		ap->tval &= ~(STR|NUM|DONTFREE);
629*3ee4fc2aSCody Peter Mello 		ap->tval |= ARR;
630*3ee4fc2aSCody Peter Mello 		ap->sval = (char *)makesymtab(NSYMTAB);
631*3ee4fc2aSCody Peter Mello 	}
632*3ee4fc2aSCody Peter Mello 	if ((buf = (char *)malloc(bufsz)) == NULL) {
633*3ee4fc2aSCody Peter Mello 		FATAL("out of memory in intest");
634*3ee4fc2aSCody Peter Mello 	}
635*3ee4fc2aSCody Peter Mello 	buf[0] = '\0';
636*3ee4fc2aSCody Peter Mello 	for (p = a[0]; p != NULL; p = p->nnext) {
6377c478bd9Sstevel@tonic-gate 		x = execute(p);	/* expr */
6387c478bd9Sstevel@tonic-gate 		s = getsval(x);
639*3ee4fc2aSCody Peter Mello 		len = strlen(s);
640*3ee4fc2aSCody Peter Mello 		nsub = strlen(getsval(subseploc));
641*3ee4fc2aSCody Peter Mello 		(void) adjbuf(&buf, &bufsz, tlen + len + nsub + 1,
642*3ee4fc2aSCody Peter Mello 		    recsize, 0, "intest");
6431ee2e5faSnakanon 		(void) memcpy(&buf[tlen], s, len);
6441ee2e5faSnakanon 		tlen += len;
645*3ee4fc2aSCody Peter Mello 		tempfree(x);
6461ee2e5faSnakanon 		if (p->nnext) {
647*3ee4fc2aSCody Peter Mello 			(void) memcpy(&buf[tlen], *SUBSEP, nsub);
648*3ee4fc2aSCody Peter Mello 			tlen += nsub;
6491ee2e5faSnakanon 		}
6501ee2e5faSnakanon 		buf[tlen] = '\0';
6517c478bd9Sstevel@tonic-gate 	}
6521ee2e5faSnakanon 	/*LINTED align*/
6531ee2e5faSnakanon 	k = lookup(buf, (Array *)ap->sval);
654*3ee4fc2aSCody Peter Mello 	tempfree(ap);
6551ee2e5faSnakanon 	free(buf);
6567c478bd9Sstevel@tonic-gate 	if (k == NULL)
657*3ee4fc2aSCody Peter Mello 		return (False);
6587c478bd9Sstevel@tonic-gate 	else
659*3ee4fc2aSCody Peter Mello 		return (True);
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 
6631ee2e5faSnakanon Cell *
matchop(Node ** a,int n)664*3ee4fc2aSCody Peter Mello matchop(Node **a, int n)	/* ~ and match() */
6657c478bd9Sstevel@tonic-gate {
666*3ee4fc2aSCody Peter Mello 	Cell *x, *y;
667*3ee4fc2aSCody Peter Mello 	char *s, *t;
668*3ee4fc2aSCody Peter Mello 	int i;
6697c478bd9Sstevel@tonic-gate 	fa *pfa;
670*3ee4fc2aSCody Peter Mello 	int (*mf)(fa *, const char *) = match, mode = 0;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	if (n == MATCHFCN) {
6737c478bd9Sstevel@tonic-gate 		mf = pmatch;
6747c478bd9Sstevel@tonic-gate 		mode = 1;
6757c478bd9Sstevel@tonic-gate 	}
676*3ee4fc2aSCody Peter Mello 	x = execute(a[1]);	/* a[1] = target text */
6777c478bd9Sstevel@tonic-gate 	s = getsval(x);
678*3ee4fc2aSCody Peter Mello 	if (a[0] == NULL)	/* a[1] == 0: already-compiled reg expr */
679*3ee4fc2aSCody Peter Mello 		i = (*mf)((fa *)a[2], s);
6807c478bd9Sstevel@tonic-gate 	else {
681*3ee4fc2aSCody Peter Mello 		y = execute(a[2]);	/* a[2] = regular expr */
6827c478bd9Sstevel@tonic-gate 		t = getsval(y);
6837c478bd9Sstevel@tonic-gate 		pfa = makedfa(t, mode);
6847c478bd9Sstevel@tonic-gate 		i = (*mf)(pfa, s);
685*3ee4fc2aSCody Peter Mello 		tempfree(y);
6867c478bd9Sstevel@tonic-gate 	}
687*3ee4fc2aSCody Peter Mello 	tempfree(x);
6887c478bd9Sstevel@tonic-gate 	if (n == MATCHFCN) {
6897c478bd9Sstevel@tonic-gate 		int start = patbeg - s + 1;
6907c478bd9Sstevel@tonic-gate 		if (patlen < 0)
6917c478bd9Sstevel@tonic-gate 			start = 0;
6921ee2e5faSnakanon 		(void) setfval(rstartloc, (Awkfloat)start);
6931ee2e5faSnakanon 		(void) setfval(rlengthloc, (Awkfloat)patlen);
694*3ee4fc2aSCody Peter Mello 		x = gettemp();
6957c478bd9Sstevel@tonic-gate 		x->tval = NUM;
6967c478bd9Sstevel@tonic-gate 		x->fval = start;
6971ee2e5faSnakanon 		return (x);
698*3ee4fc2aSCody Peter Mello 	} else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
699*3ee4fc2aSCody Peter Mello 		return (True);
7007c478bd9Sstevel@tonic-gate 	else
701*3ee4fc2aSCody Peter Mello 		return (False);
7027c478bd9Sstevel@tonic-gate }
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 
7051ee2e5faSnakanon Cell *
boolop(Node ** a,int n)706*3ee4fc2aSCody Peter Mello boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
7077c478bd9Sstevel@tonic-gate {
708*3ee4fc2aSCody Peter Mello 	Cell *x, *y;
709*3ee4fc2aSCody Peter Mello 	int i;
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
7127c478bd9Sstevel@tonic-gate 	i = istrue(x);
713*3ee4fc2aSCody Peter Mello 	tempfree(x);
7147c478bd9Sstevel@tonic-gate 	switch (n) {
7157c478bd9Sstevel@tonic-gate 	case BOR:
7161ee2e5faSnakanon 		if (i)
717*3ee4fc2aSCody Peter Mello 			return (True);
7187c478bd9Sstevel@tonic-gate 		y = execute(a[1]);
7197c478bd9Sstevel@tonic-gate 		i = istrue(y);
720*3ee4fc2aSCody Peter Mello 		tempfree(y);
721*3ee4fc2aSCody Peter Mello 		return (i ? True : False);
7227c478bd9Sstevel@tonic-gate 	case AND:
7231ee2e5faSnakanon 		if (!i)
724*3ee4fc2aSCody Peter Mello 			return (False);
7257c478bd9Sstevel@tonic-gate 		y = execute(a[1]);
7267c478bd9Sstevel@tonic-gate 		i = istrue(y);
727*3ee4fc2aSCody Peter Mello 		tempfree(y);
728*3ee4fc2aSCody Peter Mello 		return (i ? True : False);
7297c478bd9Sstevel@tonic-gate 	case NOT:
730*3ee4fc2aSCody Peter Mello 		return (i ? False : True);
7317c478bd9Sstevel@tonic-gate 	default:	/* can't happen */
732*3ee4fc2aSCody Peter Mello 		FATAL("unknown boolean operator %d", n);
7337c478bd9Sstevel@tonic-gate 	}
7347c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
7351ee2e5faSnakanon 	return (NULL);
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate 
7381ee2e5faSnakanon Cell *
relop(Node ** a,int n)739*3ee4fc2aSCody Peter Mello relop(Node **a, int n)	/* a[0] < a[1], etc. */
7407c478bd9Sstevel@tonic-gate {
741*3ee4fc2aSCody Peter Mello 	int i;
742*3ee4fc2aSCody Peter Mello 	Cell *x, *y;
7437c478bd9Sstevel@tonic-gate 	Awkfloat j;
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
7467c478bd9Sstevel@tonic-gate 	y = execute(a[1]);
7477c478bd9Sstevel@tonic-gate 	if (x->tval&NUM && y->tval&NUM) {
7487c478bd9Sstevel@tonic-gate 		j = x->fval - y->fval;
7491ee2e5faSnakanon 		i = j < 0 ? -1: (j > 0 ? 1: 0);
7507c478bd9Sstevel@tonic-gate 	} else {
751*3ee4fc2aSCody Peter Mello 		i = strcmp(getsval(x), getsval(y));
7527c478bd9Sstevel@tonic-gate 	}
753*3ee4fc2aSCody Peter Mello 	tempfree(x);
754*3ee4fc2aSCody Peter Mello 	tempfree(y);
7557c478bd9Sstevel@tonic-gate 	switch (n) {
756*3ee4fc2aSCody Peter Mello 	case LT:	return (i < 0 ? True : False);
757*3ee4fc2aSCody Peter Mello 	case LE:	return (i <= 0 ? True : False);
758*3ee4fc2aSCody Peter Mello 	case NE:	return (i != 0 ? True : False);
759*3ee4fc2aSCody Peter Mello 	case EQ:	return (i == 0 ? True : False);
760*3ee4fc2aSCody Peter Mello 	case GE:	return (i >= 0 ? True : False);
761*3ee4fc2aSCody Peter Mello 	case GT:	return (i > 0 ? True : False);
7627c478bd9Sstevel@tonic-gate 	default:	/* can't happen */
763*3ee4fc2aSCody Peter Mello 		FATAL("unknown relational operator %d", n);
7647c478bd9Sstevel@tonic-gate 	}
7657c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
766*3ee4fc2aSCody Peter Mello 	return (False);
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate 
7691ee2e5faSnakanon static void
tfree(Cell * a)770*3ee4fc2aSCody Peter Mello tfree(Cell *a)	/* free a tempcell */
7717c478bd9Sstevel@tonic-gate {
772*3ee4fc2aSCody Peter Mello 	if (freeable(a)) {
773*3ee4fc2aSCody Peter Mello 		dprintf(("freeing %s %s %o\n",
774*3ee4fc2aSCody Peter Mello 		    NN(a->nval), NN(a->sval), a->tval));
7757c478bd9Sstevel@tonic-gate 		xfree(a->sval);
776*3ee4fc2aSCody Peter Mello 	}
7777c478bd9Sstevel@tonic-gate 	if (a == tmps)
778*3ee4fc2aSCody Peter Mello 		FATAL("tempcell list is curdled");
7797c478bd9Sstevel@tonic-gate 	a->cnext = tmps;
7807c478bd9Sstevel@tonic-gate 	tmps = a;
7817c478bd9Sstevel@tonic-gate }
7827c478bd9Sstevel@tonic-gate 
7831ee2e5faSnakanon static Cell *
gettemp(void)784*3ee4fc2aSCody Peter Mello gettemp(void)	/* get a tempcell */
7851ee2e5faSnakanon {
7861ee2e5faSnakanon 	int i;
787*3ee4fc2aSCody Peter Mello 	Cell *x;
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	if (!tmps) {
7901ee2e5faSnakanon 		tmps = (Cell *)calloc(100, sizeof (Cell));
7917c478bd9Sstevel@tonic-gate 		if (!tmps)
792*3ee4fc2aSCody Peter Mello 			FATAL("out of space for temporaries");
7931ee2e5faSnakanon 		for (i = 1; i < 100; i++)
7947c478bd9Sstevel@tonic-gate 			tmps[i-1].cnext = &tmps[i];
795*3ee4fc2aSCody Peter Mello 		tmps[i-1].cnext = NULL;
7967c478bd9Sstevel@tonic-gate 	}
7977c478bd9Sstevel@tonic-gate 	x = tmps;
7987c478bd9Sstevel@tonic-gate 	tmps = x->cnext;
7997c478bd9Sstevel@tonic-gate 	*x = tempcell;
800*3ee4fc2aSCody Peter Mello 	dprintf(("gtemp %.8s %06lo\n", NN(x->nval), (ulong_t)x));
8011ee2e5faSnakanon 	return (x);
8027c478bd9Sstevel@tonic-gate }
8037c478bd9Sstevel@tonic-gate 
8041ee2e5faSnakanon /*ARGSUSED*/
8051ee2e5faSnakanon Cell *
indirect(Node ** a,int n)806*3ee4fc2aSCody Peter Mello indirect(Node **a, int n)	/* $( a[0] ) */
8077c478bd9Sstevel@tonic-gate {
808*3ee4fc2aSCody Peter Mello 	Awkfloat val;
809*3ee4fc2aSCody Peter Mello 	Cell *x;
810*3ee4fc2aSCody Peter Mello 	int m;
811*3ee4fc2aSCody Peter Mello 	char *s;
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
814*3ee4fc2aSCody Peter Mello 
815*3ee4fc2aSCody Peter Mello 	/* freebsd: defend against super large field numbers */
816*3ee4fc2aSCody Peter Mello 	val = getfval(x);
817*3ee4fc2aSCody Peter Mello 	if ((Awkfloat)INT_MAX < val)
818*3ee4fc2aSCody Peter Mello 		FATAL("trying to access out of range field %s", x->nval);
819*3ee4fc2aSCody Peter Mello 	m = (int)val;
8201ee2e5faSnakanon 	if (m == 0 && !is_number(s = getsval(x)))	/* suspicion! */
821*3ee4fc2aSCody Peter Mello 		FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
822*3ee4fc2aSCody Peter Mello 		/* BUG: can x->nval ever be null??? */
823*3ee4fc2aSCody Peter Mello 	tempfree(x);
8247c478bd9Sstevel@tonic-gate 	x = fieldadr(m);
825*3ee4fc2aSCody Peter Mello 	x->ctype = OCELL;	/* BUG?  why are these needed? */
8267c478bd9Sstevel@tonic-gate 	x->csub = CFLD;
8271ee2e5faSnakanon 	return (x);
8287c478bd9Sstevel@tonic-gate }
8297c478bd9Sstevel@tonic-gate 
8301ee2e5faSnakanon /*ARGSUSED*/
8311ee2e5faSnakanon Cell *
substr(Node ** a,int nnn)832*3ee4fc2aSCody Peter Mello substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
8337c478bd9Sstevel@tonic-gate {
834*3ee4fc2aSCody Peter Mello 	int k, m, n;
835*3ee4fc2aSCody Peter Mello 	char *s;
8367c478bd9Sstevel@tonic-gate 	int temp;
837*3ee4fc2aSCody Peter Mello 	Cell *x, *y, *z = NULL;
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
8407c478bd9Sstevel@tonic-gate 	y = execute(a[1]);
841*3ee4fc2aSCody Peter Mello 	if (a[2] != NULL)
8427c478bd9Sstevel@tonic-gate 		z = execute(a[2]);
8437c478bd9Sstevel@tonic-gate 	s = getsval(x);
844*3ee4fc2aSCody Peter Mello 	k = strlen(s) + 1;
8457c478bd9Sstevel@tonic-gate 	if (k <= 1) {
846*3ee4fc2aSCody Peter Mello 		tempfree(x);
847*3ee4fc2aSCody Peter Mello 		tempfree(y);
848*3ee4fc2aSCody Peter Mello 		if (a[2] != NULL) {
849*3ee4fc2aSCody Peter Mello 			tempfree(z);
850*3ee4fc2aSCody Peter Mello 		}
851*3ee4fc2aSCody Peter Mello 		x = gettemp();
852*3ee4fc2aSCody Peter Mello 		(void) setsval(x, "");
8531ee2e5faSnakanon 		return (x);
8547c478bd9Sstevel@tonic-gate 	}
85512809310Snakanon 	m = (int)getfval(y);
8567c478bd9Sstevel@tonic-gate 	if (m <= 0)
8577c478bd9Sstevel@tonic-gate 		m = 1;
8587c478bd9Sstevel@tonic-gate 	else if (m > k)
8597c478bd9Sstevel@tonic-gate 		m = k;
860*3ee4fc2aSCody Peter Mello 	tempfree(y);
861*3ee4fc2aSCody Peter Mello 	if (a[2] != NULL) {
86212809310Snakanon 		n = (int)getfval(z);
863*3ee4fc2aSCody Peter Mello 		tempfree(z);
8647c478bd9Sstevel@tonic-gate 	} else
8657c478bd9Sstevel@tonic-gate 		n = k - 1;
8667c478bd9Sstevel@tonic-gate 	if (n < 0)
8677c478bd9Sstevel@tonic-gate 		n = 0;
8687c478bd9Sstevel@tonic-gate 	else if (n > k - m)
8697c478bd9Sstevel@tonic-gate 		n = k - m;
8701ee2e5faSnakanon 	dprintf(("substr: m=%d, n=%d, s=%s\n", m, n, s));
871*3ee4fc2aSCody Peter Mello 	y = gettemp();
8721ee2e5faSnakanon 	temp = s[n + m - 1];	/* with thanks to John Linderman */
8731ee2e5faSnakanon 	s[n + m - 1] = '\0';
8741ee2e5faSnakanon 	(void) setsval(y, s + m - 1);
8751ee2e5faSnakanon 	s[n + m - 1] = temp;
876*3ee4fc2aSCody Peter Mello 	tempfree(x);
8771ee2e5faSnakanon 	return (y);
8787c478bd9Sstevel@tonic-gate }
8797c478bd9Sstevel@tonic-gate 
8801ee2e5faSnakanon /*ARGSUSED*/
8811ee2e5faSnakanon Cell *
sindex(Node ** a,int nnn)882*3ee4fc2aSCody Peter Mello sindex(Node **a, int nnn)		/* index(a[0], a[1]) */
8837c478bd9Sstevel@tonic-gate {
884*3ee4fc2aSCody Peter Mello 	Cell *x, *y, *z;
885*3ee4fc2aSCody Peter Mello 	char *s1, *s2, *p1, *p2, *q;
8867c478bd9Sstevel@tonic-gate 	Awkfloat v = 0.0;
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
8897c478bd9Sstevel@tonic-gate 	s1 = getsval(x);
8907c478bd9Sstevel@tonic-gate 	y = execute(a[1]);
8917c478bd9Sstevel@tonic-gate 	s2 = getsval(y);
8927c478bd9Sstevel@tonic-gate 
893*3ee4fc2aSCody Peter Mello 	z = gettemp();
8947c478bd9Sstevel@tonic-gate 	for (p1 = s1; *p1 != '\0'; p1++) {
8951ee2e5faSnakanon 		for (q = p1, p2 = s2; *p2 != '\0' && *q == *p2; q++, p2++)
8967c478bd9Sstevel@tonic-gate 			;
8977c478bd9Sstevel@tonic-gate 		if (*p2 == '\0') {
8987c478bd9Sstevel@tonic-gate 			v = (Awkfloat) (p1 - s1 + 1);	/* origin 1 */
8997c478bd9Sstevel@tonic-gate 			break;
9007c478bd9Sstevel@tonic-gate 		}
9017c478bd9Sstevel@tonic-gate 	}
902*3ee4fc2aSCody Peter Mello 	tempfree(x);
903*3ee4fc2aSCody Peter Mello 	tempfree(y);
9041ee2e5faSnakanon 	(void) setfval(z, v);
9051ee2e5faSnakanon 	return (z);
9067c478bd9Sstevel@tonic-gate }
9077c478bd9Sstevel@tonic-gate 
908*3ee4fc2aSCody Peter Mello #define	MAXNUMSIZE	50
909*3ee4fc2aSCody Peter Mello 
910*3ee4fc2aSCody Peter Mello /* printf-like conversions */
911*3ee4fc2aSCody Peter Mello int
format(char ** pbuf,int * pbufsize,const char * s,Node * a)912*3ee4fc2aSCody Peter Mello format(char **pbuf, int *pbufsize, const char *s, Node *a)
9137c478bd9Sstevel@tonic-gate {
914*3ee4fc2aSCody Peter Mello 	char *fmt;
915*3ee4fc2aSCody Peter Mello 	const char *os;
916*3ee4fc2aSCody Peter Mello 	Cell *x;
917*3ee4fc2aSCody Peter Mello 	int flag = 0, n, len;
918*3ee4fc2aSCody Peter Mello 	int fmtwd; /* format width */
919*3ee4fc2aSCody Peter Mello 	char *buf = *pbuf;
920*3ee4fc2aSCody Peter Mello 	size_t bufsize = *pbufsize;
921*3ee4fc2aSCody Peter Mello 	size_t fmtsz = recsize;
922*3ee4fc2aSCody Peter Mello 	size_t cnt, tcnt, ret;
923*3ee4fc2aSCody Peter Mello 
9247c478bd9Sstevel@tonic-gate 	os = s;
9251ee2e5faSnakanon 	cnt = 0;
926*3ee4fc2aSCody Peter Mello 	if ((fmt = (char *)malloc(fmtsz)) == NULL)
927*3ee4fc2aSCody Peter Mello 		FATAL("out of memory in format()");
9287c478bd9Sstevel@tonic-gate 	while (*s) {
9297c478bd9Sstevel@tonic-gate 		if (*s != '%') {
9301ee2e5faSnakanon 			expand_buf(&buf, &bufsize, cnt);
9311ee2e5faSnakanon 			buf[cnt++] = *s++;
9327c478bd9Sstevel@tonic-gate 			continue;
9337c478bd9Sstevel@tonic-gate 		}
9347c478bd9Sstevel@tonic-gate 		if (*(s+1) == '%') {
9351ee2e5faSnakanon 			expand_buf(&buf, &bufsize, cnt);
9361ee2e5faSnakanon 			buf[cnt++] = '%';
9377c478bd9Sstevel@tonic-gate 			s += 2;
9387c478bd9Sstevel@tonic-gate 			continue;
9397c478bd9Sstevel@tonic-gate 		}
940*3ee4fc2aSCody Peter Mello 		/*
941*3ee4fc2aSCody Peter Mello 		 * have to be real careful in case this is a huge number,
942*3ee4fc2aSCody Peter Mello 		 * eg, "%100000d".
943*3ee4fc2aSCody Peter Mello 		 */
944*3ee4fc2aSCody Peter Mello 		fmtwd = atoi(s+1);
945*3ee4fc2aSCody Peter Mello 		if (fmtwd < 0)
946*3ee4fc2aSCody Peter Mello 			fmtwd = -fmtwd;
9471ee2e5faSnakanon 		for (tcnt = 0; ; s++) {
948*3ee4fc2aSCody Peter Mello 			expand_buf(&fmt, &fmtsz, tcnt);
9491ee2e5faSnakanon 			fmt[tcnt++] = *s;
9501ee2e5faSnakanon 			if (*s == '\0')
9511ee2e5faSnakanon 				break;
952*3ee4fc2aSCody Peter Mello 			if (isalpha((uschar)*s) &&
953*3ee4fc2aSCody Peter Mello 			    *s != 'l' && *s != 'h' && *s != 'L')
9547c478bd9Sstevel@tonic-gate 				break;	/* the ansi panoply */
955*3ee4fc2aSCody Peter Mello 			if (*s == '$') {
956*3ee4fc2aSCody Peter Mello 				FATAL("'$' not permitted in awk formats");
957*3ee4fc2aSCody Peter Mello 			}
9587c478bd9Sstevel@tonic-gate 			if (*s == '*') {
9597c478bd9Sstevel@tonic-gate 				if (a == NULL) {
960*3ee4fc2aSCody Peter Mello 					FATAL("not enough args in printf(%s) "
961*3ee4fc2aSCody Peter Mello 					    "or sprintf(%s)", os, os);
9627c478bd9Sstevel@tonic-gate 				}
9637c478bd9Sstevel@tonic-gate 				x = execute(a);
9647c478bd9Sstevel@tonic-gate 				a = a->nnext;
9651ee2e5faSnakanon 				tcnt--;
966*3ee4fc2aSCody Peter Mello 				expand_buf(&fmt, &fmtsz, tcnt + 12);
967*3ee4fc2aSCody Peter Mello 				fmtwd = (int)getfval(x);
968*3ee4fc2aSCody Peter Mello 				ret = sprintf(&fmt[tcnt], "%d", fmtwd);
969*3ee4fc2aSCody Peter Mello 				if (fmtwd < 0)
970*3ee4fc2aSCody Peter Mello 					fmtwd = -fmtwd;
9711ee2e5faSnakanon 				tcnt += ret;
972*3ee4fc2aSCody Peter Mello 				tempfree(x);
9737c478bd9Sstevel@tonic-gate 			}
9747c478bd9Sstevel@tonic-gate 		}
9751ee2e5faSnakanon 		fmt[tcnt] = '\0';
976*3ee4fc2aSCody Peter Mello 		if (fmtwd < 0)
977*3ee4fc2aSCody Peter Mello 			fmtwd = -fmtwd;
9781ee2e5faSnakanon 
9797c478bd9Sstevel@tonic-gate 		switch (*s) {
980*3ee4fc2aSCody Peter Mello 		case 'a': case 'A':
981*3ee4fc2aSCody Peter Mello 			flag = *s;
982*3ee4fc2aSCody Peter Mello 			break;
9837c478bd9Sstevel@tonic-gate 		case 'f': case 'e': case 'g': case 'E': case 'G':
984*3ee4fc2aSCody Peter Mello 			flag = 'f';
9857c478bd9Sstevel@tonic-gate 			break;
9867c478bd9Sstevel@tonic-gate 		case 'd': case 'i':
987*3ee4fc2aSCody Peter Mello 			flag = 'd';
9881ee2e5faSnakanon 			if (*(s-1) == 'l')
9891ee2e5faSnakanon 				break;
9901ee2e5faSnakanon 			fmt[tcnt - 1] = 'l';
991*3ee4fc2aSCody Peter Mello 			expand_buf(&fmt, &fmtsz, tcnt);
9921ee2e5faSnakanon 			fmt[tcnt++] = 'd';
9931ee2e5faSnakanon 			fmt[tcnt] = '\0';
9947c478bd9Sstevel@tonic-gate 			break;
9957c478bd9Sstevel@tonic-gate 		case 'o': case 'x': case 'X': case 'u':
996*3ee4fc2aSCody Peter Mello 			flag = *(s-1) == 'l' ? 'd' : 'u';
9977c478bd9Sstevel@tonic-gate 			break;
9987c478bd9Sstevel@tonic-gate 		case 's':
999*3ee4fc2aSCody Peter Mello 			flag = 's';
10007c478bd9Sstevel@tonic-gate 			break;
10017c478bd9Sstevel@tonic-gate 		case 'c':
1002*3ee4fc2aSCody Peter Mello 			flag = 'c';
10037c478bd9Sstevel@tonic-gate 			break;
10047c478bd9Sstevel@tonic-gate 		default:
1005*3ee4fc2aSCody Peter Mello 			WARNING("weird printf conversion %s", fmt);
1006*3ee4fc2aSCody Peter Mello 			flag = '?';
10077c478bd9Sstevel@tonic-gate 			break;
10087c478bd9Sstevel@tonic-gate 		}
1009*3ee4fc2aSCody Peter Mello 		if (flag == '?') {
1010*3ee4fc2aSCody Peter Mello 			len = strlen(fmt);
10111ee2e5faSnakanon 			expand_buf(&buf, &bufsize, cnt + len);
10121ee2e5faSnakanon 			(void) memcpy(&buf[cnt], fmt, len);
10131ee2e5faSnakanon 			cnt += len;
10141ee2e5faSnakanon 			buf[cnt] = '\0';
10157c478bd9Sstevel@tonic-gate 			continue;
10167c478bd9Sstevel@tonic-gate 		}
10177c478bd9Sstevel@tonic-gate 		if (a == NULL) {
1018*3ee4fc2aSCody Peter Mello 			FATAL("not enough args in printf(%s) "
1019*3ee4fc2aSCody Peter Mello 			    "or sprintf(%s)", os, os);
10207c478bd9Sstevel@tonic-gate 		}
10217c478bd9Sstevel@tonic-gate 		x = execute(a);
10227c478bd9Sstevel@tonic-gate 		a = a->nnext;
1023*3ee4fc2aSCody Peter Mello 		n = MAXNUMSIZE;
1024*3ee4fc2aSCody Peter Mello 		if (fmtwd > n)
1025*3ee4fc2aSCody Peter Mello 			n = fmtwd;
1026*3ee4fc2aSCody Peter Mello retry:
1027*3ee4fc2aSCody Peter Mello 		/* make sure we have at least 1 byte space */
1028*3ee4fc2aSCody Peter Mello 		(void) adjbuf(&buf, &bufsize, 1 + n + cnt,
1029*3ee4fc2aSCody Peter Mello 		    recsize, NULL, "format5");
1030*3ee4fc2aSCody Peter Mello 		len = bufsize - cnt;
1031*3ee4fc2aSCody Peter Mello 		switch (flag) {
1032*3ee4fc2aSCody Peter Mello 		case 'a':
1033*3ee4fc2aSCody Peter Mello 		case 'A':
1034*3ee4fc2aSCody Peter Mello 		case 'f':
1035*3ee4fc2aSCody Peter Mello 			/*LINTED*/
1036*3ee4fc2aSCody Peter Mello 			ret = snprintf(&buf[cnt], len,
1037*3ee4fc2aSCody Peter Mello 			    fmt, getfval(x));
1038*3ee4fc2aSCody Peter Mello 			break;
1039*3ee4fc2aSCody Peter Mello 		case 'd':
1040*3ee4fc2aSCody Peter Mello 			/*LINTED*/
1041*3ee4fc2aSCody Peter Mello 			ret = snprintf(&buf[cnt], len,
1042*3ee4fc2aSCody Peter Mello 			    fmt, (long)getfval(x));
1043*3ee4fc2aSCody Peter Mello 			break;
1044*3ee4fc2aSCody Peter Mello 		case 'u':
1045*3ee4fc2aSCody Peter Mello 			/*LINTED*/
1046*3ee4fc2aSCody Peter Mello 			ret = snprintf(&buf[cnt], len,
1047*3ee4fc2aSCody Peter Mello 			    fmt, (int)getfval(x));
1048*3ee4fc2aSCody Peter Mello 			break;
1049*3ee4fc2aSCody Peter Mello 		case 's':
1050*3ee4fc2aSCody Peter Mello 			/*LINTED*/
1051*3ee4fc2aSCody Peter Mello 			ret = snprintf(&buf[cnt], len,
1052*3ee4fc2aSCody Peter Mello 			    fmt, getsval(x));
1053*3ee4fc2aSCody Peter Mello 			break;
1054*3ee4fc2aSCody Peter Mello 		case 'c':
1055*3ee4fc2aSCody Peter Mello 			if (!isnum(x)) {
10561ee2e5faSnakanon 				/*LINTED*/
1057*3ee4fc2aSCody Peter Mello 				ret = snprintf(&buf[cnt], len,
1058*3ee4fc2aSCody Peter Mello 				    fmt, getsval(x)[0]);
10591ee2e5faSnakanon 				break;
1060*3ee4fc2aSCody Peter Mello 			}
1061*3ee4fc2aSCody Peter Mello 			if (getfval(x)) {
10621ee2e5faSnakanon 				/*LINTED*/
1063*3ee4fc2aSCody Peter Mello 				ret = snprintf(&buf[cnt], len,
1064*3ee4fc2aSCody Peter Mello 				    fmt, (int)getfval(x));
1065*3ee4fc2aSCody Peter Mello 			} else {
1066*3ee4fc2aSCody Peter Mello 				/* explicit null byte */
1067*3ee4fc2aSCody Peter Mello 				buf[cnt] = '\0';
1068*3ee4fc2aSCody Peter Mello 				/* next output will start here */
1069*3ee4fc2aSCody Peter Mello 				buf[cnt + 1] = '\0';
1070*3ee4fc2aSCody Peter Mello 				ret = 1;
10711ee2e5faSnakanon 			}
1072*3ee4fc2aSCody Peter Mello 			break;
1073*3ee4fc2aSCody Peter Mello 		default:
1074*3ee4fc2aSCody Peter Mello 			FATAL("can't happen: "
1075*3ee4fc2aSCody Peter Mello 			    "bad conversion %c in format()", flag);
1076*3ee4fc2aSCody Peter Mello 		}
1077*3ee4fc2aSCody Peter Mello 		if (ret >= len) {
1078*3ee4fc2aSCody Peter Mello 			(void) adjbuf(&buf, &bufsize, cnt + ret + 1,
1079*3ee4fc2aSCody Peter Mello 			    recsize, NULL, "format6");
1080*3ee4fc2aSCody Peter Mello 			goto retry;
10817c478bd9Sstevel@tonic-gate 		}
1082*3ee4fc2aSCody Peter Mello 		tempfree(x);
10831ee2e5faSnakanon 		cnt += ret;
10847c478bd9Sstevel@tonic-gate 		s++;
10857c478bd9Sstevel@tonic-gate 	}
10861ee2e5faSnakanon 	buf[cnt] = '\0';
10871ee2e5faSnakanon 	free(fmt);
1088*3ee4fc2aSCody Peter Mello 	for (; a != NULL; a = a->nnext)	/* evaluate any remaining args */
1089*3ee4fc2aSCody Peter Mello 		(void) execute(a);
1090*3ee4fc2aSCody Peter Mello 	*pbuf = buf;
1091*3ee4fc2aSCody Peter Mello 	*pbufsize = bufsize;
1092*3ee4fc2aSCody Peter Mello 	return (cnt);
10937c478bd9Sstevel@tonic-gate }
10947c478bd9Sstevel@tonic-gate 
10951ee2e5faSnakanon /*ARGSUSED*/
10961ee2e5faSnakanon Cell *
awksprintf(Node ** a,int n)1097*3ee4fc2aSCody Peter Mello awksprintf(Node **a, int n)		/* sprintf(a[0]) */
10987c478bd9Sstevel@tonic-gate {
1099*3ee4fc2aSCody Peter Mello 	Cell *x;
1100*3ee4fc2aSCody Peter Mello 	Node *y;
1101*3ee4fc2aSCody Peter Mello 	char *buf;
1102*3ee4fc2aSCody Peter Mello 	int bufsz = 3 * recsize;
11037c478bd9Sstevel@tonic-gate 
1104*3ee4fc2aSCody Peter Mello 	if ((buf = (char *)malloc(bufsz)) == NULL)
1105*3ee4fc2aSCody Peter Mello 		FATAL("out of memory in awksprintf");
11067c478bd9Sstevel@tonic-gate 	y = a[0]->nnext;
11077c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
1108*3ee4fc2aSCody Peter Mello 	if (format(&buf, &bufsz, getsval(x), y) == -1)
1109*3ee4fc2aSCody Peter Mello 		FATAL("sprintf string %.30s... too long.  can't happen.", buf);
1110*3ee4fc2aSCody Peter Mello 	tempfree(x);
1111*3ee4fc2aSCody Peter Mello 	x = gettemp();
11121ee2e5faSnakanon 	x->sval = buf;
11137c478bd9Sstevel@tonic-gate 	x->tval = STR;
11141ee2e5faSnakanon 	return (x);
11157c478bd9Sstevel@tonic-gate }
11167c478bd9Sstevel@tonic-gate 
11171ee2e5faSnakanon /*ARGSUSED*/
11181ee2e5faSnakanon Cell *
awkprintf(Node ** a,int n)1119*3ee4fc2aSCody Peter Mello awkprintf(Node **a, int n)		/* printf */
11207c478bd9Sstevel@tonic-gate {
1121*3ee4fc2aSCody Peter Mello 	/* a[0] is list of args, starting with format string */
1122*3ee4fc2aSCody Peter Mello 	/* a[1] is redirection operator, a[2] is redirection file */
11237c478bd9Sstevel@tonic-gate 	FILE *fp;
1124*3ee4fc2aSCody Peter Mello 	Cell *x;
1125*3ee4fc2aSCody Peter Mello 	Node *y;
1126*3ee4fc2aSCody Peter Mello 	char *buf;
1127*3ee4fc2aSCody Peter Mello 	int len;
1128*3ee4fc2aSCody Peter Mello 	int bufsz = 3 * recsize;
11297c478bd9Sstevel@tonic-gate 
1130*3ee4fc2aSCody Peter Mello 	if ((buf = (char *)malloc(bufsz)) == NULL)
1131*3ee4fc2aSCody Peter Mello 		FATAL("out of memory in awkprintf");
11327c478bd9Sstevel@tonic-gate 	y = a[0]->nnext;
11337c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
1134*3ee4fc2aSCody Peter Mello 	if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
1135*3ee4fc2aSCody Peter Mello 		FATAL("printf string %.30s... too long. can't happen.", buf);
1136*3ee4fc2aSCody Peter Mello 	tempfree(x);
1137*3ee4fc2aSCody Peter Mello 	if (a[1] == NULL) {
1138*3ee4fc2aSCody Peter Mello 		(void) fwrite(buf, len, 1, stdout);
1139*3ee4fc2aSCody Peter Mello 		if (ferror(stdout))
1140*3ee4fc2aSCody Peter Mello 			FATAL("write error on stdout");
1141*3ee4fc2aSCody Peter Mello 	} else {
1142*3ee4fc2aSCody Peter Mello 		fp = redirect(ptoi(a[1]), a[2]);
1143*3ee4fc2aSCody Peter Mello 		(void) fwrite(buf, len, 1, fp);
11441ee2e5faSnakanon 		(void) fflush(fp);
1145*3ee4fc2aSCody Peter Mello 		if (ferror(fp))
1146*3ee4fc2aSCody Peter Mello 			FATAL("write error on %s", filename(fp));
11477c478bd9Sstevel@tonic-gate 	}
11481ee2e5faSnakanon 	free(buf);
1149*3ee4fc2aSCody Peter Mello 	return (True);
11507c478bd9Sstevel@tonic-gate }
11517c478bd9Sstevel@tonic-gate 
11521ee2e5faSnakanon Cell *
arith(Node ** a,int n)1153*3ee4fc2aSCody Peter Mello arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
11547c478bd9Sstevel@tonic-gate {
1155*3ee4fc2aSCody Peter Mello 	Awkfloat i, j = 0;
11561ee2e5faSnakanon 	double v;
1157*3ee4fc2aSCody Peter Mello 	Cell *x, *y, *z;
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
11607c478bd9Sstevel@tonic-gate 	i = getfval(x);
1161*3ee4fc2aSCody Peter Mello 	tempfree(x);
1162*3ee4fc2aSCody Peter Mello 	if (n != UMINUS && n != UPLUS) {
11637c478bd9Sstevel@tonic-gate 		y = execute(a[1]);
11647c478bd9Sstevel@tonic-gate 		j = getfval(y);
1165*3ee4fc2aSCody Peter Mello 		tempfree(y);
11667c478bd9Sstevel@tonic-gate 	}
1167*3ee4fc2aSCody Peter Mello 	z = gettemp();
11687c478bd9Sstevel@tonic-gate 	switch (n) {
11697c478bd9Sstevel@tonic-gate 	case ADD:
11707c478bd9Sstevel@tonic-gate 		i += j;
11717c478bd9Sstevel@tonic-gate 		break;
11727c478bd9Sstevel@tonic-gate 	case MINUS:
11737c478bd9Sstevel@tonic-gate 		i -= j;
11747c478bd9Sstevel@tonic-gate 		break;
11757c478bd9Sstevel@tonic-gate 	case MULT:
11767c478bd9Sstevel@tonic-gate 		i *= j;
11777c478bd9Sstevel@tonic-gate 		break;
11787c478bd9Sstevel@tonic-gate 	case DIVIDE:
11797c478bd9Sstevel@tonic-gate 		if (j == 0)
1180*3ee4fc2aSCody Peter Mello 			FATAL("division by zero");
11817c478bd9Sstevel@tonic-gate 		i /= j;
11827c478bd9Sstevel@tonic-gate 		break;
11837c478bd9Sstevel@tonic-gate 	case MOD:
11847c478bd9Sstevel@tonic-gate 		if (j == 0)
1185*3ee4fc2aSCody Peter Mello 			FATAL("division by zero in mod");
11861ee2e5faSnakanon 		(void) modf(i/j, &v);
11877c478bd9Sstevel@tonic-gate 		i = i - j * v;
11887c478bd9Sstevel@tonic-gate 		break;
11897c478bd9Sstevel@tonic-gate 	case UMINUS:
11907c478bd9Sstevel@tonic-gate 		i = -i;
11917c478bd9Sstevel@tonic-gate 		break;
1192*3ee4fc2aSCody Peter Mello 	case UPLUS: /* handled by getfval(), above */
1193*3ee4fc2aSCody Peter Mello 		break;
11947c478bd9Sstevel@tonic-gate 	case POWER:
11951ee2e5faSnakanon 		if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
11961ee2e5faSnakanon 			i = ipow(i, (int)j);
11977c478bd9Sstevel@tonic-gate 		else
11987c478bd9Sstevel@tonic-gate 			i = errcheck(pow(i, j), "pow");
11997c478bd9Sstevel@tonic-gate 		break;
12007c478bd9Sstevel@tonic-gate 	default:	/* can't happen */
1201*3ee4fc2aSCody Peter Mello 		FATAL("illegal arithmetic operator %d", n);
12027c478bd9Sstevel@tonic-gate 	}
12031ee2e5faSnakanon 	(void) setfval(z, i);
12041ee2e5faSnakanon 	return (z);
12057c478bd9Sstevel@tonic-gate }
12067c478bd9Sstevel@tonic-gate 
12071ee2e5faSnakanon static double
ipow(double x,int n)1208*3ee4fc2aSCody Peter Mello ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
12097c478bd9Sstevel@tonic-gate {
12107c478bd9Sstevel@tonic-gate 	double v;
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	if (n <= 0)
12131ee2e5faSnakanon 		return (1.0);
12147c478bd9Sstevel@tonic-gate 	v = ipow(x, n/2);
12157c478bd9Sstevel@tonic-gate 	if (n % 2 == 0)
12161ee2e5faSnakanon 		return (v * v);
12177c478bd9Sstevel@tonic-gate 	else
12181ee2e5faSnakanon 		return (x * v * v);
12197c478bd9Sstevel@tonic-gate }
12207c478bd9Sstevel@tonic-gate 
12211ee2e5faSnakanon Cell *
incrdecr(Node ** a,int n)1222*3ee4fc2aSCody Peter Mello incrdecr(Node **a, int n)		/* a[0]++, etc. */
12237c478bd9Sstevel@tonic-gate {
1224*3ee4fc2aSCody Peter Mello 	Cell *x, *z;
1225*3ee4fc2aSCody Peter Mello 	int k;
12267c478bd9Sstevel@tonic-gate 	Awkfloat xf;
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
12297c478bd9Sstevel@tonic-gate 	xf = getfval(x);
12307c478bd9Sstevel@tonic-gate 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
12317c478bd9Sstevel@tonic-gate 	if (n == PREINCR || n == PREDECR) {
12321ee2e5faSnakanon 		(void) setfval(x, xf + k);
12331ee2e5faSnakanon 		return (x);
12347c478bd9Sstevel@tonic-gate 	}
1235*3ee4fc2aSCody Peter Mello 	z = gettemp();
12361ee2e5faSnakanon 	(void) setfval(z, xf);
12371ee2e5faSnakanon 	(void) setfval(x, xf + k);
1238*3ee4fc2aSCody Peter Mello 	tempfree(x);
12391ee2e5faSnakanon 	return (z);
12407c478bd9Sstevel@tonic-gate }
12417c478bd9Sstevel@tonic-gate 
1242*3ee4fc2aSCody Peter Mello /* a[0] = a[1], a[0] += a[1], etc. */
1243*3ee4fc2aSCody Peter Mello /* this is subtle; don't muck with it. */
12441ee2e5faSnakanon Cell *
assign(Node ** a,int n)12451ee2e5faSnakanon assign(Node **a, int n)
12467c478bd9Sstevel@tonic-gate {
1247*3ee4fc2aSCody Peter Mello 	Cell *x, *y;
12487c478bd9Sstevel@tonic-gate 	Awkfloat xf, yf;
12491ee2e5faSnakanon 	double v;
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	y = execute(a[1]);
12527c478bd9Sstevel@tonic-gate 	x = execute(a[0]);	/* order reversed from before... */
12537c478bd9Sstevel@tonic-gate 	if (n == ASSIGN) {	/* ordinary assignment */
1254*3ee4fc2aSCody Peter Mello 		/*LINTED if*/
1255*3ee4fc2aSCody Peter Mello 		if (x == y && !(x->tval & (FLD|REC)) && x != nfloc) {
1256*3ee4fc2aSCody Peter Mello 			/*
1257*3ee4fc2aSCody Peter Mello 			 * If this is a self-assignment, we leave things alone,
1258*3ee4fc2aSCody Peter Mello 			 * unless it's a field or NF.
1259*3ee4fc2aSCody Peter Mello 			 */
1260*3ee4fc2aSCody Peter Mello 		} else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
12611ee2e5faSnakanon 			(void) setsval(x, getsval(y));
12627c478bd9Sstevel@tonic-gate 			x->fval = getfval(y);
12637c478bd9Sstevel@tonic-gate 			x->tval |= NUM;
1264*3ee4fc2aSCody Peter Mello 		} else if (isstr(y))
12651ee2e5faSnakanon 			(void) setsval(x, getsval(y));
1266*3ee4fc2aSCody Peter Mello 		else if (isnum(y))
12671ee2e5faSnakanon 			(void) setfval(x, getfval(y));
12687c478bd9Sstevel@tonic-gate 		else
12697c478bd9Sstevel@tonic-gate 			funnyvar(y, "read value of");
1270*3ee4fc2aSCody Peter Mello 		tempfree(y);
12711ee2e5faSnakanon 		return (x);
12727c478bd9Sstevel@tonic-gate 	}
12737c478bd9Sstevel@tonic-gate 	xf = getfval(x);
12747c478bd9Sstevel@tonic-gate 	yf = getfval(y);
12757c478bd9Sstevel@tonic-gate 	switch (n) {
12767c478bd9Sstevel@tonic-gate 	case ADDEQ:
12777c478bd9Sstevel@tonic-gate 		xf += yf;
12787c478bd9Sstevel@tonic-gate 		break;
12797c478bd9Sstevel@tonic-gate 	case SUBEQ:
12807c478bd9Sstevel@tonic-gate 		xf -= yf;
12817c478bd9Sstevel@tonic-gate 		break;
12827c478bd9Sstevel@tonic-gate 	case MULTEQ:
12837c478bd9Sstevel@tonic-gate 		xf *= yf;
12847c478bd9Sstevel@tonic-gate 		break;
12857c478bd9Sstevel@tonic-gate 	case DIVEQ:
12867c478bd9Sstevel@tonic-gate 		if (yf == 0)
1287*3ee4fc2aSCody Peter Mello 			FATAL("division by zero in /=");
12887c478bd9Sstevel@tonic-gate 		xf /= yf;
12897c478bd9Sstevel@tonic-gate 		break;
12907c478bd9Sstevel@tonic-gate 	case MODEQ:
12917c478bd9Sstevel@tonic-gate 		if (yf == 0)
1292*3ee4fc2aSCody Peter Mello 			FATAL("division by zero in %%=");
12931ee2e5faSnakanon 		(void) modf(xf/yf, &v);
12947c478bd9Sstevel@tonic-gate 		xf = xf - yf * v;
12957c478bd9Sstevel@tonic-gate 		break;
12967c478bd9Sstevel@tonic-gate 	case POWEQ:
12971ee2e5faSnakanon 		if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
12981ee2e5faSnakanon 			xf = ipow(xf, (int)yf);
12997c478bd9Sstevel@tonic-gate 		else
13007c478bd9Sstevel@tonic-gate 			xf = errcheck(pow(xf, yf), "pow");
13017c478bd9Sstevel@tonic-gate 		break;
13027c478bd9Sstevel@tonic-gate 	default:
1303*3ee4fc2aSCody Peter Mello 		FATAL("illegal assignment operator %d", n);
13047c478bd9Sstevel@tonic-gate 		break;
13057c478bd9Sstevel@tonic-gate 	}
1306*3ee4fc2aSCody Peter Mello 	tempfree(y);
13071ee2e5faSnakanon 	(void) setfval(x, xf);
13081ee2e5faSnakanon 	return (x);
13097c478bd9Sstevel@tonic-gate }
13107c478bd9Sstevel@tonic-gate 
13111ee2e5faSnakanon /*ARGSUSED*/
13121ee2e5faSnakanon Cell *
cat(Node ** a,int q)1313*3ee4fc2aSCody Peter Mello cat(Node **a, int q)	/* a[0] cat a[1] */
13147c478bd9Sstevel@tonic-gate {
1315*3ee4fc2aSCody Peter Mello 	Cell *x, *y, *z;
1316*3ee4fc2aSCody Peter Mello 	int n1, n2;
1317*3ee4fc2aSCody Peter Mello 	char *s = NULL;
1318*3ee4fc2aSCody Peter Mello 	size_t ssz = 0;
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
1321*3ee4fc2aSCody Peter Mello 	n1 = strlen(getsval(x));
1322*3ee4fc2aSCody Peter Mello 	(void) adjbuf(&s, &ssz, n1 + 1, recsize, 0, "cat1");
1323*3ee4fc2aSCody Peter Mello 	(void) strncpy(s, x->sval, ssz);
1324*3ee4fc2aSCody Peter Mello 
13257c478bd9Sstevel@tonic-gate 	y = execute(a[1]);
1326*3ee4fc2aSCody Peter Mello 	n2 = strlen(getsval(y));
1327*3ee4fc2aSCody Peter Mello 	(void) adjbuf(&s, &ssz, n1 + n2 + 1, recsize, 0, "cat2");
1328*3ee4fc2aSCody Peter Mello 	(void) strncpy(s + n1, y->sval, ssz - n1);
1329*3ee4fc2aSCody Peter Mello 
1330*3ee4fc2aSCody Peter Mello 	tempfree(x);
1331*3ee4fc2aSCody Peter Mello 	tempfree(y);
1332*3ee4fc2aSCody Peter Mello 
1333*3ee4fc2aSCody Peter Mello 	z = gettemp();
13347c478bd9Sstevel@tonic-gate 	z->sval = s;
13357c478bd9Sstevel@tonic-gate 	z->tval = STR;
1336*3ee4fc2aSCody Peter Mello 
13371ee2e5faSnakanon 	return (z);
13387c478bd9Sstevel@tonic-gate }
13397c478bd9Sstevel@tonic-gate 
13401ee2e5faSnakanon /*ARGSUSED*/
13411ee2e5faSnakanon Cell *
pastat(Node ** a,int n)1342*3ee4fc2aSCody Peter Mello pastat(Node **a, int n)	/* a[0] { a[1] } */
13437c478bd9Sstevel@tonic-gate {
1344*3ee4fc2aSCody Peter Mello 	Cell *x;
13457c478bd9Sstevel@tonic-gate 
1346*3ee4fc2aSCody Peter Mello 	if (a[0] == NULL)
13477c478bd9Sstevel@tonic-gate 		x = execute(a[1]);
13487c478bd9Sstevel@tonic-gate 	else {
13497c478bd9Sstevel@tonic-gate 		x = execute(a[0]);
13507c478bd9Sstevel@tonic-gate 		if (istrue(x)) {
1351*3ee4fc2aSCody Peter Mello 			tempfree(x);
13527c478bd9Sstevel@tonic-gate 			x = execute(a[1]);
13537c478bd9Sstevel@tonic-gate 		}
13547c478bd9Sstevel@tonic-gate 	}
13551ee2e5faSnakanon 	return (x);
13567c478bd9Sstevel@tonic-gate }
13577c478bd9Sstevel@tonic-gate 
13581ee2e5faSnakanon /*ARGSUSED*/
13591ee2e5faSnakanon Cell *
dopa2(Node ** a,int n)1360*3ee4fc2aSCody Peter Mello dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
13617c478bd9Sstevel@tonic-gate {
13627c478bd9Sstevel@tonic-gate 	Cell	*x;
13637c478bd9Sstevel@tonic-gate 	int	pair;
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 	if (!pairstack) {
13667c478bd9Sstevel@tonic-gate 		/* first time */
13677c478bd9Sstevel@tonic-gate 		dprintf(("paircnt: %d\n", paircnt));
1368*3ee4fc2aSCody Peter Mello 		pairstack = (int *)calloc(paircnt, sizeof (int));
1369*3ee4fc2aSCody Peter Mello 		if (pairstack == NULL)
1370*3ee4fc2aSCody Peter Mello 			FATAL("out of space in dopa2");
13717c478bd9Sstevel@tonic-gate 	}
13727c478bd9Sstevel@tonic-gate 
1373*3ee4fc2aSCody Peter Mello 	pair = ptoi(a[3]);
13747c478bd9Sstevel@tonic-gate 	if (pairstack[pair] == 0) {
13757c478bd9Sstevel@tonic-gate 		x = execute(a[0]);
13767c478bd9Sstevel@tonic-gate 		if (istrue(x))
13777c478bd9Sstevel@tonic-gate 			pairstack[pair] = 1;
1378*3ee4fc2aSCody Peter Mello 		tempfree(x);
13797c478bd9Sstevel@tonic-gate 	}
13807c478bd9Sstevel@tonic-gate 	if (pairstack[pair] == 1) {
13817c478bd9Sstevel@tonic-gate 		x = execute(a[1]);
13827c478bd9Sstevel@tonic-gate 		if (istrue(x))
13837c478bd9Sstevel@tonic-gate 			pairstack[pair] = 0;
1384*3ee4fc2aSCody Peter Mello 		tempfree(x);
13857c478bd9Sstevel@tonic-gate 		x = execute(a[2]);
13861ee2e5faSnakanon 		return (x);
13877c478bd9Sstevel@tonic-gate 	}
1388*3ee4fc2aSCody Peter Mello 	return (False);
13897c478bd9Sstevel@tonic-gate }
13907c478bd9Sstevel@tonic-gate 
13911ee2e5faSnakanon /*ARGSUSED*/
13921ee2e5faSnakanon Cell *
split(Node ** a,int nnn)1393*3ee4fc2aSCody Peter Mello split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
13947c478bd9Sstevel@tonic-gate {
1395*3ee4fc2aSCody Peter Mello 	Cell *x = NULL, *y, *ap;
1396*3ee4fc2aSCody Peter Mello 	char *s, *origs;
1397*3ee4fc2aSCody Peter Mello 	char *fs, *origfs = NULL;
1398*3ee4fc2aSCody Peter Mello 	int sep;
1399*3ee4fc2aSCody Peter Mello 	char *t, temp, num[50];
1400*3ee4fc2aSCody Peter Mello 	int n, tempstat, arg3type;
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 	y = execute(a[0]);	/* source string */
1403*3ee4fc2aSCody Peter Mello 	origs = s = tostring(getsval(y));
1404*3ee4fc2aSCody Peter Mello 	arg3type = ptoi(a[3]);
1405*3ee4fc2aSCody Peter Mello 	if (a[2] == NULL)	/* fs string */
1406*3ee4fc2aSCody Peter Mello 		fs = getsval(fsloc);
1407*3ee4fc2aSCody Peter Mello 	else if (arg3type == STRING) {	/* split(str,arr,"string") */
14087c478bd9Sstevel@tonic-gate 		x = execute(a[2]);
1409*3ee4fc2aSCody Peter Mello 		origfs = fs = tostring(getsval(x));
1410*3ee4fc2aSCody Peter Mello 		tempfree(x);
1411*3ee4fc2aSCody Peter Mello 	} else if (arg3type == REGEXPR)
1412*3ee4fc2aSCody Peter Mello 		fs = "(regexpr)";	/* split(str,arr,/regexpr/) */
14137c478bd9Sstevel@tonic-gate 	else
1414*3ee4fc2aSCody Peter Mello 		FATAL("illegal type of split");
14157c478bd9Sstevel@tonic-gate 	sep = *fs;
14167c478bd9Sstevel@tonic-gate 	ap = execute(a[1]);	/* array name */
14177c478bd9Sstevel@tonic-gate 	freesymtab(ap);
1418*3ee4fc2aSCody Peter Mello 	dprintf(("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs));
14197c478bd9Sstevel@tonic-gate 	ap->tval &= ~STR;
14207c478bd9Sstevel@tonic-gate 	ap->tval |= ARR;
1421*3ee4fc2aSCody Peter Mello 	ap->sval = (char *)makesymtab(NSYMTAB);
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	n = 0;
1424*3ee4fc2aSCody Peter Mello 	if (arg3type == REGEXPR && strlen((char *)((fa*)a[2])->restr) == 0) {
1425*3ee4fc2aSCody Peter Mello 		/*
1426*3ee4fc2aSCody Peter Mello 		 * split(s, a, //); have to arrange things such that it looks
1427*3ee4fc2aSCody Peter Mello 		 * like an empty separator.
1428*3ee4fc2aSCody Peter Mello 		 */
1429*3ee4fc2aSCody Peter Mello 		arg3type = 0;
1430*3ee4fc2aSCody Peter Mello 		fs = "";
1431*3ee4fc2aSCody Peter Mello 		sep = 0;
1432*3ee4fc2aSCody Peter Mello 	}
1433*3ee4fc2aSCody Peter Mello 	if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) {
14341ee2e5faSnakanon 		/* reg expr */
14357c478bd9Sstevel@tonic-gate 		fa *pfa;
1436*3ee4fc2aSCody Peter Mello 		if (arg3type == REGEXPR) {	/* it's ready already */
14371ee2e5faSnakanon 			pfa = (fa *)a[2];
14387c478bd9Sstevel@tonic-gate 		} else {
14397c478bd9Sstevel@tonic-gate 			pfa = makedfa(fs, 1);
14407c478bd9Sstevel@tonic-gate 		}
14411ee2e5faSnakanon 		if (nematch(pfa, s)) {
14427c478bd9Sstevel@tonic-gate 			tempstat = pfa->initstat;
14437c478bd9Sstevel@tonic-gate 			pfa->initstat = 2;
14447c478bd9Sstevel@tonic-gate 			do {
14457c478bd9Sstevel@tonic-gate 				n++;
1446*3ee4fc2aSCody Peter Mello 				(void) sprintf(num, "%d", n);
14477c478bd9Sstevel@tonic-gate 				temp = *patbeg;
14487c478bd9Sstevel@tonic-gate 				*patbeg = '\0';
14491ee2e5faSnakanon 				if (is_number(s)) {
14501ee2e5faSnakanon 					(void) setsymtab(num, s,
1451*3ee4fc2aSCody Peter Mello 					    atof(s),
14521ee2e5faSnakanon 					    /*LINTED align*/
14531ee2e5faSnakanon 					    STR|NUM, (Array *)ap->sval);
14541ee2e5faSnakanon 				} else {
14551ee2e5faSnakanon 					(void) setsymtab(num, s, 0.0,
14561ee2e5faSnakanon 					    /*LINTED align*/
14571ee2e5faSnakanon 					    STR, (Array *)ap->sval);
14581ee2e5faSnakanon 				}
14597c478bd9Sstevel@tonic-gate 				*patbeg = temp;
14607c478bd9Sstevel@tonic-gate 				s = patbeg + patlen;
14617c478bd9Sstevel@tonic-gate 				if (*(patbeg+patlen-1) == 0 || *s == 0) {
14627c478bd9Sstevel@tonic-gate 					n++;
1463*3ee4fc2aSCody Peter Mello 					(void) sprintf(num, "%d", n);
1464*3ee4fc2aSCody Peter Mello 					(void) setsymtab(num, "", 0.0,
14651ee2e5faSnakanon 					    /*LINTED align*/
14661ee2e5faSnakanon 					    STR, (Array *)ap->sval);
14677c478bd9Sstevel@tonic-gate 					pfa->initstat = tempstat;
14687c478bd9Sstevel@tonic-gate 					goto spdone;
14697c478bd9Sstevel@tonic-gate 				}
14701ee2e5faSnakanon 			} while (nematch(pfa, s));
1471*3ee4fc2aSCody Peter Mello 			/* bwk: has to be here to reset */
1472*3ee4fc2aSCody Peter Mello 			/* cf gsub and refldbld */
1473*3ee4fc2aSCody Peter Mello 			pfa->initstat = tempstat;
14747c478bd9Sstevel@tonic-gate 		}
14757c478bd9Sstevel@tonic-gate 		n++;
1476*3ee4fc2aSCody Peter Mello 		(void) sprintf(num, "%d", n);
14771ee2e5faSnakanon 		if (is_number(s)) {
1478*3ee4fc2aSCody Peter Mello 			(void) setsymtab(num, s, atof(s),
14791ee2e5faSnakanon 			    /*LINTED align*/
14801ee2e5faSnakanon 			    STR|NUM, (Array *)ap->sval);
14811ee2e5faSnakanon 		} else {
14821ee2e5faSnakanon 			/*LINTED align*/
14831ee2e5faSnakanon 			(void) setsymtab(num, s, 0.0, STR, (Array *)ap->sval);
14841ee2e5faSnakanon 		}
14851ee2e5faSnakanon spdone:
14867c478bd9Sstevel@tonic-gate 		pfa = NULL;
14877c478bd9Sstevel@tonic-gate 	} else if (sep == ' ') {
14887c478bd9Sstevel@tonic-gate 		for (n = 0; ; ) {
14897c478bd9Sstevel@tonic-gate 			while (*s == ' ' || *s == '\t' || *s == '\n')
14907c478bd9Sstevel@tonic-gate 				s++;
1491*3ee4fc2aSCody Peter Mello 			if (*s == '\0')
14927c478bd9Sstevel@tonic-gate 				break;
14937c478bd9Sstevel@tonic-gate 			n++;
14947c478bd9Sstevel@tonic-gate 			t = s;
14957c478bd9Sstevel@tonic-gate 			do
14967c478bd9Sstevel@tonic-gate 				s++;
14971ee2e5faSnakanon 			while (*s != ' ' && *s != '\t' &&
14981ee2e5faSnakanon 			    *s != '\n' && *s != '\0')
14991ee2e5faSnakanon 				;
15007c478bd9Sstevel@tonic-gate 			temp = *s;
15017c478bd9Sstevel@tonic-gate 			*s = '\0';
1502*3ee4fc2aSCody Peter Mello 			(void) sprintf(num, "%d", n);
15031ee2e5faSnakanon 			if (is_number(t)) {
1504*3ee4fc2aSCody Peter Mello 				(void) setsymtab(num, t, atof(t),
15051ee2e5faSnakanon 				    /*LINTED align*/
15061ee2e5faSnakanon 				    STR|NUM, (Array *)ap->sval);
15071ee2e5faSnakanon 			} else {
15081ee2e5faSnakanon 				(void) setsymtab(num, t, 0.0,
15091ee2e5faSnakanon 				    /*LINTED align*/
15101ee2e5faSnakanon 				    STR, (Array *)ap->sval);
15111ee2e5faSnakanon 			}
15127c478bd9Sstevel@tonic-gate 			*s = temp;
1513*3ee4fc2aSCody Peter Mello 			if (*s != '\0')
15147c478bd9Sstevel@tonic-gate 				s++;
15157c478bd9Sstevel@tonic-gate 		}
1516*3ee4fc2aSCody Peter Mello 	} else if (sep == '\0') {	/* split(s, a, "") => 1 char/elem */
1517*3ee4fc2aSCody Peter Mello 		for (n = 0; *s != 0; s++) {
1518*3ee4fc2aSCody Peter Mello 			char buf[2];
1519*3ee4fc2aSCody Peter Mello 			n++;
1520*3ee4fc2aSCody Peter Mello 			(void) sprintf(num, "%d", n);
1521*3ee4fc2aSCody Peter Mello 			buf[0] = *s;
1522*3ee4fc2aSCody Peter Mello 			buf[1] = '\0';
1523*3ee4fc2aSCody Peter Mello 			if (isdigit((uschar)buf[0])) {
1524*3ee4fc2aSCody Peter Mello 				(void) setsymtab(num, buf, atof(buf),
1525*3ee4fc2aSCody Peter Mello 				    /*LINTED align*/
1526*3ee4fc2aSCody Peter Mello 				    STR|NUM, (Array *)ap->sval);
1527*3ee4fc2aSCody Peter Mello 			} else {
1528*3ee4fc2aSCody Peter Mello 				(void) setsymtab(num, buf, 0.0,
1529*3ee4fc2aSCody Peter Mello 				    /*LINTED align*/
1530*3ee4fc2aSCody Peter Mello 				    STR, (Array *)ap->sval);
1531*3ee4fc2aSCody Peter Mello 			}
1532*3ee4fc2aSCody Peter Mello 		}
1533*3ee4fc2aSCody Peter Mello 	} else if (*s != '\0') {
15347c478bd9Sstevel@tonic-gate 		for (;;) {
15357c478bd9Sstevel@tonic-gate 			n++;
15367c478bd9Sstevel@tonic-gate 			t = s;
15377c478bd9Sstevel@tonic-gate 			while (*s != sep && *s != '\n' && *s != '\0')
15387c478bd9Sstevel@tonic-gate 				s++;
15397c478bd9Sstevel@tonic-gate 			temp = *s;
15407c478bd9Sstevel@tonic-gate 			*s = '\0';
1541*3ee4fc2aSCody Peter Mello 			(void) sprintf(num, "%d", n);
15421ee2e5faSnakanon 			if (is_number(t)) {
1543*3ee4fc2aSCody Peter Mello 				(void) setsymtab(num, t, atof(t),
15441ee2e5faSnakanon 				    /*LINTED align*/
15451ee2e5faSnakanon 				    STR|NUM, (Array *)ap->sval);
15461ee2e5faSnakanon 			} else {
15471ee2e5faSnakanon 				(void) setsymtab(num, t, 0.0,
15481ee2e5faSnakanon 				    /*LINTED align*/
15491ee2e5faSnakanon 				    STR, (Array *)ap->sval);
15501ee2e5faSnakanon 			}
15517c478bd9Sstevel@tonic-gate 			*s = temp;
1552*3ee4fc2aSCody Peter Mello 			if (*s++ == '\0')
15537c478bd9Sstevel@tonic-gate 				break;
15547c478bd9Sstevel@tonic-gate 		}
15557c478bd9Sstevel@tonic-gate 	}
1556*3ee4fc2aSCody Peter Mello 	tempfree(ap);
1557*3ee4fc2aSCody Peter Mello 	tempfree(y);
1558*3ee4fc2aSCody Peter Mello 	free(origs);
1559*3ee4fc2aSCody Peter Mello 	free(origfs);
1560*3ee4fc2aSCody Peter Mello 	x = gettemp();
15617c478bd9Sstevel@tonic-gate 	x->tval = NUM;
15627c478bd9Sstevel@tonic-gate 	x->fval = n;
15631ee2e5faSnakanon 	return (x);
15647c478bd9Sstevel@tonic-gate }
15657c478bd9Sstevel@tonic-gate 
15661ee2e5faSnakanon /*ARGSUSED*/
15671ee2e5faSnakanon Cell *
condexpr(Node ** a,int n)1568*3ee4fc2aSCody Peter Mello condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
15697c478bd9Sstevel@tonic-gate {
1570*3ee4fc2aSCody Peter Mello 	Cell *x;
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
15737c478bd9Sstevel@tonic-gate 	if (istrue(x)) {
1574*3ee4fc2aSCody Peter Mello 		tempfree(x);
15757c478bd9Sstevel@tonic-gate 		x = execute(a[1]);
15767c478bd9Sstevel@tonic-gate 	} else {
1577*3ee4fc2aSCody Peter Mello 		tempfree(x);
15787c478bd9Sstevel@tonic-gate 		x = execute(a[2]);
15797c478bd9Sstevel@tonic-gate 	}
15801ee2e5faSnakanon 	return (x);
15817c478bd9Sstevel@tonic-gate }
15827c478bd9Sstevel@tonic-gate 
15831ee2e5faSnakanon /*ARGSUSED*/
15841ee2e5faSnakanon Cell *
ifstat(Node ** a,int n)1585*3ee4fc2aSCody Peter Mello ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
15867c478bd9Sstevel@tonic-gate {
1587*3ee4fc2aSCody Peter Mello 	Cell *x;
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
15907c478bd9Sstevel@tonic-gate 	if (istrue(x)) {
1591*3ee4fc2aSCody Peter Mello 		tempfree(x);
15927c478bd9Sstevel@tonic-gate 		x = execute(a[1]);
1593*3ee4fc2aSCody Peter Mello 	} else if (a[2] != NULL) {
1594*3ee4fc2aSCody Peter Mello 		tempfree(x);
15957c478bd9Sstevel@tonic-gate 		x = execute(a[2]);
15967c478bd9Sstevel@tonic-gate 	}
15971ee2e5faSnakanon 	return (x);
15987c478bd9Sstevel@tonic-gate }
15997c478bd9Sstevel@tonic-gate 
16001ee2e5faSnakanon /*ARGSUSED*/
16011ee2e5faSnakanon Cell *
whilestat(Node ** a,int n)1602*3ee4fc2aSCody Peter Mello whilestat(Node **a, int n)	/* while (a[0]) a[1] */
16037c478bd9Sstevel@tonic-gate {
1604*3ee4fc2aSCody Peter Mello 	Cell *x;
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	for (;;) {
16077c478bd9Sstevel@tonic-gate 		x = execute(a[0]);
16087c478bd9Sstevel@tonic-gate 		if (!istrue(x))
16091ee2e5faSnakanon 			return (x);
1610*3ee4fc2aSCody Peter Mello 		tempfree(x);
16117c478bd9Sstevel@tonic-gate 		x = execute(a[1]);
16127c478bd9Sstevel@tonic-gate 		if (isbreak(x)) {
1613*3ee4fc2aSCody Peter Mello 			x = True;
16141ee2e5faSnakanon 			return (x);
16157c478bd9Sstevel@tonic-gate 		}
16167c478bd9Sstevel@tonic-gate 		if (isnext(x) || isexit(x) || isret(x))
16171ee2e5faSnakanon 			return (x);
1618*3ee4fc2aSCody Peter Mello 		tempfree(x);
16197c478bd9Sstevel@tonic-gate 	}
16207c478bd9Sstevel@tonic-gate }
16217c478bd9Sstevel@tonic-gate 
16221ee2e5faSnakanon /*ARGSUSED*/
16231ee2e5faSnakanon Cell *
dostat(Node ** a,int n)1624*3ee4fc2aSCody Peter Mello dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
16257c478bd9Sstevel@tonic-gate {
1626*3ee4fc2aSCody Peter Mello 	Cell *x;
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 	for (;;) {
16297c478bd9Sstevel@tonic-gate 		x = execute(a[0]);
16307c478bd9Sstevel@tonic-gate 		if (isbreak(x))
1631*3ee4fc2aSCody Peter Mello 			return (True);
16327c478bd9Sstevel@tonic-gate 		if (isnext(x) || isexit(x) || isret(x))
16331ee2e5faSnakanon 			return (x);
1634*3ee4fc2aSCody Peter Mello 		tempfree(x);
16357c478bd9Sstevel@tonic-gate 		x = execute(a[1]);
16367c478bd9Sstevel@tonic-gate 		if (!istrue(x))
16371ee2e5faSnakanon 			return (x);
1638*3ee4fc2aSCody Peter Mello 		tempfree(x);
16397c478bd9Sstevel@tonic-gate 	}
16407c478bd9Sstevel@tonic-gate }
16417c478bd9Sstevel@tonic-gate 
16421ee2e5faSnakanon /*ARGSUSED*/
16431ee2e5faSnakanon Cell *
forstat(Node ** a,int n)1644*3ee4fc2aSCody Peter Mello forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
16457c478bd9Sstevel@tonic-gate {
1646*3ee4fc2aSCody Peter Mello 	Cell *x;
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
1649*3ee4fc2aSCody Peter Mello 	tempfree(x);
16507c478bd9Sstevel@tonic-gate 	for (;;) {
1651*3ee4fc2aSCody Peter Mello 		if (a[1] != NULL) {
16527c478bd9Sstevel@tonic-gate 			x = execute(a[1]);
16531ee2e5faSnakanon 			if (!istrue(x))
16541ee2e5faSnakanon 				return (x);
16551ee2e5faSnakanon 			else
1656*3ee4fc2aSCody Peter Mello 				tempfree(x);
16577c478bd9Sstevel@tonic-gate 		}
16587c478bd9Sstevel@tonic-gate 		x = execute(a[3]);
16597c478bd9Sstevel@tonic-gate 		if (isbreak(x))		/* turn off break */
1660*3ee4fc2aSCody Peter Mello 			return (True);
16617c478bd9Sstevel@tonic-gate 		if (isnext(x) || isexit(x) || isret(x))
16621ee2e5faSnakanon 			return (x);
1663*3ee4fc2aSCody Peter Mello 		tempfree(x);
16647c478bd9Sstevel@tonic-gate 		x = execute(a[2]);
1665*3ee4fc2aSCody Peter Mello 		tempfree(x);
16667c478bd9Sstevel@tonic-gate 	}
16677c478bd9Sstevel@tonic-gate }
16687c478bd9Sstevel@tonic-gate 
16691ee2e5faSnakanon /*ARGSUSED*/
16701ee2e5faSnakanon Cell *
instat(Node ** a,int n)1671*3ee4fc2aSCody Peter Mello instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
16727c478bd9Sstevel@tonic-gate {
1673*3ee4fc2aSCody Peter Mello 	Cell *x, *vp, *arrayp, *cp, *ncp;
16747c478bd9Sstevel@tonic-gate 	Array *tp;
16757c478bd9Sstevel@tonic-gate 	int i;
16767c478bd9Sstevel@tonic-gate 
16777c478bd9Sstevel@tonic-gate 	vp = execute(a[0]);
16787c478bd9Sstevel@tonic-gate 	arrayp = execute(a[1]);
1679*3ee4fc2aSCody Peter Mello 	if (!isarr(arrayp)) {
1680*3ee4fc2aSCody Peter Mello 		dprintf(("making %s into an array\n", arrayp->nval));
1681*3ee4fc2aSCody Peter Mello 		if (freeable(arrayp))
1682*3ee4fc2aSCody Peter Mello 			xfree(arrayp->sval);
1683*3ee4fc2aSCody Peter Mello 		arrayp->tval &= ~(STR|NUM|DONTFREE);
1684*3ee4fc2aSCody Peter Mello 		arrayp->tval |= ARR;
1685*3ee4fc2aSCody Peter Mello 		arrayp->sval = (char *)makesymtab(NSYMTAB);
1686*3ee4fc2aSCody Peter Mello 	}
16871ee2e5faSnakanon 	/*LINTED align*/
16881ee2e5faSnakanon 	tp = (Array *)arrayp->sval;
1689*3ee4fc2aSCody Peter Mello 	tempfree(arrayp);
16901ee2e5faSnakanon 	for (i = 0; i < tp->size; i++) { /* this routine knows too much */
16917c478bd9Sstevel@tonic-gate 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
16921ee2e5faSnakanon 			(void) setsval(vp, cp->nval);
16937c478bd9Sstevel@tonic-gate 			ncp = cp->cnext;
16947c478bd9Sstevel@tonic-gate 			x = execute(a[2]);
16957c478bd9Sstevel@tonic-gate 			if (isbreak(x)) {
1696*3ee4fc2aSCody Peter Mello 				tempfree(vp);
1697*3ee4fc2aSCody Peter Mello 				return (True);
16987c478bd9Sstevel@tonic-gate 			}
16997c478bd9Sstevel@tonic-gate 			if (isnext(x) || isexit(x) || isret(x)) {
1700*3ee4fc2aSCody Peter Mello 				tempfree(vp);
17011ee2e5faSnakanon 				return (x);
17027c478bd9Sstevel@tonic-gate 			}
1703*3ee4fc2aSCody Peter Mello 			tempfree(x);
17047c478bd9Sstevel@tonic-gate 		}
17057c478bd9Sstevel@tonic-gate 	}
1706*3ee4fc2aSCody Peter Mello 	return (True);
17077c478bd9Sstevel@tonic-gate }
17087c478bd9Sstevel@tonic-gate 
17091ee2e5faSnakanon /*ARGSUSED*/
17101ee2e5faSnakanon Cell *
bltin(Node ** a,int n)1711*3ee4fc2aSCody Peter Mello bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
17127c478bd9Sstevel@tonic-gate {
1713*3ee4fc2aSCody Peter Mello 	Cell *x, *y;
17147c478bd9Sstevel@tonic-gate 	Awkfloat u;
1715*3ee4fc2aSCody Peter Mello 	int t;
1716*3ee4fc2aSCody Peter Mello 	Awkfloat tmp;
1717*3ee4fc2aSCody Peter Mello 	char *p, *buf;
17187c478bd9Sstevel@tonic-gate 	Node *nextarg;
1719*3ee4fc2aSCody Peter Mello 	FILE *fp;
1720*3ee4fc2aSCody Peter Mello 	void flush_all(void);
1721*3ee4fc2aSCody Peter Mello 	int status = 0;
17227c478bd9Sstevel@tonic-gate 
1723*3ee4fc2aSCody Peter Mello 	t = ptoi(a[0]);
17247c478bd9Sstevel@tonic-gate 	x = execute(a[1]);
17257c478bd9Sstevel@tonic-gate 	nextarg = a[1]->nnext;
17267c478bd9Sstevel@tonic-gate 	switch (t) {
17277c478bd9Sstevel@tonic-gate 	case FLENGTH:
1728*3ee4fc2aSCody Peter Mello 		if (isarr(x)) {
1729*3ee4fc2aSCody Peter Mello 			/* LINTED align */
1730*3ee4fc2aSCody Peter Mello 			u = ((Array *)x->sval)->nelem;
1731*3ee4fc2aSCody Peter Mello 		} else {
1732*3ee4fc2aSCody Peter Mello 			u = strlen(getsval(x));
1733*3ee4fc2aSCody Peter Mello 		}
1734*3ee4fc2aSCody Peter Mello 		break;
17357c478bd9Sstevel@tonic-gate 	case FLOG:
17367c478bd9Sstevel@tonic-gate 		u = errcheck(log(getfval(x)), "log"); break;
17377c478bd9Sstevel@tonic-gate 	case FINT:
17381ee2e5faSnakanon 		(void) modf(getfval(x), &u); break;
17397c478bd9Sstevel@tonic-gate 	case FEXP:
17407c478bd9Sstevel@tonic-gate 		u = errcheck(exp(getfval(x)), "exp"); break;
17417c478bd9Sstevel@tonic-gate 	case FSQRT:
17427c478bd9Sstevel@tonic-gate 		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
17437c478bd9Sstevel@tonic-gate 	case FSIN:
17447c478bd9Sstevel@tonic-gate 		u = sin(getfval(x)); break;
17457c478bd9Sstevel@tonic-gate 	case FCOS:
17467c478bd9Sstevel@tonic-gate 		u = cos(getfval(x)); break;
17477c478bd9Sstevel@tonic-gate 	case FATAN:
1748*3ee4fc2aSCody Peter Mello 		if (nextarg == NULL) {
1749*3ee4fc2aSCody Peter Mello 			WARNING("atan2 requires two arguments; returning 1.0");
17507c478bd9Sstevel@tonic-gate 			u = 1.0;
17517c478bd9Sstevel@tonic-gate 		} else {
17527c478bd9Sstevel@tonic-gate 			y = execute(a[1]->nnext);
17537c478bd9Sstevel@tonic-gate 			u = atan2(getfval(x), getfval(y));
1754*3ee4fc2aSCody Peter Mello 			tempfree(y);
17557c478bd9Sstevel@tonic-gate 			nextarg = nextarg->nnext;
17567c478bd9Sstevel@tonic-gate 		}
17577c478bd9Sstevel@tonic-gate 		break;
17587c478bd9Sstevel@tonic-gate 	case FSYSTEM:
17591ee2e5faSnakanon 		/* in case something is buffered already */
17601ee2e5faSnakanon 		(void) fflush(stdout);
1761*3ee4fc2aSCody Peter Mello 		status = system(getsval(x));
1762*3ee4fc2aSCody Peter Mello 		u = status;
1763*3ee4fc2aSCody Peter Mello 		if (status != -1) {
1764*3ee4fc2aSCody Peter Mello 			if (WIFEXITED(status)) {
1765*3ee4fc2aSCody Peter Mello 				u = WEXITSTATUS(status);
1766*3ee4fc2aSCody Peter Mello 			} else if (WIFSIGNALED(status)) {
1767*3ee4fc2aSCody Peter Mello 				u = WTERMSIG(status) + 256;
1768*3ee4fc2aSCody Peter Mello 				if (WCOREDUMP(status))
1769*3ee4fc2aSCody Peter Mello 					u += 256;
1770*3ee4fc2aSCody Peter Mello 			} else	/* something else?!? */
1771*3ee4fc2aSCody Peter Mello 				u = 0;
1772*3ee4fc2aSCody Peter Mello 		}
17737c478bd9Sstevel@tonic-gate 		break;
17747c478bd9Sstevel@tonic-gate 	case FRAND:
1775*3ee4fc2aSCody Peter Mello 		/* in principle, rand() returns something in 0..RAND_MAX */
1776*3ee4fc2aSCody Peter Mello 		u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
17777c478bd9Sstevel@tonic-gate 		break;
17787c478bd9Sstevel@tonic-gate 	case FSRAND:
1779*3ee4fc2aSCody Peter Mello 		if (isrec(x))	/* no argument provided */
17807c478bd9Sstevel@tonic-gate 			u = time((time_t *)0);
17817c478bd9Sstevel@tonic-gate 		else
17827c478bd9Sstevel@tonic-gate 			u = getfval(x);
1783*3ee4fc2aSCody Peter Mello 		tmp = u;
1784*3ee4fc2aSCody Peter Mello 		srand((unsigned int) u);
1785*3ee4fc2aSCody Peter Mello 		u = srand_seed;
1786*3ee4fc2aSCody Peter Mello 		srand_seed = tmp;
17877c478bd9Sstevel@tonic-gate 		break;
17887c478bd9Sstevel@tonic-gate 	case FTOUPPER:
17897c478bd9Sstevel@tonic-gate 	case FTOLOWER:
17901ee2e5faSnakanon 		buf = tostring(getsval(x));
17917c478bd9Sstevel@tonic-gate 		if (t == FTOUPPER) {
17927c478bd9Sstevel@tonic-gate 			for (p = buf; *p; p++)
1793*3ee4fc2aSCody Peter Mello 				if (islower((uschar)*p))
1794*3ee4fc2aSCody Peter Mello 					*p = toupper((uschar)*p);
17957c478bd9Sstevel@tonic-gate 		} else {
17967c478bd9Sstevel@tonic-gate 			for (p = buf; *p; p++)
1797*3ee4fc2aSCody Peter Mello 				if (isupper((uschar)*p))
1798*3ee4fc2aSCody Peter Mello 					*p = tolower((uschar)*p);
17997c478bd9Sstevel@tonic-gate 		}
1800*3ee4fc2aSCody Peter Mello 		tempfree(x);
1801*3ee4fc2aSCody Peter Mello 		x = gettemp();
18021ee2e5faSnakanon 		(void) setsval(x, buf);
18031ee2e5faSnakanon 		free(buf);
18041ee2e5faSnakanon 		return (x);
1805*3ee4fc2aSCody Peter Mello 	case FFLUSH:
1806*3ee4fc2aSCody Peter Mello 		if (isrec(x) || strlen(getsval(x)) == 0) {
1807*3ee4fc2aSCody Peter Mello 			flush_all();	/* fflush() or fflush("") -> all */
1808*3ee4fc2aSCody Peter Mello 			u = 0;
1809*3ee4fc2aSCody Peter Mello 		} else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
1810*3ee4fc2aSCody Peter Mello 			u = EOF;
1811*3ee4fc2aSCody Peter Mello 		else
1812*3ee4fc2aSCody Peter Mello 			u = fflush(fp);
1813*3ee4fc2aSCody Peter Mello 		break;
18147c478bd9Sstevel@tonic-gate 	default:	/* can't happen */
1815*3ee4fc2aSCody Peter Mello 		FATAL("illegal function type %d", t);
18167c478bd9Sstevel@tonic-gate 		break;
18177c478bd9Sstevel@tonic-gate 	}
1818*3ee4fc2aSCody Peter Mello 	tempfree(x);
1819*3ee4fc2aSCody Peter Mello 	x = gettemp();
18201ee2e5faSnakanon 	(void) setfval(x, u);
1821*3ee4fc2aSCody Peter Mello 	if (nextarg != NULL) {
1822*3ee4fc2aSCody Peter Mello 		WARNING("warning: function has too many arguments");
1823*3ee4fc2aSCody Peter Mello 		for (; nextarg != NULL; nextarg = nextarg->nnext)
18241ee2e5faSnakanon 			(void) execute(nextarg);
18257c478bd9Sstevel@tonic-gate 	}
18261ee2e5faSnakanon 	return (x);
18277c478bd9Sstevel@tonic-gate }
18287c478bd9Sstevel@tonic-gate 
18291ee2e5faSnakanon /*ARGSUSED*/
18301ee2e5faSnakanon Cell *
printstat(Node ** a,int n)1831*3ee4fc2aSCody Peter Mello printstat(Node **a, int n)	/* print a[0] */
18327c478bd9Sstevel@tonic-gate {
1833*3ee4fc2aSCody Peter Mello 	Node *x;
1834*3ee4fc2aSCody Peter Mello 	Cell *y;
18357c478bd9Sstevel@tonic-gate 	FILE *fp;
18367c478bd9Sstevel@tonic-gate 
1837*3ee4fc2aSCody Peter Mello 	if (a[1] == NULL)	/* a[1] is redirection operator, a[2] is file */
18387c478bd9Sstevel@tonic-gate 		fp = stdout;
18397c478bd9Sstevel@tonic-gate 	else
1840*3ee4fc2aSCody Peter Mello 		fp = redirect(ptoi(a[1]), a[2]);
18417c478bd9Sstevel@tonic-gate 	for (x = a[0]; x != NULL; x = x->nnext) {
18427c478bd9Sstevel@tonic-gate 		y = execute(x);
1843*3ee4fc2aSCody Peter Mello 		(void) fputs(getpssval(y), fp);
1844*3ee4fc2aSCody Peter Mello 		tempfree(y);
18457c478bd9Sstevel@tonic-gate 		if (x->nnext == NULL)
1846*3ee4fc2aSCody Peter Mello 			(void) fputs(getsval(orsloc), fp);
18477c478bd9Sstevel@tonic-gate 		else
1848*3ee4fc2aSCody Peter Mello 			(void) fputs(getsval(ofsloc), fp);
18497c478bd9Sstevel@tonic-gate 	}
1850*3ee4fc2aSCody Peter Mello 	if (a[1] != NULL)
18511ee2e5faSnakanon 		(void) fflush(fp);
1852*3ee4fc2aSCody Peter Mello 	if (ferror(fp))
1853*3ee4fc2aSCody Peter Mello 		FATAL("write error on %s", filename(fp));
1854*3ee4fc2aSCody Peter Mello 	return (True);
18557c478bd9Sstevel@tonic-gate }
18567c478bd9Sstevel@tonic-gate 
18571ee2e5faSnakanon /*ARGSUSED*/
18581ee2e5faSnakanon Cell *
nullproc(Node ** a,int n)18591ee2e5faSnakanon nullproc(Node **a, int n)
18607c478bd9Sstevel@tonic-gate {
18611ee2e5faSnakanon 	return (0);
18621ee2e5faSnakanon }
18631ee2e5faSnakanon 
18647c478bd9Sstevel@tonic-gate 
18651ee2e5faSnakanon static FILE *
redirect(int a,Node * b)1866*3ee4fc2aSCody Peter Mello redirect(int a, Node *b)	/* set up all i/o redirections */
18677c478bd9Sstevel@tonic-gate {
18687c478bd9Sstevel@tonic-gate 	FILE *fp;
18697c478bd9Sstevel@tonic-gate 	Cell *x;
1870*3ee4fc2aSCody Peter Mello 	char *fname;
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 	x = execute(b);
18737c478bd9Sstevel@tonic-gate 	fname = getsval(x);
18747c478bd9Sstevel@tonic-gate 	fp = openfile(a, fname);
18757c478bd9Sstevel@tonic-gate 	if (fp == NULL)
1876*3ee4fc2aSCody Peter Mello 		FATAL("can't open file %s", fname);
1877*3ee4fc2aSCody Peter Mello 	tempfree(x);
18781ee2e5faSnakanon 	return (fp);
18797c478bd9Sstevel@tonic-gate }
18807c478bd9Sstevel@tonic-gate 
1881*3ee4fc2aSCody Peter Mello struct files {
1882*3ee4fc2aSCody Peter Mello 	FILE	*fp;
1883*3ee4fc2aSCody Peter Mello 	const char	*fname;
1884*3ee4fc2aSCody Peter Mello 	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
1885*3ee4fc2aSCody Peter Mello } *files;
1886*3ee4fc2aSCody Peter Mello 
1887*3ee4fc2aSCody Peter Mello int nfiles;
1888*3ee4fc2aSCody Peter Mello 
1889*3ee4fc2aSCody Peter Mello void
stdinit(void)1890*3ee4fc2aSCody Peter Mello stdinit(void)	/* in case stdin, etc., are not constants */
1891*3ee4fc2aSCody Peter Mello {
1892*3ee4fc2aSCody Peter Mello 	nfiles = FOPEN_MAX;
1893*3ee4fc2aSCody Peter Mello 	files = calloc(nfiles, sizeof (*files));
1894*3ee4fc2aSCody Peter Mello 	if (files == NULL)
1895*3ee4fc2aSCody Peter Mello 		FATAL("can't allocate file memory for %u files", nfiles);
1896*3ee4fc2aSCody Peter Mello 	files[0].fp = stdin;
1897*3ee4fc2aSCody Peter Mello 	files[0].fname = "/dev/stdin";
1898*3ee4fc2aSCody Peter Mello 	files[0].mode = LT;
1899*3ee4fc2aSCody Peter Mello 	files[1].fp = stdout;
1900*3ee4fc2aSCody Peter Mello 	files[1].fname = "/dev/stdout";
1901*3ee4fc2aSCody Peter Mello 	files[1].mode = GT;
1902*3ee4fc2aSCody Peter Mello 	files[2].fp = stderr;
1903*3ee4fc2aSCody Peter Mello 	files[2].fname = "/dev/stderr";
1904*3ee4fc2aSCody Peter Mello 	files[2].mode = GT;
1905*3ee4fc2aSCody Peter Mello }
1906*3ee4fc2aSCody Peter Mello 
19071ee2e5faSnakanon static FILE *
openfile(int a,const char * s)1908*3ee4fc2aSCody Peter Mello openfile(int a, const char *s)
19097c478bd9Sstevel@tonic-gate {
1910*3ee4fc2aSCody Peter Mello 	int i, m;
1911*3ee4fc2aSCody Peter Mello 	FILE *fp = NULL;
19127c478bd9Sstevel@tonic-gate 
19137c478bd9Sstevel@tonic-gate 	if (*s == '\0')
1914*3ee4fc2aSCody Peter Mello 		FATAL("null file name in print or getline");
1915*3ee4fc2aSCody Peter Mello 	for (i = 0; i < nfiles; i++) {
1916*3ee4fc2aSCody Peter Mello 		if (files[i].fname && strcmp(s, files[i].fname) == 0) {
19171ee2e5faSnakanon 			if (a == files[i].mode ||
1918*3ee4fc2aSCody Peter Mello 			    (a == APPEND && files[i].mode == GT)) {
19191ee2e5faSnakanon 				return (files[i].fp);
19201ee2e5faSnakanon 			}
1921*3ee4fc2aSCody Peter Mello 			if (a == FFLUSH)
1922*3ee4fc2aSCody Peter Mello 				return (files[i].fp);
19231ee2e5faSnakanon 		}
19241ee2e5faSnakanon 	}
1925*3ee4fc2aSCody Peter Mello 	if (a == FFLUSH)	/* didn't find it, so don't create it! */
1926*3ee4fc2aSCody Peter Mello 		return (NULL);
1927*3ee4fc2aSCody Peter Mello 
1928*3ee4fc2aSCody Peter Mello 	for (i = 0; i < nfiles; i++) {
19297c478bd9Sstevel@tonic-gate 		if (files[i].fp == 0)
19307c478bd9Sstevel@tonic-gate 			break;
19311ee2e5faSnakanon 	}
1932*3ee4fc2aSCody Peter Mello 	if (i >= nfiles) {
1933*3ee4fc2aSCody Peter Mello 		struct files *nf;
1934*3ee4fc2aSCody Peter Mello 		int nnf = nfiles + FOPEN_MAX;
1935*3ee4fc2aSCody Peter Mello 		nf = realloc(files, nnf * sizeof (*nf));
1936*3ee4fc2aSCody Peter Mello 		if (nf == NULL)
1937*3ee4fc2aSCody Peter Mello 			FATAL("cannot grow files for %s and %d files", s, nnf);
1938*3ee4fc2aSCody Peter Mello 		(void) memset(&nf[nfiles], 0, FOPEN_MAX * sizeof (*nf));
1939*3ee4fc2aSCody Peter Mello 		nfiles = nnf;
1940*3ee4fc2aSCody Peter Mello 		files = nf;
1941*3ee4fc2aSCody Peter Mello 	}
19421ee2e5faSnakanon 	(void) fflush(stdout);	/* force a semblance of order */
19437c478bd9Sstevel@tonic-gate 	m = a;
19447c478bd9Sstevel@tonic-gate 	if (a == GT) {
1945*3ee4fc2aSCody Peter Mello 		fp = fopen(s, "wF");
19467c478bd9Sstevel@tonic-gate 	} else if (a == APPEND) {
1947*3ee4fc2aSCody Peter Mello 		fp = fopen(s, "aF");
19487c478bd9Sstevel@tonic-gate 		m = GT;	/* so can mix > and >> */
19497c478bd9Sstevel@tonic-gate 	} else if (a == '|') {	/* output pipe */
1950*3ee4fc2aSCody Peter Mello 		fp = popen(s, "wF");
19517c478bd9Sstevel@tonic-gate 	} else if (a == LE) {	/* input pipe */
1952*3ee4fc2aSCody Peter Mello 		fp = popen(s, "rF");
19537c478bd9Sstevel@tonic-gate 	} else if (a == LT) {	/* getline <file */
1954*3ee4fc2aSCody Peter Mello 		fp = strcmp(s, "-") == 0 ?
1955*3ee4fc2aSCody Peter Mello 		    stdin : fopen(s, "rF");	/* "-" is stdin */
19567c478bd9Sstevel@tonic-gate 	} else	/* can't happen */
1957*3ee4fc2aSCody Peter Mello 		FATAL("illegal redirection %d", a);
19587c478bd9Sstevel@tonic-gate 	if (fp != NULL) {
19597c478bd9Sstevel@tonic-gate 		files[i].fname = tostring(s);
19607c478bd9Sstevel@tonic-gate 		files[i].fp = fp;
19617c478bd9Sstevel@tonic-gate 		files[i].mode = m;
19627c478bd9Sstevel@tonic-gate 	}
19631ee2e5faSnakanon 	return (fp);
19647c478bd9Sstevel@tonic-gate }
19657c478bd9Sstevel@tonic-gate 
1966*3ee4fc2aSCody Peter Mello const char *
filename(FILE * fp)1967*3ee4fc2aSCody Peter Mello filename(FILE *fp)
1968*3ee4fc2aSCody Peter Mello {
1969*3ee4fc2aSCody Peter Mello 	int i;
1970*3ee4fc2aSCody Peter Mello 
1971*3ee4fc2aSCody Peter Mello 	for (i = 0; i < nfiles; i++)
1972*3ee4fc2aSCody Peter Mello 		if (fp == files[i].fp)
1973*3ee4fc2aSCody Peter Mello 			return (files[i].fname);
1974*3ee4fc2aSCody Peter Mello 	return ("???");
1975*3ee4fc2aSCody Peter Mello }
1976*3ee4fc2aSCody Peter Mello 
19771ee2e5faSnakanon /*ARGSUSED*/
19781ee2e5faSnakanon Cell *
closefile(Node ** a,int n)19791ee2e5faSnakanon closefile(Node **a, int n)
19807c478bd9Sstevel@tonic-gate {
1981*3ee4fc2aSCody Peter Mello 	Cell *x;
19827c478bd9Sstevel@tonic-gate 	int i, stat;
19837c478bd9Sstevel@tonic-gate 
19847c478bd9Sstevel@tonic-gate 	x = execute(a[0]);
19851ee2e5faSnakanon 	(void) getsval(x);
1986*3ee4fc2aSCody Peter Mello 	stat = -1;
1987*3ee4fc2aSCody Peter Mello 	for (i = 0; i < nfiles; i++) {
1988*3ee4fc2aSCody Peter Mello 		if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
19891ee2e5faSnakanon 			if (ferror(files[i].fp)) {
1990*3ee4fc2aSCody Peter Mello 				WARNING("i/o error occurred on %s",
1991*3ee4fc2aSCody Peter Mello 				    files[i].fname);
19921ee2e5faSnakanon 			}
19937c478bd9Sstevel@tonic-gate 			if (files[i].mode == '|' || files[i].mode == LE)
19947c478bd9Sstevel@tonic-gate 				stat = pclose(files[i].fp);
19957c478bd9Sstevel@tonic-gate 			else
19967c478bd9Sstevel@tonic-gate 				stat = fclose(files[i].fp);
19971ee2e5faSnakanon 			if (stat == EOF) {
1998*3ee4fc2aSCody Peter Mello 				WARNING("i/o error occurred closing %s",
1999*3ee4fc2aSCody Peter Mello 				    files[i].fname);
20001ee2e5faSnakanon 			}
2001*3ee4fc2aSCody Peter Mello 			if (i > 2)	/* don't do /dev/std... */
2002*3ee4fc2aSCody Peter Mello 				xfree(files[i].fname);
20031ee2e5faSnakanon 			/* watch out for ref thru this */
20041ee2e5faSnakanon 			files[i].fname = NULL;
20057c478bd9Sstevel@tonic-gate 			files[i].fp = NULL;
20067c478bd9Sstevel@tonic-gate 		}
20071ee2e5faSnakanon 	}
2008*3ee4fc2aSCody Peter Mello 	tempfree(x);
2009*3ee4fc2aSCody Peter Mello 	x = gettemp();
2010*3ee4fc2aSCody Peter Mello 	(void) setfval(x, (Awkfloat) stat);
2011*3ee4fc2aSCody Peter Mello 	return (x);
20127c478bd9Sstevel@tonic-gate }
20137c478bd9Sstevel@tonic-gate 
20141ee2e5faSnakanon static void
closeall(void)20151ee2e5faSnakanon closeall(void)
20167c478bd9Sstevel@tonic-gate {
20177c478bd9Sstevel@tonic-gate 	int i, stat;
20187c478bd9Sstevel@tonic-gate 
2019*3ee4fc2aSCody Peter Mello 	for (i = 0; i < nfiles; i++) {
20207c478bd9Sstevel@tonic-gate 		if (files[i].fp) {
20211ee2e5faSnakanon 			if (ferror(files[i].fp)) {
2022*3ee4fc2aSCody Peter Mello 				WARNING("i/o error occurred on %s",
2023*3ee4fc2aSCody Peter Mello 				    files[i].fname);
20241ee2e5faSnakanon 			}
20257c478bd9Sstevel@tonic-gate 			if (files[i].mode == '|' || files[i].mode == LE)
20267c478bd9Sstevel@tonic-gate 				stat = pclose(files[i].fp);
20277c478bd9Sstevel@tonic-gate 			else
20287c478bd9Sstevel@tonic-gate 				stat = fclose(files[i].fp);
20291ee2e5faSnakanon 			if (stat == EOF) {
2030*3ee4fc2aSCody Peter Mello 				WARNING("i/o error occurred while closing %s",
2031*3ee4fc2aSCody Peter Mello 				    files[i].fname);
20321ee2e5faSnakanon 			}
20337c478bd9Sstevel@tonic-gate 		}
20341ee2e5faSnakanon 	}
20357c478bd9Sstevel@tonic-gate }
20367c478bd9Sstevel@tonic-gate 
2037*3ee4fc2aSCody Peter Mello void
flush_all(void)2038*3ee4fc2aSCody Peter Mello flush_all(void)
2039*3ee4fc2aSCody Peter Mello {
2040*3ee4fc2aSCody Peter Mello 	int i;
2041*3ee4fc2aSCody Peter Mello 
2042*3ee4fc2aSCody Peter Mello 	for (i = 0; i < nfiles; i++)
2043*3ee4fc2aSCody Peter Mello 		if (files[i].fp)
2044*3ee4fc2aSCody Peter Mello 			(void) fflush(files[i].fp);
2045*3ee4fc2aSCody Peter Mello }
2046*3ee4fc2aSCody Peter Mello 
20471ee2e5faSnakanon /*ARGSUSED*/
20481ee2e5faSnakanon Cell *
sub(Node ** a,int nnn)2049*3ee4fc2aSCody Peter Mello sub(Node **a, int nnn)	/* substitute command */
20507c478bd9Sstevel@tonic-gate {
2051*3ee4fc2aSCody Peter Mello 	char *sptr, *pb, *q;
2052*3ee4fc2aSCody Peter Mello 	Cell *x, *y, *result;
2053*3ee4fc2aSCody Peter Mello 	char *t, *buf;
20547c478bd9Sstevel@tonic-gate 	fa *pfa;
2055*3ee4fc2aSCody Peter Mello 	size_t bufsz = recsize;
20567c478bd9Sstevel@tonic-gate 
2057*3ee4fc2aSCody Peter Mello 	if ((buf = (char *)malloc(bufsz)) == NULL)
2058*3ee4fc2aSCody Peter Mello 		FATAL("out of memory in sub");
20597c478bd9Sstevel@tonic-gate 	x = execute(a[3]);	/* target string */
20607c478bd9Sstevel@tonic-gate 	t = getsval(x);
2061*3ee4fc2aSCody Peter Mello 	if (a[0] == NULL)	/* 0 => a[1] is already-compiled regexpr */
20621ee2e5faSnakanon 		pfa = (fa *)a[1];	/* regular expression */
20637c478bd9Sstevel@tonic-gate 	else {
20647c478bd9Sstevel@tonic-gate 		y = execute(a[1]);
20657c478bd9Sstevel@tonic-gate 		pfa = makedfa(getsval(y), 1);
2066*3ee4fc2aSCody Peter Mello 		tempfree(y);
20677c478bd9Sstevel@tonic-gate 	}
20687c478bd9Sstevel@tonic-gate 	y = execute(a[2]);	/* replacement string */
2069*3ee4fc2aSCody Peter Mello 	result = False;
20707c478bd9Sstevel@tonic-gate 	if (pmatch(pfa, t)) {
20717c478bd9Sstevel@tonic-gate 		sptr = t;
2072*3ee4fc2aSCody Peter Mello 		(void) adjbuf(&buf, &bufsz,
2073*3ee4fc2aSCody Peter Mello 		    1 + patbeg - sptr, recsize, 0, "sub");
2074*3ee4fc2aSCody Peter Mello 		pb = buf;
2075*3ee4fc2aSCody Peter Mello 		while (sptr < patbeg)
2076*3ee4fc2aSCody Peter Mello 			*pb++ = *sptr++;
20777c478bd9Sstevel@tonic-gate 		sptr = getsval(y);
2078*3ee4fc2aSCody Peter Mello 		while (*sptr != '\0') {
2079*3ee4fc2aSCody Peter Mello 			(void) adjbuf(&buf, &bufsz, 5 + pb - buf,
2080*3ee4fc2aSCody Peter Mello 			    recsize, &pb, "sub");
2081*3ee4fc2aSCody Peter Mello 			if (*sptr == '\\') {
2082*3ee4fc2aSCody Peter Mello 				backsub(&pb, &sptr);
20837c478bd9Sstevel@tonic-gate 			} else if (*sptr == '&') {
20847c478bd9Sstevel@tonic-gate 				sptr++;
2085*3ee4fc2aSCody Peter Mello 				(void) adjbuf(&buf, &bufsz,
2086*3ee4fc2aSCody Peter Mello 				    1 + patlen + pb - buf, recsize, &pb, "sub");
2087*3ee4fc2aSCody Peter Mello 				for (q = patbeg; q < patbeg+patlen; )
2088*3ee4fc2aSCody Peter Mello 					*pb++ = *q++;
20891ee2e5faSnakanon 			} else {
2090*3ee4fc2aSCody Peter Mello 				*pb++ = *sptr++;
20911ee2e5faSnakanon 			}
20921ee2e5faSnakanon 		}
2093*3ee4fc2aSCody Peter Mello 		*pb = '\0';
2094*3ee4fc2aSCody Peter Mello 		if (pb > buf + bufsz)
2095*3ee4fc2aSCody Peter Mello 			FATAL("sub result1 %.30s too big; can't happen", buf);
20967c478bd9Sstevel@tonic-gate 		sptr = patbeg + patlen;
20971ee2e5faSnakanon 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
2098*3ee4fc2aSCody Peter Mello 			(void) adjbuf(&buf, &bufsz,
2099*3ee4fc2aSCody Peter Mello 			    1 + strlen(sptr) + pb - buf, 0, &pb, "sub");
2100*3ee4fc2aSCody Peter Mello 			while ((*pb++ = *sptr++) != '\0')
2101*3ee4fc2aSCody Peter Mello 				;
21021ee2e5faSnakanon 		}
2103*3ee4fc2aSCody Peter Mello 		if (pb > buf + bufsz)
2104*3ee4fc2aSCody Peter Mello 			FATAL("sub result2 %.30s too big; can't happen", buf);
2105*3ee4fc2aSCody Peter Mello 		(void) setsval(x, buf);	/* BUG: should be able to avoid copy */
2106*3ee4fc2aSCody Peter Mello 		result = True;
21077c478bd9Sstevel@tonic-gate 	}
2108*3ee4fc2aSCody Peter Mello 	tempfree(x);
2109*3ee4fc2aSCody Peter Mello 	tempfree(y);
2110*3ee4fc2aSCody Peter Mello 	free(buf);
21111ee2e5faSnakanon 	return (result);
21127c478bd9Sstevel@tonic-gate }
21137c478bd9Sstevel@tonic-gate 
21141ee2e5faSnakanon /*ARGSUSED*/
21151ee2e5faSnakanon Cell *
gsub(Node ** a,int nnn)2116*3ee4fc2aSCody Peter Mello gsub(Node **a, int nnn)	/* global substitute */
21177c478bd9Sstevel@tonic-gate {
2118*3ee4fc2aSCody Peter Mello 	Cell *x, *y;
2119*3ee4fc2aSCody Peter Mello 	char *rptr, *sptr, *t, *pb, *q;
2120*3ee4fc2aSCody Peter Mello 	char *buf;
2121*3ee4fc2aSCody Peter Mello 	fa *pfa;
21227c478bd9Sstevel@tonic-gate 	int mflag, tempstat, num;
2123*3ee4fc2aSCody Peter Mello 	size_t bufsz = recsize;
21247c478bd9Sstevel@tonic-gate 
2125*3ee4fc2aSCody Peter Mello 	if ((buf = (char *)malloc(bufsz)) == NULL)
2126*3ee4fc2aSCody Peter Mello 		FATAL("out of memory in gsub");
21277c478bd9Sstevel@tonic-gate 	mflag = 0;	/* if mflag == 0, can replace empty string */
21287c478bd9Sstevel@tonic-gate 	num = 0;
21297c478bd9Sstevel@tonic-gate 	x = execute(a[3]);	/* target string */
21307c478bd9Sstevel@tonic-gate 	t = getsval(x);
2131*3ee4fc2aSCody Peter Mello 	if (a[0] == NULL)	/* 0 => a[1] is already-compiled regexpr */
2132*3ee4fc2aSCody Peter Mello 		pfa = (fa *)a[1];	/* regular expression */
21337c478bd9Sstevel@tonic-gate 	else {
21347c478bd9Sstevel@tonic-gate 		y = execute(a[1]);
21357c478bd9Sstevel@tonic-gate 		pfa = makedfa(getsval(y), 1);
2136*3ee4fc2aSCody Peter Mello 		tempfree(y);
21377c478bd9Sstevel@tonic-gate 	}
21387c478bd9Sstevel@tonic-gate 	y = execute(a[2]);	/* replacement string */
21397c478bd9Sstevel@tonic-gate 	if (pmatch(pfa, t)) {
21407c478bd9Sstevel@tonic-gate 		tempstat = pfa->initstat;
21417c478bd9Sstevel@tonic-gate 		pfa->initstat = 2;
2142*3ee4fc2aSCody Peter Mello 		pb = buf;
21437c478bd9Sstevel@tonic-gate 		rptr = getsval(y);
21447c478bd9Sstevel@tonic-gate 		do {
2145*3ee4fc2aSCody Peter Mello 			if (patlen == 0 && *patbeg != '\0') {
21461ee2e5faSnakanon 				/* matched empty string */
21477c478bd9Sstevel@tonic-gate 				if (mflag == 0) {	/* can replace empty */
21487c478bd9Sstevel@tonic-gate 					num++;
21497c478bd9Sstevel@tonic-gate 					sptr = rptr;
2150*3ee4fc2aSCody Peter Mello 					while (*sptr != '\0') {
2151*3ee4fc2aSCody Peter Mello 						(void) adjbuf(&buf, &bufsz,
2152*3ee4fc2aSCody Peter Mello 						    5 + pb - buf, recsize,
2153*3ee4fc2aSCody Peter Mello 						    &pb, "gsub");
2154*3ee4fc2aSCody Peter Mello 						if (*sptr == '\\') {
2155*3ee4fc2aSCody Peter Mello 							backsub(&pb, &sptr);
21567c478bd9Sstevel@tonic-gate 						} else if (*sptr == '&') {
21577c478bd9Sstevel@tonic-gate 							sptr++;
2158*3ee4fc2aSCody Peter Mello 							(void) adjbuf(&buf,
2159*3ee4fc2aSCody Peter Mello 							    &bufsz,
2160*3ee4fc2aSCody Peter Mello 							    1+patlen+pb-buf,
2161*3ee4fc2aSCody Peter Mello 							    recsize,
2162*3ee4fc2aSCody Peter Mello 							    &pb, "gsub");
2163*3ee4fc2aSCody Peter Mello 							for (
2164*3ee4fc2aSCody Peter Mello 							    q = patbeg;
2165*3ee4fc2aSCody Peter Mello 							    q < patbeg+patlen;
2166*3ee4fc2aSCody Peter Mello 							    *pb++ = *q++)
2167*3ee4fc2aSCody Peter Mello 								;
21681ee2e5faSnakanon 						} else {
2169*3ee4fc2aSCody Peter Mello 							*pb++ = *sptr++;
21701ee2e5faSnakanon 						}
21711ee2e5faSnakanon 					}
21727c478bd9Sstevel@tonic-gate 				}
2173*3ee4fc2aSCody Peter Mello 				if (*t == '\0')	/* at end */
21747c478bd9Sstevel@tonic-gate 					goto done;
2175*3ee4fc2aSCody Peter Mello 				(void) adjbuf(&buf, &bufsz,
2176*3ee4fc2aSCody Peter Mello 				    2 + pb - buf, recsize, &pb, "gsub");
2177*3ee4fc2aSCody Peter Mello 				*pb++ = *t++;
2178*3ee4fc2aSCody Peter Mello 				/* BUG: not sure of this test */
2179*3ee4fc2aSCody Peter Mello 				if (pb > buf + bufsz)
2180*3ee4fc2aSCody Peter Mello 					FATAL("gsub result0 %.30s too big; "
2181*3ee4fc2aSCody Peter Mello 					    "can't happen", buf);
21827c478bd9Sstevel@tonic-gate 				mflag = 0;
21831ee2e5faSnakanon 			} else {	/* matched nonempty string */
21847c478bd9Sstevel@tonic-gate 				num++;
21857c478bd9Sstevel@tonic-gate 				sptr = t;
2186*3ee4fc2aSCody Peter Mello 				(void) adjbuf(&buf, &bufsz,
2187*3ee4fc2aSCody Peter Mello 				    1 + (patbeg - sptr) + pb - buf,
2188*3ee4fc2aSCody Peter Mello 				    recsize, &pb, "gsub");
2189*3ee4fc2aSCody Peter Mello 				while (sptr < patbeg)
2190*3ee4fc2aSCody Peter Mello 					*pb++ = *sptr++;
21917c478bd9Sstevel@tonic-gate 				sptr = rptr;
2192*3ee4fc2aSCody Peter Mello 				while (*sptr != '\0') {
2193*3ee4fc2aSCody Peter Mello 					(void) adjbuf(&buf, &bufsz,
2194*3ee4fc2aSCody Peter Mello 					    5 + pb - buf, recsize, &pb, "gsub");
2195*3ee4fc2aSCody Peter Mello 					if (*sptr == '\\') {
2196*3ee4fc2aSCody Peter Mello 						backsub(&pb, &sptr);
21977c478bd9Sstevel@tonic-gate 					} else if (*sptr == '&') {
21987c478bd9Sstevel@tonic-gate 						sptr++;
2199*3ee4fc2aSCody Peter Mello 						(void) adjbuf(&buf, &bufsz,
2200*3ee4fc2aSCody Peter Mello 						    1 + patlen + pb - buf,
2201*3ee4fc2aSCody Peter Mello 						    recsize, &pb, "gsub");
2202*3ee4fc2aSCody Peter Mello 						for (
2203*3ee4fc2aSCody Peter Mello 						    q = patbeg;
2204*3ee4fc2aSCody Peter Mello 						    q < patbeg+patlen;
2205*3ee4fc2aSCody Peter Mello 						    *pb++ = *q++)
2206*3ee4fc2aSCody Peter Mello 							;
22071ee2e5faSnakanon 					} else {
2208*3ee4fc2aSCody Peter Mello 						*pb++ = *sptr++;
22091ee2e5faSnakanon 					}
22101ee2e5faSnakanon 				}
22117c478bd9Sstevel@tonic-gate 				t = patbeg + patlen;
2212*3ee4fc2aSCody Peter Mello 				if (patlen == 0 || *(t-1) == '\0' || *t == '\0')
22137c478bd9Sstevel@tonic-gate 					goto done;
2214*3ee4fc2aSCody Peter Mello 				if (pb > buf + bufsz)
2215*3ee4fc2aSCody Peter Mello 					FATAL("gsub result1 %.30s too big; "
2216*3ee4fc2aSCody Peter Mello 					    "can't happen", buf);
22177c478bd9Sstevel@tonic-gate 				mflag = 1;
22187c478bd9Sstevel@tonic-gate 			}
22191ee2e5faSnakanon 		} while (pmatch(pfa, t));
22207c478bd9Sstevel@tonic-gate 		sptr = t;
2221*3ee4fc2aSCody Peter Mello 		(void) adjbuf(&buf, &bufsz,
2222*3ee4fc2aSCody Peter Mello 		    1 + strlen(sptr) + pb - buf, 0, &pb, "gsub");
2223*3ee4fc2aSCody Peter Mello 		while ((*pb++ = *sptr++) != '\0')
2224*3ee4fc2aSCody Peter Mello 			;
22251ee2e5faSnakanon 	done:
2226*3ee4fc2aSCody Peter Mello 		if (pb < buf + bufsz)
2227*3ee4fc2aSCody Peter Mello 			*pb = '\0';
2228*3ee4fc2aSCody Peter Mello 		else if (*(pb-1) != '\0')
2229*3ee4fc2aSCody Peter Mello 			FATAL("gsub result2 %.30s truncated; "
2230*3ee4fc2aSCody Peter Mello 			    "can't happen", buf);
2231*3ee4fc2aSCody Peter Mello 		/* BUG: should be able to avoid copy + free */
22321ee2e5faSnakanon 		(void) setsval(x, buf);
22337c478bd9Sstevel@tonic-gate 		pfa->initstat = tempstat;
22347c478bd9Sstevel@tonic-gate 	}
2235*3ee4fc2aSCody Peter Mello 	tempfree(x);
2236*3ee4fc2aSCody Peter Mello 	tempfree(y);
2237*3ee4fc2aSCody Peter Mello 	x = gettemp();
22387c478bd9Sstevel@tonic-gate 	x->tval = NUM;
22397c478bd9Sstevel@tonic-gate 	x->fval = num;
2240*3ee4fc2aSCody Peter Mello 	free(buf);
22411ee2e5faSnakanon 	return (x);
22427c478bd9Sstevel@tonic-gate }
2243*3ee4fc2aSCody Peter Mello 
2244*3ee4fc2aSCody Peter Mello /*
2245*3ee4fc2aSCody Peter Mello  * handle \\& variations; sptr[0] == '\\'
2246*3ee4fc2aSCody Peter Mello  */
2247*3ee4fc2aSCody Peter Mello static void
backsub(char ** pb_ptr,char ** sptr_ptr)2248*3ee4fc2aSCody Peter Mello backsub(char **pb_ptr, char **sptr_ptr)
2249*3ee4fc2aSCody Peter Mello {
2250*3ee4fc2aSCody Peter Mello 	char *pb = *pb_ptr, *sptr = *sptr_ptr;
2251*3ee4fc2aSCody Peter Mello 
2252*3ee4fc2aSCody Peter Mello 	if (sptr[1] == '\\') {
2253*3ee4fc2aSCody Peter Mello 		if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
2254*3ee4fc2aSCody Peter Mello 			*pb++ = '\\';
2255*3ee4fc2aSCody Peter Mello 			*pb++ = '&';
2256*3ee4fc2aSCody Peter Mello 			sptr += 4;
2257*3ee4fc2aSCody Peter Mello 		} else if (sptr[2] == '&') {	/* \\& -> \ + matched */
2258*3ee4fc2aSCody Peter Mello 			*pb++ = '\\';
2259*3ee4fc2aSCody Peter Mello 			sptr += 2;
2260*3ee4fc2aSCody Peter Mello 		} else {			/* \\x -> \\x */
2261*3ee4fc2aSCody Peter Mello 			*pb++ = *sptr++;
2262*3ee4fc2aSCody Peter Mello 			*pb++ = *sptr++;
2263*3ee4fc2aSCody Peter Mello 		}
2264*3ee4fc2aSCody Peter Mello 	} else if (sptr[1] == '&') {	/* literal & */
2265*3ee4fc2aSCody Peter Mello 		sptr++;
2266*3ee4fc2aSCody Peter Mello 		*pb++ = *sptr++;
2267*3ee4fc2aSCody Peter Mello 	} else				/* literal \ */
2268*3ee4fc2aSCody Peter Mello 		*pb++ = *sptr++;
2269*3ee4fc2aSCody Peter Mello 
2270*3ee4fc2aSCody Peter Mello 	*pb_ptr = pb;
2271*3ee4fc2aSCody Peter Mello 	*sptr_ptr = sptr;
2272*3ee4fc2aSCody Peter Mello }
2273