run.c revision 112336
1/****************************************************************
2Copyright (C) Lucent Technologies 1997
3All Rights Reserved
4
5Permission to use, copy, modify, and distribute this software and
6its documentation for any purpose and without fee is hereby
7granted, provided that the above copyright notice appear in all
8copies and that both that the copyright notice and this
9permission notice and warranty disclaimer appear in supporting
10documentation, and that the name Lucent Technologies or any of
11its entities not be used in advertising or publicity pertaining
12to distribution of the software without specific, written prior
13permission.
14
15LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22THIS 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
41void 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
65jmp_buf env;
66extern	int	pairstack[];
67
68Node	*winner = NULL;	/* root of parse tree */
69Cell	*tmps;		/* free temporary cells for execution */
70
71static Cell	truecell	={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
72Cell	*True	= &truecell;
73static Cell	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
74Cell	*False	= &falsecell;
75static Cell	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
76Cell	*jbreak	= &breakcell;
77static Cell	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM };
78Cell	*jcont	= &contcell;
79static Cell	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
80Cell	*jnext	= &nextcell;
81static Cell	nextfilecell	={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
82Cell	*jnextfile	= &nextfilecell;
83static Cell	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
84Cell	*jexit	= &exitcell;
85static Cell	retcell		={ OJUMP, JRET, 0, 0, 0.0, NUM };
86Cell	*jret	= &retcell;
87static Cell	tempcell	={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
88
89Node	*curnode = NULL;	/* the node being executed, for debugging */
90
91/* buffer memory management */
92int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
93	const char *whatrtn)
94/* pbuf:    address of pointer to buffer being managed
95 * psiz:    address of buffer size variable
96 * minlen:  minimum length of buffer needed
97 * quantum: buffer size quantum
98 * pbptr:   address of movable pointer into buffer, or 0 if none
99 * whatrtn: name of the calling routine if failure should cause fatal error
100 *
101 * return   0 for realloc failure, !=0 for success
102 */
103{
104	if (minlen > *psiz) {
105		char *tbuf;
106		int rminlen = quantum ? minlen % quantum : 0;
107		int boff = pbptr ? *pbptr - *pbuf : 0;
108		/* round up to next multiple of quantum */
109		if (rminlen)
110			minlen += quantum - rminlen;
111		tbuf = (char *) realloc(*pbuf, minlen);
112		if (tbuf == NULL) {
113			if (whatrtn)
114				FATAL("out of memory in %s", whatrtn);
115			return 0;
116		}
117		*pbuf = tbuf;
118		*psiz = minlen;
119		if (pbptr)
120			*pbptr = tbuf + boff;
121	}
122	return 1;
123}
124
125void 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
134Cell *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
171Cell *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
205struct 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
214struct Frame *frame = NULL;	/* base of stack frames; dynamically allocated */
215int	nframe = 0;		/* number of frames allocated */
216struct Frame *fp = NULL;	/* frame pointer. bottom level unused */
217
218Cell *call(Node **a, int n)	/* function call.  very kludgy and fragile */
219{
220	static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
221	int i, ncall, ndef;
222	Node *x;
223	Cell *args[NARGS], *oargs[NARGS];	/* BUG: fixed size arrays */
224	Cell *y, *z, *fcn;
225	char *s;
226
227	fcn = execute(a[0]);	/* the function itself */
228	s = fcn->nval;
229	if (!isfcn(fcn))
230		FATAL("calling undefined function %s", s);
231	if (frame == NULL) {
232		fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
233		if (frame == NULL)
234			FATAL("out of space for stack frames calling %s", s);
235	}
236	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)	/* args in call */
237		ncall++;
238	ndef = (int) fcn->fval;			/* args in defn */
239	   dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
240	if (ncall > ndef)
241		WARNING("function %s called with %d args, uses only %d",
242			s, ncall, ndef);
243	if (ncall + ndef > NARGS)
244		FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
245	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {	/* get call args */
246		   dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
247		y = execute(x);
248		oargs[i] = y;
249		   dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
250			   i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval) );
251		if (isfcn(y))
252			FATAL("can't use function %s as argument in %s", y->nval, s);
253		if (isarr(y))
254			args[i] = y;	/* arrays by ref */
255		else
256			args[i] = copycell(y);
257		tempfree(y);
258	}
259	for ( ; i < ndef; i++) {	/* add null args for ones not provided */
260		args[i] = gettemp();
261		*args[i] = newcopycell;
262	}
263	fp++;	/* now ok to up frame */
264	if (fp >= frame + nframe) {
265		int dfp = fp - frame;	/* old index */
266		frame = (struct Frame *)
267			realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
268		if (frame == NULL)
269			FATAL("out of space for stack frames in %s", s);
270		fp = frame + dfp;
271	}
272	fp->fcncell = fcn;
273	fp->args = args;
274	fp->nargs = ndef;	/* number defined with (excess are locals) */
275	fp->retval = gettemp();
276
277	   dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
278	y = execute((Node *)(fcn->sval));	/* execute body */
279	   dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
280
281	for (i = 0; i < ndef; i++) {
282		Cell *t = fp->args[i];
283		if (isarr(t)) {
284			if (t->csub == CCOPY) {
285				if (i >= ncall) {
286					freesymtab(t);
287					t->csub = CTEMP;
288					tempfree(t);
289				} else {
290					oargs[i]->tval = t->tval;
291					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
292					oargs[i]->sval = t->sval;
293					tempfree(t);
294				}
295			}
296		} else if (t != y) {	/* kludge to prevent freeing twice */
297			t->csub = CTEMP;
298			tempfree(t);
299		}
300	}
301	tempfree(fcn);
302	if (isexit(y) || isnext(y))
303		return y;
304	tempfree(y);		/* this can free twice! */
305	z = fp->retval;			/* return value */
306	   dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
307	fp--;
308	return(z);
309}
310
311Cell *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
326Cell *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
337Cell *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
381Cell *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
434Cell *getnf(Node **a, int n)	/* get NF */
435{
436	if (donefld == 0)
437		fldbld();
438	return (Cell *) a[0];
439}
440
441Cell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
442{
443	Cell *x, *y, *z;
444	char *s;
445	Node *np;
446	char *buf;
447	int bufsz = recsize;
448	int nsub = strlen(*SUBSEP);
449
450	if ((buf = (char *) malloc(bufsz)) == NULL)
451		FATAL("out of memory in array");
452
453	x = execute(a[0]);	/* Cell* for symbol table */
454	buf[0] = 0;
455	for (np = a[1]; np; np = np->nnext) {
456		y = execute(np);	/* subscript */
457		s = getsval(y);
458		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
459			FATAL("out of memory for %s[%s...]", x->nval, buf);
460		strcat(buf, s);
461		if (np->nnext)
462			strcat(buf, *SUBSEP);
463		tempfree(y);
464	}
465	if (!isarr(x)) {
466		   dprintf( ("making %s into an array\n", NN(x->nval)) );
467		if (freeable(x))
468			xfree(x->sval);
469		x->tval &= ~(STR|NUM|DONTFREE);
470		x->tval |= ARR;
471		x->sval = (char *) makesymtab(NSYMTAB);
472	}
473	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
474	z->ctype = OCELL;
475	z->csub = CVAR;
476	tempfree(x);
477	free(buf);
478	return(z);
479}
480
481Cell *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
519Cell *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
561Cell *matchop(Node **a, int n)	/* ~ and match() */
562{
563	Cell *x, *y;
564	char *s, *t;
565	int i;
566	fa *pfa;
567	int (*mf)(fa *, const char *) = match, mode = 0;
568
569	if (n == MATCHFCN) {
570		mf = pmatch;
571		mode = 1;
572	}
573	x = execute(a[1]);	/* a[1] = target text */
574	s = getsval(x);
575	if (a[0] == 0)		/* a[1] == 0: already-compiled reg expr */
576		i = (*mf)((fa *) a[2], s);
577	else {
578		y = execute(a[2]);	/* a[2] = regular expr */
579		t = getsval(y);
580		pfa = makedfa(t, mode);
581		i = (*mf)(pfa, s);
582		tempfree(y);
583	}
584	tempfree(x);
585	if (n == MATCHFCN) {
586		int start = patbeg - s + 1;
587		if (patlen < 0)
588			start = 0;
589		setfval(rstartloc, (Awkfloat) start);
590		setfval(rlengthloc, (Awkfloat) patlen);
591		x = gettemp();
592		x->tval = NUM;
593		x->fval = start;
594		return x;
595	} else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
596		return(True);
597	else
598		return(False);
599}
600
601
602Cell *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
634Cell *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
669void tfree(Cell *a)	/* free a tempcell */
670{
671	if (freeable(a)) {
672		   dprintf( ("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval) );
673		xfree(a->sval);
674	}
675	if (a == tmps)
676		FATAL("tempcell list is curdled");
677	a->cnext = tmps;
678	tmps = a;
679}
680
681Cell *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
699Cell *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
717Cell *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
765Cell *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
793int format(char **pbuf, int *pbufsize, const char *s, Node *a)	/* printf-like conversions */
794{
795	char *fmt;
796	char *p, *t;
797	const char *os;
798	Cell *x;
799	int flag = 0, n;
800	int fmtwd; /* format width */
801	int fmtsz = recsize;
802	char *buf = *pbuf;
803	int bufsize = *pbufsize;
804
805	os = s;
806	p = buf;
807	if ((fmt = (char *) malloc(fmtsz)) == NULL)
808		FATAL("out of memory in format()");
809	while (*s) {
810		adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format");
811		if (*s != '%') {
812			*p++ = *s++;
813			continue;
814		}
815		if (*(s+1) == '%') {
816			*p++ = '%';
817			s += 2;
818			continue;
819		}
820		/* have to be real careful in case this is a huge number, eg, %100000d */
821		fmtwd = atoi(s+1);
822		if (fmtwd < 0)
823			fmtwd = -fmtwd;
824		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
825		for (t = fmt; (*t++ = *s) != '\0'; s++) {
826			if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0))
827				FATAL("format item %.30s... ran format() out of memory", os);
828			if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L')
829				break;	/* the ansi panoply */
830			if (*s == '*') {
831				x = execute(a);
832				a = a->nnext;
833				sprintf(t-1, "%d", fmtwd=(int) getfval(x));
834				if (fmtwd < 0)
835					fmtwd = -fmtwd;
836				adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
837				t = fmt + strlen(fmt);
838				tempfree(x);
839			}
840		}
841		*t = '\0';
842		if (fmtwd < 0)
843			fmtwd = -fmtwd;
844		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
845
846		switch (*s) {
847		case 'f': case 'e': case 'g': case 'E': case 'G':
848			flag = 'f';
849			break;
850		case 'd': case 'i':
851			flag = 'd';
852			if(*(s-1) == 'l') break;
853			*(t-1) = 'l';
854			*t = 'd';
855			*++t = '\0';
856			break;
857		case 'o': case 'x': case 'X': case 'u':
858			flag = *(s-1) == 'l' ? 'd' : 'u';
859			break;
860		case 's':
861			flag = 's';
862			break;
863		case 'c':
864			flag = 'c';
865			break;
866		default:
867			WARNING("weird printf conversion %s", fmt);
868			flag = '?';
869			break;
870		}
871		if (a == NULL)
872			FATAL("not enough args in printf(%s)", os);
873		x = execute(a);
874		a = a->nnext;
875		n = MAXNUMSIZE;
876		if (fmtwd > n)
877			n = fmtwd;
878		adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
879		switch (flag) {
880		case '?':	sprintf(p, "%s", fmt);	/* unknown, so dump it too */
881			t = getsval(x);
882			n = strlen(t);
883			if (fmtwd > n)
884				n = fmtwd;
885			adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
886			p += strlen(p);
887			sprintf(p, "%s", t);
888			break;
889		case 'f':	sprintf(p, fmt, getfval(x)); break;
890		case 'd':	sprintf(p, fmt, (long) getfval(x)); break;
891		case 'u':	sprintf(p, fmt, (int) getfval(x)); break;
892		case 's':
893			t = getsval(x);
894			n = strlen(t);
895			if (fmtwd > n)
896				n = fmtwd;
897			if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
898				FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
899			sprintf(p, fmt, t);
900			break;
901		case 'c':
902			if (isnum(x)) {
903				if (getfval(x))
904					sprintf(p, fmt, (int) getfval(x));
905				else {
906					*p++ = '\0'; /* explicit null byte */
907					*p = '\0';   /* next output will start here */
908				}
909			} else
910				sprintf(p, fmt, getsval(x)[0]);
911			break;
912		default:
913			FATAL("can't happen: bad conversion %c in format()", flag);
914		}
915		tempfree(x);
916		p += strlen(p);
917		s++;
918	}
919	*p = '\0';
920	free(fmt);
921	for ( ; a; a = a->nnext)		/* evaluate any remaining args */
922		execute(a);
923	*pbuf = buf;
924	*pbufsize = bufsize;
925	return p - buf;
926}
927
928Cell *awksprintf(Node **a, int n)		/* sprintf(a[0]) */
929{
930	Cell *x;
931	Node *y;
932	char *buf;
933	int bufsz=3*recsize;
934
935	if ((buf = (char *) malloc(bufsz)) == NULL)
936		FATAL("out of memory in awksprintf");
937	y = a[0]->nnext;
938	x = execute(a[0]);
939	if (format(&buf, &bufsz, getsval(x), y) == -1)
940		FATAL("sprintf string %.30s... too long.  can't happen.", buf);
941	tempfree(x);
942	x = gettemp();
943	x->sval = buf;
944	x->tval = STR;
945	return(x);
946}
947
948Cell *awkprintf(Node **a, int n)		/* printf */
949{	/* a[0] is list of args, starting with format string */
950	/* a[1] is redirection operator, a[2] is redirection file */
951	FILE *fp;
952	Cell *x;
953	Node *y;
954	char *buf;
955	int len;
956	int bufsz=3*recsize;
957
958	if ((buf = (char *) malloc(bufsz)) == NULL)
959		FATAL("out of memory in awkprintf");
960	y = a[0]->nnext;
961	x = execute(a[0]);
962	if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
963		FATAL("printf string %.30s... too long.  can't happen.", buf);
964	tempfree(x);
965	if (a[1] == NULL) {
966		/* fputs(buf, stdout); */
967		fwrite(buf, len, 1, stdout);
968		if (ferror(stdout))
969			FATAL("write error on stdout");
970	} else {
971		fp = redirect(ptoi(a[1]), a[2]);
972		/* fputs(buf, fp); */
973		fwrite(buf, len, 1, fp);
974		fflush(fp);
975		if (ferror(fp))
976			FATAL("write error on %s", filename(fp));
977	}
978	free(buf);
979	return(True);
980}
981
982Cell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
983{
984	Awkfloat i, j = 0;
985	double v;
986	Cell *x, *y, *z;
987
988	x = execute(a[0]);
989	i = getfval(x);
990	tempfree(x);
991	if (n != UMINUS) {
992		y = execute(a[1]);
993		j = getfval(y);
994		tempfree(y);
995	}
996	z = gettemp();
997	switch (n) {
998	case ADD:
999		i += j;
1000		break;
1001	case MINUS:
1002		i -= j;
1003		break;
1004	case MULT:
1005		i *= j;
1006		break;
1007	case DIVIDE:
1008		if (j == 0)
1009			FATAL("division by zero");
1010		i /= j;
1011		break;
1012	case MOD:
1013		if (j == 0)
1014			FATAL("division by zero in mod");
1015		modf(i/j, &v);
1016		i = i - j * v;
1017		break;
1018	case UMINUS:
1019		i = -i;
1020		break;
1021	case POWER:
1022		if (j >= 0 && modf(j, &v) == 0.0)	/* pos integer exponent */
1023			i = ipow(i, (int) j);
1024		else
1025			i = errcheck(pow(i, j), "pow");
1026		break;
1027	default:	/* can't happen */
1028		FATAL("illegal arithmetic operator %d", n);
1029	}
1030	setfval(z, i);
1031	return(z);
1032}
1033
1034double ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
1035{
1036	double v;
1037
1038	if (n <= 0)
1039		return 1;
1040	v = ipow(x, n/2);
1041	if (n % 2 == 0)
1042		return v * v;
1043	else
1044		return x * v * v;
1045}
1046
1047Cell *incrdecr(Node **a, int n)		/* a[0]++, etc. */
1048{
1049	Cell *x, *z;
1050	int k;
1051	Awkfloat xf;
1052
1053	x = execute(a[0]);
1054	xf = getfval(x);
1055	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1056	if (n == PREINCR || n == PREDECR) {
1057		setfval(x, xf + k);
1058		return(x);
1059	}
1060	z = gettemp();
1061	setfval(z, xf);
1062	setfval(x, xf + k);
1063	tempfree(x);
1064	return(z);
1065}
1066
1067Cell *assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
1068{		/* this is subtle; don't muck with it. */
1069	Cell *x, *y;
1070	Awkfloat xf, yf;
1071	double v;
1072
1073	y = execute(a[1]);
1074	x = execute(a[0]);
1075	if (n == ASSIGN) {	/* ordinary assignment */
1076		if (x == y && !(x->tval & (FLD|REC)))	/* self-assignment: */
1077			;		/* leave alone unless it's a field */
1078		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1079			setsval(x, getsval(y));
1080			x->fval = getfval(y);
1081			x->tval |= NUM;
1082		}
1083		else if (isstr(y))
1084			setsval(x, getsval(y));
1085		else if (isnum(y))
1086			setfval(x, getfval(y));
1087		else
1088			funnyvar(y, "read value of");
1089		tempfree(y);
1090		return(x);
1091	}
1092	xf = getfval(x);
1093	yf = getfval(y);
1094	switch (n) {
1095	case ADDEQ:
1096		xf += yf;
1097		break;
1098	case SUBEQ:
1099		xf -= yf;
1100		break;
1101	case MULTEQ:
1102		xf *= yf;
1103		break;
1104	case DIVEQ:
1105		if (yf == 0)
1106			FATAL("division by zero in /=");
1107		xf /= yf;
1108		break;
1109	case MODEQ:
1110		if (yf == 0)
1111			FATAL("division by zero in %%=");
1112		modf(xf/yf, &v);
1113		xf = xf - yf * v;
1114		break;
1115	case POWEQ:
1116		if (yf >= 0 && modf(yf, &v) == 0.0)	/* pos integer exponent */
1117			xf = ipow(xf, (int) yf);
1118		else
1119			xf = errcheck(pow(xf, yf), "pow");
1120		break;
1121	default:
1122		FATAL("illegal assignment operator %d", n);
1123		break;
1124	}
1125	tempfree(y);
1126	setfval(x, xf);
1127	return(x);
1128}
1129
1130Cell *cat(Node **a, int q)	/* a[0] cat a[1] */
1131{
1132	Cell *x, *y, *z;
1133	int n1, n2;
1134	char *s;
1135
1136	x = execute(a[0]);
1137	y = execute(a[1]);
1138	getsval(x);
1139	getsval(y);
1140	n1 = strlen(x->sval);
1141	n2 = strlen(y->sval);
1142	s = (char *) malloc(n1 + n2 + 1);
1143	if (s == NULL)
1144		FATAL("out of space concatenating %.15s... and %.15s...",
1145			x->sval, y->sval);
1146	strcpy(s, x->sval);
1147	strcpy(s+n1, y->sval);
1148	tempfree(y);
1149	z = gettemp();
1150	z->sval = s;
1151	z->tval = STR;
1152	tempfree(x);
1153	return(z);
1154}
1155
1156Cell *pastat(Node **a, int n)	/* a[0] { a[1] } */
1157{
1158	Cell *x;
1159
1160	if (a[0] == 0)
1161		x = execute(a[1]);
1162	else {
1163		x = execute(a[0]);
1164		if (istrue(x)) {
1165			tempfree(x);
1166			x = execute(a[1]);
1167		}
1168	}
1169	return x;
1170}
1171
1172Cell *dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
1173{
1174	Cell *x;
1175	int pair;
1176
1177	pair = ptoi(a[3]);
1178	if (pairstack[pair] == 0) {
1179		x = execute(a[0]);
1180		if (istrue(x))
1181			pairstack[pair] = 1;
1182		tempfree(x);
1183	}
1184	if (pairstack[pair] == 1) {
1185		x = execute(a[1]);
1186		if (istrue(x))
1187			pairstack[pair] = 0;
1188		tempfree(x);
1189		x = execute(a[2]);
1190		return(x);
1191	}
1192	return(False);
1193}
1194
1195Cell *split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
1196{
1197	Cell *x = 0, *y, *ap;
1198	char *s;
1199	int sep;
1200	char *t, temp, num[50], *fs = 0;
1201	int n, tempstat, arg3type;
1202
1203	y = execute(a[0]);	/* source string */
1204	s = getsval(y);
1205	arg3type = ptoi(a[3]);
1206	if (a[2] == 0)		/* fs string */
1207		fs = *FS;
1208	else if (arg3type == STRING) {	/* split(str,arr,"string") */
1209		x = execute(a[2]);
1210		fs = getsval(x);
1211	} else if (arg3type == REGEXPR)
1212		fs = "(regexpr)";	/* split(str,arr,/regexpr/) */
1213	else
1214		FATAL("illegal type of split");
1215	sep = *fs;
1216	ap = execute(a[1]);	/* array name */
1217	freesymtab(ap);
1218	   dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs) );
1219	ap->tval &= ~STR;
1220	ap->tval |= ARR;
1221	ap->sval = (char *) makesymtab(NSYMTAB);
1222
1223	n = 0;
1224	if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) {	/* reg expr */
1225		fa *pfa;
1226		if (arg3type == REGEXPR) {	/* it's ready already */
1227			pfa = (fa *) a[2];
1228		} else {
1229			pfa = makedfa(fs, 1);
1230		}
1231		if (nematch(pfa,s)) {
1232			tempstat = pfa->initstat;
1233			pfa->initstat = 2;
1234			do {
1235				n++;
1236				sprintf(num, "%d", n);
1237				temp = *patbeg;
1238				*patbeg = '\0';
1239				if (is_number(s))
1240					setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1241				else
1242					setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1243				*patbeg = temp;
1244				s = patbeg + patlen;
1245				if (*(patbeg+patlen-1) == 0 || *s == 0) {
1246					n++;
1247					sprintf(num, "%d", n);
1248					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1249					pfa->initstat = tempstat;
1250					goto spdone;
1251				}
1252			} while (nematch(pfa,s));
1253		}
1254		n++;
1255		sprintf(num, "%d", n);
1256		if (is_number(s))
1257			setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1258		else
1259			setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1260  spdone:
1261		pfa = NULL;
1262	} else if (sep == ' ') {
1263		for (n = 0; ; ) {
1264			while (*s == ' ' || *s == '\t' || *s == '\n')
1265				s++;
1266			if (*s == 0)
1267				break;
1268			n++;
1269			t = s;
1270			do
1271				s++;
1272			while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1273			temp = *s;
1274			*s = '\0';
1275			sprintf(num, "%d", n);
1276			if (is_number(t))
1277				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1278			else
1279				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1280			*s = temp;
1281			if (*s != 0)
1282				s++;
1283		}
1284	} else if (sep == 0) {	/* new: split(s, a, "") => 1 char/elem */
1285		for (n = 0; *s != 0; s++) {
1286			char buf[2];
1287			n++;
1288			sprintf(num, "%d", n);
1289			buf[0] = *s;
1290			buf[1] = 0;
1291			if (isdigit((uschar)buf[0]))
1292				setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1293			else
1294				setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1295		}
1296	} else if (*s != 0) {
1297		for (;;) {
1298			n++;
1299			t = s;
1300			while (*s != sep && *s != '\n' && *s != '\0')
1301				s++;
1302			temp = *s;
1303			*s = '\0';
1304			sprintf(num, "%d", n);
1305			if (is_number(t))
1306				setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1307			else
1308				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1309			*s = temp;
1310			if (*s++ == 0)
1311				break;
1312		}
1313	}
1314	tempfree(ap);
1315	tempfree(y);
1316	if (a[2] != 0 && arg3type == STRING) {
1317		tempfree(x);
1318	}
1319	x = gettemp();
1320	x->tval = NUM;
1321	x->fval = n;
1322	return(x);
1323}
1324
1325Cell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
1326{
1327	Cell *x;
1328
1329	x = execute(a[0]);
1330	if (istrue(x)) {
1331		tempfree(x);
1332		x = execute(a[1]);
1333	} else {
1334		tempfree(x);
1335		x = execute(a[2]);
1336	}
1337	return(x);
1338}
1339
1340Cell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
1341{
1342	Cell *x;
1343
1344	x = execute(a[0]);
1345	if (istrue(x)) {
1346		tempfree(x);
1347		x = execute(a[1]);
1348	} else if (a[2] != 0) {
1349		tempfree(x);
1350		x = execute(a[2]);
1351	}
1352	return(x);
1353}
1354
1355Cell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
1356{
1357	Cell *x;
1358
1359	for (;;) {
1360		x = execute(a[0]);
1361		if (!istrue(x))
1362			return(x);
1363		tempfree(x);
1364		x = execute(a[1]);
1365		if (isbreak(x)) {
1366			x = True;
1367			return(x);
1368		}
1369		if (isnext(x) || isexit(x) || isret(x))
1370			return(x);
1371		tempfree(x);
1372	}
1373}
1374
1375Cell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
1376{
1377	Cell *x;
1378
1379	for (;;) {
1380		x = execute(a[0]);
1381		if (isbreak(x))
1382			return True;
1383		if (isnext(x) || isexit(x) || isret(x))
1384			return(x);
1385		tempfree(x);
1386		x = execute(a[1]);
1387		if (!istrue(x))
1388			return(x);
1389		tempfree(x);
1390	}
1391}
1392
1393Cell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
1394{
1395	Cell *x;
1396
1397	x = execute(a[0]);
1398	tempfree(x);
1399	for (;;) {
1400		if (a[1]!=0) {
1401			x = execute(a[1]);
1402			if (!istrue(x)) return(x);
1403			else tempfree(x);
1404		}
1405		x = execute(a[3]);
1406		if (isbreak(x))		/* turn off break */
1407			return True;
1408		if (isnext(x) || isexit(x) || isret(x))
1409			return(x);
1410		tempfree(x);
1411		x = execute(a[2]);
1412		tempfree(x);
1413	}
1414}
1415
1416Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
1417{
1418	Cell *x, *vp, *arrayp, *cp, *ncp;
1419	Array *tp;
1420	int i;
1421
1422	vp = execute(a[0]);
1423	arrayp = execute(a[1]);
1424	if (!isarr(arrayp)) {
1425		return True;
1426	}
1427	tp = (Array *) arrayp->sval;
1428	tempfree(arrayp);
1429	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
1430		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1431			setsval(vp, cp->nval);
1432			ncp = cp->cnext;
1433			x = execute(a[2]);
1434			if (isbreak(x)) {
1435				tempfree(vp);
1436				return True;
1437			}
1438			if (isnext(x) || isexit(x) || isret(x)) {
1439				tempfree(vp);
1440				return(x);
1441			}
1442			tempfree(x);
1443		}
1444	}
1445	return True;
1446}
1447
1448Cell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
1449{
1450	Cell *x, *y;
1451	Awkfloat u;
1452	int t;
1453	char *p, *buf;
1454	Node *nextarg;
1455	FILE *fp;
1456	void flush_all(void);
1457
1458	t = ptoi(a[0]);
1459	x = execute(a[1]);
1460	nextarg = a[1]->nnext;
1461	switch (t) {
1462	case FLENGTH:
1463		if (isarr(x))
1464			u = ((Array *) x->sval)->nelem;	/* GROT.  should be function*/
1465		else
1466			u = strlen(getsval(x));
1467		break;
1468	case FLOG:
1469		u = errcheck(log(getfval(x)), "log"); break;
1470	case FINT:
1471		modf(getfval(x), &u); break;
1472	case FEXP:
1473		u = errcheck(exp(getfval(x)), "exp"); break;
1474	case FSQRT:
1475		u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1476	case FSIN:
1477		u = sin(getfval(x)); break;
1478	case FCOS:
1479		u = cos(getfval(x)); break;
1480	case FATAN:
1481		if (nextarg == 0) {
1482			WARNING("atan2 requires two arguments; returning 1.0");
1483			u = 1.0;
1484		} else {
1485			y = execute(a[1]->nnext);
1486			u = atan2(getfval(x), getfval(y));
1487			tempfree(y);
1488			nextarg = nextarg->nnext;
1489		}
1490		break;
1491	case FSYSTEM:
1492		fflush(stdout);		/* in case something is buffered already */
1493		u = (Awkfloat) system(getsval(x)) / 256;   /* 256 is unix-dep */
1494		break;
1495	case FRAND:
1496		/* in principle, rand() returns something in 0..RAND_MAX */
1497		u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1498		break;
1499	case FSRAND:
1500		if (isrec(x))	/* no argument provided */
1501			u = time((time_t *)0);
1502		else
1503			u = getfval(x);
1504		srand((unsigned int) u);
1505		break;
1506	case FTOUPPER:
1507	case FTOLOWER:
1508		buf = tostring(getsval(x));
1509		if (t == FTOUPPER) {
1510			for (p = buf; *p; p++)
1511				if (islower((uschar) *p))
1512					*p = toupper((uschar)*p);
1513		} else {
1514			for (p = buf; *p; p++)
1515				if (isupper((uschar) *p))
1516					*p = tolower((uschar)*p);
1517		}
1518		tempfree(x);
1519		x = gettemp();
1520		setsval(x, buf);
1521		free(buf);
1522		return x;
1523	case FFLUSH:
1524		if (isrec(x) || strlen(getsval(x)) == 0) {
1525			flush_all();	/* fflush() or fflush("") -> all */
1526			u = 0;
1527		} else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
1528			u = EOF;
1529		else
1530			u = fflush(fp);
1531		break;
1532	default:	/* can't happen */
1533		FATAL("illegal function type %d", t);
1534		break;
1535	}
1536	tempfree(x);
1537	x = gettemp();
1538	setfval(x, u);
1539	if (nextarg != 0) {
1540		WARNING("warning: function has too many arguments");
1541		for ( ; nextarg; nextarg = nextarg->nnext)
1542			execute(nextarg);
1543	}
1544	return(x);
1545}
1546
1547Cell *printstat(Node **a, int n)	/* print a[0] */
1548{
1549	Node *x;
1550	Cell *y;
1551	FILE *fp;
1552
1553	if (a[1] == 0)	/* a[1] is redirection operator, a[2] is file */
1554		fp = stdout;
1555	else
1556		fp = redirect(ptoi(a[1]), a[2]);
1557	for (x = a[0]; x != NULL; x = x->nnext) {
1558		y = execute(x);
1559		fputs(getpssval(y), fp);
1560		tempfree(y);
1561		if (x->nnext == NULL)
1562			fputs(*ORS, fp);
1563		else
1564			fputs(*OFS, fp);
1565	}
1566	if (a[1] != 0)
1567		fflush(fp);
1568	if (ferror(fp))
1569		FATAL("write error on %s", filename(fp));
1570	return(True);
1571}
1572
1573Cell *nullproc(Node **a, int n)
1574{
1575	n = n;
1576	a = a;
1577	return 0;
1578}
1579
1580
1581FILE *redirect(int a, Node *b)	/* set up all i/o redirections */
1582{
1583	FILE *fp;
1584	Cell *x;
1585	char *fname;
1586
1587	x = execute(b);
1588	fname = getsval(x);
1589	fp = openfile(a, fname);
1590	if (fp == NULL)
1591		FATAL("can't open file %s", fname);
1592	tempfree(x);
1593	return fp;
1594}
1595
1596struct files {
1597	FILE	*fp;
1598	const char	*fname;
1599	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
1600} files[FOPEN_MAX] ={
1601	{ NULL,  "/dev/stdin",  LT },	/* watch out: don't free this! */
1602	{ NULL, "/dev/stdout", GT },
1603	{ NULL, "/dev/stderr", GT }
1604};
1605
1606void stdinit(void)	/* in case stdin, etc., are not constants */
1607{
1608	files[0].fp = stdin;
1609	files[1].fp = stdout;
1610	files[2].fp = stderr;
1611}
1612
1613FILE *openfile(int a, const char *us)
1614{
1615	const char *s = us;
1616	int i, m;
1617	FILE *fp = 0;
1618
1619	if (*s == '\0')
1620		FATAL("null file name in print or getline");
1621	for (i=0; i < FOPEN_MAX; i++)
1622		if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1623			if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1624				return files[i].fp;
1625			if (a == FFLUSH)
1626				return files[i].fp;
1627		}
1628	if (a == FFLUSH)	/* didn't find it, so don't create it! */
1629		return NULL;
1630
1631	for (i=0; i < FOPEN_MAX; i++)
1632		if (files[i].fp == 0)
1633			break;
1634	if (i >= FOPEN_MAX)
1635		FATAL("%s makes too many open files", s);
1636	fflush(stdout);	/* force a semblance of order */
1637	m = a;
1638	if (a == GT) {
1639		fp = fopen(s, "w");
1640	} else if (a == APPEND) {
1641		fp = fopen(s, "a");
1642		m = GT;	/* so can mix > and >> */
1643	} else if (a == '|') {	/* output pipe */
1644		fp = popen(s, "w");
1645	} else if (a == LE) {	/* input pipe */
1646		fp = popen(s, "r");
1647	} else if (a == LT) {	/* getline <file */
1648		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
1649	} else	/* can't happen */
1650		FATAL("illegal redirection %d", a);
1651	if (fp != NULL) {
1652		files[i].fname = tostring(s);
1653		files[i].fp = fp;
1654		files[i].mode = m;
1655	}
1656	return fp;
1657}
1658
1659const char *filename(FILE *fp)
1660{
1661	int i;
1662
1663	for (i = 0; i < FOPEN_MAX; i++)
1664		if (fp == files[i].fp)
1665			return files[i].fname;
1666	return "???";
1667}
1668
1669Cell *closefile(Node **a, int n)
1670{
1671	Cell *x;
1672	int i, stat;
1673
1674	n = n;
1675	x = execute(a[0]);
1676	getsval(x);
1677	stat = -1;
1678	for (i = 0; i < FOPEN_MAX; i++) {
1679		if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1680			if (ferror(files[i].fp))
1681				WARNING( "i/o error occurred on %s", files[i].fname );
1682			if (files[i].mode == '|' || files[i].mode == LE)
1683				stat = pclose(files[i].fp);
1684			else
1685				stat = fclose(files[i].fp);
1686			if (stat == EOF)
1687				WARNING( "i/o error occurred closing %s", files[i].fname );
1688			if (i > 2)	/* don't do /dev/std... */
1689				xfree(files[i].fname);
1690			files[i].fname = NULL;	/* watch out for ref thru this */
1691			files[i].fp = NULL;
1692		}
1693	}
1694	tempfree(x);
1695	x = gettemp();
1696	setfval(x, (Awkfloat) stat);
1697	return(x);
1698}
1699
1700void closeall(void)
1701{
1702	int i, stat;
1703
1704	for (i = 0; i < FOPEN_MAX; i++) {
1705		if (files[i].fp) {
1706			if (ferror(files[i].fp))
1707				WARNING( "i/o error occurred on %s", files[i].fname );
1708			if (files[i].mode == '|' || files[i].mode == LE)
1709				stat = pclose(files[i].fp);
1710			else
1711				stat = fclose(files[i].fp);
1712			if (stat == EOF)
1713				WARNING( "i/o error occurred while closing %s", files[i].fname );
1714		}
1715	}
1716}
1717
1718void flush_all(void)
1719{
1720	int i;
1721
1722	for (i = 0; i < FOPEN_MAX; i++)
1723		if (files[i].fp)
1724			fflush(files[i].fp);
1725}
1726
1727void backsub(char **pb_ptr, char **sptr_ptr);
1728
1729Cell *sub(Node **a, int nnn)	/* substitute command */
1730{
1731	char *sptr, *pb, *q;
1732	Cell *x, *y, *result;
1733	char *t, *buf;
1734	fa *pfa;
1735	int bufsz = recsize;
1736
1737	if ((buf = (char *) malloc(bufsz)) == NULL)
1738		FATAL("out of memory in sub");
1739	x = execute(a[3]);	/* target string */
1740	t = getsval(x);
1741	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
1742		pfa = (fa *) a[1];	/* regular expression */
1743	else {
1744		y = execute(a[1]);
1745		pfa = makedfa(getsval(y), 1);
1746		tempfree(y);
1747	}
1748	y = execute(a[2]);	/* replacement string */
1749	result = False;
1750	if (pmatch(pfa, t)) {
1751		sptr = t;
1752		adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1753		pb = buf;
1754		while (sptr < patbeg)
1755			*pb++ = *sptr++;
1756		sptr = getsval(y);
1757		while (*sptr != 0) {
1758			adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1759			if (*sptr == '\\') {
1760				backsub(&pb, &sptr);
1761			} else if (*sptr == '&') {
1762				sptr++;
1763				adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1764				for (q = patbeg; q < patbeg+patlen; )
1765					*pb++ = *q++;
1766			} else
1767				*pb++ = *sptr++;
1768		}
1769		*pb = '\0';
1770		if (pb > buf + bufsz)
1771			FATAL("sub result1 %.30s too big; can't happen", buf);
1772		sptr = patbeg + patlen;
1773		if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1774			adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1775			while ((*pb++ = *sptr++) != 0)
1776				;
1777		}
1778		if (pb > buf + bufsz)
1779			FATAL("sub result2 %.30s too big; can't happen", buf);
1780		setsval(x, buf);	/* BUG: should be able to avoid copy */
1781		result = True;;
1782	}
1783	tempfree(x);
1784	tempfree(y);
1785	free(buf);
1786	return result;
1787}
1788
1789Cell *gsub(Node **a, int nnn)	/* global substitute */
1790{
1791	Cell *x, *y;
1792	char *rptr, *sptr, *t, *pb, *q;
1793	char *buf;
1794	fa *pfa;
1795	int mflag, tempstat, num;
1796	int bufsz = recsize;
1797
1798	if ((buf = (char *) malloc(bufsz)) == NULL)
1799		FATAL("out of memory in gsub");
1800	mflag = 0;	/* if mflag == 0, can replace empty string */
1801	num = 0;
1802	x = execute(a[3]);	/* target string */
1803	t = getsval(x);
1804	if (a[0] == 0)		/* 0 => a[1] is already-compiled regexpr */
1805		pfa = (fa *) a[1];	/* regular expression */
1806	else {
1807		y = execute(a[1]);
1808		pfa = makedfa(getsval(y), 1);
1809		tempfree(y);
1810	}
1811	y = execute(a[2]);	/* replacement string */
1812	if (pmatch(pfa, t)) {
1813		tempstat = pfa->initstat;
1814		pfa->initstat = 2;
1815		pb = buf;
1816		rptr = getsval(y);
1817		do {
1818			if (patlen == 0 && *patbeg != 0) {	/* matched empty string */
1819				if (mflag == 0) {	/* can replace empty */
1820					num++;
1821					sptr = rptr;
1822					while (*sptr != 0) {
1823						adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1824						if (*sptr == '\\') {
1825							backsub(&pb, &sptr);
1826						} else if (*sptr == '&') {
1827							sptr++;
1828							adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1829							for (q = patbeg; q < patbeg+patlen; )
1830								*pb++ = *q++;
1831						} else
1832							*pb++ = *sptr++;
1833					}
1834				}
1835				if (*t == 0)	/* at end */
1836					goto done;
1837				adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1838				*pb++ = *t++;
1839				if (pb > buf + bufsz)	/* BUG: not sure of this test */
1840					FATAL("gsub result0 %.30s too big; can't happen", buf);
1841				mflag = 0;
1842			}
1843			else {	/* matched nonempty string */
1844				num++;
1845				sptr = t;
1846				adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
1847				while (sptr < patbeg)
1848					*pb++ = *sptr++;
1849				sptr = rptr;
1850				while (*sptr != 0) {
1851					adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1852					if (*sptr == '\\') {
1853						backsub(&pb, &sptr);
1854					} else if (*sptr == '&') {
1855						sptr++;
1856						adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1857						for (q = patbeg; q < patbeg+patlen; )
1858							*pb++ = *q++;
1859					} else
1860						*pb++ = *sptr++;
1861				}
1862				t = patbeg + patlen;
1863				if (patlen == 0 || *t == 0 || *(t-1) == 0)
1864					goto done;
1865				if (pb > buf + bufsz)
1866					FATAL("gsub result1 %.30s too big; can't happen", buf);
1867				mflag = 1;
1868			}
1869		} while (pmatch(pfa,t));
1870		sptr = t;
1871		adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
1872		while ((*pb++ = *sptr++) != 0)
1873			;
1874	done:	if (pb > buf + bufsz)
1875			FATAL("gsub result2 %.30s too big; can't happen", buf);
1876		*pb = '\0';
1877		setsval(x, buf);	/* BUG: should be able to avoid copy + free */
1878		pfa->initstat = tempstat;
1879	}
1880	tempfree(x);
1881	tempfree(y);
1882	x = gettemp();
1883	x->tval = NUM;
1884	x->fval = num;
1885	free(buf);
1886	return(x);
1887}
1888
1889void backsub(char **pb_ptr, char **sptr_ptr)	/* handle \\& variations */
1890{						/* sptr[0] == '\\' */
1891	char *pb = *pb_ptr, *sptr = *sptr_ptr;
1892
1893	if (sptr[1] == '\\') {
1894		if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
1895			*pb++ = '\\';
1896			*pb++ = '&';
1897			sptr += 4;
1898		} else if (sptr[2] == '&') {	/* \\& -> \ + matched */
1899			*pb++ = '\\';
1900			sptr += 2;
1901		} else {			/* \\x -> \\x */
1902			*pb++ = *sptr++;
1903			*pb++ = *sptr++;
1904		}
1905	} else if (sptr[1] == '&') {	/* literal & */
1906		sptr++;
1907		*pb++ = *sptr++;
1908	} else				/* literal \ */
1909		*pb++ = *sptr++;
1910
1911	*pb_ptr = pb;
1912	*sptr_ptr = sptr;
1913}
1914