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 ****************************************************************/
37 #define tempfree(x) if (istemp(x)) tfree(x); else
42 void tempfree(Cell *p) {
43 if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
44 WARNING("bad csub %d in Cell %d %s",
45 p->csub, p->ctype, p->sval);
54 #define FOPEN_MAX _NFILE
59 #define FOPEN_MAX 40 /* max number of open files */
63 #define RAND_MAX 32767 /* all that ansi guarantees */
67 extern int pairstack[];
69 Node *winner = NULL; /* root of parse tree */
70 Cell *tmps; /* free temporary cells for execution */
72 static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
73 Cell *True = &truecell;
74 static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
75 Cell *False = &falsecell;
76 static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
77 Cell *jbreak = &breakcell;
78 static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM };
79 Cell *jcont = &contcell;
80 static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
81 Cell *jnext = &nextcell;
82 static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
83 Cell *jnextfile = &nextfilecell;
84 static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
85 Cell *jexit = &exitcell;
86 static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM };
87 Cell *jret = &retcell;
88 static Cell tempcell ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
90 Node *curnode = NULL; /* the node being executed, for debugging */
92 /* buffer memory management */
93 int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
95 /* pbuf: address of pointer to buffer being managed
96 * psiz: address of buffer size variable
97 * minlen: minimum length of buffer needed
98 * quantum: buffer size quantum
99 * pbptr: address of movable pointer into buffer, or 0 if none
100 * whatrtn: name of the calling routine if failure should cause fatal error
102 * return 0 for realloc failure, !=0 for success
105 if (minlen > *psiz) {
107 int rminlen = quantum ? minlen % quantum : 0;
108 int boff = pbptr ? *pbptr - *pbuf : 0;
109 /* round up to next multiple of quantum */
111 minlen += quantum - rminlen;
112 tbuf = (char *) realloc(*pbuf, minlen);
115 FATAL("out of memory in %s", whatrtn);
121 *pbptr = tbuf + boff;
126 void run(Node *a) /* execution of parse tree starts here */
128 extern void stdinit(void);
135 Cell *execute(Node *u) /* execute a node of the parse tree */
138 Cell *(*proc)(Node **, int);
144 for (a = u; ; a = a->nnext) {
147 x = (Cell *) (a->narg[0]);
148 if (isfld(x) && !donefld)
150 else if (isrec(x) && !donerec)
155 if (notlegal(nobj)) /* probably a Cell* but too risky to print */
156 FATAL("illegal statement");
157 proc = proctab[nobj-FIRSTTOKEN];
158 x = (*proc)(a->narg, nobj);
159 if (isfld(x) && !donefld)
161 else if (isrec(x) && !donerec)
167 if (a->nnext == NULL)
174 Cell *program(Node **a, int n) /* execute an awk program */
175 { /* a[0] = BEGIN, a[1] = body, a[2] = END */
178 if (setjmp(env) != 0)
180 if (a[0]) { /* BEGIN */
185 FATAL("illegal break, continue, next or nextfile from BEGIN");
189 while (getrec(&record, &recsize, 1) > 0) {
196 if (setjmp(env) != 0) /* handles exit within END */
198 if (a[2]) { /* END */
200 if (isbreak(x) || isnext(x) || iscont(x))
201 FATAL("illegal break, continue, next or nextfile from END");
208 struct Frame { /* stack frame for awk function calls */
209 int nargs; /* number of arguments in this call */
210 Cell *fcncell; /* pointer to Cell for function */
211 Cell **args; /* pointer to array of arguments after execute */
212 Cell *retval; /* return value */
215 #define NARGS 50 /* max args in a call */
217 struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
218 int nframe = 0; /* number of frames allocated */
219 struct Frame *fp = NULL; /* frame pointer. bottom level unused */
221 Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
223 static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
226 Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */
230 fcn = execute(a[0]); /* the function itself */
233 FATAL("calling undefined function %s", s);
235 fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
237 FATAL("out of space for stack frames calling %s", s);
239 for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
241 ndef = (int) fcn->fval; /* args in defn */
242 dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
244 WARNING("function %s called with %d args, uses only %d",
246 if (ncall + ndef > NARGS)
247 FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
248 for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */
249 dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
252 dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
253 i, y->nval, y->fval, isarr(y) ? "(array)" : y->sval, y->tval) );
255 FATAL("can't use function %s as argument in %s", y->nval, s);
257 args[i] = y; /* arrays by ref */
259 args[i] = copycell(y);
262 for ( ; i < ndef; i++) { /* add null args for ones not provided */
264 *args[i] = newcopycell;
266 fp++; /* now ok to up frame */
267 if (fp >= frame + nframe) {
268 int dfp = fp - frame; /* old index */
269 frame = (struct Frame *)
270 realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
272 FATAL("out of space for stack frames in %s", s);
277 fp->nargs = ndef; /* number defined with (excess are locals) */
278 fp->retval = gettemp();
280 dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
281 y = execute((Node *)(fcn->sval)); /* execute body */
282 dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
284 for (i = 0; i < ndef; i++) {
285 Cell *t = fp->args[i];
287 if (t->csub == CCOPY) {
293 oargs[i]->tval = t->tval;
294 oargs[i]->tval &= ~(STR|NUM|DONTFREE);
295 oargs[i]->sval = t->sval;
299 } else if (t != y) { /* kludge to prevent freeing twice */
305 if (isexit(y) || isnext(y) || isnextfile(y))
307 tempfree(y); /* this can free twice! */
308 z = fp->retval; /* return value */
309 dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
314 Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
319 y->csub = CCOPY; /* prevents freeing until call is over */
320 y->nval = x->nval; /* BUG? */
321 y->sval = x->sval ? tostring(x->sval) : NULL;
323 y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */
324 /* is DONTFREE right? */
328 Cell *arg(Node **a, int n) /* nth argument of a function */
331 n = ptoi(a[0]); /* argument number, counting from 0 */
332 dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
334 FATAL("argument #%d of function %s was not supplied",
335 n+1, fp->fcncell->nval);
339 Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */
347 errorflag = (int) getfval(y);
354 if ((y->tval & (STR|NUM)) == (STR|NUM)) {
355 setsval(fp->retval, getsval(y));
356 fp->retval->fval = getfval(y);
357 fp->retval->tval |= NUM;
359 else if (y->tval & STR)
360 setsval(fp->retval, getsval(y));
361 else if (y->tval & NUM)
362 setfval(fp->retval, getfval(y));
363 else /* can't happen */
364 FATAL("bad type variable %d", y->tval);
377 default: /* can't happen */
378 FATAL("illegal jump type %d", n);
380 return 0; /* not reached */
383 Cell *getline(Node **a, int n) /* get next line from specific input */
384 { /* a[0] is variable, a[1] is operator, a[2] is filename */
386 extern Cell **fldtab;
389 int bufsize = recsize;
392 if ((buf = (char *) malloc(bufsize)) == NULL)
393 FATAL("out of memory in getline");
395 fflush(stdout); /* in case someone is waiting for a prompt */
397 if (a[1] != NULL) { /* getline < file */
398 x = execute(a[2]); /* filename */
400 if (mode == '|') /* input pipe */
401 mode = LE; /* arbitrary flag */
402 fp = openfile(mode, getsval(x));
407 n = readrec(&buf, &bufsize, fp);
410 } else if (a[0] != NULL) { /* getline var <file */
414 } else { /* getline <file */
415 setsval(fldtab[0], buf);
416 if (is_number(fldtab[0]->sval)) {
417 fldtab[0]->fval = atof(fldtab[0]->sval);
418 fldtab[0]->tval |= NUM;
421 } else { /* bare getline; use current input */
422 if (a[0] == NULL) /* getline */
423 n = getrec(&record, &recsize, 1);
424 else { /* getline var */
425 n = getrec(&buf, &bufsize, 0);
431 setfval(r, (Awkfloat) n);
436 Cell *getnf(Node **a, int n) /* get NF */
440 return (Cell *) a[0];
443 Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
450 int nsub = strlen(*SUBSEP);
452 if ((buf = (char *) malloc(bufsz)) == NULL)
453 FATAL("out of memory in array");
455 x = execute(a[0]); /* Cell* for symbol table */
457 for (np = a[1]; np; np = np->nnext) {
458 y = execute(np); /* subscript */
460 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
461 FATAL("out of memory for %s[%s...]", x->nval, buf);
464 strcat(buf, *SUBSEP);
468 dprintf( ("making %s into an array\n", x->nval) );
471 x->tval &= ~(STR|NUM|DONTFREE);
473 x->sval = (char *) makesymtab(NSYMTAB);
475 z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
483 Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
488 int nsub = strlen(*SUBSEP);
490 x = execute(a[0]); /* Cell* for symbol table */
493 if (a[1] == 0) { /* delete the elements, not the table */
497 x->sval = (char *) makesymtab(NSYMTAB);
501 if ((buf = (char *) malloc(bufsz)) == NULL)
502 FATAL("out of memory in adelete");
504 for (np = a[1]; np; np = np->nnext) {
505 y = execute(np); /* subscript */
507 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
508 FATAL("out of memory deleting %s[%s...]", x->nval, buf);
511 strcat(buf, *SUBSEP);
521 Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
528 int nsub = strlen(*SUBSEP);
530 ap = execute(a[1]); /* array name */
532 dprintf( ("making %s into an array\n", ap->nval) );
535 ap->tval &= ~(STR|NUM|DONTFREE);
537 ap->sval = (char *) makesymtab(NSYMTAB);
539 if ((buf = (char *) malloc(bufsz)) == NULL) {
540 FATAL("out of memory in intest");
543 for (p = a[0]; p; p = p->nnext) {
544 x = execute(p); /* expr */
546 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
547 FATAL("out of memory deleting %s[%s...]", x->nval, buf);
551 strcat(buf, *SUBSEP);
553 k = lookup(buf, (Array *) ap->sval);
563 Cell *matchop(Node **a, int n) /* ~ and match() */
570 x = execute(a[1]); /* a[1] = target text */
572 if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */
575 y = execute(a[2]); /* a[2] = regular expr */
586 int start = countposn(s, patbeg-s)+1;
589 setfval(rstartloc, (Awkfloat) start);
590 setfval(rlengthloc, (Awkfloat) countposn(patbeg, 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]) */
729 k = countposn(s, strlen(s)) + 1;
739 m = (int) getfval(y);
746 n = (int) getfval(z);
754 dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
758 for (p = s; *p && n--; p += mblen(p, k))
760 temp = *p; /* with thanks to John Linderman */
768 Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
771 char *s1, *s2, *p1, *p2, *q;
780 for (p1 = s1; *p1 != '\0'; p1++) {
781 for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
784 v = (Awkfloat) countposn(s1, p1-s1) + 1; /* origin 1 */
794 #define MAXNUMSIZE 50
796 int format(char **pbuf, int *pbufsize, char *s, Node *a) /* printf-like conversions */
802 int fmtwd; /* format width */
805 int bufsize = *pbufsize;
809 if ((fmt = (char *) malloc(fmtsz)) == NULL)
810 FATAL("out of memory in format()");
812 adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format");
822 /* have to be real careful in case this is a huge number, eg, %100000d */
826 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
827 for (t = fmt; (*t++ = *s) != '\0'; s++) {
828 if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0))
829 FATAL("format item %.30s... ran format() out of memory", os);
830 if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
831 break; /* the ansi panoply */
835 sprintf(t-1, "%d", fmtwd=(int) getfval(x));
838 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
839 t = fmt + strlen(fmt);
846 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
849 case 'f': case 'e': case 'g': case 'E': case 'G':
854 if(*(s-1) == 'l') break;
859 case 'o': case 'x': case 'X': case 'u':
860 flag = *(s-1) == 'l' ? 2 : 3;
869 WARNING("weird printf conversion %s", fmt);
874 FATAL("not enough args in printf(%s)", os);
880 adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
882 case 0: sprintf(p, "%s", fmt); /* unknown, so dump it too */
887 adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
891 case 1: sprintf(p, fmt, getfval(x)); break;
892 case 2: sprintf(p, fmt, (long) getfval(x)); break;
893 case 3: sprintf(p, fmt, (int) getfval(x)); break;
899 if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
900 FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
906 sprintf(p, fmt, (int) getfval(x));
912 sprintf(p, fmt, getsval(x)[0]);
921 for ( ; a; a = a->nnext) /* evaluate any remaining args */
928 Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
935 if ((buf = (char *) malloc(bufsz)) == NULL)
936 FATAL("out of memory in awksprintf");
939 if (format(&buf, &bufsz, getsval(x), y) == -1)
940 FATAL("sprintf string %.30s... too long. can't happen.", buf);
948 Cell *awkprintf(Node **a, int n) /* printf */
949 { /* a[0] is list of args, starting with format string */
950 /* a[1] is redirection operator, a[2] is redirection file */
958 if ((buf = (char *) malloc(bufsz)) == NULL)
959 FATAL("out of memory in awkprintf");
962 if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
963 FATAL("printf string %.30s... too long. can't happen.", buf);
966 /* fputs(buf, stdout); */
967 fwrite(buf, len, 1, stdout);
969 FATAL("write error on stdout");
971 fp = redirect(ptoi(a[1]), a[2]);
972 /* fputs(buf, fp); */
973 fwrite(buf, len, 1, fp);
976 FATAL("write error on %s", filename(fp));
982 Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
1009 FATAL("division by zero");
1014 FATAL("division by zero in mod");
1022 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1023 i = ipow(i, (int) j);
1025 i = errcheck(pow(i, j), "pow");
1027 default: /* can't happen */
1028 FATAL("illegal arithmetic operator %d", n);
1034 double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
1047 Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
1055 k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1056 if (n == PREINCR || n == PREDECR) {
1067 Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
1068 { /* this is subtle; don't muck with it. */
1075 if (n == ASSIGN) { /* ordinary assignment */
1076 if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
1077 ; /* leave alone unless it's a field */
1078 else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1079 setsval(x, getsval(y));
1080 x->fval = getfval(y);
1084 setsval(x, getsval(y));
1086 setfval(x, getfval(y));
1088 funnyvar(y, "read value of");
1106 FATAL("division by zero in /=");
1111 FATAL("division by zero in %%=");
1116 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1117 xf = ipow(xf, (int) yf);
1119 xf = errcheck(pow(xf, yf), "pow");
1122 FATAL("illegal assignment operator %d", n);
1130 Cell *cat(Node **a, int q) /* a[0] cat a[1] */
1140 n1 = strlen(x->sval);
1141 n2 = strlen(y->sval);
1142 s = (char *) malloc(n1 + n2 + 1);
1144 FATAL("out of space concatenating %.15s... and %.15s...",
1147 strcpy(s+n1, y->sval);
1156 Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
1172 Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
1178 if (pairstack[pair] == 0) {
1181 pairstack[pair] = 1;
1184 if (pairstack[pair] == 1) {
1187 pairstack[pair] = 0;
1195 Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
1197 Cell *x = 0, *y, *ap;
1198 char *s, *t, *fs = 0;
1200 int n, nb, sep, tempstat, arg3type;
1202 y = execute(a[0]); /* source string */
1204 arg3type = ptoi(a[3]);
1205 if (a[2] == 0) /* fs string */
1207 else if (arg3type == STRING) { /* split(str,arr,"string") */
1210 } else if (arg3type == REGEXPR)
1211 fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
1213 FATAL("illegal type of split");
1215 ap = execute(a[1]); /* array name */
1217 y->tval |= DONTFREE; /* split(a[x], a); */
1220 dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
1223 ap->sval = (char *) makesymtab(NSYMTAB);
1226 if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) { /* reg expr */
1228 if (arg3type == REGEXPR) { /* it's ready already */
1234 if (nematch(p,s,t)) {
1237 sprintf(num, "%d", n);
1241 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1243 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1245 t = patbeg + patlen;
1246 if (t[-1] == 0 || *t == 0) {
1248 sprintf(num, "%d", n);
1249 setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1252 } while (nematch(p,s,t));
1255 sprintf(num, "%d", n);
1257 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1259 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1262 } else if (sep == ' ') {
1264 while (*s == ' ' || *s == '\t' || *s == '\n')
1272 while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1275 sprintf(num, "%d", n);
1277 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1279 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1284 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
1285 for (n = 0; *s != 0; s += nb) {
1290 snprintf(num, sizeof num, "%d", n);
1291 nb = chartorune(&r, s);
1292 memmove(buf, s, nb);
1294 if (isdigit(buf[0]))
1295 setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1297 setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1299 } else if (*s != 0) {
1303 while (*s != sep && *s != '\n' && *s != '\0')
1307 sprintf(num, "%d", n);
1309 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1311 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1319 if (a[2] != 0 && arg3type == STRING)
1327 Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
1342 Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
1350 } else if (a[2] != 0) {
1357 Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
1371 if (isnext(x) || isexit(x) || isret(x))
1377 Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
1385 if (isnext(x) || isnextfile(x) || isexit(x) || isret(x))
1395 Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
1404 if (!istrue(x)) return(x);
1408 if (isbreak(x)) /* turn off break */
1410 if (isnext(x) || isexit(x) || isret(x))
1418 Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1420 Cell *x, *vp, *arrayp, *cp, *ncp;
1425 arrayp = execute(a[1]);
1426 if (!isarr(arrayp)) {
1429 tp = (Array *) arrayp->sval;
1431 for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1432 for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1433 setsval(vp, cp->nval);
1440 if (isnext(x) || isexit(x) || isret(x)) {
1450 Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
1460 void flush_all(void);
1464 nextarg = a[1]->nnext;
1468 u = ((Array *) x->sval)->nelem; /* GROT. should be function*/
1471 u = (Awkfloat) countposn(p, strlen(p));
1475 u = errcheck(log(getfval(x)), "log"); break;
1477 modf(getfval(x), &u); break;
1479 u = errcheck(exp(getfval(x)), "exp"); break;
1481 u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1483 u = sin(getfval(x)); break;
1485 u = cos(getfval(x)); break;
1488 WARNING("atan2 requires two arguments; returning 1.0");
1491 y = execute(a[1]->nnext);
1492 u = atan2(getfval(x), getfval(y));
1494 nextarg = nextarg->nnext;
1498 fflush(stdout); /* in case something is buffered already */
1499 u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */
1502 /* in principle, rand() returns something in 0..RAND_MAX */
1503 u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1506 if (isrec(x)) /* no argument provided */
1507 u = time((time_t *)0);
1510 srand((unsigned int) u);
1514 buf = tostring(getsval(x));
1515 if (t == FTOUPPER) {
1516 for (p = buf; *p; p++)
1520 for (p = buf; *p; p++)
1530 if (isrec(x) || strlen(getsval(x)) == 0) {
1531 flush_all(); /* fflush() or fflush("") -> all */
1533 } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
1539 wc = (int)getfval(x);
1540 mbc[wctomb(mbc, wc)] = 0;
1545 default: /* can't happen */
1546 FATAL("illegal function type %d", t);
1553 WARNING("warning: function has too many arguments");
1554 for ( ; nextarg; nextarg = nextarg->nnext)
1560 Cell *printstat(Node **a, int n) /* print a[0] */
1567 if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
1570 fp = redirect(ptoi(a[1]), a[2]);
1571 for (x = a[0]; x != NULL; x = x->nnext) {
1573 fputs(getsval(y), fp);
1575 if (x->nnext == NULL)
1576 r = fputs(*ORS, fp);
1578 r = fputs(*OFS, fp);
1580 FATAL("write error on %s", filename(fp));
1583 if (fflush(fp) == EOF)
1584 FATAL("write error on %s", filename(fp));
1588 Cell *nullproc(Node **a, int n)
1596 FILE *redirect(int a, Node *b) /* set up all i/o redirections */
1604 fp = openfile(a, fname);
1606 FATAL("can't open file %s", fname);
1614 int mode; /* '|', 'a', 'w' => LE/LT, GT */
1615 } files[FOPEN_MAX] ={
1616 { NULL, "/dev/stdin", LT }, /* watch out: don't free this! */
1617 { NULL, "/dev/stdout", GT },
1618 { NULL, "/dev/stderr", GT }
1621 void stdinit(void) /* in case stdin, etc., are not constants */
1623 files[0].fp = stdin;
1624 files[1].fp = stdout;
1625 files[2].fp = stderr;
1628 FILE *openfile(int a, char *us)
1635 FATAL("null file name in print or getline");
1636 for (i=0; i < FOPEN_MAX; i++)
1637 if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1638 if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1643 if (a == FFLUSH) /* didn't find it, so don't create it! */
1646 for (i=0; i < FOPEN_MAX; i++)
1647 if (files[i].fp == 0)
1650 FATAL("%s makes too many open files", s);
1651 fflush(stdout); /* force a semblance of order */
1655 } else if (a == APPEND) {
1657 m = GT; /* so can mix > and >> */
1658 } else if (a == '|') { /* output pipe */
1660 } else if (a == LE) { /* input pipe */
1662 } else if (a == LT) { /* getline <file */
1663 fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
1664 } else /* can't happen */
1665 FATAL("illegal redirection %d", a);
1667 files[i].fname = tostring(s);
1674 char *filename(FILE *fp)
1678 for (i = 0; i < FOPEN_MAX; i++)
1679 if (fp == files[i].fp)
1680 return files[i].fname;
1684 Cell *closefile(Node **a, int n)
1692 for (i = 0; i < FOPEN_MAX; i++)
1693 if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1694 if (ferror(files[i].fp))
1695 WARNING( "i/o error occurred on %s", files[i].fname );
1696 if (files[i].mode == '|' || files[i].mode == LE)
1697 stat = pclose(files[i].fp);
1699 stat = fclose(files[i].fp);
1701 WARNING( "i/o error occurred closing %s", files[i].fname );
1702 if (i > 2) /* don't do /dev/std... */
1703 xfree(files[i].fname);
1704 files[i].fname = NULL; /* watch out for ref thru this */
1715 for (i = 0; i < FOPEN_MAX; i++)
1717 if (ferror(files[i].fp))
1718 WARNING( "i/o error occurred on %s", files[i].fname );
1719 if (files[i].mode == '|' || files[i].mode == LE)
1720 stat = pclose(files[i].fp);
1722 stat = fclose(files[i].fp);
1724 WARNING( "i/o error occurred while closing %s", files[i].fname );
1728 void flush_all(void)
1732 for (i = 0; i < FOPEN_MAX; i++)
1734 fflush(files[i].fp);
1737 void backsub(char **pb_ptr, char **sptr_ptr);
1739 Cell *sub(Node **a, int nnn) /* substitute command */
1741 char *sptr, *pb, *q;
1742 Cell *x, *y, *result;
1745 int bufsz = recsize;
1747 if ((buf = (char *) malloc(bufsz)) == NULL)
1748 FATAL("out of memory in sub");
1749 x = execute(a[3]); /* target string */
1751 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1752 p = (void *) a[1]; /* regular expression */
1755 p = compre(getsval(y));
1758 y = execute(a[2]); /* replacement string */
1760 if (pmatch(p, t, t)) {
1762 adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1764 while (sptr < patbeg)
1767 while (*sptr != 0) {
1768 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1769 if (*sptr == '\\') {
1770 backsub(&pb, &sptr);
1771 } else if (*sptr == '&') {
1773 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1774 for (q = patbeg; q < patbeg+patlen; )
1780 if (pb > buf + bufsz)
1781 FATAL("sub result1 %.30s too big; can't happen", buf);
1782 sptr = patbeg + patlen;
1783 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1784 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1785 while ((*pb++ = *sptr++) != 0)
1788 if (pb > buf + bufsz)
1789 FATAL("sub result2 %.30s too big; can't happen", buf);
1790 setsval(x, buf); /* BUG: should be able to avoid copy */
1799 Cell *gsub(Node **a, int nnn) /* global substitute */
1802 char *rptr, *sptr, *t, *pb, *c;
1806 int bufsz = recsize;
1808 if ((buf = (char *)malloc(bufsz)) == NULL)
1809 FATAL("out of memory in gsub");
1810 mflag = 0; /* if mflag == 0, can replace empty string */
1812 x = execute(a[3]); /* target string */
1814 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1815 p = (void *) a[1]; /* regular expression */
1818 p = compre(getsval(y));
1821 y = execute(a[2]); /* replacement string */
1822 if (pmatch(p, t, c)) {
1826 if (patlen == 0 && *patbeg != 0) { /* matched empty string */
1827 if (mflag == 0) { /* can replace empty */
1830 while (*sptr != 0) {
1831 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1832 if (*sptr == '\\') {
1833 backsub(&pb, &sptr);
1834 } else if (*sptr == '&') {
1837 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1838 for (q = patbeg; q < patbeg+patlen; )
1844 if (*c == 0) /* at end */
1846 adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1848 if (pb > buf + bufsz) /* BUG: not sure of this test */
1849 FATAL("gsub result0 %.30s too big; can't happen", buf);
1852 else { /* matched nonempty string */
1855 adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
1856 while (sptr < patbeg)
1859 while (*sptr != 0) {
1860 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1861 if (*sptr == '\\') {
1862 backsub(&pb, &sptr);
1863 } else if (*sptr == '&') {
1866 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1867 for (q = patbeg; q < patbeg+patlen; )
1872 c = patbeg + patlen;
1873 if ((c[-1] == 0) || (*c == 0))
1875 if (pb > buf + bufsz)
1876 FATAL("gsub result1 %.30s too big; can't happen", buf);
1879 } while (pmatch(p, t, c));
1881 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
1882 while ((*pb++ = *sptr++) != 0)
1884 done: if (pb > buf + bufsz)
1885 FATAL("gsub result2 %.30s too big; can't happen", buf);
1887 setsval(x, buf); /* BUG: should be able to avoid copy + free */
1898 void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */
1899 { /* sptr[0] == '\\' */
1900 char *pb = *pb_ptr, *sptr = *sptr_ptr;
1902 if (sptr[1] == '\\') {
1903 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
1907 } else if (sptr[2] == '&') { /* \\& -> \ + matched */
1910 } else { /* \\x -> \\x */
1914 } else if (sptr[1] == '&') { /* literal & */
1917 } else /* literal \ */