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 */
1216 y->tval |= DONTFREE; /* split(a[x], a); */
1218 y->tval &= ~DONTFREE;
1219 dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
1222 ap->sval = (char *) makesymtab(NSYMTAB);
1225 if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) { /* reg expr */
1227 if (arg3type == REGEXPR) { /* it's ready already */
1233 if (nematch(p,s,t)) {
1236 sprintf(num, "%d", n);
1240 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1242 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1244 t = patbeg + patlen;
1245 if (t[-1] == 0 || *t == 0) {
1247 sprintf(num, "%d", n);
1248 setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1251 } while (nematch(p,s,t));
1254 sprintf(num, "%d", n);
1256 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1258 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1261 } else if (sep == ' ') {
1263 while (*s == ' ' || *s == '\t' || *s == '\n')
1271 while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1274 sprintf(num, "%d", n);
1276 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1278 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1283 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
1284 for (n = 0; *s != 0; s += nb) {
1289 snprintf(num, sizeof num, "%d", n);
1290 nb = chartorune(&r, s);
1291 memmove(buf, s, nb);
1293 if (isdigit(buf[0]))
1294 setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1296 setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1298 } else if (*s != 0) {
1302 while (*s != sep && *s != '\n' && *s != '\0')
1306 sprintf(num, "%d", n);
1308 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1310 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1318 if (a[2] != 0 && arg3type == STRING)
1326 Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
1341 Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
1349 } else if (a[2] != 0) {
1356 Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
1370 if (isnext(x) || isexit(x) || isret(x))
1376 Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
1384 if (isnext(x) || isnextfile(x) || isexit(x) || isret(x))
1394 Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
1403 if (!istrue(x)) return(x);
1407 if (isbreak(x)) /* turn off break */
1409 if (isnext(x) || isexit(x) || isret(x))
1417 Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1419 Cell *x, *vp, *arrayp, *cp, *ncp;
1424 arrayp = execute(a[1]);
1425 if (!isarr(arrayp)) {
1428 tp = (Array *) arrayp->sval;
1430 for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1431 for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1432 setsval(vp, cp->nval);
1439 if (isnext(x) || isexit(x) || isret(x)) {
1449 Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
1459 void flush_all(void);
1463 nextarg = a[1]->nnext;
1467 u = ((Array *) x->sval)->nelem; /* GROT. should be function*/
1470 u = (Awkfloat) countposn(p, strlen(p));
1474 u = errcheck(log(getfval(x)), "log"); break;
1476 modf(getfval(x), &u); break;
1478 u = errcheck(exp(getfval(x)), "exp"); break;
1480 u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1482 u = sin(getfval(x)); break;
1484 u = cos(getfval(x)); break;
1487 WARNING("atan2 requires two arguments; returning 1.0");
1490 y = execute(a[1]->nnext);
1491 u = atan2(getfval(x), getfval(y));
1493 nextarg = nextarg->nnext;
1497 fflush(stdout); /* in case something is buffered already */
1498 u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */
1501 /* in principle, rand() returns something in 0..RAND_MAX */
1502 u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1505 if (isrec(x)) /* no argument provided */
1506 u = time((time_t *)0);
1509 srand((unsigned int) u);
1513 buf = tostring(getsval(x));
1514 if (t == FTOUPPER) {
1515 for (p = buf; *p; p++)
1519 for (p = buf; *p; p++)
1529 if (isrec(x) || strlen(getsval(x)) == 0) {
1530 flush_all(); /* fflush() or fflush("") -> all */
1532 } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
1538 wc = (int)getfval(x);
1539 mbc[wctomb(mbc, wc)] = 0;
1544 default: /* can't happen */
1545 FATAL("illegal function type %d", t);
1552 WARNING("warning: function has too many arguments");
1553 for ( ; nextarg; nextarg = nextarg->nnext)
1559 Cell *printstat(Node **a, int n) /* print a[0] */
1566 if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
1569 fp = redirect(ptoi(a[1]), a[2]);
1570 for (x = a[0]; x != NULL; x = x->nnext) {
1572 fputs(getsval(y), fp);
1574 if (x->nnext == NULL)
1575 r = fputs(*ORS, fp);
1577 r = fputs(*OFS, fp);
1579 FATAL("write error on %s", filename(fp));
1582 if (fflush(fp) == EOF)
1583 FATAL("write error on %s", filename(fp));
1587 Cell *nullproc(Node **a, int n)
1595 FILE *redirect(int a, Node *b) /* set up all i/o redirections */
1603 fp = openfile(a, fname);
1605 FATAL("can't open file %s", fname);
1613 int mode; /* '|', 'a', 'w' => LE/LT, GT */
1614 } files[FOPEN_MAX] ={
1615 { NULL, "/dev/stdin", LT }, /* watch out: don't free this! */
1616 { NULL, "/dev/stdout", GT },
1617 { NULL, "/dev/stderr", GT }
1620 void stdinit(void) /* in case stdin, etc., are not constants */
1622 files[0].fp = stdin;
1623 files[1].fp = stdout;
1624 files[2].fp = stderr;
1627 FILE *openfile(int a, char *us)
1634 FATAL("null file name in print or getline");
1635 for (i=0; i < FOPEN_MAX; i++)
1636 if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1637 if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1642 if (a == FFLUSH) /* didn't find it, so don't create it! */
1645 for (i=0; i < FOPEN_MAX; i++)
1646 if (files[i].fp == 0)
1649 FATAL("%s makes too many open files", s);
1650 fflush(stdout); /* force a semblance of order */
1654 } else if (a == APPEND) {
1656 m = GT; /* so can mix > and >> */
1657 } else if (a == '|') { /* output pipe */
1659 } else if (a == LE) { /* input pipe */
1661 } else if (a == LT) { /* getline <file */
1662 fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
1663 } else /* can't happen */
1664 FATAL("illegal redirection %d", a);
1666 files[i].fname = tostring(s);
1673 char *filename(FILE *fp)
1677 for (i = 0; i < FOPEN_MAX; i++)
1678 if (fp == files[i].fp)
1679 return files[i].fname;
1683 Cell *closefile(Node **a, int n)
1691 for (i = 0; i < FOPEN_MAX; i++)
1692 if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1693 if (ferror(files[i].fp))
1694 WARNING( "i/o error occurred on %s", files[i].fname );
1695 if (files[i].mode == '|' || files[i].mode == LE)
1696 stat = pclose(files[i].fp);
1698 stat = fclose(files[i].fp);
1700 WARNING( "i/o error occurred closing %s", files[i].fname );
1701 if (i > 2) /* don't do /dev/std... */
1702 xfree(files[i].fname);
1703 files[i].fname = NULL; /* watch out for ref thru this */
1714 for (i = 0; i < FOPEN_MAX; i++)
1716 if (ferror(files[i].fp))
1717 WARNING( "i/o error occurred on %s", files[i].fname );
1718 if (files[i].mode == '|' || files[i].mode == LE)
1719 stat = pclose(files[i].fp);
1721 stat = fclose(files[i].fp);
1723 WARNING( "i/o error occurred while closing %s", files[i].fname );
1727 void flush_all(void)
1731 for (i = 0; i < FOPEN_MAX; i++)
1733 fflush(files[i].fp);
1736 void backsub(char **pb_ptr, char **sptr_ptr);
1738 Cell *sub(Node **a, int nnn) /* substitute command */
1740 char *sptr, *pb, *q;
1741 Cell *x, *y, *result;
1744 int bufsz = recsize;
1746 if ((buf = (char *) malloc(bufsz)) == NULL)
1747 FATAL("out of memory in sub");
1748 x = execute(a[3]); /* target string */
1750 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1751 p = (void *) a[1]; /* regular expression */
1754 p = compre(getsval(y));
1757 y = execute(a[2]); /* replacement string */
1759 if (pmatch(p, t, t)) {
1761 adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1763 while (sptr < patbeg)
1766 while (*sptr != 0) {
1767 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1768 if (*sptr == '\\') {
1769 backsub(&pb, &sptr);
1770 } else if (*sptr == '&') {
1772 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1773 for (q = patbeg; q < patbeg+patlen; )
1779 if (pb > buf + bufsz)
1780 FATAL("sub result1 %.30s too big; can't happen", buf);
1781 sptr = patbeg + patlen;
1782 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1783 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1784 while ((*pb++ = *sptr++) != 0)
1787 if (pb > buf + bufsz)
1788 FATAL("sub result2 %.30s too big; can't happen", buf);
1789 setsval(x, buf); /* BUG: should be able to avoid copy */
1798 Cell *gsub(Node **a, int nnn) /* global substitute */
1801 char *rptr, *sptr, *t, *pb, *c;
1805 int bufsz = recsize;
1807 if ((buf = (char *)malloc(bufsz)) == NULL)
1808 FATAL("out of memory in gsub");
1809 mflag = 0; /* if mflag == 0, can replace empty string */
1811 x = execute(a[3]); /* target string */
1813 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1814 p = (void *) a[1]; /* regular expression */
1817 p = compre(getsval(y));
1820 y = execute(a[2]); /* replacement string */
1821 if (pmatch(p, t, c)) {
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 == '&') {
1836 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1837 for (q = patbeg; q < patbeg+patlen; )
1843 if (*c == 0) /* at end */
1845 adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1847 if (pb > buf + bufsz) /* BUG: not sure of this test */
1848 FATAL("gsub result0 %.30s too big; can't happen", buf);
1851 else { /* matched nonempty string */
1854 adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
1855 while (sptr < patbeg)
1858 while (*sptr != 0) {
1859 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1860 if (*sptr == '\\') {
1861 backsub(&pb, &sptr);
1862 } else if (*sptr == '&') {
1865 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1866 for (q = patbeg; q < patbeg+patlen; )
1871 c = patbeg + patlen;
1872 if ((c[-1] == 0) || (*c == 0))
1874 if (pb > buf + bufsz)
1875 FATAL("gsub result1 %.30s too big; can't happen", buf);
1878 } while (pmatch(p, t, c));
1880 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
1881 while ((*pb++ = *sptr++) != 0)
1883 done: if (pb > buf + bufsz)
1884 FATAL("gsub result2 %.30s too big; can't happen", buf);
1886 setsval(x, buf); /* BUG: should be able to avoid copy + free */
1897 void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */
1898 { /* sptr[0] == '\\' */
1899 char *pb = *pb_ptr, *sptr = *sptr_ptr;
1901 if (sptr[1] == '\\') {
1902 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
1906 } else if (sptr[2] == '&') { /* \\& -> \ + matched */
1909 } else { /* \\x -> \\x */
1913 } else if (sptr[1] == '&') { /* literal & */
1916 } else /* literal \ */