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