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 };
223 Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */
227 fcn = execute(a[0]); /* the function itself */
230 FATAL("calling undefined function %s", s);
232 fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
234 FATAL("out of space for stack frames calling %s", s);
236 for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
238 ndef = (int) fcn->fval; /* args in defn */
239 dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
241 WARNING("function %s called with %d args, uses only %d",
243 if (ncall + ndef > NARGS)
244 FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
245 for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */
246 dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
249 dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
250 i, y->nval, y->fval, isarr(y) ? "(array)" : y->sval, y->tval) );
252 FATAL("can't use function %s as argument in %s", y->nval, s);
254 args[i] = y; /* arrays by ref */
256 args[i] = copycell(y);
259 for ( ; i < ndef; i++) { /* add null args for ones not provided */
261 *args[i] = newcopycell;
263 fp++; /* now ok to up frame */
264 if (fp >= frame + nframe) {
265 int dfp = fp - frame; /* old index */
266 frame = (struct Frame *)
267 realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
269 FATAL("out of space for stack frames in %s", s);
274 fp->nargs = ndef; /* number defined with (excess are locals) */
275 fp->retval = gettemp();
277 dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
278 y = execute((Node *)(fcn->sval)); /* execute body */
279 dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
281 for (i = 0; i < ndef; i++) {
282 Cell *t = fp->args[i];
284 if (t->csub == CCOPY) {
290 oargs[i]->tval = t->tval;
291 oargs[i]->tval &= ~(STR|NUM|DONTFREE);
292 oargs[i]->sval = t->sval;
296 } else if (t != y) { /* kludge to prevent freeing twice */
302 if (isexit(y) || isnext(y))
304 tempfree(y); /* this can free twice! */
305 z = fp->retval; /* return value */
306 dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
311 Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
316 y->csub = CCOPY; /* prevents freeing until call is over */
317 y->nval = x->nval; /* BUG? */
319 y->sval = tostring(x->sval);
321 y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */
322 /* is DONTFREE right? */
326 Cell *arg(Node **a, int n) /* nth argument of a function */
329 n = ptoi(a[0]); /* argument number, counting from 0 */
330 dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
332 FATAL("argument #%d of function %s was not supplied",
333 n+1, fp->fcncell->nval);
337 Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */
345 errorflag = (int) getfval(y);
352 if ((y->tval & (STR|NUM)) == (STR|NUM)) {
353 setsval(fp->retval, getsval(y));
354 fp->retval->fval = getfval(y);
355 fp->retval->tval |= NUM;
357 else if (y->tval & STR)
358 setsval(fp->retval, getsval(y));
359 else if (y->tval & NUM)
360 setfval(fp->retval, getfval(y));
361 else /* can't happen */
362 FATAL("bad type variable %d", y->tval);
375 default: /* can't happen */
376 FATAL("illegal jump type %d", n);
378 return 0; /* not reached */
381 Cell *getline(Node **a, int n) /* get next line from specific input */
382 { /* a[0] is variable, a[1] is operator, a[2] is filename */
384 extern Cell **fldtab;
387 int bufsize = recsize;
390 if ((buf = (char *) malloc(bufsize)) == NULL)
391 FATAL("out of memory in getline");
393 fflush(stdout); /* in case someone is waiting for a prompt */
395 if (a[1] != NULL) { /* getline < file */
396 x = execute(a[2]); /* filename */
398 if (mode == '|') /* input pipe */
399 mode = LE; /* arbitrary flag */
400 fp = openfile(mode, getsval(x));
405 n = readrec(&buf, &bufsize, fp);
408 } else if (a[0] != NULL) { /* getline var <file */
412 } else { /* getline <file */
413 setsval(fldtab[0], buf);
414 if (is_number(fldtab[0]->sval)) {
415 fldtab[0]->fval = atof(fldtab[0]->sval);
416 fldtab[0]->tval |= NUM;
419 } else { /* bare getline; use current input */
420 if (a[0] == NULL) /* getline */
421 n = getrec(&record, &recsize, 1);
422 else { /* getline var */
423 n = getrec(&buf, &bufsize, 0);
429 setfval(r, (Awkfloat) n);
434 Cell *getnf(Node **a, int n) /* get NF */
438 return (Cell *) a[0];
441 Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
448 int nsub = strlen(*SUBSEP);
450 if ((buf = (char *) malloc(bufsz)) == NULL)
451 FATAL("out of memory in array");
453 x = execute(a[0]); /* Cell* for symbol table */
455 for (np = a[1]; np; np = np->nnext) {
456 y = execute(np); /* subscript */
458 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
459 FATAL("out of memory for %s[%s...]", x->nval, buf);
462 strcat(buf, *SUBSEP);
466 dprintf( ("making %s into an array\n", x->nval) );
469 x->tval &= ~(STR|NUM|DONTFREE);
471 x->sval = (char *) makesymtab(NSYMTAB);
473 z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
481 Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
486 int nsub = strlen(*SUBSEP);
488 x = execute(a[0]); /* Cell* for symbol table */
491 if (a[1] == 0) { /* delete the elements, not the table */
495 x->sval = (char *) makesymtab(NSYMTAB);
499 if ((buf = (char *) malloc(bufsz)) == NULL)
500 FATAL("out of memory in adelete");
502 for (np = a[1]; np; np = np->nnext) {
503 y = execute(np); /* subscript */
505 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
506 FATAL("out of memory deleting %s[%s...]", x->nval, buf);
509 strcat(buf, *SUBSEP);
519 Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
526 int nsub = strlen(*SUBSEP);
528 ap = execute(a[1]); /* array name */
530 dprintf( ("making %s into an array\n", ap->nval) );
533 ap->tval &= ~(STR|NUM|DONTFREE);
535 ap->sval = (char *) makesymtab(NSYMTAB);
537 if ((buf = (char *) malloc(bufsz)) == NULL) {
538 FATAL("out of memory in intest");
541 for (p = a[0]; p; p = p->nnext) {
542 x = execute(p); /* expr */
544 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
545 FATAL("out of memory deleting %s[%s...]", x->nval, buf);
549 strcat(buf, *SUBSEP);
551 k = lookup(buf, (Array *) ap->sval);
561 Cell *matchop(Node **a, int n) /* ~ and match() */
567 int (*mf)(fa *, char *) = match, mode = 0;
573 x = execute(a[1]); /* a[1] = target text */
575 if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */
576 i = (*mf)((fa *) a[2], s);
578 y = execute(a[2]); /* a[2] = regular expr */
580 pfa = makedfa(t, mode);
586 int start = patbeg - s + 1;
589 setfval(rstartloc, (Awkfloat) start);
590 setfval(rlengthloc, (Awkfloat) patlen);
595 } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
602 Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
619 if ( !i ) return(False);
626 if (i) return(False);
628 default: /* can't happen */
629 FATAL("unknown boolean operator %d", n);
631 return 0; /*NOTREACHED*/
634 Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
642 if (x->tval&NUM && y->tval&NUM) {
643 j = x->fval - y->fval;
644 i = j<0? -1: (j>0? 1: 0);
646 i = strcmp(getsval(x), getsval(y));
651 case LT: if (i<0) return(True);
653 case LE: if (i<=0) return(True);
655 case NE: if (i!=0) return(True);
657 case EQ: if (i == 0) return(True);
659 case GE: if (i>=0) return(True);
661 case GT: if (i>0) return(True);
663 default: /* can't happen */
664 FATAL("unknown relational operator %d", n);
666 return 0; /*NOTREACHED*/
669 void tfree(Cell *a) /* free a tempcell */
672 dprintf( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) );
676 FATAL("tempcell list is curdled");
681 Cell *gettemp(void) /* get a tempcell */
686 tmps = (Cell *) calloc(100, sizeof(Cell));
688 FATAL("out of space for temporaries");
689 for(i = 1; i < 100; i++)
690 tmps[i-1].cnext = &tmps[i];
699 Cell *indirect(Node **a, int n) /* $( a[0] ) */
706 m = (int) getfval(x);
707 if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */
708 FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
709 /* BUG: can x->nval ever be null??? */
712 x->ctype = OCELL; /* BUG? why are these needed? */
717 Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
740 m = (int) getfval(y);
747 n = (int) getfval(z);
755 dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
757 temp = s[n+m-1]; /* with thanks to John Linderman */
759 setsval(y, s + m - 1);
765 Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
768 char *s1, *s2, *p1, *p2, *q;
777 for (p1 = s1; *p1 != '\0'; p1++) {
778 for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
781 v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */
791 #define MAXNUMSIZE 50
793 int format(char **pbuf, int *pbufsize, char *s, Node *a) /* printf-like conversions */
799 int fmtwd; /* format width */
802 int bufsize = *pbufsize;
806 if ((fmt = (char *) malloc(fmtsz)) == NULL)
807 FATAL("out of memory in format()");
809 adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format");
819 /* have to be real careful in case this is a huge number, eg, %100000d */
823 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
824 for (t = fmt; (*t++ = *s) != '\0'; s++) {
825 if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0))
826 FATAL("format item %.30s... ran format() out of memory", os);
827 if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L')
828 break; /* the ansi panoply */
832 sprintf(t-1, "%d", fmtwd=(int) getfval(x));
835 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
836 t = fmt + strlen(fmt);
843 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
846 case 'f': case 'e': case 'g': case 'E': case 'G':
851 if(*(s-1) == 'l') break;
856 case 'o': case 'x': case 'X': case 'u':
857 flag = *(s-1) == 'l' ? 2 : 3;
866 WARNING("weird printf conversion %s", fmt);
871 FATAL("not enough args in printf(%s)", os);
877 adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
879 case 0: sprintf(p, "%s", fmt); /* unknown, so dump it too */
884 adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
888 case 1: sprintf(p, fmt, getfval(x)); break;
889 case 2: sprintf(p, fmt, (long) getfval(x)); break;
890 case 3: sprintf(p, fmt, (int) getfval(x)); break;
896 if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
897 FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
903 sprintf(p, fmt, (int) getfval(x));
907 sprintf(p, fmt, getsval(x)[0]);
916 for ( ; a; a = a->nnext) /* evaluate any remaining args */
923 Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
930 if ((buf = (char *) malloc(bufsz)) == NULL)
931 FATAL("out of memory in awksprintf");
934 if (format(&buf, &bufsz, getsval(x), y) == -1)
935 FATAL("sprintf string %.30s... too long. can't happen.", buf);
943 Cell *awkprintf(Node **a, int n) /* printf */
944 { /* a[0] is list of args, starting with format string */
945 /* a[1] is redirection operator, a[2] is redirection file */
953 if ((buf = (char *) malloc(bufsz)) == NULL)
954 FATAL("out of memory in awkprintf");
957 if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
958 FATAL("printf string %.30s... too long. can't happen.", buf);
961 /* fputs(buf, stdout); */
962 fwrite(buf, len, 1, stdout);
964 FATAL("write error on stdout");
966 fp = redirect(ptoi(a[1]), a[2]);
967 /* fputs(buf, fp); */
968 fwrite(buf, len, 1, fp);
971 FATAL("write error on %s", filename(fp));
977 Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
1004 FATAL("division by zero");
1009 FATAL("division by zero in mod");
1017 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1018 i = ipow(i, (int) j);
1020 i = errcheck(pow(i, j), "pow");
1022 default: /* can't happen */
1023 FATAL("illegal arithmetic operator %d", n);
1029 double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
1042 Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
1050 k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1051 if (n == PREINCR || n == PREDECR) {
1062 Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
1063 { /* this is subtle; don't muck with it. */
1070 if (n == ASSIGN) { /* ordinary assignment */
1071 if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
1072 ; /* leave alone unless it's a field */
1073 else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1074 setsval(x, getsval(y));
1075 x->fval = getfval(y);
1079 setsval(x, getsval(y));
1081 setfval(x, getfval(y));
1083 funnyvar(y, "read value of");
1101 FATAL("division by zero in /=");
1106 FATAL("division by zero in %%=");
1111 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1112 xf = ipow(xf, (int) yf);
1114 xf = errcheck(pow(xf, yf), "pow");
1117 FATAL("illegal assignment operator %d", n);
1125 Cell *cat(Node **a, int q) /* a[0] cat a[1] */
1135 n1 = strlen(x->sval);
1136 n2 = strlen(y->sval);
1137 s = (char *) malloc(n1 + n2 + 1);
1139 FATAL("out of space concatenating %.15s... and %.15s...",
1142 strcpy(s+n1, y->sval);
1151 Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
1167 Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
1173 if (pairstack[pair] == 0) {
1176 pairstack[pair] = 1;
1179 if (pairstack[pair] == 1) {
1182 pairstack[pair] = 0;
1190 Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
1192 Cell *x = 0, *y, *ap;
1195 char *t, temp, num[50], *fs = 0;
1196 int n, tempstat, arg3type;
1198 y = execute(a[0]); /* source string */
1200 arg3type = ptoi(a[3]);
1201 if (a[2] == 0) /* fs string */
1203 else if (arg3type == STRING) { /* split(str,arr,"string") */
1206 } else if (arg3type == REGEXPR)
1207 fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
1209 FATAL("illegal type of split");
1211 ap = execute(a[1]); /* array name */
1213 dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
1216 ap->sval = (char *) makesymtab(NSYMTAB);
1219 if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) { /* reg expr */
1221 if (arg3type == REGEXPR) { /* it's ready already */
1224 pfa = makedfa(fs, 1);
1226 if (nematch(pfa,s)) {
1227 tempstat = pfa->initstat;
1231 sprintf(num, "%d", n);
1235 setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1237 setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1239 s = patbeg + patlen;
1240 if (*(patbeg+patlen-1) == 0 || *s == 0) {
1242 sprintf(num, "%d", n);
1243 setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1244 pfa->initstat = tempstat;
1247 } while (nematch(pfa,s));
1250 sprintf(num, "%d", n);
1252 setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1254 setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1257 } else if (sep == ' ') {
1259 while (*s == ' ' || *s == '\t' || *s == '\n')
1267 while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1270 sprintf(num, "%d", n);
1272 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1274 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1279 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
1280 for (n = 0; *s != 0; s++) {
1283 sprintf(num, "%d", n);
1286 if (isdigit((uschar)buf[0]))
1287 setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1289 setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1291 } else if (*s != 0) {
1295 while (*s != sep && *s != '\n' && *s != '\0')
1299 sprintf(num, "%d", n);
1301 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1303 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1311 if (a[2] != 0 && arg3type == STRING) {
1320 Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
1335 Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
1343 } else if (a[2] != 0) {
1350 Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
1364 if (isnext(x) || isexit(x) || isret(x))
1370 Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
1378 if (isnext(x) || isexit(x) || isret(x))
1388 Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
1397 if (!istrue(x)) return(x);
1401 if (isbreak(x)) /* turn off break */
1403 if (isnext(x) || isexit(x) || isret(x))
1411 Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1413 Cell *x, *vp, *arrayp, *cp, *ncp;
1418 arrayp = execute(a[1]);
1419 if (!isarr(arrayp)) {
1422 tp = (Array *) arrayp->sval;
1424 for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1425 for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1426 setsval(vp, cp->nval);
1433 if (isnext(x) || isexit(x) || isret(x)) {
1443 Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
1451 void flush_all(void);
1455 nextarg = a[1]->nnext;
1459 u = ((Array *) x->sval)->nelem; /* GROT. should be function*/
1461 u = strlen(getsval(x));
1464 u = errcheck(log(getfval(x)), "log"); break;
1466 modf(getfval(x), &u); break;
1468 u = errcheck(exp(getfval(x)), "exp"); break;
1470 u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1472 u = sin(getfval(x)); break;
1474 u = cos(getfval(x)); break;
1477 WARNING("atan2 requires two arguments; returning 1.0");
1480 y = execute(a[1]->nnext);
1481 u = atan2(getfval(x), getfval(y));
1483 nextarg = nextarg->nnext;
1487 fflush(stdout); /* in case something is buffered already */
1488 u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */
1491 /* in principle, rand() returns something in 0..RAND_MAX */
1492 u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1495 if (isrec(x)) /* no argument provided */
1496 u = time((time_t *)0);
1499 srand((unsigned int) u);
1503 buf = tostring(getsval(x));
1504 if (t == FTOUPPER) {
1505 for (p = buf; *p; p++)
1506 if (islower((uschar) *p))
1509 for (p = buf; *p; p++)
1510 if (isupper((uschar) *p))
1519 if (isrec(x) || strlen(getsval(x)) == 0) {
1520 flush_all(); /* fflush() or fflush("") -> all */
1522 } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
1527 default: /* can't happen */
1528 FATAL("illegal function type %d", t);
1535 WARNING("warning: function has too many arguments");
1536 for ( ; nextarg; nextarg = nextarg->nnext)
1542 Cell *printstat(Node **a, int n) /* print a[0] */
1548 if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
1551 fp = redirect(ptoi(a[1]), a[2]);
1552 for (x = a[0]; x != NULL; x = x->nnext) {
1554 fputs(getsval(y), fp);
1556 if (x->nnext == NULL)
1564 FATAL("write error on %s", filename(fp));
1568 Cell *nullproc(Node **a, int n)
1576 FILE *redirect(int a, Node *b) /* set up all i/o redirections */
1584 fp = openfile(a, fname);
1586 FATAL("can't open file %s", fname);
1594 int mode; /* '|', 'a', 'w' => LE/LT, GT */
1595 } files[FOPEN_MAX] ={
1596 { NULL, "/dev/stdin", LT }, /* watch out: don't free this! */
1597 { NULL, "/dev/stdout", GT },
1598 { NULL, "/dev/stderr", GT }
1601 void stdinit(void) /* in case stdin, etc., are not constants */
1603 files[0].fp = stdin;
1604 files[1].fp = stdout;
1605 files[2].fp = stderr;
1608 FILE *openfile(int a, char *us)
1615 FATAL("null file name in print or getline");
1616 for (i=0; i < FOPEN_MAX; i++)
1617 if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1618 if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1623 if (a == FFLUSH) /* didn't find it, so don't create it! */
1626 for (i=0; i < FOPEN_MAX; i++)
1627 if (files[i].fp == 0)
1630 FATAL("%s makes too many open files", s);
1631 fflush(stdout); /* force a semblance of order */
1635 } else if (a == APPEND) {
1637 m = GT; /* so can mix > and >> */
1638 } else if (a == '|') { /* output pipe */
1640 } else if (a == LE) { /* input pipe */
1642 } else if (a == LT) { /* getline <file */
1643 fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
1644 } else /* can't happen */
1645 FATAL("illegal redirection %d", a);
1647 files[i].fname = tostring(s);
1654 char *filename(FILE *fp)
1658 for (i = 0; i < FOPEN_MAX; i++)
1659 if (fp == files[i].fp)
1660 return files[i].fname;
1664 Cell *closefile(Node **a, int n)
1673 for (i = 0; i < FOPEN_MAX; i++) {
1674 if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1675 if (ferror(files[i].fp))
1676 WARNING( "i/o error occurred on %s", files[i].fname );
1677 if (files[i].mode == '|' || files[i].mode == LE)
1678 stat = pclose(files[i].fp);
1680 stat = fclose(files[i].fp);
1682 WARNING( "i/o error occurred closing %s", files[i].fname );
1683 if (i > 2) /* don't do /dev/std... */
1684 xfree(files[i].fname);
1685 files[i].fname = NULL; /* watch out for ref thru this */
1691 setfval(x, (Awkfloat) stat);
1699 for (i = 0; i < FOPEN_MAX; i++) {
1701 if (ferror(files[i].fp))
1702 WARNING( "i/o error occurred on %s", files[i].fname );
1703 if (files[i].mode == '|' || files[i].mode == LE)
1704 stat = pclose(files[i].fp);
1706 stat = fclose(files[i].fp);
1708 WARNING( "i/o error occurred while closing %s", files[i].fname );
1713 void flush_all(void)
1717 for (i = 0; i < FOPEN_MAX; i++)
1719 fflush(files[i].fp);
1722 void backsub(char **pb_ptr, char **sptr_ptr);
1724 Cell *sub(Node **a, int nnn) /* substitute command */
1726 char *sptr, *pb, *q;
1727 Cell *x, *y, *result;
1730 int bufsz = recsize;
1732 if ((buf = (char *) malloc(bufsz)) == NULL)
1733 FATAL("out of memory in sub");
1734 x = execute(a[3]); /* target string */
1736 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1737 pfa = (fa *) a[1]; /* regular expression */
1740 pfa = makedfa(getsval(y), 1);
1743 y = execute(a[2]); /* replacement string */
1745 if (pmatch(pfa, t)) {
1747 adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1749 while (sptr < patbeg)
1752 while (*sptr != 0) {
1753 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1754 if (*sptr == '\\') {
1755 backsub(&pb, &sptr);
1756 } else if (*sptr == '&') {
1758 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1759 for (q = patbeg; q < patbeg+patlen; )
1765 if (pb > buf + bufsz)
1766 FATAL("sub result1 %.30s too big; can't happen", buf);
1767 sptr = patbeg + patlen;
1768 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1769 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1770 while ((*pb++ = *sptr++) != 0)
1773 if (pb > buf + bufsz)
1774 FATAL("sub result2 %.30s too big; can't happen", buf);
1775 setsval(x, buf); /* BUG: should be able to avoid copy */
1784 Cell *gsub(Node **a, int nnn) /* global substitute */
1787 char *rptr, *sptr, *t, *pb, *q;
1790 int mflag, tempstat, num;
1791 int bufsz = recsize;
1793 if ((buf = (char *) malloc(bufsz)) == NULL)
1794 FATAL("out of memory in gsub");
1795 mflag = 0; /* if mflag == 0, can replace empty string */
1797 x = execute(a[3]); /* target string */
1799 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1800 pfa = (fa *) a[1]; /* regular expression */
1803 pfa = makedfa(getsval(y), 1);
1806 y = execute(a[2]); /* replacement string */
1807 if (pmatch(pfa, t)) {
1808 tempstat = pfa->initstat;
1813 if (patlen == 0 && *patbeg != 0) { /* matched empty string */
1814 if (mflag == 0) { /* can replace empty */
1817 while (*sptr != 0) {
1818 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1819 if (*sptr == '\\') {
1820 backsub(&pb, &sptr);
1821 } else if (*sptr == '&') {
1823 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1824 for (q = patbeg; q < patbeg+patlen; )
1830 if (*t == 0) /* at end */
1832 adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1834 if (pb > buf + bufsz) /* BUG: not sure of this test */
1835 FATAL("gsub result0 %.30s too big; can't happen", buf);
1838 else { /* matched nonempty string */
1841 adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
1842 while (sptr < patbeg)
1845 while (*sptr != 0) {
1846 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1847 if (*sptr == '\\') {
1848 backsub(&pb, &sptr);
1849 } else if (*sptr == '&') {
1851 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1852 for (q = patbeg; q < patbeg+patlen; )
1857 t = patbeg + patlen;
1858 if (patlen == 0 || *t == 0 || *(t-1) == 0)
1860 if (pb > buf + bufsz)
1861 FATAL("gsub result1 %.30s too big; can't happen", buf);
1864 } while (pmatch(pfa,t));
1866 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
1867 while ((*pb++ = *sptr++) != 0)
1869 done: if (pb > buf + bufsz)
1870 FATAL("gsub result2 %.30s too big; can't happen", buf);
1872 setsval(x, buf); /* BUG: should be able to avoid copy + free */
1873 pfa->initstat = tempstat;
1884 void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */
1885 { /* sptr[0] == '\\' */
1886 char *pb = *pb_ptr, *sptr = *sptr_ptr;
1888 if (sptr[1] == '\\') {
1889 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
1893 } else if (sptr[2] == '&') { /* \\& -> \ + matched */
1896 } else { /* \\x -> \\x */
1900 } else if (sptr[1] == '&') { /* literal & */
1903 } else /* literal \ */