xref: /inferno-os/utils/awk/run.c (revision 45a20ab721a513710138340faff3d59a31c3e01e)
174a4d8c2SCharles.Forsyth /****************************************************************
274a4d8c2SCharles.Forsyth Copyright (C) Lucent Technologies 1997
374a4d8c2SCharles.Forsyth All Rights Reserved
474a4d8c2SCharles.Forsyth 
574a4d8c2SCharles.Forsyth Permission to use, copy, modify, and distribute this software and
674a4d8c2SCharles.Forsyth its documentation for any purpose and without fee is hereby
774a4d8c2SCharles.Forsyth granted, provided that the above copyright notice appear in all
874a4d8c2SCharles.Forsyth copies and that both that the copyright notice and this
974a4d8c2SCharles.Forsyth permission notice and warranty disclaimer appear in supporting
1074a4d8c2SCharles.Forsyth documentation, and that the name Lucent Technologies or any of
1174a4d8c2SCharles.Forsyth its entities not be used in advertising or publicity pertaining
1274a4d8c2SCharles.Forsyth to distribution of the software without specific, written prior
1374a4d8c2SCharles.Forsyth permission.
1474a4d8c2SCharles.Forsyth 
1574a4d8c2SCharles.Forsyth LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1674a4d8c2SCharles.Forsyth INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1774a4d8c2SCharles.Forsyth IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
1874a4d8c2SCharles.Forsyth SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1974a4d8c2SCharles.Forsyth WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
2074a4d8c2SCharles.Forsyth IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2174a4d8c2SCharles.Forsyth ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
2274a4d8c2SCharles.Forsyth THIS SOFTWARE.
2374a4d8c2SCharles.Forsyth ****************************************************************/
2474a4d8c2SCharles.Forsyth 
2574a4d8c2SCharles.Forsyth #define DEBUG
2674a4d8c2SCharles.Forsyth #include <stdio.h>
2774a4d8c2SCharles.Forsyth #include <ctype.h>
2874a4d8c2SCharles.Forsyth #include <setjmp.h>
2974a4d8c2SCharles.Forsyth #include <math.h>
3074a4d8c2SCharles.Forsyth #include <string.h>
3174a4d8c2SCharles.Forsyth #include <stdlib.h>
3274a4d8c2SCharles.Forsyth #include <time.h>
3374a4d8c2SCharles.Forsyth #include "awk.h"
3474a4d8c2SCharles.Forsyth #include "ytab.h"
3574a4d8c2SCharles.Forsyth 
3674a4d8c2SCharles.Forsyth #define tempfree(x)	if (istemp(x)) tfree(x); else
3774a4d8c2SCharles.Forsyth 
3874a4d8c2SCharles.Forsyth /*
3974a4d8c2SCharles.Forsyth #undef tempfree
4074a4d8c2SCharles.Forsyth 
4174a4d8c2SCharles.Forsyth void tempfree(Cell *p) {
4274a4d8c2SCharles.Forsyth 	if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
4374a4d8c2SCharles.Forsyth 		WARNING("bad csub %d in Cell %d %s",
4474a4d8c2SCharles.Forsyth 			p->csub, p->ctype, p->sval);
4574a4d8c2SCharles.Forsyth 	}
4674a4d8c2SCharles.Forsyth 	if (istemp(p))
4774a4d8c2SCharles.Forsyth 		tfree(p);
4874a4d8c2SCharles.Forsyth }
4974a4d8c2SCharles.Forsyth */
5074a4d8c2SCharles.Forsyth 
5174a4d8c2SCharles.Forsyth #ifdef _NFILE
5274a4d8c2SCharles.Forsyth #ifndef FOPEN_MAX
5374a4d8c2SCharles.Forsyth #define FOPEN_MAX _NFILE
5474a4d8c2SCharles.Forsyth #endif
5574a4d8c2SCharles.Forsyth #endif
5674a4d8c2SCharles.Forsyth 
5774a4d8c2SCharles.Forsyth #ifndef	FOPEN_MAX
5874a4d8c2SCharles.Forsyth #define	FOPEN_MAX	40	/* max number of open files */
5974a4d8c2SCharles.Forsyth #endif
6074a4d8c2SCharles.Forsyth 
6174a4d8c2SCharles.Forsyth #ifndef RAND_MAX
6274a4d8c2SCharles.Forsyth #define RAND_MAX	32767	/* all that ansi guarantees */
6374a4d8c2SCharles.Forsyth #endif
6474a4d8c2SCharles.Forsyth 
6574a4d8c2SCharles.Forsyth jmp_buf env;
6674a4d8c2SCharles.Forsyth extern	int	pairstack[];
6774a4d8c2SCharles.Forsyth 
6874a4d8c2SCharles.Forsyth Node	*winner = NULL;	/* root of parse tree */
6974a4d8c2SCharles.Forsyth Cell	*tmps;		/* free temporary cells for execution */
7074a4d8c2SCharles.Forsyth 
7174a4d8c2SCharles.Forsyth static Cell	truecell	={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
7274a4d8c2SCharles.Forsyth Cell	*True	= &truecell;
7374a4d8c2SCharles.Forsyth static Cell	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
7474a4d8c2SCharles.Forsyth Cell	*False	= &falsecell;
7574a4d8c2SCharles.Forsyth static Cell	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
7674a4d8c2SCharles.Forsyth Cell	*jbreak	= &breakcell;
7774a4d8c2SCharles.Forsyth static Cell	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM };
7874a4d8c2SCharles.Forsyth Cell	*jcont	= &contcell;
7974a4d8c2SCharles.Forsyth static Cell	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
8074a4d8c2SCharles.Forsyth Cell	*jnext	= &nextcell;
8174a4d8c2SCharles.Forsyth static Cell	nextfilecell	={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
8274a4d8c2SCharles.Forsyth Cell	*jnextfile	= &nextfilecell;
8374a4d8c2SCharles.Forsyth static Cell	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
8474a4d8c2SCharles.Forsyth Cell	*jexit	= &exitcell;
8574a4d8c2SCharles.Forsyth static Cell	retcell		={ OJUMP, JRET, 0, 0, 0.0, NUM };
8674a4d8c2SCharles.Forsyth Cell	*jret	= &retcell;
8774a4d8c2SCharles.Forsyth static Cell	tempcell	={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
8874a4d8c2SCharles.Forsyth 
8974a4d8c2SCharles.Forsyth Node	*curnode = NULL;	/* the node being executed, for debugging */
9074a4d8c2SCharles.Forsyth 
9174a4d8c2SCharles.Forsyth /* buffer memory management */
adjbuf(char ** pbuf,int * psiz,int minlen,int quantum,char ** pbptr,char * whatrtn)9274a4d8c2SCharles.Forsyth int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
9374a4d8c2SCharles.Forsyth 	char *whatrtn)
9474a4d8c2SCharles.Forsyth /* pbuf:    address of pointer to buffer being managed
9574a4d8c2SCharles.Forsyth  * psiz:    address of buffer size variable
9674a4d8c2SCharles.Forsyth  * minlen:  minimum length of buffer needed
9774a4d8c2SCharles.Forsyth  * quantum: buffer size quantum
9874a4d8c2SCharles.Forsyth  * pbptr:   address of movable pointer into buffer, or 0 if none
9974a4d8c2SCharles.Forsyth  * whatrtn: name of the calling routine if failure should cause fatal error
10074a4d8c2SCharles.Forsyth  *
10174a4d8c2SCharles.Forsyth  * return   0 for realloc failure, !=0 for success
10274a4d8c2SCharles.Forsyth  */
10374a4d8c2SCharles.Forsyth {
10474a4d8c2SCharles.Forsyth 	if (minlen > *psiz) {
10574a4d8c2SCharles.Forsyth 		char *tbuf;
10674a4d8c2SCharles.Forsyth 		int rminlen = quantum ? minlen % quantum : 0;
10774a4d8c2SCharles.Forsyth 		int boff = pbptr ? *pbptr - *pbuf : 0;
10874a4d8c2SCharles.Forsyth 		/* round up to next multiple of quantum */
10974a4d8c2SCharles.Forsyth 		if (rminlen)
11074a4d8c2SCharles.Forsyth 			minlen += quantum - rminlen;
11174a4d8c2SCharles.Forsyth 		tbuf = (char *) realloc(*pbuf, minlen);
11274a4d8c2SCharles.Forsyth 		if (tbuf == NULL) {
11374a4d8c2SCharles.Forsyth 			if (whatrtn)
11474a4d8c2SCharles.Forsyth 				FATAL("out of memory in %s", whatrtn);
11574a4d8c2SCharles.Forsyth 			return 0;
11674a4d8c2SCharles.Forsyth 		}
11774a4d8c2SCharles.Forsyth 		*pbuf = tbuf;
11874a4d8c2SCharles.Forsyth 		*psiz = minlen;
11974a4d8c2SCharles.Forsyth 		if (pbptr)
12074a4d8c2SCharles.Forsyth 			*pbptr = tbuf + boff;
12174a4d8c2SCharles.Forsyth 	}
12274a4d8c2SCharles.Forsyth 	return 1;
12374a4d8c2SCharles.Forsyth }
12474a4d8c2SCharles.Forsyth 
run(Node * a)12574a4d8c2SCharles.Forsyth void run(Node *a)	/* execution of parse tree starts here */
12674a4d8c2SCharles.Forsyth {
12774a4d8c2SCharles.Forsyth 	extern void stdinit(void);
12874a4d8c2SCharles.Forsyth 
12974a4d8c2SCharles.Forsyth 	stdinit();
13074a4d8c2SCharles.Forsyth 	execute(a);
13174a4d8c2SCharles.Forsyth 	closeall();
13274a4d8c2SCharles.Forsyth }
13374a4d8c2SCharles.Forsyth 
execute(Node * u)13474a4d8c2SCharles.Forsyth Cell *execute(Node *u)	/* execute a node of the parse tree */
13574a4d8c2SCharles.Forsyth {
13674a4d8c2SCharles.Forsyth 	Cell *(*proc)(Node **, int);
13774a4d8c2SCharles.Forsyth 	Cell *x;
13874a4d8c2SCharles.Forsyth 	Node *a;
13974a4d8c2SCharles.Forsyth 
14074a4d8c2SCharles.Forsyth 	if (u == NULL)
14174a4d8c2SCharles.Forsyth 		return(True);
14274a4d8c2SCharles.Forsyth 	for (a = u; ; a = a->nnext) {
14374a4d8c2SCharles.Forsyth 		curnode = a;
14474a4d8c2SCharles.Forsyth 		if (isvalue(a)) {
14574a4d8c2SCharles.Forsyth 			x = (Cell *) (a->narg[0]);
14674a4d8c2SCharles.Forsyth 			if (isfld(x) && !donefld)
14774a4d8c2SCharles.Forsyth 				fldbld();
14874a4d8c2SCharles.Forsyth 			else if (isrec(x) && !donerec)
14974a4d8c2SCharles.Forsyth 				recbld();
15074a4d8c2SCharles.Forsyth 			return(x);
15174a4d8c2SCharles.Forsyth 		}
15274a4d8c2SCharles.Forsyth 		if (notlegal(a->nobj))	/* probably a Cell* but too risky to print */
15374a4d8c2SCharles.Forsyth 			FATAL("illegal statement");
15474a4d8c2SCharles.Forsyth 		proc = proctab[a->nobj-FIRSTTOKEN];
15574a4d8c2SCharles.Forsyth 		x = (*proc)(a->narg, a->nobj);
15674a4d8c2SCharles.Forsyth 		if (isfld(x) && !donefld)
15774a4d8c2SCharles.Forsyth 			fldbld();
15874a4d8c2SCharles.Forsyth 		else if (isrec(x) && !donerec)
15974a4d8c2SCharles.Forsyth 			recbld();
16074a4d8c2SCharles.Forsyth 		if (isexpr(a))
16174a4d8c2SCharles.Forsyth 			return(x);
16274a4d8c2SCharles.Forsyth 		if (isjump(x))
16374a4d8c2SCharles.Forsyth 			return(x);
16474a4d8c2SCharles.Forsyth 		if (a->nnext == NULL)
16574a4d8c2SCharles.Forsyth 			return(x);
16674a4d8c2SCharles.Forsyth 		tempfree(x);
16774a4d8c2SCharles.Forsyth 	}
16874a4d8c2SCharles.Forsyth }
16974a4d8c2SCharles.Forsyth 
17074a4d8c2SCharles.Forsyth 
program(Node ** a,int n)17174a4d8c2SCharles.Forsyth Cell *program(Node **a, int n)	/* execute an awk program */
17274a4d8c2SCharles.Forsyth {				/* a[0] = BEGIN, a[1] = body, a[2] = END */
17374a4d8c2SCharles.Forsyth 	Cell *x;
17474a4d8c2SCharles.Forsyth 
17574a4d8c2SCharles.Forsyth 	if (setjmp(env) != 0)
17674a4d8c2SCharles.Forsyth 		goto ex;
17774a4d8c2SCharles.Forsyth 	if (a[0]) {		/* BEGIN */
17874a4d8c2SCharles.Forsyth 		x = execute(a[0]);
17974a4d8c2SCharles.Forsyth 		if (isexit(x))
18074a4d8c2SCharles.Forsyth 			return(True);
18174a4d8c2SCharles.Forsyth 		if (isjump(x))
18274a4d8c2SCharles.Forsyth 			FATAL("illegal break, continue, next or nextfile from BEGIN");
18374a4d8c2SCharles.Forsyth 		tempfree(x);
18474a4d8c2SCharles.Forsyth 	}
18574a4d8c2SCharles.Forsyth 	if (a[1] || a[2])
18674a4d8c2SCharles.Forsyth 		while (getrec(&record, &recsize, 1) > 0) {
18774a4d8c2SCharles.Forsyth 			x = execute(a[1]);
18874a4d8c2SCharles.Forsyth 			if (isexit(x))
18974a4d8c2SCharles.Forsyth 				break;
19074a4d8c2SCharles.Forsyth 			tempfree(x);
19174a4d8c2SCharles.Forsyth 		}
19274a4d8c2SCharles.Forsyth   ex:
19374a4d8c2SCharles.Forsyth 	if (setjmp(env) != 0)	/* handles exit within END */
19474a4d8c2SCharles.Forsyth 		goto ex1;
19574a4d8c2SCharles.Forsyth 	if (a[2]) {		/* END */
19674a4d8c2SCharles.Forsyth 		x = execute(a[2]);
19774a4d8c2SCharles.Forsyth 		if (isbreak(x) || isnext(x) || iscont(x))
19874a4d8c2SCharles.Forsyth 			FATAL("illegal break, continue, next or nextfile from END");
19974a4d8c2SCharles.Forsyth 		tempfree(x);
20074a4d8c2SCharles.Forsyth 	}
20174a4d8c2SCharles.Forsyth   ex1:
20274a4d8c2SCharles.Forsyth 	return(True);
20374a4d8c2SCharles.Forsyth }
20474a4d8c2SCharles.Forsyth 
20574a4d8c2SCharles.Forsyth struct Frame {	/* stack frame for awk function calls */
20674a4d8c2SCharles.Forsyth 	int nargs;	/* number of arguments in this call */
20774a4d8c2SCharles.Forsyth 	Cell *fcncell;	/* pointer to Cell for function */
20874a4d8c2SCharles.Forsyth 	Cell **args;	/* pointer to array of arguments after execute */
20974a4d8c2SCharles.Forsyth 	Cell *retval;	/* return value */
21074a4d8c2SCharles.Forsyth };
21174a4d8c2SCharles.Forsyth 
21274a4d8c2SCharles.Forsyth #define	NARGS	50	/* max args in a call */
21374a4d8c2SCharles.Forsyth 
21474a4d8c2SCharles.Forsyth struct Frame *frame = NULL;	/* base of stack frames; dynamically allocated */
21574a4d8c2SCharles.Forsyth int	nframe = 0;		/* number of frames allocated */
21674a4d8c2SCharles.Forsyth struct Frame *fp = NULL;	/* frame pointer. bottom level unused */
21774a4d8c2SCharles.Forsyth 
call(Node ** a,int n)21874a4d8c2SCharles.Forsyth Cell *call(Node **a, int n)	/* function call.  very kludgy and fragile */
21974a4d8c2SCharles.Forsyth {
22074a4d8c2SCharles.Forsyth 	static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
22174a4d8c2SCharles.Forsyth 	int i, ncall, ndef;
22274a4d8c2SCharles.Forsyth 	Node *x;
22374a4d8c2SCharles.Forsyth 	Cell *args[NARGS], *oargs[NARGS];	/* BUG: fixed size arrays */
22474a4d8c2SCharles.Forsyth 	Cell *y, *z, *fcn;
22574a4d8c2SCharles.Forsyth 	char *s;
22674a4d8c2SCharles.Forsyth 
22774a4d8c2SCharles.Forsyth 	fcn = execute(a[0]);	/* the function itself */
22874a4d8c2SCharles.Forsyth 	s = fcn->nval;
22974a4d8c2SCharles.Forsyth 	if (!isfcn(fcn))
23074a4d8c2SCharles.Forsyth 		FATAL("calling undefined function %s", s);
23174a4d8c2SCharles.Forsyth 	if (frame == NULL) {
23274a4d8c2SCharles.Forsyth 		fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
23374a4d8c2SCharles.Forsyth 		if (frame == NULL)
23474a4d8c2SCharles.Forsyth 			FATAL("out of space for stack frames calling %s", s);
23574a4d8c2SCharles.Forsyth 	}
23674a4d8c2SCharles.Forsyth 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)	/* args in call */
23774a4d8c2SCharles.Forsyth 		ncall++;
23874a4d8c2SCharles.Forsyth 	ndef = (int) fcn->fval;			/* args in defn */
23974a4d8c2SCharles.Forsyth 	   dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
24074a4d8c2SCharles.Forsyth 	if (ncall > ndef)
24174a4d8c2SCharles.Forsyth 		WARNING("function %s called with %d args, uses only %d",
24274a4d8c2SCharles.Forsyth 			s, ncall, ndef);
24374a4d8c2SCharles.Forsyth 	if (ncall + ndef > NARGS)
24474a4d8c2SCharles.Forsyth 		FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
24574a4d8c2SCharles.Forsyth 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {	/* get call args */
24674a4d8c2SCharles.Forsyth 		   dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
24774a4d8c2SCharles.Forsyth 		y = execute(x);
24874a4d8c2SCharles.Forsyth 		oargs[i] = y;
24974a4d8c2SCharles.Forsyth 		   dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
25074a4d8c2SCharles.Forsyth 			   i, y->nval, y->fval, isarr(y) ? "(array)" : y->sval, y->tval) );
25174a4d8c2SCharles.Forsyth 		if (isfcn(y))
25274a4d8c2SCharles.Forsyth 			FATAL("can't use function %s as argument in %s", y->nval, s);
25374a4d8c2SCharles.Forsyth 		if (isarr(y))
25474a4d8c2SCharles.Forsyth 			args[i] = y;	/* arrays by ref */
25574a4d8c2SCharles.Forsyth 		else
25674a4d8c2SCharles.Forsyth 			args[i] = copycell(y);
25774a4d8c2SCharles.Forsyth 		tempfree(y);
25874a4d8c2SCharles.Forsyth 	}
25974a4d8c2SCharles.Forsyth 	for ( ; i < ndef; i++) {	/* add null args for ones not provided */
26074a4d8c2SCharles.Forsyth 		args[i] = gettemp();
26174a4d8c2SCharles.Forsyth 		*args[i] = newcopycell;
26274a4d8c2SCharles.Forsyth 	}
26374a4d8c2SCharles.Forsyth 	fp++;	/* now ok to up frame */
26474a4d8c2SCharles.Forsyth 	if (fp >= frame + nframe) {
26574a4d8c2SCharles.Forsyth 		int dfp = fp - frame;	/* old index */
26674a4d8c2SCharles.Forsyth 		frame = (struct Frame *)
26774a4d8c2SCharles.Forsyth 			realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
26874a4d8c2SCharles.Forsyth 		if (frame == NULL)
26974a4d8c2SCharles.Forsyth 			FATAL("out of space for stack frames in %s", s);
27074a4d8c2SCharles.Forsyth 		fp = frame + dfp;
27174a4d8c2SCharles.Forsyth 	}
27274a4d8c2SCharles.Forsyth 	fp->fcncell = fcn;
27374a4d8c2SCharles.Forsyth 	fp->args = args;
27474a4d8c2SCharles.Forsyth 	fp->nargs = ndef;	/* number defined with (excess are locals) */
27574a4d8c2SCharles.Forsyth 	fp->retval = gettemp();
27674a4d8c2SCharles.Forsyth 
27774a4d8c2SCharles.Forsyth 	   dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
27874a4d8c2SCharles.Forsyth 	y = execute((Node *)(fcn->sval));	/* execute body */
27974a4d8c2SCharles.Forsyth 	   dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
28074a4d8c2SCharles.Forsyth 
28174a4d8c2SCharles.Forsyth 	for (i = 0; i < ndef; i++) {
28274a4d8c2SCharles.Forsyth 		Cell *t = fp->args[i];
28374a4d8c2SCharles.Forsyth 		if (isarr(t)) {
28474a4d8c2SCharles.Forsyth 			if (t->csub == CCOPY) {
28574a4d8c2SCharles.Forsyth 				if (i >= ncall) {
28674a4d8c2SCharles.Forsyth 					freesymtab(t);
28774a4d8c2SCharles.Forsyth 					t->csub = CTEMP;
28874a4d8c2SCharles.Forsyth 					tempfree(t);
28974a4d8c2SCharles.Forsyth 				} else {
29074a4d8c2SCharles.Forsyth 					oargs[i]->tval = t->tval;
29174a4d8c2SCharles.Forsyth 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
29274a4d8c2SCharles.Forsyth 					oargs[i]->sval = t->sval;
29374a4d8c2SCharles.Forsyth 					tempfree(t);
29474a4d8c2SCharles.Forsyth 				}
29574a4d8c2SCharles.Forsyth 			}
29674a4d8c2SCharles.Forsyth 		} else if (t != y) {	/* kludge to prevent freeing twice */
29774a4d8c2SCharles.Forsyth 			t->csub = CTEMP;
29874a4d8c2SCharles.Forsyth 			tempfree(t);
29974a4d8c2SCharles.Forsyth 		}
30074a4d8c2SCharles.Forsyth 	}
30174a4d8c2SCharles.Forsyth 	tempfree(fcn);
30274a4d8c2SCharles.Forsyth 	if (isexit(y) || isnext(y))
30374a4d8c2SCharles.Forsyth 		return y;
30474a4d8c2SCharles.Forsyth 	tempfree(y);		/* this can free twice! */
30574a4d8c2SCharles.Forsyth 	z = fp->retval;			/* return value */
30674a4d8c2SCharles.Forsyth 	   dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
30774a4d8c2SCharles.Forsyth 	fp--;
30874a4d8c2SCharles.Forsyth 	return(z);
30974a4d8c2SCharles.Forsyth }
31074a4d8c2SCharles.Forsyth 
copycell(Cell * x)31174a4d8c2SCharles.Forsyth Cell *copycell(Cell *x)	/* make a copy of a cell in a temp */
31274a4d8c2SCharles.Forsyth {
31374a4d8c2SCharles.Forsyth 	Cell *y;
31474a4d8c2SCharles.Forsyth 
31574a4d8c2SCharles.Forsyth 	y = gettemp();
31674a4d8c2SCharles.Forsyth 	y->csub = CCOPY;	/* prevents freeing until call is over */
31774a4d8c2SCharles.Forsyth 	y->nval = x->nval;	/* BUG? */
31874a4d8c2SCharles.Forsyth 	if (isstr(x))
31974a4d8c2SCharles.Forsyth 		y->sval = tostring(x->sval);
32074a4d8c2SCharles.Forsyth 	y->fval = x->fval;
32174a4d8c2SCharles.Forsyth 	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);	/* copy is not constant or field */
32274a4d8c2SCharles.Forsyth 							/* is DONTFREE right? */
32374a4d8c2SCharles.Forsyth 	return y;
32474a4d8c2SCharles.Forsyth }
32574a4d8c2SCharles.Forsyth 
arg(Node ** a,int n)32674a4d8c2SCharles.Forsyth Cell *arg(Node **a, int n)	/* nth argument of a function */
32774a4d8c2SCharles.Forsyth {
32874a4d8c2SCharles.Forsyth 
32974a4d8c2SCharles.Forsyth 	n = ptoi(a[0]);	/* argument number, counting from 0 */
33074a4d8c2SCharles.Forsyth 	   dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
33174a4d8c2SCharles.Forsyth 	if (n+1 > fp->nargs)
33274a4d8c2SCharles.Forsyth 		FATAL("argument #%d of function %s was not supplied",
33374a4d8c2SCharles.Forsyth 			n+1, fp->fcncell->nval);
33474a4d8c2SCharles.Forsyth 	return fp->args[n];
33574a4d8c2SCharles.Forsyth }
33674a4d8c2SCharles.Forsyth 
jump(Node ** a,int n)33774a4d8c2SCharles.Forsyth Cell *jump(Node **a, int n)	/* break, continue, next, nextfile, return */
33874a4d8c2SCharles.Forsyth {
33974a4d8c2SCharles.Forsyth 	Cell *y;
34074a4d8c2SCharles.Forsyth 
34174a4d8c2SCharles.Forsyth 	switch (n) {
34274a4d8c2SCharles.Forsyth 	case EXIT:
34374a4d8c2SCharles.Forsyth 		if (a[0] != NULL) {
34474a4d8c2SCharles.Forsyth 			y = execute(a[0]);
34574a4d8c2SCharles.Forsyth 			errorflag = (int) getfval(y);
34674a4d8c2SCharles.Forsyth 			tempfree(y);
34774a4d8c2SCharles.Forsyth 		}
34874a4d8c2SCharles.Forsyth 		longjmp(env, 1);
34974a4d8c2SCharles.Forsyth 	case RETURN:
35074a4d8c2SCharles.Forsyth 		if (a[0] != NULL) {
35174a4d8c2SCharles.Forsyth 			y = execute(a[0]);
35274a4d8c2SCharles.Forsyth 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
35374a4d8c2SCharles.Forsyth 				setsval(fp->retval, getsval(y));
35474a4d8c2SCharles.Forsyth 				fp->retval->fval = getfval(y);
35574a4d8c2SCharles.Forsyth 				fp->retval->tval |= NUM;
35674a4d8c2SCharles.Forsyth 			}
35774a4d8c2SCharles.Forsyth 			else if (y->tval & STR)
35874a4d8c2SCharles.Forsyth 				setsval(fp->retval, getsval(y));
35974a4d8c2SCharles.Forsyth 			else if (y->tval & NUM)
36074a4d8c2SCharles.Forsyth 				setfval(fp->retval, getfval(y));
36174a4d8c2SCharles.Forsyth 			else		/* can't happen */
36274a4d8c2SCharles.Forsyth 				FATAL("bad type variable %d", y->tval);
36374a4d8c2SCharles.Forsyth 			tempfree(y);
36474a4d8c2SCharles.Forsyth 		}
36574a4d8c2SCharles.Forsyth 		return(jret);
36674a4d8c2SCharles.Forsyth 	case NEXT:
36774a4d8c2SCharles.Forsyth 		return(jnext);
36874a4d8c2SCharles.Forsyth 	case NEXTFILE:
36974a4d8c2SCharles.Forsyth 		nextfile();
37074a4d8c2SCharles.Forsyth 		return(jnextfile);
37174a4d8c2SCharles.Forsyth 	case BREAK:
37274a4d8c2SCharles.Forsyth 		return(jbreak);
37374a4d8c2SCharles.Forsyth 	case CONTINUE:
37474a4d8c2SCharles.Forsyth 		return(jcont);
37574a4d8c2SCharles.Forsyth 	default:	/* can't happen */
37674a4d8c2SCharles.Forsyth 		FATAL("illegal jump type %d", n);
37774a4d8c2SCharles.Forsyth 	}
37874a4d8c2SCharles.Forsyth 	return 0;	/* not reached */
37974a4d8c2SCharles.Forsyth }
38074a4d8c2SCharles.Forsyth 
getline(Node ** a,int n)38174a4d8c2SCharles.Forsyth Cell *getline(Node **a, int n)	/* get next line from specific input */
38274a4d8c2SCharles.Forsyth {		/* a[0] is variable, a[1] is operator, a[2] is filename */
38374a4d8c2SCharles.Forsyth 	Cell *r, *x;
38474a4d8c2SCharles.Forsyth 	extern Cell **fldtab;
38574a4d8c2SCharles.Forsyth 	FILE *fp;
38674a4d8c2SCharles.Forsyth 	char *buf;
38774a4d8c2SCharles.Forsyth 	int bufsize = recsize;
38874a4d8c2SCharles.Forsyth 	int mode;
38974a4d8c2SCharles.Forsyth 
39074a4d8c2SCharles.Forsyth 	if ((buf = (char *) malloc(bufsize)) == NULL)
39174a4d8c2SCharles.Forsyth 		FATAL("out of memory in getline");
39274a4d8c2SCharles.Forsyth 
39374a4d8c2SCharles.Forsyth 	fflush(stdout);	/* in case someone is waiting for a prompt */
39474a4d8c2SCharles.Forsyth 	r = gettemp();
39574a4d8c2SCharles.Forsyth 	if (a[1] != NULL) {		/* getline < file */
39674a4d8c2SCharles.Forsyth 		x = execute(a[2]);		/* filename */
39774a4d8c2SCharles.Forsyth 		mode = ptoi(a[1]);
39874a4d8c2SCharles.Forsyth 		if (mode == '|')		/* input pipe */
39974a4d8c2SCharles.Forsyth 			mode = LE;	/* arbitrary flag */
40074a4d8c2SCharles.Forsyth 		fp = openfile(mode, getsval(x));
40174a4d8c2SCharles.Forsyth 		tempfree(x);
40274a4d8c2SCharles.Forsyth 		if (fp == NULL)
40374a4d8c2SCharles.Forsyth 			n = -1;
40474a4d8c2SCharles.Forsyth 		else
40574a4d8c2SCharles.Forsyth 			n = readrec(&buf, &bufsize, fp);
40674a4d8c2SCharles.Forsyth 		if (n <= 0) {
40774a4d8c2SCharles.Forsyth 			;
40874a4d8c2SCharles.Forsyth 		} else if (a[0] != NULL) {	/* getline var <file */
40974a4d8c2SCharles.Forsyth 			x = execute(a[0]);
41074a4d8c2SCharles.Forsyth 			setsval(x, buf);
41174a4d8c2SCharles.Forsyth 			tempfree(x);
41274a4d8c2SCharles.Forsyth 		} else {			/* getline <file */
41374a4d8c2SCharles.Forsyth 			setsval(fldtab[0], buf);
41474a4d8c2SCharles.Forsyth 			if (is_number(fldtab[0]->sval)) {
41574a4d8c2SCharles.Forsyth 				fldtab[0]->fval = atof(fldtab[0]->sval);
41674a4d8c2SCharles.Forsyth 				fldtab[0]->tval |= NUM;
41774a4d8c2SCharles.Forsyth 			}
41874a4d8c2SCharles.Forsyth 		}
41974a4d8c2SCharles.Forsyth 	} else {			/* bare getline; use current input */
42074a4d8c2SCharles.Forsyth 		if (a[0] == NULL)	/* getline */
42174a4d8c2SCharles.Forsyth 			n = getrec(&record, &recsize, 1);
42274a4d8c2SCharles.Forsyth 		else {			/* getline var */
42374a4d8c2SCharles.Forsyth 			n = getrec(&buf, &bufsize, 0);
42474a4d8c2SCharles.Forsyth 			x = execute(a[0]);
42574a4d8c2SCharles.Forsyth 			setsval(x, buf);
42674a4d8c2SCharles.Forsyth 			tempfree(x);
42774a4d8c2SCharles.Forsyth 		}
42874a4d8c2SCharles.Forsyth 	}
42974a4d8c2SCharles.Forsyth 	setfval(r, (Awkfloat) n);
43074a4d8c2SCharles.Forsyth 	free(buf);
43174a4d8c2SCharles.Forsyth 	return r;
43274a4d8c2SCharles.Forsyth }
43374a4d8c2SCharles.Forsyth 
getnf(Node ** a,int n)43474a4d8c2SCharles.Forsyth Cell *getnf(Node **a, int n)	/* get NF */
43574a4d8c2SCharles.Forsyth {
43674a4d8c2SCharles.Forsyth 	if (donefld == 0)
43774a4d8c2SCharles.Forsyth 		fldbld();
43874a4d8c2SCharles.Forsyth 	return (Cell *) a[0];
43974a4d8c2SCharles.Forsyth }
44074a4d8c2SCharles.Forsyth 
array(Node ** a,int n)44174a4d8c2SCharles.Forsyth Cell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
44274a4d8c2SCharles.Forsyth {
44374a4d8c2SCharles.Forsyth 	Cell *x, *y, *z;
44474a4d8c2SCharles.Forsyth 	char *s;
44574a4d8c2SCharles.Forsyth 	Node *np;
44674a4d8c2SCharles.Forsyth 	char *buf;
44774a4d8c2SCharles.Forsyth 	int bufsz = recsize;
44874a4d8c2SCharles.Forsyth 	int nsub = strlen(*SUBSEP);
44974a4d8c2SCharles.Forsyth 
45074a4d8c2SCharles.Forsyth 	if ((buf = (char *) malloc(bufsz)) == NULL)
45174a4d8c2SCharles.Forsyth 		FATAL("out of memory in array");
45274a4d8c2SCharles.Forsyth 
45374a4d8c2SCharles.Forsyth 	x = execute(a[0]);	/* Cell* for symbol table */
45474a4d8c2SCharles.Forsyth 	buf[0] = 0;
45574a4d8c2SCharles.Forsyth 	for (np = a[1]; np; np = np->nnext) {
45674a4d8c2SCharles.Forsyth 		y = execute(np);	/* subscript */
45774a4d8c2SCharles.Forsyth 		s = getsval(y);
45874a4d8c2SCharles.Forsyth 		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
45974a4d8c2SCharles.Forsyth 			FATAL("out of memory for %s[%s...]", x->nval, buf);
46074a4d8c2SCharles.Forsyth 		strcat(buf, s);
46174a4d8c2SCharles.Forsyth 		if (np->nnext)
46274a4d8c2SCharles.Forsyth 			strcat(buf, *SUBSEP);
46374a4d8c2SCharles.Forsyth 		tempfree(y);
46474a4d8c2SCharles.Forsyth 	}
46574a4d8c2SCharles.Forsyth 	if (!isarr(x)) {
46674a4d8c2SCharles.Forsyth 		   dprintf( ("making %s into an array\n", x->nval) );
46774a4d8c2SCharles.Forsyth 		if (freeable(x))
46874a4d8c2SCharles.Forsyth 			xfree(x->sval);
46974a4d8c2SCharles.Forsyth 		x->tval &= ~(STR|NUM|DONTFREE);
47074a4d8c2SCharles.Forsyth 		x->tval |= ARR;
47174a4d8c2SCharles.Forsyth 		x->sval = (char *) makesymtab(NSYMTAB);
47274a4d8c2SCharles.Forsyth 	}
47374a4d8c2SCharles.Forsyth 	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
47474a4d8c2SCharles.Forsyth 	z->ctype = OCELL;
47574a4d8c2SCharles.Forsyth 	z->csub = CVAR;
47674a4d8c2SCharles.Forsyth 	tempfree(x);
47774a4d8c2SCharles.Forsyth 	free(buf);
47874a4d8c2SCharles.Forsyth 	return(z);
47974a4d8c2SCharles.Forsyth }
48074a4d8c2SCharles.Forsyth 
awkdelete(Node ** a,int n)48174a4d8c2SCharles.Forsyth Cell *awkdelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
48274a4d8c2SCharles.Forsyth {
48374a4d8c2SCharles.Forsyth 	Cell *x, *y;
48474a4d8c2SCharles.Forsyth 	Node *np;
48574a4d8c2SCharles.Forsyth 	char *s;
48674a4d8c2SCharles.Forsyth 	int nsub = strlen(*SUBSEP);
48774a4d8c2SCharles.Forsyth 
48874a4d8c2SCharles.Forsyth 	x = execute(a[0]);	/* Cell* for symbol table */
48974a4d8c2SCharles.Forsyth 	if (!isarr(x))
49074a4d8c2SCharles.Forsyth 		return True;
49174a4d8c2SCharles.Forsyth 	if (a[1] == 0) {	/* delete the elements, not the table */
49274a4d8c2SCharles.Forsyth 		freesymtab(x);
49374a4d8c2SCharles.Forsyth 		x->tval &= ~STR;
49474a4d8c2SCharles.Forsyth 		x->tval |= ARR;
49574a4d8c2SCharles.Forsyth 		x->sval = (char *) makesymtab(NSYMTAB);
49674a4d8c2SCharles.Forsyth 	} else {
49774a4d8c2SCharles.Forsyth 		int bufsz = recsize;
49874a4d8c2SCharles.Forsyth 		char *buf;
49974a4d8c2SCharles.Forsyth 		if ((buf = (char *) malloc(bufsz)) == NULL)
50074a4d8c2SCharles.Forsyth 			FATAL("out of memory in adelete");
50174a4d8c2SCharles.Forsyth 		buf[0] = 0;
50274a4d8c2SCharles.Forsyth 		for (np = a[1]; np; np = np->nnext) {
50374a4d8c2SCharles.Forsyth 			y = execute(np);	/* subscript */
50474a4d8c2SCharles.Forsyth 			s = getsval(y);
50574a4d8c2SCharles.Forsyth 			if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
50674a4d8c2SCharles.Forsyth 				FATAL("out of memory deleting %s[%s...]", x->nval, buf);
50774a4d8c2SCharles.Forsyth 			strcat(buf, s);
50874a4d8c2SCharles.Forsyth 			if (np->nnext)
50974a4d8c2SCharles.Forsyth 				strcat(buf, *SUBSEP);
51074a4d8c2SCharles.Forsyth 			tempfree(y);
51174a4d8c2SCharles.Forsyth 		}
51274a4d8c2SCharles.Forsyth 		freeelem(x, buf);
51374a4d8c2SCharles.Forsyth 		free(buf);
51474a4d8c2SCharles.Forsyth 	}
51574a4d8c2SCharles.Forsyth 	tempfree(x);
51674a4d8c2SCharles.Forsyth 	return True;
51774a4d8c2SCharles.Forsyth }
51874a4d8c2SCharles.Forsyth 
intest(Node ** a,int n)51974a4d8c2SCharles.Forsyth Cell *intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
52074a4d8c2SCharles.Forsyth {
52174a4d8c2SCharles.Forsyth 	Cell *x, *ap, *k;
52274a4d8c2SCharles.Forsyth 	Node *p;
52374a4d8c2SCharles.Forsyth 	char *buf;
52474a4d8c2SCharles.Forsyth 	char *s;
52574a4d8c2SCharles.Forsyth 	int bufsz = recsize;
52674a4d8c2SCharles.Forsyth 	int nsub = strlen(*SUBSEP);
52774a4d8c2SCharles.Forsyth 
52874a4d8c2SCharles.Forsyth 	ap = execute(a[1]);	/* array name */
52974a4d8c2SCharles.Forsyth 	if (!isarr(ap)) {
53074a4d8c2SCharles.Forsyth 		   dprintf( ("making %s into an array\n", ap->nval) );
53174a4d8c2SCharles.Forsyth 		if (freeable(ap))
53274a4d8c2SCharles.Forsyth 			xfree(ap->sval);
53374a4d8c2SCharles.Forsyth 		ap->tval &= ~(STR|NUM|DONTFREE);
53474a4d8c2SCharles.Forsyth 		ap->tval |= ARR;
53574a4d8c2SCharles.Forsyth 		ap->sval = (char *) makesymtab(NSYMTAB);
53674a4d8c2SCharles.Forsyth 	}
53774a4d8c2SCharles.Forsyth 	if ((buf = (char *) malloc(bufsz)) == NULL) {
53874a4d8c2SCharles.Forsyth 		FATAL("out of memory in intest");
53974a4d8c2SCharles.Forsyth 	}
54074a4d8c2SCharles.Forsyth 	buf[0] = 0;
54174a4d8c2SCharles.Forsyth 	for (p = a[0]; p; p = p->nnext) {
54274a4d8c2SCharles.Forsyth 		x = execute(p);	/* expr */
54374a4d8c2SCharles.Forsyth 		s = getsval(x);
54474a4d8c2SCharles.Forsyth 		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
54574a4d8c2SCharles.Forsyth 			FATAL("out of memory deleting %s[%s...]", x->nval, buf);
54674a4d8c2SCharles.Forsyth 		strcat(buf, s);
54774a4d8c2SCharles.Forsyth 		tempfree(x);
54874a4d8c2SCharles.Forsyth 		if (p->nnext)
54974a4d8c2SCharles.Forsyth 			strcat(buf, *SUBSEP);
55074a4d8c2SCharles.Forsyth 	}
55174a4d8c2SCharles.Forsyth 	k = lookup(buf, (Array *) ap->sval);
55274a4d8c2SCharles.Forsyth 	tempfree(ap);
55374a4d8c2SCharles.Forsyth 	free(buf);
55474a4d8c2SCharles.Forsyth 	if (k == NULL)
55574a4d8c2SCharles.Forsyth 		return(False);
55674a4d8c2SCharles.Forsyth 	else
55774a4d8c2SCharles.Forsyth 		return(True);
55874a4d8c2SCharles.Forsyth }
55974a4d8c2SCharles.Forsyth 
56074a4d8c2SCharles.Forsyth 
matchop(Node ** a,int n)56174a4d8c2SCharles.Forsyth Cell *matchop(Node **a, int n)	/* ~ and match() */
56274a4d8c2SCharles.Forsyth {
56374a4d8c2SCharles.Forsyth 	Cell *x, *y;
56474a4d8c2SCharles.Forsyth 	char *s, *t;
56574a4d8c2SCharles.Forsyth 	int i;
56674a4d8c2SCharles.Forsyth 	fa *pfa;
56774a4d8c2SCharles.Forsyth 	int (*mf)(fa *, char *) = match, mode = 0;
56874a4d8c2SCharles.Forsyth 
56974a4d8c2SCharles.Forsyth 	if (n == MATCHFCN) {
57074a4d8c2SCharles.Forsyth 		mf = pmatch;
57174a4d8c2SCharles.Forsyth 		mode = 1;
57274a4d8c2SCharles.Forsyth 	}
57374a4d8c2SCharles.Forsyth 	x = execute(a[1]);	/* a[1] = target text */
57474a4d8c2SCharles.Forsyth 	s = getsval(x);
57574a4d8c2SCharles.Forsyth 	if (a[0] == 0)		/* a[1] == 0: already-compiled reg expr */
57674a4d8c2SCharles.Forsyth 		i = (*mf)((fa *) a[2], s);
57774a4d8c2SCharles.Forsyth 	else {
57874a4d8c2SCharles.Forsyth 		y = execute(a[2]);	/* a[2] = regular expr */
57974a4d8c2SCharles.Forsyth 		t = getsval(y);
58074a4d8c2SCharles.Forsyth 		pfa = makedfa(t, mode);
58174a4d8c2SCharles.Forsyth 		i = (*mf)(pfa, s);
58274a4d8c2SCharles.Forsyth 		tempfree(y);
58374a4d8c2SCharles.Forsyth 	}
58474a4d8c2SCharles.Forsyth 	tempfree(x);
58574a4d8c2SCharles.Forsyth 	if (n == MATCHFCN) {
58674a4d8c2SCharles.Forsyth 		int start = patbeg - s + 1;
58774a4d8c2SCharles.Forsyth 		if (patlen < 0)
58874a4d8c2SCharles.Forsyth 			start = 0;
58974a4d8c2SCharles.Forsyth 		setfval(rstartloc, (Awkfloat) start);
59074a4d8c2SCharles.Forsyth 		setfval(rlengthloc, (Awkfloat) patlen);
59174a4d8c2SCharles.Forsyth 		x = gettemp();
59274a4d8c2SCharles.Forsyth 		x->tval = NUM;
59374a4d8c2SCharles.Forsyth 		x->fval = start;
59474a4d8c2SCharles.Forsyth 		return x;
59574a4d8c2SCharles.Forsyth 	} else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
59674a4d8c2SCharles.Forsyth 		return(True);
59774a4d8c2SCharles.Forsyth 	else
59874a4d8c2SCharles.Forsyth 		return(False);
59974a4d8c2SCharles.Forsyth }
60074a4d8c2SCharles.Forsyth 
60174a4d8c2SCharles.Forsyth 
boolop(Node ** a,int n)60274a4d8c2SCharles.Forsyth Cell *boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
60374a4d8c2SCharles.Forsyth {
60474a4d8c2SCharles.Forsyth 	Cell *x, *y;
60574a4d8c2SCharles.Forsyth 	int i;
60674a4d8c2SCharles.Forsyth 
60774a4d8c2SCharles.Forsyth 	x = execute(a[0]);
60874a4d8c2SCharles.Forsyth 	i = istrue(x);
60974a4d8c2SCharles.Forsyth 	tempfree(x);
61074a4d8c2SCharles.Forsyth 	switch (n) {
61174a4d8c2SCharles.Forsyth 	case BOR:
61274a4d8c2SCharles.Forsyth 		if (i) return(True);
61374a4d8c2SCharles.Forsyth 		y = execute(a[1]);
61474a4d8c2SCharles.Forsyth 		i = istrue(y);
61574a4d8c2SCharles.Forsyth 		tempfree(y);
61674a4d8c2SCharles.Forsyth 		if (i) return(True);
61774a4d8c2SCharles.Forsyth 		else return(False);
61874a4d8c2SCharles.Forsyth 	case AND:
61974a4d8c2SCharles.Forsyth 		if ( !i ) return(False);
62074a4d8c2SCharles.Forsyth 		y = execute(a[1]);
62174a4d8c2SCharles.Forsyth 		i = istrue(y);
62274a4d8c2SCharles.Forsyth 		tempfree(y);
62374a4d8c2SCharles.Forsyth 		if (i) return(True);
62474a4d8c2SCharles.Forsyth 		else return(False);
62574a4d8c2SCharles.Forsyth 	case NOT:
62674a4d8c2SCharles.Forsyth 		if (i) return(False);
62774a4d8c2SCharles.Forsyth 		else return(True);
62874a4d8c2SCharles.Forsyth 	default:	/* can't happen */
62974a4d8c2SCharles.Forsyth 		FATAL("unknown boolean operator %d", n);
63074a4d8c2SCharles.Forsyth 	}
63174a4d8c2SCharles.Forsyth 	return 0;	/*NOTREACHED*/
63274a4d8c2SCharles.Forsyth }
63374a4d8c2SCharles.Forsyth 
relop(Node ** a,int n)63474a4d8c2SCharles.Forsyth Cell *relop(Node **a, int n)	/* a[0 < a[1], etc. */
63574a4d8c2SCharles.Forsyth {
63674a4d8c2SCharles.Forsyth 	int i;
63774a4d8c2SCharles.Forsyth 	Cell *x, *y;
63874a4d8c2SCharles.Forsyth 	Awkfloat j;
63974a4d8c2SCharles.Forsyth 
64074a4d8c2SCharles.Forsyth 	x = execute(a[0]);
64174a4d8c2SCharles.Forsyth 	y = execute(a[1]);
64274a4d8c2SCharles.Forsyth 	if (x->tval&NUM && y->tval&NUM) {
64374a4d8c2SCharles.Forsyth 		j = x->fval - y->fval;
64474a4d8c2SCharles.Forsyth 		i = j<0? -1: (j>0? 1: 0);
64574a4d8c2SCharles.Forsyth 	} else {
64674a4d8c2SCharles.Forsyth 		i = strcmp(getsval(x), getsval(y));
64774a4d8c2SCharles.Forsyth 	}
64874a4d8c2SCharles.Forsyth 	tempfree(x);
64974a4d8c2SCharles.Forsyth 	tempfree(y);
65074a4d8c2SCharles.Forsyth 	switch (n) {
65174a4d8c2SCharles.Forsyth 	case LT:	if (i<0) return(True);
65274a4d8c2SCharles.Forsyth 			else return(False);
65374a4d8c2SCharles.Forsyth 	case LE:	if (i<=0) return(True);
65474a4d8c2SCharles.Forsyth 			else return(False);
65574a4d8c2SCharles.Forsyth 	case NE:	if (i!=0) return(True);
65674a4d8c2SCharles.Forsyth 			else return(False);
65774a4d8c2SCharles.Forsyth 	case EQ:	if (i == 0) return(True);
65874a4d8c2SCharles.Forsyth 			else return(False);
65974a4d8c2SCharles.Forsyth 	case GE:	if (i>=0) return(True);
66074a4d8c2SCharles.Forsyth 			else return(False);
66174a4d8c2SCharles.Forsyth 	case GT:	if (i>0) return(True);
66274a4d8c2SCharles.Forsyth 			else return(False);
66374a4d8c2SCharles.Forsyth 	default:	/* can't happen */
66474a4d8c2SCharles.Forsyth 		FATAL("unknown relational operator %d", n);
66574a4d8c2SCharles.Forsyth 	}
66674a4d8c2SCharles.Forsyth 	return 0;	/*NOTREACHED*/
66774a4d8c2SCharles.Forsyth }
66874a4d8c2SCharles.Forsyth 
tfree(Cell * a)66974a4d8c2SCharles.Forsyth void tfree(Cell *a)	/* free a tempcell */
67074a4d8c2SCharles.Forsyth {
67174a4d8c2SCharles.Forsyth 	if (freeable(a)) {
67274a4d8c2SCharles.Forsyth 		   dprintf( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) );
67374a4d8c2SCharles.Forsyth 		xfree(a->sval);
67474a4d8c2SCharles.Forsyth 	}
67574a4d8c2SCharles.Forsyth 	if (a == tmps)
67674a4d8c2SCharles.Forsyth 		FATAL("tempcell list is curdled");
67774a4d8c2SCharles.Forsyth 	a->cnext = tmps;
67874a4d8c2SCharles.Forsyth 	tmps = a;
67974a4d8c2SCharles.Forsyth }
68074a4d8c2SCharles.Forsyth 
gettemp(void)68174a4d8c2SCharles.Forsyth Cell *gettemp(void)	/* get a tempcell */
68274a4d8c2SCharles.Forsyth {	int i;
68374a4d8c2SCharles.Forsyth 	Cell *x;
68474a4d8c2SCharles.Forsyth 
68574a4d8c2SCharles.Forsyth 	if (!tmps) {
68674a4d8c2SCharles.Forsyth 		tmps = (Cell *) calloc(100, sizeof(Cell));
68774a4d8c2SCharles.Forsyth 		if (!tmps)
68874a4d8c2SCharles.Forsyth 			FATAL("out of space for temporaries");
68974a4d8c2SCharles.Forsyth 		for(i = 1; i < 100; i++)
69074a4d8c2SCharles.Forsyth 			tmps[i-1].cnext = &tmps[i];
69174a4d8c2SCharles.Forsyth 		tmps[i-1].cnext = 0;
69274a4d8c2SCharles.Forsyth 	}
69374a4d8c2SCharles.Forsyth 	x = tmps;
69474a4d8c2SCharles.Forsyth 	tmps = x->cnext;
69574a4d8c2SCharles.Forsyth 	*x = tempcell;
69674a4d8c2SCharles.Forsyth 	return(x);
69774a4d8c2SCharles.Forsyth }
69874a4d8c2SCharles.Forsyth 
indirect(Node ** a,int n)69974a4d8c2SCharles.Forsyth Cell *indirect(Node **a, int n)	/* $( a[0] ) */
70074a4d8c2SCharles.Forsyth {
70174a4d8c2SCharles.Forsyth 	Cell *x;
70274a4d8c2SCharles.Forsyth 	int m;
70374a4d8c2SCharles.Forsyth 	char *s;
70474a4d8c2SCharles.Forsyth 
70574a4d8c2SCharles.Forsyth 	x = execute(a[0]);
70674a4d8c2SCharles.Forsyth 	m = (int) getfval(x);
70774a4d8c2SCharles.Forsyth 	if (m == 0 && !is_number(s = getsval(x)))	/* suspicion! */
70874a4d8c2SCharles.Forsyth 		FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
70974a4d8c2SCharles.Forsyth 		/* BUG: can x->nval ever be null??? */
71074a4d8c2SCharles.Forsyth 	tempfree(x);
71174a4d8c2SCharles.Forsyth 	x = fieldadr(m);
71274a4d8c2SCharles.Forsyth 	x->ctype = OCELL;	/* BUG?  why are these needed? */
71374a4d8c2SCharles.Forsyth 	x->csub = CFLD;
71474a4d8c2SCharles.Forsyth 	return(x);
71574a4d8c2SCharles.Forsyth }
71674a4d8c2SCharles.Forsyth 
substr(Node ** a,int nnn)71774a4d8c2SCharles.Forsyth Cell *substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
71874a4d8c2SCharles.Forsyth {
71974a4d8c2SCharles.Forsyth 	int k, m, n;
72074a4d8c2SCharles.Forsyth 	char *s;
72174a4d8c2SCharles.Forsyth 	int temp;
72274a4d8c2SCharles.Forsyth 	Cell *x, *y, *z = 0;
72374a4d8c2SCharles.Forsyth 
72474a4d8c2SCharles.Forsyth 	x = execute(a[0]);
72574a4d8c2SCharles.Forsyth 	y = execute(a[1]);
72674a4d8c2SCharles.Forsyth 	if (a[2] != 0)
72774a4d8c2SCharles.Forsyth 		z = execute(a[2]);
72874a4d8c2SCharles.Forsyth 	s = getsval(x);
72974a4d8c2SCharles.Forsyth 	k = strlen(s) + 1;
73074a4d8c2SCharles.Forsyth 	if (k <= 1) {
73174a4d8c2SCharles.Forsyth 		tempfree(x);
73274a4d8c2SCharles.Forsyth 		tempfree(y);
73374a4d8c2SCharles.Forsyth 		if (a[2] != 0) {
73474a4d8c2SCharles.Forsyth 			tempfree(z);
73574a4d8c2SCharles.Forsyth 		}
73674a4d8c2SCharles.Forsyth 		x = gettemp();
73774a4d8c2SCharles.Forsyth 		setsval(x, "");
73874a4d8c2SCharles.Forsyth 		return(x);
73974a4d8c2SCharles.Forsyth 	}
74074a4d8c2SCharles.Forsyth 	m = (int) getfval(y);
74174a4d8c2SCharles.Forsyth 	if (m <= 0)
74274a4d8c2SCharles.Forsyth 		m = 1;
74374a4d8c2SCharles.Forsyth 	else if (m > k)
74474a4d8c2SCharles.Forsyth 		m = k;
74574a4d8c2SCharles.Forsyth 	tempfree(y);
74674a4d8c2SCharles.Forsyth 	if (a[2] != 0) {
74774a4d8c2SCharles.Forsyth 		n = (int) getfval(z);
74874a4d8c2SCharles.Forsyth 		tempfree(z);
74974a4d8c2SCharles.Forsyth 	} else
75074a4d8c2SCharles.Forsyth 		n = k - 1;
75174a4d8c2SCharles.Forsyth 	if (n < 0)
75274a4d8c2SCharles.Forsyth 		n = 0;
75374a4d8c2SCharles.Forsyth 	else if (n > k - m)
75474a4d8c2SCharles.Forsyth 		n = k - m;
75574a4d8c2SCharles.Forsyth 	   dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
75674a4d8c2SCharles.Forsyth 	y = gettemp();
75774a4d8c2SCharles.Forsyth 	temp = s[n+m-1];	/* with thanks to John Linderman */
75874a4d8c2SCharles.Forsyth 	s[n+m-1] = '\0';
75974a4d8c2SCharles.Forsyth 	setsval(y, s + m - 1);
76074a4d8c2SCharles.Forsyth 	s[n+m-1] = temp;
76174a4d8c2SCharles.Forsyth 	tempfree(x);
76274a4d8c2SCharles.Forsyth 	return(y);
76374a4d8c2SCharles.Forsyth }
76474a4d8c2SCharles.Forsyth 
sindex(Node ** a,int nnn)76574a4d8c2SCharles.Forsyth Cell *sindex(Node **a, int nnn)		/* index(a[0], a[1]) */
76674a4d8c2SCharles.Forsyth {
76774a4d8c2SCharles.Forsyth 	Cell *x, *y, *z;
76874a4d8c2SCharles.Forsyth 	char *s1, *s2, *p1, *p2, *q;
76974a4d8c2SCharles.Forsyth 	Awkfloat v = 0.0;
77074a4d8c2SCharles.Forsyth 
77174a4d8c2SCharles.Forsyth 	x = execute(a[0]);
77274a4d8c2SCharles.Forsyth 	s1 = getsval(x);
77374a4d8c2SCharles.Forsyth 	y = execute(a[1]);
77474a4d8c2SCharles.Forsyth 	s2 = getsval(y);
77574a4d8c2SCharles.Forsyth 
77674a4d8c2SCharles.Forsyth 	z = gettemp();
77774a4d8c2SCharles.Forsyth 	for (p1 = s1; *p1 != '\0'; p1++) {
77874a4d8c2SCharles.Forsyth 		for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
77974a4d8c2SCharles.Forsyth 			;
78074a4d8c2SCharles.Forsyth 		if (*p2 == '\0') {
78174a4d8c2SCharles.Forsyth 			v = (Awkfloat) (p1 - s1 + 1);	/* origin 1 */
78274a4d8c2SCharles.Forsyth 			break;
78374a4d8c2SCharles.Forsyth 		}
78474a4d8c2SCharles.Forsyth 	}
78574a4d8c2SCharles.Forsyth 	tempfree(x);
78674a4d8c2SCharles.Forsyth 	tempfree(y);
78774a4d8c2SCharles.Forsyth 	setfval(z, v);
78874a4d8c2SCharles.Forsyth 	return(z);
78974a4d8c2SCharles.Forsyth }
79074a4d8c2SCharles.Forsyth 
79174a4d8c2SCharles.Forsyth #define	MAXNUMSIZE	50
79274a4d8c2SCharles.Forsyth 
format(char ** pbuf,int * pbufsize,char * s,Node * a)79374a4d8c2SCharles.Forsyth int format(char **pbuf, int *pbufsize, char *s, Node *a)	/* printf-like conversions */
79474a4d8c2SCharles.Forsyth {
79574a4d8c2SCharles.Forsyth 	char *fmt;
79674a4d8c2SCharles.Forsyth 	char *p, *t, *os;
79774a4d8c2SCharles.Forsyth 	Cell *x;
79874a4d8c2SCharles.Forsyth 	int flag = 0, n;
79974a4d8c2SCharles.Forsyth 	int fmtwd; /* format width */
80074a4d8c2SCharles.Forsyth 	int fmtsz = recsize;
80174a4d8c2SCharles.Forsyth 	char *buf = *pbuf;
80274a4d8c2SCharles.Forsyth 	int bufsize = *pbufsize;
80374a4d8c2SCharles.Forsyth 
80474a4d8c2SCharles.Forsyth 	os = s;
80574a4d8c2SCharles.Forsyth 	p = buf;
80674a4d8c2SCharles.Forsyth 	if ((fmt = (char *) malloc(fmtsz)) == NULL)
80774a4d8c2SCharles.Forsyth 		FATAL("out of memory in format()");
80874a4d8c2SCharles.Forsyth 	while (*s) {
80974a4d8c2SCharles.Forsyth 		adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format");
81074a4d8c2SCharles.Forsyth 		if (*s != '%') {
81174a4d8c2SCharles.Forsyth 			*p++ = *s++;
81274a4d8c2SCharles.Forsyth 			continue;
81374a4d8c2SCharles.Forsyth 		}
81474a4d8c2SCharles.Forsyth 		if (*(s+1) == '%') {
81574a4d8c2SCharles.Forsyth 			*p++ = '%';
81674a4d8c2SCharles.Forsyth 			s += 2;
81774a4d8c2SCharles.Forsyth 			continue;
81874a4d8c2SCharles.Forsyth 		}
81974a4d8c2SCharles.Forsyth 		/* have to be real careful in case this is a huge number, eg, %100000d */
82074a4d8c2SCharles.Forsyth 		fmtwd = atoi(s+1);
82174a4d8c2SCharles.Forsyth 		if (fmtwd < 0)
82274a4d8c2SCharles.Forsyth 			fmtwd = -fmtwd;
82374a4d8c2SCharles.Forsyth 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
82474a4d8c2SCharles.Forsyth 		for (t = fmt; (*t++ = *s) != '\0'; s++) {
82574a4d8c2SCharles.Forsyth 			if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0))
82674a4d8c2SCharles.Forsyth 				FATAL("format item %.30s... ran format() out of memory", os);
82774a4d8c2SCharles.Forsyth 			if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L')
82874a4d8c2SCharles.Forsyth 				break;	/* the ansi panoply */
82974a4d8c2SCharles.Forsyth 			if (*s == '*') {
83074a4d8c2SCharles.Forsyth 				x = execute(a);
83174a4d8c2SCharles.Forsyth 				a = a->nnext;
83274a4d8c2SCharles.Forsyth 				sprintf(t-1, "%d", fmtwd=(int) getfval(x));
83374a4d8c2SCharles.Forsyth 				if (fmtwd < 0)
83474a4d8c2SCharles.Forsyth 					fmtwd = -fmtwd;
83574a4d8c2SCharles.Forsyth 				adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
83674a4d8c2SCharles.Forsyth 				t = fmt + strlen(fmt);
83774a4d8c2SCharles.Forsyth 				tempfree(x);
83874a4d8c2SCharles.Forsyth 			}
83974a4d8c2SCharles.Forsyth 		}
84074a4d8c2SCharles.Forsyth 		*t = '\0';
84174a4d8c2SCharles.Forsyth 		if (fmtwd < 0)
84274a4d8c2SCharles.Forsyth 			fmtwd = -fmtwd;
84374a4d8c2SCharles.Forsyth 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
84474a4d8c2SCharles.Forsyth 
84574a4d8c2SCharles.Forsyth 		switch (*s) {
84674a4d8c2SCharles.Forsyth 		case 'f': case 'e': case 'g': case 'E': case 'G':
84774a4d8c2SCharles.Forsyth 			flag = 1;
84874a4d8c2SCharles.Forsyth 			break;
84974a4d8c2SCharles.Forsyth 		case 'd': case 'i':
85074a4d8c2SCharles.Forsyth 			flag = 2;
85174a4d8c2SCharles.Forsyth 			if(*(s-1) == 'l') break;
85274a4d8c2SCharles.Forsyth 			*(t-1) = 'l';
85374a4d8c2SCharles.Forsyth 			*t = 'd';
85474a4d8c2SCharles.Forsyth 			*++t = '\0';
85574a4d8c2SCharles.Forsyth 			break;
85674a4d8c2SCharles.Forsyth 		case 'o': case 'x': case 'X': case 'u':
85774a4d8c2SCharles.Forsyth 			flag = *(s-1) == 'l' ? 2 : 3;
85874a4d8c2SCharles.Forsyth 			break;
85974a4d8c2SCharles.Forsyth 		case 's':
86074a4d8c2SCharles.Forsyth 			flag = 4;
86174a4d8c2SCharles.Forsyth 			break;
86274a4d8c2SCharles.Forsyth 		case 'c':
86374a4d8c2SCharles.Forsyth 			flag = 5;
86474a4d8c2SCharles.Forsyth 			break;
86574a4d8c2SCharles.Forsyth 		default:
86674a4d8c2SCharles.Forsyth 			WARNING("weird printf conversion %s", fmt);
86774a4d8c2SCharles.Forsyth 			flag = 0;
86874a4d8c2SCharles.Forsyth 			break;
86974a4d8c2SCharles.Forsyth 		}
87074a4d8c2SCharles.Forsyth 		if (a == NULL)
87174a4d8c2SCharles.Forsyth 			FATAL("not enough args in printf(%s)", os);
87274a4d8c2SCharles.Forsyth 		x = execute(a);
87374a4d8c2SCharles.Forsyth 		a = a->nnext;
87474a4d8c2SCharles.Forsyth 		n = MAXNUMSIZE;
87574a4d8c2SCharles.Forsyth 		if (fmtwd > n)
87674a4d8c2SCharles.Forsyth 			n = fmtwd;
87774a4d8c2SCharles.Forsyth 		adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
87874a4d8c2SCharles.Forsyth 		switch (flag) {
87974a4d8c2SCharles.Forsyth 		case 0:	sprintf(p, "%s", fmt);	/* unknown, so dump it too */
88074a4d8c2SCharles.Forsyth 			t = getsval(x);
88174a4d8c2SCharles.Forsyth 			n = strlen(t);
88274a4d8c2SCharles.Forsyth 			if (fmtwd > n)
88374a4d8c2SCharles.Forsyth 				n = fmtwd;
88474a4d8c2SCharles.Forsyth 			adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
88574a4d8c2SCharles.Forsyth 			p += strlen(p);
88674a4d8c2SCharles.Forsyth 			sprintf(p, "%s", t);
88774a4d8c2SCharles.Forsyth 			break;
88874a4d8c2SCharles.Forsyth 		case 1:	sprintf(p, fmt, getfval(x)); break;
88974a4d8c2SCharles.Forsyth 		case 2:	sprintf(p, fmt, (long) getfval(x)); break;
89074a4d8c2SCharles.Forsyth 		case 3:	sprintf(p, fmt, (int) getfval(x)); break;
89174a4d8c2SCharles.Forsyth 		case 4:
89274a4d8c2SCharles.Forsyth 			t = getsval(x);
89374a4d8c2SCharles.Forsyth 			n = strlen(t);
89474a4d8c2SCharles.Forsyth 			if (fmtwd > n)
89574a4d8c2SCharles.Forsyth 				n = fmtwd;
89674a4d8c2SCharles.Forsyth 			if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
89774a4d8c2SCharles.Forsyth 				FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
89874a4d8c2SCharles.Forsyth 			sprintf(p, fmt, t);
89974a4d8c2SCharles.Forsyth 			break;
90074a4d8c2SCharles.Forsyth 		case 5:
90174a4d8c2SCharles.Forsyth 			if (isnum(x)) {
90274a4d8c2SCharles.Forsyth 				if (getfval(x))
90374a4d8c2SCharles.Forsyth 					sprintf(p, fmt, (int) getfval(x));
90474a4d8c2SCharles.Forsyth 				else
90574a4d8c2SCharles.Forsyth 					*p++ = '\0';
90674a4d8c2SCharles.Forsyth 			} else
90774a4d8c2SCharles.Forsyth 				sprintf(p, fmt, getsval(x)[0]);
90874a4d8c2SCharles.Forsyth 			break;
90974a4d8c2SCharles.Forsyth 		}
91074a4d8c2SCharles.Forsyth 		tempfree(x);
91174a4d8c2SCharles.Forsyth 		p += strlen(p);
91274a4d8c2SCharles.Forsyth 		s++;
91374a4d8c2SCharles.Forsyth 	}
91474a4d8c2SCharles.Forsyth 	*p = '\0';
91574a4d8c2SCharles.Forsyth 	free(fmt);
91674a4d8c2SCharles.Forsyth 	for ( ; a; a = a->nnext)		/* evaluate any remaining args */
91774a4d8c2SCharles.Forsyth 		execute(a);
91874a4d8c2SCharles.Forsyth 	*pbuf = buf;
91974a4d8c2SCharles.Forsyth 	*pbufsize = bufsize;
92074a4d8c2SCharles.Forsyth 	return p - buf;
92174a4d8c2SCharles.Forsyth }
92274a4d8c2SCharles.Forsyth 
awksprintf(Node ** a,int n)92374a4d8c2SCharles.Forsyth Cell *awksprintf(Node **a, int n)		/* sprintf(a[0]) */
92474a4d8c2SCharles.Forsyth {
92574a4d8c2SCharles.Forsyth 	Cell *x;
92674a4d8c2SCharles.Forsyth 	Node *y;
92774a4d8c2SCharles.Forsyth 	char *buf;
92874a4d8c2SCharles.Forsyth 	int bufsz=3*recsize;
92974a4d8c2SCharles.Forsyth 
93074a4d8c2SCharles.Forsyth 	if ((buf = (char *) malloc(bufsz)) == NULL)
93174a4d8c2SCharles.Forsyth 		FATAL("out of memory in awksprintf");
93274a4d8c2SCharles.Forsyth 	y = a[0]->nnext;
93374a4d8c2SCharles.Forsyth 	x = execute(a[0]);
93474a4d8c2SCharles.Forsyth 	if (format(&buf, &bufsz, getsval(x), y) == -1)
93574a4d8c2SCharles.Forsyth 		FATAL("sprintf string %.30s... too long.  can't happen.", buf);
93674a4d8c2SCharles.Forsyth 	tempfree(x);
93774a4d8c2SCharles.Forsyth 	x = gettemp();
93874a4d8c2SCharles.Forsyth 	x->sval = buf;
93974a4d8c2SCharles.Forsyth 	x->tval = STR;
94074a4d8c2SCharles.Forsyth 	return(x);
94174a4d8c2SCharles.Forsyth }
94274a4d8c2SCharles.Forsyth 
awkprintf(Node ** a,int n)94374a4d8c2SCharles.Forsyth Cell *awkprintf(Node **a, int n)		/* printf */
94474a4d8c2SCharles.Forsyth {	/* a[0] is list of args, starting with format string */
94574a4d8c2SCharles.Forsyth 	/* a[1] is redirection operator, a[2] is redirection file */
94674a4d8c2SCharles.Forsyth 	FILE *fp;
94774a4d8c2SCharles.Forsyth 	Cell *x;
94874a4d8c2SCharles.Forsyth 	Node *y;
94974a4d8c2SCharles.Forsyth 	char *buf;
95074a4d8c2SCharles.Forsyth 	int len;
95174a4d8c2SCharles.Forsyth 	int bufsz=3*recsize;
95274a4d8c2SCharles.Forsyth 
95374a4d8c2SCharles.Forsyth 	if ((buf = (char *) malloc(bufsz)) == NULL)
95474a4d8c2SCharles.Forsyth 		FATAL("out of memory in awkprintf");
95574a4d8c2SCharles.Forsyth 	y = a[0]->nnext;
95674a4d8c2SCharles.Forsyth 	x = execute(a[0]);
95774a4d8c2SCharles.Forsyth 	if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
95874a4d8c2SCharles.Forsyth 		FATAL("printf string %.30s... too long.  can't happen.", buf);
95974a4d8c2SCharles.Forsyth 	tempfree(x);
96074a4d8c2SCharles.Forsyth 	if (a[1] == NULL) {
96174a4d8c2SCharles.Forsyth 		/* fputs(buf, stdout); */
96274a4d8c2SCharles.Forsyth 		fwrite(buf, len, 1, stdout);
96374a4d8c2SCharles.Forsyth 		if (ferror(stdout))
96474a4d8c2SCharles.Forsyth 			FATAL("write error on stdout");
96574a4d8c2SCharles.Forsyth 	} else {
96674a4d8c2SCharles.Forsyth 		fp = redirect(ptoi(a[1]), a[2]);
96774a4d8c2SCharles.Forsyth 		/* fputs(buf, fp); */
96874a4d8c2SCharles.Forsyth 		fwrite(buf, len, 1, fp);
96974a4d8c2SCharles.Forsyth 		fflush(fp);
97074a4d8c2SCharles.Forsyth 		if (ferror(fp))
97174a4d8c2SCharles.Forsyth 			FATAL("write error on %s", filename(fp));
97274a4d8c2SCharles.Forsyth 	}
97374a4d8c2SCharles.Forsyth 	free(buf);
97474a4d8c2SCharles.Forsyth 	return(True);
97574a4d8c2SCharles.Forsyth }
97674a4d8c2SCharles.Forsyth 
arith(Node ** a,int n)97774a4d8c2SCharles.Forsyth Cell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
97874a4d8c2SCharles.Forsyth {
97974a4d8c2SCharles.Forsyth 	Awkfloat i, j = 0;
98074a4d8c2SCharles.Forsyth 	double v;
98174a4d8c2SCharles.Forsyth 	Cell *x, *y, *z;
98274a4d8c2SCharles.Forsyth 
98374a4d8c2SCharles.Forsyth 	x = execute(a[0]);
98474a4d8c2SCharles.Forsyth 	i = getfval(x);
98574a4d8c2SCharles.Forsyth 	tempfree(x);
98674a4d8c2SCharles.Forsyth 	if (n != UMINUS) {
98774a4d8c2SCharles.Forsyth 		y = execute(a[1]);
98874a4d8c2SCharles.Forsyth 		j = getfval(y);
98974a4d8c2SCharles.Forsyth 		tempfree(y);
99074a4d8c2SCharles.Forsyth 	}
99174a4d8c2SCharles.Forsyth 	z = gettemp();
99274a4d8c2SCharles.Forsyth 	switch (n) {
99374a4d8c2SCharles.Forsyth 	case ADD:
99474a4d8c2SCharles.Forsyth 		i += j;
99574a4d8c2SCharles.Forsyth 		break;
99674a4d8c2SCharles.Forsyth 	case MINUS:
99774a4d8c2SCharles.Forsyth 		i -= j;
99874a4d8c2SCharles.Forsyth 		break;
99974a4d8c2SCharles.Forsyth 	case MULT:
100074a4d8c2SCharles.Forsyth 		i *= j;
100174a4d8c2SCharles.Forsyth 		break;
100274a4d8c2SCharles.Forsyth 	case DIVIDE:
100374a4d8c2SCharles.Forsyth 		if (j == 0)
100474a4d8c2SCharles.Forsyth 			FATAL("division by zero");
100574a4d8c2SCharles.Forsyth 		i /= j;
100674a4d8c2SCharles.Forsyth 		break;
100774a4d8c2SCharles.Forsyth 	case MOD:
100874a4d8c2SCharles.Forsyth 		if (j == 0)
100974a4d8c2SCharles.Forsyth 			FATAL("division by zero in mod");
101074a4d8c2SCharles.Forsyth 		modf(i/j, &v);
101174a4d8c2SCharles.Forsyth 		i = i - j * v;
101274a4d8c2SCharles.Forsyth 		break;
101374a4d8c2SCharles.Forsyth 	case UMINUS:
101474a4d8c2SCharles.Forsyth 		i = -i;
101574a4d8c2SCharles.Forsyth 		break;
101674a4d8c2SCharles.Forsyth 	case POWER:
101774a4d8c2SCharles.Forsyth 		if (j >= 0 && modf(j, &v) == 0.0)	/* pos integer exponent */
101874a4d8c2SCharles.Forsyth 			i = ipow(i, (int) j);
101974a4d8c2SCharles.Forsyth 		else
102074a4d8c2SCharles.Forsyth 			i = errcheck(pow(i, j), "pow");
102174a4d8c2SCharles.Forsyth 		break;
102274a4d8c2SCharles.Forsyth 	default:	/* can't happen */
102374a4d8c2SCharles.Forsyth 		FATAL("illegal arithmetic operator %d", n);
102474a4d8c2SCharles.Forsyth 	}
102574a4d8c2SCharles.Forsyth 	setfval(z, i);
102674a4d8c2SCharles.Forsyth 	return(z);
102774a4d8c2SCharles.Forsyth }
102874a4d8c2SCharles.Forsyth 
ipow(double x,int n)102974a4d8c2SCharles.Forsyth double ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
103074a4d8c2SCharles.Forsyth {
103174a4d8c2SCharles.Forsyth 	double v;
103274a4d8c2SCharles.Forsyth 
103374a4d8c2SCharles.Forsyth 	if (n <= 0)
103474a4d8c2SCharles.Forsyth 		return 1;
103574a4d8c2SCharles.Forsyth 	v = ipow(x, n/2);
103674a4d8c2SCharles.Forsyth 	if (n % 2 == 0)
103774a4d8c2SCharles.Forsyth 		return v * v;
103874a4d8c2SCharles.Forsyth 	else
103974a4d8c2SCharles.Forsyth 		return x * v * v;
104074a4d8c2SCharles.Forsyth }
104174a4d8c2SCharles.Forsyth 
incrdecr(Node ** a,int n)104274a4d8c2SCharles.Forsyth Cell *incrdecr(Node **a, int n)		/* a[0]++, etc. */
104374a4d8c2SCharles.Forsyth {
104474a4d8c2SCharles.Forsyth 	Cell *x, *z;
104574a4d8c2SCharles.Forsyth 	int k;
104674a4d8c2SCharles.Forsyth 	Awkfloat xf;
104774a4d8c2SCharles.Forsyth 
104874a4d8c2SCharles.Forsyth 	x = execute(a[0]);
104974a4d8c2SCharles.Forsyth 	xf = getfval(x);
105074a4d8c2SCharles.Forsyth 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
105174a4d8c2SCharles.Forsyth 	if (n == PREINCR || n == PREDECR) {
105274a4d8c2SCharles.Forsyth 		setfval(x, xf + k);
105374a4d8c2SCharles.Forsyth 		return(x);
105474a4d8c2SCharles.Forsyth 	}
105574a4d8c2SCharles.Forsyth 	z = gettemp();
105674a4d8c2SCharles.Forsyth 	setfval(z, xf);
105774a4d8c2SCharles.Forsyth 	setfval(x, xf + k);
105874a4d8c2SCharles.Forsyth 	tempfree(x);
105974a4d8c2SCharles.Forsyth 	return(z);
106074a4d8c2SCharles.Forsyth }
106174a4d8c2SCharles.Forsyth 
assign(Node ** a,int n)106274a4d8c2SCharles.Forsyth Cell *assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
106374a4d8c2SCharles.Forsyth {		/* this is subtle; don't muck with it. */
106474a4d8c2SCharles.Forsyth 	Cell *x, *y;
106574a4d8c2SCharles.Forsyth 	Awkfloat xf, yf;
106674a4d8c2SCharles.Forsyth 	double v;
106774a4d8c2SCharles.Forsyth 
106874a4d8c2SCharles.Forsyth 	y = execute(a[1]);
106974a4d8c2SCharles.Forsyth 	x = execute(a[0]);
107074a4d8c2SCharles.Forsyth 	if (n == ASSIGN) {	/* ordinary assignment */
107174a4d8c2SCharles.Forsyth 		if (x == y && !(x->tval & (FLD|REC)))	/* self-assignment: */
107274a4d8c2SCharles.Forsyth 			;		/* leave alone unless it's a field */
107374a4d8c2SCharles.Forsyth 		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
107474a4d8c2SCharles.Forsyth 			setsval(x, getsval(y));
107574a4d8c2SCharles.Forsyth 			x->fval = getfval(y);
107674a4d8c2SCharles.Forsyth 			x->tval |= NUM;
107774a4d8c2SCharles.Forsyth 		}
107874a4d8c2SCharles.Forsyth 		else if (isstr(y))
107974a4d8c2SCharles.Forsyth 			setsval(x, getsval(y));
108074a4d8c2SCharles.Forsyth 		else if (isnum(y))
108174a4d8c2SCharles.Forsyth 			setfval(x, getfval(y));
108274a4d8c2SCharles.Forsyth 		else
108374a4d8c2SCharles.Forsyth 			funnyvar(y, "read value of");
108474a4d8c2SCharles.Forsyth 		tempfree(y);
108574a4d8c2SCharles.Forsyth 		return(x);
108674a4d8c2SCharles.Forsyth 	}
108774a4d8c2SCharles.Forsyth 	xf = getfval(x);
108874a4d8c2SCharles.Forsyth 	yf = getfval(y);
108974a4d8c2SCharles.Forsyth 	switch (n) {
109074a4d8c2SCharles.Forsyth 	case ADDEQ:
109174a4d8c2SCharles.Forsyth 		xf += yf;
109274a4d8c2SCharles.Forsyth 		break;
109374a4d8c2SCharles.Forsyth 	case SUBEQ:
109474a4d8c2SCharles.Forsyth 		xf -= yf;
109574a4d8c2SCharles.Forsyth 		break;
109674a4d8c2SCharles.Forsyth 	case MULTEQ:
109774a4d8c2SCharles.Forsyth 		xf *= yf;
109874a4d8c2SCharles.Forsyth 		break;
109974a4d8c2SCharles.Forsyth 	case DIVEQ:
110074a4d8c2SCharles.Forsyth 		if (yf == 0)
110174a4d8c2SCharles.Forsyth 			FATAL("division by zero in /=");
110274a4d8c2SCharles.Forsyth 		xf /= yf;
110374a4d8c2SCharles.Forsyth 		break;
110474a4d8c2SCharles.Forsyth 	case MODEQ:
110574a4d8c2SCharles.Forsyth 		if (yf == 0)
110674a4d8c2SCharles.Forsyth 			FATAL("division by zero in %%=");
110774a4d8c2SCharles.Forsyth 		modf(xf/yf, &v);
110874a4d8c2SCharles.Forsyth 		xf = xf - yf * v;
110974a4d8c2SCharles.Forsyth 		break;
111074a4d8c2SCharles.Forsyth 	case POWEQ:
111174a4d8c2SCharles.Forsyth 		if (yf >= 0 && modf(yf, &v) == 0.0)	/* pos integer exponent */
111274a4d8c2SCharles.Forsyth 			xf = ipow(xf, (int) yf);
111374a4d8c2SCharles.Forsyth 		else
111474a4d8c2SCharles.Forsyth 			xf = errcheck(pow(xf, yf), "pow");
111574a4d8c2SCharles.Forsyth 		break;
111674a4d8c2SCharles.Forsyth 	default:
111774a4d8c2SCharles.Forsyth 		FATAL("illegal assignment operator %d", n);
111874a4d8c2SCharles.Forsyth 		break;
111974a4d8c2SCharles.Forsyth 	}
112074a4d8c2SCharles.Forsyth 	tempfree(y);
112174a4d8c2SCharles.Forsyth 	setfval(x, xf);
112274a4d8c2SCharles.Forsyth 	return(x);
112374a4d8c2SCharles.Forsyth }
112474a4d8c2SCharles.Forsyth 
cat(Node ** a,int q)112574a4d8c2SCharles.Forsyth Cell *cat(Node **a, int q)	/* a[0] cat a[1] */
112674a4d8c2SCharles.Forsyth {
112774a4d8c2SCharles.Forsyth 	Cell *x, *y, *z;
112874a4d8c2SCharles.Forsyth 	int n1, n2;
112974a4d8c2SCharles.Forsyth 	char *s;
113074a4d8c2SCharles.Forsyth 
113174a4d8c2SCharles.Forsyth 	x = execute(a[0]);
113274a4d8c2SCharles.Forsyth 	y = execute(a[1]);
113374a4d8c2SCharles.Forsyth 	getsval(x);
113474a4d8c2SCharles.Forsyth 	getsval(y);
113574a4d8c2SCharles.Forsyth 	n1 = strlen(x->sval);
113674a4d8c2SCharles.Forsyth 	n2 = strlen(y->sval);
113774a4d8c2SCharles.Forsyth 	s = (char *) malloc(n1 + n2 + 1);
113874a4d8c2SCharles.Forsyth 	if (s == NULL)
113974a4d8c2SCharles.Forsyth 		FATAL("out of space concatenating %.15s... and %.15s...",
114074a4d8c2SCharles.Forsyth 			x->sval, y->sval);
114174a4d8c2SCharles.Forsyth 	strcpy(s, x->sval);
114274a4d8c2SCharles.Forsyth 	strcpy(s+n1, y->sval);
114374a4d8c2SCharles.Forsyth 	tempfree(y);
114474a4d8c2SCharles.Forsyth 	z = gettemp();
114574a4d8c2SCharles.Forsyth 	z->sval = s;
114674a4d8c2SCharles.Forsyth 	z->tval = STR;
114774a4d8c2SCharles.Forsyth 	tempfree(x);
114874a4d8c2SCharles.Forsyth 	return(z);
114974a4d8c2SCharles.Forsyth }
115074a4d8c2SCharles.Forsyth 
pastat(Node ** a,int n)115174a4d8c2SCharles.Forsyth Cell *pastat(Node **a, int n)	/* a[0] { a[1] } */
115274a4d8c2SCharles.Forsyth {
115374a4d8c2SCharles.Forsyth 	Cell *x;
115474a4d8c2SCharles.Forsyth 
115574a4d8c2SCharles.Forsyth 	if (a[0] == 0)
115674a4d8c2SCharles.Forsyth 		x = execute(a[1]);
115774a4d8c2SCharles.Forsyth 	else {
115874a4d8c2SCharles.Forsyth 		x = execute(a[0]);
115974a4d8c2SCharles.Forsyth 		if (istrue(x)) {
116074a4d8c2SCharles.Forsyth 			tempfree(x);
116174a4d8c2SCharles.Forsyth 			x = execute(a[1]);
116274a4d8c2SCharles.Forsyth 		}
116374a4d8c2SCharles.Forsyth 	}
116474a4d8c2SCharles.Forsyth 	return x;
116574a4d8c2SCharles.Forsyth }
116674a4d8c2SCharles.Forsyth 
dopa2(Node ** a,int n)116774a4d8c2SCharles.Forsyth Cell *dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
116874a4d8c2SCharles.Forsyth {
116974a4d8c2SCharles.Forsyth 	Cell *x;
117074a4d8c2SCharles.Forsyth 	int pair;
117174a4d8c2SCharles.Forsyth 
117274a4d8c2SCharles.Forsyth 	pair = ptoi(a[3]);
117374a4d8c2SCharles.Forsyth 	if (pairstack[pair] == 0) {
117474a4d8c2SCharles.Forsyth 		x = execute(a[0]);
117574a4d8c2SCharles.Forsyth 		if (istrue(x))
117674a4d8c2SCharles.Forsyth 			pairstack[pair] = 1;
117774a4d8c2SCharles.Forsyth 		tempfree(x);
117874a4d8c2SCharles.Forsyth 	}
117974a4d8c2SCharles.Forsyth 	if (pairstack[pair] == 1) {
118074a4d8c2SCharles.Forsyth 		x = execute(a[1]);
118174a4d8c2SCharles.Forsyth 		if (istrue(x))
118274a4d8c2SCharles.Forsyth 			pairstack[pair] = 0;
118374a4d8c2SCharles.Forsyth 		tempfree(x);
118474a4d8c2SCharles.Forsyth 		x = execute(a[2]);
118574a4d8c2SCharles.Forsyth 		return(x);
118674a4d8c2SCharles.Forsyth 	}
118774a4d8c2SCharles.Forsyth 	return(False);
118874a4d8c2SCharles.Forsyth }
118974a4d8c2SCharles.Forsyth 
split(Node ** a,int nnn)119074a4d8c2SCharles.Forsyth Cell *split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
119174a4d8c2SCharles.Forsyth {
119274a4d8c2SCharles.Forsyth 	Cell *x = 0, *y, *ap;
119374a4d8c2SCharles.Forsyth 	char *s;
119474a4d8c2SCharles.Forsyth 	int sep;
119574a4d8c2SCharles.Forsyth 	char *t, temp, num[50], *fs = 0;
119674a4d8c2SCharles.Forsyth 	int n, tempstat, arg3type;
119774a4d8c2SCharles.Forsyth 
119874a4d8c2SCharles.Forsyth 	y = execute(a[0]);	/* source string */
119974a4d8c2SCharles.Forsyth 	s = getsval(y);
120074a4d8c2SCharles.Forsyth 	arg3type = ptoi(a[3]);
120174a4d8c2SCharles.Forsyth 	if (a[2] == 0)		/* fs string */
120274a4d8c2SCharles.Forsyth 		fs = *FS;
120374a4d8c2SCharles.Forsyth 	else if (arg3type == STRING) {	/* split(str,arr,"string") */
120474a4d8c2SCharles.Forsyth 		x = execute(a[2]);
120574a4d8c2SCharles.Forsyth 		fs = getsval(x);
120674a4d8c2SCharles.Forsyth 	} else if (arg3type == REGEXPR)
120774a4d8c2SCharles.Forsyth 		fs = "(regexpr)";	/* split(str,arr,/regexpr/) */
120874a4d8c2SCharles.Forsyth 	else
120974a4d8c2SCharles.Forsyth 		FATAL("illegal type of split");
121074a4d8c2SCharles.Forsyth 	sep = *fs;
121174a4d8c2SCharles.Forsyth 	ap = execute(a[1]);	/* array name */
121235d297e4Sforsyth 	n = y->tval;
121335d297e4Sforsyth 	y->tval |= DONTFREE;	/* split(a[x], a); */
121474a4d8c2SCharles.Forsyth 	freesymtab(ap);
121535d297e4Sforsyth 	y->tval = n;
121674a4d8c2SCharles.Forsyth 	   dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
121774a4d8c2SCharles.Forsyth 	ap->tval &= ~STR;
121874a4d8c2SCharles.Forsyth 	ap->tval |= ARR;
121974a4d8c2SCharles.Forsyth 	ap->sval = (char *) makesymtab(NSYMTAB);
122074a4d8c2SCharles.Forsyth 
122174a4d8c2SCharles.Forsyth 	n = 0;
122274a4d8c2SCharles.Forsyth 	if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) {	/* reg expr */
122374a4d8c2SCharles.Forsyth 		fa *pfa;
122474a4d8c2SCharles.Forsyth 		if (arg3type == REGEXPR) {	/* it's ready already */
122574a4d8c2SCharles.Forsyth 			pfa = (fa *) a[2];
122674a4d8c2SCharles.Forsyth 		} else {
122774a4d8c2SCharles.Forsyth 			pfa = makedfa(fs, 1);
122874a4d8c2SCharles.Forsyth 		}
122974a4d8c2SCharles.Forsyth 		if (nematch(pfa,s)) {
123074a4d8c2SCharles.Forsyth 			tempstat = pfa->initstat;
123174a4d8c2SCharles.Forsyth 			pfa->initstat = 2;
123274a4d8c2SCharles.Forsyth 			do {
123374a4d8c2SCharles.Forsyth 				n++;
123474a4d8c2SCharles.Forsyth 				sprintf(num, "%d", n);
123574a4d8c2SCharles.Forsyth 				temp = *patbeg;
123674a4d8c2SCharles.Forsyth 				*patbeg = '\0';
123774a4d8c2SCharles.Forsyth 				if (is_number(s))
123874a4d8c2SCharles.Forsyth 					setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
123974a4d8c2SCharles.Forsyth 				else
124074a4d8c2SCharles.Forsyth 					setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
124174a4d8c2SCharles.Forsyth 				*patbeg = temp;
124274a4d8c2SCharles.Forsyth 				s = patbeg + patlen;
124374a4d8c2SCharles.Forsyth 				if (*(patbeg+patlen-1) == 0 || *s == 0) {
124474a4d8c2SCharles.Forsyth 					n++;
124574a4d8c2SCharles.Forsyth 					sprintf(num, "%d", n);
124674a4d8c2SCharles.Forsyth 					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
124774a4d8c2SCharles.Forsyth 					pfa->initstat = tempstat;
124874a4d8c2SCharles.Forsyth 					goto spdone;
124974a4d8c2SCharles.Forsyth 				}
125074a4d8c2SCharles.Forsyth 			} while (nematch(pfa,s));
125174a4d8c2SCharles.Forsyth 		}
125274a4d8c2SCharles.Forsyth 		n++;
125374a4d8c2SCharles.Forsyth 		sprintf(num, "%d", n);
125474a4d8c2SCharles.Forsyth 		if (is_number(s))
125574a4d8c2SCharles.Forsyth 			setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
125674a4d8c2SCharles.Forsyth 		else
125774a4d8c2SCharles.Forsyth 			setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
125874a4d8c2SCharles.Forsyth   spdone:
125974a4d8c2SCharles.Forsyth 		pfa = NULL;
126074a4d8c2SCharles.Forsyth 	} else if (sep == ' ') {
126174a4d8c2SCharles.Forsyth 		for (n = 0; ; ) {
126274a4d8c2SCharles.Forsyth 			while (*s == ' ' || *s == '\t' || *s == '\n')
126374a4d8c2SCharles.Forsyth 				s++;
126474a4d8c2SCharles.Forsyth 			if (*s == 0)
126574a4d8c2SCharles.Forsyth 				break;
126674a4d8c2SCharles.Forsyth 			n++;
126774a4d8c2SCharles.Forsyth 			t = s;
126874a4d8c2SCharles.Forsyth 			do
126974a4d8c2SCharles.Forsyth 				s++;
127074a4d8c2SCharles.Forsyth 			while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
127174a4d8c2SCharles.Forsyth 			temp = *s;
127274a4d8c2SCharles.Forsyth 			*s = '\0';
127374a4d8c2SCharles.Forsyth 			sprintf(num, "%d", n);
127474a4d8c2SCharles.Forsyth 			if (is_number(t))
127574a4d8c2SCharles.Forsyth 				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
127674a4d8c2SCharles.Forsyth 			else
127774a4d8c2SCharles.Forsyth 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
127874a4d8c2SCharles.Forsyth 			*s = temp;
127974a4d8c2SCharles.Forsyth 			if (*s != 0)
128074a4d8c2SCharles.Forsyth 				s++;
128174a4d8c2SCharles.Forsyth 		}
128274a4d8c2SCharles.Forsyth 	} else if (sep == 0) {	/* new: split(s, a, "") => 1 char/elem */
128374a4d8c2SCharles.Forsyth 		for (n = 0; *s != 0; s++) {
128474a4d8c2SCharles.Forsyth 			char buf[2];
128574a4d8c2SCharles.Forsyth 			n++;
128674a4d8c2SCharles.Forsyth 			sprintf(num, "%d", n);
128774a4d8c2SCharles.Forsyth 			buf[0] = *s;
128874a4d8c2SCharles.Forsyth 			buf[1] = 0;
128974a4d8c2SCharles.Forsyth 			if (isdigit((uschar)buf[0]))
129074a4d8c2SCharles.Forsyth 				setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
129174a4d8c2SCharles.Forsyth 			else
129274a4d8c2SCharles.Forsyth 				setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
129374a4d8c2SCharles.Forsyth 		}
129474a4d8c2SCharles.Forsyth 	} else if (*s != 0) {
129574a4d8c2SCharles.Forsyth 		for (;;) {
129674a4d8c2SCharles.Forsyth 			n++;
129774a4d8c2SCharles.Forsyth 			t = s;
129874a4d8c2SCharles.Forsyth 			while (*s != sep && *s != '\n' && *s != '\0')
129974a4d8c2SCharles.Forsyth 				s++;
130074a4d8c2SCharles.Forsyth 			temp = *s;
130174a4d8c2SCharles.Forsyth 			*s = '\0';
130274a4d8c2SCharles.Forsyth 			sprintf(num, "%d", n);
130374a4d8c2SCharles.Forsyth 			if (is_number(t))
130474a4d8c2SCharles.Forsyth 				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
130574a4d8c2SCharles.Forsyth 			else
130674a4d8c2SCharles.Forsyth 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
130774a4d8c2SCharles.Forsyth 			*s = temp;
130874a4d8c2SCharles.Forsyth 			if (*s++ == 0)
130974a4d8c2SCharles.Forsyth 				break;
131074a4d8c2SCharles.Forsyth 		}
131174a4d8c2SCharles.Forsyth 	}
131274a4d8c2SCharles.Forsyth 	tempfree(ap);
131374a4d8c2SCharles.Forsyth 	tempfree(y);
131474a4d8c2SCharles.Forsyth 	if (a[2] != 0 && arg3type == STRING) {
131574a4d8c2SCharles.Forsyth 		tempfree(x);
131674a4d8c2SCharles.Forsyth 	}
131774a4d8c2SCharles.Forsyth 	x = gettemp();
131874a4d8c2SCharles.Forsyth 	x->tval = NUM;
131974a4d8c2SCharles.Forsyth 	x->fval = n;
132074a4d8c2SCharles.Forsyth 	return(x);
132174a4d8c2SCharles.Forsyth }
132274a4d8c2SCharles.Forsyth 
condexpr(Node ** a,int n)132374a4d8c2SCharles.Forsyth Cell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
132474a4d8c2SCharles.Forsyth {
132574a4d8c2SCharles.Forsyth 	Cell *x;
132674a4d8c2SCharles.Forsyth 
132774a4d8c2SCharles.Forsyth 	x = execute(a[0]);
132874a4d8c2SCharles.Forsyth 	if (istrue(x)) {
132974a4d8c2SCharles.Forsyth 		tempfree(x);
133074a4d8c2SCharles.Forsyth 		x = execute(a[1]);
133174a4d8c2SCharles.Forsyth 	} else {
133274a4d8c2SCharles.Forsyth 		tempfree(x);
133374a4d8c2SCharles.Forsyth 		x = execute(a[2]);
133474a4d8c2SCharles.Forsyth 	}
133574a4d8c2SCharles.Forsyth 	return(x);
133674a4d8c2SCharles.Forsyth }
133774a4d8c2SCharles.Forsyth 
ifstat(Node ** a,int n)133874a4d8c2SCharles.Forsyth Cell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
133974a4d8c2SCharles.Forsyth {
134074a4d8c2SCharles.Forsyth 	Cell *x;
134174a4d8c2SCharles.Forsyth 
134274a4d8c2SCharles.Forsyth 	x = execute(a[0]);
134374a4d8c2SCharles.Forsyth 	if (istrue(x)) {
134474a4d8c2SCharles.Forsyth 		tempfree(x);
134574a4d8c2SCharles.Forsyth 		x = execute(a[1]);
134674a4d8c2SCharles.Forsyth 	} else if (a[2] != 0) {
134774a4d8c2SCharles.Forsyth 		tempfree(x);
134874a4d8c2SCharles.Forsyth 		x = execute(a[2]);
134974a4d8c2SCharles.Forsyth 	}
135074a4d8c2SCharles.Forsyth 	return(x);
135174a4d8c2SCharles.Forsyth }
135274a4d8c2SCharles.Forsyth 
whilestat(Node ** a,int n)135374a4d8c2SCharles.Forsyth Cell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
135474a4d8c2SCharles.Forsyth {
135574a4d8c2SCharles.Forsyth 	Cell *x;
135674a4d8c2SCharles.Forsyth 
135774a4d8c2SCharles.Forsyth 	for (;;) {
135874a4d8c2SCharles.Forsyth 		x = execute(a[0]);
135974a4d8c2SCharles.Forsyth 		if (!istrue(x))
136074a4d8c2SCharles.Forsyth 			return(x);
136174a4d8c2SCharles.Forsyth 		tempfree(x);
136274a4d8c2SCharles.Forsyth 		x = execute(a[1]);
136374a4d8c2SCharles.Forsyth 		if (isbreak(x)) {
136474a4d8c2SCharles.Forsyth 			x = True;
136574a4d8c2SCharles.Forsyth 			return(x);
136674a4d8c2SCharles.Forsyth 		}
136774a4d8c2SCharles.Forsyth 		if (isnext(x) || isexit(x) || isret(x))
136874a4d8c2SCharles.Forsyth 			return(x);
136974a4d8c2SCharles.Forsyth 		tempfree(x);
137074a4d8c2SCharles.Forsyth 	}
137174a4d8c2SCharles.Forsyth }
137274a4d8c2SCharles.Forsyth 
dostat(Node ** a,int n)137374a4d8c2SCharles.Forsyth Cell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
137474a4d8c2SCharles.Forsyth {
137574a4d8c2SCharles.Forsyth 	Cell *x;
137674a4d8c2SCharles.Forsyth 
137774a4d8c2SCharles.Forsyth 	for (;;) {
137874a4d8c2SCharles.Forsyth 		x = execute(a[0]);
137974a4d8c2SCharles.Forsyth 		if (isbreak(x))
138074a4d8c2SCharles.Forsyth 			return True;
138174a4d8c2SCharles.Forsyth 		if (isnext(x) || isexit(x) || isret(x))
138274a4d8c2SCharles.Forsyth 			return(x);
138374a4d8c2SCharles.Forsyth 		tempfree(x);
138474a4d8c2SCharles.Forsyth 		x = execute(a[1]);
138574a4d8c2SCharles.Forsyth 		if (!istrue(x))
138674a4d8c2SCharles.Forsyth 			return(x);
138774a4d8c2SCharles.Forsyth 		tempfree(x);
138874a4d8c2SCharles.Forsyth 	}
138974a4d8c2SCharles.Forsyth }
139074a4d8c2SCharles.Forsyth 
forstat(Node ** a,int n)139174a4d8c2SCharles.Forsyth Cell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
139274a4d8c2SCharles.Forsyth {
139374a4d8c2SCharles.Forsyth 	Cell *x;
139474a4d8c2SCharles.Forsyth 
139574a4d8c2SCharles.Forsyth 	x = execute(a[0]);
139674a4d8c2SCharles.Forsyth 	tempfree(x);
139774a4d8c2SCharles.Forsyth 	for (;;) {
139874a4d8c2SCharles.Forsyth 		if (a[1]!=0) {
139974a4d8c2SCharles.Forsyth 			x = execute(a[1]);
140074a4d8c2SCharles.Forsyth 			if (!istrue(x)) return(x);
140174a4d8c2SCharles.Forsyth 			else tempfree(x);
140274a4d8c2SCharles.Forsyth 		}
140374a4d8c2SCharles.Forsyth 		x = execute(a[3]);
140474a4d8c2SCharles.Forsyth 		if (isbreak(x))		/* turn off break */
140574a4d8c2SCharles.Forsyth 			return True;
140674a4d8c2SCharles.Forsyth 		if (isnext(x) || isexit(x) || isret(x))
140774a4d8c2SCharles.Forsyth 			return(x);
140874a4d8c2SCharles.Forsyth 		tempfree(x);
140974a4d8c2SCharles.Forsyth 		x = execute(a[2]);
141074a4d8c2SCharles.Forsyth 		tempfree(x);
141174a4d8c2SCharles.Forsyth 	}
141274a4d8c2SCharles.Forsyth }
141374a4d8c2SCharles.Forsyth 
instat(Node ** a,int n)141474a4d8c2SCharles.Forsyth Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
141574a4d8c2SCharles.Forsyth {
141674a4d8c2SCharles.Forsyth 	Cell *x, *vp, *arrayp, *cp, *ncp;
141774a4d8c2SCharles.Forsyth 	Array *tp;
141874a4d8c2SCharles.Forsyth 	int i;
141974a4d8c2SCharles.Forsyth 
142074a4d8c2SCharles.Forsyth 	vp = execute(a[0]);
142174a4d8c2SCharles.Forsyth 	arrayp = execute(a[1]);
142274a4d8c2SCharles.Forsyth 	if (!isarr(arrayp)) {
142374a4d8c2SCharles.Forsyth 		return True;
142474a4d8c2SCharles.Forsyth 	}
142574a4d8c2SCharles.Forsyth 	tp = (Array *) arrayp->sval;
142674a4d8c2SCharles.Forsyth 	tempfree(arrayp);
142774a4d8c2SCharles.Forsyth 	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
142874a4d8c2SCharles.Forsyth 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
142974a4d8c2SCharles.Forsyth 			setsval(vp, cp->nval);
143074a4d8c2SCharles.Forsyth 			ncp = cp->cnext;
143174a4d8c2SCharles.Forsyth 			x = execute(a[2]);
143274a4d8c2SCharles.Forsyth 			if (isbreak(x)) {
143374a4d8c2SCharles.Forsyth 				tempfree(vp);
143474a4d8c2SCharles.Forsyth 				return True;
143574a4d8c2SCharles.Forsyth 			}
143674a4d8c2SCharles.Forsyth 			if (isnext(x) || isexit(x) || isret(x)) {
143774a4d8c2SCharles.Forsyth 				tempfree(vp);
143874a4d8c2SCharles.Forsyth 				return(x);
143974a4d8c2SCharles.Forsyth 			}
144074a4d8c2SCharles.Forsyth 			tempfree(x);
144174a4d8c2SCharles.Forsyth 		}
144274a4d8c2SCharles.Forsyth 	}
144374a4d8c2SCharles.Forsyth 	return True;
144474a4d8c2SCharles.Forsyth }
144574a4d8c2SCharles.Forsyth 
bltin(Node ** a,int n)144674a4d8c2SCharles.Forsyth Cell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
144774a4d8c2SCharles.Forsyth {
144874a4d8c2SCharles.Forsyth 	Cell *x, *y;
144974a4d8c2SCharles.Forsyth 	Awkfloat u;
145074a4d8c2SCharles.Forsyth 	int t;
145174a4d8c2SCharles.Forsyth 	char *p, *buf;
145274a4d8c2SCharles.Forsyth 	Node *nextarg;
145374a4d8c2SCharles.Forsyth 	FILE *fp;
145474a4d8c2SCharles.Forsyth 
145574a4d8c2SCharles.Forsyth 	t = ptoi(a[0]);
145674a4d8c2SCharles.Forsyth 	x = execute(a[1]);
145774a4d8c2SCharles.Forsyth 	nextarg = a[1]->nnext;
145874a4d8c2SCharles.Forsyth 	switch (t) {
145974a4d8c2SCharles.Forsyth 	case FLENGTH:
146074a4d8c2SCharles.Forsyth 		u = strlen(getsval(x)); break;
146174a4d8c2SCharles.Forsyth 	case FLOG:
146274a4d8c2SCharles.Forsyth 		u = errcheck(log(getfval(x)), "log"); break;
146374a4d8c2SCharles.Forsyth 	case FINT:
146474a4d8c2SCharles.Forsyth 		modf(getfval(x), &u); break;
146574a4d8c2SCharles.Forsyth 	case FEXP:
146674a4d8c2SCharles.Forsyth 		u = errcheck(exp(getfval(x)), "exp"); break;
146774a4d8c2SCharles.Forsyth 	case FSQRT:
146874a4d8c2SCharles.Forsyth 		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
146974a4d8c2SCharles.Forsyth 	case FSIN:
147074a4d8c2SCharles.Forsyth 		u = sin(getfval(x)); break;
147174a4d8c2SCharles.Forsyth 	case FCOS:
147274a4d8c2SCharles.Forsyth 		u = cos(getfval(x)); break;
147374a4d8c2SCharles.Forsyth 	case FATAN:
147474a4d8c2SCharles.Forsyth 		if (nextarg == 0) {
147574a4d8c2SCharles.Forsyth 			WARNING("atan2 requires two arguments; returning 1.0");
147674a4d8c2SCharles.Forsyth 			u = 1.0;
147774a4d8c2SCharles.Forsyth 		} else {
147874a4d8c2SCharles.Forsyth 			y = execute(a[1]->nnext);
147974a4d8c2SCharles.Forsyth 			u = atan2(getfval(x), getfval(y));
148074a4d8c2SCharles.Forsyth 			tempfree(y);
148174a4d8c2SCharles.Forsyth 			nextarg = nextarg->nnext;
148274a4d8c2SCharles.Forsyth 		}
148374a4d8c2SCharles.Forsyth 		break;
148474a4d8c2SCharles.Forsyth 	case FSYSTEM:
148574a4d8c2SCharles.Forsyth 		fflush(stdout);		/* in case something is buffered already */
148674a4d8c2SCharles.Forsyth 		u = (Awkfloat) system(getsval(x)) / 256;   /* 256 is unix-dep */
148774a4d8c2SCharles.Forsyth 		break;
148874a4d8c2SCharles.Forsyth 	case FRAND:
148974a4d8c2SCharles.Forsyth 		/* in principle, rand() returns something in 0..RAND_MAX */
149074a4d8c2SCharles.Forsyth 		u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
149174a4d8c2SCharles.Forsyth 		break;
149274a4d8c2SCharles.Forsyth 	case FSRAND:
149374a4d8c2SCharles.Forsyth 		if (isrec(x))	/* no argument provided */
149474a4d8c2SCharles.Forsyth 			u = time((time_t *)0);
149574a4d8c2SCharles.Forsyth 		else
149674a4d8c2SCharles.Forsyth 			u = getfval(x);
149774a4d8c2SCharles.Forsyth 		srand((unsigned int) u);
149874a4d8c2SCharles.Forsyth 		break;
149974a4d8c2SCharles.Forsyth 	case FTOUPPER:
150074a4d8c2SCharles.Forsyth 	case FTOLOWER:
150174a4d8c2SCharles.Forsyth 		buf = tostring(getsval(x));
150274a4d8c2SCharles.Forsyth 		if (t == FTOUPPER) {
150374a4d8c2SCharles.Forsyth 			for (p = buf; *p; p++)
150474a4d8c2SCharles.Forsyth 				if (islower((uschar) *p))
150574a4d8c2SCharles.Forsyth 					*p = toupper(*p);
150674a4d8c2SCharles.Forsyth 		} else {
150774a4d8c2SCharles.Forsyth 			for (p = buf; *p; p++)
150874a4d8c2SCharles.Forsyth 				if (isupper((uschar) *p))
150974a4d8c2SCharles.Forsyth 					*p = tolower(*p);
151074a4d8c2SCharles.Forsyth 		}
151174a4d8c2SCharles.Forsyth 		tempfree(x);
151274a4d8c2SCharles.Forsyth 		x = gettemp();
151374a4d8c2SCharles.Forsyth 		setsval(x, buf);
151474a4d8c2SCharles.Forsyth 		free(buf);
151574a4d8c2SCharles.Forsyth 		return x;
151674a4d8c2SCharles.Forsyth 	case FFLUSH:
151774a4d8c2SCharles.Forsyth 		if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
151874a4d8c2SCharles.Forsyth 			u = EOF;
151974a4d8c2SCharles.Forsyth 		else
152074a4d8c2SCharles.Forsyth 			u = fflush(fp);
152174a4d8c2SCharles.Forsyth 		break;
152274a4d8c2SCharles.Forsyth 	default:	/* can't happen */
152374a4d8c2SCharles.Forsyth 		FATAL("illegal function type %d", t);
152474a4d8c2SCharles.Forsyth 		break;
152574a4d8c2SCharles.Forsyth 	}
152674a4d8c2SCharles.Forsyth 	tempfree(x);
152774a4d8c2SCharles.Forsyth 	x = gettemp();
152874a4d8c2SCharles.Forsyth 	setfval(x, u);
152974a4d8c2SCharles.Forsyth 	if (nextarg != 0) {
153074a4d8c2SCharles.Forsyth 		WARNING("warning: function has too many arguments");
153174a4d8c2SCharles.Forsyth 		for ( ; nextarg; nextarg = nextarg->nnext)
153274a4d8c2SCharles.Forsyth 			execute(nextarg);
153374a4d8c2SCharles.Forsyth 	}
153474a4d8c2SCharles.Forsyth 	return(x);
153574a4d8c2SCharles.Forsyth }
153674a4d8c2SCharles.Forsyth 
printstat(Node ** a,int n)153774a4d8c2SCharles.Forsyth Cell *printstat(Node **a, int n)	/* print a[0] */
153874a4d8c2SCharles.Forsyth {
153974a4d8c2SCharles.Forsyth 	Node *x;
154074a4d8c2SCharles.Forsyth 	Cell *y;
154174a4d8c2SCharles.Forsyth 	FILE *fp;
154274a4d8c2SCharles.Forsyth 
154374a4d8c2SCharles.Forsyth 	if (a[1] == 0)	/* a[1] is redirection operator, a[2] is file */
154474a4d8c2SCharles.Forsyth 		fp = stdout;
154574a4d8c2SCharles.Forsyth 	else
154674a4d8c2SCharles.Forsyth 		fp = redirect(ptoi(a[1]), a[2]);
154774a4d8c2SCharles.Forsyth 	for (x = a[0]; x != NULL; x = x->nnext) {
154874a4d8c2SCharles.Forsyth 		y = execute(x);
154974a4d8c2SCharles.Forsyth 		fputs(getsval(y), fp);
155074a4d8c2SCharles.Forsyth 		tempfree(y);
155174a4d8c2SCharles.Forsyth 		if (x->nnext == NULL)
155274a4d8c2SCharles.Forsyth 			fputs(*ORS, fp);
155374a4d8c2SCharles.Forsyth 		else
155474a4d8c2SCharles.Forsyth 			fputs(*OFS, fp);
155574a4d8c2SCharles.Forsyth 	}
155674a4d8c2SCharles.Forsyth 	if (a[1] != 0)
155774a4d8c2SCharles.Forsyth 		fflush(fp);
155874a4d8c2SCharles.Forsyth 	if (ferror(fp))
155974a4d8c2SCharles.Forsyth 		FATAL("write error on %s", filename(fp));
156074a4d8c2SCharles.Forsyth 	return(True);
156174a4d8c2SCharles.Forsyth }
156274a4d8c2SCharles.Forsyth 
nullproc(Node ** a,int n)156374a4d8c2SCharles.Forsyth Cell *nullproc(Node **a, int n)
156474a4d8c2SCharles.Forsyth {
156574a4d8c2SCharles.Forsyth 	n = n;
156674a4d8c2SCharles.Forsyth 	a = a;
156774a4d8c2SCharles.Forsyth 	return 0;
156874a4d8c2SCharles.Forsyth }
156974a4d8c2SCharles.Forsyth 
157074a4d8c2SCharles.Forsyth 
redirect(int a,Node * b)157174a4d8c2SCharles.Forsyth FILE *redirect(int a, Node *b)	/* set up all i/o redirections */
157274a4d8c2SCharles.Forsyth {
157374a4d8c2SCharles.Forsyth 	FILE *fp;
157474a4d8c2SCharles.Forsyth 	Cell *x;
157574a4d8c2SCharles.Forsyth 	char *fname;
157674a4d8c2SCharles.Forsyth 
157774a4d8c2SCharles.Forsyth 	x = execute(b);
157874a4d8c2SCharles.Forsyth 	fname = getsval(x);
157974a4d8c2SCharles.Forsyth 	fp = openfile(a, fname);
158074a4d8c2SCharles.Forsyth 	if (fp == NULL)
158174a4d8c2SCharles.Forsyth 		FATAL("can't open file %s", fname);
158274a4d8c2SCharles.Forsyth 	tempfree(x);
158374a4d8c2SCharles.Forsyth 	return fp;
158474a4d8c2SCharles.Forsyth }
158574a4d8c2SCharles.Forsyth 
158674a4d8c2SCharles.Forsyth struct files {
158774a4d8c2SCharles.Forsyth 	FILE	*fp;
158874a4d8c2SCharles.Forsyth 	char	*fname;
158974a4d8c2SCharles.Forsyth 	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
159074a4d8c2SCharles.Forsyth } files[FOPEN_MAX] ={
159174a4d8c2SCharles.Forsyth 	{ NULL,  "/dev/stdin",  LT },	/* watch out: don't free this! */
159274a4d8c2SCharles.Forsyth 	{ NULL, "/dev/stdout", GT },
159374a4d8c2SCharles.Forsyth 	{ NULL, "/dev/stderr", GT }
159474a4d8c2SCharles.Forsyth };
159574a4d8c2SCharles.Forsyth 
stdinit(void)159674a4d8c2SCharles.Forsyth void stdinit(void)	/* in case stdin, etc., are not constants */
159774a4d8c2SCharles.Forsyth {
159874a4d8c2SCharles.Forsyth 	files[0].fp = stdin;
159974a4d8c2SCharles.Forsyth 	files[1].fp = stdout;
160074a4d8c2SCharles.Forsyth 	files[2].fp = stderr;
160174a4d8c2SCharles.Forsyth }
160274a4d8c2SCharles.Forsyth 
openfile(int a,char * us)160374a4d8c2SCharles.Forsyth FILE *openfile(int a, char *us)
160474a4d8c2SCharles.Forsyth {
160574a4d8c2SCharles.Forsyth 	char *s = us;
160674a4d8c2SCharles.Forsyth 	int i, m;
160774a4d8c2SCharles.Forsyth 	FILE *fp = 0;
160874a4d8c2SCharles.Forsyth 
160974a4d8c2SCharles.Forsyth 	if (*s == '\0')
161074a4d8c2SCharles.Forsyth 		FATAL("null file name in print or getline");
161174a4d8c2SCharles.Forsyth 	for (i=0; i < FOPEN_MAX; i++)
161274a4d8c2SCharles.Forsyth 		if (files[i].fname && strcmp(s, files[i].fname) == 0) {
161374a4d8c2SCharles.Forsyth 			if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
161474a4d8c2SCharles.Forsyth 				return files[i].fp;
161574a4d8c2SCharles.Forsyth 			if (a == FFLUSH)
161674a4d8c2SCharles.Forsyth 				return files[i].fp;
161774a4d8c2SCharles.Forsyth 		}
161874a4d8c2SCharles.Forsyth 	if (a == FFLUSH)	/* didn't find it, so don't create it! */
161974a4d8c2SCharles.Forsyth 		return NULL;
162074a4d8c2SCharles.Forsyth 
162174a4d8c2SCharles.Forsyth 	for (i=0; i < FOPEN_MAX; i++)
162274a4d8c2SCharles.Forsyth 		if (files[i].fp == 0)
162374a4d8c2SCharles.Forsyth 			break;
162474a4d8c2SCharles.Forsyth 	if (i >= FOPEN_MAX)
162574a4d8c2SCharles.Forsyth 		FATAL("%s makes too many open files", s);
162674a4d8c2SCharles.Forsyth 	fflush(stdout);	/* force a semblance of order */
162774a4d8c2SCharles.Forsyth 	m = a;
162874a4d8c2SCharles.Forsyth 	if (a == GT) {
162974a4d8c2SCharles.Forsyth 		fp = fopen(s, "w");
163074a4d8c2SCharles.Forsyth 	} else if (a == APPEND) {
163174a4d8c2SCharles.Forsyth 		fp = fopen(s, "a");
163274a4d8c2SCharles.Forsyth 		m = GT;	/* so can mix > and >> */
163374a4d8c2SCharles.Forsyth 	} else if (a == '|') {	/* output pipe */
163474a4d8c2SCharles.Forsyth 		fp = popen(s, "w");
163574a4d8c2SCharles.Forsyth 	} else if (a == LE) {	/* input pipe */
163674a4d8c2SCharles.Forsyth 		fp = popen(s, "r");
163774a4d8c2SCharles.Forsyth 	} else if (a == LT) {	/* getline <file */
163874a4d8c2SCharles.Forsyth 		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
163974a4d8c2SCharles.Forsyth 	} else	/* can't happen */
164074a4d8c2SCharles.Forsyth 		FATAL("illegal redirection %d", a);
164174a4d8c2SCharles.Forsyth 	if (fp != NULL) {
164274a4d8c2SCharles.Forsyth 		files[i].fname = tostring(s);
164374a4d8c2SCharles.Forsyth 		files[i].fp = fp;
164474a4d8c2SCharles.Forsyth 		files[i].mode = m;
164574a4d8c2SCharles.Forsyth 	}
164674a4d8c2SCharles.Forsyth 	return fp;
164774a4d8c2SCharles.Forsyth }
164874a4d8c2SCharles.Forsyth 
filename(FILE * fp)164974a4d8c2SCharles.Forsyth char *filename(FILE *fp)
165074a4d8c2SCharles.Forsyth {
165174a4d8c2SCharles.Forsyth 	int i;
165274a4d8c2SCharles.Forsyth 
165374a4d8c2SCharles.Forsyth 	for (i = 0; i < FOPEN_MAX; i++)
165474a4d8c2SCharles.Forsyth 		if (fp == files[i].fp)
165574a4d8c2SCharles.Forsyth 			return files[i].fname;
1656*45a20ab7Sforsyth 	return "?";
165774a4d8c2SCharles.Forsyth }
165874a4d8c2SCharles.Forsyth 
closefile(Node ** a,int n)165974a4d8c2SCharles.Forsyth Cell *closefile(Node **a, int n)
166074a4d8c2SCharles.Forsyth {
166174a4d8c2SCharles.Forsyth 	Cell *x;
166274a4d8c2SCharles.Forsyth 	int i, stat;
166374a4d8c2SCharles.Forsyth 
166474a4d8c2SCharles.Forsyth 	n = n;
166574a4d8c2SCharles.Forsyth 	x = execute(a[0]);
166674a4d8c2SCharles.Forsyth 	getsval(x);
166774a4d8c2SCharles.Forsyth 	stat = -1;
166874a4d8c2SCharles.Forsyth 	for (i = 0; i < FOPEN_MAX; i++) {
166974a4d8c2SCharles.Forsyth 		if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
167074a4d8c2SCharles.Forsyth 			if (ferror(files[i].fp))
167174a4d8c2SCharles.Forsyth 				WARNING( "i/o error occurred on %s", files[i].fname );
167274a4d8c2SCharles.Forsyth 			if (files[i].mode == '|' || files[i].mode == LE)
167374a4d8c2SCharles.Forsyth 				stat = pclose(files[i].fp);
167474a4d8c2SCharles.Forsyth 			else
167574a4d8c2SCharles.Forsyth 				stat = fclose(files[i].fp);
167674a4d8c2SCharles.Forsyth 			if (stat == EOF)
167774a4d8c2SCharles.Forsyth 				WARNING( "i/o error occurred closing %s", files[i].fname );
167874a4d8c2SCharles.Forsyth 			if (i > 2)	/* don't do /dev/std... */
167974a4d8c2SCharles.Forsyth 				xfree(files[i].fname);
168074a4d8c2SCharles.Forsyth 			files[i].fname = NULL;	/* watch out for ref thru this */
168174a4d8c2SCharles.Forsyth 			files[i].fp = NULL;
168274a4d8c2SCharles.Forsyth 		}
168374a4d8c2SCharles.Forsyth 	}
168474a4d8c2SCharles.Forsyth 	tempfree(x);
168574a4d8c2SCharles.Forsyth 	x = gettemp();
168674a4d8c2SCharles.Forsyth 	setfval(x, (Awkfloat) stat);
168774a4d8c2SCharles.Forsyth 	return(x);
168874a4d8c2SCharles.Forsyth }
168974a4d8c2SCharles.Forsyth 
closeall(void)169074a4d8c2SCharles.Forsyth void closeall(void)
169174a4d8c2SCharles.Forsyth {
169274a4d8c2SCharles.Forsyth 	int i, stat;
169374a4d8c2SCharles.Forsyth 
169474a4d8c2SCharles.Forsyth 	for (i = 0; i < FOPEN_MAX; i++) {
169574a4d8c2SCharles.Forsyth 		if (files[i].fp) {
169674a4d8c2SCharles.Forsyth 			if (ferror(files[i].fp))
169774a4d8c2SCharles.Forsyth 				WARNING( "i/o error occurred on %s", files[i].fname );
169874a4d8c2SCharles.Forsyth 			if (files[i].mode == '|' || files[i].mode == LE)
169974a4d8c2SCharles.Forsyth 				stat = pclose(files[i].fp);
170074a4d8c2SCharles.Forsyth 			else
170174a4d8c2SCharles.Forsyth 				stat = fclose(files[i].fp);
170274a4d8c2SCharles.Forsyth 			if (stat == EOF && i != 0)
170374a4d8c2SCharles.Forsyth 				WARNING( "i/o error occurred while closing %s", files[i].fname );
170474a4d8c2SCharles.Forsyth 		}
170574a4d8c2SCharles.Forsyth 	}
170674a4d8c2SCharles.Forsyth }
170774a4d8c2SCharles.Forsyth 
170874a4d8c2SCharles.Forsyth void backsub(char **pb_ptr, char **sptr_ptr);
170974a4d8c2SCharles.Forsyth 
sub(Node ** a,int nnn)171074a4d8c2SCharles.Forsyth Cell *sub(Node **a, int nnn)	/* substitute command */
171174a4d8c2SCharles.Forsyth {
171274a4d8c2SCharles.Forsyth 	char *sptr, *pb, *q;
171374a4d8c2SCharles.Forsyth 	Cell *x, *y, *result;
171474a4d8c2SCharles.Forsyth 	char *t, *buf;
171574a4d8c2SCharles.Forsyth 	fa *pfa;
171674a4d8c2SCharles.Forsyth 	int bufsz = recsize;
171774a4d8c2SCharles.Forsyth 
171874a4d8c2SCharles.Forsyth 	if ((buf = (char *) malloc(bufsz)) == NULL)
171974a4d8c2SCharles.Forsyth 		FATAL("out of memory in sub");
172074a4d8c2SCharles.Forsyth 	x = execute(a[3]);	/* target string */
172174a4d8c2SCharles.Forsyth 	t = getsval(x);
172274a4d8c2SCharles.Forsyth 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
172374a4d8c2SCharles.Forsyth 		pfa = (fa *) a[1];	/* regular expression */
172474a4d8c2SCharles.Forsyth 	else {
172574a4d8c2SCharles.Forsyth 		y = execute(a[1]);
172674a4d8c2SCharles.Forsyth 		pfa = makedfa(getsval(y), 1);
172774a4d8c2SCharles.Forsyth 		tempfree(y);
172874a4d8c2SCharles.Forsyth 	}
172974a4d8c2SCharles.Forsyth 	y = execute(a[2]);	/* replacement string */
173074a4d8c2SCharles.Forsyth 	result = False;
173174a4d8c2SCharles.Forsyth 	if (pmatch(pfa, t)) {
173274a4d8c2SCharles.Forsyth 		sptr = t;
173374a4d8c2SCharles.Forsyth 		adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
173474a4d8c2SCharles.Forsyth 		pb = buf;
173574a4d8c2SCharles.Forsyth 		while (sptr < patbeg)
173674a4d8c2SCharles.Forsyth 			*pb++ = *sptr++;
173774a4d8c2SCharles.Forsyth 		sptr = getsval(y);
173874a4d8c2SCharles.Forsyth 		while (*sptr != 0) {
173974a4d8c2SCharles.Forsyth 			adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
174074a4d8c2SCharles.Forsyth 			if (*sptr == '\\') {
174174a4d8c2SCharles.Forsyth 				backsub(&pb, &sptr);
174274a4d8c2SCharles.Forsyth 			} else if (*sptr == '&') {
174374a4d8c2SCharles.Forsyth 				sptr++;
174474a4d8c2SCharles.Forsyth 				adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
174574a4d8c2SCharles.Forsyth 				for (q = patbeg; q < patbeg+patlen; )
174674a4d8c2SCharles.Forsyth 					*pb++ = *q++;
174774a4d8c2SCharles.Forsyth 			} else
174874a4d8c2SCharles.Forsyth 				*pb++ = *sptr++;
174974a4d8c2SCharles.Forsyth 		}
175074a4d8c2SCharles.Forsyth 		*pb = '\0';
175174a4d8c2SCharles.Forsyth 		if (pb > buf + bufsz)
175274a4d8c2SCharles.Forsyth 			FATAL("sub result1 %.30s too big; can't happen", buf);
175374a4d8c2SCharles.Forsyth 		sptr = patbeg + patlen;
175474a4d8c2SCharles.Forsyth 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
175574a4d8c2SCharles.Forsyth 			adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
175674a4d8c2SCharles.Forsyth 			while ((*pb++ = *sptr++) != 0)
175774a4d8c2SCharles.Forsyth 				;
175874a4d8c2SCharles.Forsyth 		}
175974a4d8c2SCharles.Forsyth 		if (pb > buf + bufsz)
176074a4d8c2SCharles.Forsyth 			FATAL("sub result2 %.30s too big; can't happen", buf);
176174a4d8c2SCharles.Forsyth 		setsval(x, buf);	/* BUG: should be able to avoid copy */
176274a4d8c2SCharles.Forsyth 		result = True;;
176374a4d8c2SCharles.Forsyth 	}
176474a4d8c2SCharles.Forsyth 	tempfree(x);
176574a4d8c2SCharles.Forsyth 	tempfree(y);
176674a4d8c2SCharles.Forsyth 	free(buf);
176774a4d8c2SCharles.Forsyth 	return result;
176874a4d8c2SCharles.Forsyth }
176974a4d8c2SCharles.Forsyth 
gsub(Node ** a,int nnn)177074a4d8c2SCharles.Forsyth Cell *gsub(Node **a, int nnn)	/* global substitute */
177174a4d8c2SCharles.Forsyth {
177274a4d8c2SCharles.Forsyth 	Cell *x, *y;
177374a4d8c2SCharles.Forsyth 	char *rptr, *sptr, *t, *pb, *q;
177474a4d8c2SCharles.Forsyth 	char *buf;
177574a4d8c2SCharles.Forsyth 	fa *pfa;
177674a4d8c2SCharles.Forsyth 	int mflag, tempstat, num;
177774a4d8c2SCharles.Forsyth 	int bufsz = recsize;
177874a4d8c2SCharles.Forsyth 
177974a4d8c2SCharles.Forsyth 	if ((buf = (char *) malloc(bufsz)) == NULL)
178074a4d8c2SCharles.Forsyth 		FATAL("out of memory in gsub");
178174a4d8c2SCharles.Forsyth 	mflag = 0;	/* if mflag == 0, can replace empty string */
178274a4d8c2SCharles.Forsyth 	num = 0;
178374a4d8c2SCharles.Forsyth 	x = execute(a[3]);	/* target string */
178474a4d8c2SCharles.Forsyth 	t = getsval(x);
178574a4d8c2SCharles.Forsyth 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
178674a4d8c2SCharles.Forsyth 		pfa = (fa *) a[1];	/* regular expression */
178774a4d8c2SCharles.Forsyth 	else {
178874a4d8c2SCharles.Forsyth 		y = execute(a[1]);
178974a4d8c2SCharles.Forsyth 		pfa = makedfa(getsval(y), 1);
179074a4d8c2SCharles.Forsyth 		tempfree(y);
179174a4d8c2SCharles.Forsyth 	}
179274a4d8c2SCharles.Forsyth 	y = execute(a[2]);	/* replacement string */
179374a4d8c2SCharles.Forsyth 	if (pmatch(pfa, t)) {
179474a4d8c2SCharles.Forsyth 		tempstat = pfa->initstat;
179574a4d8c2SCharles.Forsyth 		pfa->initstat = 2;
179674a4d8c2SCharles.Forsyth 		pb = buf;
179774a4d8c2SCharles.Forsyth 		rptr = getsval(y);
179874a4d8c2SCharles.Forsyth 		do {
179974a4d8c2SCharles.Forsyth 			if (patlen == 0 && *patbeg != 0) {	/* matched empty string */
180074a4d8c2SCharles.Forsyth 				if (mflag == 0) {	/* can replace empty */
180174a4d8c2SCharles.Forsyth 					num++;
180274a4d8c2SCharles.Forsyth 					sptr = rptr;
180374a4d8c2SCharles.Forsyth 					while (*sptr != 0) {
180474a4d8c2SCharles.Forsyth 						adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
180574a4d8c2SCharles.Forsyth 						if (*sptr == '\\') {
180674a4d8c2SCharles.Forsyth 							backsub(&pb, &sptr);
180774a4d8c2SCharles.Forsyth 						} else if (*sptr == '&') {
180874a4d8c2SCharles.Forsyth 							sptr++;
180974a4d8c2SCharles.Forsyth 							adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
181074a4d8c2SCharles.Forsyth 							for (q = patbeg; q < patbeg+patlen; )
181174a4d8c2SCharles.Forsyth 								*pb++ = *q++;
181274a4d8c2SCharles.Forsyth 						} else
181374a4d8c2SCharles.Forsyth 							*pb++ = *sptr++;
181474a4d8c2SCharles.Forsyth 					}
181574a4d8c2SCharles.Forsyth 				}
181674a4d8c2SCharles.Forsyth 				if (*t == 0)	/* at end */
181774a4d8c2SCharles.Forsyth 					goto done;
181874a4d8c2SCharles.Forsyth 				adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
181974a4d8c2SCharles.Forsyth 				*pb++ = *t++;
182074a4d8c2SCharles.Forsyth 				if (pb > buf + bufsz)	/* BUG: not sure of this test */
182174a4d8c2SCharles.Forsyth 					FATAL("gsub result0 %.30s too big; can't happen", buf);
182274a4d8c2SCharles.Forsyth 				mflag = 0;
182374a4d8c2SCharles.Forsyth 			}
182474a4d8c2SCharles.Forsyth 			else {	/* matched nonempty string */
182574a4d8c2SCharles.Forsyth 				num++;
182674a4d8c2SCharles.Forsyth 				sptr = t;
182774a4d8c2SCharles.Forsyth 				adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
182874a4d8c2SCharles.Forsyth 				while (sptr < patbeg)
182974a4d8c2SCharles.Forsyth 					*pb++ = *sptr++;
183074a4d8c2SCharles.Forsyth 				sptr = rptr;
183174a4d8c2SCharles.Forsyth 				while (*sptr != 0) {
183274a4d8c2SCharles.Forsyth 					adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
183374a4d8c2SCharles.Forsyth 					if (*sptr == '\\') {
183474a4d8c2SCharles.Forsyth 						backsub(&pb, &sptr);
183574a4d8c2SCharles.Forsyth 					} else if (*sptr == '&') {
183674a4d8c2SCharles.Forsyth 						sptr++;
183774a4d8c2SCharles.Forsyth 						adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
183874a4d8c2SCharles.Forsyth 						for (q = patbeg; q < patbeg+patlen; )
183974a4d8c2SCharles.Forsyth 							*pb++ = *q++;
184074a4d8c2SCharles.Forsyth 					} else
184174a4d8c2SCharles.Forsyth 						*pb++ = *sptr++;
184274a4d8c2SCharles.Forsyth 				}
184374a4d8c2SCharles.Forsyth 				t = patbeg + patlen;
184474a4d8c2SCharles.Forsyth 				if (patlen == 0 || *t == 0 || *(t-1) == 0)
184574a4d8c2SCharles.Forsyth 					goto done;
184674a4d8c2SCharles.Forsyth 				if (pb > buf + bufsz)
184774a4d8c2SCharles.Forsyth 					FATAL("gsub result1 %.30s too big; can't happen", buf);
184874a4d8c2SCharles.Forsyth 				mflag = 1;
184974a4d8c2SCharles.Forsyth 			}
185074a4d8c2SCharles.Forsyth 		} while (pmatch(pfa,t));
185174a4d8c2SCharles.Forsyth 		sptr = t;
185274a4d8c2SCharles.Forsyth 		adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
185374a4d8c2SCharles.Forsyth 		while ((*pb++ = *sptr++) != 0)
185474a4d8c2SCharles.Forsyth 			;
185574a4d8c2SCharles.Forsyth 	done:	if (pb > buf + bufsz)
185674a4d8c2SCharles.Forsyth 			FATAL("gsub result2 %.30s too big; can't happen", buf);
185774a4d8c2SCharles.Forsyth 		*pb = '\0';
185874a4d8c2SCharles.Forsyth 		setsval(x, buf);	/* BUG: should be able to avoid copy + free */
185974a4d8c2SCharles.Forsyth 		pfa->initstat = tempstat;
186074a4d8c2SCharles.Forsyth 	}
186174a4d8c2SCharles.Forsyth 	tempfree(x);
186274a4d8c2SCharles.Forsyth 	tempfree(y);
186374a4d8c2SCharles.Forsyth 	x = gettemp();
186474a4d8c2SCharles.Forsyth 	x->tval = NUM;
186574a4d8c2SCharles.Forsyth 	x->fval = num;
186674a4d8c2SCharles.Forsyth 	free(buf);
186774a4d8c2SCharles.Forsyth 	return(x);
186874a4d8c2SCharles.Forsyth }
186974a4d8c2SCharles.Forsyth 
backsub(char ** pb_ptr,char ** sptr_ptr)187074a4d8c2SCharles.Forsyth void backsub(char **pb_ptr, char **sptr_ptr)	/* handle \\& variations */
187174a4d8c2SCharles.Forsyth {						/* sptr[0] == '\\' */
187274a4d8c2SCharles.Forsyth 	char *pb = *pb_ptr, *sptr = *sptr_ptr;
187374a4d8c2SCharles.Forsyth 
187474a4d8c2SCharles.Forsyth 	if (sptr[1] == '\\') {
187574a4d8c2SCharles.Forsyth 		if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
187674a4d8c2SCharles.Forsyth 			*pb++ = '\\';
187774a4d8c2SCharles.Forsyth 			*pb++ = '&';
187874a4d8c2SCharles.Forsyth 			sptr += 4;
187974a4d8c2SCharles.Forsyth 		} else if (sptr[2] == '&') {	/* \\& -> \ + matched */
188074a4d8c2SCharles.Forsyth 			*pb++ = '\\';
188174a4d8c2SCharles.Forsyth 			sptr += 2;
188274a4d8c2SCharles.Forsyth 		} else {			/* \\x -> \\x */
188374a4d8c2SCharles.Forsyth 			*pb++ = *sptr++;
188474a4d8c2SCharles.Forsyth 			*pb++ = *sptr++;
188574a4d8c2SCharles.Forsyth 		}
188674a4d8c2SCharles.Forsyth 	} else if (sptr[1] == '&') {	/* literal & */
188774a4d8c2SCharles.Forsyth 		sptr++;
188874a4d8c2SCharles.Forsyth 		*pb++ = *sptr++;
188974a4d8c2SCharles.Forsyth 	} else				/* literal \ */
189074a4d8c2SCharles.Forsyth 		*pb++ = *sptr++;
189174a4d8c2SCharles.Forsyth 
189274a4d8c2SCharles.Forsyth 	*pb_ptr = pb;
189374a4d8c2SCharles.Forsyth 	*sptr_ptr = sptr;
189474a4d8c2SCharles.Forsyth }
1895