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