xref: /aosp_15_r20/external/one-true-awk/run.c (revision 9a7741de182b2776d7b30d6355f2585c0780a51b)
1*9a7741deSElliott Hughes /****************************************************************
2*9a7741deSElliott Hughes Copyright (C) Lucent Technologies 1997
3*9a7741deSElliott Hughes All Rights Reserved
4*9a7741deSElliott Hughes 
5*9a7741deSElliott Hughes Permission to use, copy, modify, and distribute this software and
6*9a7741deSElliott Hughes its documentation for any purpose and without fee is hereby
7*9a7741deSElliott Hughes granted, provided that the above copyright notice appear in all
8*9a7741deSElliott Hughes copies and that both that the copyright notice and this
9*9a7741deSElliott Hughes permission notice and warranty disclaimer appear in supporting
10*9a7741deSElliott Hughes documentation, and that the name Lucent Technologies or any of
11*9a7741deSElliott Hughes its entities not be used in advertising or publicity pertaining
12*9a7741deSElliott Hughes to distribution of the software without specific, written prior
13*9a7741deSElliott Hughes permission.
14*9a7741deSElliott Hughes 
15*9a7741deSElliott Hughes LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16*9a7741deSElliott Hughes INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17*9a7741deSElliott Hughes IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18*9a7741deSElliott Hughes SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19*9a7741deSElliott Hughes WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20*9a7741deSElliott Hughes IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21*9a7741deSElliott Hughes ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22*9a7741deSElliott Hughes THIS SOFTWARE.
23*9a7741deSElliott Hughes ****************************************************************/
24*9a7741deSElliott Hughes 
25*9a7741deSElliott Hughes #define DEBUG
26*9a7741deSElliott Hughes #include <stdio.h>
27*9a7741deSElliott Hughes #include <ctype.h>
28*9a7741deSElliott Hughes #include <errno.h>
29*9a7741deSElliott Hughes #include <wctype.h>
30*9a7741deSElliott Hughes #include <fcntl.h>
31*9a7741deSElliott Hughes #include <setjmp.h>
32*9a7741deSElliott Hughes #include <limits.h>
33*9a7741deSElliott Hughes #include <math.h>
34*9a7741deSElliott Hughes #include <string.h>
35*9a7741deSElliott Hughes #include <stdlib.h>
36*9a7741deSElliott Hughes #include <time.h>
37*9a7741deSElliott Hughes #include <sys/types.h>
38*9a7741deSElliott Hughes #include <sys/wait.h>
39*9a7741deSElliott Hughes #include "awk.h"
40*9a7741deSElliott Hughes #include "awkgram.tab.h"
41*9a7741deSElliott Hughes 
42*9a7741deSElliott Hughes 
43*9a7741deSElliott Hughes static void stdinit(void);
44*9a7741deSElliott Hughes static void flush_all(void);
45*9a7741deSElliott Hughes static char *wide_char_to_byte_str(int rune, size_t *outlen);
46*9a7741deSElliott Hughes 
47*9a7741deSElliott Hughes #if 1
48*9a7741deSElliott Hughes #define tempfree(x)	do { if (istemp(x)) tfree(x); } while (/*CONSTCOND*/0)
49*9a7741deSElliott Hughes #else
tempfree(Cell * p)50*9a7741deSElliott Hughes void tempfree(Cell *p) {
51*9a7741deSElliott Hughes 	if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
52*9a7741deSElliott Hughes 		WARNING("bad csub %d in Cell %d %s",
53*9a7741deSElliott Hughes 			p->csub, p->ctype, p->sval);
54*9a7741deSElliott Hughes 	}
55*9a7741deSElliott Hughes 	if (istemp(p))
56*9a7741deSElliott Hughes 		tfree(p);
57*9a7741deSElliott Hughes }
58*9a7741deSElliott Hughes #endif
59*9a7741deSElliott Hughes 
60*9a7741deSElliott Hughes /* do we really need these? */
61*9a7741deSElliott Hughes /* #ifdef _NFILE */
62*9a7741deSElliott Hughes /* #ifndef FOPEN_MAX */
63*9a7741deSElliott Hughes /* #define FOPEN_MAX _NFILE */
64*9a7741deSElliott Hughes /* #endif */
65*9a7741deSElliott Hughes /* #endif */
66*9a7741deSElliott Hughes /*  */
67*9a7741deSElliott Hughes /* #ifndef	FOPEN_MAX */
68*9a7741deSElliott Hughes /* #define	FOPEN_MAX	40 */	/* max number of open files */
69*9a7741deSElliott Hughes /* #endif */
70*9a7741deSElliott Hughes /*  */
71*9a7741deSElliott Hughes /* #ifndef RAND_MAX */
72*9a7741deSElliott Hughes /* #define RAND_MAX	32767 */	/* all that ansi guarantees */
73*9a7741deSElliott Hughes /* #endif */
74*9a7741deSElliott Hughes 
75*9a7741deSElliott Hughes jmp_buf env;
76*9a7741deSElliott Hughes extern	int	pairstack[];
77*9a7741deSElliott Hughes extern	Awkfloat	srand_seed;
78*9a7741deSElliott Hughes 
79*9a7741deSElliott Hughes Node	*winner = NULL;	/* root of parse tree */
80*9a7741deSElliott Hughes Cell	*tmps;		/* free temporary cells for execution */
81*9a7741deSElliott Hughes 
82*9a7741deSElliott Hughes static Cell	truecell	={ OBOOL, BTRUE, 0, 0, 1.0, NUM, NULL, NULL };
83*9a7741deSElliott Hughes Cell	*True	= &truecell;
84*9a7741deSElliott Hughes static Cell	falsecell	={ OBOOL, BFALSE, 0, 0, 0.0, NUM, NULL, NULL };
85*9a7741deSElliott Hughes Cell	*False	= &falsecell;
86*9a7741deSElliott Hughes static Cell	breakcell	={ OJUMP, JBREAK, 0, 0, 0.0, NUM, NULL, NULL };
87*9a7741deSElliott Hughes Cell	*jbreak	= &breakcell;
88*9a7741deSElliott Hughes static Cell	contcell	={ OJUMP, JCONT, 0, 0, 0.0, NUM, NULL, NULL };
89*9a7741deSElliott Hughes Cell	*jcont	= &contcell;
90*9a7741deSElliott Hughes static Cell	nextcell	={ OJUMP, JNEXT, 0, 0, 0.0, NUM, NULL, NULL };
91*9a7741deSElliott Hughes Cell	*jnext	= &nextcell;
92*9a7741deSElliott Hughes static Cell	nextfilecell	={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM, NULL, NULL };
93*9a7741deSElliott Hughes Cell	*jnextfile	= &nextfilecell;
94*9a7741deSElliott Hughes static Cell	exitcell	={ OJUMP, JEXIT, 0, 0, 0.0, NUM, NULL, NULL };
95*9a7741deSElliott Hughes Cell	*jexit	= &exitcell;
96*9a7741deSElliott Hughes static Cell	retcell		={ OJUMP, JRET, 0, 0, 0.0, NUM, NULL, NULL };
97*9a7741deSElliott Hughes Cell	*jret	= &retcell;
98*9a7741deSElliott Hughes static Cell	tempcell	={ OCELL, CTEMP, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL, NULL };
99*9a7741deSElliott Hughes 
100*9a7741deSElliott Hughes Node	*curnode = NULL;	/* the node being executed, for debugging */
101*9a7741deSElliott Hughes 
102*9a7741deSElliott Hughes /* buffer memory management */
adjbuf(char ** pbuf,int * psiz,int minlen,int quantum,char ** pbptr,const char * whatrtn)103*9a7741deSElliott Hughes int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
104*9a7741deSElliott Hughes 	const char *whatrtn)
105*9a7741deSElliott Hughes /* pbuf:    address of pointer to buffer being managed
106*9a7741deSElliott Hughes  * psiz:    address of buffer size variable
107*9a7741deSElliott Hughes  * minlen:  minimum length of buffer needed
108*9a7741deSElliott Hughes  * quantum: buffer size quantum
109*9a7741deSElliott Hughes  * pbptr:   address of movable pointer into buffer, or 0 if none
110*9a7741deSElliott Hughes  * whatrtn: name of the calling routine if failure should cause fatal error
111*9a7741deSElliott Hughes  *
112*9a7741deSElliott Hughes  * return   0 for realloc failure, !=0 for success
113*9a7741deSElliott Hughes  */
114*9a7741deSElliott Hughes {
115*9a7741deSElliott Hughes 	if (minlen > *psiz) {
116*9a7741deSElliott Hughes 		char *tbuf;
117*9a7741deSElliott Hughes 		int rminlen = quantum ? minlen % quantum : 0;
118*9a7741deSElliott Hughes 		int boff = pbptr ? *pbptr - *pbuf : 0;
119*9a7741deSElliott Hughes 		/* round up to next multiple of quantum */
120*9a7741deSElliott Hughes 		if (rminlen)
121*9a7741deSElliott Hughes 			minlen += quantum - rminlen;
122*9a7741deSElliott Hughes 		tbuf = (char *) realloc(*pbuf, minlen);
123*9a7741deSElliott Hughes 		DPRINTF("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, (void*)*pbuf, (void*)tbuf);
124*9a7741deSElliott Hughes 		if (tbuf == NULL) {
125*9a7741deSElliott Hughes 			if (whatrtn)
126*9a7741deSElliott Hughes 				FATAL("out of memory in %s", whatrtn);
127*9a7741deSElliott Hughes 			return 0;
128*9a7741deSElliott Hughes 		}
129*9a7741deSElliott Hughes 		*pbuf = tbuf;
130*9a7741deSElliott Hughes 		*psiz = minlen;
131*9a7741deSElliott Hughes 		if (pbptr)
132*9a7741deSElliott Hughes 			*pbptr = tbuf + boff;
133*9a7741deSElliott Hughes 	}
134*9a7741deSElliott Hughes 	return 1;
135*9a7741deSElliott Hughes }
136*9a7741deSElliott Hughes 
run(Node * a)137*9a7741deSElliott Hughes void run(Node *a)	/* execution of parse tree starts here */
138*9a7741deSElliott Hughes {
139*9a7741deSElliott Hughes 
140*9a7741deSElliott Hughes 	stdinit();
141*9a7741deSElliott Hughes 	execute(a);
142*9a7741deSElliott Hughes 	closeall();
143*9a7741deSElliott Hughes }
144*9a7741deSElliott Hughes 
execute(Node * u)145*9a7741deSElliott Hughes Cell *execute(Node *u)	/* execute a node of the parse tree */
146*9a7741deSElliott Hughes {
147*9a7741deSElliott Hughes 	Cell *(*proc)(Node **, int);
148*9a7741deSElliott Hughes 	Cell *x;
149*9a7741deSElliott Hughes 	Node *a;
150*9a7741deSElliott Hughes 
151*9a7741deSElliott Hughes 	if (u == NULL)
152*9a7741deSElliott Hughes 		return(True);
153*9a7741deSElliott Hughes 	for (a = u; ; a = a->nnext) {
154*9a7741deSElliott Hughes 		curnode = a;
155*9a7741deSElliott Hughes 		if (isvalue(a)) {
156*9a7741deSElliott Hughes 			x = (Cell *) (a->narg[0]);
157*9a7741deSElliott Hughes 			if (isfld(x) && !donefld)
158*9a7741deSElliott Hughes 				fldbld();
159*9a7741deSElliott Hughes 			else if (isrec(x) && !donerec)
160*9a7741deSElliott Hughes 				recbld();
161*9a7741deSElliott Hughes 			return(x);
162*9a7741deSElliott Hughes 		}
163*9a7741deSElliott Hughes 		if (notlegal(a->nobj))	/* probably a Cell* but too risky to print */
164*9a7741deSElliott Hughes 			FATAL("illegal statement");
165*9a7741deSElliott Hughes 		proc = proctab[a->nobj-FIRSTTOKEN];
166*9a7741deSElliott Hughes 		x = (*proc)(a->narg, a->nobj);
167*9a7741deSElliott Hughes 		if (isfld(x) && !donefld)
168*9a7741deSElliott Hughes 			fldbld();
169*9a7741deSElliott Hughes 		else if (isrec(x) && !donerec)
170*9a7741deSElliott Hughes 			recbld();
171*9a7741deSElliott Hughes 		if (isexpr(a))
172*9a7741deSElliott Hughes 			return(x);
173*9a7741deSElliott Hughes 		if (isjump(x))
174*9a7741deSElliott Hughes 			return(x);
175*9a7741deSElliott Hughes 		if (a->nnext == NULL)
176*9a7741deSElliott Hughes 			return(x);
177*9a7741deSElliott Hughes 		tempfree(x);
178*9a7741deSElliott Hughes 	}
179*9a7741deSElliott Hughes }
180*9a7741deSElliott Hughes 
181*9a7741deSElliott Hughes 
program(Node ** a,int n)182*9a7741deSElliott Hughes Cell *program(Node **a, int n)	/* execute an awk program */
183*9a7741deSElliott Hughes {				/* a[0] = BEGIN, a[1] = body, a[2] = END */
184*9a7741deSElliott Hughes 	Cell *x;
185*9a7741deSElliott Hughes 
186*9a7741deSElliott Hughes 	if (setjmp(env) != 0)
187*9a7741deSElliott Hughes 		goto ex;
188*9a7741deSElliott Hughes 	if (a[0]) {		/* BEGIN */
189*9a7741deSElliott Hughes 		x = execute(a[0]);
190*9a7741deSElliott Hughes 		if (isexit(x))
191*9a7741deSElliott Hughes 			return(True);
192*9a7741deSElliott Hughes 		if (isjump(x))
193*9a7741deSElliott Hughes 			FATAL("illegal break, continue, next or nextfile from BEGIN");
194*9a7741deSElliott Hughes 		tempfree(x);
195*9a7741deSElliott Hughes 	}
196*9a7741deSElliott Hughes 	if (a[1] || a[2])
197*9a7741deSElliott Hughes 		while (getrec(&record, &recsize, true) > 0) {
198*9a7741deSElliott Hughes 			x = execute(a[1]);
199*9a7741deSElliott Hughes 			if (isexit(x))
200*9a7741deSElliott Hughes 				break;
201*9a7741deSElliott Hughes 			tempfree(x);
202*9a7741deSElliott Hughes 		}
203*9a7741deSElliott Hughes   ex:
204*9a7741deSElliott Hughes 	if (setjmp(env) != 0)	/* handles exit within END */
205*9a7741deSElliott Hughes 		goto ex1;
206*9a7741deSElliott Hughes 	if (a[2]) {		/* END */
207*9a7741deSElliott Hughes 		x = execute(a[2]);
208*9a7741deSElliott Hughes 		if (isbreak(x) || isnext(x) || iscont(x))
209*9a7741deSElliott Hughes 			FATAL("illegal break, continue, next or nextfile from END");
210*9a7741deSElliott Hughes 		tempfree(x);
211*9a7741deSElliott Hughes 	}
212*9a7741deSElliott Hughes   ex1:
213*9a7741deSElliott Hughes 	return(True);
214*9a7741deSElliott Hughes }
215*9a7741deSElliott Hughes 
216*9a7741deSElliott Hughes struct Frame {	/* stack frame for awk function calls */
217*9a7741deSElliott Hughes 	int nargs;	/* number of arguments in this call */
218*9a7741deSElliott Hughes 	Cell *fcncell;	/* pointer to Cell for function */
219*9a7741deSElliott Hughes 	Cell **args;	/* pointer to array of arguments after execute */
220*9a7741deSElliott Hughes 	Cell *retval;	/* return value */
221*9a7741deSElliott Hughes };
222*9a7741deSElliott Hughes 
223*9a7741deSElliott Hughes #define	NARGS	50	/* max args in a call */
224*9a7741deSElliott Hughes 
225*9a7741deSElliott Hughes struct Frame *frame = NULL;	/* base of stack frames; dynamically allocated */
226*9a7741deSElliott Hughes int	nframe = 0;		/* number of frames allocated */
227*9a7741deSElliott Hughes struct Frame *frp = NULL;	/* frame pointer. bottom level unused */
228*9a7741deSElliott Hughes 
call(Node ** a,int n)229*9a7741deSElliott Hughes Cell *call(Node **a, int n)	/* function call.  very kludgy and fragile */
230*9a7741deSElliott Hughes {
231*9a7741deSElliott Hughes 	static const Cell newcopycell = { OCELL, CCOPY, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL, NULL };
232*9a7741deSElliott Hughes 	int i, ncall, ndef;
233*9a7741deSElliott Hughes 	int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */
234*9a7741deSElliott Hughes 	Node *x;
235*9a7741deSElliott Hughes 	Cell *args[NARGS], *oargs[NARGS];	/* BUG: fixed size arrays */
236*9a7741deSElliott Hughes 	Cell *y, *z, *fcn;
237*9a7741deSElliott Hughes 	char *s;
238*9a7741deSElliott Hughes 
239*9a7741deSElliott Hughes 	fcn = execute(a[0]);	/* the function itself */
240*9a7741deSElliott Hughes 	s = fcn->nval;
241*9a7741deSElliott Hughes 	if (!isfcn(fcn))
242*9a7741deSElliott Hughes 		FATAL("calling undefined function %s", s);
243*9a7741deSElliott Hughes 	if (frame == NULL) {
244*9a7741deSElliott Hughes 		frp = frame = (struct Frame *) calloc(nframe += 100, sizeof(*frame));
245*9a7741deSElliott Hughes 		if (frame == NULL)
246*9a7741deSElliott Hughes 			FATAL("out of space for stack frames calling %s", s);
247*9a7741deSElliott Hughes 	}
248*9a7741deSElliott Hughes 	for (ncall = 0, x = a[1]; x != NULL; x = x->nnext)	/* args in call */
249*9a7741deSElliott Hughes 		ncall++;
250*9a7741deSElliott Hughes 	ndef = (int) fcn->fval;			/* args in defn */
251*9a7741deSElliott Hughes 	DPRINTF("calling %s, %d args (%d in defn), frp=%d\n", s, ncall, ndef, (int) (frp-frame));
252*9a7741deSElliott Hughes 	if (ncall > ndef)
253*9a7741deSElliott Hughes 		WARNING("function %s called with %d args, uses only %d",
254*9a7741deSElliott Hughes 			s, ncall, ndef);
255*9a7741deSElliott Hughes 	if (ncall + ndef > NARGS)
256*9a7741deSElliott Hughes 		FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
257*9a7741deSElliott Hughes 	for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) {	/* get call args */
258*9a7741deSElliott Hughes 		DPRINTF("evaluate args[%d], frp=%d:\n", i, (int) (frp-frame));
259*9a7741deSElliott Hughes 		y = execute(x);
260*9a7741deSElliott Hughes 		oargs[i] = y;
261*9a7741deSElliott Hughes 		DPRINTF("args[%d]: %s %f <%s>, t=%o\n",
262*9a7741deSElliott Hughes 			i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval);
263*9a7741deSElliott Hughes 		if (isfcn(y))
264*9a7741deSElliott Hughes 			FATAL("can't use function %s as argument in %s", y->nval, s);
265*9a7741deSElliott Hughes 		if (isarr(y))
266*9a7741deSElliott Hughes 			args[i] = y;	/* arrays by ref */
267*9a7741deSElliott Hughes 		else
268*9a7741deSElliott Hughes 			args[i] = copycell(y);
269*9a7741deSElliott Hughes 		tempfree(y);
270*9a7741deSElliott Hughes 	}
271*9a7741deSElliott Hughes 	for ( ; i < ndef; i++) {	/* add null args for ones not provided */
272*9a7741deSElliott Hughes 		args[i] = gettemp();
273*9a7741deSElliott Hughes 		*args[i] = newcopycell;
274*9a7741deSElliott Hughes 	}
275*9a7741deSElliott Hughes 	frp++;	/* now ok to up frame */
276*9a7741deSElliott Hughes 	if (frp >= frame + nframe) {
277*9a7741deSElliott Hughes 		int dfp = frp - frame;	/* old index */
278*9a7741deSElliott Hughes 		frame = (struct Frame *) realloc(frame, (nframe += 100) * sizeof(*frame));
279*9a7741deSElliott Hughes 		if (frame == NULL)
280*9a7741deSElliott Hughes 			FATAL("out of space for stack frames in %s", s);
281*9a7741deSElliott Hughes 		frp = frame + dfp;
282*9a7741deSElliott Hughes 	}
283*9a7741deSElliott Hughes 	frp->fcncell = fcn;
284*9a7741deSElliott Hughes 	frp->args = args;
285*9a7741deSElliott Hughes 	frp->nargs = ndef;	/* number defined with (excess are locals) */
286*9a7741deSElliott Hughes 	frp->retval = gettemp();
287*9a7741deSElliott Hughes 
288*9a7741deSElliott Hughes 	DPRINTF("start exec of %s, frp=%d\n", s, (int) (frp-frame));
289*9a7741deSElliott Hughes 	y = execute((Node *)(fcn->sval));	/* execute body */
290*9a7741deSElliott Hughes 	DPRINTF("finished exec of %s, frp=%d\n", s, (int) (frp-frame));
291*9a7741deSElliott Hughes 
292*9a7741deSElliott Hughes 	for (i = 0; i < ndef; i++) {
293*9a7741deSElliott Hughes 		Cell *t = frp->args[i];
294*9a7741deSElliott Hughes 		if (isarr(t)) {
295*9a7741deSElliott Hughes 			if (t->csub == CCOPY) {
296*9a7741deSElliott Hughes 				if (i >= ncall) {
297*9a7741deSElliott Hughes 					freesymtab(t);
298*9a7741deSElliott Hughes 					t->csub = CTEMP;
299*9a7741deSElliott Hughes 					tempfree(t);
300*9a7741deSElliott Hughes 				} else {
301*9a7741deSElliott Hughes 					oargs[i]->tval = t->tval;
302*9a7741deSElliott Hughes 					oargs[i]->tval &= ~(STR|NUM|DONTFREE);
303*9a7741deSElliott Hughes 					oargs[i]->sval = t->sval;
304*9a7741deSElliott Hughes 					tempfree(t);
305*9a7741deSElliott Hughes 				}
306*9a7741deSElliott Hughes 			}
307*9a7741deSElliott Hughes 		} else if (t != y) {	/* kludge to prevent freeing twice */
308*9a7741deSElliott Hughes 			t->csub = CTEMP;
309*9a7741deSElliott Hughes 			tempfree(t);
310*9a7741deSElliott Hughes 		} else if (t == y && t->csub == CCOPY) {
311*9a7741deSElliott Hughes 			t->csub = CTEMP;
312*9a7741deSElliott Hughes 			tempfree(t);
313*9a7741deSElliott Hughes 			freed = 1;
314*9a7741deSElliott Hughes 		}
315*9a7741deSElliott Hughes 	}
316*9a7741deSElliott Hughes 	tempfree(fcn);
317*9a7741deSElliott Hughes 	if (isexit(y) || isnext(y))
318*9a7741deSElliott Hughes 		return y;
319*9a7741deSElliott Hughes 	if (freed == 0) {
320*9a7741deSElliott Hughes 		tempfree(y);	/* don't free twice! */
321*9a7741deSElliott Hughes 	}
322*9a7741deSElliott Hughes 	z = frp->retval;			/* return value */
323*9a7741deSElliott Hughes 	DPRINTF("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval);
324*9a7741deSElliott Hughes 	frp--;
325*9a7741deSElliott Hughes 	return(z);
326*9a7741deSElliott Hughes }
327*9a7741deSElliott Hughes 
copycell(Cell * x)328*9a7741deSElliott Hughes Cell *copycell(Cell *x)	/* make a copy of a cell in a temp */
329*9a7741deSElliott Hughes {
330*9a7741deSElliott Hughes 	Cell *y;
331*9a7741deSElliott Hughes 
332*9a7741deSElliott Hughes 	/* copy is not constant or field */
333*9a7741deSElliott Hughes 
334*9a7741deSElliott Hughes 	y = gettemp();
335*9a7741deSElliott Hughes 	y->tval = x->tval & ~(CON|FLD|REC);
336*9a7741deSElliott Hughes 	y->csub = CCOPY;	/* prevents freeing until call is over */
337*9a7741deSElliott Hughes 	y->nval = x->nval;	/* BUG? */
338*9a7741deSElliott Hughes 	if (isstr(x) /* || x->ctype == OCELL */) {
339*9a7741deSElliott Hughes 		y->sval = tostring(x->sval);
340*9a7741deSElliott Hughes 		y->tval &= ~DONTFREE;
341*9a7741deSElliott Hughes 	} else
342*9a7741deSElliott Hughes 		y->tval |= DONTFREE;
343*9a7741deSElliott Hughes 	y->fval = x->fval;
344*9a7741deSElliott Hughes 	return y;
345*9a7741deSElliott Hughes }
346*9a7741deSElliott Hughes 
arg(Node ** a,int n)347*9a7741deSElliott Hughes Cell *arg(Node **a, int n)	/* nth argument of a function */
348*9a7741deSElliott Hughes {
349*9a7741deSElliott Hughes 
350*9a7741deSElliott Hughes 	n = ptoi(a[0]);	/* argument number, counting from 0 */
351*9a7741deSElliott Hughes 	DPRINTF("arg(%d), frp->nargs=%d\n", n, frp->nargs);
352*9a7741deSElliott Hughes 	if (n+1 > frp->nargs)
353*9a7741deSElliott Hughes 		FATAL("argument #%d of function %s was not supplied",
354*9a7741deSElliott Hughes 			n+1, frp->fcncell->nval);
355*9a7741deSElliott Hughes 	return frp->args[n];
356*9a7741deSElliott Hughes }
357*9a7741deSElliott Hughes 
jump(Node ** a,int n)358*9a7741deSElliott Hughes Cell *jump(Node **a, int n)	/* break, continue, next, nextfile, return */
359*9a7741deSElliott Hughes {
360*9a7741deSElliott Hughes 	Cell *y;
361*9a7741deSElliott Hughes 
362*9a7741deSElliott Hughes 	switch (n) {
363*9a7741deSElliott Hughes 	case EXIT:
364*9a7741deSElliott Hughes 		if (a[0] != NULL) {
365*9a7741deSElliott Hughes 			y = execute(a[0]);
366*9a7741deSElliott Hughes 			errorflag = (int) getfval(y);
367*9a7741deSElliott Hughes 			tempfree(y);
368*9a7741deSElliott Hughes 		}
369*9a7741deSElliott Hughes 		longjmp(env, 1);
370*9a7741deSElliott Hughes 	case RETURN:
371*9a7741deSElliott Hughes 		if (a[0] != NULL) {
372*9a7741deSElliott Hughes 			y = execute(a[0]);
373*9a7741deSElliott Hughes 			if ((y->tval & (STR|NUM)) == (STR|NUM)) {
374*9a7741deSElliott Hughes 				setsval(frp->retval, getsval(y));
375*9a7741deSElliott Hughes 				frp->retval->fval = getfval(y);
376*9a7741deSElliott Hughes 				frp->retval->tval |= NUM;
377*9a7741deSElliott Hughes 			}
378*9a7741deSElliott Hughes 			else if (y->tval & STR)
379*9a7741deSElliott Hughes 				setsval(frp->retval, getsval(y));
380*9a7741deSElliott Hughes 			else if (y->tval & NUM)
381*9a7741deSElliott Hughes 				setfval(frp->retval, getfval(y));
382*9a7741deSElliott Hughes 			else		/* can't happen */
383*9a7741deSElliott Hughes 				FATAL("bad type variable %d", y->tval);
384*9a7741deSElliott Hughes 			tempfree(y);
385*9a7741deSElliott Hughes 		}
386*9a7741deSElliott Hughes 		return(jret);
387*9a7741deSElliott Hughes 	case NEXT:
388*9a7741deSElliott Hughes 		return(jnext);
389*9a7741deSElliott Hughes 	case NEXTFILE:
390*9a7741deSElliott Hughes 		nextfile();
391*9a7741deSElliott Hughes 		return(jnextfile);
392*9a7741deSElliott Hughes 	case BREAK:
393*9a7741deSElliott Hughes 		return(jbreak);
394*9a7741deSElliott Hughes 	case CONTINUE:
395*9a7741deSElliott Hughes 		return(jcont);
396*9a7741deSElliott Hughes 	default:	/* can't happen */
397*9a7741deSElliott Hughes 		FATAL("illegal jump type %d", n);
398*9a7741deSElliott Hughes 	}
399*9a7741deSElliott Hughes 	return 0;	/* not reached */
400*9a7741deSElliott Hughes }
401*9a7741deSElliott Hughes 
awkgetline(Node ** a,int n)402*9a7741deSElliott Hughes Cell *awkgetline(Node **a, int n)	/* get next line from specific input */
403*9a7741deSElliott Hughes {		/* a[0] is variable, a[1] is operator, a[2] is filename */
404*9a7741deSElliott Hughes 	Cell *r, *x;
405*9a7741deSElliott Hughes 	extern Cell **fldtab;
406*9a7741deSElliott Hughes 	FILE *fp;
407*9a7741deSElliott Hughes 	char *buf;
408*9a7741deSElliott Hughes 	int bufsize = recsize;
409*9a7741deSElliott Hughes 	int mode;
410*9a7741deSElliott Hughes 	bool newflag;
411*9a7741deSElliott Hughes 	double result;
412*9a7741deSElliott Hughes 
413*9a7741deSElliott Hughes 	if ((buf = (char *) malloc(bufsize)) == NULL)
414*9a7741deSElliott Hughes 		FATAL("out of memory in getline");
415*9a7741deSElliott Hughes 
416*9a7741deSElliott Hughes 	fflush(stdout);	/* in case someone is waiting for a prompt */
417*9a7741deSElliott Hughes 	r = gettemp();
418*9a7741deSElliott Hughes 	if (a[1] != NULL) {		/* getline < file */
419*9a7741deSElliott Hughes 		x = execute(a[2]);		/* filename */
420*9a7741deSElliott Hughes 		mode = ptoi(a[1]);
421*9a7741deSElliott Hughes 		if (mode == '|')		/* input pipe */
422*9a7741deSElliott Hughes 			mode = LE;	/* arbitrary flag */
423*9a7741deSElliott Hughes 		fp = openfile(mode, getsval(x), &newflag);
424*9a7741deSElliott Hughes 		tempfree(x);
425*9a7741deSElliott Hughes 		if (fp == NULL)
426*9a7741deSElliott Hughes 			n = -1;
427*9a7741deSElliott Hughes 		else
428*9a7741deSElliott Hughes 			n = readrec(&buf, &bufsize, fp, newflag);
429*9a7741deSElliott Hughes 		if (n <= 0) {
430*9a7741deSElliott Hughes 			;
431*9a7741deSElliott Hughes 		} else if (a[0] != NULL) {	/* getline var <file */
432*9a7741deSElliott Hughes 			x = execute(a[0]);
433*9a7741deSElliott Hughes 			setsval(x, buf);
434*9a7741deSElliott Hughes 			if (is_number(x->sval, & result)) {
435*9a7741deSElliott Hughes 				x->fval = result;
436*9a7741deSElliott Hughes 				x->tval |= NUM;
437*9a7741deSElliott Hughes 			}
438*9a7741deSElliott Hughes 			tempfree(x);
439*9a7741deSElliott Hughes 		} else {			/* getline <file */
440*9a7741deSElliott Hughes 			setsval(fldtab[0], buf);
441*9a7741deSElliott Hughes 			if (is_number(fldtab[0]->sval, & result)) {
442*9a7741deSElliott Hughes 				fldtab[0]->fval = result;
443*9a7741deSElliott Hughes 				fldtab[0]->tval |= NUM;
444*9a7741deSElliott Hughes 			}
445*9a7741deSElliott Hughes 		}
446*9a7741deSElliott Hughes 	} else {			/* bare getline; use current input */
447*9a7741deSElliott Hughes 		if (a[0] == NULL)	/* getline */
448*9a7741deSElliott Hughes 			n = getrec(&record, &recsize, true);
449*9a7741deSElliott Hughes 		else {			/* getline var */
450*9a7741deSElliott Hughes 			n = getrec(&buf, &bufsize, false);
451*9a7741deSElliott Hughes 			if (n > 0) {
452*9a7741deSElliott Hughes 				x = execute(a[0]);
453*9a7741deSElliott Hughes 				setsval(x, buf);
454*9a7741deSElliott Hughes 				if (is_number(x->sval, & result)) {
455*9a7741deSElliott Hughes 					x->fval = result;
456*9a7741deSElliott Hughes 					x->tval |= NUM;
457*9a7741deSElliott Hughes 				}
458*9a7741deSElliott Hughes 				tempfree(x);
459*9a7741deSElliott Hughes 			}
460*9a7741deSElliott Hughes 		}
461*9a7741deSElliott Hughes 	}
462*9a7741deSElliott Hughes 	setfval(r, (Awkfloat) n);
463*9a7741deSElliott Hughes 	free(buf);
464*9a7741deSElliott Hughes 	return r;
465*9a7741deSElliott Hughes }
466*9a7741deSElliott Hughes 
getnf(Node ** a,int n)467*9a7741deSElliott Hughes Cell *getnf(Node **a, int n)	/* get NF */
468*9a7741deSElliott Hughes {
469*9a7741deSElliott Hughes 	if (!donefld)
470*9a7741deSElliott Hughes 		fldbld();
471*9a7741deSElliott Hughes 	return (Cell *) a[0];
472*9a7741deSElliott Hughes }
473*9a7741deSElliott Hughes 
474*9a7741deSElliott Hughes static char *
makearraystring(Node * p,const char * func)475*9a7741deSElliott Hughes makearraystring(Node *p, const char *func)
476*9a7741deSElliott Hughes {
477*9a7741deSElliott Hughes 	char *buf;
478*9a7741deSElliott Hughes 	int bufsz = recsize;
479*9a7741deSElliott Hughes 	size_t blen;
480*9a7741deSElliott Hughes 
481*9a7741deSElliott Hughes 	if ((buf = (char *) malloc(bufsz)) == NULL) {
482*9a7741deSElliott Hughes 		FATAL("%s: out of memory", func);
483*9a7741deSElliott Hughes 	}
484*9a7741deSElliott Hughes 
485*9a7741deSElliott Hughes 	blen = 0;
486*9a7741deSElliott Hughes 	buf[blen] = '\0';
487*9a7741deSElliott Hughes 
488*9a7741deSElliott Hughes 	for (; p; p = p->nnext) {
489*9a7741deSElliott Hughes 		Cell *x = execute(p);	/* expr */
490*9a7741deSElliott Hughes 		char *s = getsval(x);
491*9a7741deSElliott Hughes 		size_t seplen = strlen(getsval(subseploc));
492*9a7741deSElliott Hughes 		size_t nsub = p->nnext ? seplen : 0;
493*9a7741deSElliott Hughes 		size_t slen = strlen(s);
494*9a7741deSElliott Hughes 		size_t tlen = blen + slen + nsub;
495*9a7741deSElliott Hughes 
496*9a7741deSElliott Hughes 		if (!adjbuf(&buf, &bufsz, tlen + 1, recsize, 0, func)) {
497*9a7741deSElliott Hughes 			FATAL("%s: out of memory %s[%s...]",
498*9a7741deSElliott Hughes 			    func, x->nval, buf);
499*9a7741deSElliott Hughes 		}
500*9a7741deSElliott Hughes 		memcpy(buf + blen, s, slen);
501*9a7741deSElliott Hughes 		if (nsub) {
502*9a7741deSElliott Hughes 			memcpy(buf + blen + slen, *SUBSEP, nsub);
503*9a7741deSElliott Hughes 		}
504*9a7741deSElliott Hughes 		buf[tlen] = '\0';
505*9a7741deSElliott Hughes 		blen = tlen;
506*9a7741deSElliott Hughes 		tempfree(x);
507*9a7741deSElliott Hughes 	}
508*9a7741deSElliott Hughes 	return buf;
509*9a7741deSElliott Hughes }
510*9a7741deSElliott Hughes 
array(Node ** a,int n)511*9a7741deSElliott Hughes Cell *array(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
512*9a7741deSElliott Hughes {
513*9a7741deSElliott Hughes 	Cell *x, *z;
514*9a7741deSElliott Hughes 	char *buf;
515*9a7741deSElliott Hughes 
516*9a7741deSElliott Hughes 	x = execute(a[0]);	/* Cell* for symbol table */
517*9a7741deSElliott Hughes 	buf = makearraystring(a[1], __func__);
518*9a7741deSElliott Hughes 	if (!isarr(x)) {
519*9a7741deSElliott Hughes 		DPRINTF("making %s into an array\n", NN(x->nval));
520*9a7741deSElliott Hughes 		if (freeable(x))
521*9a7741deSElliott Hughes 			xfree(x->sval);
522*9a7741deSElliott Hughes 		x->tval &= ~(STR|NUM|DONTFREE);
523*9a7741deSElliott Hughes 		x->tval |= ARR;
524*9a7741deSElliott Hughes 		x->sval = (char *) makesymtab(NSYMTAB);
525*9a7741deSElliott Hughes 	}
526*9a7741deSElliott Hughes 	z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
527*9a7741deSElliott Hughes 	z->ctype = OCELL;
528*9a7741deSElliott Hughes 	z->csub = CVAR;
529*9a7741deSElliott Hughes 	tempfree(x);
530*9a7741deSElliott Hughes 	free(buf);
531*9a7741deSElliott Hughes 	return(z);
532*9a7741deSElliott Hughes }
533*9a7741deSElliott Hughes 
awkdelete(Node ** a,int n)534*9a7741deSElliott Hughes Cell *awkdelete(Node **a, int n)	/* a[0] is symtab, a[1] is list of subscripts */
535*9a7741deSElliott Hughes {
536*9a7741deSElliott Hughes 	Cell *x;
537*9a7741deSElliott Hughes 
538*9a7741deSElliott Hughes 	x = execute(a[0]);	/* Cell* for symbol table */
539*9a7741deSElliott Hughes 	if (x == symtabloc) {
540*9a7741deSElliott Hughes 		FATAL("cannot delete SYMTAB or its elements");
541*9a7741deSElliott Hughes 	}
542*9a7741deSElliott Hughes 	if (!isarr(x))
543*9a7741deSElliott Hughes 		return True;
544*9a7741deSElliott Hughes 	if (a[1] == NULL) {	/* delete the elements, not the table */
545*9a7741deSElliott Hughes 		freesymtab(x);
546*9a7741deSElliott Hughes 		x->tval &= ~STR;
547*9a7741deSElliott Hughes 		x->tval |= ARR;
548*9a7741deSElliott Hughes 		x->sval = (char *) makesymtab(NSYMTAB);
549*9a7741deSElliott Hughes 	} else {
550*9a7741deSElliott Hughes 		char *buf = makearraystring(a[1], __func__);
551*9a7741deSElliott Hughes 		freeelem(x, buf);
552*9a7741deSElliott Hughes 		free(buf);
553*9a7741deSElliott Hughes 	}
554*9a7741deSElliott Hughes 	tempfree(x);
555*9a7741deSElliott Hughes 	return True;
556*9a7741deSElliott Hughes }
557*9a7741deSElliott Hughes 
intest(Node ** a,int n)558*9a7741deSElliott Hughes Cell *intest(Node **a, int n)	/* a[0] is index (list), a[1] is symtab */
559*9a7741deSElliott Hughes {
560*9a7741deSElliott Hughes 	Cell *ap, *k;
561*9a7741deSElliott Hughes 	char *buf;
562*9a7741deSElliott Hughes 
563*9a7741deSElliott Hughes 	ap = execute(a[1]);	/* array name */
564*9a7741deSElliott Hughes 	if (!isarr(ap)) {
565*9a7741deSElliott Hughes 		DPRINTF("making %s into an array\n", ap->nval);
566*9a7741deSElliott Hughes 		if (freeable(ap))
567*9a7741deSElliott Hughes 			xfree(ap->sval);
568*9a7741deSElliott Hughes 		ap->tval &= ~(STR|NUM|DONTFREE);
569*9a7741deSElliott Hughes 		ap->tval |= ARR;
570*9a7741deSElliott Hughes 		ap->sval = (char *) makesymtab(NSYMTAB);
571*9a7741deSElliott Hughes 	}
572*9a7741deSElliott Hughes 	buf = makearraystring(a[0], __func__);
573*9a7741deSElliott Hughes 	k = lookup(buf, (Array *) ap->sval);
574*9a7741deSElliott Hughes 	tempfree(ap);
575*9a7741deSElliott Hughes 	free(buf);
576*9a7741deSElliott Hughes 	if (k == NULL)
577*9a7741deSElliott Hughes 		return(False);
578*9a7741deSElliott Hughes 	else
579*9a7741deSElliott Hughes 		return(True);
580*9a7741deSElliott Hughes }
581*9a7741deSElliott Hughes 
582*9a7741deSElliott Hughes 
583*9a7741deSElliott Hughes /* ======== utf-8 code ========== */
584*9a7741deSElliott Hughes 
585*9a7741deSElliott Hughes /*
586*9a7741deSElliott Hughes  * Awk strings can contain ascii, random 8-bit items (eg Latin-1),
587*9a7741deSElliott Hughes  * or utf-8.  u8_isutf tests whether a string starts with a valid
588*9a7741deSElliott Hughes  * utf-8 sequence, and returns 0 if not (e.g., high bit set).
589*9a7741deSElliott Hughes  * u8_nextlen returns length of next valid sequence, which is
590*9a7741deSElliott Hughes  * 1 for ascii, 2..4 for utf-8, or 1 for high bit non-utf.
591*9a7741deSElliott Hughes  * u8_strlen returns length of string in valid utf-8 sequences
592*9a7741deSElliott Hughes  * and/or high-bit bytes.  Conversion functions go between byte
593*9a7741deSElliott Hughes  * number and character number.
594*9a7741deSElliott Hughes  *
595*9a7741deSElliott Hughes  * In theory, this behaves the same as before for non-utf8 bytes.
596*9a7741deSElliott Hughes  *
597*9a7741deSElliott Hughes  * Limited checking! This is a potential security hole.
598*9a7741deSElliott Hughes  */
599*9a7741deSElliott Hughes 
600*9a7741deSElliott Hughes /* is s the beginning of a valid utf-8 string? */
601*9a7741deSElliott Hughes /* return length 1..4 if yes, 0 if no */
u8_isutf(const char * s)602*9a7741deSElliott Hughes int u8_isutf(const char *s)
603*9a7741deSElliott Hughes {
604*9a7741deSElliott Hughes 	int n, ret;
605*9a7741deSElliott Hughes 	unsigned char c;
606*9a7741deSElliott Hughes 
607*9a7741deSElliott Hughes 	c = s[0];
608*9a7741deSElliott Hughes 	if (c < 128 || awk_mb_cur_max == 1)
609*9a7741deSElliott Hughes 		return 1; /* what if it's 0? */
610*9a7741deSElliott Hughes 
611*9a7741deSElliott Hughes 	n = strlen(s);
612*9a7741deSElliott Hughes 	if (n >= 2 && ((c>>5) & 0x7) == 0x6 && (s[1] & 0xC0) == 0x80) {
613*9a7741deSElliott Hughes 		ret = 2; /* 110xxxxx 10xxxxxx */
614*9a7741deSElliott Hughes 	} else if (n >= 3 && ((c>>4) & 0xF) == 0xE && (s[1] & 0xC0) == 0x80
615*9a7741deSElliott Hughes 			 && (s[2] & 0xC0) == 0x80) {
616*9a7741deSElliott Hughes 		ret = 3; /* 1110xxxx 10xxxxxx 10xxxxxx */
617*9a7741deSElliott Hughes 	} else if (n >= 4 && ((c>>3) & 0x1F) == 0x1E && (s[1] & 0xC0) == 0x80
618*9a7741deSElliott Hughes 			 && (s[2] & 0xC0) == 0x80 && (s[3] & 0xC0) == 0x80) {
619*9a7741deSElliott Hughes 		ret = 4; /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
620*9a7741deSElliott Hughes 	} else {
621*9a7741deSElliott Hughes 		ret = 0;
622*9a7741deSElliott Hughes 	}
623*9a7741deSElliott Hughes 	return ret;
624*9a7741deSElliott Hughes }
625*9a7741deSElliott Hughes 
626*9a7741deSElliott Hughes /* Convert (prefix of) utf8 string to utf-32 rune. */
627*9a7741deSElliott Hughes /* Sets *rune to the value, returns the length. */
628*9a7741deSElliott Hughes /* No error checking: watch out. */
u8_rune(int * rune,const char * s)629*9a7741deSElliott Hughes int u8_rune(int *rune, const char *s)
630*9a7741deSElliott Hughes {
631*9a7741deSElliott Hughes 	int n, ret;
632*9a7741deSElliott Hughes 	unsigned char c;
633*9a7741deSElliott Hughes 
634*9a7741deSElliott Hughes 	c = s[0];
635*9a7741deSElliott Hughes 	if (c < 128 || awk_mb_cur_max == 1) {
636*9a7741deSElliott Hughes 		*rune = c;
637*9a7741deSElliott Hughes 		return 1;
638*9a7741deSElliott Hughes 	}
639*9a7741deSElliott Hughes 
640*9a7741deSElliott Hughes 	n = strlen(s);
641*9a7741deSElliott Hughes 	if (n >= 2 && ((c>>5) & 0x7) == 0x6 && (s[1] & 0xC0) == 0x80) {
642*9a7741deSElliott Hughes 		*rune = ((c & 0x1F) << 6) | (s[1] & 0x3F); /* 110xxxxx 10xxxxxx */
643*9a7741deSElliott Hughes 		ret = 2;
644*9a7741deSElliott Hughes 	} else if (n >= 3 && ((c>>4) & 0xF) == 0xE && (s[1] & 0xC0) == 0x80
645*9a7741deSElliott Hughes 			  && (s[2] & 0xC0) == 0x80) {
646*9a7741deSElliott Hughes 		*rune = ((c & 0xF) << 12) | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F);
647*9a7741deSElliott Hughes 			/* 1110xxxx 10xxxxxx 10xxxxxx */
648*9a7741deSElliott Hughes 		ret = 3;
649*9a7741deSElliott Hughes 	} else if (n >= 4 && ((c>>3) & 0x1F) == 0x1E && (s[1] & 0xC0) == 0x80
650*9a7741deSElliott Hughes 			  && (s[2] & 0xC0) == 0x80 && (s[3] & 0xC0) == 0x80) {
651*9a7741deSElliott Hughes 		*rune = ((c & 0x7) << 18) | ((s[1] & 0x3F) << 12) | ((s[2] & 0x3F) << 6) | (s[3] & 0x3F);
652*9a7741deSElliott Hughes 			/* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
653*9a7741deSElliott Hughes 		ret = 4;
654*9a7741deSElliott Hughes 	} else {
655*9a7741deSElliott Hughes 		*rune = c;
656*9a7741deSElliott Hughes 		ret = 1;
657*9a7741deSElliott Hughes 	}
658*9a7741deSElliott Hughes 	return ret; /* returns one byte if sequence doesn't look like utf */
659*9a7741deSElliott Hughes }
660*9a7741deSElliott Hughes 
661*9a7741deSElliott Hughes /* return length of next sequence: 1 for ascii or random, 2..4 for valid utf8 */
u8_nextlen(const char * s)662*9a7741deSElliott Hughes int u8_nextlen(const char *s)
663*9a7741deSElliott Hughes {
664*9a7741deSElliott Hughes 	int len;
665*9a7741deSElliott Hughes 
666*9a7741deSElliott Hughes 	len = u8_isutf(s);
667*9a7741deSElliott Hughes 	if (len == 0)
668*9a7741deSElliott Hughes 		len = 1;
669*9a7741deSElliott Hughes 	return len;
670*9a7741deSElliott Hughes }
671*9a7741deSElliott Hughes 
672*9a7741deSElliott Hughes /* return number of utf characters or single non-utf bytes */
u8_strlen(const char * s)673*9a7741deSElliott Hughes int u8_strlen(const char *s)
674*9a7741deSElliott Hughes {
675*9a7741deSElliott Hughes 	int i, len, n, totlen;
676*9a7741deSElliott Hughes 	unsigned char c;
677*9a7741deSElliott Hughes 
678*9a7741deSElliott Hughes 	n = strlen(s);
679*9a7741deSElliott Hughes 	totlen = 0;
680*9a7741deSElliott Hughes 	for (i = 0; i < n; i += len) {
681*9a7741deSElliott Hughes 		c = s[i];
682*9a7741deSElliott Hughes 		if (c < 128 || awk_mb_cur_max == 1) {
683*9a7741deSElliott Hughes 			len = 1;
684*9a7741deSElliott Hughes 		} else {
685*9a7741deSElliott Hughes 			len = u8_nextlen(&s[i]);
686*9a7741deSElliott Hughes 		}
687*9a7741deSElliott Hughes 		totlen++;
688*9a7741deSElliott Hughes 		if (i > n)
689*9a7741deSElliott Hughes 			FATAL("bad utf count [%s] n=%d i=%d\n", s, n, i);
690*9a7741deSElliott Hughes 	}
691*9a7741deSElliott Hughes 	return totlen;
692*9a7741deSElliott Hughes }
693*9a7741deSElliott Hughes 
694*9a7741deSElliott Hughes /* convert utf-8 char number in a string to its byte offset */
u8_char2byte(const char * s,int charnum)695*9a7741deSElliott Hughes int u8_char2byte(const char *s, int charnum)
696*9a7741deSElliott Hughes {
697*9a7741deSElliott Hughes 	int n;
698*9a7741deSElliott Hughes 	int bytenum = 0;
699*9a7741deSElliott Hughes 
700*9a7741deSElliott Hughes 	while (charnum > 0) {
701*9a7741deSElliott Hughes 		n = u8_nextlen(s);
702*9a7741deSElliott Hughes 		s += n;
703*9a7741deSElliott Hughes 		bytenum += n;
704*9a7741deSElliott Hughes 		charnum--;
705*9a7741deSElliott Hughes 	}
706*9a7741deSElliott Hughes 	return bytenum;
707*9a7741deSElliott Hughes }
708*9a7741deSElliott Hughes 
709*9a7741deSElliott Hughes /* convert byte offset in s to utf-8 char number that starts there */
u8_byte2char(const char * s,int bytenum)710*9a7741deSElliott Hughes int u8_byte2char(const char *s, int bytenum)
711*9a7741deSElliott Hughes {
712*9a7741deSElliott Hughes 	int i, len, b;
713*9a7741deSElliott Hughes 	int charnum = 0; /* BUG: what origin? */
714*9a7741deSElliott Hughes 	/* should be 0 to match start==0 which means no match */
715*9a7741deSElliott Hughes 
716*9a7741deSElliott Hughes 	b = strlen(s);
717*9a7741deSElliott Hughes 	if (bytenum > b) {
718*9a7741deSElliott Hughes 		return -1; /* ??? */
719*9a7741deSElliott Hughes 	}
720*9a7741deSElliott Hughes 	for (i = 0; i <= bytenum; i += len) {
721*9a7741deSElliott Hughes 		len = u8_nextlen(s+i);
722*9a7741deSElliott Hughes 		charnum++;
723*9a7741deSElliott Hughes 	}
724*9a7741deSElliott Hughes 	return charnum;
725*9a7741deSElliott Hughes }
726*9a7741deSElliott Hughes 
727*9a7741deSElliott Hughes /* runetochar() adapted from rune.c in the Plan 9 distribution */
728*9a7741deSElliott Hughes 
729*9a7741deSElliott Hughes enum
730*9a7741deSElliott Hughes {
731*9a7741deSElliott Hughes 	Runeerror = 128, /* from somewhere else */
732*9a7741deSElliott Hughes 	Runemax = 0x10FFFF,
733*9a7741deSElliott Hughes 
734*9a7741deSElliott Hughes 	Bit1    = 7,
735*9a7741deSElliott Hughes 	Bitx    = 6,
736*9a7741deSElliott Hughes 	Bit2    = 5,
737*9a7741deSElliott Hughes 	Bit3    = 4,
738*9a7741deSElliott Hughes 	Bit4    = 3,
739*9a7741deSElliott Hughes 	Bit5    = 2,
740*9a7741deSElliott Hughes 
741*9a7741deSElliott Hughes 	T1      = ((1<<(Bit1+1))-1) ^ 0xFF,     /* 0000 0000 */
742*9a7741deSElliott Hughes 	Tx      = ((1<<(Bitx+1))-1) ^ 0xFF,     /* 1000 0000 */
743*9a7741deSElliott Hughes 	T2      = ((1<<(Bit2+1))-1) ^ 0xFF,     /* 1100 0000 */
744*9a7741deSElliott Hughes 	T3      = ((1<<(Bit3+1))-1) ^ 0xFF,     /* 1110 0000 */
745*9a7741deSElliott Hughes 	T4      = ((1<<(Bit4+1))-1) ^ 0xFF,     /* 1111 0000 */
746*9a7741deSElliott Hughes 	T5      = ((1<<(Bit5+1))-1) ^ 0xFF,     /* 1111 1000 */
747*9a7741deSElliott Hughes 
748*9a7741deSElliott Hughes 	Rune1   = (1<<(Bit1+0*Bitx))-1,	 	/* 0000 0000 0000 0000 0111 1111 */
749*9a7741deSElliott Hughes 	Rune2   = (1<<(Bit2+1*Bitx))-1,	 	/* 0000 0000 0000 0111 1111 1111 */
750*9a7741deSElliott Hughes 	Rune3   = (1<<(Bit3+2*Bitx))-1,	 	/* 0000 0000 1111 1111 1111 1111 */
751*9a7741deSElliott Hughes 	Rune4   = (1<<(Bit4+3*Bitx))-1,	 	/* 0011 1111 1111 1111 1111 1111 */
752*9a7741deSElliott Hughes 
753*9a7741deSElliott Hughes 	Maskx   = (1<<Bitx)-1,		  	/* 0011 1111 */
754*9a7741deSElliott Hughes 	Testx   = Maskx ^ 0xFF,		 	/* 1100 0000 */
755*9a7741deSElliott Hughes 
756*9a7741deSElliott Hughes };
757*9a7741deSElliott Hughes 
runetochar(char * str,int c)758*9a7741deSElliott Hughes int runetochar(char *str, int c)
759*9a7741deSElliott Hughes {
760*9a7741deSElliott Hughes 	/* one character sequence 00000-0007F => 00-7F */
761*9a7741deSElliott Hughes 	if (c <= Rune1) {
762*9a7741deSElliott Hughes 		str[0] = c;
763*9a7741deSElliott Hughes 		return 1;
764*9a7741deSElliott Hughes 	}
765*9a7741deSElliott Hughes 
766*9a7741deSElliott Hughes 	/* two character sequence 00080-007FF => T2 Tx */
767*9a7741deSElliott Hughes 	if (c <= Rune2) {
768*9a7741deSElliott Hughes 		str[0] = T2 | (c >> 1*Bitx);
769*9a7741deSElliott Hughes 		str[1] = Tx | (c & Maskx);
770*9a7741deSElliott Hughes 		return 2;
771*9a7741deSElliott Hughes 	}
772*9a7741deSElliott Hughes 
773*9a7741deSElliott Hughes 	/* three character sequence 00800-0FFFF => T3 Tx Tx */
774*9a7741deSElliott Hughes 	if (c > Runemax)
775*9a7741deSElliott Hughes 		c = Runeerror;
776*9a7741deSElliott Hughes 	if (c <= Rune3) {
777*9a7741deSElliott Hughes 		str[0] = T3 |  (c >> 2*Bitx);
778*9a7741deSElliott Hughes 		str[1] = Tx | ((c >> 1*Bitx) & Maskx);
779*9a7741deSElliott Hughes 		str[2] = Tx |  (c & Maskx);
780*9a7741deSElliott Hughes 		return 3;
781*9a7741deSElliott Hughes 	}
782*9a7741deSElliott Hughes 
783*9a7741deSElliott Hughes 	/* four character sequence 010000-1FFFFF => T4 Tx Tx Tx */
784*9a7741deSElliott Hughes 	str[0] = T4 |  (c >> 3*Bitx);
785*9a7741deSElliott Hughes 	str[1] = Tx | ((c >> 2*Bitx) & Maskx);
786*9a7741deSElliott Hughes 	str[2] = Tx | ((c >> 1*Bitx) & Maskx);
787*9a7741deSElliott Hughes 	str[3] = Tx |  (c & Maskx);
788*9a7741deSElliott Hughes 	return 4;
789*9a7741deSElliott Hughes }
790*9a7741deSElliott Hughes 
791*9a7741deSElliott Hughes 
792*9a7741deSElliott Hughes /* ========== end of utf8 code =========== */
793*9a7741deSElliott Hughes 
794*9a7741deSElliott Hughes 
795*9a7741deSElliott Hughes 
matchop(Node ** a,int n)796*9a7741deSElliott Hughes Cell *matchop(Node **a, int n)	/* ~ and match() */
797*9a7741deSElliott Hughes {
798*9a7741deSElliott Hughes 	Cell *x, *y, *z;
799*9a7741deSElliott Hughes 	char *s, *t;
800*9a7741deSElliott Hughes 	int i;
801*9a7741deSElliott Hughes 	int cstart, cpatlen, len;
802*9a7741deSElliott Hughes 	fa *pfa;
803*9a7741deSElliott Hughes 	int (*mf)(fa *, const char *) = match, mode = 0;
804*9a7741deSElliott Hughes 
805*9a7741deSElliott Hughes 	if (n == MATCHFCN) {
806*9a7741deSElliott Hughes 		mf = pmatch;
807*9a7741deSElliott Hughes 		mode = 1;
808*9a7741deSElliott Hughes 	}
809*9a7741deSElliott Hughes 	x = execute(a[1]);	/* a[1] = target text */
810*9a7741deSElliott Hughes 	s = getsval(x);
811*9a7741deSElliott Hughes 	if (a[0] == NULL)	/* a[1] == 0: already-compiled reg expr */
812*9a7741deSElliott Hughes 		i = (*mf)((fa *) a[2], s);
813*9a7741deSElliott Hughes 	else {
814*9a7741deSElliott Hughes 		y = execute(a[2]);	/* a[2] = regular expr */
815*9a7741deSElliott Hughes 		t = getsval(y);
816*9a7741deSElliott Hughes 		pfa = makedfa(t, mode);
817*9a7741deSElliott Hughes 		i = (*mf)(pfa, s);
818*9a7741deSElliott Hughes 		tempfree(y);
819*9a7741deSElliott Hughes 	}
820*9a7741deSElliott Hughes 	z = x;
821*9a7741deSElliott Hughes 	if (n == MATCHFCN) {
822*9a7741deSElliott Hughes 		int start = patbeg - s + 1; /* origin 1 */
823*9a7741deSElliott Hughes 		if (patlen < 0) {
824*9a7741deSElliott Hughes 			start = 0; /* not found */
825*9a7741deSElliott Hughes 		} else {
826*9a7741deSElliott Hughes 			cstart = u8_byte2char(s, start-1);
827*9a7741deSElliott Hughes 			cpatlen = 0;
828*9a7741deSElliott Hughes 			for (i = 0; i < patlen; i += len) {
829*9a7741deSElliott Hughes 				len = u8_nextlen(patbeg+i);
830*9a7741deSElliott Hughes 				cpatlen++;
831*9a7741deSElliott Hughes 			}
832*9a7741deSElliott Hughes 
833*9a7741deSElliott Hughes 			start = cstart;
834*9a7741deSElliott Hughes 			patlen = cpatlen;
835*9a7741deSElliott Hughes 		}
836*9a7741deSElliott Hughes 
837*9a7741deSElliott Hughes 		setfval(rstartloc, (Awkfloat) start);
838*9a7741deSElliott Hughes 		setfval(rlengthloc, (Awkfloat) patlen);
839*9a7741deSElliott Hughes 		x = gettemp();
840*9a7741deSElliott Hughes 		x->tval = NUM;
841*9a7741deSElliott Hughes 		x->fval = start;
842*9a7741deSElliott Hughes 	} else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
843*9a7741deSElliott Hughes 		x = True;
844*9a7741deSElliott Hughes 	else
845*9a7741deSElliott Hughes 		x = False;
846*9a7741deSElliott Hughes 
847*9a7741deSElliott Hughes 	tempfree(z);
848*9a7741deSElliott Hughes 	return x;
849*9a7741deSElliott Hughes }
850*9a7741deSElliott Hughes 
851*9a7741deSElliott Hughes 
boolop(Node ** a,int n)852*9a7741deSElliott Hughes Cell *boolop(Node **a, int n)	/* a[0] || a[1], a[0] && a[1], !a[0] */
853*9a7741deSElliott Hughes {
854*9a7741deSElliott Hughes 	Cell *x, *y;
855*9a7741deSElliott Hughes 	int i;
856*9a7741deSElliott Hughes 
857*9a7741deSElliott Hughes 	x = execute(a[0]);
858*9a7741deSElliott Hughes 	i = istrue(x);
859*9a7741deSElliott Hughes 	tempfree(x);
860*9a7741deSElliott Hughes 	switch (n) {
861*9a7741deSElliott Hughes 	case BOR:
862*9a7741deSElliott Hughes 		if (i) return(True);
863*9a7741deSElliott Hughes 		y = execute(a[1]);
864*9a7741deSElliott Hughes 		i = istrue(y);
865*9a7741deSElliott Hughes 		tempfree(y);
866*9a7741deSElliott Hughes 		if (i) return(True);
867*9a7741deSElliott Hughes 		else return(False);
868*9a7741deSElliott Hughes 	case AND:
869*9a7741deSElliott Hughes 		if ( !i ) return(False);
870*9a7741deSElliott Hughes 		y = execute(a[1]);
871*9a7741deSElliott Hughes 		i = istrue(y);
872*9a7741deSElliott Hughes 		tempfree(y);
873*9a7741deSElliott Hughes 		if (i) return(True);
874*9a7741deSElliott Hughes 		else return(False);
875*9a7741deSElliott Hughes 	case NOT:
876*9a7741deSElliott Hughes 		if (i) return(False);
877*9a7741deSElliott Hughes 		else return(True);
878*9a7741deSElliott Hughes 	default:	/* can't happen */
879*9a7741deSElliott Hughes 		FATAL("unknown boolean operator %d", n);
880*9a7741deSElliott Hughes 	}
881*9a7741deSElliott Hughes 	return 0;	/*NOTREACHED*/
882*9a7741deSElliott Hughes }
883*9a7741deSElliott Hughes 
relop(Node ** a,int n)884*9a7741deSElliott Hughes Cell *relop(Node **a, int n)	/* a[0 < a[1], etc. */
885*9a7741deSElliott Hughes {
886*9a7741deSElliott Hughes 	int i;
887*9a7741deSElliott Hughes 	Cell *x, *y;
888*9a7741deSElliott Hughes 	Awkfloat j;
889*9a7741deSElliott Hughes 	bool x_is_nan, y_is_nan;
890*9a7741deSElliott Hughes 
891*9a7741deSElliott Hughes 	x = execute(a[0]);
892*9a7741deSElliott Hughes 	y = execute(a[1]);
893*9a7741deSElliott Hughes 	x_is_nan = isnan(x->fval);
894*9a7741deSElliott Hughes 	y_is_nan = isnan(y->fval);
895*9a7741deSElliott Hughes 	if (x->tval&NUM && y->tval&NUM) {
896*9a7741deSElliott Hughes 		if ((x_is_nan || y_is_nan) && n != NE)
897*9a7741deSElliott Hughes 			return(False);
898*9a7741deSElliott Hughes 		j = x->fval - y->fval;
899*9a7741deSElliott Hughes 		i = j<0? -1: (j>0? 1: 0);
900*9a7741deSElliott Hughes 	} else {
901*9a7741deSElliott Hughes 		i = strcmp(getsval(x), getsval(y));
902*9a7741deSElliott Hughes 	}
903*9a7741deSElliott Hughes 	tempfree(x);
904*9a7741deSElliott Hughes 	tempfree(y);
905*9a7741deSElliott Hughes 	switch (n) {
906*9a7741deSElliott Hughes 	case LT:	if (i<0) return(True);
907*9a7741deSElliott Hughes 			else return(False);
908*9a7741deSElliott Hughes 	case LE:	if (i<=0) return(True);
909*9a7741deSElliott Hughes 			else return(False);
910*9a7741deSElliott Hughes 	case NE:	if (x_is_nan && y_is_nan) return(True);
911*9a7741deSElliott Hughes 			else if (i!=0) return(True);
912*9a7741deSElliott Hughes 			else return(False);
913*9a7741deSElliott Hughes 	case EQ:	if (i == 0) return(True);
914*9a7741deSElliott Hughes 			else return(False);
915*9a7741deSElliott Hughes 	case GE:	if (i>=0) return(True);
916*9a7741deSElliott Hughes 			else return(False);
917*9a7741deSElliott Hughes 	case GT:	if (i>0) return(True);
918*9a7741deSElliott Hughes 			else return(False);
919*9a7741deSElliott Hughes 	default:	/* can't happen */
920*9a7741deSElliott Hughes 		FATAL("unknown relational operator %d", n);
921*9a7741deSElliott Hughes 	}
922*9a7741deSElliott Hughes 	return 0;	/*NOTREACHED*/
923*9a7741deSElliott Hughes }
924*9a7741deSElliott Hughes 
tfree(Cell * a)925*9a7741deSElliott Hughes void tfree(Cell *a)	/* free a tempcell */
926*9a7741deSElliott Hughes {
927*9a7741deSElliott Hughes 	if (freeable(a)) {
928*9a7741deSElliott Hughes 		DPRINTF("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval);
929*9a7741deSElliott Hughes 		xfree(a->sval);
930*9a7741deSElliott Hughes 	}
931*9a7741deSElliott Hughes 	if (a == tmps)
932*9a7741deSElliott Hughes 		FATAL("tempcell list is curdled");
933*9a7741deSElliott Hughes 	a->cnext = tmps;
934*9a7741deSElliott Hughes 	tmps = a;
935*9a7741deSElliott Hughes }
936*9a7741deSElliott Hughes 
gettemp(void)937*9a7741deSElliott Hughes Cell *gettemp(void)	/* get a tempcell */
938*9a7741deSElliott Hughes {	int i;
939*9a7741deSElliott Hughes 	Cell *x;
940*9a7741deSElliott Hughes 
941*9a7741deSElliott Hughes 	if (!tmps) {
942*9a7741deSElliott Hughes 		tmps = (Cell *) calloc(100, sizeof(*tmps));
943*9a7741deSElliott Hughes 		if (!tmps)
944*9a7741deSElliott Hughes 			FATAL("out of space for temporaries");
945*9a7741deSElliott Hughes 		for (i = 1; i < 100; i++)
946*9a7741deSElliott Hughes 			tmps[i-1].cnext = &tmps[i];
947*9a7741deSElliott Hughes 		tmps[i-1].cnext = NULL;
948*9a7741deSElliott Hughes 	}
949*9a7741deSElliott Hughes 	x = tmps;
950*9a7741deSElliott Hughes 	tmps = x->cnext;
951*9a7741deSElliott Hughes 	*x = tempcell;
952*9a7741deSElliott Hughes 	return(x);
953*9a7741deSElliott Hughes }
954*9a7741deSElliott Hughes 
indirect(Node ** a,int n)955*9a7741deSElliott Hughes Cell *indirect(Node **a, int n)	/* $( a[0] ) */
956*9a7741deSElliott Hughes {
957*9a7741deSElliott Hughes 	Awkfloat val;
958*9a7741deSElliott Hughes 	Cell *x;
959*9a7741deSElliott Hughes 	int m;
960*9a7741deSElliott Hughes 	char *s;
961*9a7741deSElliott Hughes 
962*9a7741deSElliott Hughes 	x = execute(a[0]);
963*9a7741deSElliott Hughes 	val = getfval(x);	/* freebsd: defend against super large field numbers */
964*9a7741deSElliott Hughes 	if ((Awkfloat)INT_MAX < val)
965*9a7741deSElliott Hughes 		FATAL("trying to access out of range field %s", x->nval);
966*9a7741deSElliott Hughes 	m = (int) val;
967*9a7741deSElliott Hughes 	if (m == 0 && !is_number(s = getsval(x), NULL))	/* suspicion! */
968*9a7741deSElliott Hughes 		FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
969*9a7741deSElliott Hughes 		/* BUG: can x->nval ever be null??? */
970*9a7741deSElliott Hughes 	tempfree(x);
971*9a7741deSElliott Hughes 	x = fieldadr(m);
972*9a7741deSElliott Hughes 	x->ctype = OCELL;	/* BUG?  why are these needed? */
973*9a7741deSElliott Hughes 	x->csub = CFLD;
974*9a7741deSElliott Hughes 	return(x);
975*9a7741deSElliott Hughes }
976*9a7741deSElliott Hughes 
substr(Node ** a,int nnn)977*9a7741deSElliott Hughes Cell *substr(Node **a, int nnn)		/* substr(a[0], a[1], a[2]) */
978*9a7741deSElliott Hughes {
979*9a7741deSElliott Hughes 	int k, m, n;
980*9a7741deSElliott Hughes 	int mb, nb;
981*9a7741deSElliott Hughes 	char *s;
982*9a7741deSElliott Hughes 	int temp;
983*9a7741deSElliott Hughes 	Cell *x, *y, *z = NULL;
984*9a7741deSElliott Hughes 
985*9a7741deSElliott Hughes 	x = execute(a[0]);
986*9a7741deSElliott Hughes 	y = execute(a[1]);
987*9a7741deSElliott Hughes 	if (a[2] != NULL)
988*9a7741deSElliott Hughes 		z = execute(a[2]);
989*9a7741deSElliott Hughes 	s = getsval(x);
990*9a7741deSElliott Hughes 	k = u8_strlen(s) + 1;
991*9a7741deSElliott Hughes 	if (k <= 1) {
992*9a7741deSElliott Hughes 		tempfree(x);
993*9a7741deSElliott Hughes 		tempfree(y);
994*9a7741deSElliott Hughes 		if (a[2] != NULL) {
995*9a7741deSElliott Hughes 			tempfree(z);
996*9a7741deSElliott Hughes 		}
997*9a7741deSElliott Hughes 		x = gettemp();
998*9a7741deSElliott Hughes 		setsval(x, "");
999*9a7741deSElliott Hughes 		return(x);
1000*9a7741deSElliott Hughes 	}
1001*9a7741deSElliott Hughes 	m = (int) getfval(y);
1002*9a7741deSElliott Hughes 	if (m <= 0)
1003*9a7741deSElliott Hughes 		m = 1;
1004*9a7741deSElliott Hughes 	else if (m > k)
1005*9a7741deSElliott Hughes 		m = k;
1006*9a7741deSElliott Hughes 	tempfree(y);
1007*9a7741deSElliott Hughes 	if (a[2] != NULL) {
1008*9a7741deSElliott Hughes 		n = (int) getfval(z);
1009*9a7741deSElliott Hughes 		tempfree(z);
1010*9a7741deSElliott Hughes 	} else
1011*9a7741deSElliott Hughes 		n = k - 1;
1012*9a7741deSElliott Hughes 	if (n < 0)
1013*9a7741deSElliott Hughes 		n = 0;
1014*9a7741deSElliott Hughes 	else if (n > k - m)
1015*9a7741deSElliott Hughes 		n = k - m;
1016*9a7741deSElliott Hughes 	/* m is start, n is length from there */
1017*9a7741deSElliott Hughes 	DPRINTF("substr: m=%d, n=%d, s=%s\n", m, n, s);
1018*9a7741deSElliott Hughes 	y = gettemp();
1019*9a7741deSElliott Hughes 	mb = u8_char2byte(s, m-1); /* byte offset of start char in s */
1020*9a7741deSElliott Hughes 	nb = u8_char2byte(s, m-1+n);  /* byte offset of end+1 char in s */
1021*9a7741deSElliott Hughes 
1022*9a7741deSElliott Hughes 	temp = s[nb];	/* with thanks to John Linderman */
1023*9a7741deSElliott Hughes 	s[nb] = '\0';
1024*9a7741deSElliott Hughes 	setsval(y, s + mb);
1025*9a7741deSElliott Hughes 	s[nb] = temp;
1026*9a7741deSElliott Hughes 	tempfree(x);
1027*9a7741deSElliott Hughes 	return(y);
1028*9a7741deSElliott Hughes }
1029*9a7741deSElliott Hughes 
sindex(Node ** a,int nnn)1030*9a7741deSElliott Hughes Cell *sindex(Node **a, int nnn)		/* index(a[0], a[1]) */
1031*9a7741deSElliott Hughes {
1032*9a7741deSElliott Hughes 	Cell *x, *y, *z;
1033*9a7741deSElliott Hughes 	char *s1, *s2, *p1, *p2, *q;
1034*9a7741deSElliott Hughes 	Awkfloat v = 0.0;
1035*9a7741deSElliott Hughes 
1036*9a7741deSElliott Hughes 	x = execute(a[0]);
1037*9a7741deSElliott Hughes 	s1 = getsval(x);
1038*9a7741deSElliott Hughes 	y = execute(a[1]);
1039*9a7741deSElliott Hughes 	s2 = getsval(y);
1040*9a7741deSElliott Hughes 
1041*9a7741deSElliott Hughes 	z = gettemp();
1042*9a7741deSElliott Hughes 	for (p1 = s1; *p1 != '\0'; p1++) {
1043*9a7741deSElliott Hughes 		for (q = p1, p2 = s2; *p2 != '\0' && *q == *p2; q++, p2++)
1044*9a7741deSElliott Hughes 			continue;
1045*9a7741deSElliott Hughes 		if (*p2 == '\0') {
1046*9a7741deSElliott Hughes 			/* v = (Awkfloat) (p1 - s1 + 1);	 origin 1 */
1047*9a7741deSElliott Hughes 
1048*9a7741deSElliott Hughes 		   /* should be a function: used in match() as well */
1049*9a7741deSElliott Hughes 			int i, len;
1050*9a7741deSElliott Hughes 			v = 0;
1051*9a7741deSElliott Hughes 			for (i = 0; i < p1-s1+1; i += len) {
1052*9a7741deSElliott Hughes 				len = u8_nextlen(s1+i);
1053*9a7741deSElliott Hughes 				v++;
1054*9a7741deSElliott Hughes 			}
1055*9a7741deSElliott Hughes 			break;
1056*9a7741deSElliott Hughes 		}
1057*9a7741deSElliott Hughes 	}
1058*9a7741deSElliott Hughes 	tempfree(x);
1059*9a7741deSElliott Hughes 	tempfree(y);
1060*9a7741deSElliott Hughes 	setfval(z, v);
1061*9a7741deSElliott Hughes 	return(z);
1062*9a7741deSElliott Hughes }
1063*9a7741deSElliott Hughes 
has_utf8(char * s)1064*9a7741deSElliott Hughes int has_utf8(char *s)	/* return 1 if s contains any utf-8 (2 bytes or more) character */
1065*9a7741deSElliott Hughes {
1066*9a7741deSElliott Hughes 	int n;
1067*9a7741deSElliott Hughes 
1068*9a7741deSElliott Hughes 	for (n = 0; *s != 0; s += n) {
1069*9a7741deSElliott Hughes 		n = u8_nextlen(s);
1070*9a7741deSElliott Hughes 		if (n > 1)
1071*9a7741deSElliott Hughes 			return 1;
1072*9a7741deSElliott Hughes 	}
1073*9a7741deSElliott Hughes 	return 0;
1074*9a7741deSElliott Hughes }
1075*9a7741deSElliott Hughes 
1076*9a7741deSElliott Hughes #define	MAXNUMSIZE	50
1077*9a7741deSElliott Hughes 
format(char ** pbuf,int * pbufsize,const char * s,Node * a)1078*9a7741deSElliott Hughes int format(char **pbuf, int *pbufsize, const char *s, Node *a)	/* printf-like conversions */
1079*9a7741deSElliott Hughes {
1080*9a7741deSElliott Hughes 	char *fmt;
1081*9a7741deSElliott Hughes 	char *p, *t;
1082*9a7741deSElliott Hughes 	const char *os;
1083*9a7741deSElliott Hughes 	Cell *x;
1084*9a7741deSElliott Hughes 	int flag = 0, n;
1085*9a7741deSElliott Hughes 	int fmtwd; /* format width */
1086*9a7741deSElliott Hughes 	int fmtsz = recsize;
1087*9a7741deSElliott Hughes 	char *buf = *pbuf;
1088*9a7741deSElliott Hughes 	int bufsize = *pbufsize;
1089*9a7741deSElliott Hughes #define FMTSZ(a)   (fmtsz - ((a) - fmt))
1090*9a7741deSElliott Hughes #define BUFSZ(a)   (bufsize - ((a) - buf))
1091*9a7741deSElliott Hughes 
1092*9a7741deSElliott Hughes 	static bool first = true;
1093*9a7741deSElliott Hughes 	static bool have_a_format = false;
1094*9a7741deSElliott Hughes 
1095*9a7741deSElliott Hughes 	if (first) {
1096*9a7741deSElliott Hughes 		char xbuf[100];
1097*9a7741deSElliott Hughes 
1098*9a7741deSElliott Hughes 		snprintf(xbuf, sizeof(xbuf), "%a", 42.0);
1099*9a7741deSElliott Hughes 		have_a_format = (strcmp(xbuf, "0x1.5p+5") == 0);
1100*9a7741deSElliott Hughes 		first = false;
1101*9a7741deSElliott Hughes 	}
1102*9a7741deSElliott Hughes 
1103*9a7741deSElliott Hughes 	os = s;
1104*9a7741deSElliott Hughes 	p = buf;
1105*9a7741deSElliott Hughes 	if ((fmt = (char *) malloc(fmtsz)) == NULL)
1106*9a7741deSElliott Hughes 		FATAL("out of memory in format()");
1107*9a7741deSElliott Hughes 	while (*s) {
1108*9a7741deSElliott Hughes 		adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1");
1109*9a7741deSElliott Hughes 		if (*s != '%') {
1110*9a7741deSElliott Hughes 			*p++ = *s++;
1111*9a7741deSElliott Hughes 			continue;
1112*9a7741deSElliott Hughes 		}
1113*9a7741deSElliott Hughes 		if (*(s+1) == '%') {
1114*9a7741deSElliott Hughes 			*p++ = '%';
1115*9a7741deSElliott Hughes 			s += 2;
1116*9a7741deSElliott Hughes 			continue;
1117*9a7741deSElliott Hughes 		}
1118*9a7741deSElliott Hughes 		fmtwd = atoi(s+1);
1119*9a7741deSElliott Hughes 		if (fmtwd < 0)
1120*9a7741deSElliott Hughes 			fmtwd = -fmtwd;
1121*9a7741deSElliott Hughes 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format2");
1122*9a7741deSElliott Hughes 		for (t = fmt; (*t++ = *s) != '\0'; s++) {
1123*9a7741deSElliott Hughes 			if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3"))
1124*9a7741deSElliott Hughes 				FATAL("format item %.30s... ran format() out of memory", os);
1125*9a7741deSElliott Hughes 			/* Ignore size specifiers */
1126*9a7741deSElliott Hughes 			if (strchr("hjLlqtz", *s) != NULL) {	/* the ansi panoply */
1127*9a7741deSElliott Hughes 				t--;
1128*9a7741deSElliott Hughes 				continue;
1129*9a7741deSElliott Hughes 			}
1130*9a7741deSElliott Hughes 			if (isalpha((uschar)*s))
1131*9a7741deSElliott Hughes 				break;
1132*9a7741deSElliott Hughes 			if (*s == '$') {
1133*9a7741deSElliott Hughes 				FATAL("'$' not permitted in awk formats");
1134*9a7741deSElliott Hughes 			}
1135*9a7741deSElliott Hughes 			if (*s == '*') {
1136*9a7741deSElliott Hughes 				if (a == NULL) {
1137*9a7741deSElliott Hughes 					FATAL("not enough args in printf(%s)", os);
1138*9a7741deSElliott Hughes 				}
1139*9a7741deSElliott Hughes 				x = execute(a);
1140*9a7741deSElliott Hughes 				a = a->nnext;
1141*9a7741deSElliott Hughes 				snprintf(t - 1, FMTSZ(t - 1),
1142*9a7741deSElliott Hughes 				    "%d", fmtwd=(int) getfval(x));
1143*9a7741deSElliott Hughes 				if (fmtwd < 0)
1144*9a7741deSElliott Hughes 					fmtwd = -fmtwd;
1145*9a7741deSElliott Hughes 				adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
1146*9a7741deSElliott Hughes 				t = fmt + strlen(fmt);
1147*9a7741deSElliott Hughes 				tempfree(x);
1148*9a7741deSElliott Hughes 			}
1149*9a7741deSElliott Hughes 		}
1150*9a7741deSElliott Hughes 		*t = '\0';
1151*9a7741deSElliott Hughes 		if (fmtwd < 0)
1152*9a7741deSElliott Hughes 			fmtwd = -fmtwd;
1153*9a7741deSElliott Hughes 		adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format4");
1154*9a7741deSElliott Hughes 		switch (*s) {
1155*9a7741deSElliott Hughes 		case 'a': case 'A':
1156*9a7741deSElliott Hughes 			if (have_a_format)
1157*9a7741deSElliott Hughes 				flag = *s;
1158*9a7741deSElliott Hughes 			else
1159*9a7741deSElliott Hughes 				flag = 'f';
1160*9a7741deSElliott Hughes 			break;
1161*9a7741deSElliott Hughes 		case 'f': case 'e': case 'g': case 'E': case 'G':
1162*9a7741deSElliott Hughes 			flag = 'f';
1163*9a7741deSElliott Hughes 			break;
1164*9a7741deSElliott Hughes 		case 'd': case 'i': case 'o': case 'x': case 'X': case 'u':
1165*9a7741deSElliott Hughes 			flag = (*s == 'd' || *s == 'i') ? 'd' : 'u';
1166*9a7741deSElliott Hughes 			*(t-1) = 'j';
1167*9a7741deSElliott Hughes 			*t = *s;
1168*9a7741deSElliott Hughes 			*++t = '\0';
1169*9a7741deSElliott Hughes 			break;
1170*9a7741deSElliott Hughes 		case 's':
1171*9a7741deSElliott Hughes 			flag = 's';
1172*9a7741deSElliott Hughes 			break;
1173*9a7741deSElliott Hughes 		case 'c':
1174*9a7741deSElliott Hughes 			flag = 'c';
1175*9a7741deSElliott Hughes 			break;
1176*9a7741deSElliott Hughes 		default:
1177*9a7741deSElliott Hughes 			WARNING("weird printf conversion %s", fmt);
1178*9a7741deSElliott Hughes 			flag = '?';
1179*9a7741deSElliott Hughes 			break;
1180*9a7741deSElliott Hughes 		}
1181*9a7741deSElliott Hughes 		if (a == NULL)
1182*9a7741deSElliott Hughes 			FATAL("not enough args in printf(%s)", os);
1183*9a7741deSElliott Hughes 		x = execute(a);
1184*9a7741deSElliott Hughes 		a = a->nnext;
1185*9a7741deSElliott Hughes 		n = MAXNUMSIZE;
1186*9a7741deSElliott Hughes 		if (fmtwd > n)
1187*9a7741deSElliott Hughes 			n = fmtwd;
1188*9a7741deSElliott Hughes 		adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5");
1189*9a7741deSElliott Hughes 		switch (flag) {
1190*9a7741deSElliott Hughes 		case '?':
1191*9a7741deSElliott Hughes 			snprintf(p, BUFSZ(p), "%s", fmt);	/* unknown, so dump it too */
1192*9a7741deSElliott Hughes 			t = getsval(x);
1193*9a7741deSElliott Hughes 			n = strlen(t);
1194*9a7741deSElliott Hughes 			if (fmtwd > n)
1195*9a7741deSElliott Hughes 				n = fmtwd;
1196*9a7741deSElliott Hughes 			adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6");
1197*9a7741deSElliott Hughes 			p += strlen(p);
1198*9a7741deSElliott Hughes 			snprintf(p, BUFSZ(p), "%s", t);
1199*9a7741deSElliott Hughes 			break;
1200*9a7741deSElliott Hughes 		case 'a':
1201*9a7741deSElliott Hughes 		case 'A':
1202*9a7741deSElliott Hughes 		case 'f':	snprintf(p, BUFSZ(p), fmt, getfval(x)); break;
1203*9a7741deSElliott Hughes 		case 'd':	snprintf(p, BUFSZ(p), fmt, (intmax_t) getfval(x)); break;
1204*9a7741deSElliott Hughes 		case 'u':	snprintf(p, BUFSZ(p), fmt, (uintmax_t) getfval(x)); break;
1205*9a7741deSElliott Hughes 
1206*9a7741deSElliott Hughes 		case 's': {
1207*9a7741deSElliott Hughes 			t = getsval(x);
1208*9a7741deSElliott Hughes 			n = strlen(t);
1209*9a7741deSElliott Hughes 			/* if simple format or no utf-8 in the string, sprintf works */
1210*9a7741deSElliott Hughes 			if (!has_utf8(t) || strcmp(fmt,"%s") == 0) {
1211*9a7741deSElliott Hughes 				if (fmtwd > n)
1212*9a7741deSElliott Hughes 					n = fmtwd;
1213*9a7741deSElliott Hughes 				if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7"))
1214*9a7741deSElliott Hughes 					FATAL("huge string/format (%d chars) in printf %.30s..." \
1215*9a7741deSElliott Hughes 						" ran format() out of memory", n, t);
1216*9a7741deSElliott Hughes 				snprintf(p, BUFSZ(p), fmt, t);
1217*9a7741deSElliott Hughes 				break;
1218*9a7741deSElliott Hughes 			}
1219*9a7741deSElliott Hughes 
1220*9a7741deSElliott Hughes 			/* get here if string has utf-8 chars and fmt is not plain %s */
1221*9a7741deSElliott Hughes 			/* "%-w.ps", where -, w and .p are all optional */
1222*9a7741deSElliott Hughes 			/* '0' before the w is a flag character */
1223*9a7741deSElliott Hughes 			/* fmt points at % */
1224*9a7741deSElliott Hughes 			int ljust = 0, wid = 0, prec = n, pad = 0;
1225*9a7741deSElliott Hughes 			char *f = fmt+1;
1226*9a7741deSElliott Hughes 			if (f[0] == '-') {
1227*9a7741deSElliott Hughes 				ljust = 1;
1228*9a7741deSElliott Hughes 				f++;
1229*9a7741deSElliott Hughes 			}
1230*9a7741deSElliott Hughes 			// flags '0' and '+' are recognized but skipped
1231*9a7741deSElliott Hughes 			if (f[0] == '0') {
1232*9a7741deSElliott Hughes 				f++;
1233*9a7741deSElliott Hughes 				if (f[0] == '+')
1234*9a7741deSElliott Hughes 					f++;
1235*9a7741deSElliott Hughes 			}
1236*9a7741deSElliott Hughes 			if (f[0] == '+') {
1237*9a7741deSElliott Hughes 				f++;
1238*9a7741deSElliott Hughes 				if (f[0] == '0')
1239*9a7741deSElliott Hughes 					f++;
1240*9a7741deSElliott Hughes 			}
1241*9a7741deSElliott Hughes 			if (isdigit(f[0])) { /* there is a wid */
1242*9a7741deSElliott Hughes 				wid = strtol(f, &f, 10);
1243*9a7741deSElliott Hughes 			}
1244*9a7741deSElliott Hughes 			if (f[0] == '.') { /* there is a .prec */
1245*9a7741deSElliott Hughes 				prec = strtol(++f, &f, 10);
1246*9a7741deSElliott Hughes 			}
1247*9a7741deSElliott Hughes 			if (prec > u8_strlen(t))
1248*9a7741deSElliott Hughes 				prec = u8_strlen(t);
1249*9a7741deSElliott Hughes 			pad = wid>prec ? wid - prec : 0;  // has to be >= 0
1250*9a7741deSElliott Hughes 			int i, k, n;
1251*9a7741deSElliott Hughes 
1252*9a7741deSElliott Hughes 			if (ljust) { // print prec chars from t, then pad blanks
1253*9a7741deSElliott Hughes 				n = u8_char2byte(t, prec);
1254*9a7741deSElliott Hughes 				for (k = 0; k < n; k++) {
1255*9a7741deSElliott Hughes 					//putchar(t[k]);
1256*9a7741deSElliott Hughes 					*p++ = t[k];
1257*9a7741deSElliott Hughes 				}
1258*9a7741deSElliott Hughes 				for (i = 0; i < pad; i++) {
1259*9a7741deSElliott Hughes 					//printf(" ");
1260*9a7741deSElliott Hughes 					*p++ = ' ';
1261*9a7741deSElliott Hughes 				}
1262*9a7741deSElliott Hughes 			} else { // print pad blanks, then prec chars from t
1263*9a7741deSElliott Hughes 				for (i = 0; i < pad; i++) {
1264*9a7741deSElliott Hughes 					//printf(" ");
1265*9a7741deSElliott Hughes 					*p++ = ' ';
1266*9a7741deSElliott Hughes 				}
1267*9a7741deSElliott Hughes 				n = u8_char2byte(t, prec);
1268*9a7741deSElliott Hughes 				for (k = 0; k < n; k++) {
1269*9a7741deSElliott Hughes 					//putchar(t[k]);
1270*9a7741deSElliott Hughes 					*p++ = t[k];
1271*9a7741deSElliott Hughes 				}
1272*9a7741deSElliott Hughes 			}
1273*9a7741deSElliott Hughes 			*p = 0;
1274*9a7741deSElliott Hughes 			break;
1275*9a7741deSElliott Hughes 		}
1276*9a7741deSElliott Hughes 
1277*9a7741deSElliott Hughes                case 'c': {
1278*9a7741deSElliott Hughes 			/*
1279*9a7741deSElliott Hughes 			 * If a numeric value is given, awk should just turn
1280*9a7741deSElliott Hughes 			 * it into a character and print it:
1281*9a7741deSElliott Hughes 			 *      BEGIN { printf("%c\n", 65) }
1282*9a7741deSElliott Hughes 			 * prints "A".
1283*9a7741deSElliott Hughes 			 *
1284*9a7741deSElliott Hughes 			 * But what if the numeric value is > 128 and
1285*9a7741deSElliott Hughes 			 * represents a valid Unicode code point?!? We do
1286*9a7741deSElliott Hughes 			 * our best to convert it back into UTF-8. If we
1287*9a7741deSElliott Hughes 			 * can't, we output the encoding of the Unicode
1288*9a7741deSElliott Hughes 			 * "invalid character", 0xFFFD.
1289*9a7741deSElliott Hughes 			 */
1290*9a7741deSElliott Hughes 			if (isnum(x)) {
1291*9a7741deSElliott Hughes 				int charval = (int) getfval(x);
1292*9a7741deSElliott Hughes 
1293*9a7741deSElliott Hughes 				if (charval != 0) {
1294*9a7741deSElliott Hughes 					if (charval < 128 || awk_mb_cur_max == 1)
1295*9a7741deSElliott Hughes 						snprintf(p, BUFSZ(p), fmt, charval);
1296*9a7741deSElliott Hughes 					else {
1297*9a7741deSElliott Hughes 						// possible unicode character
1298*9a7741deSElliott Hughes 						size_t count;
1299*9a7741deSElliott Hughes 						char *bs = wide_char_to_byte_str(charval, &count);
1300*9a7741deSElliott Hughes 
1301*9a7741deSElliott Hughes 						if (bs == NULL)	{ // invalid character
1302*9a7741deSElliott Hughes 							// use unicode invalid character, 0xFFFD
1303*9a7741deSElliott Hughes 							static char invalid_char[] = "\357\277\275";
1304*9a7741deSElliott Hughes 							bs = invalid_char;
1305*9a7741deSElliott Hughes 							count = 3;
1306*9a7741deSElliott Hughes 						}
1307*9a7741deSElliott Hughes 						t = bs;
1308*9a7741deSElliott Hughes 						n = count;
1309*9a7741deSElliott Hughes 						goto format_percent_c;
1310*9a7741deSElliott Hughes 					}
1311*9a7741deSElliott Hughes 				} else {
1312*9a7741deSElliott Hughes 					*p++ = '\0'; /* explicit null byte */
1313*9a7741deSElliott Hughes 					*p = '\0';   /* next output will start here */
1314*9a7741deSElliott Hughes 				}
1315*9a7741deSElliott Hughes 				break;
1316*9a7741deSElliott Hughes 			}
1317*9a7741deSElliott Hughes 			t = getsval(x);
1318*9a7741deSElliott Hughes 			n = u8_nextlen(t);
1319*9a7741deSElliott Hughes 		format_percent_c:
1320*9a7741deSElliott Hughes 			if (n < 2) { /* not utf8 */
1321*9a7741deSElliott Hughes 				snprintf(p, BUFSZ(p), fmt, getsval(x)[0]);
1322*9a7741deSElliott Hughes 				break;
1323*9a7741deSElliott Hughes 			}
1324*9a7741deSElliott Hughes 
1325*9a7741deSElliott Hughes 			// utf8 character, almost same song and dance as for %s
1326*9a7741deSElliott Hughes 			int ljust = 0, wid = 0, prec = n, pad = 0;
1327*9a7741deSElliott Hughes 			char *f = fmt+1;
1328*9a7741deSElliott Hughes 			if (f[0] == '-') {
1329*9a7741deSElliott Hughes 				ljust = 1;
1330*9a7741deSElliott Hughes 				f++;
1331*9a7741deSElliott Hughes 			}
1332*9a7741deSElliott Hughes 			// flags '0' and '+' are recognized but skipped
1333*9a7741deSElliott Hughes 			if (f[0] == '0') {
1334*9a7741deSElliott Hughes 				f++;
1335*9a7741deSElliott Hughes 				if (f[0] == '+')
1336*9a7741deSElliott Hughes 					f++;
1337*9a7741deSElliott Hughes 			}
1338*9a7741deSElliott Hughes 			if (f[0] == '+') {
1339*9a7741deSElliott Hughes 				f++;
1340*9a7741deSElliott Hughes 				if (f[0] == '0')
1341*9a7741deSElliott Hughes 					f++;
1342*9a7741deSElliott Hughes 			}
1343*9a7741deSElliott Hughes 			if (isdigit(f[0])) { /* there is a wid */
1344*9a7741deSElliott Hughes 				wid = strtol(f, &f, 10);
1345*9a7741deSElliott Hughes 			}
1346*9a7741deSElliott Hughes 			if (f[0] == '.') { /* there is a .prec */
1347*9a7741deSElliott Hughes 				prec = strtol(++f, &f, 10);
1348*9a7741deSElliott Hughes 			}
1349*9a7741deSElliott Hughes 			if (prec > 1)           // %c --> only one character
1350*9a7741deSElliott Hughes 				prec = 1;
1351*9a7741deSElliott Hughes 			pad = wid>prec ? wid - prec : 0;  // has to be >= 0
1352*9a7741deSElliott Hughes 			int i;
1353*9a7741deSElliott Hughes 
1354*9a7741deSElliott Hughes 			if (ljust) { // print one char from t, then pad blanks
1355*9a7741deSElliott Hughes 				for (i = 0; i < n; i++)
1356*9a7741deSElliott Hughes 					*p++ = t[i];
1357*9a7741deSElliott Hughes 				for (i = 0; i < pad; i++) {
1358*9a7741deSElliott Hughes 					//printf(" ");
1359*9a7741deSElliott Hughes 					*p++ = ' ';
1360*9a7741deSElliott Hughes 				}
1361*9a7741deSElliott Hughes 			} else { // print pad blanks, then prec chars from t
1362*9a7741deSElliott Hughes 				for (i = 0; i < pad; i++) {
1363*9a7741deSElliott Hughes 					//printf(" ");
1364*9a7741deSElliott Hughes 					*p++ = ' ';
1365*9a7741deSElliott Hughes 				}
1366*9a7741deSElliott Hughes 				for (i = 0; i < n; i++)
1367*9a7741deSElliott Hughes 					*p++ = t[i];
1368*9a7741deSElliott Hughes 			}
1369*9a7741deSElliott Hughes 			*p = 0;
1370*9a7741deSElliott Hughes 			break;
1371*9a7741deSElliott Hughes 		}
1372*9a7741deSElliott Hughes 		default:
1373*9a7741deSElliott Hughes 			FATAL("can't happen: bad conversion %c in format()", flag);
1374*9a7741deSElliott Hughes 		}
1375*9a7741deSElliott Hughes 
1376*9a7741deSElliott Hughes 		tempfree(x);
1377*9a7741deSElliott Hughes 		p += strlen(p);
1378*9a7741deSElliott Hughes 		s++;
1379*9a7741deSElliott Hughes 	}
1380*9a7741deSElliott Hughes 	*p = '\0';
1381*9a7741deSElliott Hughes 	free(fmt);
1382*9a7741deSElliott Hughes 	for ( ; a; a = a->nnext) {		/* evaluate any remaining args */
1383*9a7741deSElliott Hughes 		x = execute(a);
1384*9a7741deSElliott Hughes 		tempfree(x);
1385*9a7741deSElliott Hughes 	}
1386*9a7741deSElliott Hughes 	*pbuf = buf;
1387*9a7741deSElliott Hughes 	*pbufsize = bufsize;
1388*9a7741deSElliott Hughes 	return p - buf;
1389*9a7741deSElliott Hughes }
1390*9a7741deSElliott Hughes 
awksprintf(Node ** a,int n)1391*9a7741deSElliott Hughes Cell *awksprintf(Node **a, int n)		/* sprintf(a[0]) */
1392*9a7741deSElliott Hughes {
1393*9a7741deSElliott Hughes 	Cell *x;
1394*9a7741deSElliott Hughes 	Node *y;
1395*9a7741deSElliott Hughes 	char *buf;
1396*9a7741deSElliott Hughes 	int bufsz=3*recsize;
1397*9a7741deSElliott Hughes 
1398*9a7741deSElliott Hughes 	if ((buf = (char *) malloc(bufsz)) == NULL)
1399*9a7741deSElliott Hughes 		FATAL("out of memory in awksprintf");
1400*9a7741deSElliott Hughes 	y = a[0]->nnext;
1401*9a7741deSElliott Hughes 	x = execute(a[0]);
1402*9a7741deSElliott Hughes 	if (format(&buf, &bufsz, getsval(x), y) == -1)
1403*9a7741deSElliott Hughes 		FATAL("sprintf string %.30s... too long.  can't happen.", buf);
1404*9a7741deSElliott Hughes 	tempfree(x);
1405*9a7741deSElliott Hughes 	x = gettemp();
1406*9a7741deSElliott Hughes 	x->sval = buf;
1407*9a7741deSElliott Hughes 	x->tval = STR;
1408*9a7741deSElliott Hughes 	return(x);
1409*9a7741deSElliott Hughes }
1410*9a7741deSElliott Hughes 
awkprintf(Node ** a,int n)1411*9a7741deSElliott Hughes Cell *awkprintf(Node **a, int n)		/* printf */
1412*9a7741deSElliott Hughes {	/* a[0] is list of args, starting with format string */
1413*9a7741deSElliott Hughes 	/* a[1] is redirection operator, a[2] is redirection file */
1414*9a7741deSElliott Hughes 	FILE *fp;
1415*9a7741deSElliott Hughes 	Cell *x;
1416*9a7741deSElliott Hughes 	Node *y;
1417*9a7741deSElliott Hughes 	char *buf;
1418*9a7741deSElliott Hughes 	int len;
1419*9a7741deSElliott Hughes 	int bufsz=3*recsize;
1420*9a7741deSElliott Hughes 
1421*9a7741deSElliott Hughes 	if ((buf = (char *) malloc(bufsz)) == NULL)
1422*9a7741deSElliott Hughes 		FATAL("out of memory in awkprintf");
1423*9a7741deSElliott Hughes 	y = a[0]->nnext;
1424*9a7741deSElliott Hughes 	x = execute(a[0]);
1425*9a7741deSElliott Hughes 	if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
1426*9a7741deSElliott Hughes 		FATAL("printf string %.30s... too long.  can't happen.", buf);
1427*9a7741deSElliott Hughes 	tempfree(x);
1428*9a7741deSElliott Hughes 	if (a[1] == NULL) {
1429*9a7741deSElliott Hughes 		/* fputs(buf, stdout); */
1430*9a7741deSElliott Hughes 		fwrite(buf, len, 1, stdout);
1431*9a7741deSElliott Hughes 		if (ferror(stdout))
1432*9a7741deSElliott Hughes 			FATAL("write error on stdout");
1433*9a7741deSElliott Hughes 	} else {
1434*9a7741deSElliott Hughes 		fp = redirect(ptoi(a[1]), a[2]);
1435*9a7741deSElliott Hughes 		/* fputs(buf, fp); */
1436*9a7741deSElliott Hughes 		fwrite(buf, len, 1, fp);
1437*9a7741deSElliott Hughes 		fflush(fp);
1438*9a7741deSElliott Hughes 		if (ferror(fp))
1439*9a7741deSElliott Hughes 			FATAL("write error on %s", filename(fp));
1440*9a7741deSElliott Hughes 	}
1441*9a7741deSElliott Hughes 	free(buf);
1442*9a7741deSElliott Hughes 	return(True);
1443*9a7741deSElliott Hughes }
1444*9a7741deSElliott Hughes 
arith(Node ** a,int n)1445*9a7741deSElliott Hughes Cell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
1446*9a7741deSElliott Hughes {
1447*9a7741deSElliott Hughes 	Awkfloat i, j = 0;
1448*9a7741deSElliott Hughes 	double v;
1449*9a7741deSElliott Hughes 	Cell *x, *y, *z;
1450*9a7741deSElliott Hughes 
1451*9a7741deSElliott Hughes 	x = execute(a[0]);
1452*9a7741deSElliott Hughes 	i = getfval(x);
1453*9a7741deSElliott Hughes 	tempfree(x);
1454*9a7741deSElliott Hughes 	if (n != UMINUS && n != UPLUS) {
1455*9a7741deSElliott Hughes 		y = execute(a[1]);
1456*9a7741deSElliott Hughes 		j = getfval(y);
1457*9a7741deSElliott Hughes 		tempfree(y);
1458*9a7741deSElliott Hughes 	}
1459*9a7741deSElliott Hughes 	z = gettemp();
1460*9a7741deSElliott Hughes 	switch (n) {
1461*9a7741deSElliott Hughes 	case ADD:
1462*9a7741deSElliott Hughes 		i += j;
1463*9a7741deSElliott Hughes 		break;
1464*9a7741deSElliott Hughes 	case MINUS:
1465*9a7741deSElliott Hughes 		i -= j;
1466*9a7741deSElliott Hughes 		break;
1467*9a7741deSElliott Hughes 	case MULT:
1468*9a7741deSElliott Hughes 		i *= j;
1469*9a7741deSElliott Hughes 		break;
1470*9a7741deSElliott Hughes 	case DIVIDE:
1471*9a7741deSElliott Hughes 		if (j == 0)
1472*9a7741deSElliott Hughes 			FATAL("division by zero");
1473*9a7741deSElliott Hughes 		i /= j;
1474*9a7741deSElliott Hughes 		break;
1475*9a7741deSElliott Hughes 	case MOD:
1476*9a7741deSElliott Hughes 		if (j == 0)
1477*9a7741deSElliott Hughes 			FATAL("division by zero in mod");
1478*9a7741deSElliott Hughes 		modf(i/j, &v);
1479*9a7741deSElliott Hughes 		i = i - j * v;
1480*9a7741deSElliott Hughes 		break;
1481*9a7741deSElliott Hughes 	case UMINUS:
1482*9a7741deSElliott Hughes 		i = -i;
1483*9a7741deSElliott Hughes 		break;
1484*9a7741deSElliott Hughes 	case UPLUS: /* handled by getfval(), above */
1485*9a7741deSElliott Hughes 		break;
1486*9a7741deSElliott Hughes 	case POWER:
1487*9a7741deSElliott Hughes 		if (j >= 0 && modf(j, &v) == 0.0)	/* pos integer exponent */
1488*9a7741deSElliott Hughes 			i = ipow(i, (int) j);
1489*9a7741deSElliott Hughes                else {
1490*9a7741deSElliott Hughes 			errno = 0;
1491*9a7741deSElliott Hughes 			i = errcheck(pow(i, j), "pow");
1492*9a7741deSElliott Hughes                }
1493*9a7741deSElliott Hughes 		break;
1494*9a7741deSElliott Hughes 	default:	/* can't happen */
1495*9a7741deSElliott Hughes 		FATAL("illegal arithmetic operator %d", n);
1496*9a7741deSElliott Hughes 	}
1497*9a7741deSElliott Hughes 	setfval(z, i);
1498*9a7741deSElliott Hughes 	return(z);
1499*9a7741deSElliott Hughes }
1500*9a7741deSElliott Hughes 
ipow(double x,int n)1501*9a7741deSElliott Hughes double ipow(double x, int n)	/* x**n.  ought to be done by pow, but isn't always */
1502*9a7741deSElliott Hughes {
1503*9a7741deSElliott Hughes 	double v;
1504*9a7741deSElliott Hughes 
1505*9a7741deSElliott Hughes 	if (n <= 0)
1506*9a7741deSElliott Hughes 		return 1;
1507*9a7741deSElliott Hughes 	v = ipow(x, n/2);
1508*9a7741deSElliott Hughes 	if (n % 2 == 0)
1509*9a7741deSElliott Hughes 		return v * v;
1510*9a7741deSElliott Hughes 	else
1511*9a7741deSElliott Hughes 		return x * v * v;
1512*9a7741deSElliott Hughes }
1513*9a7741deSElliott Hughes 
incrdecr(Node ** a,int n)1514*9a7741deSElliott Hughes Cell *incrdecr(Node **a, int n)		/* a[0]++, etc. */
1515*9a7741deSElliott Hughes {
1516*9a7741deSElliott Hughes 	Cell *x, *z;
1517*9a7741deSElliott Hughes 	int k;
1518*9a7741deSElliott Hughes 	Awkfloat xf;
1519*9a7741deSElliott Hughes 
1520*9a7741deSElliott Hughes 	x = execute(a[0]);
1521*9a7741deSElliott Hughes 	xf = getfval(x);
1522*9a7741deSElliott Hughes 	k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1523*9a7741deSElliott Hughes 	if (n == PREINCR || n == PREDECR) {
1524*9a7741deSElliott Hughes 		setfval(x, xf + k);
1525*9a7741deSElliott Hughes 		return(x);
1526*9a7741deSElliott Hughes 	}
1527*9a7741deSElliott Hughes 	z = gettemp();
1528*9a7741deSElliott Hughes 	setfval(z, xf);
1529*9a7741deSElliott Hughes 	setfval(x, xf + k);
1530*9a7741deSElliott Hughes 	tempfree(x);
1531*9a7741deSElliott Hughes 	return(z);
1532*9a7741deSElliott Hughes }
1533*9a7741deSElliott Hughes 
assign(Node ** a,int n)1534*9a7741deSElliott Hughes Cell *assign(Node **a, int n)	/* a[0] = a[1], a[0] += a[1], etc. */
1535*9a7741deSElliott Hughes {		/* this is subtle; don't muck with it. */
1536*9a7741deSElliott Hughes 	Cell *x, *y;
1537*9a7741deSElliott Hughes 	Awkfloat xf, yf;
1538*9a7741deSElliott Hughes 	double v;
1539*9a7741deSElliott Hughes 
1540*9a7741deSElliott Hughes 	y = execute(a[1]);
1541*9a7741deSElliott Hughes 	x = execute(a[0]);
1542*9a7741deSElliott Hughes 	if (n == ASSIGN) {	/* ordinary assignment */
1543*9a7741deSElliott Hughes 		if (x == y && !(x->tval & (FLD|REC)) && x != nfloc)
1544*9a7741deSElliott Hughes 			;	/* self-assignment: leave alone unless it's a field or NF */
1545*9a7741deSElliott Hughes 		else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1546*9a7741deSElliott Hughes 			yf = getfval(y);
1547*9a7741deSElliott Hughes 			setsval(x, getsval(y));
1548*9a7741deSElliott Hughes 			x->fval = yf;
1549*9a7741deSElliott Hughes 			x->tval |= NUM;
1550*9a7741deSElliott Hughes 		}
1551*9a7741deSElliott Hughes 		else if (isstr(y))
1552*9a7741deSElliott Hughes 			setsval(x, getsval(y));
1553*9a7741deSElliott Hughes 		else if (isnum(y))
1554*9a7741deSElliott Hughes 			setfval(x, getfval(y));
1555*9a7741deSElliott Hughes 		else
1556*9a7741deSElliott Hughes 			funnyvar(y, "read value of");
1557*9a7741deSElliott Hughes 		tempfree(y);
1558*9a7741deSElliott Hughes 		return(x);
1559*9a7741deSElliott Hughes 	}
1560*9a7741deSElliott Hughes 	xf = getfval(x);
1561*9a7741deSElliott Hughes 	yf = getfval(y);
1562*9a7741deSElliott Hughes 	switch (n) {
1563*9a7741deSElliott Hughes 	case ADDEQ:
1564*9a7741deSElliott Hughes 		xf += yf;
1565*9a7741deSElliott Hughes 		break;
1566*9a7741deSElliott Hughes 	case SUBEQ:
1567*9a7741deSElliott Hughes 		xf -= yf;
1568*9a7741deSElliott Hughes 		break;
1569*9a7741deSElliott Hughes 	case MULTEQ:
1570*9a7741deSElliott Hughes 		xf *= yf;
1571*9a7741deSElliott Hughes 		break;
1572*9a7741deSElliott Hughes 	case DIVEQ:
1573*9a7741deSElliott Hughes 		if (yf == 0)
1574*9a7741deSElliott Hughes 			FATAL("division by zero in /=");
1575*9a7741deSElliott Hughes 		xf /= yf;
1576*9a7741deSElliott Hughes 		break;
1577*9a7741deSElliott Hughes 	case MODEQ:
1578*9a7741deSElliott Hughes 		if (yf == 0)
1579*9a7741deSElliott Hughes 			FATAL("division by zero in %%=");
1580*9a7741deSElliott Hughes 		modf(xf/yf, &v);
1581*9a7741deSElliott Hughes 		xf = xf - yf * v;
1582*9a7741deSElliott Hughes 		break;
1583*9a7741deSElliott Hughes 	case POWEQ:
1584*9a7741deSElliott Hughes 		if (yf >= 0 && modf(yf, &v) == 0.0)	/* pos integer exponent */
1585*9a7741deSElliott Hughes 			xf = ipow(xf, (int) yf);
1586*9a7741deSElliott Hughes                else {
1587*9a7741deSElliott Hughes 			errno = 0;
1588*9a7741deSElliott Hughes 			xf = errcheck(pow(xf, yf), "pow");
1589*9a7741deSElliott Hughes                }
1590*9a7741deSElliott Hughes 		break;
1591*9a7741deSElliott Hughes 	default:
1592*9a7741deSElliott Hughes 		FATAL("illegal assignment operator %d", n);
1593*9a7741deSElliott Hughes 		break;
1594*9a7741deSElliott Hughes 	}
1595*9a7741deSElliott Hughes 	tempfree(y);
1596*9a7741deSElliott Hughes 	setfval(x, xf);
1597*9a7741deSElliott Hughes 	return(x);
1598*9a7741deSElliott Hughes }
1599*9a7741deSElliott Hughes 
cat(Node ** a,int q)1600*9a7741deSElliott Hughes Cell *cat(Node **a, int q)	/* a[0] cat a[1] */
1601*9a7741deSElliott Hughes {
1602*9a7741deSElliott Hughes 	Cell *x, *y, *z;
1603*9a7741deSElliott Hughes 	int n1, n2;
1604*9a7741deSElliott Hughes 	char *s = NULL;
1605*9a7741deSElliott Hughes 	int ssz = 0;
1606*9a7741deSElliott Hughes 
1607*9a7741deSElliott Hughes 	x = execute(a[0]);
1608*9a7741deSElliott Hughes 	n1 = strlen(getsval(x));
1609*9a7741deSElliott Hughes 	adjbuf(&s, &ssz, n1 + 1, recsize, 0, "cat1");
1610*9a7741deSElliott Hughes 	memcpy(s, x->sval, n1);
1611*9a7741deSElliott Hughes 
1612*9a7741deSElliott Hughes 	tempfree(x);
1613*9a7741deSElliott Hughes 
1614*9a7741deSElliott Hughes 	y = execute(a[1]);
1615*9a7741deSElliott Hughes 	n2 = strlen(getsval(y));
1616*9a7741deSElliott Hughes 	adjbuf(&s, &ssz, n1 + n2 + 1, recsize, 0, "cat2");
1617*9a7741deSElliott Hughes 	memcpy(s + n1, y->sval, n2);
1618*9a7741deSElliott Hughes 	s[n1 + n2] = '\0';
1619*9a7741deSElliott Hughes 
1620*9a7741deSElliott Hughes 	tempfree(y);
1621*9a7741deSElliott Hughes 
1622*9a7741deSElliott Hughes 	z = gettemp();
1623*9a7741deSElliott Hughes 	z->sval = s;
1624*9a7741deSElliott Hughes 	z->tval = STR;
1625*9a7741deSElliott Hughes 
1626*9a7741deSElliott Hughes 	return(z);
1627*9a7741deSElliott Hughes }
1628*9a7741deSElliott Hughes 
pastat(Node ** a,int n)1629*9a7741deSElliott Hughes Cell *pastat(Node **a, int n)	/* a[0] { a[1] } */
1630*9a7741deSElliott Hughes {
1631*9a7741deSElliott Hughes 	Cell *x;
1632*9a7741deSElliott Hughes 
1633*9a7741deSElliott Hughes 	if (a[0] == NULL)
1634*9a7741deSElliott Hughes 		x = execute(a[1]);
1635*9a7741deSElliott Hughes 	else {
1636*9a7741deSElliott Hughes 		x = execute(a[0]);
1637*9a7741deSElliott Hughes 		if (istrue(x)) {
1638*9a7741deSElliott Hughes 			tempfree(x);
1639*9a7741deSElliott Hughes 			x = execute(a[1]);
1640*9a7741deSElliott Hughes 		}
1641*9a7741deSElliott Hughes 	}
1642*9a7741deSElliott Hughes 	return x;
1643*9a7741deSElliott Hughes }
1644*9a7741deSElliott Hughes 
dopa2(Node ** a,int n)1645*9a7741deSElliott Hughes Cell *dopa2(Node **a, int n)	/* a[0], a[1] { a[2] } */
1646*9a7741deSElliott Hughes {
1647*9a7741deSElliott Hughes 	Cell *x;
1648*9a7741deSElliott Hughes 	int pair;
1649*9a7741deSElliott Hughes 
1650*9a7741deSElliott Hughes 	pair = ptoi(a[3]);
1651*9a7741deSElliott Hughes 	if (pairstack[pair] == 0) {
1652*9a7741deSElliott Hughes 		x = execute(a[0]);
1653*9a7741deSElliott Hughes 		if (istrue(x))
1654*9a7741deSElliott Hughes 			pairstack[pair] = 1;
1655*9a7741deSElliott Hughes 		tempfree(x);
1656*9a7741deSElliott Hughes 	}
1657*9a7741deSElliott Hughes 	if (pairstack[pair] == 1) {
1658*9a7741deSElliott Hughes 		x = execute(a[1]);
1659*9a7741deSElliott Hughes 		if (istrue(x))
1660*9a7741deSElliott Hughes 			pairstack[pair] = 0;
1661*9a7741deSElliott Hughes 		tempfree(x);
1662*9a7741deSElliott Hughes 		x = execute(a[2]);
1663*9a7741deSElliott Hughes 		return(x);
1664*9a7741deSElliott Hughes 	}
1665*9a7741deSElliott Hughes 	return(False);
1666*9a7741deSElliott Hughes }
1667*9a7741deSElliott Hughes 
split(Node ** a,int nnn)1668*9a7741deSElliott Hughes Cell *split(Node **a, int nnn)	/* split(a[0], a[1], a[2]); a[3] is type */
1669*9a7741deSElliott Hughes {
1670*9a7741deSElliott Hughes 	Cell *x = NULL, *y, *ap;
1671*9a7741deSElliott Hughes 	const char *s, *origs, *t;
1672*9a7741deSElliott Hughes 	const char *fs = NULL;
1673*9a7741deSElliott Hughes 	char *origfs = NULL;
1674*9a7741deSElliott Hughes 	int sep;
1675*9a7741deSElliott Hughes 	char temp, num[50];
1676*9a7741deSElliott Hughes 	int n, tempstat, arg3type;
1677*9a7741deSElliott Hughes 	int j;
1678*9a7741deSElliott Hughes 	double result;
1679*9a7741deSElliott Hughes 
1680*9a7741deSElliott Hughes 	y = execute(a[0]);	/* source string */
1681*9a7741deSElliott Hughes 	origs = s = strdup(getsval(y));
1682*9a7741deSElliott Hughes 	tempfree(y);
1683*9a7741deSElliott Hughes 	arg3type = ptoi(a[3]);
1684*9a7741deSElliott Hughes 	if (a[2] == NULL) {		/* BUG: CSV should override implicit fs but not explicit */
1685*9a7741deSElliott Hughes 		fs = getsval(fsloc);
1686*9a7741deSElliott Hughes 	} else if (arg3type == STRING) {	/* split(str,arr,"string") */
1687*9a7741deSElliott Hughes 		x = execute(a[2]);
1688*9a7741deSElliott Hughes 		fs = origfs = strdup(getsval(x));
1689*9a7741deSElliott Hughes 		tempfree(x);
1690*9a7741deSElliott Hughes 	} else if (arg3type == REGEXPR) {
1691*9a7741deSElliott Hughes 		fs = "(regexpr)";	/* split(str,arr,/regexpr/) */
1692*9a7741deSElliott Hughes 	} else {
1693*9a7741deSElliott Hughes 		FATAL("illegal type of split");
1694*9a7741deSElliott Hughes 	}
1695*9a7741deSElliott Hughes 	sep = *fs;
1696*9a7741deSElliott Hughes 	ap = execute(a[1]);	/* array name */
1697*9a7741deSElliott Hughes /* BUG 7/26/22: this appears not to reset array: see C1/asplit */
1698*9a7741deSElliott Hughes 	freesymtab(ap);
1699*9a7741deSElliott Hughes 	DPRINTF("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs);
1700*9a7741deSElliott Hughes 	ap->tval &= ~STR;
1701*9a7741deSElliott Hughes 	ap->tval |= ARR;
1702*9a7741deSElliott Hughes 	ap->sval = (char *) makesymtab(NSYMTAB);
1703*9a7741deSElliott Hughes 
1704*9a7741deSElliott Hughes 	n = 0;
1705*9a7741deSElliott Hughes         if (arg3type == REGEXPR && strlen((char*)((fa*)a[2])->restr) == 0) {
1706*9a7741deSElliott Hughes 		/* split(s, a, //); have to arrange that it looks like empty sep */
1707*9a7741deSElliott Hughes 		arg3type = 0;
1708*9a7741deSElliott Hughes 		fs = "";
1709*9a7741deSElliott Hughes 		sep = 0;
1710*9a7741deSElliott Hughes 	}
1711*9a7741deSElliott Hughes 	if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) {	/* reg expr */
1712*9a7741deSElliott Hughes 		fa *pfa;
1713*9a7741deSElliott Hughes 		if (arg3type == REGEXPR) {	/* it's ready already */
1714*9a7741deSElliott Hughes 			pfa = (fa *) a[2];
1715*9a7741deSElliott Hughes 		} else {
1716*9a7741deSElliott Hughes 			pfa = makedfa(fs, 1);
1717*9a7741deSElliott Hughes 		}
1718*9a7741deSElliott Hughes 		if (nematch(pfa,s)) {
1719*9a7741deSElliott Hughes 			tempstat = pfa->initstat;
1720*9a7741deSElliott Hughes 			pfa->initstat = 2;
1721*9a7741deSElliott Hughes 			do {
1722*9a7741deSElliott Hughes 				n++;
1723*9a7741deSElliott Hughes 				snprintf(num, sizeof(num), "%d", n);
1724*9a7741deSElliott Hughes 				temp = *patbeg;
1725*9a7741deSElliott Hughes 				setptr(patbeg, '\0');
1726*9a7741deSElliott Hughes 				if (is_number(s, & result))
1727*9a7741deSElliott Hughes 					setsymtab(num, s, result, STR|NUM, (Array *) ap->sval);
1728*9a7741deSElliott Hughes 				else
1729*9a7741deSElliott Hughes 					setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1730*9a7741deSElliott Hughes 				setptr(patbeg, temp);
1731*9a7741deSElliott Hughes 				s = patbeg + patlen;
1732*9a7741deSElliott Hughes 				if (*(patbeg+patlen-1) == '\0' || *s == '\0') {
1733*9a7741deSElliott Hughes 					n++;
1734*9a7741deSElliott Hughes 					snprintf(num, sizeof(num), "%d", n);
1735*9a7741deSElliott Hughes 					setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1736*9a7741deSElliott Hughes 					pfa->initstat = tempstat;
1737*9a7741deSElliott Hughes 					goto spdone;
1738*9a7741deSElliott Hughes 				}
1739*9a7741deSElliott Hughes 			} while (nematch(pfa,s));
1740*9a7741deSElliott Hughes 			pfa->initstat = tempstat; 	/* bwk: has to be here to reset */
1741*9a7741deSElliott Hughes 							/* cf gsub and refldbld */
1742*9a7741deSElliott Hughes 		}
1743*9a7741deSElliott Hughes 		n++;
1744*9a7741deSElliott Hughes 		snprintf(num, sizeof(num), "%d", n);
1745*9a7741deSElliott Hughes 		if (is_number(s, & result))
1746*9a7741deSElliott Hughes 			setsymtab(num, s, result, STR|NUM, (Array *) ap->sval);
1747*9a7741deSElliott Hughes 		else
1748*9a7741deSElliott Hughes 			setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1749*9a7741deSElliott Hughes   spdone:
1750*9a7741deSElliott Hughes 		pfa = NULL;
1751*9a7741deSElliott Hughes 
1752*9a7741deSElliott Hughes 	} else if (a[2] == NULL && CSV) {	/* CSV only if no explicit separator */
1753*9a7741deSElliott Hughes 		char *newt = (char *) malloc(strlen(s)); /* for building new string; reuse for each field */
1754*9a7741deSElliott Hughes 		for (;;) {
1755*9a7741deSElliott Hughes 			char *fr = newt;
1756*9a7741deSElliott Hughes 			n++;
1757*9a7741deSElliott Hughes 			if (*s == '"' ) { /* start of "..." */
1758*9a7741deSElliott Hughes 				for (s++ ; *s != '\0'; ) {
1759*9a7741deSElliott Hughes 					if (*s == '"' && s[1] != '\0' && s[1] == '"') {
1760*9a7741deSElliott Hughes 						s += 2; /* doubled quote */
1761*9a7741deSElliott Hughes 						*fr++ = '"';
1762*9a7741deSElliott Hughes 					} else if (*s == '"' && (s[1] == '\0' || s[1] == ',')) {
1763*9a7741deSElliott Hughes 						s++; /* skip over closing quote */
1764*9a7741deSElliott Hughes 						break;
1765*9a7741deSElliott Hughes 					} else {
1766*9a7741deSElliott Hughes 						*fr++ = *s++;
1767*9a7741deSElliott Hughes 					}
1768*9a7741deSElliott Hughes 				}
1769*9a7741deSElliott Hughes 				*fr++ = 0;
1770*9a7741deSElliott Hughes 			} else {	/* unquoted field */
1771*9a7741deSElliott Hughes 				while (*s != ',' && *s != '\0')
1772*9a7741deSElliott Hughes 					*fr++ = *s++;
1773*9a7741deSElliott Hughes 				*fr++ = 0;
1774*9a7741deSElliott Hughes 			}
1775*9a7741deSElliott Hughes 			snprintf(num, sizeof(num), "%d", n);
1776*9a7741deSElliott Hughes 			if (is_number(newt, &result))
1777*9a7741deSElliott Hughes 				setsymtab(num, newt, result, STR|NUM, (Array *) ap->sval);
1778*9a7741deSElliott Hughes 			else
1779*9a7741deSElliott Hughes 				setsymtab(num, newt, 0.0, STR, (Array *) ap->sval);
1780*9a7741deSElliott Hughes 			if (*s++ == '\0')
1781*9a7741deSElliott Hughes 				break;
1782*9a7741deSElliott Hughes 		}
1783*9a7741deSElliott Hughes 		free(newt);
1784*9a7741deSElliott Hughes 
1785*9a7741deSElliott Hughes 	} else if (!CSV && sep == ' ') { /* usual case: split on white space */
1786*9a7741deSElliott Hughes 		for (n = 0; ; ) {
1787*9a7741deSElliott Hughes #define ISWS(c)	((c) == ' ' || (c) == '\t' || (c) == '\n')
1788*9a7741deSElliott Hughes 			while (ISWS(*s))
1789*9a7741deSElliott Hughes 				s++;
1790*9a7741deSElliott Hughes 			if (*s == '\0')
1791*9a7741deSElliott Hughes 				break;
1792*9a7741deSElliott Hughes 			n++;
1793*9a7741deSElliott Hughes 			t = s;
1794*9a7741deSElliott Hughes 			do
1795*9a7741deSElliott Hughes 				s++;
1796*9a7741deSElliott Hughes 			while (*s != '\0' && !ISWS(*s));
1797*9a7741deSElliott Hughes 			temp = *s;
1798*9a7741deSElliott Hughes 			setptr(s, '\0');
1799*9a7741deSElliott Hughes 			snprintf(num, sizeof(num), "%d", n);
1800*9a7741deSElliott Hughes 			if (is_number(t, & result))
1801*9a7741deSElliott Hughes 				setsymtab(num, t, result, STR|NUM, (Array *) ap->sval);
1802*9a7741deSElliott Hughes 			else
1803*9a7741deSElliott Hughes 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1804*9a7741deSElliott Hughes 			setptr(s, temp);
1805*9a7741deSElliott Hughes 			if (*s != '\0')
1806*9a7741deSElliott Hughes 				s++;
1807*9a7741deSElliott Hughes 		}
1808*9a7741deSElliott Hughes 
1809*9a7741deSElliott Hughes 	} else if (sep == 0) {	/* new: split(s, a, "") => 1 char/elem */
1810*9a7741deSElliott Hughes 		for (n = 0; *s != '\0'; s += u8_nextlen(s)) {
1811*9a7741deSElliott Hughes 			char buf[10];
1812*9a7741deSElliott Hughes 			n++;
1813*9a7741deSElliott Hughes 			snprintf(num, sizeof(num), "%d", n);
1814*9a7741deSElliott Hughes 
1815*9a7741deSElliott Hughes 			for (j = 0; j < u8_nextlen(s); j++) {
1816*9a7741deSElliott Hughes 				buf[j] = s[j];
1817*9a7741deSElliott Hughes 			}
1818*9a7741deSElliott Hughes 			buf[j] = '\0';
1819*9a7741deSElliott Hughes 
1820*9a7741deSElliott Hughes 			if (isdigit((uschar)buf[0]))
1821*9a7741deSElliott Hughes 				setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1822*9a7741deSElliott Hughes 			else
1823*9a7741deSElliott Hughes 				setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1824*9a7741deSElliott Hughes 		}
1825*9a7741deSElliott Hughes 
1826*9a7741deSElliott Hughes 	} else if (*s != '\0') {  /* some random single character */
1827*9a7741deSElliott Hughes 		for (;;) {
1828*9a7741deSElliott Hughes 			n++;
1829*9a7741deSElliott Hughes 			t = s;
1830*9a7741deSElliott Hughes 			while (*s != sep && *s != '\0')
1831*9a7741deSElliott Hughes 				s++;
1832*9a7741deSElliott Hughes 			temp = *s;
1833*9a7741deSElliott Hughes 			setptr(s, '\0');
1834*9a7741deSElliott Hughes 			snprintf(num, sizeof(num), "%d", n);
1835*9a7741deSElliott Hughes 			if (is_number(t, & result))
1836*9a7741deSElliott Hughes 				setsymtab(num, t, result, STR|NUM, (Array *) ap->sval);
1837*9a7741deSElliott Hughes 			else
1838*9a7741deSElliott Hughes 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1839*9a7741deSElliott Hughes 			setptr(s, temp);
1840*9a7741deSElliott Hughes 			if (*s++ == '\0')
1841*9a7741deSElliott Hughes 				break;
1842*9a7741deSElliott Hughes 		}
1843*9a7741deSElliott Hughes 	}
1844*9a7741deSElliott Hughes 	tempfree(ap);
1845*9a7741deSElliott Hughes 	xfree(origs);
1846*9a7741deSElliott Hughes 	xfree(origfs);
1847*9a7741deSElliott Hughes 	x = gettemp();
1848*9a7741deSElliott Hughes 	x->tval = NUM;
1849*9a7741deSElliott Hughes 	x->fval = n;
1850*9a7741deSElliott Hughes 	return(x);
1851*9a7741deSElliott Hughes }
1852*9a7741deSElliott Hughes 
condexpr(Node ** a,int n)1853*9a7741deSElliott Hughes Cell *condexpr(Node **a, int n)	/* a[0] ? a[1] : a[2] */
1854*9a7741deSElliott Hughes {
1855*9a7741deSElliott Hughes 	Cell *x;
1856*9a7741deSElliott Hughes 
1857*9a7741deSElliott Hughes 	x = execute(a[0]);
1858*9a7741deSElliott Hughes 	if (istrue(x)) {
1859*9a7741deSElliott Hughes 		tempfree(x);
1860*9a7741deSElliott Hughes 		x = execute(a[1]);
1861*9a7741deSElliott Hughes 	} else {
1862*9a7741deSElliott Hughes 		tempfree(x);
1863*9a7741deSElliott Hughes 		x = execute(a[2]);
1864*9a7741deSElliott Hughes 	}
1865*9a7741deSElliott Hughes 	return(x);
1866*9a7741deSElliott Hughes }
1867*9a7741deSElliott Hughes 
ifstat(Node ** a,int n)1868*9a7741deSElliott Hughes Cell *ifstat(Node **a, int n)	/* if (a[0]) a[1]; else a[2] */
1869*9a7741deSElliott Hughes {
1870*9a7741deSElliott Hughes 	Cell *x;
1871*9a7741deSElliott Hughes 
1872*9a7741deSElliott Hughes 	x = execute(a[0]);
1873*9a7741deSElliott Hughes 	if (istrue(x)) {
1874*9a7741deSElliott Hughes 		tempfree(x);
1875*9a7741deSElliott Hughes 		x = execute(a[1]);
1876*9a7741deSElliott Hughes 	} else if (a[2] != NULL) {
1877*9a7741deSElliott Hughes 		tempfree(x);
1878*9a7741deSElliott Hughes 		x = execute(a[2]);
1879*9a7741deSElliott Hughes 	}
1880*9a7741deSElliott Hughes 	return(x);
1881*9a7741deSElliott Hughes }
1882*9a7741deSElliott Hughes 
whilestat(Node ** a,int n)1883*9a7741deSElliott Hughes Cell *whilestat(Node **a, int n)	/* while (a[0]) a[1] */
1884*9a7741deSElliott Hughes {
1885*9a7741deSElliott Hughes 	Cell *x;
1886*9a7741deSElliott Hughes 
1887*9a7741deSElliott Hughes 	for (;;) {
1888*9a7741deSElliott Hughes 		x = execute(a[0]);
1889*9a7741deSElliott Hughes 		if (!istrue(x))
1890*9a7741deSElliott Hughes 			return(x);
1891*9a7741deSElliott Hughes 		tempfree(x);
1892*9a7741deSElliott Hughes 		x = execute(a[1]);
1893*9a7741deSElliott Hughes 		if (isbreak(x)) {
1894*9a7741deSElliott Hughes 			x = True;
1895*9a7741deSElliott Hughes 			return(x);
1896*9a7741deSElliott Hughes 		}
1897*9a7741deSElliott Hughes 		if (isnext(x) || isexit(x) || isret(x))
1898*9a7741deSElliott Hughes 			return(x);
1899*9a7741deSElliott Hughes 		tempfree(x);
1900*9a7741deSElliott Hughes 	}
1901*9a7741deSElliott Hughes }
1902*9a7741deSElliott Hughes 
dostat(Node ** a,int n)1903*9a7741deSElliott Hughes Cell *dostat(Node **a, int n)	/* do a[0]; while(a[1]) */
1904*9a7741deSElliott Hughes {
1905*9a7741deSElliott Hughes 	Cell *x;
1906*9a7741deSElliott Hughes 
1907*9a7741deSElliott Hughes 	for (;;) {
1908*9a7741deSElliott Hughes 		x = execute(a[0]);
1909*9a7741deSElliott Hughes 		if (isbreak(x))
1910*9a7741deSElliott Hughes 			return True;
1911*9a7741deSElliott Hughes 		if (isnext(x) || isexit(x) || isret(x))
1912*9a7741deSElliott Hughes 			return(x);
1913*9a7741deSElliott Hughes 		tempfree(x);
1914*9a7741deSElliott Hughes 		x = execute(a[1]);
1915*9a7741deSElliott Hughes 		if (!istrue(x))
1916*9a7741deSElliott Hughes 			return(x);
1917*9a7741deSElliott Hughes 		tempfree(x);
1918*9a7741deSElliott Hughes 	}
1919*9a7741deSElliott Hughes }
1920*9a7741deSElliott Hughes 
forstat(Node ** a,int n)1921*9a7741deSElliott Hughes Cell *forstat(Node **a, int n)	/* for (a[0]; a[1]; a[2]) a[3] */
1922*9a7741deSElliott Hughes {
1923*9a7741deSElliott Hughes 	Cell *x;
1924*9a7741deSElliott Hughes 
1925*9a7741deSElliott Hughes 	x = execute(a[0]);
1926*9a7741deSElliott Hughes 	tempfree(x);
1927*9a7741deSElliott Hughes 	for (;;) {
1928*9a7741deSElliott Hughes 		if (a[1]!=NULL) {
1929*9a7741deSElliott Hughes 			x = execute(a[1]);
1930*9a7741deSElliott Hughes 			if (!istrue(x)) return(x);
1931*9a7741deSElliott Hughes 			else tempfree(x);
1932*9a7741deSElliott Hughes 		}
1933*9a7741deSElliott Hughes 		x = execute(a[3]);
1934*9a7741deSElliott Hughes 		if (isbreak(x))		/* turn off break */
1935*9a7741deSElliott Hughes 			return True;
1936*9a7741deSElliott Hughes 		if (isnext(x) || isexit(x) || isret(x))
1937*9a7741deSElliott Hughes 			return(x);
1938*9a7741deSElliott Hughes 		tempfree(x);
1939*9a7741deSElliott Hughes 		x = execute(a[2]);
1940*9a7741deSElliott Hughes 		tempfree(x);
1941*9a7741deSElliott Hughes 	}
1942*9a7741deSElliott Hughes }
1943*9a7741deSElliott Hughes 
instat(Node ** a,int n)1944*9a7741deSElliott Hughes Cell *instat(Node **a, int n)	/* for (a[0] in a[1]) a[2] */
1945*9a7741deSElliott Hughes {
1946*9a7741deSElliott Hughes 	Cell *x, *vp, *arrayp, *cp, *ncp;
1947*9a7741deSElliott Hughes 	Array *tp;
1948*9a7741deSElliott Hughes 	int i;
1949*9a7741deSElliott Hughes 
1950*9a7741deSElliott Hughes 	vp = execute(a[0]);
1951*9a7741deSElliott Hughes 	arrayp = execute(a[1]);
1952*9a7741deSElliott Hughes 	if (!isarr(arrayp)) {
1953*9a7741deSElliott Hughes 		return True;
1954*9a7741deSElliott Hughes 	}
1955*9a7741deSElliott Hughes 	tp = (Array *) arrayp->sval;
1956*9a7741deSElliott Hughes 	tempfree(arrayp);
1957*9a7741deSElliott Hughes 	for (i = 0; i < tp->size; i++) {	/* this routine knows too much */
1958*9a7741deSElliott Hughes 		for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1959*9a7741deSElliott Hughes 			setsval(vp, cp->nval);
1960*9a7741deSElliott Hughes 			ncp = cp->cnext;
1961*9a7741deSElliott Hughes 			x = execute(a[2]);
1962*9a7741deSElliott Hughes 			if (isbreak(x)) {
1963*9a7741deSElliott Hughes 				tempfree(vp);
1964*9a7741deSElliott Hughes 				return True;
1965*9a7741deSElliott Hughes 			}
1966*9a7741deSElliott Hughes 			if (isnext(x) || isexit(x) || isret(x)) {
1967*9a7741deSElliott Hughes 				tempfree(vp);
1968*9a7741deSElliott Hughes 				return(x);
1969*9a7741deSElliott Hughes 			}
1970*9a7741deSElliott Hughes 			tempfree(x);
1971*9a7741deSElliott Hughes 		}
1972*9a7741deSElliott Hughes 	}
1973*9a7741deSElliott Hughes 	return True;
1974*9a7741deSElliott Hughes }
1975*9a7741deSElliott Hughes 
nawk_convert(const char * s,int (* fun_c)(int),wint_t (* fun_wc)(wint_t))1976*9a7741deSElliott Hughes static char *nawk_convert(const char *s, int (*fun_c)(int),
1977*9a7741deSElliott Hughes     wint_t (*fun_wc)(wint_t))
1978*9a7741deSElliott Hughes {
1979*9a7741deSElliott Hughes 	char *buf      = NULL;
1980*9a7741deSElliott Hughes 	char *pbuf     = NULL;
1981*9a7741deSElliott Hughes 	const char *ps = NULL;
1982*9a7741deSElliott Hughes 	size_t n       = 0;
1983*9a7741deSElliott Hughes 	wchar_t wc;
1984*9a7741deSElliott Hughes 	const size_t sz = awk_mb_cur_max;
1985*9a7741deSElliott Hughes 	int unused;
1986*9a7741deSElliott Hughes 
1987*9a7741deSElliott Hughes 	if (sz == 1) {
1988*9a7741deSElliott Hughes 		buf = tostring(s);
1989*9a7741deSElliott Hughes 
1990*9a7741deSElliott Hughes 		for (pbuf = buf; *pbuf; pbuf++)
1991*9a7741deSElliott Hughes 			*pbuf = fun_c((uschar)*pbuf);
1992*9a7741deSElliott Hughes 
1993*9a7741deSElliott Hughes 		return buf;
1994*9a7741deSElliott Hughes 	} else {
1995*9a7741deSElliott Hughes 		/* upper/lower character may be shorter/longer */
1996*9a7741deSElliott Hughes 		buf = tostringN(s, strlen(s) * sz + 1);
1997*9a7741deSElliott Hughes 
1998*9a7741deSElliott Hughes 		(void) mbtowc(NULL, NULL, 0);	/* reset internal state */
1999*9a7741deSElliott Hughes 		/*
2000*9a7741deSElliott Hughes 		 * Reset internal state here too.
2001*9a7741deSElliott Hughes 		 * Assign result to avoid a compiler warning. (Casting to void
2002*9a7741deSElliott Hughes 		 * doesn't work.)
2003*9a7741deSElliott Hughes 		 * Increment said variable to avoid a different warning.
2004*9a7741deSElliott Hughes 		 */
2005*9a7741deSElliott Hughes 		unused = wctomb(NULL, L'\0');
2006*9a7741deSElliott Hughes 		unused++;
2007*9a7741deSElliott Hughes 
2008*9a7741deSElliott Hughes 		ps   = s;
2009*9a7741deSElliott Hughes 		pbuf = buf;
2010*9a7741deSElliott Hughes 		while (n = mbtowc(&wc, ps, sz),
2011*9a7741deSElliott Hughes 		       n > 0 && n != (size_t)-1 && n != (size_t)-2)
2012*9a7741deSElliott Hughes 		{
2013*9a7741deSElliott Hughes 			ps += n;
2014*9a7741deSElliott Hughes 
2015*9a7741deSElliott Hughes 			n = wctomb(pbuf, fun_wc(wc));
2016*9a7741deSElliott Hughes 			if (n == (size_t)-1)
2017*9a7741deSElliott Hughes 				FATAL("illegal wide character %s", s);
2018*9a7741deSElliott Hughes 
2019*9a7741deSElliott Hughes 			pbuf += n;
2020*9a7741deSElliott Hughes 		}
2021*9a7741deSElliott Hughes 
2022*9a7741deSElliott Hughes 		*pbuf = '\0';
2023*9a7741deSElliott Hughes 
2024*9a7741deSElliott Hughes 		if (n)
2025*9a7741deSElliott Hughes 			FATAL("illegal byte sequence %s", s);
2026*9a7741deSElliott Hughes 
2027*9a7741deSElliott Hughes 		return buf;
2028*9a7741deSElliott Hughes 	}
2029*9a7741deSElliott Hughes }
2030*9a7741deSElliott Hughes 
2031*9a7741deSElliott Hughes #ifdef __DJGPP__
towupper(wint_t wc)2032*9a7741deSElliott Hughes static wint_t towupper(wint_t wc)
2033*9a7741deSElliott Hughes {
2034*9a7741deSElliott Hughes 	if (wc >= 0 && wc < 256)
2035*9a7741deSElliott Hughes 		return toupper(wc & 0xFF);
2036*9a7741deSElliott Hughes 
2037*9a7741deSElliott Hughes 	return wc;
2038*9a7741deSElliott Hughes }
2039*9a7741deSElliott Hughes 
towlower(wint_t wc)2040*9a7741deSElliott Hughes static wint_t towlower(wint_t wc)
2041*9a7741deSElliott Hughes {
2042*9a7741deSElliott Hughes 	if (wc >= 0 && wc < 256)
2043*9a7741deSElliott Hughes 		return tolower(wc & 0xFF);
2044*9a7741deSElliott Hughes 
2045*9a7741deSElliott Hughes 	return wc;
2046*9a7741deSElliott Hughes }
2047*9a7741deSElliott Hughes #endif
2048*9a7741deSElliott Hughes 
nawk_toupper(const char * s)2049*9a7741deSElliott Hughes static char *nawk_toupper(const char *s)
2050*9a7741deSElliott Hughes {
2051*9a7741deSElliott Hughes 	return nawk_convert(s, toupper, towupper);
2052*9a7741deSElliott Hughes }
2053*9a7741deSElliott Hughes 
nawk_tolower(const char * s)2054*9a7741deSElliott Hughes static char *nawk_tolower(const char *s)
2055*9a7741deSElliott Hughes {
2056*9a7741deSElliott Hughes 	return nawk_convert(s, tolower, towlower);
2057*9a7741deSElliott Hughes }
2058*9a7741deSElliott Hughes 
2059*9a7741deSElliott Hughes 
2060*9a7741deSElliott Hughes 
bltin(Node ** a,int n)2061*9a7741deSElliott Hughes Cell *bltin(Node **a, int n)	/* builtin functions. a[0] is type, a[1] is arg list */
2062*9a7741deSElliott Hughes {
2063*9a7741deSElliott Hughes 	Cell *x, *y;
2064*9a7741deSElliott Hughes 	Awkfloat u = 0;
2065*9a7741deSElliott Hughes 	int t;
2066*9a7741deSElliott Hughes 	Awkfloat tmp;
2067*9a7741deSElliott Hughes 	char *buf;
2068*9a7741deSElliott Hughes 	Node *nextarg;
2069*9a7741deSElliott Hughes 	FILE *fp;
2070*9a7741deSElliott Hughes 	int status = 0;
2071*9a7741deSElliott Hughes 	int estatus = 0;
2072*9a7741deSElliott Hughes 
2073*9a7741deSElliott Hughes 	t = ptoi(a[0]);
2074*9a7741deSElliott Hughes 	x = execute(a[1]);
2075*9a7741deSElliott Hughes 	nextarg = a[1]->nnext;
2076*9a7741deSElliott Hughes 	switch (t) {
2077*9a7741deSElliott Hughes 	case FLENGTH:
2078*9a7741deSElliott Hughes 		if (isarr(x))
2079*9a7741deSElliott Hughes 			u = ((Array *) x->sval)->nelem;	/* GROT.  should be function*/
2080*9a7741deSElliott Hughes 		else
2081*9a7741deSElliott Hughes 			u = u8_strlen(getsval(x));
2082*9a7741deSElliott Hughes 		break;
2083*9a7741deSElliott Hughes 	case FLOG:
2084*9a7741deSElliott Hughes 		errno = 0;
2085*9a7741deSElliott Hughes 		u = errcheck(log(getfval(x)), "log");
2086*9a7741deSElliott Hughes 		break;
2087*9a7741deSElliott Hughes 	case FINT:
2088*9a7741deSElliott Hughes 		modf(getfval(x), &u); break;
2089*9a7741deSElliott Hughes 	case FEXP:
2090*9a7741deSElliott Hughes 		errno = 0;
2091*9a7741deSElliott Hughes 		u = errcheck(exp(getfval(x)), "exp");
2092*9a7741deSElliott Hughes 		break;
2093*9a7741deSElliott Hughes 	case FSQRT:
2094*9a7741deSElliott Hughes 		errno = 0;
2095*9a7741deSElliott Hughes 		u = errcheck(sqrt(getfval(x)), "sqrt");
2096*9a7741deSElliott Hughes 		break;
2097*9a7741deSElliott Hughes 	case FSIN:
2098*9a7741deSElliott Hughes 		u = sin(getfval(x)); break;
2099*9a7741deSElliott Hughes 	case FCOS:
2100*9a7741deSElliott Hughes 		u = cos(getfval(x)); break;
2101*9a7741deSElliott Hughes 	case FATAN:
2102*9a7741deSElliott Hughes 		if (nextarg == NULL) {
2103*9a7741deSElliott Hughes 			WARNING("atan2 requires two arguments; returning 1.0");
2104*9a7741deSElliott Hughes 			u = 1.0;
2105*9a7741deSElliott Hughes 		} else {
2106*9a7741deSElliott Hughes 			y = execute(a[1]->nnext);
2107*9a7741deSElliott Hughes 			u = atan2(getfval(x), getfval(y));
2108*9a7741deSElliott Hughes 			tempfree(y);
2109*9a7741deSElliott Hughes 			nextarg = nextarg->nnext;
2110*9a7741deSElliott Hughes 		}
2111*9a7741deSElliott Hughes 		break;
2112*9a7741deSElliott Hughes 	case FSYSTEM:
2113*9a7741deSElliott Hughes 		fflush(stdout);		/* in case something is buffered already */
2114*9a7741deSElliott Hughes 		estatus = status = system(getsval(x));
2115*9a7741deSElliott Hughes 		if (status != -1) {
2116*9a7741deSElliott Hughes 			if (WIFEXITED(status)) {
2117*9a7741deSElliott Hughes 				estatus = WEXITSTATUS(status);
2118*9a7741deSElliott Hughes 			} else if (WIFSIGNALED(status)) {
2119*9a7741deSElliott Hughes 				estatus = WTERMSIG(status) + 256;
2120*9a7741deSElliott Hughes #ifdef WCOREDUMP
2121*9a7741deSElliott Hughes 				if (WCOREDUMP(status))
2122*9a7741deSElliott Hughes 					estatus += 256;
2123*9a7741deSElliott Hughes #endif
2124*9a7741deSElliott Hughes 			} else	/* something else?!? */
2125*9a7741deSElliott Hughes 				estatus = 0;
2126*9a7741deSElliott Hughes 		}
2127*9a7741deSElliott Hughes 		/* else estatus was set to -1 */
2128*9a7741deSElliott Hughes 		u = estatus;
2129*9a7741deSElliott Hughes 		break;
2130*9a7741deSElliott Hughes 	case FRAND:
2131*9a7741deSElliott Hughes 		/* random() returns numbers in [0..2^31-1]
2132*9a7741deSElliott Hughes 		 * in order to get a number in [0, 1), divide it by 2^31
2133*9a7741deSElliott Hughes 		 */
2134*9a7741deSElliott Hughes 		u = (Awkfloat) random() / (0x7fffffffL + 0x1UL);
2135*9a7741deSElliott Hughes 		break;
2136*9a7741deSElliott Hughes 	case FSRAND:
2137*9a7741deSElliott Hughes 		if (isrec(x))	/* no argument provided */
2138*9a7741deSElliott Hughes 			u = time((time_t *)0);
2139*9a7741deSElliott Hughes 		else
2140*9a7741deSElliott Hughes 			u = getfval(x);
2141*9a7741deSElliott Hughes 		tmp = u;
2142*9a7741deSElliott Hughes 		srandom((unsigned long) u);
2143*9a7741deSElliott Hughes 		u = srand_seed;
2144*9a7741deSElliott Hughes 		srand_seed = tmp;
2145*9a7741deSElliott Hughes 		break;
2146*9a7741deSElliott Hughes 	case FTOUPPER:
2147*9a7741deSElliott Hughes 	case FTOLOWER:
2148*9a7741deSElliott Hughes 		if (t == FTOUPPER)
2149*9a7741deSElliott Hughes 			buf = nawk_toupper(getsval(x));
2150*9a7741deSElliott Hughes 		else
2151*9a7741deSElliott Hughes 			buf = nawk_tolower(getsval(x));
2152*9a7741deSElliott Hughes 		tempfree(x);
2153*9a7741deSElliott Hughes 		x = gettemp();
2154*9a7741deSElliott Hughes 		setsval(x, buf);
2155*9a7741deSElliott Hughes 		free(buf);
2156*9a7741deSElliott Hughes 		return x;
2157*9a7741deSElliott Hughes 	case FFLUSH:
2158*9a7741deSElliott Hughes 		if (isrec(x) || strlen(getsval(x)) == 0) {
2159*9a7741deSElliott Hughes 			flush_all();	/* fflush() or fflush("") -> all */
2160*9a7741deSElliott Hughes 			u = 0;
2161*9a7741deSElliott Hughes 		} else if ((fp = openfile(FFLUSH, getsval(x), NULL)) == NULL)
2162*9a7741deSElliott Hughes 			u = EOF;
2163*9a7741deSElliott Hughes 		else
2164*9a7741deSElliott Hughes 			u = fflush(fp);
2165*9a7741deSElliott Hughes 		break;
2166*9a7741deSElliott Hughes 	default:	/* can't happen */
2167*9a7741deSElliott Hughes 		FATAL("illegal function type %d", t);
2168*9a7741deSElliott Hughes 		break;
2169*9a7741deSElliott Hughes 	}
2170*9a7741deSElliott Hughes 	tempfree(x);
2171*9a7741deSElliott Hughes 	x = gettemp();
2172*9a7741deSElliott Hughes 	setfval(x, u);
2173*9a7741deSElliott Hughes 	if (nextarg != NULL) {
2174*9a7741deSElliott Hughes 		WARNING("warning: function has too many arguments");
2175*9a7741deSElliott Hughes 		for ( ; nextarg; nextarg = nextarg->nnext) {
2176*9a7741deSElliott Hughes 			y = execute(nextarg);
2177*9a7741deSElliott Hughes 			tempfree(y);
2178*9a7741deSElliott Hughes 		}
2179*9a7741deSElliott Hughes 	}
2180*9a7741deSElliott Hughes 	return(x);
2181*9a7741deSElliott Hughes }
2182*9a7741deSElliott Hughes 
printstat(Node ** a,int n)2183*9a7741deSElliott Hughes Cell *printstat(Node **a, int n)	/* print a[0] */
2184*9a7741deSElliott Hughes {
2185*9a7741deSElliott Hughes 	Node *x;
2186*9a7741deSElliott Hughes 	Cell *y;
2187*9a7741deSElliott Hughes 	FILE *fp;
2188*9a7741deSElliott Hughes 
2189*9a7741deSElliott Hughes 	if (a[1] == NULL)	/* a[1] is redirection operator, a[2] is file */
2190*9a7741deSElliott Hughes 		fp = stdout;
2191*9a7741deSElliott Hughes 	else
2192*9a7741deSElliott Hughes 		fp = redirect(ptoi(a[1]), a[2]);
2193*9a7741deSElliott Hughes 	for (x = a[0]; x != NULL; x = x->nnext) {
2194*9a7741deSElliott Hughes 		y = execute(x);
2195*9a7741deSElliott Hughes 		fputs(getpssval(y), fp);
2196*9a7741deSElliott Hughes 		tempfree(y);
2197*9a7741deSElliott Hughes 		if (x->nnext == NULL)
2198*9a7741deSElliott Hughes 			fputs(getsval(orsloc), fp);
2199*9a7741deSElliott Hughes 		else
2200*9a7741deSElliott Hughes 			fputs(getsval(ofsloc), fp);
2201*9a7741deSElliott Hughes 	}
2202*9a7741deSElliott Hughes 	if (a[1] != NULL)
2203*9a7741deSElliott Hughes 		fflush(fp);
2204*9a7741deSElliott Hughes 	if (ferror(fp))
2205*9a7741deSElliott Hughes 		FATAL("write error on %s", filename(fp));
2206*9a7741deSElliott Hughes 	return(True);
2207*9a7741deSElliott Hughes }
2208*9a7741deSElliott Hughes 
nullproc(Node ** a,int n)2209*9a7741deSElliott Hughes Cell *nullproc(Node **a, int n)
2210*9a7741deSElliott Hughes {
2211*9a7741deSElliott Hughes 	return 0;
2212*9a7741deSElliott Hughes }
2213*9a7741deSElliott Hughes 
2214*9a7741deSElliott Hughes 
redirect(int a,Node * b)2215*9a7741deSElliott Hughes FILE *redirect(int a, Node *b)	/* set up all i/o redirections */
2216*9a7741deSElliott Hughes {
2217*9a7741deSElliott Hughes 	FILE *fp;
2218*9a7741deSElliott Hughes 	Cell *x;
2219*9a7741deSElliott Hughes 	char *fname;
2220*9a7741deSElliott Hughes 
2221*9a7741deSElliott Hughes 	x = execute(b);
2222*9a7741deSElliott Hughes 	fname = getsval(x);
2223*9a7741deSElliott Hughes 	fp = openfile(a, fname, NULL);
2224*9a7741deSElliott Hughes 	if (fp == NULL)
2225*9a7741deSElliott Hughes 		FATAL("can't open file %s", fname);
2226*9a7741deSElliott Hughes 	tempfree(x);
2227*9a7741deSElliott Hughes 	return fp;
2228*9a7741deSElliott Hughes }
2229*9a7741deSElliott Hughes 
2230*9a7741deSElliott Hughes struct files {
2231*9a7741deSElliott Hughes 	FILE	*fp;
2232*9a7741deSElliott Hughes 	const char	*fname;
2233*9a7741deSElliott Hughes 	int	mode;	/* '|', 'a', 'w' => LE/LT, GT */
2234*9a7741deSElliott Hughes } *files;
2235*9a7741deSElliott Hughes 
2236*9a7741deSElliott Hughes size_t nfiles;
2237*9a7741deSElliott Hughes 
stdinit(void)2238*9a7741deSElliott Hughes static void stdinit(void)	/* in case stdin, etc., are not constants */
2239*9a7741deSElliott Hughes {
2240*9a7741deSElliott Hughes 	nfiles = FOPEN_MAX;
2241*9a7741deSElliott Hughes 	files = (struct files *) calloc(nfiles, sizeof(*files));
2242*9a7741deSElliott Hughes 	if (files == NULL)
2243*9a7741deSElliott Hughes 		FATAL("can't allocate file memory for %zu files", nfiles);
2244*9a7741deSElliott Hughes         files[0].fp = stdin;
2245*9a7741deSElliott Hughes 	files[0].fname = tostring("/dev/stdin");
2246*9a7741deSElliott Hughes 	files[0].mode = LT;
2247*9a7741deSElliott Hughes         files[1].fp = stdout;
2248*9a7741deSElliott Hughes 	files[1].fname = tostring("/dev/stdout");
2249*9a7741deSElliott Hughes 	files[1].mode = GT;
2250*9a7741deSElliott Hughes         files[2].fp = stderr;
2251*9a7741deSElliott Hughes 	files[2].fname = tostring("/dev/stderr");
2252*9a7741deSElliott Hughes 	files[2].mode = GT;
2253*9a7741deSElliott Hughes }
2254*9a7741deSElliott Hughes 
openfile(int a,const char * us,bool * pnewflag)2255*9a7741deSElliott Hughes FILE *openfile(int a, const char *us, bool *pnewflag)
2256*9a7741deSElliott Hughes {
2257*9a7741deSElliott Hughes 	const char *s = us;
2258*9a7741deSElliott Hughes 	size_t i;
2259*9a7741deSElliott Hughes 	int m;
2260*9a7741deSElliott Hughes 	FILE *fp = NULL;
2261*9a7741deSElliott Hughes 
2262*9a7741deSElliott Hughes 	if (*s == '\0')
2263*9a7741deSElliott Hughes 		FATAL("null file name in print or getline");
2264*9a7741deSElliott Hughes 	for (i = 0; i < nfiles; i++)
2265*9a7741deSElliott Hughes 		if (files[i].fname && strcmp(s, files[i].fname) == 0 &&
2266*9a7741deSElliott Hughes 		    (a == files[i].mode || (a==APPEND && files[i].mode==GT) ||
2267*9a7741deSElliott Hughes 		     a == FFLUSH)) {
2268*9a7741deSElliott Hughes 			if (pnewflag)
2269*9a7741deSElliott Hughes 				*pnewflag = false;
2270*9a7741deSElliott Hughes 			return files[i].fp;
2271*9a7741deSElliott Hughes 		}
2272*9a7741deSElliott Hughes 	if (a == FFLUSH)	/* didn't find it, so don't create it! */
2273*9a7741deSElliott Hughes 		return NULL;
2274*9a7741deSElliott Hughes 
2275*9a7741deSElliott Hughes 	for (i = 0; i < nfiles; i++)
2276*9a7741deSElliott Hughes 		if (files[i].fp == NULL)
2277*9a7741deSElliott Hughes 			break;
2278*9a7741deSElliott Hughes 	if (i >= nfiles) {
2279*9a7741deSElliott Hughes 		struct files *nf;
2280*9a7741deSElliott Hughes 		size_t nnf = nfiles + FOPEN_MAX;
2281*9a7741deSElliott Hughes 		nf = (struct files *) realloc(files, nnf * sizeof(*nf));
2282*9a7741deSElliott Hughes 		if (nf == NULL)
2283*9a7741deSElliott Hughes 			FATAL("cannot grow files for %s and %zu files", s, nnf);
2284*9a7741deSElliott Hughes 		memset(&nf[nfiles], 0, FOPEN_MAX * sizeof(*nf));
2285*9a7741deSElliott Hughes 		nfiles = nnf;
2286*9a7741deSElliott Hughes 		files = nf;
2287*9a7741deSElliott Hughes 	}
2288*9a7741deSElliott Hughes 	fflush(stdout);	/* force a semblance of order */
2289*9a7741deSElliott Hughes 	m = a;
2290*9a7741deSElliott Hughes 	if (a == GT) {
2291*9a7741deSElliott Hughes 		fp = fopen(s, "w");
2292*9a7741deSElliott Hughes 	} else if (a == APPEND) {
2293*9a7741deSElliott Hughes 		fp = fopen(s, "a");
2294*9a7741deSElliott Hughes 		m = GT;	/* so can mix > and >> */
2295*9a7741deSElliott Hughes 	} else if (a == '|') {	/* output pipe */
2296*9a7741deSElliott Hughes 		fp = popen(s, "w");
2297*9a7741deSElliott Hughes 	} else if (a == LE) {	/* input pipe */
2298*9a7741deSElliott Hughes 		fp = popen(s, "r");
2299*9a7741deSElliott Hughes 	} else if (a == LT) {	/* getline <file */
2300*9a7741deSElliott Hughes 		fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r");	/* "-" is stdin */
2301*9a7741deSElliott Hughes 	} else	/* can't happen */
2302*9a7741deSElliott Hughes 		FATAL("illegal redirection %d", a);
2303*9a7741deSElliott Hughes 	if (fp != NULL) {
2304*9a7741deSElliott Hughes 		files[i].fname = tostring(s);
2305*9a7741deSElliott Hughes 		files[i].fp = fp;
2306*9a7741deSElliott Hughes 		files[i].mode = m;
2307*9a7741deSElliott Hughes 		if (pnewflag)
2308*9a7741deSElliott Hughes 			*pnewflag = true;
2309*9a7741deSElliott Hughes 		if (fp != stdin && fp != stdout && fp != stderr)
2310*9a7741deSElliott Hughes 			(void) fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
2311*9a7741deSElliott Hughes 	}
2312*9a7741deSElliott Hughes 	return fp;
2313*9a7741deSElliott Hughes }
2314*9a7741deSElliott Hughes 
filename(FILE * fp)2315*9a7741deSElliott Hughes const char *filename(FILE *fp)
2316*9a7741deSElliott Hughes {
2317*9a7741deSElliott Hughes 	size_t i;
2318*9a7741deSElliott Hughes 
2319*9a7741deSElliott Hughes 	for (i = 0; i < nfiles; i++)
2320*9a7741deSElliott Hughes 		if (fp == files[i].fp)
2321*9a7741deSElliott Hughes 			return files[i].fname;
2322*9a7741deSElliott Hughes 	return "???";
2323*9a7741deSElliott Hughes }
2324*9a7741deSElliott Hughes 
closefile(Node ** a,int n)2325*9a7741deSElliott Hughes Cell *closefile(Node **a, int n)
2326*9a7741deSElliott Hughes {
2327*9a7741deSElliott Hughes  	Cell *x;
2328*9a7741deSElliott Hughes 	size_t i;
2329*9a7741deSElliott Hughes 	bool stat;
2330*9a7741deSElliott Hughes 
2331*9a7741deSElliott Hughes  	x = execute(a[0]);
2332*9a7741deSElliott Hughes  	getsval(x);
2333*9a7741deSElliott Hughes 	stat = true;
2334*9a7741deSElliott Hughes  	for (i = 0; i < nfiles; i++) {
2335*9a7741deSElliott Hughes 		if (!files[i].fname || strcmp(x->sval, files[i].fname) != 0)
2336*9a7741deSElliott Hughes 			continue;
2337*9a7741deSElliott Hughes 		if (files[i].mode == GT || files[i].mode == '|')
2338*9a7741deSElliott Hughes 			fflush(files[i].fp);
2339*9a7741deSElliott Hughes 		if (ferror(files[i].fp)) {
2340*9a7741deSElliott Hughes 			if ((files[i].mode == GT && files[i].fp != stderr)
2341*9a7741deSElliott Hughes 			  || files[i].mode == '|')
2342*9a7741deSElliott Hughes 				FATAL("write error on %s", files[i].fname);
2343*9a7741deSElliott Hughes 			else
2344*9a7741deSElliott Hughes 				WARNING("i/o error occurred on %s", files[i].fname);
2345*9a7741deSElliott Hughes 		}
2346*9a7741deSElliott Hughes 		if (files[i].fp == stdin || files[i].fp == stdout ||
2347*9a7741deSElliott Hughes 		    files[i].fp == stderr)
2348*9a7741deSElliott Hughes 			stat = freopen("/dev/null", "r+", files[i].fp) == NULL;
2349*9a7741deSElliott Hughes 		else if (files[i].mode == '|' || files[i].mode == LE)
2350*9a7741deSElliott Hughes 			stat = pclose(files[i].fp) == -1;
2351*9a7741deSElliott Hughes 		else
2352*9a7741deSElliott Hughes 			stat = fclose(files[i].fp) == EOF;
2353*9a7741deSElliott Hughes 		if (stat)
2354*9a7741deSElliott Hughes 			WARNING("i/o error occurred closing %s", files[i].fname);
2355*9a7741deSElliott Hughes 		xfree(files[i].fname);
2356*9a7741deSElliott Hughes 		files[i].fname = NULL;	/* watch out for ref thru this */
2357*9a7741deSElliott Hughes 		files[i].fp = NULL;
2358*9a7741deSElliott Hughes 		break;
2359*9a7741deSElliott Hughes  	}
2360*9a7741deSElliott Hughes  	tempfree(x);
2361*9a7741deSElliott Hughes  	x = gettemp();
2362*9a7741deSElliott Hughes 	setfval(x, (Awkfloat) (stat ? -1 : 0));
2363*9a7741deSElliott Hughes  	return(x);
2364*9a7741deSElliott Hughes }
2365*9a7741deSElliott Hughes 
closeall(void)2366*9a7741deSElliott Hughes void closeall(void)
2367*9a7741deSElliott Hughes {
2368*9a7741deSElliott Hughes 	size_t i;
2369*9a7741deSElliott Hughes 	bool stat = false;
2370*9a7741deSElliott Hughes 
2371*9a7741deSElliott Hughes 	for (i = 0; i < nfiles; i++) {
2372*9a7741deSElliott Hughes 		if (! files[i].fp)
2373*9a7741deSElliott Hughes 			continue;
2374*9a7741deSElliott Hughes 		if (files[i].mode == GT || files[i].mode == '|')
2375*9a7741deSElliott Hughes 			fflush(files[i].fp);
2376*9a7741deSElliott Hughes 		if (ferror(files[i].fp)) {
2377*9a7741deSElliott Hughes 			if ((files[i].mode == GT && files[i].fp != stderr)
2378*9a7741deSElliott Hughes 			  || files[i].mode == '|')
2379*9a7741deSElliott Hughes 				FATAL("write error on %s", files[i].fname);
2380*9a7741deSElliott Hughes 			else
2381*9a7741deSElliott Hughes 				WARNING("i/o error occurred on %s", files[i].fname);
2382*9a7741deSElliott Hughes 		}
2383*9a7741deSElliott Hughes 		if (files[i].fp == stdin || files[i].fp == stdout ||
2384*9a7741deSElliott Hughes 		    files[i].fp == stderr)
2385*9a7741deSElliott Hughes 			continue;
2386*9a7741deSElliott Hughes 		if (files[i].mode == '|' || files[i].mode == LE)
2387*9a7741deSElliott Hughes 			stat = pclose(files[i].fp) == -1;
2388*9a7741deSElliott Hughes 		else
2389*9a7741deSElliott Hughes 			stat = fclose(files[i].fp) == EOF;
2390*9a7741deSElliott Hughes 		if (stat)
2391*9a7741deSElliott Hughes 			WARNING("i/o error occurred while closing %s", files[i].fname);
2392*9a7741deSElliott Hughes 	}
2393*9a7741deSElliott Hughes }
2394*9a7741deSElliott Hughes 
flush_all(void)2395*9a7741deSElliott Hughes static void flush_all(void)
2396*9a7741deSElliott Hughes {
2397*9a7741deSElliott Hughes 	size_t i;
2398*9a7741deSElliott Hughes 
2399*9a7741deSElliott Hughes 	for (i = 0; i < nfiles; i++)
2400*9a7741deSElliott Hughes 		if (files[i].fp)
2401*9a7741deSElliott Hughes 			fflush(files[i].fp);
2402*9a7741deSElliott Hughes }
2403*9a7741deSElliott Hughes 
2404*9a7741deSElliott Hughes void backsub(char **pb_ptr, const char **sptr_ptr);
2405*9a7741deSElliott Hughes 
dosub(Node ** a,int subop)2406*9a7741deSElliott Hughes Cell *dosub(Node **a, int subop)        /* sub and gsub */
2407*9a7741deSElliott Hughes {
2408*9a7741deSElliott Hughes 	fa *pfa;
2409*9a7741deSElliott Hughes 	int tempstat = 0;
2410*9a7741deSElliott Hughes 	char *repl;
2411*9a7741deSElliott Hughes 	Cell *x;
2412*9a7741deSElliott Hughes 
2413*9a7741deSElliott Hughes 	char *buf = NULL;
2414*9a7741deSElliott Hughes 	char *pb = NULL;
2415*9a7741deSElliott Hughes 	int bufsz = recsize;
2416*9a7741deSElliott Hughes 
2417*9a7741deSElliott Hughes 	const char *r, *s;
2418*9a7741deSElliott Hughes 	const char *start;
2419*9a7741deSElliott Hughes 	const char *noempty = NULL;      /* empty match disallowed here */
2420*9a7741deSElliott Hughes 	size_t m = 0;                    /* match count */
2421*9a7741deSElliott Hughes 	size_t whichm = 0;               /* which match to select, 0 = global */
2422*9a7741deSElliott Hughes 	int mtype;                       /* match type */
2423*9a7741deSElliott Hughes 
2424*9a7741deSElliott Hughes 	if (a[0] == NULL) {	/* 0 => a[1] is already-compiled regexpr */
2425*9a7741deSElliott Hughes 		pfa = (fa *) a[1];
2426*9a7741deSElliott Hughes 	} else {
2427*9a7741deSElliott Hughes 		x = execute(a[1]);
2428*9a7741deSElliott Hughes 		pfa = makedfa(getsval(x), 1);
2429*9a7741deSElliott Hughes 		tempfree(x);
2430*9a7741deSElliott Hughes 	}
2431*9a7741deSElliott Hughes 
2432*9a7741deSElliott Hughes 	x = execute(a[2]);	/* replacement string */
2433*9a7741deSElliott Hughes 	repl = tostring(getsval(x));
2434*9a7741deSElliott Hughes 	tempfree(x);
2435*9a7741deSElliott Hughes 
2436*9a7741deSElliott Hughes 	switch (subop) {
2437*9a7741deSElliott Hughes 	case SUB:
2438*9a7741deSElliott Hughes 		whichm = 1;
2439*9a7741deSElliott Hughes 		x = execute(a[3]);    /* source string */
2440*9a7741deSElliott Hughes 		break;
2441*9a7741deSElliott Hughes 	case GSUB:
2442*9a7741deSElliott Hughes 		whichm = 0;
2443*9a7741deSElliott Hughes 		x = execute(a[3]);    /* source string */
2444*9a7741deSElliott Hughes 		break;
2445*9a7741deSElliott Hughes 	default:
2446*9a7741deSElliott Hughes 		FATAL("dosub: unrecognized subop: %d", subop);
2447*9a7741deSElliott Hughes 	}
2448*9a7741deSElliott Hughes 
2449*9a7741deSElliott Hughes 	start = getsval(x);
2450*9a7741deSElliott Hughes 	while (pmatch(pfa, start)) {
2451*9a7741deSElliott Hughes 		if (buf == NULL) {
2452*9a7741deSElliott Hughes 			if ((pb = buf = (char *) malloc(bufsz)) == NULL)
2453*9a7741deSElliott Hughes 				FATAL("out of memory in dosub");
2454*9a7741deSElliott Hughes 			tempstat = pfa->initstat;
2455*9a7741deSElliott Hughes 			pfa->initstat = 2;
2456*9a7741deSElliott Hughes 		}
2457*9a7741deSElliott Hughes 
2458*9a7741deSElliott Hughes 		/* match types */
2459*9a7741deSElliott Hughes 		#define	MT_IGNORE  0  /* unselected or invalid */
2460*9a7741deSElliott Hughes 		#define MT_INSERT  1  /* selected, empty */
2461*9a7741deSElliott Hughes 		#define MT_REPLACE 2  /* selected, not empty */
2462*9a7741deSElliott Hughes 
2463*9a7741deSElliott Hughes 		/* an empty match just after replacement is invalid */
2464*9a7741deSElliott Hughes 
2465*9a7741deSElliott Hughes 		if (patbeg == noempty && patlen == 0) {
2466*9a7741deSElliott Hughes 			mtype = MT_IGNORE;    /* invalid, not counted */
2467*9a7741deSElliott Hughes 		} else if (whichm == ++m || whichm == 0) {
2468*9a7741deSElliott Hughes 			mtype = patlen ? MT_REPLACE : MT_INSERT;
2469*9a7741deSElliott Hughes 		} else {
2470*9a7741deSElliott Hughes 			mtype = MT_IGNORE;    /* unselected, but counted */
2471*9a7741deSElliott Hughes 		}
2472*9a7741deSElliott Hughes 
2473*9a7741deSElliott Hughes 		/* leading text: */
2474*9a7741deSElliott Hughes 		if (patbeg > start) {
2475*9a7741deSElliott Hughes 			adjbuf(&buf, &bufsz, (pb - buf) + (patbeg - start),
2476*9a7741deSElliott Hughes 				recsize, &pb, "dosub");
2477*9a7741deSElliott Hughes 			s = start;
2478*9a7741deSElliott Hughes 			while (s < patbeg)
2479*9a7741deSElliott Hughes 				*pb++ = *s++;
2480*9a7741deSElliott Hughes 		}
2481*9a7741deSElliott Hughes 
2482*9a7741deSElliott Hughes 		if (mtype == MT_IGNORE)
2483*9a7741deSElliott Hughes 			goto matching_text;  /* skip replacement text */
2484*9a7741deSElliott Hughes 
2485*9a7741deSElliott Hughes 		r = repl;
2486*9a7741deSElliott Hughes 		while (*r != 0) {
2487*9a7741deSElliott Hughes 			adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "dosub");
2488*9a7741deSElliott Hughes 			if (*r == '\\') {
2489*9a7741deSElliott Hughes 				backsub(&pb, &r);
2490*9a7741deSElliott Hughes 			} else if (*r == '&') {
2491*9a7741deSElliott Hughes 				r++;
2492*9a7741deSElliott Hughes 				adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize,
2493*9a7741deSElliott Hughes 					&pb, "dosub");
2494*9a7741deSElliott Hughes 				for (s = patbeg; s < patbeg+patlen; )
2495*9a7741deSElliott Hughes 					*pb++ = *s++;
2496*9a7741deSElliott Hughes 			} else {
2497*9a7741deSElliott Hughes 				*pb++ = *r++;
2498*9a7741deSElliott Hughes 			}
2499*9a7741deSElliott Hughes 		}
2500*9a7741deSElliott Hughes 
2501*9a7741deSElliott Hughes matching_text:
2502*9a7741deSElliott Hughes 		if (mtype == MT_REPLACE || *patbeg == '\0')
2503*9a7741deSElliott Hughes 			goto next_search;  /* skip matching text */
2504*9a7741deSElliott Hughes 
2505*9a7741deSElliott Hughes 		if (patlen == 0)
2506*9a7741deSElliott Hughes 			patlen = u8_nextlen(patbeg);
2507*9a7741deSElliott Hughes 		adjbuf(&buf, &bufsz, (pb-buf) + patlen, recsize, &pb, "dosub");
2508*9a7741deSElliott Hughes 		s = patbeg;
2509*9a7741deSElliott Hughes 		while (s < patbeg + patlen)
2510*9a7741deSElliott Hughes 			*pb++ = *s++;
2511*9a7741deSElliott Hughes 
2512*9a7741deSElliott Hughes next_search:
2513*9a7741deSElliott Hughes 		start = patbeg + patlen;
2514*9a7741deSElliott Hughes 		if (m == whichm || *patbeg == '\0')
2515*9a7741deSElliott Hughes 			break;
2516*9a7741deSElliott Hughes 		if (mtype == MT_REPLACE)
2517*9a7741deSElliott Hughes 			noempty = start;
2518*9a7741deSElliott Hughes 
2519*9a7741deSElliott Hughes 		#undef MT_IGNORE
2520*9a7741deSElliott Hughes 		#undef MT_INSERT
2521*9a7741deSElliott Hughes 		#undef MT_REPLACE
2522*9a7741deSElliott Hughes 	}
2523*9a7741deSElliott Hughes 
2524*9a7741deSElliott Hughes 	xfree(repl);
2525*9a7741deSElliott Hughes 
2526*9a7741deSElliott Hughes 	if (buf != NULL) {
2527*9a7741deSElliott Hughes 		pfa->initstat = tempstat;
2528*9a7741deSElliott Hughes 
2529*9a7741deSElliott Hughes 		/* trailing text */
2530*9a7741deSElliott Hughes 		adjbuf(&buf, &bufsz, 1+strlen(start)+pb-buf, 0, &pb, "dosub");
2531*9a7741deSElliott Hughes 		while ((*pb++ = *start++) != '\0')
2532*9a7741deSElliott Hughes 			;
2533*9a7741deSElliott Hughes 
2534*9a7741deSElliott Hughes 		setsval(x, buf);
2535*9a7741deSElliott Hughes 		free(buf);
2536*9a7741deSElliott Hughes 	}
2537*9a7741deSElliott Hughes 
2538*9a7741deSElliott Hughes 	tempfree(x);
2539*9a7741deSElliott Hughes 	x = gettemp();
2540*9a7741deSElliott Hughes 	x->tval = NUM;
2541*9a7741deSElliott Hughes 	x->fval = m;
2542*9a7741deSElliott Hughes 	return x;
2543*9a7741deSElliott Hughes }
2544*9a7741deSElliott Hughes 
backsub(char ** pb_ptr,const char ** sptr_ptr)2545*9a7741deSElliott Hughes void backsub(char **pb_ptr, const char **sptr_ptr)	/* handle \\& variations */
2546*9a7741deSElliott Hughes {						/* sptr[0] == '\\' */
2547*9a7741deSElliott Hughes 	char *pb = *pb_ptr;
2548*9a7741deSElliott Hughes 	const char *sptr = *sptr_ptr;
2549*9a7741deSElliott Hughes 	static bool first = true;
2550*9a7741deSElliott Hughes 	static bool do_posix = false;
2551*9a7741deSElliott Hughes 
2552*9a7741deSElliott Hughes 	if (first) {
2553*9a7741deSElliott Hughes 		first = false;
2554*9a7741deSElliott Hughes 		do_posix = (getenv("POSIXLY_CORRECT") != NULL);
2555*9a7741deSElliott Hughes 	}
2556*9a7741deSElliott Hughes 
2557*9a7741deSElliott Hughes 	if (sptr[1] == '\\') {
2558*9a7741deSElliott Hughes 		if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
2559*9a7741deSElliott Hughes 			*pb++ = '\\';
2560*9a7741deSElliott Hughes 			*pb++ = '&';
2561*9a7741deSElliott Hughes 			sptr += 4;
2562*9a7741deSElliott Hughes 		} else if (sptr[2] == '&') {	/* \\& -> \ + matched */
2563*9a7741deSElliott Hughes 			*pb++ = '\\';
2564*9a7741deSElliott Hughes 			sptr += 2;
2565*9a7741deSElliott Hughes 		} else if (do_posix) {		/* \\x -> \x */
2566*9a7741deSElliott Hughes 			sptr++;
2567*9a7741deSElliott Hughes 			*pb++ = *sptr++;
2568*9a7741deSElliott Hughes 		} else {			/* \\x -> \\x */
2569*9a7741deSElliott Hughes 			*pb++ = *sptr++;
2570*9a7741deSElliott Hughes 			*pb++ = *sptr++;
2571*9a7741deSElliott Hughes 		}
2572*9a7741deSElliott Hughes 	} else if (sptr[1] == '&') {	/* literal & */
2573*9a7741deSElliott Hughes 		sptr++;
2574*9a7741deSElliott Hughes 		*pb++ = *sptr++;
2575*9a7741deSElliott Hughes 	} else				/* literal \ */
2576*9a7741deSElliott Hughes 		*pb++ = *sptr++;
2577*9a7741deSElliott Hughes 
2578*9a7741deSElliott Hughes 	*pb_ptr = pb;
2579*9a7741deSElliott Hughes 	*sptr_ptr = sptr;
2580*9a7741deSElliott Hughes }
2581*9a7741deSElliott Hughes 
wide_char_to_byte_str(int rune,size_t * outlen)2582*9a7741deSElliott Hughes static char *wide_char_to_byte_str(int rune, size_t *outlen)
2583*9a7741deSElliott Hughes {
2584*9a7741deSElliott Hughes 	static char buf[5];
2585*9a7741deSElliott Hughes 	int len;
2586*9a7741deSElliott Hughes 
2587*9a7741deSElliott Hughes 	if (rune < 0 || rune > 0x10FFFF)
2588*9a7741deSElliott Hughes 		return NULL;
2589*9a7741deSElliott Hughes 
2590*9a7741deSElliott Hughes 	memset(buf, 0, sizeof(buf));
2591*9a7741deSElliott Hughes 
2592*9a7741deSElliott Hughes 	len = 0;
2593*9a7741deSElliott Hughes 	if (rune <= 0x0000007F) {
2594*9a7741deSElliott Hughes 		buf[len++] = rune;
2595*9a7741deSElliott Hughes 	} else if (rune <= 0x000007FF) {
2596*9a7741deSElliott Hughes 		// 110xxxxx 10xxxxxx
2597*9a7741deSElliott Hughes 		buf[len++] = 0xC0 | (rune >> 6);
2598*9a7741deSElliott Hughes 		buf[len++] = 0x80 | (rune & 0x3F);
2599*9a7741deSElliott Hughes 	} else if (rune <= 0x0000FFFF) {
2600*9a7741deSElliott Hughes 		// 1110xxxx 10xxxxxx 10xxxxxx
2601*9a7741deSElliott Hughes 		buf[len++] = 0xE0 | (rune >> 12);
2602*9a7741deSElliott Hughes 		buf[len++] = 0x80 | ((rune >> 6) & 0x3F);
2603*9a7741deSElliott Hughes 		buf[len++] = 0x80 | (rune & 0x3F);
2604*9a7741deSElliott Hughes 
2605*9a7741deSElliott Hughes 	} else {
2606*9a7741deSElliott Hughes 		// 0x00010000 - 0x10FFFF
2607*9a7741deSElliott Hughes 		// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
2608*9a7741deSElliott Hughes 		buf[len++] = 0xF0 | (rune >> 18);
2609*9a7741deSElliott Hughes 		buf[len++] = 0x80 | ((rune >> 12) & 0x3F);
2610*9a7741deSElliott Hughes 		buf[len++] = 0x80 | ((rune >> 6) & 0x3F);
2611*9a7741deSElliott Hughes 		buf[len++] = 0x80 | (rune & 0x3F);
2612*9a7741deSElliott Hughes 	}
2613*9a7741deSElliott Hughes 
2614*9a7741deSElliott Hughes 	*outlen = len;
2615*9a7741deSElliott Hughes 	buf[len++] = '\0';
2616*9a7741deSElliott Hughes 
2617*9a7741deSElliott Hughes 	return buf;
2618*9a7741deSElliott Hughes }
2619