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