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