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