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