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