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