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