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