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