xref: /plan9/sys/src/cmd/awk/run.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
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 "y.tab.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 	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, y->nval, y->fval, isarr(y) ? "(array)" : 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) || isnextfile(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 	y->sval = x->sval ? tostring(x->sval) : NULL;
319 	y->fval = x->fval;
320 	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);	/* copy is not constant or field */
321 							/* is DONTFREE right? */
322 	return y;
323 }
324 
325 Cell *arg(Node **a, int n)	/* nth argument of a function */
326 {
327 
328 	n = ptoi(a[0]);	/* argument number, counting from 0 */
329 	   dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
330 	if (n+1 > fp->nargs)
331 		FATAL("argument #%d of function %s was not supplied",
332 			n+1, fp->fcncell->nval);
333 	return fp->args[n];
334 }
335 
336 Cell *jump(Node **a, int n)	/* break, continue, next, nextfile, return */
337 {
338 	Cell *y;
339 
340 	switch (n) {
341 	case EXIT:
342 		if (a[0] != NULL) {
343 			y = execute(a[0]);
344 			errorflag = (int) getfval(y);
345 			tempfree(y);
346 		}
347 		longjmp(env, 1);
348 	case RETURN:
349 		if (a[0] != NULL) {
350 			y = execute(a[0]);
351 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
352 				setsval(fp->retval, getsval(y));
353 				fp->retval->fval = getfval(y);
354 				fp->retval->tval |= NUM;
355 			}
356 			else if (y->tval & STR)
357 				setsval(fp->retval, getsval(y));
358 			else if (y->tval & NUM)
359 				setfval(fp->retval, getfval(y));
360 			else		/* can't happen */
361 				FATAL("bad type variable %d", y->tval);
362 			tempfree(y);
363 		}
364 		return(jret);
365 	case NEXT:
366 		return(jnext);
367 	case NEXTFILE:
368 		nextfile();
369 		return(jnextfile);
370 	case BREAK:
371 		return(jbreak);
372 	case CONTINUE:
373 		return(jcont);
374 	default:	/* can't happen */
375 		FATAL("illegal jump type %d", n);
376 	}
377 	return 0;	/* not reached */
378 }
379 
380 Cell *getline(Node **a, int n)	/* get next line from specific input */
381 {		/* a[0] is variable, a[1] is operator, a[2] is filename */
382 	Cell *r, *x;
383 	extern Cell **fldtab;
384 	FILE *fp;
385 	char *buf;
386 	int bufsize = recsize;
387 	int mode;
388 
389 	if ((buf = (char *) malloc(bufsize)) == NULL)
390 		FATAL("out of memory in getline");
391 
392 	fflush(stdout);	/* in case someone is waiting for a prompt */
393 	r = gettemp();
394 	if (a[1] != NULL) {		/* getline < file */
395 		x = execute(a[2]);		/* filename */
396 		mode = ptoi(a[1]);
397 		if (mode == '|')		/* input pipe */
398 			mode = LE;	/* arbitrary flag */
399 		fp = openfile(mode, getsval(x));
400 		tempfree(x);
401 		if (fp == NULL)
402 			n = -1;
403 		else
404 			n = readrec(&buf, &bufsize, fp);
405 		if (n <= 0) {
406 			;
407 		} else if (a[0] != NULL) {	/* getline var <file */
408 			x = execute(a[0]);
409 			setsval(x, buf);
410 			tempfree(x);
411 		} else {			/* getline <file */
412 			setsval(fldtab[0], buf);
413 			if (is_number(fldtab[0]->sval)) {
414 				fldtab[0]->fval = atof(fldtab[0]->sval);
415 				fldtab[0]->tval |= NUM;
416 			}
417 		}
418 	} else {			/* bare getline; use current input */
419 		if (a[0] == NULL)	/* getline */
420 			n = getrec(&record, &recsize, 1);
421 		else {			/* getline var */
422 			n = getrec(&buf, &bufsize, 0);
423 			x = execute(a[0]);
424 			setsval(x, buf);
425 			tempfree(x);
426 		}
427 	}
428 	setfval(r, (Awkfloat) n);
429 	free(buf);
430 	return r;
431 }
432 
433 Cell *getnf(Node **a, int n)	/* get NF */
434 {
435 	if (donefld == 0)
436 		fldbld();
437 	return (Cell *) a[0];
438 }
439 
440 Cell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
441 {
442 	Cell *x, *y, *z;
443 	char *s;
444 	Node *np;
445 	char *buf;
446 	int bufsz = recsize;
447 	int nsub = strlen(*SUBSEP);
448 
449 	if ((buf = (char *) malloc(bufsz)) == NULL)
450 		FATAL("out of memory in array");
451 
452 	x = execute(a[0]);	/* Cell* for symbol table */
453 	buf[0] = 0;
454 	for (np = a[1]; np; np = np->nnext) {
455 		y = execute(np);	/* subscript */
456 		s = getsval(y);
457 		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
458 			FATAL("out of memory for %s[%s...]", x->nval, buf);
459 		strcat(buf, s);
460 		if (np->nnext)
461 			strcat(buf, *SUBSEP);
462 		tempfree(y);
463 	}
464 	if (!isarr(x)) {
465 		   dprintf( ("making %s into an array\n", x->nval) );
466 		if (freeable(x))
467 			xfree(x->sval);
468 		x->tval &= ~(STR|NUM|DONTFREE);
469 		x->tval |= ARR;
470 		x->sval = (char *) makesymtab(NSYMTAB);
471 	}
472 	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
473 	z->ctype = OCELL;
474 	z->csub = CVAR;
475 	tempfree(x);
476 	free(buf);
477 	return(z);
478 }
479 
480 Cell *awkdelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
481 {
482 	Cell *x, *y;
483 	Node *np;
484 	char *s;
485 	int nsub = strlen(*SUBSEP);
486 
487 	x = execute(a[0]);	/* Cell* for symbol table */
488 	if (!isarr(x))
489 		return True;
490 	if (a[1] == 0) {	/* delete the elements, not the table */
491 		freesymtab(x);
492 		x->tval &= ~STR;
493 		x->tval |= ARR;
494 		x->sval = (char *) makesymtab(NSYMTAB);
495 	} else {
496 		int bufsz = recsize;
497 		char *buf;
498 		if ((buf = (char *) malloc(bufsz)) == NULL)
499 			FATAL("out of memory in adelete");
500 		buf[0] = 0;
501 		for (np = a[1]; np; np = np->nnext) {
502 			y = execute(np);	/* subscript */
503 			s = getsval(y);
504 			if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
505 				FATAL("out of memory deleting %s[%s...]", x->nval, buf);
506 			strcat(buf, s);
507 			if (np->nnext)
508 				strcat(buf, *SUBSEP);
509 			tempfree(y);
510 		}
511 		freeelem(x, buf);
512 		free(buf);
513 	}
514 	tempfree(x);
515 	return True;
516 }
517 
518 Cell *intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
519 {
520 	Cell *x, *ap, *k;
521 	Node *p;
522 	char *buf;
523 	char *s;
524 	int bufsz = recsize;
525 	int nsub = strlen(*SUBSEP);
526 
527 	ap = execute(a[1]);	/* array name */
528 	if (!isarr(ap)) {
529 		   dprintf( ("making %s into an array\n", ap->nval) );
530 		if (freeable(ap))
531 			xfree(ap->sval);
532 		ap->tval &= ~(STR|NUM|DONTFREE);
533 		ap->tval |= ARR;
534 		ap->sval = (char *) makesymtab(NSYMTAB);
535 	}
536 	if ((buf = (char *) malloc(bufsz)) == NULL) {
537 		FATAL("out of memory in intest");
538 	}
539 	buf[0] = 0;
540 	for (p = a[0]; p; p = p->nnext) {
541 		x = execute(p);	/* expr */
542 		s = getsval(x);
543 		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
544 			FATAL("out of memory deleting %s[%s...]", x->nval, buf);
545 		strcat(buf, s);
546 		tempfree(x);
547 		if (p->nnext)
548 			strcat(buf, *SUBSEP);
549 	}
550 	k = lookup(buf, (Array *) ap->sval);
551 	tempfree(ap);
552 	free(buf);
553 	if (k == NULL)
554 		return(False);
555 	else
556 		return(True);
557 }
558 
559 
560 Cell *matchop(Node **a, int n)	/* ~ and match() */
561 {
562 	Cell *x, *y;
563 	char *s, *t;
564 	int i;
565 	void *p;
566 
567 	x = execute(a[1]);	/* a[1] = target text */
568 	s = getsval(x);
569 	if (a[0] == 0)		/* a[1] == 0: already-compiled reg expr */
570 		p = (void *) a[2];
571 	else {
572 		y = execute(a[2]);	/* a[2] = regular expr */
573 		t = getsval(y);
574 		p = compre(t);
575 		tempfree(y);
576 	}
577 	if (n == MATCHFCN)
578 		i = pmatch(p, s, s);
579 	else
580 		i = match(p, s, s);
581 	tempfree(x);
582 	if (n == MATCHFCN) {
583 		int start = countposn(s, patbeg-s)+1;
584 		if (patlen < 0)
585 			start = 0;
586 		setfval(rstartloc, (Awkfloat) start);
587 		setfval(rlengthloc, (Awkfloat) countposn(patbeg, patlen));
588 		x = gettemp();
589 		x->tval = NUM;
590 		x->fval = start;
591 		return x;
592 	} else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
593 		return(True);
594 	else
595 		return(False);
596 }
597 
598 
599 Cell *boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
600 {
601 	Cell *x, *y;
602 	int i;
603 
604 	x = execute(a[0]);
605 	i = istrue(x);
606 	tempfree(x);
607 	switch (n) {
608 	case BOR:
609 		if (i) return(True);
610 		y = execute(a[1]);
611 		i = istrue(y);
612 		tempfree(y);
613 		if (i) return(True);
614 		else return(False);
615 	case AND:
616 		if ( !i ) return(False);
617 		y = execute(a[1]);
618 		i = istrue(y);
619 		tempfree(y);
620 		if (i) return(True);
621 		else return(False);
622 	case NOT:
623 		if (i) return(False);
624 		else return(True);
625 	default:	/* can't happen */
626 		FATAL("unknown boolean operator %d", n);
627 	}
628 	return 0;	/*NOTREACHED*/
629 }
630 
631 Cell *relop(Node **a, int n)	/* a[0 < a[1], etc. */
632 {
633 	int i;
634 	Cell *x, *y;
635 	Awkfloat j;
636 
637 	x = execute(a[0]);
638 	y = execute(a[1]);
639 	if (x->tval&NUM && y->tval&NUM) {
640 		j = x->fval - y->fval;
641 		i = j<0? -1: (j>0? 1: 0);
642 	} else {
643 		i = strcmp(getsval(x), getsval(y));
644 	}
645 	tempfree(x);
646 	tempfree(y);
647 	switch (n) {
648 	case LT:	if (i<0) return(True);
649 			else return(False);
650 	case LE:	if (i<=0) return(True);
651 			else return(False);
652 	case NE:	if (i!=0) return(True);
653 			else return(False);
654 	case EQ:	if (i == 0) return(True);
655 			else return(False);
656 	case GE:	if (i>=0) return(True);
657 			else return(False);
658 	case GT:	if (i>0) return(True);
659 			else return(False);
660 	default:	/* can't happen */
661 		FATAL("unknown relational operator %d", n);
662 	}
663 	return 0;	/*NOTREACHED*/
664 }
665 
666 void tfree(Cell *a)	/* free a tempcell */
667 {
668 	if (freeable(a)) {
669 		   dprintf( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) );
670 		xfree(a->sval);
671 	}
672 	if (a == tmps)
673 		FATAL("tempcell list is curdled");
674 	a->cnext = tmps;
675 	tmps = a;
676 }
677 
678 Cell *gettemp(void)	/* get a tempcell */
679 {	int i;
680 	Cell *x;
681 
682 	if (!tmps) {
683 		tmps = (Cell *) calloc(100, sizeof(Cell));
684 		if (!tmps)
685 			FATAL("out of space for temporaries");
686 		for(i = 1; i < 100; i++)
687 			tmps[i-1].cnext = &tmps[i];
688 		tmps[i-1].cnext = 0;
689 	}
690 	x = tmps;
691 	tmps = x->cnext;
692 	*x = tempcell;
693 	return(x);
694 }
695 
696 Cell *indirect(Node **a, int n)	/* $( a[0] ) */
697 {
698 	Cell *x;
699 	int m;
700 	char *s;
701 
702 	x = execute(a[0]);
703 	m = (int) getfval(x);
704 	if (m == 0 && !is_number(s = getsval(x)))	/* suspicion! */
705 		FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
706 		/* BUG: can x->nval ever be null??? */
707 	tempfree(x);
708 	x = fieldadr(m);
709 	x->ctype = OCELL;	/* BUG?  why are these needed? */
710 	x->csub = CFLD;
711 	return(x);
712 }
713 
714 Cell *substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
715 {
716 	int k, m, n;
717 	char *s, *p;
718 	int temp;
719 	Cell *x, *y, *z = 0;
720 
721 	x = execute(a[0]);
722 	y = execute(a[1]);
723 	if (a[2] != 0)
724 		z = execute(a[2]);
725 	s = getsval(x);
726 	k = countposn(s, strlen(s)) + 1;
727 	if (k <= 1) {
728 		tempfree(x);
729 		tempfree(y);
730 		if (a[2] != 0)
731 			tempfree(z);
732 		x = gettemp();
733 		setsval(x, "");
734 		return(x);
735 	}
736 	m = (int) getfval(y);
737 	if (m <= 0)
738 		m = 1;
739 	else if (m > k)
740 		m = k;
741 	tempfree(y);
742 	if (a[2] != 0) {
743 		n = (int) getfval(z);
744 		tempfree(z);
745 	} else
746 		n = k - 1;
747 	if (n < 0)
748 		n = 0;
749 	else if (n > k - m)
750 		n = k - m;
751 	   dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
752 	y = gettemp();
753 	while (*s && --m)
754 		 s += mblen(s, k);
755 	for (p = s; *p && n--; p += mblen(p, k))
756 			;
757 	temp = *p;	/* with thanks to John Linderman */
758 	*p = '\0';
759 	setsval(y, s);
760 	*p = 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) countposn(s1, 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, char *s, Node *a)	/* printf-like conversions */
794 {
795 	char *fmt;
796 	char *p, *t, *os;
797 	Cell *x;
798 	int flag = 0, n;
799 	int fmtwd; /* format width */
800 	int fmtsz = recsize;
801 	char *buf = *pbuf;
802 	int bufsize = *pbufsize;
803 
804 	os = s;
805 	p = buf;
806 	if ((fmt = (char *) malloc(fmtsz)) == NULL)
807 		FATAL("out of memory in format()");
808 	while (*s) {
809 		adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format");
810 		if (*s != '%') {
811 			*p++ = *s++;
812 			continue;
813 		}
814 		if (*(s+1) == '%') {
815 			*p++ = '%';
816 			s += 2;
817 			continue;
818 		}
819 		/* have to be real careful in case this is a huge number, eg, %100000d */
820 		fmtwd = atoi(s+1);
821 		if (fmtwd < 0)
822 			fmtwd = -fmtwd;
823 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
824 		for (t = fmt; (*t++ = *s) != '\0'; s++) {
825 			if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0))
826 				FATAL("format item %.30s... ran format() out of memory", os);
827 			if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
828 				break;	/* the ansi panoply */
829 			if (*s == '*') {
830 				x = execute(a);
831 				a = a->nnext;
832 				sprintf(t-1, "%d", fmtwd=(int) getfval(x));
833 				if (fmtwd < 0)
834 					fmtwd = -fmtwd;
835 				adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
836 				t = fmt + strlen(fmt);
837 				tempfree(x);
838 			}
839 		}
840 		*t = '\0';
841 		if (fmtwd < 0)
842 			fmtwd = -fmtwd;
843 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
844 
845 		switch (*s) {
846 		case 'f': case 'e': case 'g': case 'E': case 'G':
847 			flag = 1;
848 			break;
849 		case 'd': case 'i':
850 			flag = 2;
851 			if(*(s-1) == 'l') break;
852 			*(t-1) = 'l';
853 			*t = 'd';
854 			*++t = '\0';
855 			break;
856 		case 'o': case 'x': case 'X': case 'u':
857 			flag = *(s-1) == 'l' ? 2 : 3;
858 			break;
859 		case 's':
860 			flag = 4;
861 			break;
862 		case 'c':
863 			flag = 5;
864 			break;
865 		default:
866 			WARNING("weird printf conversion %s", fmt);
867 			flag = 0;
868 			break;
869 		}
870 		if (a == NULL)
871 			FATAL("not enough args in printf(%s)", os);
872 		x = execute(a);
873 		a = a->nnext;
874 		n = MAXNUMSIZE;
875 		if (fmtwd > n)
876 			n = fmtwd;
877 		adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
878 		switch (flag) {
879 		case 0:	sprintf(p, "%s", fmt);	/* unknown, so dump it too */
880 			t = getsval(x);
881 			n = strlen(t);
882 			if (fmtwd > n)
883 				n = fmtwd;
884 			adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
885 			p += strlen(p);
886 			sprintf(p, "%s", t);
887 			break;
888 		case 1:	sprintf(p, fmt, getfval(x)); break;
889 		case 2:	sprintf(p, fmt, (long) getfval(x)); break;
890 		case 3:	sprintf(p, fmt, (int) getfval(x)); break;
891 		case 4:
892 			t = getsval(x);
893 			n = strlen(t);
894 			if (fmtwd > n)
895 				n = fmtwd;
896 			if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
897 				FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
898 			sprintf(p, fmt, t);
899 			break;
900 		case 5:
901 			if (isnum(x)) {
902 				if (getfval(x))
903 					sprintf(p, fmt, (int) getfval(x));
904 				else
905 					*p++ = '\0';
906 			} else
907 				sprintf(p, fmt, getsval(x)[0]);
908 			break;
909 		}
910 		tempfree(x);
911 		p += strlen(p);
912 		s++;
913 	}
914 	*p = '\0';
915 	free(fmt);
916 	for ( ; a; a = a->nnext)		/* evaluate any remaining args */
917 		execute(a);
918 	*pbuf = buf;
919 	*pbufsize = bufsize;
920 	return p - buf;
921 }
922 
923 Cell *awksprintf(Node **a, int n)		/* sprintf(a[0]) */
924 {
925 	Cell *x;
926 	Node *y;
927 	char *buf;
928 	int bufsz=3*recsize;
929 
930 	if ((buf = (char *) malloc(bufsz)) == NULL)
931 		FATAL("out of memory in awksprintf");
932 	y = a[0]->nnext;
933 	x = execute(a[0]);
934 	if (format(&buf, &bufsz, getsval(x), y) == -1)
935 		FATAL("sprintf string %.30s... too long.  can't happen.", buf);
936 	tempfree(x);
937 	x = gettemp();
938 	x->sval = buf;
939 	x->tval = STR;
940 	return(x);
941 }
942 
943 Cell *awkprintf(Node **a, int n)		/* printf */
944 {	/* a[0] is list of args, starting with format string */
945 	/* a[1] is redirection operator, a[2] is redirection file */
946 	FILE *fp;
947 	Cell *x;
948 	Node *y;
949 	char *buf;
950 	int len;
951 	int bufsz=3*recsize;
952 
953 	if ((buf = (char *) malloc(bufsz)) == NULL)
954 		FATAL("out of memory in awkprintf");
955 	y = a[0]->nnext;
956 	x = execute(a[0]);
957 	if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
958 		FATAL("printf string %.30s... too long.  can't happen.", buf);
959 	tempfree(x);
960 	if (a[1] == NULL) {
961 		/* fputs(buf, stdout); */
962 		fwrite(buf, len, 1, stdout);
963 		if (ferror(stdout))
964 			FATAL("write error on stdout");
965 	} else {
966 		fp = redirect(ptoi(a[1]), a[2]);
967 		/* fputs(buf, fp); */
968 		fwrite(buf, len, 1, fp);
969 		fflush(fp);
970 		if (ferror(fp))
971 			FATAL("write error on %s", filename(fp));
972 	}
973 	free(buf);
974 	return(True);
975 }
976 
977 Cell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
978 {
979 	Awkfloat i, j = 0;
980 	double v;
981 	Cell *x, *y, *z;
982 
983 	x = execute(a[0]);
984 	i = getfval(x);
985 	tempfree(x);
986 	if (n != UMINUS) {
987 		y = execute(a[1]);
988 		j = getfval(y);
989 		tempfree(y);
990 	}
991 	z = gettemp();
992 	switch (n) {
993 	case ADD:
994 		i += j;
995 		break;
996 	case MINUS:
997 		i -= j;
998 		break;
999 	case MULT:
1000 		i *= j;
1001 		break;
1002 	case DIVIDE:
1003 		if (j == 0)
1004 			FATAL("division by zero");
1005 		i /= j;
1006 		break;
1007 	case MOD:
1008 		if (j == 0)
1009 			FATAL("division by zero in mod");
1010 		modf(i/j, &v);
1011 		i = i - j * v;
1012 		break;
1013 	case UMINUS:
1014 		i = -i;
1015 		break;
1016 	case POWER:
1017 		if (j >= 0 && modf(j, &v) == 0.0)	/* pos integer exponent */
1018 			i = ipow(i, (int) j);
1019 		else
1020 			i = errcheck(pow(i, j), "pow");
1021 		break;
1022 	default:	/* can't happen */
1023 		FATAL("illegal arithmetic operator %d", n);
1024 	}
1025 	setfval(z, i);
1026 	return(z);
1027 }
1028 
1029 double ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
1030 {
1031 	double v;
1032 
1033 	if (n <= 0)
1034 		return 1;
1035 	v = ipow(x, n/2);
1036 	if (n % 2 == 0)
1037 		return v * v;
1038 	else
1039 		return x * v * v;
1040 }
1041 
1042 Cell *incrdecr(Node **a, int n)		/* a[0]++, etc. */
1043 {
1044 	Cell *x, *z;
1045 	int k;
1046 	Awkfloat xf;
1047 
1048 	x = execute(a[0]);
1049 	xf = getfval(x);
1050 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1051 	if (n == PREINCR || n == PREDECR) {
1052 		setfval(x, xf + k);
1053 		return(x);
1054 	}
1055 	z = gettemp();
1056 	setfval(z, xf);
1057 	setfval(x, xf + k);
1058 	tempfree(x);
1059 	return(z);
1060 }
1061 
1062 Cell *assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
1063 {		/* this is subtle; don't muck with it. */
1064 	Cell *x, *y;
1065 	Awkfloat xf, yf;
1066 	double v;
1067 
1068 	y = execute(a[1]);
1069 	x = execute(a[0]);
1070 	if (n == ASSIGN) {	/* ordinary assignment */
1071 		if (x == y && !(x->tval & (FLD|REC)))	/* self-assignment: */
1072 			;		/* leave alone unless it's a field */
1073 		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1074 			setsval(x, getsval(y));
1075 			x->fval = getfval(y);
1076 			x->tval |= NUM;
1077 		}
1078 		else if (isstr(y))
1079 			setsval(x, getsval(y));
1080 		else if (isnum(y))
1081 			setfval(x, getfval(y));
1082 		else
1083 			funnyvar(y, "read value of");
1084 		tempfree(y);
1085 		return(x);
1086 	}
1087 	xf = getfval(x);
1088 	yf = getfval(y);
1089 	switch (n) {
1090 	case ADDEQ:
1091 		xf += yf;
1092 		break;
1093 	case SUBEQ:
1094 		xf -= yf;
1095 		break;
1096 	case MULTEQ:
1097 		xf *= yf;
1098 		break;
1099 	case DIVEQ:
1100 		if (yf == 0)
1101 			FATAL("division by zero in /=");
1102 		xf /= yf;
1103 		break;
1104 	case MODEQ:
1105 		if (yf == 0)
1106 			FATAL("division by zero in %%=");
1107 		modf(xf/yf, &v);
1108 		xf = xf - yf * v;
1109 		break;
1110 	case POWEQ:
1111 		if (yf >= 0 && modf(yf, &v) == 0.0)	/* pos integer exponent */
1112 			xf = ipow(xf, (int) yf);
1113 		else
1114 			xf = errcheck(pow(xf, yf), "pow");
1115 		break;
1116 	default:
1117 		FATAL("illegal assignment operator %d", n);
1118 		break;
1119 	}
1120 	tempfree(y);
1121 	setfval(x, xf);
1122 	return(x);
1123 }
1124 
1125 Cell *cat(Node **a, int q)	/* a[0] cat a[1] */
1126 {
1127 	Cell *x, *y, *z;
1128 	int n1, n2;
1129 	char *s;
1130 
1131 	x = execute(a[0]);
1132 	y = execute(a[1]);
1133 	getsval(x);
1134 	getsval(y);
1135 	n1 = strlen(x->sval);
1136 	n2 = strlen(y->sval);
1137 	s = (char *) malloc(n1 + n2 + 1);
1138 	if (s == NULL)
1139 		FATAL("out of space concatenating %.15s... and %.15s...",
1140 			x->sval, y->sval);
1141 	strcpy(s, x->sval);
1142 	strcpy(s+n1, y->sval);
1143 	tempfree(y);
1144 	z = gettemp();
1145 	z->sval = s;
1146 	z->tval = STR;
1147 	tempfree(x);
1148 	return(z);
1149 }
1150 
1151 Cell *pastat(Node **a, int n)	/* a[0] { a[1] } */
1152 {
1153 	Cell *x;
1154 
1155 	if (a[0] == 0)
1156 		x = execute(a[1]);
1157 	else {
1158 		x = execute(a[0]);
1159 		if (istrue(x)) {
1160 			tempfree(x);
1161 			x = execute(a[1]);
1162 		}
1163 	}
1164 	return x;
1165 }
1166 
1167 Cell *dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
1168 {
1169 	Cell *x;
1170 	int pair;
1171 
1172 	pair = ptoi(a[3]);
1173 	if (pairstack[pair] == 0) {
1174 		x = execute(a[0]);
1175 		if (istrue(x))
1176 			pairstack[pair] = 1;
1177 		tempfree(x);
1178 	}
1179 	if (pairstack[pair] == 1) {
1180 		x = execute(a[1]);
1181 		if (istrue(x))
1182 			pairstack[pair] = 0;
1183 		tempfree(x);
1184 		x = execute(a[2]);
1185 		return(x);
1186 	}
1187 	return(False);
1188 }
1189 
1190 Cell *split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
1191 {
1192 	Cell *x = 0, *y, *ap;
1193 	char *s;
1194 	int sep;
1195 	char *t, temp, num[50], *fs = 0;
1196 	int n, tempstat, arg3type;
1197 
1198 	y = execute(a[0]);	/* source string */
1199 	s = getsval(y);
1200 	arg3type = ptoi(a[3]);
1201 	if (a[2] == 0)		/* fs string */
1202 		fs = *FS;
1203 	else if (arg3type == STRING) {	/* split(str,arr,"string") */
1204 		x = execute(a[2]);
1205 		fs = getsval(x);
1206 	} else if (arg3type == REGEXPR)
1207 		fs = "(regexpr)";	/* split(str,arr,/regexpr/) */
1208 	else
1209 		FATAL("illegal type of split");
1210 	sep = *fs;
1211 	ap = execute(a[1]);	/* array name */
1212 	freesymtab(ap);
1213 	   dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
1214 	ap->tval &= ~STR;
1215 	ap->tval |= ARR;
1216 	ap->sval = (char *) makesymtab(NSYMTAB);
1217 
1218 	n = 0;
1219 	if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) {	/* reg expr */
1220 		void *p;
1221 		if (arg3type == REGEXPR) {	/* it's ready already */
1222 			p = (void *) a[2];
1223 		} else {
1224 			p = compre(fs);
1225 		}
1226 		t = s;
1227 		if (nematch(p,s,t)) {
1228 			do {
1229 				n++;
1230 				sprintf(num, "%d", n);
1231 				temp = *patbeg;
1232 				*patbeg = '\0';
1233 				if (is_number(t))
1234 					setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1235 				else
1236 					setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1237 				*patbeg = temp;
1238 				t = patbeg + patlen;
1239 				if (t[-1] == 0 || *t == 0) {
1240 					n++;
1241 					sprintf(num, "%d", n);
1242 					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1243 					goto spdone;
1244 				}
1245 			} while (nematch(p,s,t));
1246 		}
1247 		n++;
1248 		sprintf(num, "%d", n);
1249 		if (is_number(t))
1250 			setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1251 		else
1252 			setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1253   spdone:
1254 		p = NULL;
1255 	} else if (sep == ' ') {
1256 		for (n = 0; ; ) {
1257 			while (*s == ' ' || *s == '\t' || *s == '\n')
1258 				s++;
1259 			if (*s == 0)
1260 				break;
1261 			n++;
1262 			t = s;
1263 			do
1264 				s++;
1265 			while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1266 			temp = *s;
1267 			*s = '\0';
1268 			sprintf(num, "%d", n);
1269 			if (is_number(t))
1270 				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1271 			else
1272 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1273 			*s = temp;
1274 			if (*s != 0)
1275 				s++;
1276 		}
1277 	} else if (sep == 0) {	/* new: split(s, a, "") => 1 char/elem */
1278 		for (n = 0; *s != 0; s++) {
1279 			char buf[2];
1280 			n++;
1281 			sprintf(num, "%d", n);
1282 			buf[0] = *s;
1283 			buf[1] = 0;
1284 			if (isdigit(buf[0]))
1285 				setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1286 			else
1287 				setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1288 		}
1289 	} else if (*s != 0) {
1290 		for (;;) {
1291 			n++;
1292 			t = s;
1293 			while (*s != sep && *s != '\n' && *s != '\0')
1294 				s++;
1295 			temp = *s;
1296 			*s = '\0';
1297 			sprintf(num, "%d", n);
1298 			if (is_number(t))
1299 				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1300 			else
1301 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1302 			*s = temp;
1303 			if (*s++ == 0)
1304 				break;
1305 		}
1306 	}
1307 	tempfree(ap);
1308 	tempfree(y);
1309 	if (a[2] != 0 && arg3type == STRING)
1310 		tempfree(x);
1311 	x = gettemp();
1312 	x->tval = NUM;
1313 	x->fval = n;
1314 	return(x);
1315 }
1316 
1317 Cell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
1318 {
1319 	Cell *x;
1320 
1321 	x = execute(a[0]);
1322 	if (istrue(x)) {
1323 		tempfree(x);
1324 		x = execute(a[1]);
1325 	} else {
1326 		tempfree(x);
1327 		x = execute(a[2]);
1328 	}
1329 	return(x);
1330 }
1331 
1332 Cell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
1333 {
1334 	Cell *x;
1335 
1336 	x = execute(a[0]);
1337 	if (istrue(x)) {
1338 		tempfree(x);
1339 		x = execute(a[1]);
1340 	} else if (a[2] != 0) {
1341 		tempfree(x);
1342 		x = execute(a[2]);
1343 	}
1344 	return(x);
1345 }
1346 
1347 Cell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
1348 {
1349 	Cell *x;
1350 
1351 	for (;;) {
1352 		x = execute(a[0]);
1353 		if (!istrue(x))
1354 			return(x);
1355 		tempfree(x);
1356 		x = execute(a[1]);
1357 		if (isbreak(x)) {
1358 			x = True;
1359 			return(x);
1360 		}
1361 		if (isnext(x) || isexit(x) || isret(x))
1362 			return(x);
1363 		tempfree(x);
1364 	}
1365 }
1366 
1367 Cell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
1368 {
1369 	Cell *x;
1370 
1371 	for (;;) {
1372 		x = execute(a[0]);
1373 		if (isbreak(x))
1374 			return True;
1375 		if (isnext(x) || isnextfile(x) || isexit(x) || isret(x))
1376 			return(x);
1377 		tempfree(x);
1378 		x = execute(a[1]);
1379 		if (!istrue(x))
1380 			return(x);
1381 		tempfree(x);
1382 	}
1383 }
1384 
1385 Cell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
1386 {
1387 	Cell *x;
1388 
1389 	x = execute(a[0]);
1390 	tempfree(x);
1391 	for (;;) {
1392 		if (a[1]!=0) {
1393 			x = execute(a[1]);
1394 			if (!istrue(x)) return(x);
1395 			else tempfree(x);
1396 		}
1397 		x = execute(a[3]);
1398 		if (isbreak(x))		/* turn off break */
1399 			return True;
1400 		if (isnext(x) || isexit(x) || isret(x))
1401 			return(x);
1402 		tempfree(x);
1403 		x = execute(a[2]);
1404 		tempfree(x);
1405 	}
1406 }
1407 
1408 Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
1409 {
1410 	Cell *x, *vp, *arrayp, *cp, *ncp;
1411 	Array *tp;
1412 	int i;
1413 
1414 	vp = execute(a[0]);
1415 	arrayp = execute(a[1]);
1416 	if (!isarr(arrayp)) {
1417 		return True;
1418 	}
1419 	tp = (Array *) arrayp->sval;
1420 	tempfree(arrayp);
1421 	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
1422 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1423 			setsval(vp, cp->nval);
1424 			ncp = cp->cnext;
1425 			x = execute(a[2]);
1426 			if (isbreak(x)) {
1427 				tempfree(vp);
1428 				return True;
1429 			}
1430 			if (isnext(x) || isexit(x) || isret(x)) {
1431 				tempfree(vp);
1432 				return(x);
1433 			}
1434 			tempfree(x);
1435 		}
1436 	}
1437 	return True;
1438 }
1439 
1440 Cell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
1441 {
1442 	Cell *x, *y;
1443 	Awkfloat u;
1444 	int t;
1445 	wchar_t wc;
1446 	char *p, *buf;
1447 	char mbc[50];
1448 	Node *nextarg;
1449 	FILE *fp;
1450 
1451 	t = ptoi(a[0]);
1452 	x = execute(a[1]);
1453 	nextarg = a[1]->nnext;
1454 	switch (t) {
1455 	case FLENGTH:
1456 		p = getsval(x);
1457 		u = (Awkfloat) countposn(p, strlen(p)); break;
1458 	case FLOG:
1459 		u = errcheck(log(getfval(x)), "log"); break;
1460 	case FINT:
1461 		modf(getfval(x), &u); break;
1462 	case FEXP:
1463 		u = errcheck(exp(getfval(x)), "exp"); break;
1464 	case FSQRT:
1465 		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1466 	case FSIN:
1467 		u = sin(getfval(x)); break;
1468 	case FCOS:
1469 		u = cos(getfval(x)); break;
1470 	case FATAN:
1471 		if (nextarg == 0) {
1472 			WARNING("atan2 requires two arguments; returning 1.0");
1473 			u = 1.0;
1474 		} else {
1475 			y = execute(a[1]->nnext);
1476 			u = atan2(getfval(x), getfval(y));
1477 			tempfree(y);
1478 			nextarg = nextarg->nnext;
1479 		}
1480 		break;
1481 	case FSYSTEM:
1482 		fflush(stdout);		/* in case something is buffered already */
1483 		u = (Awkfloat) system(getsval(x)) / 256;   /* 256 is unix-dep */
1484 		break;
1485 	case FRAND:
1486 		/* in principle, rand() returns something in 0..RAND_MAX */
1487 		u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1488 		break;
1489 	case FSRAND:
1490 		if (isrec(x))	/* no argument provided */
1491 			u = time((time_t *)0);
1492 		else
1493 			u = getfval(x);
1494 		srand((unsigned int) u);
1495 		break;
1496 	case FTOUPPER:
1497 	case FTOLOWER:
1498 		buf = tostring(getsval(x));
1499 		if (t == FTOUPPER) {
1500 			for (p = buf; *p; p++)
1501 				if (islower(*p))
1502 					*p = toupper(*p);
1503 		} else {
1504 			for (p = buf; *p; p++)
1505 				if (isupper(*p))
1506 					*p = tolower(*p);
1507 		}
1508 		tempfree(x);
1509 		x = gettemp();
1510 		setsval(x, buf);
1511 		free(buf);
1512 		return x;
1513 	case FFLUSH:
1514 		if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
1515 			u = EOF;
1516 		else
1517 			u = fflush(fp);
1518 		break;
1519 	case FUTF:
1520 		wc = (int)getfval(x);
1521 		mbc[wctomb(mbc, wc)] = 0;
1522 		tempfree(x);
1523 		x = gettemp();
1524 		setsval(x, mbc);
1525 		return x;
1526 	default:	/* can't happen */
1527 		FATAL("illegal function type %d", t);
1528 		break;
1529 	}
1530 	tempfree(x);
1531 	x = gettemp();
1532 	setfval(x, u);
1533 	if (nextarg != 0) {
1534 		WARNING("warning: function has too many arguments");
1535 		for ( ; nextarg; nextarg = nextarg->nnext)
1536 			execute(nextarg);
1537 	}
1538 	return(x);
1539 }
1540 
1541 Cell *printstat(Node **a, int n)	/* print a[0] */
1542 {
1543 	Node *x;
1544 	Cell *y;
1545 	FILE *fp;
1546 
1547 	if (a[1] == 0)	/* a[1] is redirection operator, a[2] is file */
1548 		fp = stdout;
1549 	else
1550 		fp = redirect(ptoi(a[1]), a[2]);
1551 	for (x = a[0]; x != NULL; x = x->nnext) {
1552 		y = execute(x);
1553 		fputs(getsval(y), fp);
1554 		tempfree(y);
1555 		if (x->nnext == NULL)
1556 			fputs(*ORS, fp);
1557 		else
1558 			fputs(*OFS, fp);
1559 	}
1560 	if (a[1] != 0)
1561 		fflush(fp);
1562 	if (ferror(fp))
1563 		FATAL("write error on %s", filename(fp));
1564 	return(True);
1565 }
1566 
1567 Cell *nullproc(Node **a, int n)
1568 {
1569 	n = n;
1570 	a = a;
1571 	return 0;
1572 }
1573 
1574 
1575 FILE *redirect(int a, Node *b)	/* set up all i/o redirections */
1576 {
1577 	FILE *fp;
1578 	Cell *x;
1579 	char *fname;
1580 
1581 	x = execute(b);
1582 	fname = getsval(x);
1583 	fp = openfile(a, fname);
1584 	if (fp == NULL)
1585 		FATAL("can't open file %s", fname);
1586 	tempfree(x);
1587 	return fp;
1588 }
1589 
1590 struct files {
1591 	FILE	*fp;
1592 	char	*fname;
1593 	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
1594 } files[FOPEN_MAX] ={
1595 	{ NULL,  "/dev/stdin",  LT },	/* watch out: don't free this! */
1596 	{ NULL, "/dev/stdout", GT },
1597 	{ NULL, "/dev/stderr", GT }
1598 };
1599 
1600 void stdinit(void)	/* in case stdin, etc., are not constants */
1601 {
1602 	files[0].fp = stdin;
1603 	files[1].fp = stdout;
1604 	files[2].fp = stderr;
1605 }
1606 
1607 FILE *openfile(int a, char *us)
1608 {
1609 	char *s = us;
1610 	int i, m;
1611 	FILE *fp = 0;
1612 
1613 	if (*s == '\0')
1614 		FATAL("null file name in print or getline");
1615 	for (i=0; i < FOPEN_MAX; i++)
1616 		if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1617 			if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1618 				return files[i].fp;
1619 			if (a == FFLUSH)
1620 				return files[i].fp;
1621 		}
1622 	if (a == FFLUSH)	/* didn't find it, so don't create it! */
1623 		return NULL;
1624 
1625 	for (i=0; i < FOPEN_MAX; i++)
1626 		if (files[i].fp == 0)
1627 			break;
1628 	if (i >= FOPEN_MAX)
1629 		FATAL("%s makes too many open files", s);
1630 	fflush(stdout);	/* force a semblance of order */
1631 	m = a;
1632 	if (a == GT) {
1633 		fp = fopen(s, "w");
1634 	} else if (a == APPEND) {
1635 		fp = fopen(s, "a");
1636 		m = GT;	/* so can mix > and >> */
1637 	} else if (a == '|') {	/* output pipe */
1638 		fp = popen(s, "w");
1639 	} else if (a == LE) {	/* input pipe */
1640 		fp = popen(s, "r");
1641 	} else if (a == LT) {	/* getline <file */
1642 		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
1643 	} else	/* can't happen */
1644 		FATAL("illegal redirection %d", a);
1645 	if (fp != NULL) {
1646 		files[i].fname = tostring(s);
1647 		files[i].fp = fp;
1648 		files[i].mode = m;
1649 	}
1650 	return fp;
1651 }
1652 
1653 char *filename(FILE *fp)
1654 {
1655 	int i;
1656 
1657 	for (i = 0; i < FOPEN_MAX; i++)
1658 		if (fp == files[i].fp)
1659 			return files[i].fname;
1660 	return "???";
1661 }
1662 
1663 Cell *closefile(Node **a, int n)
1664 {
1665 	Cell *x;
1666 	int i, stat;
1667 
1668 	n = n;
1669 	x = execute(a[0]);
1670 	getsval(x);
1671 	for (i = 0; i < FOPEN_MAX; i++)
1672 		if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1673 			if (ferror(files[i].fp))
1674 				WARNING( "i/o error occurred on %s", files[i].fname );
1675 			if (files[i].mode == '|' || files[i].mode == LE)
1676 				stat = pclose(files[i].fp);
1677 			else
1678 				stat = fclose(files[i].fp);
1679 			if (stat == EOF)
1680 				WARNING( "i/o error occurred closing %s", files[i].fname );
1681 			if (i > 2)	/* don't do /dev/std... */
1682 				xfree(files[i].fname);
1683 			files[i].fname = NULL;	/* watch out for ref thru this */
1684 			files[i].fp = NULL;
1685 		}
1686 	tempfree(x);
1687 	return(True);
1688 }
1689 
1690 void closeall(void)
1691 {
1692 	int i, stat;
1693 
1694 	for (i = 0; i < FOPEN_MAX; i++)
1695 		if (files[i].fp) {
1696 			if (ferror(files[i].fp))
1697 				WARNING( "i/o error occurred on %s", files[i].fname );
1698 			if (files[i].mode == '|' || files[i].mode == LE)
1699 				stat = pclose(files[i].fp);
1700 			else
1701 				stat = fclose(files[i].fp);
1702 			if (stat == EOF)
1703 				WARNING( "i/o error occurred while closing %s", files[i].fname );
1704 		}
1705 }
1706 
1707 void backsub(char **pb_ptr, char **sptr_ptr);
1708 
1709 Cell *sub(Node **a, int nnn)	/* substitute command */
1710 {
1711 	char *sptr, *pb, *q;
1712 	Cell *x, *y, *result;
1713 	char *t, *buf;
1714 	void *p;
1715 	int bufsz = recsize;
1716 
1717 	if ((buf = (char *) malloc(bufsz)) == NULL)
1718 		FATAL("out of memory in sub");
1719 	x = execute(a[3]);	/* target string */
1720 	t = getsval(x);
1721 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
1722 		p = (void *) a[1];	/* regular expression */
1723 	else {
1724 		y = execute(a[1]);
1725 		p = compre(getsval(y));
1726 		tempfree(y);
1727 	}
1728 	y = execute(a[2]);	/* replacement string */
1729 	result = False;
1730 	if (pmatch(p, t, t)) {
1731 		sptr = t;
1732 		adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1733 		pb = buf;
1734 		while (sptr < patbeg)
1735 			*pb++ = *sptr++;
1736 		sptr = getsval(y);
1737 		while (*sptr != 0) {
1738 			adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1739 			if (*sptr == '\\') {
1740 				backsub(&pb, &sptr);
1741 			} else if (*sptr == '&') {
1742 				sptr++;
1743 				adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1744 				for (q = patbeg; q < patbeg+patlen; )
1745 					*pb++ = *q++;
1746 			} else
1747 				*pb++ = *sptr++;
1748 		}
1749 		*pb = '\0';
1750 		if (pb > buf + bufsz)
1751 			FATAL("sub result1 %.30s too big; can't happen", buf);
1752 		sptr = patbeg + patlen;
1753 		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1754 			adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1755 			while ((*pb++ = *sptr++) != 0)
1756 				;
1757 		}
1758 		if (pb > buf + bufsz)
1759 			FATAL("sub result2 %.30s too big; can't happen", buf);
1760 		setsval(x, buf);	/* BUG: should be able to avoid copy */
1761 		result = True;;
1762 	}
1763 	tempfree(x);
1764 	tempfree(y);
1765 	free(buf);
1766 	return result;
1767 }
1768 
1769 Cell *gsub(Node **a, int nnn)	/* global substitute */
1770 {
1771 	Cell *x, *y;
1772 	char *rptr, *sptr, *t, *pb, *c;
1773 	char *buf;
1774 	void *p;
1775 	int mflag, num;
1776 	int bufsz = recsize;
1777 
1778 	if ((buf = (char *)malloc(bufsz)) == NULL)
1779 		FATAL("out of memory in gsub");
1780 	mflag = 0;	/* if mflag == 0, can replace empty string */
1781 	num = 0;
1782 	x = execute(a[3]);	/* target string */
1783 	c = t = getsval(x);
1784 	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
1785 		p = (void *) a[1];	/* regular expression */
1786 	else {
1787 		y = execute(a[1]);
1788 		p = compre(getsval(y));
1789 		tempfree(y);
1790 	}
1791 	y = execute(a[2]);	/* replacement string */
1792 	if (pmatch(p, t, c)) {
1793 		pb = buf;
1794 		rptr = getsval(y);
1795 		do {
1796 			if (patlen == 0 && *patbeg != 0) {	/* matched empty string */
1797 				if (mflag == 0) {	/* can replace empty */
1798 					num++;
1799 					sptr = rptr;
1800 					while (*sptr != 0) {
1801 						adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1802 						if (*sptr == '\\') {
1803 							backsub(&pb, &sptr);
1804 						} else if (*sptr == '&') {
1805 							char *q;
1806 							sptr++;
1807 							adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1808 							for (q = patbeg; q < patbeg+patlen; )
1809 								*pb++ = *q++;
1810 						} else
1811 							*pb++ = *sptr++;
1812 					}
1813 				}
1814 				if (*c == 0)	/* at end */
1815 					goto done;
1816 				adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1817 				*pb++ = *c++;
1818 				if (pb > buf + bufsz)	/* BUG: not sure of this test */
1819 					FATAL("gsub result0 %.30s too big; can't happen", buf);
1820 				mflag = 0;
1821 			}
1822 			else {	/* matched nonempty string */
1823 				num++;
1824 				sptr = c;
1825 				adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
1826 				while (sptr < patbeg)
1827 					*pb++ = *sptr++;
1828 				sptr = rptr;
1829 				while (*sptr != 0) {
1830 					adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1831 					if (*sptr == '\\') {
1832 						backsub(&pb, &sptr);
1833 					} else if (*sptr == '&') {
1834 						char *q;
1835 						sptr++;
1836 						adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1837 						for (q = patbeg; q < patbeg+patlen; )
1838 							*pb++ = *q++;
1839 					} else
1840 						*pb++ = *sptr++;
1841 				}
1842 				c = patbeg + patlen;
1843 				if ((c[-1] == 0) || (*c == 0))
1844 					goto done;
1845 				if (pb > buf + bufsz)
1846 					FATAL("gsub result1 %.30s too big; can't happen", buf);
1847 				mflag = 1;
1848 			}
1849 		} while (pmatch(p, t, c));
1850 		sptr = c;
1851 		adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
1852 		while ((*pb++ = *sptr++) != 0)
1853 			;
1854 	done:	if (pb > buf + bufsz)
1855 			FATAL("gsub result2 %.30s too big; can't happen", buf);
1856 		*pb = '\0';
1857 		setsval(x, buf);	/* BUG: should be able to avoid copy + free */
1858 	}
1859 	tempfree(x);
1860 	tempfree(y);
1861 	x = gettemp();
1862 	x->tval = NUM;
1863 	x->fval = num;
1864 	free(buf);
1865 	return(x);
1866 }
1867 
1868 void backsub(char **pb_ptr, char **sptr_ptr)	/* handle \\& variations */
1869 {						/* sptr[0] == '\\' */
1870 	char *pb = *pb_ptr, *sptr = *sptr_ptr;
1871 
1872 	if (sptr[1] == '\\') {
1873 		if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
1874 			*pb++ = '\\';
1875 			*pb++ = '&';
1876 			sptr += 4;
1877 		} else if (sptr[2] == '&') {	/* \\& -> \ + matched */
1878 			*pb++ = '\\';
1879 			sptr += 2;
1880 		} else {			/* \\x -> \\x */
1881 			*pb++ = *sptr++;
1882 			*pb++ = *sptr++;
1883 		}
1884 	} else if (sptr[1] == '&') {	/* literal & */
1885 		sptr++;
1886 		*pb++ = *sptr++;
1887 	} else				/* literal \ */
1888 		*pb++ = *sptr++;
1889 
1890 	*pb_ptr = pb;
1891 	*sptr_ptr = sptr;
1892 }
1893