xref: /inferno-os/utils/awk/run.c (revision ddf161d27871e47d85fd56e8403c715af8ce43c8)
1  /****************************************************************
2  Copyright (C) Lucent Technologies 1997
3  All Rights Reserved
4  
5  Permission to use, copy, modify, and distribute this software and
6  its documentation for any purpose and without fee is hereby
7  granted, provided that the above copyright notice appear in all
8  copies and that both that the copyright notice and this
9  permission notice and warranty disclaimer appear in supporting
10  documentation, and that the name Lucent Technologies or any of
11  its entities not be used in advertising or publicity pertaining
12  to distribution of the software without specific, written prior
13  permission.
14  
15  LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17  IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20  IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22  THIS SOFTWARE.
23  ****************************************************************/
24  
25  #define DEBUG
26  #include <stdio.h>
27  #include <ctype.h>
28  #include <setjmp.h>
29  #include <math.h>
30  #include <string.h>
31  #include <stdlib.h>
32  #include <time.h>
33  #include "awk.h"
34  #include "ytab.h"
35  
36  #define tempfree(x)	if (istemp(x)) tfree(x); else
37  
38  /*
39  #undef tempfree
40  
41  void tempfree(Cell *p) {
42  	if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
43  		WARNING("bad csub %d in Cell %d %s",
44  			p->csub, p->ctype, p->sval);
45  	}
46  	if (istemp(p))
47  		tfree(p);
48  }
49  */
50  
51  #ifdef _NFILE
52  #ifndef FOPEN_MAX
53  #define FOPEN_MAX _NFILE
54  #endif
55  #endif
56  
57  #ifndef	FOPEN_MAX
58  #define	FOPEN_MAX	40	/* max number of open files */
59  #endif
60  
61  #ifndef RAND_MAX
62  #define RAND_MAX	32767	/* all that ansi guarantees */
63  #endif
64  
65  jmp_buf env;
66  extern	int	pairstack[];
67  
68  Node	*winner = NULL;	/* root of parse tree */
69  Cell	*tmps;		/* free temporary cells for execution */
70  
71  static Cell	truecell	={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
72  Cell	*True	= &truecell;
73  static Cell	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
74  Cell	*False	= &falsecell;
75  static Cell	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
76  Cell	*jbreak	= &breakcell;
77  static Cell	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM };
78  Cell	*jcont	= &contcell;
79  static Cell	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
80  Cell	*jnext	= &nextcell;
81  static Cell	nextfilecell	={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
82  Cell	*jnextfile	= &nextfilecell;
83  static Cell	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
84  Cell	*jexit	= &exitcell;
85  static Cell	retcell		={ OJUMP, JRET, 0, 0, 0.0, NUM };
86  Cell	*jret	= &retcell;
87  static Cell	tempcell	={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
88  
89  Node	*curnode = NULL;	/* the node being executed, for debugging */
90  
91  /* buffer memory management */
92  int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
93  	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))
303  		return y;
304  	tempfree(y);		/* this can free twice! */
305  	z = fp->retval;			/* return value */
306  	   dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
307  	fp--;
308  	return(z);
309  }
310  
311  Cell *copycell(Cell *x)	/* make a copy of a cell in a temp */
312  {
313  	Cell *y;
314  
315  	y = gettemp();
316  	y->csub = CCOPY;	/* prevents freeing until call is over */
317  	y->nval = x->nval;	/* BUG? */
318  	if (isstr(x))
319  		y->sval = tostring(x->sval);
320  	y->fval = x->fval;
321  	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);	/* copy is not constant or field */
322  							/* is DONTFREE right? */
323  	return y;
324  }
325  
326  Cell *arg(Node **a, int n)	/* nth argument of a function */
327  {
328  
329  	n = ptoi(a[0]);	/* argument number, counting from 0 */
330  	   dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
331  	if (n+1 > fp->nargs)
332  		FATAL("argument #%d of function %s was not supplied",
333  			n+1, fp->fcncell->nval);
334  	return fp->args[n];
335  }
336  
337  Cell *jump(Node **a, int n)	/* break, continue, next, nextfile, return */
338  {
339  	Cell *y;
340  
341  	switch (n) {
342  	case EXIT:
343  		if (a[0] != NULL) {
344  			y = execute(a[0]);
345  			errorflag = (int) getfval(y);
346  			tempfree(y);
347  		}
348  		longjmp(env, 1);
349  	case RETURN:
350  		if (a[0] != NULL) {
351  			y = execute(a[0]);
352  			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
353  				setsval(fp->retval, getsval(y));
354  				fp->retval->fval = getfval(y);
355  				fp->retval->tval |= NUM;
356  			}
357  			else if (y->tval & STR)
358  				setsval(fp->retval, getsval(y));
359  			else if (y->tval & NUM)
360  				setfval(fp->retval, getfval(y));
361  			else		/* can't happen */
362  				FATAL("bad type variable %d", y->tval);
363  			tempfree(y);
364  		}
365  		return(jret);
366  	case NEXT:
367  		return(jnext);
368  	case NEXTFILE:
369  		nextfile();
370  		return(jnextfile);
371  	case BREAK:
372  		return(jbreak);
373  	case CONTINUE:
374  		return(jcont);
375  	default:	/* can't happen */
376  		FATAL("illegal jump type %d", n);
377  	}
378  	return 0;	/* not reached */
379  }
380  
381  Cell *getline(Node **a, int n)	/* get next line from specific input */
382  {		/* a[0] is variable, a[1] is operator, a[2] is filename */
383  	Cell *r, *x;
384  	extern Cell **fldtab;
385  	FILE *fp;
386  	char *buf;
387  	int bufsize = recsize;
388  	int mode;
389  
390  	if ((buf = (char *) malloc(bufsize)) == NULL)
391  		FATAL("out of memory in getline");
392  
393  	fflush(stdout);	/* in case someone is waiting for a prompt */
394  	r = gettemp();
395  	if (a[1] != NULL) {		/* getline < file */
396  		x = execute(a[2]);		/* filename */
397  		mode = ptoi(a[1]);
398  		if (mode == '|')		/* input pipe */
399  			mode = LE;	/* arbitrary flag */
400  		fp = openfile(mode, getsval(x));
401  		tempfree(x);
402  		if (fp == NULL)
403  			n = -1;
404  		else
405  			n = readrec(&buf, &bufsize, fp);
406  		if (n <= 0) {
407  			;
408  		} else if (a[0] != NULL) {	/* getline var <file */
409  			x = execute(a[0]);
410  			setsval(x, buf);
411  			tempfree(x);
412  		} else {			/* getline <file */
413  			setsval(fldtab[0], buf);
414  			if (is_number(fldtab[0]->sval)) {
415  				fldtab[0]->fval = atof(fldtab[0]->sval);
416  				fldtab[0]->tval |= NUM;
417  			}
418  		}
419  	} else {			/* bare getline; use current input */
420  		if (a[0] == NULL)	/* getline */
421  			n = getrec(&record, &recsize, 1);
422  		else {			/* getline var */
423  			n = getrec(&buf, &bufsize, 0);
424  			x = execute(a[0]);
425  			setsval(x, buf);
426  			tempfree(x);
427  		}
428  	}
429  	setfval(r, (Awkfloat) n);
430  	free(buf);
431  	return r;
432  }
433  
434  Cell *getnf(Node **a, int n)	/* get NF */
435  {
436  	if (donefld == 0)
437  		fldbld();
438  	return (Cell *) a[0];
439  }
440  
441  Cell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
442  {
443  	Cell *x, *y, *z;
444  	char *s;
445  	Node *np;
446  	char *buf;
447  	int bufsz = recsize;
448  	int nsub = strlen(*SUBSEP);
449  
450  	if ((buf = (char *) malloc(bufsz)) == NULL)
451  		FATAL("out of memory in array");
452  
453  	x = execute(a[0]);	/* Cell* for symbol table */
454  	buf[0] = 0;
455  	for (np = a[1]; np; np = np->nnext) {
456  		y = execute(np);	/* subscript */
457  		s = getsval(y);
458  		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
459  			FATAL("out of memory for %s[%s...]", x->nval, buf);
460  		strcat(buf, s);
461  		if (np->nnext)
462  			strcat(buf, *SUBSEP);
463  		tempfree(y);
464  	}
465  	if (!isarr(x)) {
466  		   dprintf( ("making %s into an array\n", x->nval) );
467  		if (freeable(x))
468  			xfree(x->sval);
469  		x->tval &= ~(STR|NUM|DONTFREE);
470  		x->tval |= ARR;
471  		x->sval = (char *) makesymtab(NSYMTAB);
472  	}
473  	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
474  	z->ctype = OCELL;
475  	z->csub = CVAR;
476  	tempfree(x);
477  	free(buf);
478  	return(z);
479  }
480  
481  Cell *awkdelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
482  {
483  	Cell *x, *y;
484  	Node *np;
485  	char *s;
486  	int nsub = strlen(*SUBSEP);
487  
488  	x = execute(a[0]);	/* Cell* for symbol table */
489  	if (!isarr(x))
490  		return True;
491  	if (a[1] == 0) {	/* delete the elements, not the table */
492  		freesymtab(x);
493  		x->tval &= ~STR;
494  		x->tval |= ARR;
495  		x->sval = (char *) makesymtab(NSYMTAB);
496  	} else {
497  		int bufsz = recsize;
498  		char *buf;
499  		if ((buf = (char *) malloc(bufsz)) == NULL)
500  			FATAL("out of memory in adelete");
501  		buf[0] = 0;
502  		for (np = a[1]; np; np = np->nnext) {
503  			y = execute(np);	/* subscript */
504  			s = getsval(y);
505  			if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
506  				FATAL("out of memory deleting %s[%s...]", x->nval, buf);
507  			strcat(buf, s);
508  			if (np->nnext)
509  				strcat(buf, *SUBSEP);
510  			tempfree(y);
511  		}
512  		freeelem(x, buf);
513  		free(buf);
514  	}
515  	tempfree(x);
516  	return True;
517  }
518  
519  Cell *intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
520  {
521  	Cell *x, *ap, *k;
522  	Node *p;
523  	char *buf;
524  	char *s;
525  	int bufsz = recsize;
526  	int nsub = strlen(*SUBSEP);
527  
528  	ap = execute(a[1]);	/* array name */
529  	if (!isarr(ap)) {
530  		   dprintf( ("making %s into an array\n", ap->nval) );
531  		if (freeable(ap))
532  			xfree(ap->sval);
533  		ap->tval &= ~(STR|NUM|DONTFREE);
534  		ap->tval |= ARR;
535  		ap->sval = (char *) makesymtab(NSYMTAB);
536  	}
537  	if ((buf = (char *) malloc(bufsz)) == NULL) {
538  		FATAL("out of memory in intest");
539  	}
540  	buf[0] = 0;
541  	for (p = a[0]; p; p = p->nnext) {
542  		x = execute(p);	/* expr */
543  		s = getsval(x);
544  		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
545  			FATAL("out of memory deleting %s[%s...]", x->nval, buf);
546  		strcat(buf, s);
547  		tempfree(x);
548  		if (p->nnext)
549  			strcat(buf, *SUBSEP);
550  	}
551  	k = lookup(buf, (Array *) ap->sval);
552  	tempfree(ap);
553  	free(buf);
554  	if (k == NULL)
555  		return(False);
556  	else
557  		return(True);
558  }
559  
560  
561  Cell *matchop(Node **a, int n)	/* ~ and match() */
562  {
563  	Cell *x, *y;
564  	char *s, *t;
565  	int i;
566  	fa *pfa;
567  	int (*mf)(fa *, char *) = match, mode = 0;
568  
569  	if (n == MATCHFCN) {
570  		mf = pmatch;
571  		mode = 1;
572  	}
573  	x = execute(a[1]);	/* a[1] = target text */
574  	s = getsval(x);
575  	if (a[0] == 0)		/* a[1] == 0: already-compiled reg expr */
576  		i = (*mf)((fa *) a[2], s);
577  	else {
578  		y = execute(a[2]);	/* a[2] = regular expr */
579  		t = getsval(y);
580  		pfa = makedfa(t, mode);
581  		i = (*mf)(pfa, s);
582  		tempfree(y);
583  	}
584  	tempfree(x);
585  	if (n == MATCHFCN) {
586  		int start = patbeg - s + 1;
587  		if (patlen < 0)
588  			start = 0;
589  		setfval(rstartloc, (Awkfloat) start);
590  		setfval(rlengthloc, (Awkfloat) patlen);
591  		x = gettemp();
592  		x->tval = NUM;
593  		x->fval = start;
594  		return x;
595  	} else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
596  		return(True);
597  	else
598  		return(False);
599  }
600  
601  
602  Cell *boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
603  {
604  	Cell *x, *y;
605  	int i;
606  
607  	x = execute(a[0]);
608  	i = istrue(x);
609  	tempfree(x);
610  	switch (n) {
611  	case BOR:
612  		if (i) return(True);
613  		y = execute(a[1]);
614  		i = istrue(y);
615  		tempfree(y);
616  		if (i) return(True);
617  		else return(False);
618  	case AND:
619  		if ( !i ) return(False);
620  		y = execute(a[1]);
621  		i = istrue(y);
622  		tempfree(y);
623  		if (i) return(True);
624  		else return(False);
625  	case NOT:
626  		if (i) return(False);
627  		else return(True);
628  	default:	/* can't happen */
629  		FATAL("unknown boolean operator %d", n);
630  	}
631  	return 0;	/*NOTREACHED*/
632  }
633  
634  Cell *relop(Node **a, int n)	/* a[0 < a[1], etc. */
635  {
636  	int i;
637  	Cell *x, *y;
638  	Awkfloat j;
639  
640  	x = execute(a[0]);
641  	y = execute(a[1]);
642  	if (x->tval&NUM && y->tval&NUM) {
643  		j = x->fval - y->fval;
644  		i = j<0? -1: (j>0? 1: 0);
645  	} else {
646  		i = strcmp(getsval(x), getsval(y));
647  	}
648  	tempfree(x);
649  	tempfree(y);
650  	switch (n) {
651  	case LT:	if (i<0) return(True);
652  			else return(False);
653  	case LE:	if (i<=0) return(True);
654  			else return(False);
655  	case NE:	if (i!=0) return(True);
656  			else return(False);
657  	case EQ:	if (i == 0) return(True);
658  			else return(False);
659  	case GE:	if (i>=0) return(True);
660  			else return(False);
661  	case GT:	if (i>0) return(True);
662  			else return(False);
663  	default:	/* can't happen */
664  		FATAL("unknown relational operator %d", n);
665  	}
666  	return 0;	/*NOTREACHED*/
667  }
668  
669  void tfree(Cell *a)	/* free a tempcell */
670  {
671  	if (freeable(a)) {
672  		   dprintf( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) );
673  		xfree(a->sval);
674  	}
675  	if (a == tmps)
676  		FATAL("tempcell list is curdled");
677  	a->cnext = tmps;
678  	tmps = a;
679  }
680  
681  Cell *gettemp(void)	/* get a tempcell */
682  {	int i;
683  	Cell *x;
684  
685  	if (!tmps) {
686  		tmps = (Cell *) calloc(100, sizeof(Cell));
687  		if (!tmps)
688  			FATAL("out of space for temporaries");
689  		for(i = 1; i < 100; i++)
690  			tmps[i-1].cnext = &tmps[i];
691  		tmps[i-1].cnext = 0;
692  	}
693  	x = tmps;
694  	tmps = x->cnext;
695  	*x = tempcell;
696  	return(x);
697  }
698  
699  Cell *indirect(Node **a, int n)	/* $( a[0] ) */
700  {
701  	Cell *x;
702  	int m;
703  	char *s;
704  
705  	x = execute(a[0]);
706  	m = (int) getfval(x);
707  	if (m == 0 && !is_number(s = getsval(x)))	/* suspicion! */
708  		FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
709  		/* BUG: can x->nval ever be null??? */
710  	tempfree(x);
711  	x = fieldadr(m);
712  	x->ctype = OCELL;	/* BUG?  why are these needed? */
713  	x->csub = CFLD;
714  	return(x);
715  }
716  
717  Cell *substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
718  {
719  	int k, m, n;
720  	char *s;
721  	int temp;
722  	Cell *x, *y, *z = 0;
723  
724  	x = execute(a[0]);
725  	y = execute(a[1]);
726  	if (a[2] != 0)
727  		z = execute(a[2]);
728  	s = getsval(x);
729  	k = strlen(s) + 1;
730  	if (k <= 1) {
731  		tempfree(x);
732  		tempfree(y);
733  		if (a[2] != 0) {
734  			tempfree(z);
735  		}
736  		x = gettemp();
737  		setsval(x, "");
738  		return(x);
739  	}
740  	m = (int) getfval(y);
741  	if (m <= 0)
742  		m = 1;
743  	else if (m > k)
744  		m = k;
745  	tempfree(y);
746  	if (a[2] != 0) {
747  		n = (int) getfval(z);
748  		tempfree(z);
749  	} else
750  		n = k - 1;
751  	if (n < 0)
752  		n = 0;
753  	else if (n > k - m)
754  		n = k - m;
755  	   dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
756  	y = gettemp();
757  	temp = s[n+m-1];	/* with thanks to John Linderman */
758  	s[n+m-1] = '\0';
759  	setsval(y, s + m - 1);
760  	s[n+m-1] = temp;
761  	tempfree(x);
762  	return(y);
763  }
764  
765  Cell *sindex(Node **a, int nnn)		/* index(a[0], a[1]) */
766  {
767  	Cell *x, *y, *z;
768  	char *s1, *s2, *p1, *p2, *q;
769  	Awkfloat v = 0.0;
770  
771  	x = execute(a[0]);
772  	s1 = getsval(x);
773  	y = execute(a[1]);
774  	s2 = getsval(y);
775  
776  	z = gettemp();
777  	for (p1 = s1; *p1 != '\0'; p1++) {
778  		for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
779  			;
780  		if (*p2 == '\0') {
781  			v = (Awkfloat) (p1 - s1 + 1);	/* origin 1 */
782  			break;
783  		}
784  	}
785  	tempfree(x);
786  	tempfree(y);
787  	setfval(z, v);
788  	return(z);
789  }
790  
791  #define	MAXNUMSIZE	50
792  
793  int format(char **pbuf, int *pbufsize, 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((uschar)*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  	n = y->tval;
1213  	y->tval |= DONTFREE;	/* split(a[x], a); */
1214  	freesymtab(ap);
1215  	y->tval = n;
1216  	   dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
1217  	ap->tval &= ~STR;
1218  	ap->tval |= ARR;
1219  	ap->sval = (char *) makesymtab(NSYMTAB);
1220  
1221  	n = 0;
1222  	if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) {	/* reg expr */
1223  		fa *pfa;
1224  		if (arg3type == REGEXPR) {	/* it's ready already */
1225  			pfa = (fa *) a[2];
1226  		} else {
1227  			pfa = makedfa(fs, 1);
1228  		}
1229  		if (nematch(pfa,s)) {
1230  			tempstat = pfa->initstat;
1231  			pfa->initstat = 2;
1232  			do {
1233  				n++;
1234  				sprintf(num, "%d", n);
1235  				temp = *patbeg;
1236  				*patbeg = '\0';
1237  				if (is_number(s))
1238  					setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1239  				else
1240  					setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1241  				*patbeg = temp;
1242  				s = patbeg + patlen;
1243  				if (*(patbeg+patlen-1) == 0 || *s == 0) {
1244  					n++;
1245  					sprintf(num, "%d", n);
1246  					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1247  					pfa->initstat = tempstat;
1248  					goto spdone;
1249  				}
1250  			} while (nematch(pfa,s));
1251  		}
1252  		n++;
1253  		sprintf(num, "%d", n);
1254  		if (is_number(s))
1255  			setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1256  		else
1257  			setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1258    spdone:
1259  		pfa = NULL;
1260  	} else if (sep == ' ') {
1261  		for (n = 0; ; ) {
1262  			while (*s == ' ' || *s == '\t' || *s == '\n')
1263  				s++;
1264  			if (*s == 0)
1265  				break;
1266  			n++;
1267  			t = s;
1268  			do
1269  				s++;
1270  			while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1271  			temp = *s;
1272  			*s = '\0';
1273  			sprintf(num, "%d", n);
1274  			if (is_number(t))
1275  				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1276  			else
1277  				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1278  			*s = temp;
1279  			if (*s != 0)
1280  				s++;
1281  		}
1282  	} else if (sep == 0) {	/* new: split(s, a, "") => 1 char/elem */
1283  		for (n = 0; *s != 0; s++) {
1284  			char buf[2];
1285  			n++;
1286  			sprintf(num, "%d", n);
1287  			buf[0] = *s;
1288  			buf[1] = 0;
1289  			if (isdigit((uschar)buf[0]))
1290  				setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1291  			else
1292  				setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1293  		}
1294  	} else if (*s != 0) {
1295  		for (;;) {
1296  			n++;
1297  			t = s;
1298  			while (*s != sep && *s != '\n' && *s != '\0')
1299  				s++;
1300  			temp = *s;
1301  			*s = '\0';
1302  			sprintf(num, "%d", n);
1303  			if (is_number(t))
1304  				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1305  			else
1306  				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1307  			*s = temp;
1308  			if (*s++ == 0)
1309  				break;
1310  		}
1311  	}
1312  	tempfree(ap);
1313  	tempfree(y);
1314  	if (a[2] != 0 && arg3type == STRING) {
1315  		tempfree(x);
1316  	}
1317  	x = gettemp();
1318  	x->tval = NUM;
1319  	x->fval = n;
1320  	return(x);
1321  }
1322  
1323  Cell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
1324  {
1325  	Cell *x;
1326  
1327  	x = execute(a[0]);
1328  	if (istrue(x)) {
1329  		tempfree(x);
1330  		x = execute(a[1]);
1331  	} else {
1332  		tempfree(x);
1333  		x = execute(a[2]);
1334  	}
1335  	return(x);
1336  }
1337  
1338  Cell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
1339  {
1340  	Cell *x;
1341  
1342  	x = execute(a[0]);
1343  	if (istrue(x)) {
1344  		tempfree(x);
1345  		x = execute(a[1]);
1346  	} else if (a[2] != 0) {
1347  		tempfree(x);
1348  		x = execute(a[2]);
1349  	}
1350  	return(x);
1351  }
1352  
1353  Cell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
1354  {
1355  	Cell *x;
1356  
1357  	for (;;) {
1358  		x = execute(a[0]);
1359  		if (!istrue(x))
1360  			return(x);
1361  		tempfree(x);
1362  		x = execute(a[1]);
1363  		if (isbreak(x)) {
1364  			x = True;
1365  			return(x);
1366  		}
1367  		if (isnext(x) || isexit(x) || isret(x))
1368  			return(x);
1369  		tempfree(x);
1370  	}
1371  }
1372  
1373  Cell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
1374  {
1375  	Cell *x;
1376  
1377  	for (;;) {
1378  		x = execute(a[0]);
1379  		if (isbreak(x))
1380  			return True;
1381  		if (isnext(x) || isexit(x) || isret(x))
1382  			return(x);
1383  		tempfree(x);
1384  		x = execute(a[1]);
1385  		if (!istrue(x))
1386  			return(x);
1387  		tempfree(x);
1388  	}
1389  }
1390  
1391  Cell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
1392  {
1393  	Cell *x;
1394  
1395  	x = execute(a[0]);
1396  	tempfree(x);
1397  	for (;;) {
1398  		if (a[1]!=0) {
1399  			x = execute(a[1]);
1400  			if (!istrue(x)) return(x);
1401  			else tempfree(x);
1402  		}
1403  		x = execute(a[3]);
1404  		if (isbreak(x))		/* turn off break */
1405  			return True;
1406  		if (isnext(x) || isexit(x) || isret(x))
1407  			return(x);
1408  		tempfree(x);
1409  		x = execute(a[2]);
1410  		tempfree(x);
1411  	}
1412  }
1413  
1414  Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
1415  {
1416  	Cell *x, *vp, *arrayp, *cp, *ncp;
1417  	Array *tp;
1418  	int i;
1419  
1420  	vp = execute(a[0]);
1421  	arrayp = execute(a[1]);
1422  	if (!isarr(arrayp)) {
1423  		return True;
1424  	}
1425  	tp = (Array *) arrayp->sval;
1426  	tempfree(arrayp);
1427  	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
1428  		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1429  			setsval(vp, cp->nval);
1430  			ncp = cp->cnext;
1431  			x = execute(a[2]);
1432  			if (isbreak(x)) {
1433  				tempfree(vp);
1434  				return True;
1435  			}
1436  			if (isnext(x) || isexit(x) || isret(x)) {
1437  				tempfree(vp);
1438  				return(x);
1439  			}
1440  			tempfree(x);
1441  		}
1442  	}
1443  	return True;
1444  }
1445  
1446  Cell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
1447  {
1448  	Cell *x, *y;
1449  	Awkfloat u;
1450  	int t;
1451  	char *p, *buf;
1452  	Node *nextarg;
1453  	FILE *fp;
1454  
1455  	t = ptoi(a[0]);
1456  	x = execute(a[1]);
1457  	nextarg = a[1]->nnext;
1458  	switch (t) {
1459  	case FLENGTH:
1460  		u = strlen(getsval(x)); break;
1461  	case FLOG:
1462  		u = errcheck(log(getfval(x)), "log"); break;
1463  	case FINT:
1464  		modf(getfval(x), &u); break;
1465  	case FEXP:
1466  		u = errcheck(exp(getfval(x)), "exp"); break;
1467  	case FSQRT:
1468  		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1469  	case FSIN:
1470  		u = sin(getfval(x)); break;
1471  	case FCOS:
1472  		u = cos(getfval(x)); break;
1473  	case FATAN:
1474  		if (nextarg == 0) {
1475  			WARNING("atan2 requires two arguments; returning 1.0");
1476  			u = 1.0;
1477  		} else {
1478  			y = execute(a[1]->nnext);
1479  			u = atan2(getfval(x), getfval(y));
1480  			tempfree(y);
1481  			nextarg = nextarg->nnext;
1482  		}
1483  		break;
1484  	case FSYSTEM:
1485  		fflush(stdout);		/* in case something is buffered already */
1486  		u = (Awkfloat) system(getsval(x)) / 256;   /* 256 is unix-dep */
1487  		break;
1488  	case FRAND:
1489  		/* in principle, rand() returns something in 0..RAND_MAX */
1490  		u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1491  		break;
1492  	case FSRAND:
1493  		if (isrec(x))	/* no argument provided */
1494  			u = time((time_t *)0);
1495  		else
1496  			u = getfval(x);
1497  		srand((unsigned int) u);
1498  		break;
1499  	case FTOUPPER:
1500  	case FTOLOWER:
1501  		buf = tostring(getsval(x));
1502  		if (t == FTOUPPER) {
1503  			for (p = buf; *p; p++)
1504  				if (islower((uschar) *p))
1505  					*p = toupper(*p);
1506  		} else {
1507  			for (p = buf; *p; p++)
1508  				if (isupper((uschar) *p))
1509  					*p = tolower(*p);
1510  		}
1511  		tempfree(x);
1512  		x = gettemp();
1513  		setsval(x, buf);
1514  		free(buf);
1515  		return x;
1516  	case FFLUSH:
1517  		if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
1518  			u = EOF;
1519  		else
1520  			u = fflush(fp);
1521  		break;
1522  	default:	/* can't happen */
1523  		FATAL("illegal function type %d", t);
1524  		break;
1525  	}
1526  	tempfree(x);
1527  	x = gettemp();
1528  	setfval(x, u);
1529  	if (nextarg != 0) {
1530  		WARNING("warning: function has too many arguments");
1531  		for ( ; nextarg; nextarg = nextarg->nnext)
1532  			execute(nextarg);
1533  	}
1534  	return(x);
1535  }
1536  
1537  Cell *printstat(Node **a, int n)	/* print a[0] */
1538  {
1539  	Node *x;
1540  	Cell *y;
1541  	FILE *fp;
1542  
1543  	if (a[1] == 0)	/* a[1] is redirection operator, a[2] is file */
1544  		fp = stdout;
1545  	else
1546  		fp = redirect(ptoi(a[1]), a[2]);
1547  	for (x = a[0]; x != NULL; x = x->nnext) {
1548  		y = execute(x);
1549  		fputs(getsval(y), fp);
1550  		tempfree(y);
1551  		if (x->nnext == NULL)
1552  			fputs(*ORS, fp);
1553  		else
1554  			fputs(*OFS, fp);
1555  	}
1556  	if (a[1] != 0)
1557  		fflush(fp);
1558  	if (ferror(fp))
1559  		FATAL("write error on %s", filename(fp));
1560  	return(True);
1561  }
1562  
1563  Cell *nullproc(Node **a, int n)
1564  {
1565  	n = n;
1566  	a = a;
1567  	return 0;
1568  }
1569  
1570  
1571  FILE *redirect(int a, Node *b)	/* set up all i/o redirections */
1572  {
1573  	FILE *fp;
1574  	Cell *x;
1575  	char *fname;
1576  
1577  	x = execute(b);
1578  	fname = getsval(x);
1579  	fp = openfile(a, fname);
1580  	if (fp == NULL)
1581  		FATAL("can't open file %s", fname);
1582  	tempfree(x);
1583  	return fp;
1584  }
1585  
1586  struct files {
1587  	FILE	*fp;
1588  	char	*fname;
1589  	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
1590  } files[FOPEN_MAX] ={
1591  	{ NULL,  "/dev/stdin",  LT },	/* watch out: don't free this! */
1592  	{ NULL, "/dev/stdout", GT },
1593  	{ NULL, "/dev/stderr", GT }
1594  };
1595  
1596  void stdinit(void)	/* in case stdin, etc., are not constants */
1597  {
1598  	files[0].fp = stdin;
1599  	files[1].fp = stdout;
1600  	files[2].fp = stderr;
1601  }
1602  
1603  FILE *openfile(int a, char *us)
1604  {
1605  	char *s = us;
1606  	int i, m;
1607  	FILE *fp = 0;
1608  
1609  	if (*s == '\0')
1610  		FATAL("null file name in print or getline");
1611  	for (i=0; i < FOPEN_MAX; i++)
1612  		if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1613  			if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1614  				return files[i].fp;
1615  			if (a == FFLUSH)
1616  				return files[i].fp;
1617  		}
1618  	if (a == FFLUSH)	/* didn't find it, so don't create it! */
1619  		return NULL;
1620  
1621  	for (i=0; i < FOPEN_MAX; i++)
1622  		if (files[i].fp == 0)
1623  			break;
1624  	if (i >= FOPEN_MAX)
1625  		FATAL("%s makes too many open files", s);
1626  	fflush(stdout);	/* force a semblance of order */
1627  	m = a;
1628  	if (a == GT) {
1629  		fp = fopen(s, "w");
1630  	} else if (a == APPEND) {
1631  		fp = fopen(s, "a");
1632  		m = GT;	/* so can mix > and >> */
1633  	} else if (a == '|') {	/* output pipe */
1634  		fp = popen(s, "w");
1635  	} else if (a == LE) {	/* input pipe */
1636  		fp = popen(s, "r");
1637  	} else if (a == LT) {	/* getline <file */
1638  		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
1639  	} else	/* can't happen */
1640  		FATAL("illegal redirection %d", a);
1641  	if (fp != NULL) {
1642  		files[i].fname = tostring(s);
1643  		files[i].fp = fp;
1644  		files[i].mode = m;
1645  	}
1646  	return fp;
1647  }
1648  
1649  char *filename(FILE *fp)
1650  {
1651  	int i;
1652  
1653  	for (i = 0; i < FOPEN_MAX; i++)
1654  		if (fp == files[i].fp)
1655  			return files[i].fname;
1656  	return "?";
1657  }
1658  
1659  Cell *closefile(Node **a, int n)
1660  {
1661  	Cell *x;
1662  	int i, stat;
1663  
1664  	n = n;
1665  	x = execute(a[0]);
1666  	getsval(x);
1667  	stat = -1;
1668  	for (i = 0; i < FOPEN_MAX; i++) {
1669  		if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1670  			if (ferror(files[i].fp))
1671  				WARNING( "i/o error occurred on %s", files[i].fname );
1672  			if (files[i].mode == '|' || files[i].mode == LE)
1673  				stat = pclose(files[i].fp);
1674  			else
1675  				stat = fclose(files[i].fp);
1676  			if (stat == EOF)
1677  				WARNING( "i/o error occurred closing %s", files[i].fname );
1678  			if (i > 2)	/* don't do /dev/std... */
1679  				xfree(files[i].fname);
1680  			files[i].fname = NULL;	/* watch out for ref thru this */
1681  			files[i].fp = NULL;
1682  		}
1683  	}
1684  	tempfree(x);
1685  	x = gettemp();
1686  	setfval(x, (Awkfloat) stat);
1687  	return(x);
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 && i != 0)
1703  				WARNING( "i/o error occurred while closing %s", files[i].fname );
1704  		}
1705  	}
1706  }
1707  
1708  void backsub(char **pb_ptr, char **sptr_ptr);
1709  
1710  Cell *sub(Node **a, int nnn)	/* substitute command */
1711  {
1712  	char *sptr, *pb, *q;
1713  	Cell *x, *y, *result;
1714  	char *t, *buf;
1715  	fa *pfa;
1716  	int bufsz = recsize;
1717  
1718  	if ((buf = (char *) malloc(bufsz)) == NULL)
1719  		FATAL("out of memory in sub");
1720  	x = execute(a[3]);	/* target string */
1721  	t = getsval(x);
1722  	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
1723  		pfa = (fa *) a[1];	/* regular expression */
1724  	else {
1725  		y = execute(a[1]);
1726  		pfa = makedfa(getsval(y), 1);
1727  		tempfree(y);
1728  	}
1729  	y = execute(a[2]);	/* replacement string */
1730  	result = False;
1731  	if (pmatch(pfa, t)) {
1732  		sptr = t;
1733  		adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1734  		pb = buf;
1735  		while (sptr < patbeg)
1736  			*pb++ = *sptr++;
1737  		sptr = getsval(y);
1738  		while (*sptr != 0) {
1739  			adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1740  			if (*sptr == '\\') {
1741  				backsub(&pb, &sptr);
1742  			} else if (*sptr == '&') {
1743  				sptr++;
1744  				adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1745  				for (q = patbeg; q < patbeg+patlen; )
1746  					*pb++ = *q++;
1747  			} else
1748  				*pb++ = *sptr++;
1749  		}
1750  		*pb = '\0';
1751  		if (pb > buf + bufsz)
1752  			FATAL("sub result1 %.30s too big; can't happen", buf);
1753  		sptr = patbeg + patlen;
1754  		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1755  			adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1756  			while ((*pb++ = *sptr++) != 0)
1757  				;
1758  		}
1759  		if (pb > buf + bufsz)
1760  			FATAL("sub result2 %.30s too big; can't happen", buf);
1761  		setsval(x, buf);	/* BUG: should be able to avoid copy */
1762  		result = True;;
1763  	}
1764  	tempfree(x);
1765  	tempfree(y);
1766  	free(buf);
1767  	return result;
1768  }
1769  
1770  Cell *gsub(Node **a, int nnn)	/* global substitute */
1771  {
1772  	Cell *x, *y;
1773  	char *rptr, *sptr, *t, *pb, *q;
1774  	char *buf;
1775  	fa *pfa;
1776  	int mflag, tempstat, num;
1777  	int bufsz = recsize;
1778  
1779  	if ((buf = (char *) malloc(bufsz)) == NULL)
1780  		FATAL("out of memory in gsub");
1781  	mflag = 0;	/* if mflag == 0, can replace empty string */
1782  	num = 0;
1783  	x = execute(a[3]);	/* target string */
1784  	t = getsval(x);
1785  	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
1786  		pfa = (fa *) a[1];	/* regular expression */
1787  	else {
1788  		y = execute(a[1]);
1789  		pfa = makedfa(getsval(y), 1);
1790  		tempfree(y);
1791  	}
1792  	y = execute(a[2]);	/* replacement string */
1793  	if (pmatch(pfa, t)) {
1794  		tempstat = pfa->initstat;
1795  		pfa->initstat = 2;
1796  		pb = buf;
1797  		rptr = getsval(y);
1798  		do {
1799  			if (patlen == 0 && *patbeg != 0) {	/* matched empty string */
1800  				if (mflag == 0) {	/* can replace empty */
1801  					num++;
1802  					sptr = rptr;
1803  					while (*sptr != 0) {
1804  						adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1805  						if (*sptr == '\\') {
1806  							backsub(&pb, &sptr);
1807  						} else if (*sptr == '&') {
1808  							sptr++;
1809  							adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1810  							for (q = patbeg; q < patbeg+patlen; )
1811  								*pb++ = *q++;
1812  						} else
1813  							*pb++ = *sptr++;
1814  					}
1815  				}
1816  				if (*t == 0)	/* at end */
1817  					goto done;
1818  				adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1819  				*pb++ = *t++;
1820  				if (pb > buf + bufsz)	/* BUG: not sure of this test */
1821  					FATAL("gsub result0 %.30s too big; can't happen", buf);
1822  				mflag = 0;
1823  			}
1824  			else {	/* matched nonempty string */
1825  				num++;
1826  				sptr = t;
1827  				adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
1828  				while (sptr < patbeg)
1829  					*pb++ = *sptr++;
1830  				sptr = rptr;
1831  				while (*sptr != 0) {
1832  					adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1833  					if (*sptr == '\\') {
1834  						backsub(&pb, &sptr);
1835  					} else if (*sptr == '&') {
1836  						sptr++;
1837  						adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1838  						for (q = patbeg; q < patbeg+patlen; )
1839  							*pb++ = *q++;
1840  					} else
1841  						*pb++ = *sptr++;
1842  				}
1843  				t = patbeg + patlen;
1844  				if (patlen == 0 || *t == 0 || *(t-1) == 0)
1845  					goto done;
1846  				if (pb > buf + bufsz)
1847  					FATAL("gsub result1 %.30s too big; can't happen", buf);
1848  				mflag = 1;
1849  			}
1850  		} while (pmatch(pfa,t));
1851  		sptr = t;
1852  		adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
1853  		while ((*pb++ = *sptr++) != 0)
1854  			;
1855  	done:	if (pb > buf + bufsz)
1856  			FATAL("gsub result2 %.30s too big; can't happen", buf);
1857  		*pb = '\0';
1858  		setsval(x, buf);	/* BUG: should be able to avoid copy + free */
1859  		pfa->initstat = tempstat;
1860  	}
1861  	tempfree(x);
1862  	tempfree(y);
1863  	x = gettemp();
1864  	x->tval = NUM;
1865  	x->fval = num;
1866  	free(buf);
1867  	return(x);
1868  }
1869  
1870  void backsub(char **pb_ptr, char **sptr_ptr)	/* handle \\& variations */
1871  {						/* sptr[0] == '\\' */
1872  	char *pb = *pb_ptr, *sptr = *sptr_ptr;
1873  
1874  	if (sptr[1] == '\\') {
1875  		if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
1876  			*pb++ = '\\';
1877  			*pb++ = '&';
1878  			sptr += 4;
1879  		} else if (sptr[2] == '&') {	/* \\& -> \ + matched */
1880  			*pb++ = '\\';
1881  			sptr += 2;
1882  		} else {			/* \\x -> \\x */
1883  			*pb++ = *sptr++;
1884  			*pb++ = *sptr++;
1885  		}
1886  	} else if (sptr[1] == '&') {	/* literal & */
1887  		sptr++;
1888  		*pb++ = *sptr++;
1889  	} else				/* literal \ */
1890  		*pb++ = *sptr++;
1891  
1892  	*pb_ptr = pb;
1893  	*sptr_ptr = sptr;
1894  }
1895