1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
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++;
1435 t = s;
1436 do
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 }