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, 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 dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
1220 ap->sval = (char *) makesymtab(NSYMTAB);
1223 if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) { /* reg expr */
1225 if (arg3type == REGEXPR) { /* it's ready already */
1231 if (nematch(p,s,t)) {
1234 sprintf(num, "%d", n);
1238 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1240 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1242 t = patbeg + patlen;
1243 if (t[-1] == 0 || *t == 0) {
1245 sprintf(num, "%d", n);
1246 setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1249 } while (nematch(p,s,t));
1252 sprintf(num, "%d", n);
1254 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1256 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1259 } else if (sep == ' ') {
1261 while (*s == ' ' || *s == '\t' || *s == '\n')
1269 while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1272 sprintf(num, "%d", n);
1274 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1276 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1281 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
1282 for (n = 0; *s != 0; s += nb) {
1287 snprintf(num, sizeof num, "%d", n);
1288 nb = chartorune(&r, s);
1289 memmove(buf, s, nb);
1291 if (isdigit(buf[0]))
1292 setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1294 setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1296 } else if (*s != 0) {
1300 while (*s != sep && *s != '\n' && *s != '\0')
1304 sprintf(num, "%d", n);
1306 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1308 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1316 if (a[2] != 0 && arg3type == STRING)
1324 Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
1339 Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
1347 } else if (a[2] != 0) {
1354 Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
1368 if (isnext(x) || isexit(x) || isret(x))
1374 Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
1382 if (isnext(x) || isnextfile(x) || isexit(x) || isret(x))
1392 Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
1401 if (!istrue(x)) return(x);
1405 if (isbreak(x)) /* turn off break */
1407 if (isnext(x) || isexit(x) || isret(x))
1415 Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1417 Cell *x, *vp, *arrayp, *cp, *ncp;
1422 arrayp = execute(a[1]);
1423 if (!isarr(arrayp)) {
1426 tp = (Array *) arrayp->sval;
1428 for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1429 for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1430 setsval(vp, cp->nval);
1437 if (isnext(x) || isexit(x) || isret(x)) {
1447 Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
1457 void flush_all(void);
1461 nextarg = a[1]->nnext;
1465 u = ((Array *) x->sval)->nelem; /* GROT. should be function*/
1468 u = (Awkfloat) countposn(p, strlen(p));
1472 u = errcheck(log(getfval(x)), "log"); break;
1474 modf(getfval(x), &u); break;
1476 u = errcheck(exp(getfval(x)), "exp"); break;
1478 u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1480 u = sin(getfval(x)); break;
1482 u = cos(getfval(x)); break;
1485 WARNING("atan2 requires two arguments; returning 1.0");
1488 y = execute(a[1]->nnext);
1489 u = atan2(getfval(x), getfval(y));
1491 nextarg = nextarg->nnext;
1495 fflush(stdout); /* in case something is buffered already */
1496 u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */
1499 /* in principle, rand() returns something in 0..RAND_MAX */
1500 u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1503 if (isrec(x)) /* no argument provided */
1504 u = time((time_t *)0);
1507 srand((unsigned int) u);
1511 buf = tostring(getsval(x));
1512 if (t == FTOUPPER) {
1513 for (p = buf; *p; p++)
1517 for (p = buf; *p; p++)
1527 if (isrec(x) || strlen(getsval(x)) == 0) {
1528 flush_all(); /* fflush() or fflush("") -> all */
1530 } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
1536 wc = (int)getfval(x);
1537 mbc[wctomb(mbc, wc)] = 0;
1542 default: /* can't happen */
1543 FATAL("illegal function type %d", t);
1550 WARNING("warning: function has too many arguments");
1551 for ( ; nextarg; nextarg = nextarg->nnext)
1557 Cell *printstat(Node **a, int n) /* print a[0] */
1564 if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
1567 fp = redirect(ptoi(a[1]), a[2]);
1568 for (x = a[0]; x != NULL; x = x->nnext) {
1570 fputs(getsval(y), fp);
1572 if (x->nnext == NULL)
1573 r = fputs(*ORS, fp);
1575 r = fputs(*OFS, fp);
1577 FATAL("write error on %s", filename(fp));
1580 if (fflush(fp) == EOF)
1581 FATAL("write error on %s", filename(fp));
1585 Cell *nullproc(Node **a, int n)
1591 FILE *redirect(int a, Node *b) /* set up all i/o redirections */
1599 fp = openfile(a, fname);
1601 FATAL("can't open file %s", fname);
1609 int mode; /* '|', 'a', 'w' => LE/LT, GT */
1610 } files[FOPEN_MAX] ={
1611 { NULL, "/dev/stdin", LT }, /* watch out: don't free this! */
1612 { NULL, "/dev/stdout", GT },
1613 { NULL, "/dev/stderr", GT }
1616 void stdinit(void) /* in case stdin, etc., are not constants */
1618 files[0].fp = stdin;
1619 files[1].fp = stdout;
1620 files[2].fp = stderr;
1623 FILE *openfile(int a, char *us)
1630 FATAL("null file name in print or getline");
1631 for (i=0; i < FOPEN_MAX; i++)
1632 if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1633 if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1638 if (a == FFLUSH) /* didn't find it, so don't create it! */
1641 for (i=0; i < FOPEN_MAX; i++)
1642 if (files[i].fp == 0)
1645 FATAL("%s makes too many open files", s);
1646 fflush(stdout); /* force a semblance of order */
1650 } else if (a == APPEND) {
1652 m = GT; /* so can mix > and >> */
1653 } else if (a == '|') { /* output pipe */
1655 } else if (a == LE) { /* input pipe */
1657 } else if (a == LT) { /* getline <file */
1658 fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
1659 } else /* can't happen */
1660 FATAL("illegal redirection %d", a);
1662 files[i].fname = tostring(s);
1669 char *filename(FILE *fp)
1673 for (i = 0; i < FOPEN_MAX; i++)
1674 if (fp == files[i].fp)
1675 return files[i].fname;
1679 Cell *closefile(Node **a, int n)
1686 for (i = 0; i < FOPEN_MAX; i++)
1687 if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1688 if (ferror(files[i].fp))
1689 WARNING( "i/o error occurred on %s", files[i].fname );
1690 if (files[i].mode == '|' || files[i].mode == LE)
1691 stat = pclose(files[i].fp);
1693 stat = fclose(files[i].fp);
1695 WARNING( "i/o error occurred closing %s", files[i].fname );
1696 if (i > 2) /* don't do /dev/std... */
1697 xfree(files[i].fname);
1698 files[i].fname = NULL; /* watch out for ref thru this */
1709 for (i = 0; i < FOPEN_MAX; i++)
1711 if (ferror(files[i].fp))
1712 WARNING( "i/o error occurred on %s", files[i].fname );
1713 if (files[i].mode == '|' || files[i].mode == LE)
1714 stat = pclose(files[i].fp);
1716 stat = fclose(files[i].fp);
1718 WARNING( "i/o error occurred while closing %s", files[i].fname );
1722 void flush_all(void)
1726 for (i = 0; i < FOPEN_MAX; i++)
1728 fflush(files[i].fp);
1731 void backsub(char **pb_ptr, char **sptr_ptr);
1733 Cell *sub(Node **a, int nnn) /* substitute command */
1735 char *sptr, *pb, *q;
1736 Cell *x, *y, *result;
1739 int bufsz = recsize;
1741 if ((buf = (char *) malloc(bufsz)) == NULL)
1742 FATAL("out of memory in sub");
1743 x = execute(a[3]); /* target string */
1745 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1746 p = (void *) a[1]; /* regular expression */
1749 p = compre(getsval(y));
1752 y = execute(a[2]); /* replacement string */
1754 if (pmatch(p, t, t)) {
1756 adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1758 while (sptr < patbeg)
1761 while (*sptr != 0) {
1762 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1763 if (*sptr == '\\') {
1764 backsub(&pb, &sptr);
1765 } else if (*sptr == '&') {
1767 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1768 for (q = patbeg; q < patbeg+patlen; )
1774 if (pb > buf + bufsz)
1775 FATAL("sub result1 %.30s too big; can't happen", buf);
1776 sptr = patbeg + patlen;
1777 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1778 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1779 while ((*pb++ = *sptr++) != 0)
1782 if (pb > buf + bufsz)
1783 FATAL("sub result2 %.30s too big; can't happen", buf);
1784 setsval(x, buf); /* BUG: should be able to avoid copy */
1793 Cell *gsub(Node **a, int nnn) /* global substitute */
1796 char *rptr, *sptr, *t, *pb, *c;
1800 int bufsz = recsize;
1802 if ((buf = (char *)malloc(bufsz)) == NULL)
1803 FATAL("out of memory in gsub");
1804 mflag = 0; /* if mflag == 0, can replace empty string */
1806 x = execute(a[3]); /* target string */
1808 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1809 p = (void *) a[1]; /* regular expression */
1812 p = compre(getsval(y));
1815 y = execute(a[2]); /* replacement string */
1816 if (pmatch(p, t, c)) {
1820 if (patlen == 0 && *patbeg != 0) { /* matched empty string */
1821 if (mflag == 0) { /* can replace empty */
1824 while (*sptr != 0) {
1825 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1826 if (*sptr == '\\') {
1827 backsub(&pb, &sptr);
1828 } else if (*sptr == '&') {
1831 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1832 for (q = patbeg; q < patbeg+patlen; )
1838 if (*c == 0) /* at end */
1840 adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1842 if (pb > buf + bufsz) /* BUG: not sure of this test */
1843 FATAL("gsub result0 %.30s too big; can't happen", buf);
1846 else { /* matched nonempty string */
1849 adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
1850 while (sptr < patbeg)
1853 while (*sptr != 0) {
1854 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1855 if (*sptr == '\\') {
1856 backsub(&pb, &sptr);
1857 } else if (*sptr == '&') {
1860 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1861 for (q = patbeg; q < patbeg+patlen; )
1866 c = patbeg + patlen;
1867 if ((c[-1] == 0) || (*c == 0))
1869 if (pb > buf + bufsz)
1870 FATAL("gsub result1 %.30s too big; can't happen", buf);
1873 } while (pmatch(p, t, c));
1875 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
1876 while ((*pb++ = *sptr++) != 0)
1878 done: if (pb > buf + bufsz)
1879 FATAL("gsub result2 %.30s too big; can't happen", buf);
1881 setsval(x, buf); /* BUG: should be able to avoid copy + free */
1892 void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */
1893 { /* sptr[0] == '\\' */
1894 char *pb = *pb_ptr, *sptr = *sptr_ptr;
1896 if (sptr[1] == '\\') {
1897 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
1901 } else if (sptr[2] == '&') { /* \\& -> \ + matched */
1904 } else { /* \\x -> \\x */
1908 } else if (sptr[1] == '&') { /* literal & */
1911 } else /* literal \ */