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