1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
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
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
23 ****************************************************************/
36 #define tempfree(x) if (istemp(x)) tfree(x); else
41 void tempfree(Cell *p) {
42 if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
43 WARNING("bad csub %d in Cell %d %s",
44 p->csub, p->ctype, p->sval);
53 #define FOPEN_MAX _NFILE
58 #define FOPEN_MAX 40 /* max number of open files */
62 #define RAND_MAX 32767 /* all that ansi guarantees */
66 extern int pairstack[];
68 Node *winner = NULL; /* root of parse tree */
69 Cell *tmps; /* free temporary cells for execution */
71 static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
72 Cell *True = &truecell;
73 static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
74 Cell *False = &falsecell;
75 static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
76 Cell *jbreak = &breakcell;
77 static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM };
78 Cell *jcont = &contcell;
79 static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
80 Cell *jnext = &nextcell;
81 static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
82 Cell *jnextfile = &nextfilecell;
83 static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
84 Cell *jexit = &exitcell;
85 static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM };
86 Cell *jret = &retcell;
87 static Cell tempcell ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
89 Node *curnode = NULL; /* the node being executed, for debugging */
91 /* buffer memory management */
92 int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
94 /* pbuf: address of pointer to buffer being managed
95 * psiz: address of buffer size variable
96 * minlen: minimum length of buffer needed
97 * quantum: buffer size quantum
98 * pbptr: address of movable pointer into buffer, or 0 if none
99 * whatrtn: name of the calling routine if failure should cause fatal error
101 * return 0 for realloc failure, !=0 for success
104 if (minlen > *psiz) {
106 int rminlen = quantum ? minlen % quantum : 0;
107 int boff = pbptr ? *pbptr - *pbuf : 0;
108 /* round up to next multiple of quantum */
110 minlen += quantum - rminlen;
111 tbuf = (char *) realloc(*pbuf, minlen);
114 FATAL("out of memory in %s", whatrtn);
120 *pbptr = tbuf + boff;
125 void run(Node *a) /* execution of parse tree starts here */
127 extern void stdinit(void);
134 Cell *execute(Node *u) /* execute a node of the parse tree */
136 Cell *(*proc)(Node **, int);
142 for (a = u; ; a = a->nnext) {
145 x = (Cell *) (a->narg[0]);
146 if (isfld(x) && !donefld)
148 else if (isrec(x) && !donerec)
152 if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */
153 FATAL("illegal statement");
154 proc = proctab[a->nobj-FIRSTTOKEN];
155 x = (*proc)(a->narg, a->nobj);
156 if (isfld(x) && !donefld)
158 else if (isrec(x) && !donerec)
164 if (a->nnext == NULL)
171 Cell *program(Node **a, int n) /* execute an awk program */
172 { /* a[0] = BEGIN, a[1] = body, a[2] = END */
175 if (setjmp(env) != 0)
177 if (a[0]) { /* BEGIN */
182 FATAL("illegal break, continue, next or nextfile from BEGIN");
186 while (getrec(&record, &recsize, 1) > 0) {
193 if (setjmp(env) != 0) /* handles exit within END */
195 if (a[2]) { /* END */
197 if (isbreak(x) || isnext(x) || iscont(x))
198 FATAL("illegal break, continue, next or nextfile from END");
205 struct Frame { /* stack frame for awk function calls */
206 int nargs; /* number of arguments in this call */
207 Cell *fcncell; /* pointer to Cell for function */
208 Cell **args; /* pointer to array of arguments after execute */
209 Cell *retval; /* return value */
212 #define NARGS 50 /* max args in a call */
214 struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
215 int nframe = 0; /* number of frames allocated */
216 struct Frame *fp = NULL; /* frame pointer. bottom level unused */
218 Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
220 static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
222 int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */
224 Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */
228 fcn = execute(a[0]); /* the function itself */
231 FATAL("calling undefined function %s", s);
233 fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
235 FATAL("out of space for stack frames calling %s", s);
237 for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
239 ndef = (int) fcn->fval; /* args in defn */
240 dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
242 WARNING("function %s called with %d args, uses only %d",
244 if (ncall + ndef > NARGS)
245 FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
246 for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */
247 dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
250 dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
251 i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval) );
253 FATAL("can't use function %s as argument in %s", y->nval, s);
255 args[i] = y; /* arrays by ref */
257 args[i] = copycell(y);
260 for ( ; i < ndef; i++) { /* add null args for ones not provided */
262 *args[i] = newcopycell;
264 fp++; /* now ok to up frame */
265 if (fp >= frame + nframe) {
266 int dfp = fp - frame; /* old index */
267 frame = (struct Frame *)
268 realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
270 FATAL("out of space for stack frames in %s", s);
275 fp->nargs = ndef; /* number defined with (excess are locals) */
276 fp->retval = gettemp();
278 dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
279 y = execute((Node *)(fcn->sval)); /* execute body */
280 dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
282 for (i = 0; i < ndef; i++) {
283 Cell *t = fp->args[i];
285 if (t->csub == CCOPY) {
291 oargs[i]->tval = t->tval;
292 oargs[i]->tval &= ~(STR|NUM|DONTFREE);
293 oargs[i]->sval = t->sval;
297 } else if (t != y) { /* kludge to prevent freeing twice */
300 } else if (t == y && t->csub == CCOPY) {
307 if (isexit(y) || isnext(y))
310 tempfree(y); /* don't free twice! */
312 z = fp->retval; /* return value */
313 dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
318 Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
323 y->csub = CCOPY; /* prevents freeing until call is over */
324 y->nval = x->nval; /* BUG? */
326 y->sval = tostring(x->sval);
328 y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */
329 /* is DONTFREE right? */
333 Cell *arg(Node **a, int n) /* nth argument of a function */
336 n = ptoi(a[0]); /* argument number, counting from 0 */
337 dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
339 FATAL("argument #%d of function %s was not supplied",
340 n+1, fp->fcncell->nval);
344 Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */
352 errorflag = (int) getfval(y);
359 if ((y->tval & (STR|NUM)) == (STR|NUM)) {
360 setsval(fp->retval, getsval(y));
361 fp->retval->fval = getfval(y);
362 fp->retval->tval |= NUM;
364 else if (y->tval & STR)
365 setsval(fp->retval, getsval(y));
366 else if (y->tval & NUM)
367 setfval(fp->retval, getfval(y));
368 else /* can't happen */
369 FATAL("bad type variable %d", y->tval);
382 default: /* can't happen */
383 FATAL("illegal jump type %d", n);
385 return 0; /* not reached */
388 Cell *getline(Node **a, int n) /* get next line from specific input */
389 { /* a[0] is variable, a[1] is operator, a[2] is filename */
391 extern Cell **fldtab;
394 int bufsize = recsize;
397 if ((buf = (char *) malloc(bufsize)) == NULL)
398 FATAL("out of memory in getline");
400 fflush(stdout); /* in case someone is waiting for a prompt */
402 if (a[1] != NULL) { /* getline < file */
403 x = execute(a[2]); /* filename */
405 if (mode == '|') /* input pipe */
406 mode = LE; /* arbitrary flag */
407 fp = openfile(mode, getsval(x));
412 n = readrec(&buf, &bufsize, fp);
415 } else if (a[0] != NULL) { /* getline var <file */
419 } else { /* getline <file */
420 setsval(fldtab[0], buf);
421 if (is_number(fldtab[0]->sval)) {
422 fldtab[0]->fval = atof(fldtab[0]->sval);
423 fldtab[0]->tval |= NUM;
426 } else { /* bare getline; use current input */
427 if (a[0] == NULL) /* getline */
428 n = getrec(&record, &recsize, 1);
429 else { /* getline var */
430 n = getrec(&buf, &bufsize, 0);
436 setfval(r, (Awkfloat) n);
441 Cell *getnf(Node **a, int n) /* get NF */
445 return (Cell *) a[0];
448 Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
455 int nsub = strlen(*SUBSEP);
457 if ((buf = (char *) malloc(bufsz)) == NULL)
458 FATAL("out of memory in array");
460 x = execute(a[0]); /* Cell* for symbol table */
462 for (np = a[1]; np; np = np->nnext) {
463 y = execute(np); /* subscript */
465 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
466 FATAL("out of memory for %s[%s...]", x->nval, buf);
469 strcat(buf, *SUBSEP);
473 dprintf( ("making %s into an array\n", NN(x->nval)) );
476 x->tval &= ~(STR|NUM|DONTFREE);
478 x->sval = (char *) makesymtab(NSYMTAB);
480 z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
488 Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
493 int nsub = strlen(*SUBSEP);
495 x = execute(a[0]); /* Cell* for symbol table */
498 if (a[1] == 0) { /* delete the elements, not the table */
502 x->sval = (char *) makesymtab(NSYMTAB);
506 if ((buf = (char *) malloc(bufsz)) == NULL)
507 FATAL("out of memory in adelete");
509 for (np = a[1]; np; np = np->nnext) {
510 y = execute(np); /* subscript */
512 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
513 FATAL("out of memory deleting %s[%s...]", x->nval, buf);
516 strcat(buf, *SUBSEP);
526 Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
533 int nsub = strlen(*SUBSEP);
535 ap = execute(a[1]); /* array name */
537 dprintf( ("making %s into an array\n", ap->nval) );
540 ap->tval &= ~(STR|NUM|DONTFREE);
542 ap->sval = (char *) makesymtab(NSYMTAB);
544 if ((buf = (char *) malloc(bufsz)) == NULL) {
545 FATAL("out of memory in intest");
548 for (p = a[0]; p; p = p->nnext) {
549 x = execute(p); /* expr */
551 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
552 FATAL("out of memory deleting %s[%s...]", x->nval, buf);
556 strcat(buf, *SUBSEP);
558 k = lookup(buf, (Array *) ap->sval);
568 Cell *matchop(Node **a, int n) /* ~ and match() */
574 int (*mf)(fa *, const char *) = match, mode = 0;
580 x = execute(a[1]); /* a[1] = target text */
582 if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */
583 i = (*mf)((fa *) a[2], s);
585 y = execute(a[2]); /* a[2] = regular expr */
587 pfa = makedfa(t, mode);
593 int start = patbeg - s + 1;
596 setfval(rstartloc, (Awkfloat) start);
597 setfval(rlengthloc, (Awkfloat) patlen);
602 } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
609 Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
626 if ( !i ) return(False);
633 if (i) return(False);
635 default: /* can't happen */
636 FATAL("unknown boolean operator %d", n);
638 return 0; /*NOTREACHED*/
641 Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
649 if (x->tval&NUM && y->tval&NUM) {
650 j = x->fval - y->fval;
651 i = j<0? -1: (j>0? 1: 0);
653 i = strcmp(getsval(x), getsval(y));
658 case LT: if (i<0) return(True);
660 case LE: if (i<=0) return(True);
662 case NE: if (i!=0) return(True);
664 case EQ: if (i == 0) return(True);
666 case GE: if (i>=0) return(True);
668 case GT: if (i>0) return(True);
670 default: /* can't happen */
671 FATAL("unknown relational operator %d", n);
673 return 0; /*NOTREACHED*/
676 void tfree(Cell *a) /* free a tempcell */
679 dprintf( ("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval) );
683 FATAL("tempcell list is curdled");
688 Cell *gettemp(void) /* get a tempcell */
693 tmps = (Cell *) calloc(100, sizeof(Cell));
695 FATAL("out of space for temporaries");
696 for(i = 1; i < 100; i++)
697 tmps[i-1].cnext = &tmps[i];
706 Cell *indirect(Node **a, int n) /* $( a[0] ) */
713 m = (int) getfval(x);
714 if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */
715 FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
716 /* BUG: can x->nval ever be null??? */
719 x->ctype = OCELL; /* BUG? why are these needed? */
724 Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
747 m = (int) getfval(y);
754 n = (int) getfval(z);
762 dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
764 temp = s[n+m-1]; /* with thanks to John Linderman */
766 setsval(y, s + m - 1);
772 Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
775 char *s1, *s2, *p1, *p2, *q;
784 for (p1 = s1; *p1 != '\0'; p1++) {
785 for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
788 v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */
798 #define MAXNUMSIZE 50
800 int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like conversions */
807 int fmtwd; /* format width */
810 int bufsize = *pbufsize;
814 if ((fmt = (char *) malloc(fmtsz)) == NULL)
815 FATAL("out of memory in format()");
817 adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format");
827 /* have to be real careful in case this is a huge number, eg, %100000d */
831 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
832 for (t = fmt; (*t++ = *s) != '\0'; s++) {
833 if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0))
834 FATAL("format item %.30s... ran format() out of memory", os);
835 if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L')
836 break; /* the ansi panoply */
840 sprintf(t-1, "%d", fmtwd=(int) getfval(x));
843 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
844 t = fmt + strlen(fmt);
851 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
854 case 'f': case 'e': case 'g': case 'E': case 'G':
859 if(*(s-1) == 'l') break;
864 case 'o': case 'x': case 'X': case 'u':
865 flag = *(s-1) == 'l' ? 'd' : 'u';
874 WARNING("weird printf conversion %s", fmt);
879 FATAL("not enough args in printf(%s)", os);
885 adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
887 case '?': sprintf(p, "%s", fmt); /* unknown, so dump it too */
892 adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
896 case 'f': sprintf(p, fmt, getfval(x)); break;
897 case 'd': sprintf(p, fmt, (long) getfval(x)); break;
898 case 'u': sprintf(p, fmt, (int) getfval(x)); break;
904 if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
905 FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
911 sprintf(p, fmt, (int) getfval(x));
913 *p++ = '\0'; /* explicit null byte */
914 *p = '\0'; /* next output will start here */
917 sprintf(p, fmt, getsval(x)[0]);
920 FATAL("can't happen: bad conversion %c in format()", flag);
928 for ( ; a; a = a->nnext) /* evaluate any remaining args */
935 Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
942 if ((buf = (char *) malloc(bufsz)) == NULL)
943 FATAL("out of memory in awksprintf");
946 if (format(&buf, &bufsz, getsval(x), y) == -1)
947 FATAL("sprintf string %.30s... too long. can't happen.", buf);
955 Cell *awkprintf(Node **a, int n) /* printf */
956 { /* a[0] is list of args, starting with format string */
957 /* a[1] is redirection operator, a[2] is redirection file */
965 if ((buf = (char *) malloc(bufsz)) == NULL)
966 FATAL("out of memory in awkprintf");
969 if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
970 FATAL("printf string %.30s... too long. can't happen.", buf);
973 /* fputs(buf, stdout); */
974 fwrite(buf, len, 1, stdout);
976 FATAL("write error on stdout");
978 fp = redirect(ptoi(a[1]), a[2]);
979 /* fputs(buf, fp); */
980 fwrite(buf, len, 1, fp);
983 FATAL("write error on %s", filename(fp));
989 Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
1016 FATAL("division by zero");
1021 FATAL("division by zero in mod");
1029 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1030 i = ipow(i, (int) j);
1032 i = errcheck(pow(i, j), "pow");
1034 default: /* can't happen */
1035 FATAL("illegal arithmetic operator %d", n);
1041 double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
1054 Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
1062 k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1063 if (n == PREINCR || n == PREDECR) {
1074 Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
1075 { /* this is subtle; don't muck with it. */
1082 if (n == ASSIGN) { /* ordinary assignment */
1083 if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
1084 ; /* leave alone unless it's a field */
1085 else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1086 setsval(x, getsval(y));
1087 x->fval = getfval(y);
1091 setsval(x, getsval(y));
1093 setfval(x, getfval(y));
1095 funnyvar(y, "read value of");
1113 FATAL("division by zero in /=");
1118 FATAL("division by zero in %%=");
1123 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1124 xf = ipow(xf, (int) yf);
1126 xf = errcheck(pow(xf, yf), "pow");
1129 FATAL("illegal assignment operator %d", n);
1137 Cell *cat(Node **a, int q) /* a[0] cat a[1] */
1147 n1 = strlen(x->sval);
1148 n2 = strlen(y->sval);
1149 s = (char *) malloc(n1 + n2 + 1);
1151 FATAL("out of space concatenating %.15s... and %.15s...",
1154 strcpy(s+n1, y->sval);
1163 Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
1179 Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
1185 if (pairstack[pair] == 0) {
1188 pairstack[pair] = 1;
1191 if (pairstack[pair] == 1) {
1194 pairstack[pair] = 0;
1202 Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
1204 Cell *x = 0, *y, *ap;
1207 char *t, temp, num[50], *fs = 0;
1208 int n, tempstat, arg3type;
1210 y = execute(a[0]); /* source string */
1212 arg3type = ptoi(a[3]);
1213 if (a[2] == 0) /* fs string */
1215 else if (arg3type == STRING) { /* split(str,arr,"string") */
1218 } else if (arg3type == REGEXPR)
1219 fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
1221 FATAL("illegal type of split");
1223 ap = execute(a[1]); /* array name */
1225 dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs) );
1228 ap->sval = (char *) makesymtab(NSYMTAB);
1231 if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) { /* reg expr */
1233 if (arg3type == REGEXPR) { /* it's ready already */
1236 pfa = makedfa(fs, 1);
1238 if (nematch(pfa,s)) {
1239 tempstat = pfa->initstat;
1243 sprintf(num, "%d", n);
1247 setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1249 setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1251 s = patbeg + patlen;
1252 if (*(patbeg+patlen-1) == 0 || *s == 0) {
1254 sprintf(num, "%d", n);
1255 setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1256 pfa->initstat = tempstat;
1259 } while (nematch(pfa,s));
1262 sprintf(num, "%d", n);
1264 setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1266 setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1269 } else if (sep == ' ') {
1271 while (*s == ' ' || *s == '\t' || *s == '\n')
1279 while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1282 sprintf(num, "%d", n);
1284 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1286 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1291 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
1292 for (n = 0; *s != 0; s++) {
1295 sprintf(num, "%d", n);
1298 if (isdigit((uschar)buf[0]))
1299 setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1301 setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1303 } else if (*s != 0) {
1307 while (*s != sep && *s != '\n' && *s != '\0')
1311 sprintf(num, "%d", n);
1313 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1315 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1323 if (a[2] != 0 && arg3type == STRING) {
1332 Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
1347 Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
1355 } else if (a[2] != 0) {
1362 Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
1376 if (isnext(x) || isexit(x) || isret(x))
1382 Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
1390 if (isnext(x) || isexit(x) || isret(x))
1400 Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
1409 if (!istrue(x)) return(x);
1413 if (isbreak(x)) /* turn off break */
1415 if (isnext(x) || isexit(x) || isret(x))
1423 Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1425 Cell *x, *vp, *arrayp, *cp, *ncp;
1430 arrayp = execute(a[1]);
1431 if (!isarr(arrayp)) {
1434 tp = (Array *) arrayp->sval;
1436 for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1437 for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1438 setsval(vp, cp->nval);
1445 if (isnext(x) || isexit(x) || isret(x)) {
1455 Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
1463 void flush_all(void);
1467 nextarg = a[1]->nnext;
1471 u = ((Array *) x->sval)->nelem; /* GROT. should be function*/
1473 u = strlen(getsval(x));
1476 u = errcheck(log(getfval(x)), "log"); break;
1478 modf(getfval(x), &u); break;
1480 u = errcheck(exp(getfval(x)), "exp"); break;
1482 u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1484 u = sin(getfval(x)); break;
1486 u = cos(getfval(x)); break;
1489 WARNING("atan2 requires two arguments; returning 1.0");
1492 y = execute(a[1]->nnext);
1493 u = atan2(getfval(x), getfval(y));
1495 nextarg = nextarg->nnext;
1499 fflush(stdout); /* in case something is buffered already */
1500 u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */
1503 /* in principle, rand() returns something in 0..RAND_MAX */
1504 u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1507 if (isrec(x)) /* no argument provided */
1508 u = time((time_t *)0);
1511 srand((unsigned int) u);
1515 buf = tostring(getsval(x));
1516 if (t == FTOUPPER) {
1517 for (p = buf; *p; p++)
1518 if (islower((uschar) *p))
1519 *p = toupper((uschar)*p);
1521 for (p = buf; *p; p++)
1522 if (isupper((uschar) *p))
1523 *p = tolower((uschar)*p);
1531 if (isrec(x) || strlen(getsval(x)) == 0) {
1532 flush_all(); /* fflush() or fflush("") -> all */
1534 } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
1539 default: /* can't happen */
1540 FATAL("illegal function type %d", t);
1547 WARNING("warning: function has too many arguments");
1548 for ( ; nextarg; nextarg = nextarg->nnext)
1554 Cell *printstat(Node **a, int n) /* print a[0] */
1560 if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
1563 fp = redirect(ptoi(a[1]), a[2]);
1564 for (x = a[0]; x != NULL; x = x->nnext) {
1566 fputs(getpssval(y), fp);
1568 if (x->nnext == NULL)
1576 FATAL("write error on %s", filename(fp));
1580 Cell *nullproc(Node **a, int n)
1588 FILE *redirect(int a, Node *b) /* set up all i/o redirections */
1596 fp = openfile(a, fname);
1598 FATAL("can't open file %s", fname);
1606 int mode; /* '|', 'a', 'w' => LE/LT, GT */
1607 } files[FOPEN_MAX] ={
1608 { NULL, "/dev/stdin", LT }, /* watch out: don't free this! */
1609 { NULL, "/dev/stdout", GT },
1610 { NULL, "/dev/stderr", GT }
1613 void stdinit(void) /* in case stdin, etc., are not constants */
1615 files[0].fp = stdin;
1616 files[1].fp = stdout;
1617 files[2].fp = stderr;
1620 FILE *openfile(int a, const char *us)
1627 FATAL("null file name in print or getline");
1628 for (i=0; i < FOPEN_MAX; i++)
1629 if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1630 if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1635 if (a == FFLUSH) /* didn't find it, so don't create it! */
1638 for (i=0; i < FOPEN_MAX; i++)
1639 if (files[i].fp == 0)
1642 FATAL("%s makes too many open files", s);
1643 fflush(stdout); /* force a semblance of order */
1647 } else if (a == APPEND) {
1649 m = GT; /* so can mix > and >> */
1650 } else if (a == '|') { /* output pipe */
1652 } else if (a == LE) { /* input pipe */
1654 } else if (a == LT) { /* getline <file */
1655 fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
1656 } else /* can't happen */
1657 FATAL("illegal redirection %d", a);
1659 files[i].fname = tostring(s);
1666 const char *filename(FILE *fp)
1670 for (i = 0; i < FOPEN_MAX; i++)
1671 if (fp == files[i].fp)
1672 return files[i].fname;
1676 Cell *closefile(Node **a, int n)
1685 for (i = 0; i < FOPEN_MAX; i++) {
1686 if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1687 if (ferror(files[i].fp))
1688 WARNING( "i/o error occurred on %s", files[i].fname );
1689 if (files[i].mode == '|' || files[i].mode == LE)
1690 stat = pclose(files[i].fp);
1692 stat = fclose(files[i].fp);
1694 WARNING( "i/o error occurred closing %s", files[i].fname );
1695 if (i > 2) /* don't do /dev/std... */
1696 xfree(files[i].fname);
1697 files[i].fname = NULL; /* watch out for ref thru this */
1703 setfval(x, (Awkfloat) stat);
1711 for (i = 0; i < FOPEN_MAX; i++) {
1713 if (ferror(files[i].fp))
1714 WARNING( "i/o error occurred on %s", files[i].fname );
1715 if (files[i].mode == '|' || files[i].mode == LE)
1716 stat = pclose(files[i].fp);
1718 stat = fclose(files[i].fp);
1720 WARNING( "i/o error occurred while closing %s", files[i].fname );
1725 void flush_all(void)
1729 for (i = 0; i < FOPEN_MAX; i++)
1731 fflush(files[i].fp);
1734 void backsub(char **pb_ptr, char **sptr_ptr);
1736 Cell *sub(Node **a, int nnn) /* substitute command */
1738 char *sptr, *pb, *q;
1739 Cell *x, *y, *result;
1742 int bufsz = recsize;
1744 if ((buf = (char *) malloc(bufsz)) == NULL)
1745 FATAL("out of memory in sub");
1746 x = execute(a[3]); /* target string */
1748 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1749 pfa = (fa *) a[1]; /* regular expression */
1752 pfa = makedfa(getsval(y), 1);
1755 y = execute(a[2]); /* replacement string */
1757 if (pmatch(pfa, t)) {
1759 adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1761 while (sptr < patbeg)
1764 while (*sptr != 0) {
1765 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1766 if (*sptr == '\\') {
1767 backsub(&pb, &sptr);
1768 } else if (*sptr == '&') {
1770 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1771 for (q = patbeg; q < patbeg+patlen; )
1777 if (pb > buf + bufsz)
1778 FATAL("sub result1 %.30s too big; can't happen", buf);
1779 sptr = patbeg + patlen;
1780 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1781 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1782 while ((*pb++ = *sptr++) != 0)
1785 if (pb > buf + bufsz)
1786 FATAL("sub result2 %.30s too big; can't happen", buf);
1787 setsval(x, buf); /* BUG: should be able to avoid copy */
1796 Cell *gsub(Node **a, int nnn) /* global substitute */
1799 char *rptr, *sptr, *t, *pb, *q;
1802 int mflag, tempstat, num;
1803 int bufsz = recsize;
1805 if ((buf = (char *) malloc(bufsz)) == NULL)
1806 FATAL("out of memory in gsub");
1807 mflag = 0; /* if mflag == 0, can replace empty string */
1809 x = execute(a[3]); /* target string */
1811 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1812 pfa = (fa *) a[1]; /* regular expression */
1815 pfa = makedfa(getsval(y), 1);
1818 y = execute(a[2]); /* replacement string */
1819 if (pmatch(pfa, t)) {
1820 tempstat = pfa->initstat;
1825 if (patlen == 0 && *patbeg != 0) { /* matched empty string */
1826 if (mflag == 0) { /* can replace empty */
1829 while (*sptr != 0) {
1830 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1831 if (*sptr == '\\') {
1832 backsub(&pb, &sptr);
1833 } else if (*sptr == '&') {
1835 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1836 for (q = patbeg; q < patbeg+patlen; )
1842 if (*t == 0) /* at end */
1844 adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1846 if (pb > buf + bufsz) /* BUG: not sure of this test */
1847 FATAL("gsub result0 %.30s too big; can't happen", buf);
1850 else { /* matched nonempty string */
1853 adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
1854 while (sptr < patbeg)
1857 while (*sptr != 0) {
1858 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1859 if (*sptr == '\\') {
1860 backsub(&pb, &sptr);
1861 } else if (*sptr == '&') {
1863 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1864 for (q = patbeg; q < patbeg+patlen; )
1869 t = patbeg + patlen;
1870 if (patlen == 0 || *t == 0 || *(t-1) == 0)
1872 if (pb > buf + bufsz)
1873 FATAL("gsub result1 %.30s too big; can't happen", buf);
1876 } while (pmatch(pfa,t));
1878 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
1879 while ((*pb++ = *sptr++) != 0)
1881 done: if (pb > buf + bufsz)
1882 FATAL("gsub result2 %.30s too big; can't happen", buf);
1884 setsval(x, buf); /* BUG: should be able to avoid copy + free */
1885 pfa->initstat = tempstat;
1896 void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */
1897 { /* sptr[0] == '\\' */
1898 char *pb = *pb_ptr, *sptr = *sptr_ptr;
1900 if (sptr[1] == '\\') {
1901 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
1905 } else if (sptr[2] == '&') { /* \\& -> \ + matched */
1908 } else { /* \\x -> \\x */
1912 } else if (sptr[1] == '&') { /* literal & */
1915 } else /* literal \ */