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