xref: /csrg-svn/contrib/awk.research/run.c (revision 65393)
1*65393Sbostic /****************************************************************
2*65393Sbostic Copyright (C) AT&T 1993
3*65393Sbostic All Rights Reserved
4*65393Sbostic 
5*65393Sbostic Permission to use, copy, modify, and distribute this software and
6*65393Sbostic its documentation for any purpose and without fee is hereby
7*65393Sbostic granted, provided that the above copyright notice appear in all
8*65393Sbostic copies and that both that the copyright notice and this
9*65393Sbostic permission notice and warranty disclaimer appear in supporting
10*65393Sbostic documentation, and that the name of AT&T or any of its entities
11*65393Sbostic not be used in advertising or publicity pertaining to
12*65393Sbostic distribution of the software without specific, written prior
13*65393Sbostic permission.
14*65393Sbostic 
15*65393Sbostic AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16*65393Sbostic INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17*65393Sbostic IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18*65393Sbostic SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19*65393Sbostic WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20*65393Sbostic IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21*65393Sbostic ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22*65393Sbostic THIS SOFTWARE.
23*65393Sbostic ****************************************************************/
24*65393Sbostic 
25*65393Sbostic #define tempfree(x)	if (istemp(x)) tfree(x); else
26*65393Sbostic 
27*65393Sbostic #define DEBUG
28*65393Sbostic #include <stdio.h>
29*65393Sbostic #include <ctype.h>
30*65393Sbostic #include <setjmp.h>
31*65393Sbostic #include <math.h>
32*65393Sbostic #include <string.h>
33*65393Sbostic #include <stdlib.h>
34*65393Sbostic #include <time.h>
35*65393Sbostic #include "awk.h"
36*65393Sbostic #include "y.tab.h"
37*65393Sbostic 
38*65393Sbostic #ifdef _NFILE
39*65393Sbostic #ifndef FOPEN_MAX
40*65393Sbostic #define FOPEN_MAX _NFILE
41*65393Sbostic #endif
42*65393Sbostic #endif
43*65393Sbostic 
44*65393Sbostic #ifndef	FOPEN_MAX
45*65393Sbostic #define	FOPEN_MAX	40	/* max number of open files */
46*65393Sbostic #endif
47*65393Sbostic 
48*65393Sbostic #ifndef RAND_MAX
49*65393Sbostic #define RAND_MAX	32767	/* all that ansi guarantees */
50*65393Sbostic #endif
51*65393Sbostic 
52*65393Sbostic jmp_buf env;
53*65393Sbostic 
54*65393Sbostic /* an attempt to go a bit faster: */
55*65393Sbostic 
56*65393Sbostic /* #define	execute(p)	(isvalue(p) ? (Cell *)((p)->narg[0]) : r_execute(p)) */
57*65393Sbostic #define	execute(p) r_execute(p)
58*65393Sbostic #define	getfval(p)	(((p)->tval & (ARR|FLD|REC|NUM)) == NUM ? (p)->fval : r_getfval(p))
59*65393Sbostic #define	getsval(p)	(((p)->tval & (ARR|FLD|REC|STR)) == STR ? (p)->sval : r_getsval(p))
60*65393Sbostic 
61*65393Sbostic 
62*65393Sbostic #define PA2NUM	29	/* max number of pat,pat patterns allowed */
63*65393Sbostic int	paircnt;		/* number of them in use */
64*65393Sbostic int	pairstack[PA2NUM];	/* state of each pat,pat */
65*65393Sbostic 
66*65393Sbostic Node	*winner = NULL;	/* root of parse tree */
67*65393Sbostic Cell	*tmps;		/* free temporary cells for execution */
68*65393Sbostic 
69*65393Sbostic static Cell	truecell	={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
70*65393Sbostic Cell	*true	= &truecell;
71*65393Sbostic static Cell	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
72*65393Sbostic Cell	*false	= &falsecell;
73*65393Sbostic static Cell	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
74*65393Sbostic Cell	*jbreak	= &breakcell;
75*65393Sbostic static Cell	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM };
76*65393Sbostic Cell	*jcont	= &contcell;
77*65393Sbostic static Cell	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
78*65393Sbostic Cell	*jnext	= &nextcell;
79*65393Sbostic static Cell	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
80*65393Sbostic Cell	*jexit	= &exitcell;
81*65393Sbostic static Cell	retcell		={ OJUMP, JRET, 0, 0, 0.0, NUM };
82*65393Sbostic Cell	*jret	= &retcell;
83*65393Sbostic static Cell	tempcell	={ OCELL, CTEMP, 0, 0, 0.0, NUM };
84*65393Sbostic 
85*65393Sbostic Node	*curnode = NULL;	/* the node being executed, for debugging */
86*65393Sbostic 
87*65393Sbostic void run(Node *a)	/* execution of parse tree starts here */
88*65393Sbostic {
89*65393Sbostic 	execute(a);
90*65393Sbostic 	closeall();
91*65393Sbostic }
92*65393Sbostic 
93*65393Sbostic Cell *r_execute(Node *u)	/* execute a node of the parse tree */
94*65393Sbostic {
95*65393Sbostic 	register Cell *(*proc)(Node **, int);
96*65393Sbostic 	register Cell *x;
97*65393Sbostic 	register Node *a;
98*65393Sbostic 
99*65393Sbostic 	if (u == NULL)
100*65393Sbostic 		return(true);
101*65393Sbostic 	for (a = u; ; a = a->nnext) {
102*65393Sbostic 		curnode = a;
103*65393Sbostic 		if (isvalue(a)) {
104*65393Sbostic 			x = (Cell *) (a->narg[0]);
105*65393Sbostic 			if ((x->tval & FLD) && !donefld)
106*65393Sbostic 				fldbld();
107*65393Sbostic 			else if ((x->tval & REC) && !donerec)
108*65393Sbostic 				recbld();
109*65393Sbostic 			return(x);
110*65393Sbostic 		}
111*65393Sbostic 		if (notlegal(a->nobj))	/* probably a Cell* but too risky to print */
112*65393Sbostic 			ERROR "illegal statement" FATAL;
113*65393Sbostic 		proc = proctab[a->nobj-FIRSTTOKEN];
114*65393Sbostic 		x = (*proc)(a->narg, a->nobj);
115*65393Sbostic 		if ((x->tval & FLD) && !donefld)
116*65393Sbostic 			fldbld();
117*65393Sbostic 		else if ((x->tval & REC) && !donerec)
118*65393Sbostic 			recbld();
119*65393Sbostic 		if (isexpr(a))
120*65393Sbostic 			return(x);
121*65393Sbostic 		if (isjump(x))
122*65393Sbostic 			return(x);
123*65393Sbostic 		if (a->nnext == NULL)
124*65393Sbostic 			return(x);
125*65393Sbostic 		tempfree(x);
126*65393Sbostic 	}
127*65393Sbostic }
128*65393Sbostic 
129*65393Sbostic 
130*65393Sbostic Cell *program(Node **a, int n)	/* execute an awk program */
131*65393Sbostic {				/* a[0] = BEGIN, a[1] = body, a[2] = END */
132*65393Sbostic 	register Cell *x;
133*65393Sbostic 
134*65393Sbostic 	if (setjmp(env) != 0)
135*65393Sbostic 		goto ex;
136*65393Sbostic 	if (a[0]) {		/* BEGIN */
137*65393Sbostic 		x = execute(a[0]);
138*65393Sbostic 		if (isexit(x))
139*65393Sbostic 			return(true);
140*65393Sbostic 		if (isjump(x))
141*65393Sbostic 			ERROR "illegal break, continue or next from BEGIN" FATAL;
142*65393Sbostic 		tempfree(x);
143*65393Sbostic 	}
144*65393Sbostic   loop:
145*65393Sbostic 	if (a[1] || a[2])
146*65393Sbostic 		while (getrec(record) > 0) {
147*65393Sbostic 			x = execute(a[1]);
148*65393Sbostic 			if (isexit(x))
149*65393Sbostic 				break;
150*65393Sbostic 			tempfree(x);
151*65393Sbostic 		}
152*65393Sbostic   ex:
153*65393Sbostic 	if (setjmp(env) != 0)	/* handles exit within END */
154*65393Sbostic 		goto ex1;
155*65393Sbostic 	if (a[2]) {		/* END */
156*65393Sbostic 		x = execute(a[2]);
157*65393Sbostic 		if (isbreak(x) || isnext(x) || iscont(x))
158*65393Sbostic 			ERROR "illegal break, next, or continue from END" FATAL;
159*65393Sbostic 		tempfree(x);
160*65393Sbostic 	}
161*65393Sbostic   ex1:
162*65393Sbostic 	return(true);
163*65393Sbostic }
164*65393Sbostic 
165*65393Sbostic struct Frame {	/* stack frame for awk function calls */
166*65393Sbostic 	int nargs;	/* number of arguments in this call */
167*65393Sbostic 	Cell *fcncell;	/* pointer to Cell for function */
168*65393Sbostic 	Cell **args;	/* pointer to array of arguments after execute */
169*65393Sbostic 	Cell *retval;	/* return value */
170*65393Sbostic };
171*65393Sbostic 
172*65393Sbostic #define	NARGS	50	/* max args in a call */
173*65393Sbostic 
174*65393Sbostic struct Frame *frame = NULL;	/* base of stack frames; dynamically allocated */
175*65393Sbostic int	nframe = 0;		/* number of frames allocated */
176*65393Sbostic struct Frame *fp = NULL;	/* frame pointer. bottom level unused */
177*65393Sbostic 
178*65393Sbostic Cell *call(Node **a, int n)	/* function call.  very kludgy and fragile */
179*65393Sbostic {
180*65393Sbostic 	static Cell newcopycell = { OCELL, CCOPY, 0, (uchar *) "", 0.0, NUM|STR|DONTFREE };
181*65393Sbostic 	int i, ncall, ndef;
182*65393Sbostic 	Node *x;
183*65393Sbostic 	Cell *args[NARGS], *oargs[NARGS], *y, *z, *fcn;
184*65393Sbostic 	uchar *s;
185*65393Sbostic 
186*65393Sbostic 	fcn = execute(a[0]);	/* the function itself */
187*65393Sbostic 	s = fcn->nval;
188*65393Sbostic 	if (!isfunc(fcn))
189*65393Sbostic 		ERROR "calling undefined function %s", s FATAL;
190*65393Sbostic 	if (frame == NULL) {
191*65393Sbostic 		fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
192*65393Sbostic 		if (frame == NULL)
193*65393Sbostic 			ERROR "out of space for stack frames calling %s", s FATAL;
194*65393Sbostic 	}
195*65393Sbostic 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)	/* args in call */
196*65393Sbostic 		ncall++;
197*65393Sbostic 	ndef = (int) fcn->fval;			/* args in defn */
198*65393Sbostic 	dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, fp-frame) );
199*65393Sbostic 	if (ncall > ndef)
200*65393Sbostic 		ERROR "function %s called with %d args, uses only %d",
201*65393Sbostic 			s, ncall, ndef WARNING;
202*65393Sbostic 	if (ncall + ndef > NARGS)
203*65393Sbostic 		ERROR "function %s has %d arguments, limit %d", s, ncall+ndef, NARGS FATAL;
204*65393Sbostic 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {	/* get call args */
205*65393Sbostic 		dprintf( ("evaluate args[%d], fp=%d:\n", i, fp-frame) );
206*65393Sbostic 		y = execute(x);
207*65393Sbostic 		oargs[i] = y;
208*65393Sbostic 		dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
209*65393Sbostic 			   i, y->nval, y->fval, isarr(y) ? "(array)" : (char*) y->sval, y->tval) );
210*65393Sbostic 		if (isfunc(y))
211*65393Sbostic 			ERROR "can't use function %s as argument in %s", y->nval, s FATAL;
212*65393Sbostic 		if (isarr(y))
213*65393Sbostic 			args[i] = y;	/* arrays by ref */
214*65393Sbostic 		else
215*65393Sbostic 			args[i] = copycell(y);
216*65393Sbostic 		tempfree(y);
217*65393Sbostic 	}
218*65393Sbostic 	for ( ; i < ndef; i++) {	/* add null args for ones not provided */
219*65393Sbostic 		args[i] = gettemp();
220*65393Sbostic 		*args[i] = newcopycell;
221*65393Sbostic 	}
222*65393Sbostic 	fp++;	/* now ok to up frame */
223*65393Sbostic 	if (fp >= frame + nframe) {
224*65393Sbostic 		int dfp = fp - frame;	/* old index */
225*65393Sbostic 		frame = (struct Frame *)
226*65393Sbostic 			realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
227*65393Sbostic 		if (frame == NULL)
228*65393Sbostic 			ERROR "out of space for stack frames in %s", s FATAL;
229*65393Sbostic 		fp = frame + dfp;
230*65393Sbostic 	}
231*65393Sbostic 	fp->fcncell = fcn;
232*65393Sbostic 	fp->args = args;
233*65393Sbostic 	fp->nargs = ndef;	/* number defined with (excess are locals) */
234*65393Sbostic 	fp->retval = gettemp();
235*65393Sbostic 
236*65393Sbostic 	dprintf( ("start exec of %s, fp=%d\n", s, fp-frame) );
237*65393Sbostic 	y = execute((Node *)(fcn->sval));	/* execute body */
238*65393Sbostic 	dprintf( ("finished exec of %s, fp=%d\n", s, fp-frame) );
239*65393Sbostic 
240*65393Sbostic 	for (i = 0; i < ndef; i++) {
241*65393Sbostic 		Cell *t = fp->args[i];
242*65393Sbostic 		if (isarr(t)) {
243*65393Sbostic 			if (t->csub == CCOPY) {
244*65393Sbostic 				if (i >= ncall) {
245*65393Sbostic 					freesymtab(t);
246*65393Sbostic 					t->csub = CTEMP;
247*65393Sbostic 				} else {
248*65393Sbostic 					oargs[i]->tval = t->tval;
249*65393Sbostic 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
250*65393Sbostic 					oargs[i]->sval = t->sval;
251*65393Sbostic 					tempfree(t);
252*65393Sbostic 				}
253*65393Sbostic 			}
254*65393Sbostic 		} else if (t != y) {	/* kludge to prevent freeing twice */
255*65393Sbostic 			t->csub = CTEMP;
256*65393Sbostic 			tempfree(t);
257*65393Sbostic 		}
258*65393Sbostic 	}
259*65393Sbostic 	tempfree(fcn);
260*65393Sbostic 	if (isexit(y) || isnext(y))
261*65393Sbostic 		return y;
262*65393Sbostic 	tempfree(y);		/* this can free twice! */
263*65393Sbostic 	z = fp->retval;			/* return value */
264*65393Sbostic 	dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
265*65393Sbostic 	fp--;
266*65393Sbostic 	return(z);
267*65393Sbostic }
268*65393Sbostic 
269*65393Sbostic Cell *copycell(Cell *x)	/* make a copy of a cell in a temp */
270*65393Sbostic {
271*65393Sbostic 	Cell *y;
272*65393Sbostic 
273*65393Sbostic 	y = gettemp();
274*65393Sbostic 	y->csub = CCOPY;	/* prevents freeing until call is over */
275*65393Sbostic 	y->nval = x->nval;
276*65393Sbostic 	y->sval = x->sval ? tostring(x->sval) : NULL;
277*65393Sbostic 	y->fval = x->fval;
278*65393Sbostic 	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);	/* copy is not constant or field */
279*65393Sbostic 							/* is DONTFREE right? */
280*65393Sbostic 	return y;
281*65393Sbostic }
282*65393Sbostic 
283*65393Sbostic Cell *arg(Node **a, int n)	/* nth argument of a function */
284*65393Sbostic {
285*65393Sbostic 
286*65393Sbostic 	n = (int) a[0];	/* argument number, counting from 0 */
287*65393Sbostic 	dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
288*65393Sbostic 	if (n+1 > fp->nargs)
289*65393Sbostic 		ERROR "argument #%d of function %s was not supplied",
290*65393Sbostic 			n+1, fp->fcncell->nval FATAL;
291*65393Sbostic 	return fp->args[n];
292*65393Sbostic }
293*65393Sbostic 
294*65393Sbostic Cell *jump(Node **a, int n)	/* break, continue, next, continue, return */
295*65393Sbostic {
296*65393Sbostic 	register Cell *y;
297*65393Sbostic 
298*65393Sbostic 	switch (n) {
299*65393Sbostic 	case EXIT:
300*65393Sbostic 		if (a[0] != NULL) {
301*65393Sbostic 			y = execute(a[0]);
302*65393Sbostic 			errorflag = getfval(y);
303*65393Sbostic 			tempfree(y);
304*65393Sbostic 		}
305*65393Sbostic 		longjmp(env, 1);
306*65393Sbostic 	case RETURN:
307*65393Sbostic 		if (a[0] != NULL) {
308*65393Sbostic 			y = execute(a[0]);
309*65393Sbostic 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
310*65393Sbostic 				setsval(fp->retval, getsval(y));
311*65393Sbostic 				fp->retval->fval = getfval(y);
312*65393Sbostic 				fp->retval->tval |= NUM;
313*65393Sbostic 			}
314*65393Sbostic 			else if (y->tval & STR)
315*65393Sbostic 				setsval(fp->retval, getsval(y));
316*65393Sbostic 			else if (y->tval & NUM)
317*65393Sbostic 				setfval(fp->retval, getfval(y));
318*65393Sbostic 			else		/* can't happen */
319*65393Sbostic 				ERROR "bad type variable %d", y->tval FATAL;
320*65393Sbostic 			tempfree(y);
321*65393Sbostic 		}
322*65393Sbostic 		return(jret);
323*65393Sbostic 	case NEXT:
324*65393Sbostic 		return(jnext);
325*65393Sbostic 	case BREAK:
326*65393Sbostic 		return(jbreak);
327*65393Sbostic 	case CONTINUE:
328*65393Sbostic 		return(jcont);
329*65393Sbostic 	default:	/* can't happen */
330*65393Sbostic 		ERROR "illegal jump type %d", n FATAL;
331*65393Sbostic 	}
332*65393Sbostic 	return 0;	/* not reached */
333*65393Sbostic }
334*65393Sbostic 
335*65393Sbostic Cell *getline(Node **a, int n)	/* get next line from specific input */
336*65393Sbostic {		/* a[0] is variable, a[1] is operator, a[2] is filename */
337*65393Sbostic 	register Cell *r, *x;
338*65393Sbostic 	uchar buf[RECSIZE];
339*65393Sbostic 	FILE *fp;
340*65393Sbostic 
341*65393Sbostic 	fflush(stdout);	/* in case someone is waiting for a prompt */
342*65393Sbostic 	r = gettemp();
343*65393Sbostic 	if (a[1] != NULL) {		/* getline < file */
344*65393Sbostic 		x = execute(a[2]);		/* filename */
345*65393Sbostic 		if ((int) a[1] == '|')	/* input pipe */
346*65393Sbostic 			a[1] = (Node *) LE;	/* arbitrary flag */
347*65393Sbostic 		fp = openfile((int) a[1], getsval(x));
348*65393Sbostic 		tempfree(x);
349*65393Sbostic 		if (fp == NULL)
350*65393Sbostic 			n = -1;
351*65393Sbostic 		else
352*65393Sbostic 			n = readrec(buf, sizeof(buf), fp);
353*65393Sbostic 		if (n <= 0) {
354*65393Sbostic 			;
355*65393Sbostic 		} else if (a[0] != NULL) {	/* getline var <file */
356*65393Sbostic 			setsval(execute(a[0]), buf);
357*65393Sbostic 		} else {			/* getline <file */
358*65393Sbostic 			if (!(recloc->tval & DONTFREE))
359*65393Sbostic 				xfree(recloc->sval);
360*65393Sbostic 			strcpy(record, buf);
361*65393Sbostic 			recloc->sval = record;
362*65393Sbostic 			recloc->tval = REC | STR | DONTFREE;
363*65393Sbostic 			if (isnumber(recloc->sval)) {
364*65393Sbostic 				recloc->fval = atof(recloc->sval);
365*65393Sbostic 				recloc->tval |= NUM;
366*65393Sbostic 			}
367*65393Sbostic 			donerec = 1; donefld = 0;
368*65393Sbostic 		}
369*65393Sbostic 	} else {			/* bare getline; use current input */
370*65393Sbostic 		if (a[0] == NULL)	/* getline */
371*65393Sbostic 			n = getrec(record);
372*65393Sbostic 		else {			/* getline var */
373*65393Sbostic 			n = getrec(buf);
374*65393Sbostic 			setsval(execute(a[0]), buf);
375*65393Sbostic 		}
376*65393Sbostic 	}
377*65393Sbostic 	setfval(r, (Awkfloat) n);
378*65393Sbostic 	return r;
379*65393Sbostic }
380*65393Sbostic 
381*65393Sbostic Cell *getnf(Node **a, int n)	/* get NF */
382*65393Sbostic {
383*65393Sbostic 	if (donefld == 0)
384*65393Sbostic 		fldbld();
385*65393Sbostic 	return (Cell *) a[0];
386*65393Sbostic }
387*65393Sbostic 
388*65393Sbostic Cell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
389*65393Sbostic {
390*65393Sbostic 	register Cell *x, *y, *z;
391*65393Sbostic 	register uchar *s;
392*65393Sbostic 	register Node *np;
393*65393Sbostic 	uchar buf[RECSIZE];
394*65393Sbostic 
395*65393Sbostic 	x = execute(a[0]);	/* Cell* for symbol table */
396*65393Sbostic 	buf[0] = 0;
397*65393Sbostic 	for (np = a[1]; np; np = np->nnext) {
398*65393Sbostic 		y = execute(np);	/* subscript */
399*65393Sbostic 		s = getsval(y);
400*65393Sbostic 		strcat(buf, s);
401*65393Sbostic 		if (np->nnext)
402*65393Sbostic 			strcat(buf, *SUBSEP);
403*65393Sbostic 		tempfree(y);
404*65393Sbostic 	}
405*65393Sbostic 	if (!isarr(x)) {
406*65393Sbostic 		dprintf( ("making %s into an array\n", x->nval) );
407*65393Sbostic 		if (freeable(x))
408*65393Sbostic 			xfree(x->sval);
409*65393Sbostic 		x->tval &= ~(STR|NUM|DONTFREE);
410*65393Sbostic 		x->tval |= ARR;
411*65393Sbostic 		x->sval = (uchar *) makesymtab(NSYMTAB);
412*65393Sbostic 	}
413*65393Sbostic 	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
414*65393Sbostic 	z->ctype = OCELL;
415*65393Sbostic 	z->csub = CVAR;
416*65393Sbostic 	tempfree(x);
417*65393Sbostic 	return(z);
418*65393Sbostic }
419*65393Sbostic 
420*65393Sbostic Cell *adelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
421*65393Sbostic {
422*65393Sbostic 	Cell *x, *y;
423*65393Sbostic 	Node *np;
424*65393Sbostic 	uchar buf[RECSIZE], *s;
425*65393Sbostic 
426*65393Sbostic 	x = execute(a[0]);	/* Cell* for symbol table */
427*65393Sbostic 	if (!isarr(x))
428*65393Sbostic 		return true;
429*65393Sbostic 	buf[0] = 0;
430*65393Sbostic 	for (np = a[1]; np; np = np->nnext) {
431*65393Sbostic 		y = execute(np);	/* subscript */
432*65393Sbostic 		s = getsval(y);
433*65393Sbostic 		strcat(buf, s);
434*65393Sbostic 		if (np->nnext)
435*65393Sbostic 			strcat(buf, *SUBSEP);
436*65393Sbostic 		tempfree(y);
437*65393Sbostic 	}
438*65393Sbostic 	freeelem(x, buf);
439*65393Sbostic 	tempfree(x);
440*65393Sbostic 	return true;
441*65393Sbostic }
442*65393Sbostic 
443*65393Sbostic Cell *intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
444*65393Sbostic {
445*65393Sbostic 	register Cell *x, *ap, *k;
446*65393Sbostic 	Node *p;
447*65393Sbostic 	char buf[RECSIZE];
448*65393Sbostic 	uchar *s;
449*65393Sbostic 
450*65393Sbostic 	ap = execute(a[1]);	/* array name */
451*65393Sbostic 	if (!isarr(ap)) {
452*65393Sbostic 		dprintf( ("making %s into an array\n", ap->nval) );
453*65393Sbostic 		if (freeable(ap))
454*65393Sbostic 			xfree(ap->sval);
455*65393Sbostic 		ap->tval &= ~(STR|NUM|DONTFREE);
456*65393Sbostic 		ap->tval |= ARR;
457*65393Sbostic 		ap->sval = (uchar *) makesymtab(NSYMTAB);
458*65393Sbostic 	}
459*65393Sbostic 	buf[0] = 0;
460*65393Sbostic 	for (p = a[0]; p; p = p->nnext) {
461*65393Sbostic 		x = execute(p);	/* expr */
462*65393Sbostic 		s = getsval(x);
463*65393Sbostic 		strcat(buf, s);
464*65393Sbostic 		tempfree(x);
465*65393Sbostic 		if (p->nnext)
466*65393Sbostic 			strcat(buf, *SUBSEP);
467*65393Sbostic 	}
468*65393Sbostic 	k = lookup(buf, (Array *) ap->sval);
469*65393Sbostic 	tempfree(ap);
470*65393Sbostic 	if (k == NULL)
471*65393Sbostic 		return(false);
472*65393Sbostic 	else
473*65393Sbostic 		return(true);
474*65393Sbostic }
475*65393Sbostic 
476*65393Sbostic 
477*65393Sbostic Cell *matchop(Node **a, int n)	/* ~ and match() */
478*65393Sbostic {
479*65393Sbostic 	register Cell *x, *y;
480*65393Sbostic 	register uchar *s, *t;
481*65393Sbostic 	register int i;
482*65393Sbostic 	fa *pfa;
483*65393Sbostic 	int (*mf)(fa *, uchar *) = match, mode = 0;
484*65393Sbostic 
485*65393Sbostic 	if (n == MATCHFCN) {
486*65393Sbostic 		mf = pmatch;
487*65393Sbostic 		mode = 1;
488*65393Sbostic 	}
489*65393Sbostic 	x = execute(a[1]);	/* a[1] = target text */
490*65393Sbostic 	s = getsval(x);
491*65393Sbostic 	if (a[0] == 0)		/* a[1] == 0: already-compiled reg expr */
492*65393Sbostic 		i = (*mf)((fa *) a[2], s);
493*65393Sbostic 	else {
494*65393Sbostic 		y = execute(a[2]);	/* a[2] = regular expr */
495*65393Sbostic 		t = getsval(y);
496*65393Sbostic 		pfa = makedfa(t, mode);
497*65393Sbostic 		i = (*mf)(pfa, s);
498*65393Sbostic 		tempfree(y);
499*65393Sbostic 	}
500*65393Sbostic 	tempfree(x);
501*65393Sbostic 	if (n == MATCHFCN) {
502*65393Sbostic 		int start = patbeg - s + 1;
503*65393Sbostic 		if (patlen < 0)
504*65393Sbostic 			start = 0;
505*65393Sbostic 		setfval(rstartloc, (Awkfloat) start);
506*65393Sbostic 		setfval(rlengthloc, (Awkfloat) patlen);
507*65393Sbostic 		x = gettemp();
508*65393Sbostic 		x->tval = NUM;
509*65393Sbostic 		x->fval = start;
510*65393Sbostic 		return x;
511*65393Sbostic 	} else if (n == MATCH && i == 1 || n == NOTMATCH && i == 0)
512*65393Sbostic 		return(true);
513*65393Sbostic 	else
514*65393Sbostic 		return(false);
515*65393Sbostic }
516*65393Sbostic 
517*65393Sbostic 
518*65393Sbostic Cell *boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
519*65393Sbostic {
520*65393Sbostic 	register Cell *x, *y;
521*65393Sbostic 	register int i;
522*65393Sbostic 
523*65393Sbostic 	x = execute(a[0]);
524*65393Sbostic 	i = istrue(x);
525*65393Sbostic 	tempfree(x);
526*65393Sbostic 	switch (n) {
527*65393Sbostic 	case BOR:
528*65393Sbostic 		if (i) return(true);
529*65393Sbostic 		y = execute(a[1]);
530*65393Sbostic 		i = istrue(y);
531*65393Sbostic 		tempfree(y);
532*65393Sbostic 		if (i) return(true);
533*65393Sbostic 		else return(false);
534*65393Sbostic 	case AND:
535*65393Sbostic 		if ( !i ) return(false);
536*65393Sbostic 		y = execute(a[1]);
537*65393Sbostic 		i = istrue(y);
538*65393Sbostic 		tempfree(y);
539*65393Sbostic 		if (i) return(true);
540*65393Sbostic 		else return(false);
541*65393Sbostic 	case NOT:
542*65393Sbostic 		if (i) return(false);
543*65393Sbostic 		else return(true);
544*65393Sbostic 	default:	/* can't happen */
545*65393Sbostic 		ERROR "unknown boolean operator %d", n FATAL;
546*65393Sbostic 	}
547*65393Sbostic 	return 0;	/*NOTREACHED*/
548*65393Sbostic }
549*65393Sbostic 
550*65393Sbostic Cell *relop(Node **a, int n)	/* a[0 < a[1], etc. */
551*65393Sbostic {
552*65393Sbostic 	register int i;
553*65393Sbostic 	register Cell *x, *y;
554*65393Sbostic 	Awkfloat j;
555*65393Sbostic 
556*65393Sbostic 	x = execute(a[0]);
557*65393Sbostic 	y = execute(a[1]);
558*65393Sbostic 	if (x->tval&NUM && y->tval&NUM) {
559*65393Sbostic 		j = x->fval - y->fval;
560*65393Sbostic 		i = j<0? -1: (j>0? 1: 0);
561*65393Sbostic 	} else {
562*65393Sbostic 		i = strcmp(getsval(x), getsval(y));
563*65393Sbostic 	}
564*65393Sbostic 	tempfree(x);
565*65393Sbostic 	tempfree(y);
566*65393Sbostic 	switch (n) {
567*65393Sbostic 	case LT:	if (i<0) return(true);
568*65393Sbostic 			else return(false);
569*65393Sbostic 	case LE:	if (i<=0) return(true);
570*65393Sbostic 			else return(false);
571*65393Sbostic 	case NE:	if (i!=0) return(true);
572*65393Sbostic 			else return(false);
573*65393Sbostic 	case EQ:	if (i == 0) return(true);
574*65393Sbostic 			else return(false);
575*65393Sbostic 	case GE:	if (i>=0) return(true);
576*65393Sbostic 			else return(false);
577*65393Sbostic 	case GT:	if (i>0) return(true);
578*65393Sbostic 			else return(false);
579*65393Sbostic 	default:	/* can't happen */
580*65393Sbostic 		ERROR "unknown relational operator %d", n FATAL;
581*65393Sbostic 	}
582*65393Sbostic 	return 0;	/*NOTREACHED*/
583*65393Sbostic }
584*65393Sbostic 
585*65393Sbostic void tfree(Cell *a)	/* free a tempcell */
586*65393Sbostic {
587*65393Sbostic 	if (freeable(a))
588*65393Sbostic 		xfree(a->sval);
589*65393Sbostic 	if (a == tmps)
590*65393Sbostic 		ERROR "tempcell list is curdled" FATAL;
591*65393Sbostic 	a->cnext = tmps;
592*65393Sbostic 	tmps = a;
593*65393Sbostic }
594*65393Sbostic 
595*65393Sbostic Cell *gettemp(void)	/* get a tempcell */
596*65393Sbostic {	int i;
597*65393Sbostic 	register Cell *x;
598*65393Sbostic 
599*65393Sbostic 	if (!tmps) {
600*65393Sbostic 		tmps = (Cell *) calloc(100, sizeof(Cell));
601*65393Sbostic 		if (!tmps)
602*65393Sbostic 			ERROR "out of space for temporaries" FATAL;
603*65393Sbostic 		for(i = 1; i < 100; i++)
604*65393Sbostic 			tmps[i-1].cnext = &tmps[i];
605*65393Sbostic 		tmps[i-1].cnext = 0;
606*65393Sbostic 	}
607*65393Sbostic 	x = tmps;
608*65393Sbostic 	tmps = x->cnext;
609*65393Sbostic 	*x = tempcell;
610*65393Sbostic 	return(x);
611*65393Sbostic }
612*65393Sbostic 
613*65393Sbostic Cell *indirect(Node **a, int n)	/* $( a[0] ) */
614*65393Sbostic {
615*65393Sbostic 	register Cell *x;
616*65393Sbostic 	register int m;
617*65393Sbostic 	register uchar *s;
618*65393Sbostic 
619*65393Sbostic 	x = execute(a[0]);
620*65393Sbostic 	m = getfval(x);
621*65393Sbostic 	if (m == 0 && !isnumber(s = getsval(x)))	/* suspicion! */
622*65393Sbostic 		ERROR "illegal field $(%s), name \"%s\"", s, x->nval FATAL;
623*65393Sbostic   /* can x->nval ever be null??? */
624*65393Sbostic 		/* ERROR "illegal field $(%s)", s FATAL; */
625*65393Sbostic 	tempfree(x);
626*65393Sbostic 	x = fieldadr(m);
627*65393Sbostic 	x->ctype = OCELL;
628*65393Sbostic 	x->csub = CFLD;
629*65393Sbostic 	return(x);
630*65393Sbostic }
631*65393Sbostic 
632*65393Sbostic Cell *substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
633*65393Sbostic {
634*65393Sbostic 	register int k, m, n;
635*65393Sbostic 	register uchar *s;
636*65393Sbostic 	int temp;
637*65393Sbostic 	register Cell *x, *y, *z;
638*65393Sbostic 
639*65393Sbostic 	x = execute(a[0]);
640*65393Sbostic 	y = execute(a[1]);
641*65393Sbostic 	if (a[2] != 0)
642*65393Sbostic 		z = execute(a[2]);
643*65393Sbostic 	s = getsval(x);
644*65393Sbostic 	k = strlen(s) + 1;
645*65393Sbostic 	if (k <= 1) {
646*65393Sbostic 		tempfree(x);
647*65393Sbostic 		tempfree(y);
648*65393Sbostic 		if (a[2] != 0)
649*65393Sbostic 			tempfree(z);
650*65393Sbostic 		x = gettemp();
651*65393Sbostic 		setsval(x, "");
652*65393Sbostic 		return(x);
653*65393Sbostic 	}
654*65393Sbostic 	m = getfval(y);
655*65393Sbostic 	if (m <= 0)
656*65393Sbostic 		m = 1;
657*65393Sbostic 	else if (m > k)
658*65393Sbostic 		m = k;
659*65393Sbostic 	tempfree(y);
660*65393Sbostic 	if (a[2] != 0) {
661*65393Sbostic 		n = getfval(z);
662*65393Sbostic 		tempfree(z);
663*65393Sbostic 	} else
664*65393Sbostic 		n = k - 1;
665*65393Sbostic 	if (n < 0)
666*65393Sbostic 		n = 0;
667*65393Sbostic 	else if (n > k - m)
668*65393Sbostic 		n = k - m;
669*65393Sbostic 	dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
670*65393Sbostic 	y = gettemp();
671*65393Sbostic 	temp = s[n+m-1];	/* with thanks to John Linderman */
672*65393Sbostic 	s[n+m-1] = '\0';
673*65393Sbostic 	setsval(y, s + m - 1);
674*65393Sbostic 	s[n+m-1] = temp;
675*65393Sbostic 	tempfree(x);
676*65393Sbostic 	return(y);
677*65393Sbostic }
678*65393Sbostic 
679*65393Sbostic Cell *sindex(Node **a, int nnn)		/* index(a[0], a[1]) */
680*65393Sbostic {
681*65393Sbostic 	register Cell *x, *y, *z;
682*65393Sbostic 	register uchar *s1, *s2, *p1, *p2, *q;
683*65393Sbostic 	Awkfloat v = 0.0;
684*65393Sbostic 
685*65393Sbostic 	x = execute(a[0]);
686*65393Sbostic 	s1 = getsval(x);
687*65393Sbostic 	y = execute(a[1]);
688*65393Sbostic 	s2 = getsval(y);
689*65393Sbostic 
690*65393Sbostic 	z = gettemp();
691*65393Sbostic 	for (p1 = s1; *p1 != '\0'; p1++) {
692*65393Sbostic 		for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
693*65393Sbostic 			;
694*65393Sbostic 		if (*p2 == '\0') {
695*65393Sbostic 			v = (Awkfloat) (p1 - s1 + 1);	/* origin 1 */
696*65393Sbostic 			break;
697*65393Sbostic 		}
698*65393Sbostic 	}
699*65393Sbostic 	tempfree(x);
700*65393Sbostic 	tempfree(y);
701*65393Sbostic 	setfval(z, v);
702*65393Sbostic 	return(z);
703*65393Sbostic }
704*65393Sbostic 
705*65393Sbostic format(uchar *buf, int bufsize, uchar *s, Node *a)	/* printf-like conversions */
706*65393Sbostic {
707*65393Sbostic 	uchar fmt[RECSIZE];
708*65393Sbostic 	register uchar *p, *t, *os;
709*65393Sbostic 	register Cell *x;
710*65393Sbostic 	int flag = 0, n;
711*65393Sbostic 
712*65393Sbostic 	os = s;
713*65393Sbostic 	p = buf;
714*65393Sbostic 	while (*s) {
715*65393Sbostic 		if (p - buf >= bufsize)
716*65393Sbostic 			return -1;
717*65393Sbostic 		if (*s != '%') {
718*65393Sbostic 			*p++ = *s++;
719*65393Sbostic 			continue;
720*65393Sbostic 		}
721*65393Sbostic 		if (*(s+1) == '%') {
722*65393Sbostic 			*p++ = '%';
723*65393Sbostic 			s += 2;
724*65393Sbostic 			continue;
725*65393Sbostic 		}
726*65393Sbostic 		for (t=fmt; (*t++ = *s) != '\0'; s++) {
727*65393Sbostic 			if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
728*65393Sbostic 				break;	/* the ansi panoply */
729*65393Sbostic 			if (*s == '*') {
730*65393Sbostic 				x = execute(a);
731*65393Sbostic 				a = a->nnext;
732*65393Sbostic 				sprintf((char *)t-1, "%d", (int) getfval(x));
733*65393Sbostic 				t = fmt + strlen(fmt);
734*65393Sbostic 				tempfree(x);
735*65393Sbostic 			}
736*65393Sbostic 		}
737*65393Sbostic 		*t = '\0';
738*65393Sbostic 		if (t >= fmt + sizeof(fmt))
739*65393Sbostic 			ERROR "format item %.30s... too long", os FATAL;
740*65393Sbostic 		switch (*s) {
741*65393Sbostic 		case 'f': case 'e': case 'g': case 'E': case 'G':
742*65393Sbostic 			flag = 1;
743*65393Sbostic 			break;
744*65393Sbostic 		case 'd': case 'i':
745*65393Sbostic 			flag = 2;
746*65393Sbostic 			if(*(s-1) == 'l') break;
747*65393Sbostic 			*(t-1) = 'l';
748*65393Sbostic 			*t = 'd';
749*65393Sbostic 			*++t = '\0';
750*65393Sbostic 			break;
751*65393Sbostic 		case 'o': case 'x': case 'X': case 'u':
752*65393Sbostic 			flag = *(s-1) == 'l' ? 2 : 3;
753*65393Sbostic 			break;
754*65393Sbostic 		case 's':
755*65393Sbostic 			flag = 4;
756*65393Sbostic 			break;
757*65393Sbostic 		case 'c':
758*65393Sbostic 			flag = 5;
759*65393Sbostic 			break;
760*65393Sbostic 		default:
761*65393Sbostic 			ERROR "weird printf conversion %s", fmt WARNING;
762*65393Sbostic 			flag = 0;
763*65393Sbostic 			break;
764*65393Sbostic 		}
765*65393Sbostic 		if (a == NULL)
766*65393Sbostic 			ERROR "not enough args in printf(%s)", os FATAL;
767*65393Sbostic 		x = execute(a);
768*65393Sbostic 		a = a->nnext;
769*65393Sbostic 		switch (flag) {
770*65393Sbostic 		case 0:	sprintf((char *)p, "%s", fmt);	/* unknown, so dump it too */
771*65393Sbostic 			p += strlen(p);
772*65393Sbostic 			sprintf((char *)p, "%s", getsval(x));
773*65393Sbostic 			break;
774*65393Sbostic 		case 1:	sprintf((char *)p, (char *)fmt, getfval(x)); break;
775*65393Sbostic 		case 2:	sprintf((char *)p, (char *)fmt, (long) getfval(x)); break;
776*65393Sbostic 		case 3:	sprintf((char *)p, (char *)fmt, (int) getfval(x)); break;
777*65393Sbostic 		case 4:
778*65393Sbostic 			t = getsval(x);
779*65393Sbostic 			n = strlen(t);
780*65393Sbostic 			if (n >= bufsize)
781*65393Sbostic 				ERROR "huge string (%d chars) in printf %.30s...",
782*65393Sbostic 					n, t FATAL;
783*65393Sbostic 			sprintf((char *)p, (char *)fmt, t);
784*65393Sbostic 			break;
785*65393Sbostic 		case 5:
786*65393Sbostic 			isnum(x) ? sprintf((char *)p, (char *)fmt, (int) getfval(x))
787*65393Sbostic 				 : sprintf((char *)p, (char *)fmt, getsval(x)[0]);
788*65393Sbostic 			break;
789*65393Sbostic 		}
790*65393Sbostic 		tempfree(x);
791*65393Sbostic 		p += strlen(p);
792*65393Sbostic 		s++;
793*65393Sbostic 	}
794*65393Sbostic 	*p = '\0';
795*65393Sbostic 	for ( ; a; a = a->nnext)		/* evaluate any remaining args */
796*65393Sbostic 		execute(a);
797*65393Sbostic 	return 0;
798*65393Sbostic }
799*65393Sbostic 
800*65393Sbostic Cell *asprintf(Node **a, int n)		/* sprintf(a[0]) */
801*65393Sbostic {
802*65393Sbostic 	register Cell *x;
803*65393Sbostic 	register Node *y;
804*65393Sbostic 	uchar buf[3*RECSIZE];
805*65393Sbostic 
806*65393Sbostic 	y = a[0]->nnext;
807*65393Sbostic 	x = execute(a[0]);
808*65393Sbostic 	if (format(buf, sizeof buf, getsval(x), y) == -1)
809*65393Sbostic 		ERROR "sprintf string %.30s... too long", buf FATAL;
810*65393Sbostic 	tempfree(x);
811*65393Sbostic 	x = gettemp();
812*65393Sbostic 	x->sval = tostring(buf);
813*65393Sbostic 	x->tval = STR;
814*65393Sbostic 	return(x);
815*65393Sbostic }
816*65393Sbostic 
817*65393Sbostic Cell *aprintf(Node **a, int n)		/* printf */
818*65393Sbostic {	/* a[0] is list of args, starting with format string */
819*65393Sbostic 	/* a[1] is redirection operator, a[2] is redirection file */
820*65393Sbostic 	FILE *fp;
821*65393Sbostic 	register Cell *x;
822*65393Sbostic 	register Node *y;
823*65393Sbostic 	uchar buf[3*RECSIZE];
824*65393Sbostic 
825*65393Sbostic 	y = a[0]->nnext;
826*65393Sbostic 	x = execute(a[0]);
827*65393Sbostic 	if (format(buf, sizeof buf, getsval(x), y) == -1)
828*65393Sbostic 		ERROR "printf string %.30s... too long", buf FATAL;
829*65393Sbostic 	tempfree(x);
830*65393Sbostic 	if (a[1] == NULL) {
831*65393Sbostic 		fputs((char *)buf, stdout);
832*65393Sbostic 		if (ferror(stdout))
833*65393Sbostic 			ERROR "write error on stdout" FATAL;
834*65393Sbostic 	} else {
835*65393Sbostic 		fp = redirect((int)a[1], a[2]);
836*65393Sbostic 		fputs((char *)buf, fp);
837*65393Sbostic 		fflush(fp);
838*65393Sbostic 		if (ferror(fp))
839*65393Sbostic 			ERROR "write error on %s", filename(fp) FATAL;
840*65393Sbostic 	}
841*65393Sbostic 	return(true);
842*65393Sbostic }
843*65393Sbostic 
844*65393Sbostic Cell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
845*65393Sbostic {
846*65393Sbostic 	Awkfloat i, j;
847*65393Sbostic 	double v;
848*65393Sbostic 	register Cell *x, *y, *z;
849*65393Sbostic 
850*65393Sbostic 	x = execute(a[0]);
851*65393Sbostic 	i = getfval(x);
852*65393Sbostic 	tempfree(x);
853*65393Sbostic 	if (n != UMINUS) {
854*65393Sbostic 		y = execute(a[1]);
855*65393Sbostic 		j = getfval(y);
856*65393Sbostic 		tempfree(y);
857*65393Sbostic 	}
858*65393Sbostic 	z = gettemp();
859*65393Sbostic 	switch (n) {
860*65393Sbostic 	case ADD:
861*65393Sbostic 		i += j;
862*65393Sbostic 		break;
863*65393Sbostic 	case MINUS:
864*65393Sbostic 		i -= j;
865*65393Sbostic 		break;
866*65393Sbostic 	case MULT:
867*65393Sbostic 		i *= j;
868*65393Sbostic 		break;
869*65393Sbostic 	case DIVIDE:
870*65393Sbostic 		if (j == 0)
871*65393Sbostic 			ERROR "division by zero" FATAL;
872*65393Sbostic 		i /= j;
873*65393Sbostic 		break;
874*65393Sbostic 	case MOD:
875*65393Sbostic 		if (j == 0)
876*65393Sbostic 			ERROR "division by zero in mod" FATAL;
877*65393Sbostic 		modf(i/j, &v);
878*65393Sbostic 		i = i - j * v;
879*65393Sbostic 		break;
880*65393Sbostic 	case UMINUS:
881*65393Sbostic 		i = -i;
882*65393Sbostic 		break;
883*65393Sbostic 	case POWER:
884*65393Sbostic 		if (j >= 0 && modf(j, &v) == 0.0)	/* pos integer exponent */
885*65393Sbostic 			i = ipow(i, (int) j);
886*65393Sbostic 		else
887*65393Sbostic 			i = errcheck(pow(i, j), "pow");
888*65393Sbostic 		break;
889*65393Sbostic 	default:	/* can't happen */
890*65393Sbostic 		ERROR "illegal arithmetic operator %d", n FATAL;
891*65393Sbostic 	}
892*65393Sbostic 	setfval(z, i);
893*65393Sbostic 	return(z);
894*65393Sbostic }
895*65393Sbostic 
896*65393Sbostic double ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
897*65393Sbostic {
898*65393Sbostic 	double v;
899*65393Sbostic 
900*65393Sbostic 	if (n <= 0)
901*65393Sbostic 		return 1;
902*65393Sbostic 	v = ipow(x, n/2);
903*65393Sbostic 	if (n % 2 == 0)
904*65393Sbostic 		return v * v;
905*65393Sbostic 	else
906*65393Sbostic 		return x * v * v;
907*65393Sbostic }
908*65393Sbostic 
909*65393Sbostic Cell *incrdecr(Node **a, int n)		/* a[0]++, etc. */
910*65393Sbostic {
911*65393Sbostic 	register Cell *x, *z;
912*65393Sbostic 	register int k;
913*65393Sbostic 	Awkfloat xf;
914*65393Sbostic 
915*65393Sbostic 	x = execute(a[0]);
916*65393Sbostic 	xf = getfval(x);
917*65393Sbostic 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
918*65393Sbostic 	if (n == PREINCR || n == PREDECR) {
919*65393Sbostic 		setfval(x, xf + k);
920*65393Sbostic 		return(x);
921*65393Sbostic 	}
922*65393Sbostic 	z = gettemp();
923*65393Sbostic 	setfval(z, xf);
924*65393Sbostic 	setfval(x, xf + k);
925*65393Sbostic 	tempfree(x);
926*65393Sbostic 	return(z);
927*65393Sbostic }
928*65393Sbostic 
929*65393Sbostic Cell *assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
930*65393Sbostic {		/* this is subtle; don't muck with it. */
931*65393Sbostic 	register Cell *x, *y;
932*65393Sbostic 	Awkfloat xf, yf;
933*65393Sbostic 	double v;
934*65393Sbostic 
935*65393Sbostic 	y = execute(a[1]);
936*65393Sbostic 	x = execute(a[0]);
937*65393Sbostic 	if (n == ASSIGN) {	/* ordinary assignment */
938*65393Sbostic 		if (x == y && !(x->tval & (FLD|REC)))	/* self-assignment: */
939*65393Sbostic 			;		/* leave alone unless it's a field */
940*65393Sbostic 		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
941*65393Sbostic 			setsval(x, getsval(y));
942*65393Sbostic 			x->fval = getfval(y);
943*65393Sbostic 			x->tval |= NUM;
944*65393Sbostic 		}
945*65393Sbostic 		else if (y->tval & STR)
946*65393Sbostic 			setsval(x, getsval(y));
947*65393Sbostic 		else if (y->tval & NUM)
948*65393Sbostic 			setfval(x, getfval(y));
949*65393Sbostic 		else
950*65393Sbostic 			funnyvar(y, "read value of");
951*65393Sbostic 		tempfree(y);
952*65393Sbostic 		return(x);
953*65393Sbostic 	}
954*65393Sbostic 	xf = getfval(x);
955*65393Sbostic 	yf = getfval(y);
956*65393Sbostic 	switch (n) {
957*65393Sbostic 	case ADDEQ:
958*65393Sbostic 		xf += yf;
959*65393Sbostic 		break;
960*65393Sbostic 	case SUBEQ:
961*65393Sbostic 		xf -= yf;
962*65393Sbostic 		break;
963*65393Sbostic 	case MULTEQ:
964*65393Sbostic 		xf *= yf;
965*65393Sbostic 		break;
966*65393Sbostic 	case DIVEQ:
967*65393Sbostic 		if (yf == 0)
968*65393Sbostic 			ERROR "division by zero in /=" FATAL;
969*65393Sbostic 		xf /= yf;
970*65393Sbostic 		break;
971*65393Sbostic 	case MODEQ:
972*65393Sbostic 		if (yf == 0)
973*65393Sbostic 			ERROR "division by zero in %%=" FATAL;
974*65393Sbostic 		modf(xf/yf, &v);
975*65393Sbostic 		xf = xf - yf * v;
976*65393Sbostic 		break;
977*65393Sbostic 	case POWEQ:
978*65393Sbostic 		if (yf >= 0 && modf(yf, &v) == 0.0)	/* pos integer exponent */
979*65393Sbostic 			xf = ipow(xf, (int) yf);
980*65393Sbostic 		else
981*65393Sbostic 			xf = errcheck(pow(xf, yf), "pow");
982*65393Sbostic 		break;
983*65393Sbostic 	default:
984*65393Sbostic 		ERROR "illegal assignment operator %d", n FATAL;
985*65393Sbostic 		break;
986*65393Sbostic 	}
987*65393Sbostic 	tempfree(y);
988*65393Sbostic 	setfval(x, xf);
989*65393Sbostic 	return(x);
990*65393Sbostic }
991*65393Sbostic 
992*65393Sbostic Cell *cat(Node **a, int q)	/* a[0] cat a[1] */
993*65393Sbostic {
994*65393Sbostic 	register Cell *x, *y, *z;
995*65393Sbostic 	register int n1, n2;
996*65393Sbostic 	register uchar *s;
997*65393Sbostic 
998*65393Sbostic 	x = execute(a[0]);
999*65393Sbostic 	y = execute(a[1]);
1000*65393Sbostic 	getsval(x);
1001*65393Sbostic 	getsval(y);
1002*65393Sbostic 	n1 = strlen(x->sval);
1003*65393Sbostic 	n2 = strlen(y->sval);
1004*65393Sbostic 	s = (uchar *) malloc(n1 + n2 + 1);
1005*65393Sbostic 	if (s == NULL)
1006*65393Sbostic 		ERROR "out of space concatenating %.15s... and %.15s...",
1007*65393Sbostic 			x->sval, y->sval FATAL;
1008*65393Sbostic 	strcpy(s, x->sval);
1009*65393Sbostic 	strcpy(s+n1, y->sval);
1010*65393Sbostic 	tempfree(y);
1011*65393Sbostic 	z = gettemp();
1012*65393Sbostic 	z->sval = s;
1013*65393Sbostic 	z->tval = STR;
1014*65393Sbostic 	tempfree(x);
1015*65393Sbostic 	return(z);
1016*65393Sbostic }
1017*65393Sbostic 
1018*65393Sbostic Cell *pastat(Node **a, int n)	/* a[0] { a[1] } */
1019*65393Sbostic {
1020*65393Sbostic 	register Cell *x;
1021*65393Sbostic 
1022*65393Sbostic 	if (a[0] == 0)
1023*65393Sbostic 		x = execute(a[1]);
1024*65393Sbostic 	else {
1025*65393Sbostic 		x = execute(a[0]);
1026*65393Sbostic 		if (istrue(x)) {
1027*65393Sbostic 			tempfree(x);
1028*65393Sbostic 			x = execute(a[1]);
1029*65393Sbostic 		}
1030*65393Sbostic 	}
1031*65393Sbostic 	return x;
1032*65393Sbostic }
1033*65393Sbostic 
1034*65393Sbostic Cell *dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
1035*65393Sbostic {
1036*65393Sbostic 	register Cell *x;
1037*65393Sbostic 	register int pair;
1038*65393Sbostic 
1039*65393Sbostic 	pair = (int) a[3];
1040*65393Sbostic 	if (pairstack[pair] == 0) {
1041*65393Sbostic 		x = execute(a[0]);
1042*65393Sbostic 		if (istrue(x))
1043*65393Sbostic 			pairstack[pair] = 1;
1044*65393Sbostic 		tempfree(x);
1045*65393Sbostic 	}
1046*65393Sbostic 	if (pairstack[pair] == 1) {
1047*65393Sbostic 		x = execute(a[1]);
1048*65393Sbostic 		if (istrue(x))
1049*65393Sbostic 			pairstack[pair] = 0;
1050*65393Sbostic 		tempfree(x);
1051*65393Sbostic 		x = execute(a[2]);
1052*65393Sbostic 		return(x);
1053*65393Sbostic 	}
1054*65393Sbostic 	return(false);
1055*65393Sbostic }
1056*65393Sbostic 
1057*65393Sbostic Cell *split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
1058*65393Sbostic {
1059*65393Sbostic 	Cell *x, *y, *ap;
1060*65393Sbostic 	register uchar *s;
1061*65393Sbostic 	register int sep;
1062*65393Sbostic 	uchar *t, temp, num[10], *fs;
1063*65393Sbostic 	int n, tempstat;
1064*65393Sbostic 
1065*65393Sbostic 	y = execute(a[0]);	/* source string */
1066*65393Sbostic 	s = getsval(y);
1067*65393Sbostic 	if (a[2] == 0)		/* fs string */
1068*65393Sbostic 		fs = *FS;
1069*65393Sbostic 	else if ((int) a[3] == STRING) {	/* split(str,arr,"string") */
1070*65393Sbostic 		x = execute(a[2]);
1071*65393Sbostic 		fs = getsval(x);
1072*65393Sbostic 	} else if ((int) a[3] == REGEXPR)
1073*65393Sbostic 		fs = (uchar*) "(regexpr)";	/* split(str,arr,/regexpr/) */
1074*65393Sbostic 	else
1075*65393Sbostic 		ERROR "illegal type of split()" FATAL;
1076*65393Sbostic 	sep = *fs;
1077*65393Sbostic 	ap = execute(a[1]);	/* array name */
1078*65393Sbostic 	freesymtab(ap);
1079*65393Sbostic 	dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
1080*65393Sbostic 	ap->tval &= ~STR;
1081*65393Sbostic 	ap->tval |= ARR;
1082*65393Sbostic 	ap->sval = (uchar *) makesymtab(NSYMTAB);
1083*65393Sbostic 
1084*65393Sbostic 	n = 0;
1085*65393Sbostic 	if (*s != '\0' && strlen(fs) > 1 || (int) a[3] == REGEXPR) {	/* reg expr */
1086*65393Sbostic 		fa *pfa;
1087*65393Sbostic 		if ((int) a[3] == REGEXPR) {	/* it's ready already */
1088*65393Sbostic 			pfa = (fa *) a[2];
1089*65393Sbostic 		} else {
1090*65393Sbostic 			pfa = makedfa(fs, 1);
1091*65393Sbostic 		}
1092*65393Sbostic 		if (nematch(pfa,s)) {
1093*65393Sbostic 			tempstat = pfa->initstat;
1094*65393Sbostic 			pfa->initstat = 2;
1095*65393Sbostic 			do {
1096*65393Sbostic 				n++;
1097*65393Sbostic 				sprintf((char *)num, "%d", n);
1098*65393Sbostic 				temp = *patbeg;
1099*65393Sbostic 				*patbeg = '\0';
1100*65393Sbostic 				if (isnumber(s))
1101*65393Sbostic 					setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval);
1102*65393Sbostic 				else
1103*65393Sbostic 					setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1104*65393Sbostic 				*patbeg = temp;
1105*65393Sbostic 				s = patbeg + patlen;
1106*65393Sbostic 				if (*(patbeg+patlen-1) == 0 || *s == 0) {
1107*65393Sbostic 					n++;
1108*65393Sbostic 					sprintf((char *)num, "%d", n);
1109*65393Sbostic 					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1110*65393Sbostic 					pfa->initstat = tempstat;
1111*65393Sbostic 					goto spdone;
1112*65393Sbostic 				}
1113*65393Sbostic 			} while (nematch(pfa,s));
1114*65393Sbostic 		}
1115*65393Sbostic 		n++;
1116*65393Sbostic 		sprintf((char *)num, "%d", n);
1117*65393Sbostic 		if (isnumber(s))
1118*65393Sbostic 			setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval);
1119*65393Sbostic 		else
1120*65393Sbostic 			setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1121*65393Sbostic   spdone:
1122*65393Sbostic 		pfa = NULL;
1123*65393Sbostic 	} else if (sep == ' ') {
1124*65393Sbostic 		for (n = 0; ; ) {
1125*65393Sbostic 			while (*s == ' ' || *s == '\t' || *s == '\n')
1126*65393Sbostic 				s++;
1127*65393Sbostic 			if (*s == 0)
1128*65393Sbostic 				break;
1129*65393Sbostic 			n++;
1130*65393Sbostic 			t = s;
1131*65393Sbostic 			do
1132*65393Sbostic 				s++;
1133*65393Sbostic 			while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1134*65393Sbostic 			temp = *s;
1135*65393Sbostic 			*s = '\0';
1136*65393Sbostic 			sprintf((char *)num, "%d", n);
1137*65393Sbostic 			if (isnumber(t))
1138*65393Sbostic 				setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
1139*65393Sbostic 			else
1140*65393Sbostic 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1141*65393Sbostic 			*s = temp;
1142*65393Sbostic 			if (*s != 0)
1143*65393Sbostic 				s++;
1144*65393Sbostic 		}
1145*65393Sbostic 	} else if (*s != 0) {
1146*65393Sbostic 		for (;;) {
1147*65393Sbostic 			n++;
1148*65393Sbostic 			t = s;
1149*65393Sbostic 			while (*s != sep && *s != '\n' && *s != '\0')
1150*65393Sbostic 				s++;
1151*65393Sbostic 			temp = *s;
1152*65393Sbostic 			*s = '\0';
1153*65393Sbostic 			sprintf((char *)num, "%d", n);
1154*65393Sbostic 			if (isnumber(t))
1155*65393Sbostic 				setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
1156*65393Sbostic 			else
1157*65393Sbostic 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1158*65393Sbostic 			*s = temp;
1159*65393Sbostic 			if (*s++ == 0)
1160*65393Sbostic 				break;
1161*65393Sbostic 		}
1162*65393Sbostic 	}
1163*65393Sbostic 	tempfree(ap);
1164*65393Sbostic 	tempfree(y);
1165*65393Sbostic 	if (a[2] != 0 && (int) a[3] == STRING)
1166*65393Sbostic 		tempfree(x);
1167*65393Sbostic 	x = gettemp();
1168*65393Sbostic 	x->tval = NUM;
1169*65393Sbostic 	x->fval = n;
1170*65393Sbostic 	return(x);
1171*65393Sbostic }
1172*65393Sbostic 
1173*65393Sbostic Cell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
1174*65393Sbostic {
1175*65393Sbostic 	register Cell *x;
1176*65393Sbostic 
1177*65393Sbostic 	x = execute(a[0]);
1178*65393Sbostic 	if (istrue(x)) {
1179*65393Sbostic 		tempfree(x);
1180*65393Sbostic 		x = execute(a[1]);
1181*65393Sbostic 	} else {
1182*65393Sbostic 		tempfree(x);
1183*65393Sbostic 		x = execute(a[2]);
1184*65393Sbostic 	}
1185*65393Sbostic 	return(x);
1186*65393Sbostic }
1187*65393Sbostic 
1188*65393Sbostic Cell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
1189*65393Sbostic {
1190*65393Sbostic 	register Cell *x;
1191*65393Sbostic 
1192*65393Sbostic 	x = execute(a[0]);
1193*65393Sbostic 	if (istrue(x)) {
1194*65393Sbostic 		tempfree(x);
1195*65393Sbostic 		x = execute(a[1]);
1196*65393Sbostic 	} else if (a[2] != 0) {
1197*65393Sbostic 		tempfree(x);
1198*65393Sbostic 		x = execute(a[2]);
1199*65393Sbostic 	}
1200*65393Sbostic 	return(x);
1201*65393Sbostic }
1202*65393Sbostic 
1203*65393Sbostic Cell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
1204*65393Sbostic {
1205*65393Sbostic 	register Cell *x;
1206*65393Sbostic 
1207*65393Sbostic 	for (;;) {
1208*65393Sbostic 		x = execute(a[0]);
1209*65393Sbostic 		if (!istrue(x))
1210*65393Sbostic 			return(x);
1211*65393Sbostic 		tempfree(x);
1212*65393Sbostic 		x = execute(a[1]);
1213*65393Sbostic 		if (isbreak(x)) {
1214*65393Sbostic 			x = true;
1215*65393Sbostic 			return(x);
1216*65393Sbostic 		}
1217*65393Sbostic 		if (isnext(x) || isexit(x) || isret(x))
1218*65393Sbostic 			return(x);
1219*65393Sbostic 		tempfree(x);
1220*65393Sbostic 	}
1221*65393Sbostic }
1222*65393Sbostic 
1223*65393Sbostic Cell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
1224*65393Sbostic {
1225*65393Sbostic 	register Cell *x;
1226*65393Sbostic 
1227*65393Sbostic 	for (;;) {
1228*65393Sbostic 		x = execute(a[0]);
1229*65393Sbostic 		if (isbreak(x))
1230*65393Sbostic 			return true;
1231*65393Sbostic 		if (isnext(x) || isexit(x) || isret(x))
1232*65393Sbostic 			return(x);
1233*65393Sbostic 		tempfree(x);
1234*65393Sbostic 		x = execute(a[1]);
1235*65393Sbostic 		if (!istrue(x))
1236*65393Sbostic 			return(x);
1237*65393Sbostic 		tempfree(x);
1238*65393Sbostic 	}
1239*65393Sbostic }
1240*65393Sbostic 
1241*65393Sbostic Cell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
1242*65393Sbostic {
1243*65393Sbostic 	register Cell *x;
1244*65393Sbostic 
1245*65393Sbostic 	x = execute(a[0]);
1246*65393Sbostic 	tempfree(x);
1247*65393Sbostic 	for (;;) {
1248*65393Sbostic 		if (a[1]!=0) {
1249*65393Sbostic 			x = execute(a[1]);
1250*65393Sbostic 			if (!istrue(x)) return(x);
1251*65393Sbostic 			else tempfree(x);
1252*65393Sbostic 		}
1253*65393Sbostic 		x = execute(a[3]);
1254*65393Sbostic 		if (isbreak(x))		/* turn off break */
1255*65393Sbostic 			return true;
1256*65393Sbostic 		if (isnext(x) || isexit(x) || isret(x))
1257*65393Sbostic 			return(x);
1258*65393Sbostic 		tempfree(x);
1259*65393Sbostic 		x = execute(a[2]);
1260*65393Sbostic 		tempfree(x);
1261*65393Sbostic 	}
1262*65393Sbostic }
1263*65393Sbostic 
1264*65393Sbostic Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
1265*65393Sbostic {
1266*65393Sbostic 	register Cell *x, *vp, *arrayp, *cp, *ncp;
1267*65393Sbostic 	Array *tp;
1268*65393Sbostic 	int i;
1269*65393Sbostic 
1270*65393Sbostic 	vp = execute(a[0]);
1271*65393Sbostic 	arrayp = execute(a[1]);
1272*65393Sbostic 	if (!isarr(arrayp)) {
1273*65393Sbostic 		return true;
1274*65393Sbostic 	}
1275*65393Sbostic 	tp = (Array *) arrayp->sval;
1276*65393Sbostic 	tempfree(arrayp);
1277*65393Sbostic 	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
1278*65393Sbostic 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1279*65393Sbostic 			setsval(vp, cp->nval);
1280*65393Sbostic 			ncp = cp->cnext;
1281*65393Sbostic 			x = execute(a[2]);
1282*65393Sbostic 			if (isbreak(x)) {
1283*65393Sbostic 				tempfree(vp);
1284*65393Sbostic 				return true;
1285*65393Sbostic 			}
1286*65393Sbostic 			if (isnext(x) || isexit(x) || isret(x)) {
1287*65393Sbostic 				tempfree(vp);
1288*65393Sbostic 				return(x);
1289*65393Sbostic 			}
1290*65393Sbostic 			tempfree(x);
1291*65393Sbostic 		}
1292*65393Sbostic 	}
1293*65393Sbostic 	return true;
1294*65393Sbostic }
1295*65393Sbostic 
1296*65393Sbostic /* if someone ever wants to run over the arrays in sorted order, */
1297*65393Sbostic /* here it is.  but it will likely run slower, not faster. */
1298*65393Sbostic 
1299*65393Sbostic /*
1300*65393Sbostic  *int qstrcmp(p, q)
1301*65393Sbostic  *	uchar **p, **q;
1302*65393Sbostic  *{
1303*65393Sbostic  *	return strcmp(*p, *q);
1304*65393Sbostic  *}
1305*65393Sbostic  */
1306*65393Sbostic 
1307*65393Sbostic /*Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
1308*65393Sbostic /*{
1309*65393Sbostic /*	register Cell *x, *vp, *arrayp, *cp, *ncp, *ret;
1310*65393Sbostic /*	Array *tp;
1311*65393Sbostic /*	int i, ne;
1312*65393Sbostic /*#define BIGENOUGH 1000
1313*65393Sbostic /*	uchar *elems[BIGENOUGH], **ep;
1314*65393Sbostic /*
1315*65393Sbostic /*	vp = execute(a[0]);
1316*65393Sbostic /*	arrayp = execute(a[1]);
1317*65393Sbostic /*	if (!isarr(arrayp))
1318*65393Sbostic /*		ERROR "%s is not an array", arrayp->nval FATAL;
1319*65393Sbostic /*	tp = (Array *) arrayp->sval;
1320*65393Sbostic /*	tempfree(arrayp);
1321*65393Sbostic /*	ep = elems;
1322*65393Sbostic /*	ret = true;
1323*65393Sbostic /*	if (tp->nelem >= BIGENOUGH)
1324*65393Sbostic /*		ep = (uchar **) malloc(tp->nelem * sizeof(char *));
1325*65393Sbostic /*
1326*65393Sbostic /*	for (i = ne = 0; i < tp->size; i++)
1327*65393Sbostic /*		for (cp = tp->tab[i]; cp != NULL; cp = cp->cnext)
1328*65393Sbostic /*			ep[ne++] = cp->nval;
1329*65393Sbostic /*	if (ne != tp->nelem)
1330*65393Sbostic /*		ERROR "can't happen: lost elems %d vs. %d", ne, tp->nelem FATAL;
1331*65393Sbostic /*	qsort(ep, ne, sizeof(char *), qstrcmp);
1332*65393Sbostic /*	for (i = 0; i < ne; i++) {
1333*65393Sbostic /*		setsval(vp, ep[i]);
1334*65393Sbostic /*		x = execute(a[2]);
1335*65393Sbostic /*		if (isbreak(x)) {
1336*65393Sbostic /*			tempfree(vp);
1337*65393Sbostic /*			break;
1338*65393Sbostic /*		}
1339*65393Sbostic /*		if (isnext(x) || isexit(x) || isret(x)) {
1340*65393Sbostic /*			tempfree(vp);
1341*65393Sbostic /*			ret = x;
1342*65393Sbostic /*			break;
1343*65393Sbostic /*		}
1344*65393Sbostic /*		tempfree(x);
1345*65393Sbostic /*	}
1346*65393Sbostic /*	if (ep != elems)
1347*65393Sbostic /*		free(ep);
1348*65393Sbostic /*	return ret;
1349*65393Sbostic /*}
1350*65393Sbostic */
1351*65393Sbostic 
1352*65393Sbostic 
1353*65393Sbostic Cell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
1354*65393Sbostic {
1355*65393Sbostic 	register Cell *x, *y;
1356*65393Sbostic 	Awkfloat u;
1357*65393Sbostic 	register int t;
1358*65393Sbostic 	uchar *p, buf[RECSIZE];
1359*65393Sbostic 	Node *nextarg;
1360*65393Sbostic 	FILE *fp;
1361*65393Sbostic 
1362*65393Sbostic 	t = (int) a[0];
1363*65393Sbostic 	x = execute(a[1]);
1364*65393Sbostic 	nextarg = a[1]->nnext;
1365*65393Sbostic 	switch (t) {
1366*65393Sbostic 	case FLENGTH:
1367*65393Sbostic 		u = strlen(getsval(x)); break;
1368*65393Sbostic 	case FLOG:
1369*65393Sbostic 		u = errcheck(log(getfval(x)), "log"); break;
1370*65393Sbostic 	case FINT:
1371*65393Sbostic 		modf(getfval(x), &u); break;
1372*65393Sbostic 	case FEXP:
1373*65393Sbostic 		u = errcheck(exp(getfval(x)), "exp"); break;
1374*65393Sbostic 	case FSQRT:
1375*65393Sbostic 		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1376*65393Sbostic 	case FSIN:
1377*65393Sbostic 		u = sin(getfval(x)); break;
1378*65393Sbostic 	case FCOS:
1379*65393Sbostic 		u = cos(getfval(x)); break;
1380*65393Sbostic 	case FATAN:
1381*65393Sbostic 		if (nextarg == 0) {
1382*65393Sbostic 			ERROR "atan2 requires two arguments; returning 1.0" WARNING;
1383*65393Sbostic 			u = 1.0;
1384*65393Sbostic 		} else {
1385*65393Sbostic 			y = execute(a[1]->nnext);
1386*65393Sbostic 			u = atan2(getfval(x), getfval(y));
1387*65393Sbostic 			tempfree(y);
1388*65393Sbostic 			nextarg = nextarg->nnext;
1389*65393Sbostic 		}
1390*65393Sbostic 		break;
1391*65393Sbostic 	case FSYSTEM:
1392*65393Sbostic 		fflush(stdout);		/* in case something is buffered already */
1393*65393Sbostic 		u = (Awkfloat) system((char *)getsval(x)) / 256;   /* 256 is unix-dep */
1394*65393Sbostic 		break;
1395*65393Sbostic 	case FRAND:
1396*65393Sbostic 		/* in principle, rand() returns something in 0..RAND_MAX */
1397*65393Sbostic 		u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1398*65393Sbostic 		break;
1399*65393Sbostic 	case FSRAND:
1400*65393Sbostic 		if (x->tval & REC)	/* no argument provided */
1401*65393Sbostic 			u = time((long *)0);
1402*65393Sbostic 		else
1403*65393Sbostic 			u = getfval(x);
1404*65393Sbostic 		srand((int) u); u = (int) u;
1405*65393Sbostic 		break;
1406*65393Sbostic 	case FTOUPPER:
1407*65393Sbostic 	case FTOLOWER:
1408*65393Sbostic 		strcpy(buf, getsval(x));
1409*65393Sbostic 		if (t == FTOUPPER) {
1410*65393Sbostic 			for (p = buf; *p; p++)
1411*65393Sbostic 				if (islower(*p))
1412*65393Sbostic 					*p = toupper(*p);
1413*65393Sbostic 		} else {
1414*65393Sbostic 			for (p = buf; *p; p++)
1415*65393Sbostic 				if (isupper(*p))
1416*65393Sbostic 					*p = tolower(*p);
1417*65393Sbostic 		}
1418*65393Sbostic 		tempfree(x);
1419*65393Sbostic 		x = gettemp();
1420*65393Sbostic 		setsval(x, buf);
1421*65393Sbostic 		return x;
1422*65393Sbostic 	case FFLUSH:
1423*65393Sbostic 		if ((fp = openfile(GT, getsval(x))) == NULL)
1424*65393Sbostic 			u = EOF;
1425*65393Sbostic 		else
1426*65393Sbostic 			u = fflush(fp);
1427*65393Sbostic 		break;
1428*65393Sbostic 	default:	/* can't happen */
1429*65393Sbostic 		ERROR "illegal function type %d", t FATAL;
1430*65393Sbostic 		break;
1431*65393Sbostic 	}
1432*65393Sbostic 	tempfree(x);
1433*65393Sbostic 	x = gettemp();
1434*65393Sbostic 	setfval(x, u);
1435*65393Sbostic 	if (nextarg != 0) {
1436*65393Sbostic 		ERROR "warning: function has too many arguments" WARNING;
1437*65393Sbostic 		for ( ; nextarg; nextarg = nextarg->nnext)
1438*65393Sbostic 			execute(nextarg);
1439*65393Sbostic 	}
1440*65393Sbostic 	return(x);
1441*65393Sbostic }
1442*65393Sbostic 
1443*65393Sbostic Cell *printstat(Node **a, int n)	/* print a[0] */
1444*65393Sbostic {
1445*65393Sbostic 	register Node *x;
1446*65393Sbostic 	register Cell *y;
1447*65393Sbostic 	FILE *fp;
1448*65393Sbostic 
1449*65393Sbostic 	if (a[1] == 0)	/* a[1] is redirection operator, a[2] is file */
1450*65393Sbostic 		fp = stdout;
1451*65393Sbostic 	else
1452*65393Sbostic 		fp = redirect((int)a[1], a[2]);
1453*65393Sbostic 	for (x = a[0]; x != NULL; x = x->nnext) {
1454*65393Sbostic 		y = execute(x);
1455*65393Sbostic 		fputs((char *)getsval(y), fp);
1456*65393Sbostic 		tempfree(y);
1457*65393Sbostic 		if (x->nnext == NULL)
1458*65393Sbostic 			fputs((char *)*ORS, fp);
1459*65393Sbostic 		else
1460*65393Sbostic 			fputs((char *)*OFS, fp);
1461*65393Sbostic 	}
1462*65393Sbostic 	if (a[1] != 0)
1463*65393Sbostic 		fflush(fp);
1464*65393Sbostic 	if (ferror(fp))
1465*65393Sbostic 		ERROR "write error on %s", filename(fp) FATAL;
1466*65393Sbostic 	return(true);
1467*65393Sbostic }
1468*65393Sbostic 
1469*65393Sbostic Cell *nullproc(Node **a, int n)
1470*65393Sbostic {
1471*65393Sbostic 	n;
1472*65393Sbostic 	a;
1473*65393Sbostic 	return 0;
1474*65393Sbostic }
1475*65393Sbostic 
1476*65393Sbostic 
1477*65393Sbostic FILE *redirect(int a, Node *b)	/* set up all i/o redirections */
1478*65393Sbostic {
1479*65393Sbostic 	FILE *fp;
1480*65393Sbostic 	Cell *x;
1481*65393Sbostic 	uchar *fname;
1482*65393Sbostic 
1483*65393Sbostic 	x = execute(b);
1484*65393Sbostic 	fname = getsval(x);
1485*65393Sbostic 	fp = openfile(a, fname);
1486*65393Sbostic 	if (fp == NULL)
1487*65393Sbostic 		ERROR "can't open file %s", fname FATAL;
1488*65393Sbostic 	tempfree(x);
1489*65393Sbostic 	return fp;
1490*65393Sbostic }
1491*65393Sbostic 
1492*65393Sbostic struct files {
1493*65393Sbostic 	FILE	*fp;
1494*65393Sbostic 	uchar	*fname;
1495*65393Sbostic 	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
1496*65393Sbostic } files[FOPEN_MAX] ={
1497*65393Sbostic 	{ stdin,  "/dev/stdin",  LT },	/* watch out: don't free this! */
1498*65393Sbostic 	{ stdout, "/dev/stdout", GT },
1499*65393Sbostic 	{ stderr, "/dev/stderr", GT }
1500*65393Sbostic };
1501*65393Sbostic 
1502*65393Sbostic FILE *openfile(int a, uchar *us)
1503*65393Sbostic {
1504*65393Sbostic 	char *s = us;
1505*65393Sbostic 	register int i, m;
1506*65393Sbostic 	register FILE *fp;
1507*65393Sbostic 
1508*65393Sbostic 	if (*s == '\0')
1509*65393Sbostic 		ERROR "null file name in print or getline" FATAL;
1510*65393Sbostic 	for (i=0; i < FOPEN_MAX; i++)
1511*65393Sbostic 		if (files[i].fname && strcmp(s, files[i].fname) == 0)
1512*65393Sbostic 			if (a == files[i].mode || a==APPEND && files[i].mode==GT)
1513*65393Sbostic 				return files[i].fp;
1514*65393Sbostic 	for (i=0; i < FOPEN_MAX; i++)
1515*65393Sbostic 		if (files[i].fp == 0)
1516*65393Sbostic 			break;
1517*65393Sbostic 	if (i >= FOPEN_MAX)
1518*65393Sbostic 		ERROR "%s makes too many open files", s FATAL;
1519*65393Sbostic 	fflush(stdout);	/* force a semblance of order */
1520*65393Sbostic 	m = a;
1521*65393Sbostic 	if (a == GT) {
1522*65393Sbostic 		fp = fopen(s, "w");
1523*65393Sbostic 	} else if (a == APPEND) {
1524*65393Sbostic 		fp = fopen(s, "a");
1525*65393Sbostic 		m = GT;	/* so can mix > and >> */
1526*65393Sbostic 	} else if (a == '|') {	/* output pipe */
1527*65393Sbostic 		fp = popen(s, "w");
1528*65393Sbostic 	} else if (a == LE) {	/* input pipe */
1529*65393Sbostic 		fp = popen(s, "r");
1530*65393Sbostic 	} else if (a == LT) {	/* getline <file */
1531*65393Sbostic 		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
1532*65393Sbostic 	} else	/* can't happen */
1533*65393Sbostic 		ERROR "illegal redirection %d", a FATAL;
1534*65393Sbostic 	if (fp != NULL) {
1535*65393Sbostic 		files[i].fname = tostring(s);
1536*65393Sbostic 		files[i].fp = fp;
1537*65393Sbostic 		files[i].mode = m;
1538*65393Sbostic 	}
1539*65393Sbostic 	return fp;
1540*65393Sbostic }
1541*65393Sbostic 
1542*65393Sbostic uchar *filename(FILE *fp)
1543*65393Sbostic {
1544*65393Sbostic 	int i;
1545*65393Sbostic 
1546*65393Sbostic 	for (i = 0; i < FOPEN_MAX; i++)
1547*65393Sbostic 		if (fp == files[i].fp)
1548*65393Sbostic 			return files[i].fname;
1549*65393Sbostic 	return "???";
1550*65393Sbostic }
1551*65393Sbostic 
1552*65393Sbostic Cell *closefile(Node **a, int n)
1553*65393Sbostic {
1554*65393Sbostic 	register Cell *x;
1555*65393Sbostic 	int i, stat;
1556*65393Sbostic 
1557*65393Sbostic 	n;
1558*65393Sbostic 	x = execute(a[0]);
1559*65393Sbostic 	getsval(x);
1560*65393Sbostic 	for (i = 0; i < FOPEN_MAX; i++)
1561*65393Sbostic 		if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1562*65393Sbostic 			if (ferror(files[i].fp))
1563*65393Sbostic 				ERROR "i/o error occurred on %s", files[i].fname WARNING;
1564*65393Sbostic 			if (files[i].mode == '|' || files[i].mode == LE)
1565*65393Sbostic 				stat = pclose(files[i].fp);
1566*65393Sbostic 			else
1567*65393Sbostic 				stat = fclose(files[i].fp);
1568*65393Sbostic 			if (stat == EOF)
1569*65393Sbostic 				ERROR "i/o error occurred closing %s", files[i].fname WARNING;
1570*65393Sbostic 			if (i > 2)	/* don't do /dev/std... */
1571*65393Sbostic 				xfree(files[i].fname);
1572*65393Sbostic 			files[i].fname = NULL;	/* watch out for ref thru this */
1573*65393Sbostic 			files[i].fp = NULL;
1574*65393Sbostic 		}
1575*65393Sbostic 	tempfree(x);
1576*65393Sbostic 	return(true);
1577*65393Sbostic }
1578*65393Sbostic 
1579*65393Sbostic void closeall(void)
1580*65393Sbostic {
1581*65393Sbostic 	int i, stat;
1582*65393Sbostic 
1583*65393Sbostic 	for (i = 0; i < FOPEN_MAX; i++)
1584*65393Sbostic 		if (files[i].fp) {
1585*65393Sbostic 			if (ferror(files[i].fp))
1586*65393Sbostic 				ERROR "i/o error occurred on %s", files[i].fname WARNING;
1587*65393Sbostic 			if (files[i].mode == '|' || files[i].mode == LE)
1588*65393Sbostic 				stat = pclose(files[i].fp);
1589*65393Sbostic 			else
1590*65393Sbostic 				stat = fclose(files[i].fp);
1591*65393Sbostic 			if (stat == EOF)
1592*65393Sbostic 				ERROR "i/o error occurred while closing %s", files[i].fname WARNING;
1593*65393Sbostic 		}
1594*65393Sbostic }
1595*65393Sbostic 
1596*65393Sbostic #define	SUBSIZE	(20 * RECSIZE)
1597*65393Sbostic 
1598*65393Sbostic Cell *sub(Node **a, int nnn)	/* substitute command */
1599*65393Sbostic {
1600*65393Sbostic 	register uchar *sptr, *pb, *q;
1601*65393Sbostic 	register Cell *x, *y, *result;
1602*65393Sbostic 	uchar buf[SUBSIZE], *t;
1603*65393Sbostic 	fa *pfa;
1604*65393Sbostic 
1605*65393Sbostic 	x = execute(a[3]);	/* target string */
1606*65393Sbostic 	t = getsval(x);
1607*65393Sbostic 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
1608*65393Sbostic 		pfa = (fa *) a[1];	/* regular expression */
1609*65393Sbostic 	else {
1610*65393Sbostic 		y = execute(a[1]);
1611*65393Sbostic 		pfa = makedfa(getsval(y), 1);
1612*65393Sbostic 		tempfree(y);
1613*65393Sbostic 	}
1614*65393Sbostic 	y = execute(a[2]);	/* replacement string */
1615*65393Sbostic 	result = false;
1616*65393Sbostic 	if (pmatch(pfa, t)) {
1617*65393Sbostic 		pb = buf;
1618*65393Sbostic 		sptr = t;
1619*65393Sbostic 		while (sptr < patbeg)
1620*65393Sbostic 			*pb++ = *sptr++;
1621*65393Sbostic 		sptr = getsval(y);
1622*65393Sbostic 		while (*sptr != 0 && pb < buf + SUBSIZE - 1)
1623*65393Sbostic 			if (*sptr == '\\' && *(sptr+1) == '&') {
1624*65393Sbostic 				sptr++;		/* skip \, */
1625*65393Sbostic 				*pb++ = *sptr++; /* add & */
1626*65393Sbostic 			} else if (*sptr == '&') {
1627*65393Sbostic 				sptr++;
1628*65393Sbostic 				for (q = patbeg; q < patbeg+patlen; )
1629*65393Sbostic 					*pb++ = *q++;
1630*65393Sbostic 			} else
1631*65393Sbostic 				*pb++ = *sptr++;
1632*65393Sbostic 		*pb = '\0';
1633*65393Sbostic 		if (pb >= buf + SUBSIZE)
1634*65393Sbostic 			ERROR "sub() result %30s too big", buf FATAL;
1635*65393Sbostic 		sptr = patbeg + patlen;
1636*65393Sbostic 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1)))
1637*65393Sbostic 			while (*pb++ = *sptr++)
1638*65393Sbostic 				;
1639*65393Sbostic 		if (pb >= buf + SUBSIZE)
1640*65393Sbostic 			ERROR "sub() result %.30s too big", buf FATAL;
1641*65393Sbostic 		setsval(x, buf);
1642*65393Sbostic 		result = true;;
1643*65393Sbostic 	}
1644*65393Sbostic 	tempfree(x);
1645*65393Sbostic 	tempfree(y);
1646*65393Sbostic 	return result;
1647*65393Sbostic }
1648*65393Sbostic 
1649*65393Sbostic Cell *gsub(Node **a, int nnn)	/* global substitute */
1650*65393Sbostic {
1651*65393Sbostic 	register Cell *x, *y;
1652*65393Sbostic 	register uchar *rptr, *sptr, *t, *pb;
1653*65393Sbostic 	uchar buf[SUBSIZE];
1654*65393Sbostic 	register fa *pfa;
1655*65393Sbostic 	int mflag, tempstat, num;
1656*65393Sbostic 
1657*65393Sbostic 	mflag = 0;	/* if mflag == 0, can replace empty string */
1658*65393Sbostic 	num = 0;
1659*65393Sbostic 	x = execute(a[3]);	/* target string */
1660*65393Sbostic 	t = getsval(x);
1661*65393Sbostic 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
1662*65393Sbostic 		pfa = (fa *) a[1];	/* regular expression */
1663*65393Sbostic 	else {
1664*65393Sbostic 		y = execute(a[1]);
1665*65393Sbostic 		pfa = makedfa(getsval(y), 1);
1666*65393Sbostic 		tempfree(y);
1667*65393Sbostic 	}
1668*65393Sbostic 	y = execute(a[2]);	/* replacement string */
1669*65393Sbostic 	if (pmatch(pfa, t)) {
1670*65393Sbostic 		tempstat = pfa->initstat;
1671*65393Sbostic 		pfa->initstat = 2;
1672*65393Sbostic 		pb = buf;
1673*65393Sbostic 		rptr = getsval(y);
1674*65393Sbostic 		do {
1675*65393Sbostic 			/*
1676*65393Sbostic 			uchar *p;
1677*65393Sbostic 			int i;
1678*65393Sbostic 			printf("target string: %s, *patbeg = %o, patlen = %d\n",
1679*65393Sbostic 				t, *patbeg, patlen);
1680*65393Sbostic 			printf("	match found: ");
1681*65393Sbostic 			p=patbeg;
1682*65393Sbostic 			for (i=0; i<patlen; i++)
1683*65393Sbostic 				printf("%c", *p++);
1684*65393Sbostic 			printf("\n");
1685*65393Sbostic 			*/
1686*65393Sbostic 			if (patlen == 0 && *patbeg != 0) {	/* matched empty string */
1687*65393Sbostic 				if (mflag == 0) {	/* can replace empty */
1688*65393Sbostic 					num++;
1689*65393Sbostic 					sptr = rptr;
1690*65393Sbostic 					while (*sptr != 0 && pb < buf + SUBSIZE-1)
1691*65393Sbostic 						if (*sptr == '\\' && *(sptr+1) == '&') {
1692*65393Sbostic 							sptr++;
1693*65393Sbostic 							*pb++ = *sptr++;
1694*65393Sbostic 						} else if (*sptr == '&') {
1695*65393Sbostic 							uchar *q;
1696*65393Sbostic 							sptr++;
1697*65393Sbostic 							for (q = patbeg; q < patbeg+patlen; )
1698*65393Sbostic 								*pb++ = *q++;
1699*65393Sbostic 						} else
1700*65393Sbostic 							*pb++ = *sptr++;
1701*65393Sbostic 				}
1702*65393Sbostic 				if (*t == 0)	/* at end */
1703*65393Sbostic 					goto done;
1704*65393Sbostic 				*pb++ = *t++;
1705*65393Sbostic 				if (pb >= buf + SUBSIZE-1)
1706*65393Sbostic 					ERROR "gsub() result %.30s too big", buf FATAL;
1707*65393Sbostic 				mflag = 0;
1708*65393Sbostic 			}
1709*65393Sbostic 			else {	/* matched nonempty string */
1710*65393Sbostic 				num++;
1711*65393Sbostic 				sptr = t;
1712*65393Sbostic 				while (sptr < patbeg && pb < buf + SUBSIZE-1)
1713*65393Sbostic 					*pb++ = *sptr++;
1714*65393Sbostic 				sptr = rptr;
1715*65393Sbostic 				while (*sptr != 0 && pb < buf + SUBSIZE-1)
1716*65393Sbostic 					if (*sptr == '\\' && *(sptr+1) == '&') {
1717*65393Sbostic 						sptr++;
1718*65393Sbostic 						*pb++ = *sptr++;
1719*65393Sbostic 					} else if (*sptr == '&') {
1720*65393Sbostic 						uchar *q;
1721*65393Sbostic 						sptr++;
1722*65393Sbostic 						for (q = patbeg; q < patbeg+patlen; )
1723*65393Sbostic 							*pb++ = *q++;
1724*65393Sbostic 					} else
1725*65393Sbostic 						*pb++ = *sptr++;
1726*65393Sbostic 				t = patbeg + patlen;
1727*65393Sbostic 				if ((*(t-1) == 0) || (*t == 0))
1728*65393Sbostic 					goto done;
1729*65393Sbostic 				if (pb >= buf + SUBSIZE-1)
1730*65393Sbostic 					ERROR "gsub() result %.30s too big", buf FATAL;
1731*65393Sbostic 				mflag = 1;
1732*65393Sbostic 			}
1733*65393Sbostic 		} while (pmatch(pfa,t));
1734*65393Sbostic 		sptr = t;
1735*65393Sbostic 		while (*pb++ = *sptr++)
1736*65393Sbostic 			;
1737*65393Sbostic 	done:	if (pb >= buf + SUBSIZE-1)
1738*65393Sbostic 			ERROR "gsub() result %.30s too big", buf FATAL;
1739*65393Sbostic 		*pb = '\0';
1740*65393Sbostic 		setsval(x, buf);
1741*65393Sbostic 		pfa->initstat = tempstat;
1742*65393Sbostic 	}
1743*65393Sbostic 	tempfree(x);
1744*65393Sbostic 	tempfree(y);
1745*65393Sbostic 	x = gettemp();
1746*65393Sbostic 	x->tval = NUM;
1747*65393Sbostic 	x->fval = num;
1748*65393Sbostic 	return(x);
1749*65393Sbostic }
1750