xref: /illumos-gate/usr/src/cmd/oawk/run.c (revision 125be069be21bcb7b94bd4525c19eb424bc56276)
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 2009 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 #define	DEBUG
31 #define	tempfree(a)	{if (istemp(a)) {xfree(a->sval); a->tval = 0; }}
32 
33 #include	"awk.def"
34 #include	"math.h"
35 #include	"awk.h"
36 #include	"stdio.h"
37 #include "ctype.h"
38 #include "wctype.h"
39 #include "awktype.h"
40 #include <stdlib.h>
41 
42 #define	RECSIZE BUFSIZ
43 
44 #define	FILENUM	10
45 struct
46 {
47 	FILE *fp;
48 	int type;
49 	wchar_t *fname;
50 } files[FILENUM];
51 FILE *popen();
52 
53 extern CELL *execute(), *nodetoobj(), *fieldel(), *dopa2(), *gettemp();
54 
55 #define	PA2NUM	29
56 int	pairstack[PA2NUM], paircnt;
57 NODE	*winner = NULL;
58 #define	MAXTMP	20
59 CELL	tmps[MAXTMP];
60 
61 static CELL	truecell	={ OBOOL, BTRUE, 0, 0, 0.0, NUM, 0 };
62 CELL	*true	= &truecell;
63 static CELL	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM, 0 };
64 CELL	*false	= &falsecell;
65 static CELL	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM, 0 };
66 CELL	*jbreak	= &breakcell;
67 static CELL	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM, 0 };
68 CELL	*jcont	= &contcell;
69 static CELL	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM, 0 };
70 CELL	*jnext	= &nextcell;
71 static CELL	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM, 0 };
72 CELL	*jexit	= &exitcell;
73 static CELL	tempcell	={ OCELL, CTEMP, 0, 0, 0.0, NUM, 0 };
74 
75 static void redirprint(wchar_t *s, int a, NODE *b);
76 
77 void freesymtab(CELL *ap);
78 void fldbld(void);
79 
80 void
81 run(NODE *a)
82 {
83 	int i;
84 
85 	execute(a);
86 	/* Wait for children to complete if output to a pipe. */
87 	for (i=0; i<FILENUM; i++)
88 		if (files[i].fp && files[i].type == '|')
89 			pclose(files[i].fp);
90 }
91 
92 
93 CELL *
94 execute(NODE *u)
95 {
96 	CELL *(*proc)();
97 	CELL *x;
98 	NODE *a;
99 
100 	if (u == NULL)
101 		return (true);
102 	for (a = u; /* dummy */; a = a->nnext) {
103 		if (cantexec(a))
104 			return (nodetoobj(a));
105 		if (notlegal(a->nobj))
106 			error(FATAL, "illegal statement %o", a);
107 		proc = proctab[a->nobj-FIRSTTOKEN];
108 		x = (*proc)(a->narg, a->nobj);
109 		if (isfld(x))
110 			fldbld();
111 		if (isexpr(a))
112 			return (x);
113 		/* a statement, goto next statement */
114 		if (isjump(x))
115 			return (x);
116 		if (a->nnext == (NODE *)NULL)
117 			return (x);
118 		tempfree(x);
119 	}
120 }
121 
122 
123 
124 
125 CELL *
126 program(NODE **a, int n)
127 {
128 	CELL *x;
129 
130 	if (a[0] != NULL) {
131 		x = execute(a[0]);
132 		if (isexit(x))
133 			return (true);
134 		if (isjump(x))
135 			error(FATAL, "unexpected break, continue or next");
136 		tempfree(x);
137 	}
138 	while (getrec()) {
139 		x = execute(a[1]);
140 		if (isexit(x)) {
141 			tempfree(x);
142 			break;
143 		}
144 		tempfree(x);
145 	}
146 	if (a[2] != NULL) {
147 		x = execute(a[2]);
148 		if (isbreak(x) || isnext(x) || iscont(x))
149 			error(FATAL, "unexpected break, continue or next");
150 		tempfree(x);
151 	}
152 	return (true);
153 }
154 
155 
156 
157 
158 CELL *
159 getline(void)
160 {
161 	CELL *x;
162 
163 	x = gettemp();
164 	setfval(x, (awkfloat) getrec());
165 	return (x);
166 }
167 
168 
169 
170 
171 CELL *
172 array(NODE **a, int n)
173 {
174 	CELL *x, *y;
175 	extern CELL *arrayel();
176 
177 	x = execute(a[1]);
178 	y = arrayel(a[0], x);
179 	tempfree(x);
180 	return (y);
181 }
182 
183 
184 
185 
186 CELL *
187 arrayel(NODE *a, CELL *b)
188 {
189 	wchar_t *s;
190 	CELL *x;
191 	int i;
192 	CELL *y;
193 
194 	s = getsval(b);
195 	x = (CELL *) a;
196 	if (!(x->tval&ARR)) {
197 		xfree(x->sval);
198 		x->tval &= ~STR;
199 		x->tval |= ARR;
200 		x->sval = (wchar_t *) makesymtab();
201 	}
202 	y = setsymtab(s, tostring(L_NULL), 0.0, STR|NUM, x->sval);
203 	y->ctype = OCELL;
204 	y->csub = CVAR;
205 	return (y);
206 }
207 
208 CELL *
209 matchop(NODE **a, int n)
210 {
211 	CELL *x;
212 	wchar_t *s;
213 	int i;
214 
215 	x = execute(a[0]);
216 	s = getsval(x);
217 	tempfree(x);
218 	i = match(a[1], s);
219 	if (n == MATCH && i == 1 || n == NOTMATCH && i == 0)
220 		return (true);
221 	else
222 		return (false);
223 }
224 
225 
226 
227 
228 CELL *
229 boolop(NODE **a, int n)
230 {
231 	CELL *x, *y;
232 	int i;
233 
234 
235 
236 
237 	x = execute(a[0]);
238 	i = istrue(x);
239 	tempfree(x);
240 	switch (n) {
241 	case BOR:
242 		if (i) return (true);
243 		y = execute(a[1]);
244 		i = istrue(y);
245 		tempfree(y);
246 		if (i) return (true);
247 		else return (false);
248 	case AND:
249 		if (!i) return (false);
250 		y = execute(a[1]);
251 		i = istrue(y);
252 		tempfree(y);
253 		if (i) return (true);
254 		else return (false);
255 	case NOT:
256 		if (i) return (false);
257 		else return (true);
258 	default:
259 		error(FATAL, "unknown boolean operator %d", n);
260 	}
261 	return (false);
262 }
263 
264 
265 
266 
267 CELL *
268 relop(NODE **a, int n)
269 {
270 	int i;
271 	CELL *x, *y;
272 	awkfloat j;
273 	wchar_t *xs, *ys;
274 
275 
276 
277 
278 	x = execute(a[0]);
279 	y = execute(a[1]);
280 	if (x->tval&NUM && y->tval&NUM) {
281 		j = x->fval - y->fval;
282 		i = j<0? -1: (j>0? 1: 0);
283 	} else {
284 		xs = getsval(x);
285 		ys = getsval(y);
286 		if (xs && ys)
287 			i = wscoll(xs, ys);
288 		else
289 			return (false);
290 	}
291 	tempfree(x);
292 	tempfree(y);
293 	switch (n) {
294 	case LT:	if (i<0) return (true);
295 			else return (false);
296 	case LE:	if (i<=0) return (true);
297 			else return (false);
298 	case NE:	if (i!=0) return (true);
299 			else return (false);
300 	case EQ:	if (i == 0) return (true);
301 			else return (false);
302 	case GE:	if (i>=0) return (true);
303 			else return (false);
304 	case GT:	if (i>0) return (true);
305 			else return (false);
306 	default:
307 		error(FATAL, "unknown relational operator %d", n);
308 	}
309 	return (false);
310 }
311 
312 
313 
314 
315 
316 
317 
318 
319 CELL *
320 gettemp(void)
321 {
322 	int i;
323 	CELL *x;
324 
325 
326 
327 
328 	for (i=0; i<MAXTMP; i++)
329 		if (tmps[i].tval == 0)
330 			break;
331 	if (i == MAXTMP)
332 		error(FATAL, "out of temporaries in gettemp");
333 	tmps[i] = tempcell;
334 	x = &tmps[i];
335 	return (x);
336 }
337 
338 
339 
340 
341 CELL *
342 indirect(NODE **a, int n)
343 {
344 	CELL *x;
345 	int m;
346 	CELL *fieldadr();
347 
348 	x = execute(a[0]);
349 	m = getfval(x);
350 	tempfree(x);
351 	x = fieldadr(m);
352 	x->ctype = OCELL;
353 	x->csub = CFLD;
354 	return (x);
355 }
356 
357 
358 
359 
360 CELL *
361 substr(NODE **a, int nnn)
362 {
363 	int k, m, n;
364 	wchar_t *s, temp;
365 	CELL *x, *y;
366 
367 	y = execute(a[0]);
368 	s = getsval(y);
369 	k = wslen(s) + 1;
370 	if (k <= 1) {
371 		x = gettemp();
372 		setsval(x, L_NULL);
373 		return (x);
374 	}
375 	x = execute(a[1]);
376 	m = getfval(x);
377 	if (m <= 0)
378 		m = 1;
379 	else if (m > k)
380 		m = k;
381 	tempfree(x);
382 	if (a[2] != 0) {
383 		x = execute(a[2]);
384 		n = getfval(x);
385 		tempfree(x);
386 	}
387 	else
388 		n = k - 1;
389 	if (n < 0)
390 		n = 0;
391 	else if (n > k - m)
392 		n = k - m;
393 	dprintf("substr: m=%d, n=%d, s=%ws\n", m, n, s);
394 	x = gettemp();
395 	temp = s[n+m-1];
396 	s[n+m-1] = (wchar_t)0x0;
397 	setsval(x, s + m - 1);
398 	s[n+m-1] = temp;
399 	tempfree(y);
400 	return (x);
401 }
402 
403 
404 
405 
406 CELL *
407 sindex(NODE **a, int nnn)
408 {
409 	CELL *x;
410 	wchar_t *s1, *s2, *p1, *p2, *q;
411 
412 	x = execute(a[0]);
413 	s1 = getsval(x);
414 	tempfree(x);
415 	x = execute(a[1]);
416 	s2 = getsval(x);
417 	tempfree(x);
418 
419 	x = gettemp();
420 	for (p1 = s1; *p1 != (wchar_t)0x0; p1++) {
421 		for (q=p1, p2=s2; *p2 != (wchar_t)0x0 && *q == *p2; q++, p2++)
422 			;
423 		if (*p2 == (wchar_t)0x0) {
424 			setfval(x, (awkfloat) (p1 - s1 + 1));	/* origin 1 */
425 			return (x);
426 		}
427 	}
428 	setfval(x, 0.0);
429 	return (x);
430 }
431 
432 
433 
434 
435 wchar_t *
436 format(wchar_t *s, NODE *a)
437 {
438 	wchar_t *buf, *ep, *str;
439 	wchar_t *p;
440 	char *t;
441 	wchar_t *os;
442 	wchar_t tbuf[2*RECSIZE];
443 	char fmt[200];
444 	CELL *x;
445 	int flag = 0;
446 	awkfloat xf;
447 
448 	os = s;
449 	p = buf= (wchar_t *)malloc(RECSIZE * sizeof (wchar_t));
450 
451 	if (p == NULL)
452 		error(FATAL, "out of space in format");
453 	ep = p + RECSIZE;
454 	while (*s) {
455 		if (*s != '%') {
456 			*p++ = *s++;
457 			continue;
458 		}
459 		if (*(s+1) == '%') {
460 			*p++ = '%';
461 			s += 2;
462 			continue;
463 		}
464 		for (t=fmt; *s != '\0'; s++)
465 		{
466 			if (*s == 's' || *s == 'c')
467 				*t++ = 'w';
468 			*t++ = *s;
469 			if (*s >= 'a' && *s <= 'z' && *s != 'l')
470 				break;
471 			if (*s == '*') {
472 				if (a == NULL) {
473 					error(FATAL,
474 			"not enough arguments in printf(%ws) or sprintf(%ws)",
475 					os, os);
476 				}
477 				x = execute(a);
478 				a = a->nnext;
479 				sprintf(t-1, "%d", (int) getfval(x));
480 				t = fmt + strlen(fmt);
481 				tempfree(x);
482 			}
483 
484 		}
485 		*t = '\0';
486 		if (t >= fmt + sizeof (fmt))
487 			error(FATAL, "format item %.20ws... too long", os);
488 		switch (*s) {
489 		case 'f': case 'e': case 'g':
490 			flag = 1;
491 			break;
492 		case 'd':
493 			flag = 2;
494 			if (*(s-1) == 'l') break;
495 			*(t-1) = 'l';
496 			*t = 'd';
497 			*++t = '\0';
498 			break;
499 		case 'o': case 'x':
500 			flag = *(s-1) == 'l' ? 2 : 3;
501 			break;
502 		case 'c':
503 			flag = 3;
504 			break;
505 		case 's':
506 			flag = 4;
507 			break;
508 		default:
509 			flag = 0;
510 			break;
511 		}
512 		if (flag == 0) {
513 			wsprintf(p, "%s", fmt);
514 			p += wslen(p);
515 			continue;
516 		}
517 		if (a == NULL) {
518 			error(FATAL,
519 	"not enough arguments in printf(%ws) or sprintf(%ws)", os, os);
520 		}
521 		x = execute(a);
522 		a = a->nnext;
523 
524 		/*
525 		 * Get the string to check length; %s is the usual problem;
526 		 * other conversions can cause overrun if they occur when
527 		 * the buffer is almost filled.
528 		 */
529 		if (flag == 4)	{ /* watch out for converting to numbers! */
530 			str = getsval(x);
531 		}
532 		else {
533 			xf = getfval(x);
534 			if (flag == 1) wsprintf(tbuf, fmt, xf);
535 			else if (flag == 2) wsprintf(tbuf, fmt, (long)xf);
536 			else if (flag == 3) wsprintf(tbuf, fmt, (int)xf);
537 			if (wslen(tbuf) >= RECSIZE)
538 				error(FATAL, "formatted item %s... too long",
539 						tbuf);
540 			str = tbuf;
541 		}
542 		/*
543 		 * If string overruns the buffer, reallocate;
544 		 * consider length of format string
545 		 */
546 		if (p + wslen(str) + wslen(s) + 1 >= ep) {
547 			int newlen, oldlen;
548 
549 			oldlen = p - buf;
550 			/* Add RECSIZE for additional space */
551 			newlen = oldlen + wslen(str) + RECSIZE;
552 			buf = realloc(buf, (unsigned) newlen * sizeof(wchar_t));
553 			if (buf == NULL)
554 				error(FATAL, "out of format space");
555 			p = buf + oldlen;
556 			ep = buf + newlen;
557 		}
558 		/* Transfer string to buffer */
559 		if (flag == 4)
560 			wsprintf(p, fmt, str);
561 		else
562 			wscpy(p, str);
563 
564 		tempfree(x);
565 		p += wslen(p);
566 		if (p >= ep)
567 			error(FATAL, "formatted string too long");
568 		s++;
569 	}
570 	*p = '\0';
571 	return (buf);
572 }
573 
574 
575 CELL *
576 a_sprintf(NODE **a, int n)
577 {
578 	CELL *x;
579 	NODE *y;
580 	wchar_t *s;
581 
582 	y = a[0]->nnext;
583 	x = execute(a[0]);
584 	s = format(getsval(x), y);
585 	tempfree(x);
586 	x = gettemp();
587 	x->sval = s;
588 	x->tval = STR;
589 	return (x);
590 }
591 
592 
593 CELL *
594 arith(NODE **a, int n)
595 {
596 	awkfloat i, j;
597 	CELL *x, *y, *z;
598 
599 	x = execute(a[0]);
600 	i = getfval(x);
601 	tempfree(x);
602 	if (n != UMINUS) {
603 		y = execute(a[1]);
604 		j = getfval(y);
605 		tempfree(y);
606 	}
607 	z = gettemp();
608 	switch (n) {
609 	case ADD:
610 		i += j;
611 		break;
612 	case MINUS:
613 		i -= j;
614 		break;
615 	case MULT:
616 		i *= j;
617 		break;
618 	case DIVIDE:
619 		if (j == 0)
620 			error(FATAL, "division by zero");
621 		i /= j;
622 		break;
623 	case MOD:
624 		if (j == 0)
625 			error(FATAL, "division by zero");
626 		i = i - j*(long)(i/j);
627 		break;
628 	case UMINUS:
629 		i = -i;
630 		break;
631 	default:
632 		error(FATAL, "illegal arithmetic operator %d", n);
633 	}
634 	setfval(z, i);
635 	return (z);
636 }
637 
638 
639 
640 
641 CELL *
642 incrdecr(NODE **a, int n)
643 {
644 	CELL *x, *z;
645 	int k;
646 	awkfloat xf;
647 
648 	x = execute(a[0]);
649 	xf = getfval(x);
650 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
651 	if (n == PREINCR || n == PREDECR) {
652 		setfval(x, xf + k);
653 		return (x);
654 	}
655 	z = gettemp();
656 	setfval(z, xf);
657 	setfval(x, xf + k);
658 	tempfree(x);
659 	return (z);
660 }
661 
662 
663 
664 CELL *
665 assign(NODE **a, int n)
666 {
667 	CELL *x, *y;
668 	awkfloat xf, yf;
669 
670 
671 
672 
673 	x = execute(a[0]);
674 	y = execute(a[1]);
675 	if (n == ASSIGN) {	/* ordinary assignment */
676 		if ((y->tval & (STR|NUM)) == (STR|NUM)) {
677 			setsval(x, y->sval);
678 			x->fval = y->fval;
679 			x->tval |= NUM;
680 
681 		} else if (y->tval & STR)
682 			setsval(x, y->sval);
683 		else if (y->tval & NUM)
684 			setfval(x, y->fval);
685 		tempfree(y);
686 		return (x);
687 	}
688 	xf = getfval(x);
689 	yf = getfval(y);
690 	switch (n) {
691 	case ADDEQ:
692 		xf += yf;
693 		break;
694 	case SUBEQ:
695 		xf -= yf;
696 		break;
697 	case MULTEQ:
698 		xf *= yf;
699 		break;
700 	case DIVEQ:
701 		if (yf == 0)
702 			error(FATAL, "division by zero");
703 		xf /= yf;
704 		break;
705 	case MODEQ:
706 		if (yf == 0)
707 			error(FATAL, "division by zero");
708 		xf = xf - yf*(long)(xf/yf);
709 		break;
710 	default:
711 		error(FATAL, "illegal assignment operator %d", n);
712 		break;
713 	}
714 	tempfree(y);
715 	setfval(x, xf);
716 	return (x);
717 }
718 
719 
720 
721 
722 CELL *
723 cat(NODE **a, int q)
724 {
725 	CELL *x, *y, *z;
726 	int n1, n2;
727 	wchar_t *s;
728 
729 
730 
731 
732 	x = execute(a[0]);
733 	y = execute(a[1]);
734 	getsval(x);
735 	getsval(y);
736 	n1 = wslen(x->sval);
737 	n2 = wslen(y->sval);
738 	if ((s = (wchar_t *) malloc((n1 + n2 + 1) * sizeof (wchar_t))) == NULL)
739 		error(FATAL, "out of space in cat");
740 	wscpy(s, x->sval);
741 	wscpy(s+n1, y->sval);
742 	tempfree(y);
743 	z = gettemp();
744 	z->sval = s;
745 	z->tval = STR;
746 	tempfree(x);
747 	return (z);
748 }
749 
750 
751 
752 
753 CELL *
754 pastat(NODE **a, int n)
755 {
756 	CELL *x;
757 
758 
759 
760 
761 	if (a[0] == 0)
762 		x = true;
763 	else
764 		x = execute(a[0]);
765 	if (istrue(x)) {
766 		tempfree(x);
767 		x = execute(a[1]);
768 	}
769 	return (x);
770 }
771 
772 
773 
774 
775 CELL *
776 dopa2(NODE **a, int n)
777 {
778 	CELL *x;
779 	int pair;
780 
781 
782 
783 
784 	pair = (int) a[3];
785 	if (pairstack[pair] == 0) {
786 		x = execute(a[0]);
787 		if (istrue(x))
788 			pairstack[pair] = 1;
789 		tempfree(x);
790 	}
791 	if (pairstack[pair] == 1) {
792 		x = execute(a[1]);
793 		if (istrue(x))
794 			pairstack[pair] = 0;
795 		tempfree(x);
796 		x = execute(a[2]);
797 		return (x);
798 	}
799 	return (false);
800 }
801 
802 
803 
804 
805 CELL *
806 aprintf(NODE **a, int n)
807 {
808 	CELL *x;
809 
810 
811 
812 
813 	x = a_sprintf(a, n);
814 	if (a[1] == NULL) {
815 		printf("%ws", x->sval);
816 		tempfree(x);
817 		return (true);
818 	}
819 	redirprint(x->sval, (int)a[1], a[2]);
820 	return (x);
821 }
822 
823 
824 
825 
826 CELL *
827 split(NODE **a, int nnn)
828 {
829 	CELL *x;
830 	CELL *ap;
831 	wchar_t *s, *p, c;
832 	wchar_t *t, temp, num[5];
833 	wchar_t sep;
834 	int n, flag;
835 
836 
837 
838 
839 	x = execute(a[0]);
840 	s = getsval(x);
841 	tempfree(x);
842 	if (a[2] == 0)
843 		sep = **FS;
844 	else {
845 		x = execute(a[2]);
846 		sep = getsval(x)[0];
847 		tempfree(x);
848 	}
849 	ap = (CELL *) a[1];
850 	freesymtab(ap);
851 	dprintf("split: s=|%ws|, a=%ws, sep=|%wc|\n", s, ap->nval, sep);
852 	ap->tval &= ~STR;
853 	ap->tval |= ARR;
854 	ap->sval = (wchar_t *) makesymtab();
855 
856 
857 
858 
859 	n = 0;
860 	if (sep == ' ')
861 		for (n = 0; /* dummy */; /* dummy */) {
862 			c = *s;
863 			while (iswblank(c) || c == '\t' || c == '\n')
864 				c = *(++s);
865 			if (*s == 0)
866 				break;
867 			n++;
868 			t = s;
869 			do
870 				c = *(++s);
871 			while (! iswblank(c) && c != '\t' &&
872 				c != '\n' && c != '\0');
873 			temp = c;
874 			*s = (wchar_t)0x0;
875 			wsprintf(num, "%d", n);
876 			if (isanumber(t))
877 				setsymtab(num, tostring(t),
878 						watof(t), STR|NUM, ap->sval);
879 			else
880 				setsymtab(num, tostring(t), 0.0, STR, ap->sval);
881 			*s = temp;
882 			if (*s != 0)
883 				s++;
884 
885 	} else if (*s != 0)
886 		for (;;) {
887 			n++;
888 			t = s;
889 			while ((c = *s) != sep && c != '\n' && c != '\0')
890 				s++;
891 			temp = c;
892 			*s = (wchar_t)0x0;
893 			wsprintf(num, "%d", n);
894 			if (isanumber(t))
895 				setsymtab(num, tostring(t),
896 						watof(t), STR|NUM, ap->sval);
897 			else
898 				setsymtab(num, tostring(t), 0.0, STR, ap->sval);
899 			*s = temp;
900 			if (*s++ == 0)
901 				break;
902 		}
903 	x = gettemp();
904 	x->tval = NUM;
905 	x->fval = n;
906 	return (x);
907 }
908 
909 
910 
911 
912 CELL *
913 ifstat(NODE **a, int n)
914 {
915 	CELL *x;
916 
917 
918 
919 
920 	x = execute(a[0]);
921 	if (istrue(x)) {
922 		tempfree(x);
923 		x = execute(a[1]);
924 
925 	} else if (a[2] != 0) {
926 		tempfree(x);
927 		x = execute(a[2]);
928 	}
929 	return (x);
930 }
931 
932 
933 
934 
935 CELL *
936 whilestat(NODE **a, int n)
937 {
938 	CELL *x;
939 
940 
941 
942 
943 	for (;;) {
944 		x = execute(a[0]);
945 		if (!istrue(x)) return (x);
946 		tempfree(x);
947 		x = execute(a[1]);
948 		if (isbreak(x)) {
949 			x = true;
950 			return (x);
951 		}
952 		if (isnext(x) || isexit(x))
953 			return (x);
954 		tempfree(x);
955 	}
956 }
957 
958 
959 
960 
961 CELL *
962 forstat(NODE **a, int n)
963 {
964 	CELL *x;
965 	CELL *z;
966 
967 
968 
969 
970 	z = execute(a[0]);
971 	tempfree(z);
972 	for (;;) {
973 		if (a[1]!=0) {
974 			x = execute(a[1]);
975 			if (!istrue(x)) return (x);
976 			else tempfree(x);
977 		}
978 		x = execute(a[3]);
979 		if (isbreak(x)) {	/* turn off break */
980 			x = true;
981 			return (x);
982 		}
983 		if (isnext(x) || isexit(x))
984 			return (x);
985 		tempfree(x);
986 		z = execute(a[2]);
987 		tempfree(z);
988 	}
989 }
990 
991 
992 
993 
994 CELL *
995 instat(NODE **a, int n)
996 {
997 	CELL *vp, *arrayp, *cp, **tp;
998 	CELL *x;
999 	int i;
1000 
1001 
1002 
1003 
1004 	vp = (CELL *) a[0];
1005 	arrayp = (CELL *) a[1];
1006 	if (!(arrayp->tval & ARR))
1007 		error(FATAL, "%ws is not an array", arrayp->nval);
1008 	tp = (CELL **) arrayp->sval;
1009 	for (i = 0; i < MAXSYM; i++) {	/* this routine knows too much */
1010 		for (cp = tp[i]; cp != NULL; cp = cp->nextval) {
1011 			setsval(vp, cp->nval);
1012 			x = execute(a[2]);
1013 			if (isbreak(x)) {
1014 				x = true;
1015 				return (x);
1016 			}
1017 			if (isnext(x) || isexit(x))
1018 				return (x);
1019 			tempfree(x);
1020 		}
1021 	}
1022 	return (true);
1023 }
1024 
1025 
1026 
1027 
1028 CELL *
1029 jump(NODE **a, int n)
1030 {
1031 	CELL *y;
1032 
1033 
1034 
1035 
1036 	switch (n) {
1037 	case EXIT:
1038 		if (a[0] != 0) {
1039 			y = execute(a[0]);
1040 			errorflag = getfval(y);
1041 		}
1042 		return (jexit);
1043 	case NEXT:
1044 		return (jnext);
1045 	case BREAK:
1046 		return (jbreak);
1047 	case CONTINUE:
1048 		return (jcont);
1049 	default:
1050 		error(FATAL, "illegal jump type %d", n);
1051 	}
1052 	return (NULL);
1053 }
1054 
1055 
1056 
1057 
1058 CELL *
1059 fncn(NODE **a, int n)
1060 {
1061 	CELL *x;
1062 	awkfloat u;
1063 	int t;
1064 	wchar_t *wp;
1065 
1066 	t = (int) a[0];
1067 	x = execute(a[1]);
1068 	if (t == FLENGTH)
1069 		u = (awkfloat) wslen(getsval(x));
1070 	else if (t == FLOG)
1071 		u = log(getfval(x));
1072 	else if (t == FINT)
1073 		u = (awkfloat) (long) getfval(x);
1074 	else if (t == FEXP)
1075 		u = exp(getfval(x));
1076 	else if (t == FSQRT)
1077 		u = sqrt(getfval(x));
1078 	else
1079 		error(FATAL, "illegal function type %d", t);
1080 	tempfree(x);
1081 	x = gettemp();
1082 	setfval(x, u);
1083 	return (x);
1084 }
1085 
1086 
1087 
1088 
1089 CELL *
1090 print(NODE **a, int n)
1091 {
1092 	NODE *x;
1093 	CELL *y;
1094 	wchar_t s[RECSIZE];
1095 	wchar_t *ss, *bp, *ep, *os;
1096 	size_t	blen, newlen, sslen, orslen, ofslen, oslen;
1097 
1098 	s[0] = '\0';
1099 	bp = s;
1100 	ep = s + RECSIZE;
1101 
1102 	blen = 0;
1103 	orslen = wcslen(*ORS);
1104 	ofslen = wcslen(*OFS);
1105 
1106 	for (x = a[0]; x != NULL; x = x->nnext) {
1107 		y = execute(x);
1108 		ss = getsval(y);
1109 
1110 		/* total new length will be */
1111 		sslen = wcslen(ss);
1112 		if (x->nnext == NULL) {
1113 			os = *ORS;
1114 			oslen = orslen;
1115 		} else {
1116 			os = *OFS;
1117 			oslen = ofslen;
1118 		}
1119 		newlen = blen + sslen + oslen;
1120 
1121 		/* allocate larger buffer if needed */
1122 		if (ep < (bp + newlen + 1)) {
1123 			wchar_t	*oldbp = bp;
1124 
1125 			if (oldbp == s)
1126 				bp = NULL;
1127 			bp = realloc(bp, sizeof (wchar_t) * (newlen + 1));
1128 			if (bp == NULL)
1129 				error(FATAL, "out of space in print");
1130 			ep = bp + newlen + 1;
1131 			if (oldbp == s)
1132 				(void) wmemcpy(bp, oldbp, blen);
1133 		}
1134 		(void) wmemcpy(bp + blen, ss, sslen);
1135 		(void) wmemcpy(bp + blen + sslen, os, oslen);
1136 		tempfree(y);
1137 		blen = newlen;
1138 		bp[blen] = '\0';
1139 	}
1140 	if (a[1] == NULL) {
1141 		(void) printf("%ws", bp);
1142 		if (bp != s)
1143 			free(bp);
1144 		return (true);
1145 	}
1146 
1147 	redirprint(bp, (int)a[1], a[2]);
1148 	if (bp != s)
1149 		free(bp);
1150 	return (false);
1151 }
1152 
1153 
1154 
1155 CELL *
1156 nullproc(void)
1157 {
1158 	return (NULL);
1159 }
1160 
1161 
1162 
1163 CELL *
1164 nodetoobj(NODE *a)
1165 {
1166 	CELL *x;
1167 
1168 	x= (CELL *) a->nobj;
1169 	x->ctype = OCELL;
1170 	x->csub = a->subtype;
1171 	if (isfld(x))
1172 		fldbld();
1173 	return (x);
1174 }
1175 
1176 static void
1177 redirprint(wchar_t *s, int a, NODE *b)
1178 {
1179 	int i;
1180 	CELL *x;
1181 
1182 	x = execute(b);
1183 	getsval(x);
1184 	for (i=0; i<FILENUM; i++)
1185 		if (files[i].fname && wscmp(x->sval, files[i].fname) == 0)
1186 			goto doit;
1187 	for (i=0; i<FILENUM; i++)
1188 		if (files[i].fp == 0)
1189 			break;
1190 	if (i >= FILENUM)
1191 		error(FATAL, "too many output files %d", i);
1192 	if (a == '|')	/* a pipe! */
1193 		files[i].fp = popen(toeuccode(x->sval), "w");
1194 	else if (a == APPEND)
1195 		files[i].fp = fopen(toeuccode(x->sval), "a");
1196 	else if (a == GT)
1197 		files[i].fp = fopen(toeuccode(x->sval), "w");
1198 	else
1199 		error(FATAL, "illegal redirection near line %lld", lineno);
1200 	if (files[i].fp == NULL)
1201 		error(FATAL, "can't open file %ws", x->sval);
1202 	files[i].fname = tostring(x->sval);
1203 	files[i].type = a;
1204 doit:
1205 	fprintf(files[i].fp, "%ws", s);
1206 #ifndef gcos
1207 	fflush(files[i].fp);	/* in case someone is waiting for the output */
1208 #endif
1209 	tempfree(x);
1210 }
1211