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