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