xref: /original-bsd/contrib/awk.research/run.c (revision 72bcf366)
141abc59cSbostic /****************************************************************
241abc59cSbostic Copyright (C) AT&T 1993
341abc59cSbostic All Rights Reserved
441abc59cSbostic 
541abc59cSbostic Permission to use, copy, modify, and distribute this software and
641abc59cSbostic its documentation for any purpose and without fee is hereby
741abc59cSbostic granted, provided that the above copyright notice appear in all
841abc59cSbostic copies and that both that the copyright notice and this
941abc59cSbostic permission notice and warranty disclaimer appear in supporting
1041abc59cSbostic documentation, and that the name of AT&T or any of its entities
1141abc59cSbostic not be used in advertising or publicity pertaining to
1241abc59cSbostic distribution of the software without specific, written prior
1341abc59cSbostic permission.
1441abc59cSbostic 
1541abc59cSbostic AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1641abc59cSbostic INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1741abc59cSbostic IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
1841abc59cSbostic SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1941abc59cSbostic WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
2041abc59cSbostic IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2141abc59cSbostic ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
2241abc59cSbostic THIS SOFTWARE.
2341abc59cSbostic ****************************************************************/
2441abc59cSbostic 
2541abc59cSbostic #define tempfree(x)	if (istemp(x)) tfree(x); else
2641abc59cSbostic 
2741abc59cSbostic #define DEBUG
2841abc59cSbostic #include <stdio.h>
2941abc59cSbostic #include <ctype.h>
3041abc59cSbostic #include <setjmp.h>
3141abc59cSbostic #include <math.h>
3241abc59cSbostic #include <string.h>
3341abc59cSbostic #include <stdlib.h>
3441abc59cSbostic #include <time.h>
3541abc59cSbostic #include "awk.h"
3641abc59cSbostic #include "y.tab.h"
3741abc59cSbostic 
3841abc59cSbostic #ifdef _NFILE
3941abc59cSbostic #ifndef FOPEN_MAX
4041abc59cSbostic #define FOPEN_MAX _NFILE
4141abc59cSbostic #endif
4241abc59cSbostic #endif
4341abc59cSbostic 
4441abc59cSbostic #ifndef	FOPEN_MAX
4541abc59cSbostic #define	FOPEN_MAX	40	/* max number of open files */
4641abc59cSbostic #endif
4741abc59cSbostic 
4841abc59cSbostic #ifndef RAND_MAX
4941abc59cSbostic #define RAND_MAX	32767	/* all that ansi guarantees */
5041abc59cSbostic #endif
5141abc59cSbostic 
5241abc59cSbostic jmp_buf env;
5341abc59cSbostic 
5441abc59cSbostic /* an attempt to go a bit faster: */
5541abc59cSbostic 
5641abc59cSbostic /* #define	execute(p)	(isvalue(p) ? (Cell *)((p)->narg[0]) : r_execute(p)) */
5741abc59cSbostic #define	execute(p) r_execute(p)
5841abc59cSbostic #define	getfval(p)	(((p)->tval & (ARR|FLD|REC|NUM)) == NUM ? (p)->fval : r_getfval(p))
5941abc59cSbostic #define	getsval(p)	(((p)->tval & (ARR|FLD|REC|STR)) == STR ? (p)->sval : r_getsval(p))
6041abc59cSbostic 
6141abc59cSbostic 
6241abc59cSbostic #define PA2NUM	29	/* max number of pat,pat patterns allowed */
6341abc59cSbostic int	paircnt;		/* number of them in use */
6441abc59cSbostic int	pairstack[PA2NUM];	/* state of each pat,pat */
6541abc59cSbostic 
6641abc59cSbostic Node	*winner = NULL;	/* root of parse tree */
6741abc59cSbostic Cell	*tmps;		/* free temporary cells for execution */
6841abc59cSbostic 
6941abc59cSbostic static Cell	truecell	={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
7041abc59cSbostic Cell	*true	= &truecell;
7141abc59cSbostic static Cell	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
7241abc59cSbostic Cell	*false	= &falsecell;
7341abc59cSbostic static Cell	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
7441abc59cSbostic Cell	*jbreak	= &breakcell;
7541abc59cSbostic static Cell	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM };
7641abc59cSbostic Cell	*jcont	= &contcell;
7741abc59cSbostic static Cell	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
7841abc59cSbostic Cell	*jnext	= &nextcell;
7941abc59cSbostic static Cell	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
8041abc59cSbostic Cell	*jexit	= &exitcell;
8141abc59cSbostic static Cell	retcell		={ OJUMP, JRET, 0, 0, 0.0, NUM };
8241abc59cSbostic Cell	*jret	= &retcell;
8341abc59cSbostic static Cell	tempcell	={ OCELL, CTEMP, 0, 0, 0.0, NUM };
8441abc59cSbostic 
8541abc59cSbostic Node	*curnode = NULL;	/* the node being executed, for debugging */
8641abc59cSbostic 
run(Node * a)8741abc59cSbostic void run(Node *a)	/* execution of parse tree starts here */
8841abc59cSbostic {
8941abc59cSbostic 	execute(a);
9041abc59cSbostic 	closeall();
9141abc59cSbostic }
9241abc59cSbostic 
r_execute(Node * u)9341abc59cSbostic Cell *r_execute(Node *u)	/* execute a node of the parse tree */
9441abc59cSbostic {
9541abc59cSbostic 	register Cell *(*proc)(Node **, int);
9641abc59cSbostic 	register Cell *x;
9741abc59cSbostic 	register Node *a;
9841abc59cSbostic 
9941abc59cSbostic 	if (u == NULL)
10041abc59cSbostic 		return(true);
10141abc59cSbostic 	for (a = u; ; a = a->nnext) {
10241abc59cSbostic 		curnode = a;
10341abc59cSbostic 		if (isvalue(a)) {
10441abc59cSbostic 			x = (Cell *) (a->narg[0]);
10541abc59cSbostic 			if ((x->tval & FLD) && !donefld)
10641abc59cSbostic 				fldbld();
10741abc59cSbostic 			else if ((x->tval & REC) && !donerec)
10841abc59cSbostic 				recbld();
10941abc59cSbostic 			return(x);
11041abc59cSbostic 		}
11141abc59cSbostic 		if (notlegal(a->nobj))	/* probably a Cell* but too risky to print */
11241abc59cSbostic 			ERROR "illegal statement" FATAL;
11341abc59cSbostic 		proc = proctab[a->nobj-FIRSTTOKEN];
11441abc59cSbostic 		x = (*proc)(a->narg, a->nobj);
11541abc59cSbostic 		if ((x->tval & FLD) && !donefld)
11641abc59cSbostic 			fldbld();
11741abc59cSbostic 		else if ((x->tval & REC) && !donerec)
11841abc59cSbostic 			recbld();
11941abc59cSbostic 		if (isexpr(a))
12041abc59cSbostic 			return(x);
12141abc59cSbostic 		if (isjump(x))
12241abc59cSbostic 			return(x);
12341abc59cSbostic 		if (a->nnext == NULL)
12441abc59cSbostic 			return(x);
12541abc59cSbostic 		tempfree(x);
12641abc59cSbostic 	}
12741abc59cSbostic }
12841abc59cSbostic 
12941abc59cSbostic 
program(Node ** a,int n)13041abc59cSbostic Cell *program(Node **a, int n)	/* execute an awk program */
13141abc59cSbostic {				/* a[0] = BEGIN, a[1] = body, a[2] = END */
13241abc59cSbostic 	register Cell *x;
13341abc59cSbostic 
13441abc59cSbostic 	if (setjmp(env) != 0)
13541abc59cSbostic 		goto ex;
13641abc59cSbostic 	if (a[0]) {		/* BEGIN */
13741abc59cSbostic 		x = execute(a[0]);
13841abc59cSbostic 		if (isexit(x))
13941abc59cSbostic 			return(true);
14041abc59cSbostic 		if (isjump(x))
14141abc59cSbostic 			ERROR "illegal break, continue or next from BEGIN" FATAL;
14241abc59cSbostic 		tempfree(x);
14341abc59cSbostic 	}
14441abc59cSbostic   loop:
14541abc59cSbostic 	if (a[1] || a[2])
14641abc59cSbostic 		while (getrec(record) > 0) {
14741abc59cSbostic 			x = execute(a[1]);
14841abc59cSbostic 			if (isexit(x))
14941abc59cSbostic 				break;
15041abc59cSbostic 			tempfree(x);
15141abc59cSbostic 		}
15241abc59cSbostic   ex:
15341abc59cSbostic 	if (setjmp(env) != 0)	/* handles exit within END */
15441abc59cSbostic 		goto ex1;
15541abc59cSbostic 	if (a[2]) {		/* END */
15641abc59cSbostic 		x = execute(a[2]);
15741abc59cSbostic 		if (isbreak(x) || isnext(x) || iscont(x))
15841abc59cSbostic 			ERROR "illegal break, next, or continue from END" FATAL;
15941abc59cSbostic 		tempfree(x);
16041abc59cSbostic 	}
16141abc59cSbostic   ex1:
16241abc59cSbostic 	return(true);
16341abc59cSbostic }
16441abc59cSbostic 
16541abc59cSbostic struct Frame {	/* stack frame for awk function calls */
16641abc59cSbostic 	int nargs;	/* number of arguments in this call */
16741abc59cSbostic 	Cell *fcncell;	/* pointer to Cell for function */
16841abc59cSbostic 	Cell **args;	/* pointer to array of arguments after execute */
16941abc59cSbostic 	Cell *retval;	/* return value */
17041abc59cSbostic };
17141abc59cSbostic 
17241abc59cSbostic #define	NARGS	50	/* max args in a call */
17341abc59cSbostic 
17441abc59cSbostic struct Frame *frame = NULL;	/* base of stack frames; dynamically allocated */
17541abc59cSbostic int	nframe = 0;		/* number of frames allocated */
17641abc59cSbostic struct Frame *fp = NULL;	/* frame pointer. bottom level unused */
17741abc59cSbostic 
call(Node ** a,int n)17841abc59cSbostic Cell *call(Node **a, int n)	/* function call.  very kludgy and fragile */
17941abc59cSbostic {
18041abc59cSbostic 	static Cell newcopycell = { OCELL, CCOPY, 0, (uchar *) "", 0.0, NUM|STR|DONTFREE };
18141abc59cSbostic 	int i, ncall, ndef;
18241abc59cSbostic 	Node *x;
18341abc59cSbostic 	Cell *args[NARGS], *oargs[NARGS], *y, *z, *fcn;
18441abc59cSbostic 	uchar *s;
18541abc59cSbostic 
18641abc59cSbostic 	fcn = execute(a[0]);	/* the function itself */
18741abc59cSbostic 	s = fcn->nval;
18841abc59cSbostic 	if (!isfunc(fcn))
18941abc59cSbostic 		ERROR "calling undefined function %s", s FATAL;
19041abc59cSbostic 	if (frame == NULL) {
19141abc59cSbostic 		fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
19241abc59cSbostic 		if (frame == NULL)
19341abc59cSbostic 			ERROR "out of space for stack frames calling %s", s FATAL;
19441abc59cSbostic 	}
19541abc59cSbostic 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)	/* args in call */
19641abc59cSbostic 		ncall++;
19741abc59cSbostic 	ndef = (int) fcn->fval;			/* args in defn */
19841abc59cSbostic 	dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, fp-frame) );
19941abc59cSbostic 	if (ncall > ndef)
20041abc59cSbostic 		ERROR "function %s called with %d args, uses only %d",
20141abc59cSbostic 			s, ncall, ndef WARNING;
20241abc59cSbostic 	if (ncall + ndef > NARGS)
20341abc59cSbostic 		ERROR "function %s has %d arguments, limit %d", s, ncall+ndef, NARGS FATAL;
20441abc59cSbostic 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {	/* get call args */
20541abc59cSbostic 		dprintf( ("evaluate args[%d], fp=%d:\n", i, fp-frame) );
20641abc59cSbostic 		y = execute(x);
20741abc59cSbostic 		oargs[i] = y;
20841abc59cSbostic 		dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
20941abc59cSbostic 			   i, y->nval, y->fval, isarr(y) ? "(array)" : (char*) y->sval, y->tval) );
21041abc59cSbostic 		if (isfunc(y))
21141abc59cSbostic 			ERROR "can't use function %s as argument in %s", y->nval, s FATAL;
21241abc59cSbostic 		if (isarr(y))
21341abc59cSbostic 			args[i] = y;	/* arrays by ref */
21441abc59cSbostic 		else
21541abc59cSbostic 			args[i] = copycell(y);
21641abc59cSbostic 		tempfree(y);
21741abc59cSbostic 	}
21841abc59cSbostic 	for ( ; i < ndef; i++) {	/* add null args for ones not provided */
21941abc59cSbostic 		args[i] = gettemp();
22041abc59cSbostic 		*args[i] = newcopycell;
22141abc59cSbostic 	}
22241abc59cSbostic 	fp++;	/* now ok to up frame */
22341abc59cSbostic 	if (fp >= frame + nframe) {
22441abc59cSbostic 		int dfp = fp - frame;	/* old index */
22541abc59cSbostic 		frame = (struct Frame *)
22641abc59cSbostic 			realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
22741abc59cSbostic 		if (frame == NULL)
22841abc59cSbostic 			ERROR "out of space for stack frames in %s", s FATAL;
22941abc59cSbostic 		fp = frame + dfp;
23041abc59cSbostic 	}
23141abc59cSbostic 	fp->fcncell = fcn;
23241abc59cSbostic 	fp->args = args;
23341abc59cSbostic 	fp->nargs = ndef;	/* number defined with (excess are locals) */
23441abc59cSbostic 	fp->retval = gettemp();
23541abc59cSbostic 
23641abc59cSbostic 	dprintf( ("start exec of %s, fp=%d\n", s, fp-frame) );
23741abc59cSbostic 	y = execute((Node *)(fcn->sval));	/* execute body */
23841abc59cSbostic 	dprintf( ("finished exec of %s, fp=%d\n", s, fp-frame) );
23941abc59cSbostic 
24041abc59cSbostic 	for (i = 0; i < ndef; i++) {
24141abc59cSbostic 		Cell *t = fp->args[i];
24241abc59cSbostic 		if (isarr(t)) {
24341abc59cSbostic 			if (t->csub == CCOPY) {
24441abc59cSbostic 				if (i >= ncall) {
24541abc59cSbostic 					freesymtab(t);
24641abc59cSbostic 					t->csub = CTEMP;
24741abc59cSbostic 				} else {
24841abc59cSbostic 					oargs[i]->tval = t->tval;
24941abc59cSbostic 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
25041abc59cSbostic 					oargs[i]->sval = t->sval;
25141abc59cSbostic 					tempfree(t);
25241abc59cSbostic 				}
25341abc59cSbostic 			}
25441abc59cSbostic 		} else if (t != y) {	/* kludge to prevent freeing twice */
25541abc59cSbostic 			t->csub = CTEMP;
25641abc59cSbostic 			tempfree(t);
25741abc59cSbostic 		}
25841abc59cSbostic 	}
25941abc59cSbostic 	tempfree(fcn);
26041abc59cSbostic 	if (isexit(y) || isnext(y))
26141abc59cSbostic 		return y;
26241abc59cSbostic 	tempfree(y);		/* this can free twice! */
26341abc59cSbostic 	z = fp->retval;			/* return value */
26441abc59cSbostic 	dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
26541abc59cSbostic 	fp--;
26641abc59cSbostic 	return(z);
26741abc59cSbostic }
26841abc59cSbostic 
copycell(Cell * x)26941abc59cSbostic Cell *copycell(Cell *x)	/* make a copy of a cell in a temp */
27041abc59cSbostic {
27141abc59cSbostic 	Cell *y;
27241abc59cSbostic 
27341abc59cSbostic 	y = gettemp();
27441abc59cSbostic 	y->csub = CCOPY;	/* prevents freeing until call is over */
27541abc59cSbostic 	y->nval = x->nval;
27641abc59cSbostic 	y->sval = x->sval ? tostring(x->sval) : NULL;
27741abc59cSbostic 	y->fval = x->fval;
27841abc59cSbostic 	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);	/* copy is not constant or field */
27941abc59cSbostic 							/* is DONTFREE right? */
28041abc59cSbostic 	return y;
28141abc59cSbostic }
28241abc59cSbostic 
arg(Node ** a,int n)28341abc59cSbostic Cell *arg(Node **a, int n)	/* nth argument of a function */
28441abc59cSbostic {
28541abc59cSbostic 
28641abc59cSbostic 	n = (int) a[0];	/* argument number, counting from 0 */
28741abc59cSbostic 	dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
28841abc59cSbostic 	if (n+1 > fp->nargs)
28941abc59cSbostic 		ERROR "argument #%d of function %s was not supplied",
29041abc59cSbostic 			n+1, fp->fcncell->nval FATAL;
29141abc59cSbostic 	return fp->args[n];
29241abc59cSbostic }
29341abc59cSbostic 
jump(Node ** a,int n)29441abc59cSbostic Cell *jump(Node **a, int n)	/* break, continue, next, continue, return */
29541abc59cSbostic {
29641abc59cSbostic 	register Cell *y;
29741abc59cSbostic 
29841abc59cSbostic 	switch (n) {
29941abc59cSbostic 	case EXIT:
30041abc59cSbostic 		if (a[0] != NULL) {
30141abc59cSbostic 			y = execute(a[0]);
30241abc59cSbostic 			errorflag = getfval(y);
30341abc59cSbostic 			tempfree(y);
30441abc59cSbostic 		}
30541abc59cSbostic 		longjmp(env, 1);
30641abc59cSbostic 	case RETURN:
30741abc59cSbostic 		if (a[0] != NULL) {
30841abc59cSbostic 			y = execute(a[0]);
30941abc59cSbostic 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
31041abc59cSbostic 				setsval(fp->retval, getsval(y));
31141abc59cSbostic 				fp->retval->fval = getfval(y);
31241abc59cSbostic 				fp->retval->tval |= NUM;
31341abc59cSbostic 			}
31441abc59cSbostic 			else if (y->tval & STR)
31541abc59cSbostic 				setsval(fp->retval, getsval(y));
31641abc59cSbostic 			else if (y->tval & NUM)
31741abc59cSbostic 				setfval(fp->retval, getfval(y));
31841abc59cSbostic 			else		/* can't happen */
31941abc59cSbostic 				ERROR "bad type variable %d", y->tval FATAL;
32041abc59cSbostic 			tempfree(y);
32141abc59cSbostic 		}
32241abc59cSbostic 		return(jret);
32341abc59cSbostic 	case NEXT:
32441abc59cSbostic 		return(jnext);
32541abc59cSbostic 	case BREAK:
32641abc59cSbostic 		return(jbreak);
32741abc59cSbostic 	case CONTINUE:
32841abc59cSbostic 		return(jcont);
32941abc59cSbostic 	default:	/* can't happen */
33041abc59cSbostic 		ERROR "illegal jump type %d", n FATAL;
33141abc59cSbostic 	}
33241abc59cSbostic 	return 0;	/* not reached */
33341abc59cSbostic }
33441abc59cSbostic 
getline(Node ** a,int n)33541abc59cSbostic Cell *getline(Node **a, int n)	/* get next line from specific input */
33641abc59cSbostic {		/* a[0] is variable, a[1] is operator, a[2] is filename */
33741abc59cSbostic 	register Cell *r, *x;
33841abc59cSbostic 	uchar buf[RECSIZE];
33941abc59cSbostic 	FILE *fp;
34041abc59cSbostic 
34141abc59cSbostic 	fflush(stdout);	/* in case someone is waiting for a prompt */
34241abc59cSbostic 	r = gettemp();
34341abc59cSbostic 	if (a[1] != NULL) {		/* getline < file */
34441abc59cSbostic 		x = execute(a[2]);		/* filename */
34541abc59cSbostic 		if ((int) a[1] == '|')	/* input pipe */
34641abc59cSbostic 			a[1] = (Node *) LE;	/* arbitrary flag */
34741abc59cSbostic 		fp = openfile((int) a[1], getsval(x));
34841abc59cSbostic 		tempfree(x);
34941abc59cSbostic 		if (fp == NULL)
35041abc59cSbostic 			n = -1;
35141abc59cSbostic 		else
35241abc59cSbostic 			n = readrec(buf, sizeof(buf), fp);
35341abc59cSbostic 		if (n <= 0) {
35441abc59cSbostic 			;
35541abc59cSbostic 		} else if (a[0] != NULL) {	/* getline var <file */
35641abc59cSbostic 			setsval(execute(a[0]), buf);
35741abc59cSbostic 		} else {			/* getline <file */
35841abc59cSbostic 			if (!(recloc->tval & DONTFREE))
35941abc59cSbostic 				xfree(recloc->sval);
36041abc59cSbostic 			strcpy(record, buf);
36141abc59cSbostic 			recloc->sval = record;
36241abc59cSbostic 			recloc->tval = REC | STR | DONTFREE;
363*72bcf366Sbostic 			if (is_a_number(recloc->sval)) {
36441abc59cSbostic 				recloc->fval = atof(recloc->sval);
36541abc59cSbostic 				recloc->tval |= NUM;
36641abc59cSbostic 			}
36741abc59cSbostic 			donerec = 1; donefld = 0;
36841abc59cSbostic 		}
36941abc59cSbostic 	} else {			/* bare getline; use current input */
37041abc59cSbostic 		if (a[0] == NULL)	/* getline */
37141abc59cSbostic 			n = getrec(record);
37241abc59cSbostic 		else {			/* getline var */
37341abc59cSbostic 			n = getrec(buf);
37441abc59cSbostic 			setsval(execute(a[0]), buf);
37541abc59cSbostic 		}
37641abc59cSbostic 	}
37741abc59cSbostic 	setfval(r, (Awkfloat) n);
37841abc59cSbostic 	return r;
37941abc59cSbostic }
38041abc59cSbostic 
getnf(Node ** a,int n)38141abc59cSbostic Cell *getnf(Node **a, int n)	/* get NF */
38241abc59cSbostic {
38341abc59cSbostic 	if (donefld == 0)
38441abc59cSbostic 		fldbld();
38541abc59cSbostic 	return (Cell *) a[0];
38641abc59cSbostic }
38741abc59cSbostic 
array(Node ** a,int n)38841abc59cSbostic Cell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
38941abc59cSbostic {
39041abc59cSbostic 	register Cell *x, *y, *z;
39141abc59cSbostic 	register uchar *s;
39241abc59cSbostic 	register Node *np;
39341abc59cSbostic 	uchar buf[RECSIZE];
39441abc59cSbostic 
39541abc59cSbostic 	x = execute(a[0]);	/* Cell* for symbol table */
39641abc59cSbostic 	buf[0] = 0;
39741abc59cSbostic 	for (np = a[1]; np; np = np->nnext) {
39841abc59cSbostic 		y = execute(np);	/* subscript */
39941abc59cSbostic 		s = getsval(y);
40041abc59cSbostic 		strcat(buf, s);
40141abc59cSbostic 		if (np->nnext)
40241abc59cSbostic 			strcat(buf, *SUBSEP);
40341abc59cSbostic 		tempfree(y);
40441abc59cSbostic 	}
40541abc59cSbostic 	if (!isarr(x)) {
40641abc59cSbostic 		dprintf( ("making %s into an array\n", x->nval) );
40741abc59cSbostic 		if (freeable(x))
40841abc59cSbostic 			xfree(x->sval);
40941abc59cSbostic 		x->tval &= ~(STR|NUM|DONTFREE);
41041abc59cSbostic 		x->tval |= ARR;
41141abc59cSbostic 		x->sval = (uchar *) makesymtab(NSYMTAB);
41241abc59cSbostic 	}
41341abc59cSbostic 	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
41441abc59cSbostic 	z->ctype = OCELL;
41541abc59cSbostic 	z->csub = CVAR;
41641abc59cSbostic 	tempfree(x);
41741abc59cSbostic 	return(z);
41841abc59cSbostic }
41941abc59cSbostic 
adelete(Node ** a,int n)42041abc59cSbostic Cell *adelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
42141abc59cSbostic {
42241abc59cSbostic 	Cell *x, *y;
42341abc59cSbostic 	Node *np;
42441abc59cSbostic 	uchar buf[RECSIZE], *s;
42541abc59cSbostic 
42641abc59cSbostic 	x = execute(a[0]);	/* Cell* for symbol table */
42741abc59cSbostic 	if (!isarr(x))
42841abc59cSbostic 		return true;
42941abc59cSbostic 	buf[0] = 0;
43041abc59cSbostic 	for (np = a[1]; np; np = np->nnext) {
43141abc59cSbostic 		y = execute(np);	/* subscript */
43241abc59cSbostic 		s = getsval(y);
43341abc59cSbostic 		strcat(buf, s);
43441abc59cSbostic 		if (np->nnext)
43541abc59cSbostic 			strcat(buf, *SUBSEP);
43641abc59cSbostic 		tempfree(y);
43741abc59cSbostic 	}
43841abc59cSbostic 	freeelem(x, buf);
43941abc59cSbostic 	tempfree(x);
44041abc59cSbostic 	return true;
44141abc59cSbostic }
44241abc59cSbostic 
intest(Node ** a,int n)44341abc59cSbostic Cell *intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
44441abc59cSbostic {
44541abc59cSbostic 	register Cell *x, *ap, *k;
44641abc59cSbostic 	Node *p;
44741abc59cSbostic 	char buf[RECSIZE];
44841abc59cSbostic 	uchar *s;
44941abc59cSbostic 
45041abc59cSbostic 	ap = execute(a[1]);	/* array name */
45141abc59cSbostic 	if (!isarr(ap)) {
45241abc59cSbostic 		dprintf( ("making %s into an array\n", ap->nval) );
45341abc59cSbostic 		if (freeable(ap))
45441abc59cSbostic 			xfree(ap->sval);
45541abc59cSbostic 		ap->tval &= ~(STR|NUM|DONTFREE);
45641abc59cSbostic 		ap->tval |= ARR;
45741abc59cSbostic 		ap->sval = (uchar *) makesymtab(NSYMTAB);
45841abc59cSbostic 	}
45941abc59cSbostic 	buf[0] = 0;
46041abc59cSbostic 	for (p = a[0]; p; p = p->nnext) {
46141abc59cSbostic 		x = execute(p);	/* expr */
46241abc59cSbostic 		s = getsval(x);
46341abc59cSbostic 		strcat(buf, s);
46441abc59cSbostic 		tempfree(x);
46541abc59cSbostic 		if (p->nnext)
46641abc59cSbostic 			strcat(buf, *SUBSEP);
46741abc59cSbostic 	}
46841abc59cSbostic 	k = lookup(buf, (Array *) ap->sval);
46941abc59cSbostic 	tempfree(ap);
47041abc59cSbostic 	if (k == NULL)
47141abc59cSbostic 		return(false);
47241abc59cSbostic 	else
47341abc59cSbostic 		return(true);
47441abc59cSbostic }
47541abc59cSbostic 
47641abc59cSbostic 
matchop(Node ** a,int n)47741abc59cSbostic Cell *matchop(Node **a, int n)	/* ~ and match() */
47841abc59cSbostic {
47941abc59cSbostic 	register Cell *x, *y;
48041abc59cSbostic 	register uchar *s, *t;
48141abc59cSbostic 	register int i;
48241abc59cSbostic 	fa *pfa;
48341abc59cSbostic 	int (*mf)(fa *, uchar *) = match, mode = 0;
48441abc59cSbostic 
48541abc59cSbostic 	if (n == MATCHFCN) {
48641abc59cSbostic 		mf = pmatch;
48741abc59cSbostic 		mode = 1;
48841abc59cSbostic 	}
48941abc59cSbostic 	x = execute(a[1]);	/* a[1] = target text */
49041abc59cSbostic 	s = getsval(x);
49141abc59cSbostic 	if (a[0] == 0)		/* a[1] == 0: already-compiled reg expr */
49241abc59cSbostic 		i = (*mf)((fa *) a[2], s);
49341abc59cSbostic 	else {
49441abc59cSbostic 		y = execute(a[2]);	/* a[2] = regular expr */
49541abc59cSbostic 		t = getsval(y);
49641abc59cSbostic 		pfa = makedfa(t, mode);
49741abc59cSbostic 		i = (*mf)(pfa, s);
49841abc59cSbostic 		tempfree(y);
49941abc59cSbostic 	}
50041abc59cSbostic 	tempfree(x);
50141abc59cSbostic 	if (n == MATCHFCN) {
50241abc59cSbostic 		int start = patbeg - s + 1;
50341abc59cSbostic 		if (patlen < 0)
50441abc59cSbostic 			start = 0;
50541abc59cSbostic 		setfval(rstartloc, (Awkfloat) start);
50641abc59cSbostic 		setfval(rlengthloc, (Awkfloat) patlen);
50741abc59cSbostic 		x = gettemp();
50841abc59cSbostic 		x->tval = NUM;
50941abc59cSbostic 		x->fval = start;
51041abc59cSbostic 		return x;
51141abc59cSbostic 	} else if (n == MATCH && i == 1 || n == NOTMATCH && i == 0)
51241abc59cSbostic 		return(true);
51341abc59cSbostic 	else
51441abc59cSbostic 		return(false);
51541abc59cSbostic }
51641abc59cSbostic 
51741abc59cSbostic 
boolop(Node ** a,int n)51841abc59cSbostic Cell *boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
51941abc59cSbostic {
52041abc59cSbostic 	register Cell *x, *y;
52141abc59cSbostic 	register int i;
52241abc59cSbostic 
52341abc59cSbostic 	x = execute(a[0]);
52441abc59cSbostic 	i = istrue(x);
52541abc59cSbostic 	tempfree(x);
52641abc59cSbostic 	switch (n) {
52741abc59cSbostic 	case BOR:
52841abc59cSbostic 		if (i) return(true);
52941abc59cSbostic 		y = execute(a[1]);
53041abc59cSbostic 		i = istrue(y);
53141abc59cSbostic 		tempfree(y);
53241abc59cSbostic 		if (i) return(true);
53341abc59cSbostic 		else return(false);
53441abc59cSbostic 	case AND:
53541abc59cSbostic 		if ( !i ) return(false);
53641abc59cSbostic 		y = execute(a[1]);
53741abc59cSbostic 		i = istrue(y);
53841abc59cSbostic 		tempfree(y);
53941abc59cSbostic 		if (i) return(true);
54041abc59cSbostic 		else return(false);
54141abc59cSbostic 	case NOT:
54241abc59cSbostic 		if (i) return(false);
54341abc59cSbostic 		else return(true);
54441abc59cSbostic 	default:	/* can't happen */
54541abc59cSbostic 		ERROR "unknown boolean operator %d", n FATAL;
54641abc59cSbostic 	}
54741abc59cSbostic 	return 0;	/*NOTREACHED*/
54841abc59cSbostic }
54941abc59cSbostic 
relop(Node ** a,int n)55041abc59cSbostic Cell *relop(Node **a, int n)	/* a[0 < a[1], etc. */
55141abc59cSbostic {
55241abc59cSbostic 	register int i;
55341abc59cSbostic 	register Cell *x, *y;
55441abc59cSbostic 	Awkfloat j;
55541abc59cSbostic 
55641abc59cSbostic 	x = execute(a[0]);
55741abc59cSbostic 	y = execute(a[1]);
55841abc59cSbostic 	if (x->tval&NUM && y->tval&NUM) {
55941abc59cSbostic 		j = x->fval - y->fval;
56041abc59cSbostic 		i = j<0? -1: (j>0? 1: 0);
56141abc59cSbostic 	} else {
56241abc59cSbostic 		i = strcmp(getsval(x), getsval(y));
56341abc59cSbostic 	}
56441abc59cSbostic 	tempfree(x);
56541abc59cSbostic 	tempfree(y);
56641abc59cSbostic 	switch (n) {
56741abc59cSbostic 	case LT:	if (i<0) return(true);
56841abc59cSbostic 			else return(false);
56941abc59cSbostic 	case LE:	if (i<=0) return(true);
57041abc59cSbostic 			else return(false);
57141abc59cSbostic 	case NE:	if (i!=0) return(true);
57241abc59cSbostic 			else return(false);
57341abc59cSbostic 	case EQ:	if (i == 0) return(true);
57441abc59cSbostic 			else return(false);
57541abc59cSbostic 	case GE:	if (i>=0) return(true);
57641abc59cSbostic 			else return(false);
57741abc59cSbostic 	case GT:	if (i>0) return(true);
57841abc59cSbostic 			else return(false);
57941abc59cSbostic 	default:	/* can't happen */
58041abc59cSbostic 		ERROR "unknown relational operator %d", n FATAL;
58141abc59cSbostic 	}
58241abc59cSbostic 	return 0;	/*NOTREACHED*/
58341abc59cSbostic }
58441abc59cSbostic 
tfree(Cell * a)58541abc59cSbostic void tfree(Cell *a)	/* free a tempcell */
58641abc59cSbostic {
58741abc59cSbostic 	if (freeable(a))
58841abc59cSbostic 		xfree(a->sval);
58941abc59cSbostic 	if (a == tmps)
59041abc59cSbostic 		ERROR "tempcell list is curdled" FATAL;
59141abc59cSbostic 	a->cnext = tmps;
59241abc59cSbostic 	tmps = a;
59341abc59cSbostic }
59441abc59cSbostic 
gettemp(void)59541abc59cSbostic Cell *gettemp(void)	/* get a tempcell */
59641abc59cSbostic {	int i;
59741abc59cSbostic 	register Cell *x;
59841abc59cSbostic 
59941abc59cSbostic 	if (!tmps) {
60041abc59cSbostic 		tmps = (Cell *) calloc(100, sizeof(Cell));
60141abc59cSbostic 		if (!tmps)
60241abc59cSbostic 			ERROR "out of space for temporaries" FATAL;
60341abc59cSbostic 		for(i = 1; i < 100; i++)
60441abc59cSbostic 			tmps[i-1].cnext = &tmps[i];
60541abc59cSbostic 		tmps[i-1].cnext = 0;
60641abc59cSbostic 	}
60741abc59cSbostic 	x = tmps;
60841abc59cSbostic 	tmps = x->cnext;
60941abc59cSbostic 	*x = tempcell;
61041abc59cSbostic 	return(x);
61141abc59cSbostic }
61241abc59cSbostic 
indirect(Node ** a,int n)61341abc59cSbostic Cell *indirect(Node **a, int n)	/* $( a[0] ) */
61441abc59cSbostic {
61541abc59cSbostic 	register Cell *x;
61641abc59cSbostic 	register int m;
61741abc59cSbostic 	register uchar *s;
61841abc59cSbostic 
61941abc59cSbostic 	x = execute(a[0]);
62041abc59cSbostic 	m = getfval(x);
621*72bcf366Sbostic 	if (m == 0 && !is_a_number(s = getsval(x)))	/* suspicion! */
62241abc59cSbostic 		ERROR "illegal field $(%s), name \"%s\"", s, x->nval FATAL;
62341abc59cSbostic   /* can x->nval ever be null??? */
62441abc59cSbostic 		/* ERROR "illegal field $(%s)", s FATAL; */
62541abc59cSbostic 	tempfree(x);
62641abc59cSbostic 	x = fieldadr(m);
62741abc59cSbostic 	x->ctype = OCELL;
62841abc59cSbostic 	x->csub = CFLD;
62941abc59cSbostic 	return(x);
63041abc59cSbostic }
63141abc59cSbostic 
substr(Node ** a,int nnn)63241abc59cSbostic Cell *substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
63341abc59cSbostic {
63441abc59cSbostic 	register int k, m, n;
63541abc59cSbostic 	register uchar *s;
63641abc59cSbostic 	int temp;
63741abc59cSbostic 	register Cell *x, *y, *z;
63841abc59cSbostic 
63941abc59cSbostic 	x = execute(a[0]);
64041abc59cSbostic 	y = execute(a[1]);
64141abc59cSbostic 	if (a[2] != 0)
64241abc59cSbostic 		z = execute(a[2]);
64341abc59cSbostic 	s = getsval(x);
64441abc59cSbostic 	k = strlen(s) + 1;
64541abc59cSbostic 	if (k <= 1) {
64641abc59cSbostic 		tempfree(x);
64741abc59cSbostic 		tempfree(y);
64841abc59cSbostic 		if (a[2] != 0)
64941abc59cSbostic 			tempfree(z);
65041abc59cSbostic 		x = gettemp();
65141abc59cSbostic 		setsval(x, "");
65241abc59cSbostic 		return(x);
65341abc59cSbostic 	}
65441abc59cSbostic 	m = getfval(y);
65541abc59cSbostic 	if (m <= 0)
65641abc59cSbostic 		m = 1;
65741abc59cSbostic 	else if (m > k)
65841abc59cSbostic 		m = k;
65941abc59cSbostic 	tempfree(y);
66041abc59cSbostic 	if (a[2] != 0) {
66141abc59cSbostic 		n = getfval(z);
66241abc59cSbostic 		tempfree(z);
66341abc59cSbostic 	} else
66441abc59cSbostic 		n = k - 1;
66541abc59cSbostic 	if (n < 0)
66641abc59cSbostic 		n = 0;
66741abc59cSbostic 	else if (n > k - m)
66841abc59cSbostic 		n = k - m;
66941abc59cSbostic 	dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
67041abc59cSbostic 	y = gettemp();
67141abc59cSbostic 	temp = s[n+m-1];	/* with thanks to John Linderman */
67241abc59cSbostic 	s[n+m-1] = '\0';
67341abc59cSbostic 	setsval(y, s + m - 1);
67441abc59cSbostic 	s[n+m-1] = temp;
67541abc59cSbostic 	tempfree(x);
67641abc59cSbostic 	return(y);
67741abc59cSbostic }
67841abc59cSbostic 
sindex(Node ** a,int nnn)67941abc59cSbostic Cell *sindex(Node **a, int nnn)		/* index(a[0], a[1]) */
68041abc59cSbostic {
68141abc59cSbostic 	register Cell *x, *y, *z;
68241abc59cSbostic 	register uchar *s1, *s2, *p1, *p2, *q;
68341abc59cSbostic 	Awkfloat v = 0.0;
68441abc59cSbostic 
68541abc59cSbostic 	x = execute(a[0]);
68641abc59cSbostic 	s1 = getsval(x);
68741abc59cSbostic 	y = execute(a[1]);
68841abc59cSbostic 	s2 = getsval(y);
68941abc59cSbostic 
69041abc59cSbostic 	z = gettemp();
69141abc59cSbostic 	for (p1 = s1; *p1 != '\0'; p1++) {
69241abc59cSbostic 		for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
69341abc59cSbostic 			;
69441abc59cSbostic 		if (*p2 == '\0') {
69541abc59cSbostic 			v = (Awkfloat) (p1 - s1 + 1);	/* origin 1 */
69641abc59cSbostic 			break;
69741abc59cSbostic 		}
69841abc59cSbostic 	}
69941abc59cSbostic 	tempfree(x);
70041abc59cSbostic 	tempfree(y);
70141abc59cSbostic 	setfval(z, v);
70241abc59cSbostic 	return(z);
70341abc59cSbostic }
70441abc59cSbostic 
format(uchar * buf,int bufsize,uchar * s,Node * a)70541abc59cSbostic format(uchar *buf, int bufsize, uchar *s, Node *a)	/* printf-like conversions */
70641abc59cSbostic {
70741abc59cSbostic 	uchar fmt[RECSIZE];
70841abc59cSbostic 	register uchar *p, *t, *os;
70941abc59cSbostic 	register Cell *x;
71041abc59cSbostic 	int flag = 0, n;
71141abc59cSbostic 
71241abc59cSbostic 	os = s;
71341abc59cSbostic 	p = buf;
71441abc59cSbostic 	while (*s) {
71541abc59cSbostic 		if (p - buf >= bufsize)
71641abc59cSbostic 			return -1;
71741abc59cSbostic 		if (*s != '%') {
71841abc59cSbostic 			*p++ = *s++;
71941abc59cSbostic 			continue;
72041abc59cSbostic 		}
72141abc59cSbostic 		if (*(s+1) == '%') {
72241abc59cSbostic 			*p++ = '%';
72341abc59cSbostic 			s += 2;
72441abc59cSbostic 			continue;
72541abc59cSbostic 		}
72641abc59cSbostic 		for (t=fmt; (*t++ = *s) != '\0'; s++) {
72741abc59cSbostic 			if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
72841abc59cSbostic 				break;	/* the ansi panoply */
72941abc59cSbostic 			if (*s == '*') {
73041abc59cSbostic 				x = execute(a);
73141abc59cSbostic 				a = a->nnext;
73241abc59cSbostic 				sprintf((char *)t-1, "%d", (int) getfval(x));
73341abc59cSbostic 				t = fmt + strlen(fmt);
73441abc59cSbostic 				tempfree(x);
73541abc59cSbostic 			}
73641abc59cSbostic 		}
73741abc59cSbostic 		*t = '\0';
73841abc59cSbostic 		if (t >= fmt + sizeof(fmt))
73941abc59cSbostic 			ERROR "format item %.30s... too long", os FATAL;
74041abc59cSbostic 		switch (*s) {
74141abc59cSbostic 		case 'f': case 'e': case 'g': case 'E': case 'G':
74241abc59cSbostic 			flag = 1;
74341abc59cSbostic 			break;
74441abc59cSbostic 		case 'd': case 'i':
74541abc59cSbostic 			flag = 2;
74641abc59cSbostic 			if(*(s-1) == 'l') break;
74741abc59cSbostic 			*(t-1) = 'l';
74841abc59cSbostic 			*t = 'd';
74941abc59cSbostic 			*++t = '\0';
75041abc59cSbostic 			break;
75141abc59cSbostic 		case 'o': case 'x': case 'X': case 'u':
75241abc59cSbostic 			flag = *(s-1) == 'l' ? 2 : 3;
75341abc59cSbostic 			break;
75441abc59cSbostic 		case 's':
75541abc59cSbostic 			flag = 4;
75641abc59cSbostic 			break;
75741abc59cSbostic 		case 'c':
75841abc59cSbostic 			flag = 5;
75941abc59cSbostic 			break;
76041abc59cSbostic 		default:
76141abc59cSbostic 			ERROR "weird printf conversion %s", fmt WARNING;
76241abc59cSbostic 			flag = 0;
76341abc59cSbostic 			break;
76441abc59cSbostic 		}
76541abc59cSbostic 		if (a == NULL)
76641abc59cSbostic 			ERROR "not enough args in printf(%s)", os FATAL;
76741abc59cSbostic 		x = execute(a);
76841abc59cSbostic 		a = a->nnext;
76941abc59cSbostic 		switch (flag) {
77041abc59cSbostic 		case 0:	sprintf((char *)p, "%s", fmt);	/* unknown, so dump it too */
77141abc59cSbostic 			p += strlen(p);
77241abc59cSbostic 			sprintf((char *)p, "%s", getsval(x));
77341abc59cSbostic 			break;
77441abc59cSbostic 		case 1:	sprintf((char *)p, (char *)fmt, getfval(x)); break;
77541abc59cSbostic 		case 2:	sprintf((char *)p, (char *)fmt, (long) getfval(x)); break;
77641abc59cSbostic 		case 3:	sprintf((char *)p, (char *)fmt, (int) getfval(x)); break;
77741abc59cSbostic 		case 4:
77841abc59cSbostic 			t = getsval(x);
77941abc59cSbostic 			n = strlen(t);
78041abc59cSbostic 			if (n >= bufsize)
78141abc59cSbostic 				ERROR "huge string (%d chars) in printf %.30s...",
78241abc59cSbostic 					n, t FATAL;
78341abc59cSbostic 			sprintf((char *)p, (char *)fmt, t);
78441abc59cSbostic 			break;
78541abc59cSbostic 		case 5:
78641abc59cSbostic 			isnum(x) ? sprintf((char *)p, (char *)fmt, (int) getfval(x))
78741abc59cSbostic 				 : sprintf((char *)p, (char *)fmt, getsval(x)[0]);
78841abc59cSbostic 			break;
78941abc59cSbostic 		}
79041abc59cSbostic 		tempfree(x);
79141abc59cSbostic 		p += strlen(p);
79241abc59cSbostic 		s++;
79341abc59cSbostic 	}
79441abc59cSbostic 	*p = '\0';
79541abc59cSbostic 	for ( ; a; a = a->nnext)		/* evaluate any remaining args */
79641abc59cSbostic 		execute(a);
79741abc59cSbostic 	return 0;
79841abc59cSbostic }
79941abc59cSbostic 
asprintf(Node ** a,int n)80041abc59cSbostic Cell *asprintf(Node **a, int n)		/* sprintf(a[0]) */
80141abc59cSbostic {
80241abc59cSbostic 	register Cell *x;
80341abc59cSbostic 	register Node *y;
80441abc59cSbostic 	uchar buf[3*RECSIZE];
80541abc59cSbostic 
80641abc59cSbostic 	y = a[0]->nnext;
80741abc59cSbostic 	x = execute(a[0]);
80841abc59cSbostic 	if (format(buf, sizeof buf, getsval(x), y) == -1)
80941abc59cSbostic 		ERROR "sprintf string %.30s... too long", buf FATAL;
81041abc59cSbostic 	tempfree(x);
81141abc59cSbostic 	x = gettemp();
81241abc59cSbostic 	x->sval = tostring(buf);
81341abc59cSbostic 	x->tval = STR;
81441abc59cSbostic 	return(x);
81541abc59cSbostic }
81641abc59cSbostic 
aprintf(Node ** a,int n)81741abc59cSbostic Cell *aprintf(Node **a, int n)		/* printf */
81841abc59cSbostic {	/* a[0] is list of args, starting with format string */
81941abc59cSbostic 	/* a[1] is redirection operator, a[2] is redirection file */
82041abc59cSbostic 	FILE *fp;
82141abc59cSbostic 	register Cell *x;
82241abc59cSbostic 	register Node *y;
82341abc59cSbostic 	uchar buf[3*RECSIZE];
82441abc59cSbostic 
82541abc59cSbostic 	y = a[0]->nnext;
82641abc59cSbostic 	x = execute(a[0]);
82741abc59cSbostic 	if (format(buf, sizeof buf, getsval(x), y) == -1)
82841abc59cSbostic 		ERROR "printf string %.30s... too long", buf FATAL;
82941abc59cSbostic 	tempfree(x);
83041abc59cSbostic 	if (a[1] == NULL) {
83141abc59cSbostic 		fputs((char *)buf, stdout);
83241abc59cSbostic 		if (ferror(stdout))
83341abc59cSbostic 			ERROR "write error on stdout" FATAL;
83441abc59cSbostic 	} else {
83541abc59cSbostic 		fp = redirect((int)a[1], a[2]);
83641abc59cSbostic 		fputs((char *)buf, fp);
83741abc59cSbostic 		fflush(fp);
83841abc59cSbostic 		if (ferror(fp))
83941abc59cSbostic 			ERROR "write error on %s", filename(fp) FATAL;
84041abc59cSbostic 	}
84141abc59cSbostic 	return(true);
84241abc59cSbostic }
84341abc59cSbostic 
arith(Node ** a,int n)84441abc59cSbostic Cell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
84541abc59cSbostic {
84641abc59cSbostic 	Awkfloat i, j;
84741abc59cSbostic 	double v;
84841abc59cSbostic 	register Cell *x, *y, *z;
84941abc59cSbostic 
85041abc59cSbostic 	x = execute(a[0]);
85141abc59cSbostic 	i = getfval(x);
85241abc59cSbostic 	tempfree(x);
85341abc59cSbostic 	if (n != UMINUS) {
85441abc59cSbostic 		y = execute(a[1]);
85541abc59cSbostic 		j = getfval(y);
85641abc59cSbostic 		tempfree(y);
85741abc59cSbostic 	}
85841abc59cSbostic 	z = gettemp();
85941abc59cSbostic 	switch (n) {
86041abc59cSbostic 	case ADD:
86141abc59cSbostic 		i += j;
86241abc59cSbostic 		break;
86341abc59cSbostic 	case MINUS:
86441abc59cSbostic 		i -= j;
86541abc59cSbostic 		break;
86641abc59cSbostic 	case MULT:
86741abc59cSbostic 		i *= j;
86841abc59cSbostic 		break;
86941abc59cSbostic 	case DIVIDE:
87041abc59cSbostic 		if (j == 0)
87141abc59cSbostic 			ERROR "division by zero" FATAL;
87241abc59cSbostic 		i /= j;
87341abc59cSbostic 		break;
87441abc59cSbostic 	case MOD:
87541abc59cSbostic 		if (j == 0)
87641abc59cSbostic 			ERROR "division by zero in mod" FATAL;
87741abc59cSbostic 		modf(i/j, &v);
87841abc59cSbostic 		i = i - j * v;
87941abc59cSbostic 		break;
88041abc59cSbostic 	case UMINUS:
88141abc59cSbostic 		i = -i;
88241abc59cSbostic 		break;
88341abc59cSbostic 	case POWER:
88441abc59cSbostic 		if (j >= 0 && modf(j, &v) == 0.0)	/* pos integer exponent */
88541abc59cSbostic 			i = ipow(i, (int) j);
88641abc59cSbostic 		else
88741abc59cSbostic 			i = errcheck(pow(i, j), "pow");
88841abc59cSbostic 		break;
88941abc59cSbostic 	default:	/* can't happen */
89041abc59cSbostic 		ERROR "illegal arithmetic operator %d", n FATAL;
89141abc59cSbostic 	}
89241abc59cSbostic 	setfval(z, i);
89341abc59cSbostic 	return(z);
89441abc59cSbostic }
89541abc59cSbostic 
ipow(double x,int n)89641abc59cSbostic double ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
89741abc59cSbostic {
89841abc59cSbostic 	double v;
89941abc59cSbostic 
90041abc59cSbostic 	if (n <= 0)
90141abc59cSbostic 		return 1;
90241abc59cSbostic 	v = ipow(x, n/2);
90341abc59cSbostic 	if (n % 2 == 0)
90441abc59cSbostic 		return v * v;
90541abc59cSbostic 	else
90641abc59cSbostic 		return x * v * v;
90741abc59cSbostic }
90841abc59cSbostic 
incrdecr(Node ** a,int n)90941abc59cSbostic Cell *incrdecr(Node **a, int n)		/* a[0]++, etc. */
91041abc59cSbostic {
91141abc59cSbostic 	register Cell *x, *z;
91241abc59cSbostic 	register int k;
91341abc59cSbostic 	Awkfloat xf;
91441abc59cSbostic 
91541abc59cSbostic 	x = execute(a[0]);
91641abc59cSbostic 	xf = getfval(x);
91741abc59cSbostic 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
91841abc59cSbostic 	if (n == PREINCR || n == PREDECR) {
91941abc59cSbostic 		setfval(x, xf + k);
92041abc59cSbostic 		return(x);
92141abc59cSbostic 	}
92241abc59cSbostic 	z = gettemp();
92341abc59cSbostic 	setfval(z, xf);
92441abc59cSbostic 	setfval(x, xf + k);
92541abc59cSbostic 	tempfree(x);
92641abc59cSbostic 	return(z);
92741abc59cSbostic }
92841abc59cSbostic 
assign(Node ** a,int n)92941abc59cSbostic Cell *assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
93041abc59cSbostic {		/* this is subtle; don't muck with it. */
93141abc59cSbostic 	register Cell *x, *y;
93241abc59cSbostic 	Awkfloat xf, yf;
93341abc59cSbostic 	double v;
93441abc59cSbostic 
93541abc59cSbostic 	y = execute(a[1]);
93641abc59cSbostic 	x = execute(a[0]);
93741abc59cSbostic 	if (n == ASSIGN) {	/* ordinary assignment */
93841abc59cSbostic 		if (x == y && !(x->tval & (FLD|REC)))	/* self-assignment: */
93941abc59cSbostic 			;		/* leave alone unless it's a field */
94041abc59cSbostic 		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
94141abc59cSbostic 			setsval(x, getsval(y));
94241abc59cSbostic 			x->fval = getfval(y);
94341abc59cSbostic 			x->tval |= NUM;
94441abc59cSbostic 		}
94541abc59cSbostic 		else if (y->tval & STR)
94641abc59cSbostic 			setsval(x, getsval(y));
94741abc59cSbostic 		else if (y->tval & NUM)
94841abc59cSbostic 			setfval(x, getfval(y));
94941abc59cSbostic 		else
95041abc59cSbostic 			funnyvar(y, "read value of");
95141abc59cSbostic 		tempfree(y);
95241abc59cSbostic 		return(x);
95341abc59cSbostic 	}
95441abc59cSbostic 	xf = getfval(x);
95541abc59cSbostic 	yf = getfval(y);
95641abc59cSbostic 	switch (n) {
95741abc59cSbostic 	case ADDEQ:
95841abc59cSbostic 		xf += yf;
95941abc59cSbostic 		break;
96041abc59cSbostic 	case SUBEQ:
96141abc59cSbostic 		xf -= yf;
96241abc59cSbostic 		break;
96341abc59cSbostic 	case MULTEQ:
96441abc59cSbostic 		xf *= yf;
96541abc59cSbostic 		break;
96641abc59cSbostic 	case DIVEQ:
96741abc59cSbostic 		if (yf == 0)
96841abc59cSbostic 			ERROR "division by zero in /=" FATAL;
96941abc59cSbostic 		xf /= yf;
97041abc59cSbostic 		break;
97141abc59cSbostic 	case MODEQ:
97241abc59cSbostic 		if (yf == 0)
97341abc59cSbostic 			ERROR "division by zero in %%=" FATAL;
97441abc59cSbostic 		modf(xf/yf, &v);
97541abc59cSbostic 		xf = xf - yf * v;
97641abc59cSbostic 		break;
97741abc59cSbostic 	case POWEQ:
97841abc59cSbostic 		if (yf >= 0 && modf(yf, &v) == 0.0)	/* pos integer exponent */
97941abc59cSbostic 			xf = ipow(xf, (int) yf);
98041abc59cSbostic 		else
98141abc59cSbostic 			xf = errcheck(pow(xf, yf), "pow");
98241abc59cSbostic 		break;
98341abc59cSbostic 	default:
98441abc59cSbostic 		ERROR "illegal assignment operator %d", n FATAL;
98541abc59cSbostic 		break;
98641abc59cSbostic 	}
98741abc59cSbostic 	tempfree(y);
98841abc59cSbostic 	setfval(x, xf);
98941abc59cSbostic 	return(x);
99041abc59cSbostic }
99141abc59cSbostic 
cat(Node ** a,int q)99241abc59cSbostic Cell *cat(Node **a, int q)	/* a[0] cat a[1] */
99341abc59cSbostic {
99441abc59cSbostic 	register Cell *x, *y, *z;
99541abc59cSbostic 	register int n1, n2;
99641abc59cSbostic 	register uchar *s;
99741abc59cSbostic 
99841abc59cSbostic 	x = execute(a[0]);
99941abc59cSbostic 	y = execute(a[1]);
100041abc59cSbostic 	getsval(x);
100141abc59cSbostic 	getsval(y);
100241abc59cSbostic 	n1 = strlen(x->sval);
100341abc59cSbostic 	n2 = strlen(y->sval);
100441abc59cSbostic 	s = (uchar *) malloc(n1 + n2 + 1);
100541abc59cSbostic 	if (s == NULL)
100641abc59cSbostic 		ERROR "out of space concatenating %.15s... and %.15s...",
100741abc59cSbostic 			x->sval, y->sval FATAL;
100841abc59cSbostic 	strcpy(s, x->sval);
100941abc59cSbostic 	strcpy(s+n1, y->sval);
101041abc59cSbostic 	tempfree(y);
101141abc59cSbostic 	z = gettemp();
101241abc59cSbostic 	z->sval = s;
101341abc59cSbostic 	z->tval = STR;
101441abc59cSbostic 	tempfree(x);
101541abc59cSbostic 	return(z);
101641abc59cSbostic }
101741abc59cSbostic 
pastat(Node ** a,int n)101841abc59cSbostic Cell *pastat(Node **a, int n)	/* a[0] { a[1] } */
101941abc59cSbostic {
102041abc59cSbostic 	register Cell *x;
102141abc59cSbostic 
102241abc59cSbostic 	if (a[0] == 0)
102341abc59cSbostic 		x = execute(a[1]);
102441abc59cSbostic 	else {
102541abc59cSbostic 		x = execute(a[0]);
102641abc59cSbostic 		if (istrue(x)) {
102741abc59cSbostic 			tempfree(x);
102841abc59cSbostic 			x = execute(a[1]);
102941abc59cSbostic 		}
103041abc59cSbostic 	}
103141abc59cSbostic 	return x;
103241abc59cSbostic }
103341abc59cSbostic 
dopa2(Node ** a,int n)103441abc59cSbostic Cell *dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
103541abc59cSbostic {
103641abc59cSbostic 	register Cell *x;
103741abc59cSbostic 	register int pair;
103841abc59cSbostic 
103941abc59cSbostic 	pair = (int) a[3];
104041abc59cSbostic 	if (pairstack[pair] == 0) {
104141abc59cSbostic 		x = execute(a[0]);
104241abc59cSbostic 		if (istrue(x))
104341abc59cSbostic 			pairstack[pair] = 1;
104441abc59cSbostic 		tempfree(x);
104541abc59cSbostic 	}
104641abc59cSbostic 	if (pairstack[pair] == 1) {
104741abc59cSbostic 		x = execute(a[1]);
104841abc59cSbostic 		if (istrue(x))
104941abc59cSbostic 			pairstack[pair] = 0;
105041abc59cSbostic 		tempfree(x);
105141abc59cSbostic 		x = execute(a[2]);
105241abc59cSbostic 		return(x);
105341abc59cSbostic 	}
105441abc59cSbostic 	return(false);
105541abc59cSbostic }
105641abc59cSbostic 
split(Node ** a,int nnn)105741abc59cSbostic Cell *split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
105841abc59cSbostic {
105941abc59cSbostic 	Cell *x, *y, *ap;
106041abc59cSbostic 	register uchar *s;
106141abc59cSbostic 	register int sep;
106241abc59cSbostic 	uchar *t, temp, num[10], *fs;
106341abc59cSbostic 	int n, tempstat;
106441abc59cSbostic 
106541abc59cSbostic 	y = execute(a[0]);	/* source string */
106641abc59cSbostic 	s = getsval(y);
106741abc59cSbostic 	if (a[2] == 0)		/* fs string */
106841abc59cSbostic 		fs = *FS;
106941abc59cSbostic 	else if ((int) a[3] == STRING) {	/* split(str,arr,"string") */
107041abc59cSbostic 		x = execute(a[2]);
107141abc59cSbostic 		fs = getsval(x);
107241abc59cSbostic 	} else if ((int) a[3] == REGEXPR)
107341abc59cSbostic 		fs = (uchar*) "(regexpr)";	/* split(str,arr,/regexpr/) */
107441abc59cSbostic 	else
107541abc59cSbostic 		ERROR "illegal type of split()" FATAL;
107641abc59cSbostic 	sep = *fs;
107741abc59cSbostic 	ap = execute(a[1]);	/* array name */
107841abc59cSbostic 	freesymtab(ap);
107941abc59cSbostic 	dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
108041abc59cSbostic 	ap->tval &= ~STR;
108141abc59cSbostic 	ap->tval |= ARR;
108241abc59cSbostic 	ap->sval = (uchar *) makesymtab(NSYMTAB);
108341abc59cSbostic 
108441abc59cSbostic 	n = 0;
108541abc59cSbostic 	if (*s != '\0' && strlen(fs) > 1 || (int) a[3] == REGEXPR) {	/* reg expr */
108641abc59cSbostic 		fa *pfa;
108741abc59cSbostic 		if ((int) a[3] == REGEXPR) {	/* it's ready already */
108841abc59cSbostic 			pfa = (fa *) a[2];
108941abc59cSbostic 		} else {
109041abc59cSbostic 			pfa = makedfa(fs, 1);
109141abc59cSbostic 		}
109241abc59cSbostic 		if (nematch(pfa,s)) {
109341abc59cSbostic 			tempstat = pfa->initstat;
109441abc59cSbostic 			pfa->initstat = 2;
109541abc59cSbostic 			do {
109641abc59cSbostic 				n++;
109741abc59cSbostic 				sprintf((char *)num, "%d", n);
109841abc59cSbostic 				temp = *patbeg;
109941abc59cSbostic 				*patbeg = '\0';
1100*72bcf366Sbostic 				if (is_a_number(s))
110141abc59cSbostic 					setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval);
110241abc59cSbostic 				else
110341abc59cSbostic 					setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
110441abc59cSbostic 				*patbeg = temp;
110541abc59cSbostic 				s = patbeg + patlen;
110641abc59cSbostic 				if (*(patbeg+patlen-1) == 0 || *s == 0) {
110741abc59cSbostic 					n++;
110841abc59cSbostic 					sprintf((char *)num, "%d", n);
110941abc59cSbostic 					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
111041abc59cSbostic 					pfa->initstat = tempstat;
111141abc59cSbostic 					goto spdone;
111241abc59cSbostic 				}
111341abc59cSbostic 			} while (nematch(pfa,s));
111441abc59cSbostic 		}
111541abc59cSbostic 		n++;
111641abc59cSbostic 		sprintf((char *)num, "%d", n);
1117*72bcf366Sbostic 		if (is_a_number(s))
111841abc59cSbostic 			setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval);
111941abc59cSbostic 		else
112041abc59cSbostic 			setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
112141abc59cSbostic   spdone:
112241abc59cSbostic 		pfa = NULL;
112341abc59cSbostic 	} else if (sep == ' ') {
112441abc59cSbostic 		for (n = 0; ; ) {
112541abc59cSbostic 			while (*s == ' ' || *s == '\t' || *s == '\n')
112641abc59cSbostic 				s++;
112741abc59cSbostic 			if (*s == 0)
112841abc59cSbostic 				break;
112941abc59cSbostic 			n++;
113041abc59cSbostic 			t = s;
113141abc59cSbostic 			do
113241abc59cSbostic 				s++;
113341abc59cSbostic 			while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
113441abc59cSbostic 			temp = *s;
113541abc59cSbostic 			*s = '\0';
113641abc59cSbostic 			sprintf((char *)num, "%d", n);
1137*72bcf366Sbostic 			if (is_a_number(t))
113841abc59cSbostic 				setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
113941abc59cSbostic 			else
114041abc59cSbostic 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
114141abc59cSbostic 			*s = temp;
114241abc59cSbostic 			if (*s != 0)
114341abc59cSbostic 				s++;
114441abc59cSbostic 		}
114541abc59cSbostic 	} else if (*s != 0) {
114641abc59cSbostic 		for (;;) {
114741abc59cSbostic 			n++;
114841abc59cSbostic 			t = s;
114941abc59cSbostic 			while (*s != sep && *s != '\n' && *s != '\0')
115041abc59cSbostic 				s++;
115141abc59cSbostic 			temp = *s;
115241abc59cSbostic 			*s = '\0';
115341abc59cSbostic 			sprintf((char *)num, "%d", n);
1154*72bcf366Sbostic 			if (is_a_number(t))
115541abc59cSbostic 				setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
115641abc59cSbostic 			else
115741abc59cSbostic 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
115841abc59cSbostic 			*s = temp;
115941abc59cSbostic 			if (*s++ == 0)
116041abc59cSbostic 				break;
116141abc59cSbostic 		}
116241abc59cSbostic 	}
116341abc59cSbostic 	tempfree(ap);
116441abc59cSbostic 	tempfree(y);
116541abc59cSbostic 	if (a[2] != 0 && (int) a[3] == STRING)
116641abc59cSbostic 		tempfree(x);
116741abc59cSbostic 	x = gettemp();
116841abc59cSbostic 	x->tval = NUM;
116941abc59cSbostic 	x->fval = n;
117041abc59cSbostic 	return(x);
117141abc59cSbostic }
117241abc59cSbostic 
condexpr(Node ** a,int n)117341abc59cSbostic Cell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
117441abc59cSbostic {
117541abc59cSbostic 	register Cell *x;
117641abc59cSbostic 
117741abc59cSbostic 	x = execute(a[0]);
117841abc59cSbostic 	if (istrue(x)) {
117941abc59cSbostic 		tempfree(x);
118041abc59cSbostic 		x = execute(a[1]);
118141abc59cSbostic 	} else {
118241abc59cSbostic 		tempfree(x);
118341abc59cSbostic 		x = execute(a[2]);
118441abc59cSbostic 	}
118541abc59cSbostic 	return(x);
118641abc59cSbostic }
118741abc59cSbostic 
ifstat(Node ** a,int n)118841abc59cSbostic Cell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
118941abc59cSbostic {
119041abc59cSbostic 	register Cell *x;
119141abc59cSbostic 
119241abc59cSbostic 	x = execute(a[0]);
119341abc59cSbostic 	if (istrue(x)) {
119441abc59cSbostic 		tempfree(x);
119541abc59cSbostic 		x = execute(a[1]);
119641abc59cSbostic 	} else if (a[2] != 0) {
119741abc59cSbostic 		tempfree(x);
119841abc59cSbostic 		x = execute(a[2]);
119941abc59cSbostic 	}
120041abc59cSbostic 	return(x);
120141abc59cSbostic }
120241abc59cSbostic 
whilestat(Node ** a,int n)120341abc59cSbostic Cell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
120441abc59cSbostic {
120541abc59cSbostic 	register Cell *x;
120641abc59cSbostic 
120741abc59cSbostic 	for (;;) {
120841abc59cSbostic 		x = execute(a[0]);
120941abc59cSbostic 		if (!istrue(x))
121041abc59cSbostic 			return(x);
121141abc59cSbostic 		tempfree(x);
121241abc59cSbostic 		x = execute(a[1]);
121341abc59cSbostic 		if (isbreak(x)) {
121441abc59cSbostic 			x = true;
121541abc59cSbostic 			return(x);
121641abc59cSbostic 		}
121741abc59cSbostic 		if (isnext(x) || isexit(x) || isret(x))
121841abc59cSbostic 			return(x);
121941abc59cSbostic 		tempfree(x);
122041abc59cSbostic 	}
122141abc59cSbostic }
122241abc59cSbostic 
dostat(Node ** a,int n)122341abc59cSbostic Cell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
122441abc59cSbostic {
122541abc59cSbostic 	register Cell *x;
122641abc59cSbostic 
122741abc59cSbostic 	for (;;) {
122841abc59cSbostic 		x = execute(a[0]);
122941abc59cSbostic 		if (isbreak(x))
123041abc59cSbostic 			return true;
123141abc59cSbostic 		if (isnext(x) || isexit(x) || isret(x))
123241abc59cSbostic 			return(x);
123341abc59cSbostic 		tempfree(x);
123441abc59cSbostic 		x = execute(a[1]);
123541abc59cSbostic 		if (!istrue(x))
123641abc59cSbostic 			return(x);
123741abc59cSbostic 		tempfree(x);
123841abc59cSbostic 	}
123941abc59cSbostic }
124041abc59cSbostic 
forstat(Node ** a,int n)124141abc59cSbostic Cell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
124241abc59cSbostic {
124341abc59cSbostic 	register Cell *x;
124441abc59cSbostic 
124541abc59cSbostic 	x = execute(a[0]);
124641abc59cSbostic 	tempfree(x);
124741abc59cSbostic 	for (;;) {
124841abc59cSbostic 		if (a[1]!=0) {
124941abc59cSbostic 			x = execute(a[1]);
125041abc59cSbostic 			if (!istrue(x)) return(x);
125141abc59cSbostic 			else tempfree(x);
125241abc59cSbostic 		}
125341abc59cSbostic 		x = execute(a[3]);
125441abc59cSbostic 		if (isbreak(x))		/* turn off break */
125541abc59cSbostic 			return true;
125641abc59cSbostic 		if (isnext(x) || isexit(x) || isret(x))
125741abc59cSbostic 			return(x);
125841abc59cSbostic 		tempfree(x);
125941abc59cSbostic 		x = execute(a[2]);
126041abc59cSbostic 		tempfree(x);
126141abc59cSbostic 	}
126241abc59cSbostic }
126341abc59cSbostic 
instat(Node ** a,int n)126441abc59cSbostic Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
126541abc59cSbostic {
126641abc59cSbostic 	register Cell *x, *vp, *arrayp, *cp, *ncp;
126741abc59cSbostic 	Array *tp;
126841abc59cSbostic 	int i;
126941abc59cSbostic 
127041abc59cSbostic 	vp = execute(a[0]);
127141abc59cSbostic 	arrayp = execute(a[1]);
127241abc59cSbostic 	if (!isarr(arrayp)) {
127341abc59cSbostic 		return true;
127441abc59cSbostic 	}
127541abc59cSbostic 	tp = (Array *) arrayp->sval;
127641abc59cSbostic 	tempfree(arrayp);
127741abc59cSbostic 	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
127841abc59cSbostic 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
127941abc59cSbostic 			setsval(vp, cp->nval);
128041abc59cSbostic 			ncp = cp->cnext;
128141abc59cSbostic 			x = execute(a[2]);
128241abc59cSbostic 			if (isbreak(x)) {
128341abc59cSbostic 				tempfree(vp);
128441abc59cSbostic 				return true;
128541abc59cSbostic 			}
128641abc59cSbostic 			if (isnext(x) || isexit(x) || isret(x)) {
128741abc59cSbostic 				tempfree(vp);
128841abc59cSbostic 				return(x);
128941abc59cSbostic 			}
129041abc59cSbostic 			tempfree(x);
129141abc59cSbostic 		}
129241abc59cSbostic 	}
129341abc59cSbostic 	return true;
129441abc59cSbostic }
129541abc59cSbostic 
129641abc59cSbostic /* if someone ever wants to run over the arrays in sorted order, */
129741abc59cSbostic /* here it is.  but it will likely run slower, not faster. */
129841abc59cSbostic 
129941abc59cSbostic /*
130041abc59cSbostic  *int qstrcmp(p, q)
130141abc59cSbostic  *	uchar **p, **q;
130241abc59cSbostic  *{
130341abc59cSbostic  *	return strcmp(*p, *q);
130441abc59cSbostic  *}
130541abc59cSbostic  */
130641abc59cSbostic 
130741abc59cSbostic /*Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
130841abc59cSbostic /*{
130941abc59cSbostic /*	register Cell *x, *vp, *arrayp, *cp, *ncp, *ret;
131041abc59cSbostic /*	Array *tp;
131141abc59cSbostic /*	int i, ne;
131241abc59cSbostic /*#define BIGENOUGH 1000
131341abc59cSbostic /*	uchar *elems[BIGENOUGH], **ep;
131441abc59cSbostic /*
131541abc59cSbostic /*	vp = execute(a[0]);
131641abc59cSbostic /*	arrayp = execute(a[1]);
131741abc59cSbostic /*	if (!isarr(arrayp))
131841abc59cSbostic /*		ERROR "%s is not an array", arrayp->nval FATAL;
131941abc59cSbostic /*	tp = (Array *) arrayp->sval;
132041abc59cSbostic /*	tempfree(arrayp);
132141abc59cSbostic /*	ep = elems;
132241abc59cSbostic /*	ret = true;
132341abc59cSbostic /*	if (tp->nelem >= BIGENOUGH)
132441abc59cSbostic /*		ep = (uchar **) malloc(tp->nelem * sizeof(char *));
132541abc59cSbostic /*
132641abc59cSbostic /*	for (i = ne = 0; i < tp->size; i++)
132741abc59cSbostic /*		for (cp = tp->tab[i]; cp != NULL; cp = cp->cnext)
132841abc59cSbostic /*			ep[ne++] = cp->nval;
132941abc59cSbostic /*	if (ne != tp->nelem)
133041abc59cSbostic /*		ERROR "can't happen: lost elems %d vs. %d", ne, tp->nelem FATAL;
133141abc59cSbostic /*	qsort(ep, ne, sizeof(char *), qstrcmp);
133241abc59cSbostic /*	for (i = 0; i < ne; i++) {
133341abc59cSbostic /*		setsval(vp, ep[i]);
133441abc59cSbostic /*		x = execute(a[2]);
133541abc59cSbostic /*		if (isbreak(x)) {
133641abc59cSbostic /*			tempfree(vp);
133741abc59cSbostic /*			break;
133841abc59cSbostic /*		}
133941abc59cSbostic /*		if (isnext(x) || isexit(x) || isret(x)) {
134041abc59cSbostic /*			tempfree(vp);
134141abc59cSbostic /*			ret = x;
134241abc59cSbostic /*			break;
134341abc59cSbostic /*		}
134441abc59cSbostic /*		tempfree(x);
134541abc59cSbostic /*	}
134641abc59cSbostic /*	if (ep != elems)
134741abc59cSbostic /*		free(ep);
134841abc59cSbostic /*	return ret;
134941abc59cSbostic /*}
135041abc59cSbostic */
135141abc59cSbostic 
135241abc59cSbostic 
bltin(Node ** a,int n)135341abc59cSbostic Cell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
135441abc59cSbostic {
135541abc59cSbostic 	register Cell *x, *y;
135641abc59cSbostic 	Awkfloat u;
135741abc59cSbostic 	register int t;
135841abc59cSbostic 	uchar *p, buf[RECSIZE];
135941abc59cSbostic 	Node *nextarg;
136041abc59cSbostic 	FILE *fp;
136141abc59cSbostic 
136241abc59cSbostic 	t = (int) a[0];
136341abc59cSbostic 	x = execute(a[1]);
136441abc59cSbostic 	nextarg = a[1]->nnext;
136541abc59cSbostic 	switch (t) {
136641abc59cSbostic 	case FLENGTH:
136741abc59cSbostic 		u = strlen(getsval(x)); break;
136841abc59cSbostic 	case FLOG:
136941abc59cSbostic 		u = errcheck(log(getfval(x)), "log"); break;
137041abc59cSbostic 	case FINT:
137141abc59cSbostic 		modf(getfval(x), &u); break;
137241abc59cSbostic 	case FEXP:
137341abc59cSbostic 		u = errcheck(exp(getfval(x)), "exp"); break;
137441abc59cSbostic 	case FSQRT:
137541abc59cSbostic 		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
137641abc59cSbostic 	case FSIN:
137741abc59cSbostic 		u = sin(getfval(x)); break;
137841abc59cSbostic 	case FCOS:
137941abc59cSbostic 		u = cos(getfval(x)); break;
138041abc59cSbostic 	case FATAN:
138141abc59cSbostic 		if (nextarg == 0) {
138241abc59cSbostic 			ERROR "atan2 requires two arguments; returning 1.0" WARNING;
138341abc59cSbostic 			u = 1.0;
138441abc59cSbostic 		} else {
138541abc59cSbostic 			y = execute(a[1]->nnext);
138641abc59cSbostic 			u = atan2(getfval(x), getfval(y));
138741abc59cSbostic 			tempfree(y);
138841abc59cSbostic 			nextarg = nextarg->nnext;
138941abc59cSbostic 		}
139041abc59cSbostic 		break;
139141abc59cSbostic 	case FSYSTEM:
139241abc59cSbostic 		fflush(stdout);		/* in case something is buffered already */
139341abc59cSbostic 		u = (Awkfloat) system((char *)getsval(x)) / 256;   /* 256 is unix-dep */
139441abc59cSbostic 		break;
139541abc59cSbostic 	case FRAND:
139641abc59cSbostic 		/* in principle, rand() returns something in 0..RAND_MAX */
139741abc59cSbostic 		u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
139841abc59cSbostic 		break;
139941abc59cSbostic 	case FSRAND:
140041abc59cSbostic 		if (x->tval & REC)	/* no argument provided */
140141abc59cSbostic 			u = time((long *)0);
140241abc59cSbostic 		else
140341abc59cSbostic 			u = getfval(x);
140441abc59cSbostic 		srand((int) u); u = (int) u;
140541abc59cSbostic 		break;
140641abc59cSbostic 	case FTOUPPER:
140741abc59cSbostic 	case FTOLOWER:
140841abc59cSbostic 		strcpy(buf, getsval(x));
140941abc59cSbostic 		if (t == FTOUPPER) {
141041abc59cSbostic 			for (p = buf; *p; p++)
141141abc59cSbostic 				if (islower(*p))
141241abc59cSbostic 					*p = toupper(*p);
141341abc59cSbostic 		} else {
141441abc59cSbostic 			for (p = buf; *p; p++)
141541abc59cSbostic 				if (isupper(*p))
141641abc59cSbostic 					*p = tolower(*p);
141741abc59cSbostic 		}
141841abc59cSbostic 		tempfree(x);
141941abc59cSbostic 		x = gettemp();
142041abc59cSbostic 		setsval(x, buf);
142141abc59cSbostic 		return x;
142241abc59cSbostic 	case FFLUSH:
142341abc59cSbostic 		if ((fp = openfile(GT, getsval(x))) == NULL)
142441abc59cSbostic 			u = EOF;
142541abc59cSbostic 		else
142641abc59cSbostic 			u = fflush(fp);
142741abc59cSbostic 		break;
142841abc59cSbostic 	default:	/* can't happen */
142941abc59cSbostic 		ERROR "illegal function type %d", t FATAL;
143041abc59cSbostic 		break;
143141abc59cSbostic 	}
143241abc59cSbostic 	tempfree(x);
143341abc59cSbostic 	x = gettemp();
143441abc59cSbostic 	setfval(x, u);
143541abc59cSbostic 	if (nextarg != 0) {
143641abc59cSbostic 		ERROR "warning: function has too many arguments" WARNING;
143741abc59cSbostic 		for ( ; nextarg; nextarg = nextarg->nnext)
143841abc59cSbostic 			execute(nextarg);
143941abc59cSbostic 	}
144041abc59cSbostic 	return(x);
144141abc59cSbostic }
144241abc59cSbostic 
printstat(Node ** a,int n)144341abc59cSbostic Cell *printstat(Node **a, int n)	/* print a[0] */
144441abc59cSbostic {
144541abc59cSbostic 	register Node *x;
144641abc59cSbostic 	register Cell *y;
144741abc59cSbostic 	FILE *fp;
144841abc59cSbostic 
144941abc59cSbostic 	if (a[1] == 0)	/* a[1] is redirection operator, a[2] is file */
145041abc59cSbostic 		fp = stdout;
145141abc59cSbostic 	else
145241abc59cSbostic 		fp = redirect((int)a[1], a[2]);
145341abc59cSbostic 	for (x = a[0]; x != NULL; x = x->nnext) {
145441abc59cSbostic 		y = execute(x);
145541abc59cSbostic 		fputs((char *)getsval(y), fp);
145641abc59cSbostic 		tempfree(y);
145741abc59cSbostic 		if (x->nnext == NULL)
145841abc59cSbostic 			fputs((char *)*ORS, fp);
145941abc59cSbostic 		else
146041abc59cSbostic 			fputs((char *)*OFS, fp);
146141abc59cSbostic 	}
146241abc59cSbostic 	if (a[1] != 0)
146341abc59cSbostic 		fflush(fp);
146441abc59cSbostic 	if (ferror(fp))
146541abc59cSbostic 		ERROR "write error on %s", filename(fp) FATAL;
146641abc59cSbostic 	return(true);
146741abc59cSbostic }
146841abc59cSbostic 
nullproc(Node ** a,int n)146941abc59cSbostic Cell *nullproc(Node **a, int n)
147041abc59cSbostic {
147141abc59cSbostic 	n;
147241abc59cSbostic 	a;
147341abc59cSbostic 	return 0;
147441abc59cSbostic }
147541abc59cSbostic 
147641abc59cSbostic 
redirect(int a,Node * b)147741abc59cSbostic FILE *redirect(int a, Node *b)	/* set up all i/o redirections */
147841abc59cSbostic {
147941abc59cSbostic 	FILE *fp;
148041abc59cSbostic 	Cell *x;
148141abc59cSbostic 	uchar *fname;
148241abc59cSbostic 
148341abc59cSbostic 	x = execute(b);
148441abc59cSbostic 	fname = getsval(x);
148541abc59cSbostic 	fp = openfile(a, fname);
148641abc59cSbostic 	if (fp == NULL)
148741abc59cSbostic 		ERROR "can't open file %s", fname FATAL;
148841abc59cSbostic 	tempfree(x);
148941abc59cSbostic 	return fp;
149041abc59cSbostic }
149141abc59cSbostic 
149241abc59cSbostic struct files {
149341abc59cSbostic 	FILE	*fp;
149441abc59cSbostic 	uchar	*fname;
149541abc59cSbostic 	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
149641abc59cSbostic } files[FOPEN_MAX] ={
149741abc59cSbostic 	{ stdin,  "/dev/stdin",  LT },	/* watch out: don't free this! */
149841abc59cSbostic 	{ stdout, "/dev/stdout", GT },
149941abc59cSbostic 	{ stderr, "/dev/stderr", GT }
150041abc59cSbostic };
150141abc59cSbostic 
openfile(int a,uchar * us)150241abc59cSbostic FILE *openfile(int a, uchar *us)
150341abc59cSbostic {
150441abc59cSbostic 	char *s = us;
150541abc59cSbostic 	register int i, m;
150641abc59cSbostic 	register FILE *fp;
150741abc59cSbostic 
150841abc59cSbostic 	if (*s == '\0')
150941abc59cSbostic 		ERROR "null file name in print or getline" FATAL;
151041abc59cSbostic 	for (i=0; i < FOPEN_MAX; i++)
151141abc59cSbostic 		if (files[i].fname && strcmp(s, files[i].fname) == 0)
151241abc59cSbostic 			if (a == files[i].mode || a==APPEND && files[i].mode==GT)
151341abc59cSbostic 				return files[i].fp;
151441abc59cSbostic 	for (i=0; i < FOPEN_MAX; i++)
151541abc59cSbostic 		if (files[i].fp == 0)
151641abc59cSbostic 			break;
151741abc59cSbostic 	if (i >= FOPEN_MAX)
151841abc59cSbostic 		ERROR "%s makes too many open files", s FATAL;
151941abc59cSbostic 	fflush(stdout);	/* force a semblance of order */
152041abc59cSbostic 	m = a;
152141abc59cSbostic 	if (a == GT) {
152241abc59cSbostic 		fp = fopen(s, "w");
152341abc59cSbostic 	} else if (a == APPEND) {
152441abc59cSbostic 		fp = fopen(s, "a");
152541abc59cSbostic 		m = GT;	/* so can mix > and >> */
152641abc59cSbostic 	} else if (a == '|') {	/* output pipe */
152741abc59cSbostic 		fp = popen(s, "w");
152841abc59cSbostic 	} else if (a == LE) {	/* input pipe */
152941abc59cSbostic 		fp = popen(s, "r");
153041abc59cSbostic 	} else if (a == LT) {	/* getline <file */
153141abc59cSbostic 		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
153241abc59cSbostic 	} else	/* can't happen */
153341abc59cSbostic 		ERROR "illegal redirection %d", a FATAL;
153441abc59cSbostic 	if (fp != NULL) {
153541abc59cSbostic 		files[i].fname = tostring(s);
153641abc59cSbostic 		files[i].fp = fp;
153741abc59cSbostic 		files[i].mode = m;
153841abc59cSbostic 	}
153941abc59cSbostic 	return fp;
154041abc59cSbostic }
154141abc59cSbostic 
filename(FILE * fp)154241abc59cSbostic uchar *filename(FILE *fp)
154341abc59cSbostic {
154441abc59cSbostic 	int i;
154541abc59cSbostic 
154641abc59cSbostic 	for (i = 0; i < FOPEN_MAX; i++)
154741abc59cSbostic 		if (fp == files[i].fp)
154841abc59cSbostic 			return files[i].fname;
154941abc59cSbostic 	return "???";
155041abc59cSbostic }
155141abc59cSbostic 
closefile(Node ** a,int n)155241abc59cSbostic Cell *closefile(Node **a, int n)
155341abc59cSbostic {
155441abc59cSbostic 	register Cell *x;
155541abc59cSbostic 	int i, stat;
155641abc59cSbostic 
155741abc59cSbostic 	n;
155841abc59cSbostic 	x = execute(a[0]);
155941abc59cSbostic 	getsval(x);
156041abc59cSbostic 	for (i = 0; i < FOPEN_MAX; i++)
156141abc59cSbostic 		if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
156241abc59cSbostic 			if (ferror(files[i].fp))
156341abc59cSbostic 				ERROR "i/o error occurred on %s", files[i].fname WARNING;
156441abc59cSbostic 			if (files[i].mode == '|' || files[i].mode == LE)
156541abc59cSbostic 				stat = pclose(files[i].fp);
156641abc59cSbostic 			else
156741abc59cSbostic 				stat = fclose(files[i].fp);
156841abc59cSbostic 			if (stat == EOF)
156941abc59cSbostic 				ERROR "i/o error occurred closing %s", files[i].fname WARNING;
157041abc59cSbostic 			if (i > 2)	/* don't do /dev/std... */
157141abc59cSbostic 				xfree(files[i].fname);
157241abc59cSbostic 			files[i].fname = NULL;	/* watch out for ref thru this */
157341abc59cSbostic 			files[i].fp = NULL;
157441abc59cSbostic 		}
157541abc59cSbostic 	tempfree(x);
157641abc59cSbostic 	return(true);
157741abc59cSbostic }
157841abc59cSbostic 
closeall(void)157941abc59cSbostic void closeall(void)
158041abc59cSbostic {
158141abc59cSbostic 	int i, stat;
158241abc59cSbostic 
158341abc59cSbostic 	for (i = 0; i < FOPEN_MAX; i++)
158441abc59cSbostic 		if (files[i].fp) {
158541abc59cSbostic 			if (ferror(files[i].fp))
158641abc59cSbostic 				ERROR "i/o error occurred on %s", files[i].fname WARNING;
158741abc59cSbostic 			if (files[i].mode == '|' || files[i].mode == LE)
158841abc59cSbostic 				stat = pclose(files[i].fp);
158941abc59cSbostic 			else
159041abc59cSbostic 				stat = fclose(files[i].fp);
159141abc59cSbostic 			if (stat == EOF)
159241abc59cSbostic 				ERROR "i/o error occurred while closing %s", files[i].fname WARNING;
159341abc59cSbostic 		}
159441abc59cSbostic }
159541abc59cSbostic 
159641abc59cSbostic #define	SUBSIZE	(20 * RECSIZE)
159741abc59cSbostic 
sub(Node ** a,int nnn)159841abc59cSbostic Cell *sub(Node **a, int nnn)	/* substitute command */
159941abc59cSbostic {
160041abc59cSbostic 	register uchar *sptr, *pb, *q;
160141abc59cSbostic 	register Cell *x, *y, *result;
160241abc59cSbostic 	uchar buf[SUBSIZE], *t;
160341abc59cSbostic 	fa *pfa;
160441abc59cSbostic 
160541abc59cSbostic 	x = execute(a[3]);	/* target string */
160641abc59cSbostic 	t = getsval(x);
160741abc59cSbostic 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
160841abc59cSbostic 		pfa = (fa *) a[1];	/* regular expression */
160941abc59cSbostic 	else {
161041abc59cSbostic 		y = execute(a[1]);
161141abc59cSbostic 		pfa = makedfa(getsval(y), 1);
161241abc59cSbostic 		tempfree(y);
161341abc59cSbostic 	}
161441abc59cSbostic 	y = execute(a[2]);	/* replacement string */
161541abc59cSbostic 	result = false;
161641abc59cSbostic 	if (pmatch(pfa, t)) {
161741abc59cSbostic 		pb = buf;
161841abc59cSbostic 		sptr = t;
161941abc59cSbostic 		while (sptr < patbeg)
162041abc59cSbostic 			*pb++ = *sptr++;
162141abc59cSbostic 		sptr = getsval(y);
162241abc59cSbostic 		while (*sptr != 0 && pb < buf + SUBSIZE - 1)
162341abc59cSbostic 			if (*sptr == '\\' && *(sptr+1) == '&') {
162441abc59cSbostic 				sptr++;		/* skip \, */
162541abc59cSbostic 				*pb++ = *sptr++; /* add & */
162641abc59cSbostic 			} else if (*sptr == '&') {
162741abc59cSbostic 				sptr++;
162841abc59cSbostic 				for (q = patbeg; q < patbeg+patlen; )
162941abc59cSbostic 					*pb++ = *q++;
163041abc59cSbostic 			} else
163141abc59cSbostic 				*pb++ = *sptr++;
163241abc59cSbostic 		*pb = '\0';
163341abc59cSbostic 		if (pb >= buf + SUBSIZE)
163441abc59cSbostic 			ERROR "sub() result %30s too big", buf FATAL;
163541abc59cSbostic 		sptr = patbeg + patlen;
163641abc59cSbostic 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1)))
163741abc59cSbostic 			while (*pb++ = *sptr++)
163841abc59cSbostic 				;
163941abc59cSbostic 		if (pb >= buf + SUBSIZE)
164041abc59cSbostic 			ERROR "sub() result %.30s too big", buf FATAL;
164141abc59cSbostic 		setsval(x, buf);
164241abc59cSbostic 		result = true;;
164341abc59cSbostic 	}
164441abc59cSbostic 	tempfree(x);
164541abc59cSbostic 	tempfree(y);
164641abc59cSbostic 	return result;
164741abc59cSbostic }
164841abc59cSbostic 
gsub(Node ** a,int nnn)164941abc59cSbostic Cell *gsub(Node **a, int nnn)	/* global substitute */
165041abc59cSbostic {
165141abc59cSbostic 	register Cell *x, *y;
165241abc59cSbostic 	register uchar *rptr, *sptr, *t, *pb;
165341abc59cSbostic 	uchar buf[SUBSIZE];
165441abc59cSbostic 	register fa *pfa;
165541abc59cSbostic 	int mflag, tempstat, num;
165641abc59cSbostic 
165741abc59cSbostic 	mflag = 0;	/* if mflag == 0, can replace empty string */
165841abc59cSbostic 	num = 0;
165941abc59cSbostic 	x = execute(a[3]);	/* target string */
166041abc59cSbostic 	t = getsval(x);
166141abc59cSbostic 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
166241abc59cSbostic 		pfa = (fa *) a[1];	/* regular expression */
166341abc59cSbostic 	else {
166441abc59cSbostic 		y = execute(a[1]);
166541abc59cSbostic 		pfa = makedfa(getsval(y), 1);
166641abc59cSbostic 		tempfree(y);
166741abc59cSbostic 	}
166841abc59cSbostic 	y = execute(a[2]);	/* replacement string */
166941abc59cSbostic 	if (pmatch(pfa, t)) {
167041abc59cSbostic 		tempstat = pfa->initstat;
167141abc59cSbostic 		pfa->initstat = 2;
167241abc59cSbostic 		pb = buf;
167341abc59cSbostic 		rptr = getsval(y);
167441abc59cSbostic 		do {
167541abc59cSbostic 			/*
167641abc59cSbostic 			uchar *p;
167741abc59cSbostic 			int i;
167841abc59cSbostic 			printf("target string: %s, *patbeg = %o, patlen = %d\n",
167941abc59cSbostic 				t, *patbeg, patlen);
168041abc59cSbostic 			printf("	match found: ");
168141abc59cSbostic 			p=patbeg;
168241abc59cSbostic 			for (i=0; i<patlen; i++)
168341abc59cSbostic 				printf("%c", *p++);
168441abc59cSbostic 			printf("\n");
168541abc59cSbostic 			*/
168641abc59cSbostic 			if (patlen == 0 && *patbeg != 0) {	/* matched empty string */
168741abc59cSbostic 				if (mflag == 0) {	/* can replace empty */
168841abc59cSbostic 					num++;
168941abc59cSbostic 					sptr = rptr;
169041abc59cSbostic 					while (*sptr != 0 && pb < buf + SUBSIZE-1)
169141abc59cSbostic 						if (*sptr == '\\' && *(sptr+1) == '&') {
169241abc59cSbostic 							sptr++;
169341abc59cSbostic 							*pb++ = *sptr++;
169441abc59cSbostic 						} else if (*sptr == '&') {
169541abc59cSbostic 							uchar *q;
169641abc59cSbostic 							sptr++;
169741abc59cSbostic 							for (q = patbeg; q < patbeg+patlen; )
169841abc59cSbostic 								*pb++ = *q++;
169941abc59cSbostic 						} else
170041abc59cSbostic 							*pb++ = *sptr++;
170141abc59cSbostic 				}
170241abc59cSbostic 				if (*t == 0)	/* at end */
170341abc59cSbostic 					goto done;
170441abc59cSbostic 				*pb++ = *t++;
170541abc59cSbostic 				if (pb >= buf + SUBSIZE-1)
170641abc59cSbostic 					ERROR "gsub() result %.30s too big", buf FATAL;
170741abc59cSbostic 				mflag = 0;
170841abc59cSbostic 			}
170941abc59cSbostic 			else {	/* matched nonempty string */
171041abc59cSbostic 				num++;
171141abc59cSbostic 				sptr = t;
171241abc59cSbostic 				while (sptr < patbeg && pb < buf + SUBSIZE-1)
171341abc59cSbostic 					*pb++ = *sptr++;
171441abc59cSbostic 				sptr = rptr;
171541abc59cSbostic 				while (*sptr != 0 && pb < buf + SUBSIZE-1)
171641abc59cSbostic 					if (*sptr == '\\' && *(sptr+1) == '&') {
171741abc59cSbostic 						sptr++;
171841abc59cSbostic 						*pb++ = *sptr++;
171941abc59cSbostic 					} else if (*sptr == '&') {
172041abc59cSbostic 						uchar *q;
172141abc59cSbostic 						sptr++;
172241abc59cSbostic 						for (q = patbeg; q < patbeg+patlen; )
172341abc59cSbostic 							*pb++ = *q++;
172441abc59cSbostic 					} else
172541abc59cSbostic 						*pb++ = *sptr++;
172641abc59cSbostic 				t = patbeg + patlen;
172741abc59cSbostic 				if ((*(t-1) == 0) || (*t == 0))
172841abc59cSbostic 					goto done;
172941abc59cSbostic 				if (pb >= buf + SUBSIZE-1)
173041abc59cSbostic 					ERROR "gsub() result %.30s too big", buf FATAL;
173141abc59cSbostic 				mflag = 1;
173241abc59cSbostic 			}
173341abc59cSbostic 		} while (pmatch(pfa,t));
173441abc59cSbostic 		sptr = t;
173541abc59cSbostic 		while (*pb++ = *sptr++)
173641abc59cSbostic 			;
173741abc59cSbostic 	done:	if (pb >= buf + SUBSIZE-1)
173841abc59cSbostic 			ERROR "gsub() result %.30s too big", buf FATAL;
173941abc59cSbostic 		*pb = '\0';
174041abc59cSbostic 		setsval(x, buf);
174141abc59cSbostic 		pfa->initstat = tempstat;
174241abc59cSbostic 	}
174341abc59cSbostic 	tempfree(x);
174441abc59cSbostic 	tempfree(y);
174541abc59cSbostic 	x = gettemp();
174641abc59cSbostic 	x->tval = NUM;
174741abc59cSbostic 	x->fval = num;
174841abc59cSbostic 	return(x);
174941abc59cSbostic }
1750