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