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 ****************************************************************/
33 #define RAND_MAX 32767 /* all that ansi guarantees */
37 extern int pairstack[];
39 Node *winner = nil; /* root of parse tree */
40 Cell *tmps; /* free temporary cells for execution */
42 static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
43 Cell *True = &truecell;
44 static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
45 Cell *False = &falsecell;
46 static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
47 Cell *jbreak = &breakcell;
48 static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM };
49 Cell *jcont = &contcell;
50 static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
51 Cell *jnext = &nextcell;
52 static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
53 Cell *jnextfile = &nextfilecell;
54 static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
55 Cell *jexit = &exitcell;
56 static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM };
57 Cell *jret = &retcell;
58 static Cell tempcell ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
60 Node *curnode = nil; /* the node being executed, for debugging */
65 char status[512], *statfld[5];
69 oty = getenv("cputype");
73 return 1; /* a command interpreter is available */
75 snprint(cmd, sizeof cmd, "/%s/bin/ape/sh", oty);
77 execl(cmd, "sh", "-c", s, nil);
84 w = await(status, sizeof(status) - 1);
87 tokenize(status, statfld, nelem(statfld));
88 if(strtol(statfld[0], nil, 0) == pid)
92 if(*statfld[4] != '\0')
97 /* buffer memory management */
98 int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
100 /* pbuf: address of pointer to buffer being managed
101 * psiz: address of buffer size variable
102 * minlen: minimum length of buffer needed
103 * quantum: buffer size quantum
104 * pbptr: address of movable pointer into buffer, or 0 if none
105 * whatrtn: name of the calling routine if failure should cause fatal error
107 * return 0 for realloc failure, !=0 for success
110 if (minlen > *psiz) {
112 int rminlen = quantum ? minlen % quantum : 0;
113 int boff = pbptr ? *pbptr - *pbuf : 0;
114 /* round up to next multiple of quantum */
116 minlen += quantum - rminlen;
117 tbuf = (char *) realloc(*pbuf, minlen);
120 FATAL("out of memory in %s", whatrtn);
126 *pbptr = tbuf + boff;
131 void run(Node *a) /* execution of parse tree starts here */
133 extern void stdinit(void);
140 Cell *execute(Node *u) /* execute a node of the parse tree */
143 Cell *(*proc)(Node **, int);
149 for (a = u; ; a = a->nnext) {
152 x = (Cell *) (a->narg[0]);
153 if (isfld(x) && !donefld)
155 else if (isrec(x) && !donerec)
160 if (notlegal(nobj)) /* probably a Cell* but too risky to print */
161 FATAL("illegal statement");
162 proc = proctab[nobj-FIRSTTOKEN];
163 x = (*proc)(a->narg, nobj);
164 if (isfld(x) && !donefld)
166 else if (isrec(x) && !donerec)
180 Cell *program(Node **a, int) /* execute an awk program */
181 { /* a[0] = BEGIN, a[1] = body, a[2] = END */
184 if (setjmp(env) != 0)
186 if (a[0]) { /* BEGIN */
191 FATAL("illegal break, continue, next or nextfile from BEGIN");
196 while (getrec(&record, &recsize, 1) > 0) {
204 if (setjmp(env) != 0) /* handles exit within END */
206 if (a[2]) { /* END */
208 if (isbreak(x) || isnext(x) || iscont(x))
209 FATAL("illegal break, continue, next or nextfile from END");
217 struct Frame { /* stack frame for awk function calls */
218 int nargs; /* number of arguments in this call */
219 Cell *fcncell; /* pointer to Cell for function */
220 Cell **args; /* pointer to array of arguments after execute */
221 Cell *retval; /* return value */
224 #define NARGS 50 /* max args in a call */
226 struct Frame *frame = nil; /* base of stack frames; dynamically allocated */
227 int nframe = 0; /* number of frames allocated */
228 struct Frame *fp = nil; /* frame pointer. bottom level unused */
230 Cell *call(Node **a, int) /* function call. very kludgy and fragile */
232 static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
235 Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */
239 fcn = execute(a[0]); /* the function itself */
242 FATAL("calling undefined function %s", s);
244 fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
246 FATAL("out of space for stack frames calling %s", s);
248 for (ncall = 0, x = a[1]; x != nil; x = x->nnext) /* args in call */
250 ndef = (int) fcn->fval; /* args in defn */
251 dprint( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
253 WARNING("function %s called with %d args, uses only %d",
255 if (ncall + ndef > NARGS)
256 FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
257 for (i = 0, x = a[1]; x != nil; i++, x = x->nnext) { /* get call args */
258 dprint( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
261 dprint( ("args[%d]: %s %f <%s>, t=%o\n",
262 i, y->nval, y->fval, isarr(y) ? "(array)" : y->sval, y->tval) );
264 FATAL("can't use function %s as argument in %s", y->nval, s);
266 args[i] = y; /* arrays by ref */
268 args[i] = copycell(y);
272 for ( ; i < ndef; i++) { /* add null args for ones not provided */
274 *args[i] = newcopycell;
276 fp++; /* now ok to up frame */
277 if (fp >= frame + nframe) {
278 int dfp = fp - frame; /* old index */
279 frame = (struct Frame *)
280 realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
282 FATAL("out of space for stack frames in %s", s);
287 fp->nargs = ndef; /* number defined with (excess are locals) */
288 fp->retval = gettemp();
290 dprint( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
291 y = execute((Node *)(fcn->sval)); /* execute body */
292 dprint( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
294 for (i = 0; i < ndef; i++) {
295 Cell *t = fp->args[i];
297 if (t->csub == CCOPY) {
304 oargs[i]->tval = t->tval;
305 oargs[i]->tval &= ~(STR|NUM|DONTFREE);
306 oargs[i]->sval = t->sval;
311 } else if (t != y) { /* kludge to prevent freeing twice */
319 if (isexit(y) || isnext(y) || isnextfile(y))
322 tfree(y); /* this can free twice! */
323 z = fp->retval; /* return value */
324 dprint( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
329 Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
334 y->csub = CCOPY; /* prevents freeing until call is over */
335 y->nval = x->nval; /* BUG? */
336 y->sval = x->sval ? tostring(x->sval) : nil;
338 y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */
339 /* is DONTFREE right? */
343 Cell *arg(Node **a, int n) /* nth argument of a function */
346 n = ptoi(a[0]); /* argument number, counting from 0 */
347 dprint( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
349 FATAL("argument #%d of function %s was not supplied",
350 n+1, fp->fcncell->nval);
354 Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */
362 errorflag = (int) getfval(y);
370 if ((y->tval & (STR|NUM)) == (STR|NUM)) {
371 setsval(fp->retval, getsval(y));
372 fp->retval->fval = getfval(y);
373 fp->retval->tval |= NUM;
375 else if (y->tval & STR)
376 setsval(fp->retval, getsval(y));
377 else if (y->tval & NUM)
378 setfval(fp->retval, getfval(y));
379 else /* can't happen */
380 FATAL("bad type variable %d", y->tval);
394 default: /* can't happen */
395 FATAL("illegal jump type %d", n);
397 return 0; /* not reached */
400 Cell *getline(Node **a, int n) /* get next line from specific input */
401 { /* a[0] is variable, a[1] is operator, a[2] is filename */
403 extern Cell **fldtab;
406 int bufsize = recsize;
409 if ((buf = (char *) malloc(bufsize)) == nil)
410 FATAL("out of memory in getline");
412 Bflush(&stdout); /* in case someone is waiting for a prompt */
414 if (a[1] != nil) { /* getline < file */
415 x = execute(a[2]); /* filename */
417 if (mode == '|') /* input pipe */
418 mode = LE; /* arbitrary flag */
419 fp = openfile(mode, getsval(x));
425 n = readrec(&buf, &bufsize, fp);
428 } else if (a[0] != nil) { /* getline var <file */
433 } else { /* getline <file */
434 setsval(fldtab[0], buf);
435 if (is_number(fldtab[0]->sval)) {
436 fldtab[0]->fval = atof(fldtab[0]->sval);
437 fldtab[0]->tval |= NUM;
440 } else { /* bare getline; use current input */
441 if (a[0] == nil) /* getline */
442 n = getrec(&record, &recsize, 1);
443 else { /* getline var */
444 n = getrec(&buf, &bufsize, 0);
451 setfval(r, (Awkfloat) n);
456 Cell *getnf(Node **a, int) /* get NF */
460 return (Cell *) a[0];
463 Cell *array(Node **a, int) /* a[0] is symtab, a[1] is list of subscripts */
470 int nsub = strlen(*SUBSEP);
472 if ((buf = (char *) malloc(bufsz)) == nil)
473 FATAL("out of memory in array");
475 x = execute(a[0]); /* Cell* for symbol table */
477 for (np = a[1]; np; np = np->nnext) {
478 y = execute(np); /* subscript */
480 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
481 FATAL("out of memory for %s[%s...]", x->nval, buf);
484 strcat(buf, *SUBSEP);
489 dprint( ("making %s into an array\n", x->nval) );
492 x->tval &= ~(STR|NUM|DONTFREE);
494 x->sval = (char *) makesymtab(NSYMTAB);
496 z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
505 Cell *awkdelete(Node **a, int) /* a[0] is symtab, a[1] is list of subscripts */
510 int nsub = strlen(*SUBSEP);
512 x = execute(a[0]); /* Cell* for symbol table */
515 if (a[1] == 0) { /* delete the elements, not the table */
519 x->sval = (char *) makesymtab(NSYMTAB);
523 if ((buf = (char *) malloc(bufsz)) == nil)
524 FATAL("out of memory in adelete");
526 for (np = a[1]; np; np = np->nnext) {
527 y = execute(np); /* subscript */
529 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
530 FATAL("out of memory deleting %s[%s...]", x->nval, buf);
533 strcat(buf, *SUBSEP);
545 Cell *intest(Node **a, int) /* a[0] is index (list), a[1] is symtab */
552 int nsub = strlen(*SUBSEP);
554 ap = execute(a[1]); /* array name */
556 dprint( ("making %s into an array\n", ap->nval) );
559 ap->tval &= ~(STR|NUM|DONTFREE);
561 ap->sval = (char *) makesymtab(NSYMTAB);
563 if ((buf = (char *) malloc(bufsz)) == nil) {
564 FATAL("out of memory in intest");
567 for (p = a[0]; p; p = p->nnext) {
568 x = execute(p); /* expr */
570 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
571 FATAL("out of memory deleting %s[%s...]", x->nval, buf);
576 strcat(buf, *SUBSEP);
578 k = lookup(buf, (Array *) ap->sval);
589 Cell *matchop(Node **a, int n) /* ~ and match() */
596 x = execute(a[1]); /* a[1] = target text */
598 if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */
601 y = execute(a[2]); /* a[2] = regular expr */
614 int start = utfnlen(s, patbeg-s)+1;
617 setfval(rstartloc, (Awkfloat) start);
618 setfval(rlengthloc, (Awkfloat) utfnlen(patbeg, patlen));
623 } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
630 Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
649 if ( !i ) return(False);
657 if (i) return(False);
659 default: /* can't happen */
660 FATAL("unknown boolean operator %d", n);
662 return 0; /*NOTREACHED*/
665 Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
673 if (x->tval&NUM && y->tval&NUM) {
674 j = x->fval - y->fval;
675 i = j<0? -1: (j>0? 1: 0);
677 i = strcmp(getsval(x), getsval(y));
684 case LT: if (i<0) return(True);
686 case LE: if (i<=0) return(True);
688 case NE: if (i!=0) return(True);
690 case EQ: if (i == 0) return(True);
692 case GE: if (i>=0) return(True);
694 case GT: if (i>0) return(True);
696 default: /* can't happen */
697 FATAL("unknown relational operator %d", n);
699 return 0; /*NOTREACHED*/
702 void tfree(Cell *a) /* free a tempcell */
705 dprint( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) );
709 FATAL("tempcell list is curdled");
714 Cell *gettemp(void) /* get a tempcell */
719 tmps = (Cell *) calloc(100, sizeof(Cell));
721 FATAL("out of space for temporaries");
722 for(i = 1; i < 100; i++)
723 tmps[i-1].cnext = &tmps[i];
732 Cell *indirect(Node **a, int) /* $( a[0] ) */
739 m = (int) getfval(x);
740 if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */
741 FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
742 /* BUG: can x->nval ever be null??? */
746 x->ctype = OCELL; /* BUG? why are these needed? */
751 Cell *substr(Node **a, int) /* substr(a[0], a[1], a[2]) */
764 k = utfnlen(s, strlen(s)) + 1;
778 m = (int) getfval(y);
786 n = (int) getfval(z);
795 dprint( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
798 s += chartorune(&r, s);
799 for (p = s; *p && n--; p += chartorune(&r, p))
801 temp = *p; /* with thanks to John Linderman */
810 Cell *sindex(Node **a, int) /* index(a[0], a[1]) */
813 char *s1, *s2, *p1, *p2, *q;
822 for (p1 = s1; *p1 != '\0'; p1++) {
823 for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
826 v = (Awkfloat) utfnlen(s1, p1-s1) + 1; /* origin 1 */
838 #define MAXNUMSIZE 50
840 int format(char **pbuf, int *pbufsize, char *s, Node *a) /* printf-like conversions */
846 int fmtwd; /* format width */
849 int bufsize = *pbufsize;
853 if ((fmt = (char *) malloc(fmtsz)) == nil)
854 FATAL("out of memory in format()");
856 adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format");
866 /* have to be real careful in case this is a huge number, eg, %100000d */
870 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
871 for (t = fmt; (*t++ = *s) != '\0'; s++) {
872 if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0))
873 FATAL("format item %.30s... ran format() out of memory", os);
874 if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
875 break; /* the ansi panoply */
879 sprint(t-1, "%d", fmtwd=(int) getfval(x));
882 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
883 t = fmt + strlen(fmt);
891 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
894 case 'f': case 'e': case 'g': case 'E': case 'G':
899 if(*(s-1) == 'l') break;
905 flag = *(s-1) == 'l' ? 2 : 3;
909 case 'o': case 'x': case 'X':
910 flag = *(s-1) == 'l' ? 2 : 3;
919 WARNING("weird printf conversion %s", fmt);
924 FATAL("not enough args in printf(%s)", os);
930 adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
932 case 0: sprint(p, "%s", fmt); /* unknown, so dump it too */
937 adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
941 case 1: sprint(p, fmt, getfval(x)); break;
942 case 2: sprint(p, fmt, (long) getfval(x)); break;
943 case 3: sprint(p, fmt, (int) getfval(x)); break;
949 if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
950 FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
956 *p++ = (uchar)getfval(x);
963 sprint(p, fmt, getsval(x)[0]);
973 for ( ; a; a = a->nnext) /* evaluate any remaining args */
980 Cell *awksprintf(Node **a, int) /* sprint(a[0]) */
987 if ((buf = (char *) malloc(bufsz)) == nil)
988 FATAL("out of memory in awksprint");
991 if (format(&buf, &bufsz, getsval(x), y) == -1)
992 FATAL("sprint string %.30s... too long. can't happen.", buf);
1001 Cell *awkprintf(Node **a, int) /* printf */
1002 { /* a[0] is list of args, starting with format string */
1003 /* a[1] is redirection operator, a[2] is redirection file */
1009 int bufsz=3*recsize;
1011 if ((buf = (char *) malloc(bufsz)) == nil)
1012 FATAL("out of memory in awkprintf");
1015 if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
1016 FATAL("printf string %.30s... too long. can't happen.", buf);
1020 /* fputs(buf, stdout); */
1021 if (Bwrite(&stdout, buf, len) < 0)
1022 FATAL("write error on stdout");
1025 fp = redirect(ptoi(a[1]), a[2]);
1026 /* fputs(buf, fp); */
1027 if(Bwrite(fp, buf, len) < 0)
1028 FATAL("write error on %s", filename(fp));
1035 Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
1064 FATAL("division by zero");
1069 FATAL("division by zero in mod");
1077 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1078 i = ipow(i, (int) j);
1080 i = errcheck(pow(i, j), "pow");
1082 default: /* can't happen */
1083 FATAL("illegal arithmetic operator %d", n);
1089 double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
1102 Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
1110 k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1111 if (n == PREINCR || n == PREDECR) {
1123 Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
1124 { /* this is subtle; don't muck with it. */
1131 if (n == ASSIGN) { /* ordinary assignment */
1132 if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
1133 goto Free; /* leave alone unless it's a field */
1134 if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1135 setsval(x, getsval(y));
1136 x->fval = getfval(y);
1140 setsval(x, getsval(y));
1142 setfval(x, getfval(y));
1144 funnyvar(y, "read value of");
1164 FATAL("division by zero in /=");
1169 FATAL("division by zero in %%=");
1174 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1175 xf = ipow(xf, (int) yf);
1177 xf = errcheck(pow(xf, yf), "pow");
1180 FATAL("illegal assignment operator %d", n);
1189 Cell *cat(Node **a, int) /* a[0] cat a[1] */
1199 n1 = strlen(x->sval);
1200 n2 = strlen(y->sval);
1201 s = (char *) malloc(n1 + n2 + 1);
1203 FATAL("out of space concatenating %.15s... and %.15s...",
1206 strcpy(s+n1, y->sval);
1217 Cell *pastat(Node **a, int) /* a[0] { a[1] } */
1234 Cell *dopa2(Node **a, int) /* a[0], a[1] { a[2] } */
1240 if (pairstack[pair] == 0) {
1243 pairstack[pair] = 1;
1247 if (pairstack[pair] == 1) {
1250 pairstack[pair] = 0;
1259 Cell *split(Node **a, int) /* split(a[0], a[1], a[2]); a[3] is type */
1261 Cell *x = 0, *y, *ap;
1262 char *s, *t, *fs = 0;
1264 int n, nb, sep, arg3type;
1266 y = execute(a[0]); /* source string */
1268 arg3type = ptoi(a[3]);
1269 if (a[2] == 0) /* fs string */
1271 else if (arg3type == STRING) { /* split(str,arr,"string") */
1274 } else if (arg3type == REGEXPR)
1275 fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
1277 FATAL("illegal type of split");
1279 ap = execute(a[1]); /* array name */
1281 y->tval |= DONTFREE; /* split(a[x], a); */
1284 dprint( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
1287 ap->sval = (char *) makesymtab(NSYMTAB);
1290 if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) { /* reg expr */
1292 if (arg3type == REGEXPR) { /* it's ready already */
1298 if (nematch(p,s,t)) {
1301 sprint(num, "%d", n);
1305 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1307 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1309 t = patbeg + patlen;
1310 if (t[-1] == 0 || *t == 0) {
1312 sprint(num, "%d", n);
1313 setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1316 } while (nematch(p,s,t));
1319 sprint(num, "%d", n);
1321 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1323 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1327 } else if (sep == ' ') {
1329 while (*s == ' ' || *s == '\t' || *s == '\n')
1337 while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1340 sprint(num, "%d", n);
1342 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1344 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1349 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
1350 for (n = 0; *s != 0; s += nb) {
1355 snprint(num, sizeof num, "%d", n);
1356 nb = chartorune(&r, s);
1357 memmove(buf, s, nb);
1359 if (isdigit(buf[0]))
1360 setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1362 setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1364 } else if (*s != 0) {
1368 while (*s != sep && *s != '\n' && *s != '\0')
1372 sprint(num, "%d", n);
1374 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1376 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1386 if (a[2] != 0 && arg3type == STRING)
1395 Cell *condexpr(Node **a, int) /* a[0] ? a[1] : a[2] */
1412 Cell *ifstat(Node **a, int) /* if (a[0]) a[1]; else a[2] */
1421 } else if (a[2] != 0) {
1429 Cell *whilestat(Node **a, int) /* while (a[0]) a[1] */
1444 if (isnext(x) || isexit(x) || isret(x))
1451 Cell *dostat(Node **a, int) /* do a[0]; while(a[1]) */
1459 if (isnext(x) || isnextfile(x) || isexit(x) || isret(x))
1471 Cell *forstat(Node **a, int) /* for (a[0]; a[1]; a[2]) a[3] */
1487 if (isbreak(x)) /* turn off break */
1489 if (isnext(x) || isexit(x) || isret(x))
1499 Cell *instat(Node **a, int) /* for (a[0] in a[1]) a[2] */
1501 Cell *x, *vp, *arrayp, *cp, *ncp;
1506 arrayp = execute(a[1]);
1507 if (!isarr(arrayp)) {
1510 tp = (Array *) arrayp->sval;
1513 for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1514 for (cp = tp->tab[i]; cp != nil; cp = ncp) {
1515 setsval(vp, cp->nval);
1523 if (isnext(x) || isexit(x) || isret(x)) {
1535 Cell *bltin(Node **a, int) /* builtin functions. a[0] is type, a[1] is arg list */
1545 void flush_all(void);
1549 nextarg = a[1]->nnext;
1553 u = ((Array *) x->sval)->nelemt; /* GROT. should be function*/
1556 u = (Awkfloat) utfnlen(p, strlen(p));
1560 u = errcheck(log(getfval(x)), "log"); break;
1562 modf(getfval(x), &u); break;
1564 u = errcheck(exp(getfval(x)), "exp"); break;
1566 u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1568 u = sin(getfval(x)); break;
1570 u = cos(getfval(x)); break;
1573 WARNING("atan2 requires two arguments; returning 1.0");
1576 y = execute(a[1]->nnext);
1577 u = atan2(getfval(x), getfval(y));
1580 nextarg = nextarg->nnext;
1584 Bflush(&stdout); /* in case something is buffered already */
1585 u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */
1588 /* in principle, rand() returns something in 0..RAND_MAX */
1589 u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1592 if (isrec(x)) /* no argument provided */
1596 srand((unsigned int) u);
1600 buf = tostring(getsval(x));
1601 if (t == FTOUPPER) {
1602 for (p = buf; *p; p++)
1606 for (p = buf; *p; p++)
1617 if (isrec(x) || strlen(getsval(x)) == 0) {
1618 flush_all(); /* fflush() or fflush("") -> all */
1620 } else if ((fp = openfile(FFLUSH, getsval(x))) == nil)
1626 wc = (int)getfval(x);
1627 mbc[runetochar(mbc, &wc)] = 0;
1633 default: /* can't happen */
1634 FATAL("illegal function type %d", t);
1642 WARNING("warning: function has too many arguments");
1643 for ( ; nextarg; nextarg = nextarg->nnext)
1649 Cell *printstat(Node **a, int) /* print a[0] */
1656 if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
1659 fp = redirect(ptoi(a[1]), a[2]);
1660 for (x = a[0]; x != nil; x = x->nnext) {
1662 Bwrite(fp, getsval(y), strlen(getsval(y)));
1665 if (x->nnext == nil)
1666 r = Bprint(fp, "%s", *ORS);
1668 r = Bprint(fp, "%s", *OFS);
1670 FATAL("write error on %s", filename(fp));
1673 FATAL("write error on %s", filename(fp));
1677 Cell *nullproc(Node **, int)
1683 Biobuf *redirect(int a, Node *b) /* set up all i/o redirections */
1691 fp = openfile(a, fname);
1693 FATAL("can't open file %s", fname);
1702 int mode; /* '|', 'a', 'w' => LE/LT, GT */
1703 } files[FOPEN_MAX] ={
1704 { nil, "/dev/stdin", LT }, /* watch out: don't free this! */
1705 { nil, "/dev/stdout", GT },
1706 { nil, "/dev/stderr", GT }
1709 void stdinit(void) /* in case stdin, etc., are not constants */
1711 files[0].fp = &stdin;
1712 files[1].fp = &stdout;
1713 files[2].fp = &stderr;
1716 Biobuf *openfile(int a, char *us)
1723 FATAL("null file name in print or getline");
1724 for (i=0; i < FOPEN_MAX; i++)
1725 if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1726 if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1731 if (a == FFLUSH) /* didn't find it, so don't create it! */
1734 for (i=0; i < FOPEN_MAX; i++)
1735 if (files[i].fp == 0)
1738 FATAL("%s makes too many open files", s);
1739 Bflush(&stdout); /* force a semblance of order */
1742 fp = Bopen(s, OWRITE);
1743 } else if (a == APPEND) {
1744 fp = Bopen(s, OWRITE);
1746 m = GT; /* so can mix > and >> */
1747 } else if (a == '|') { /* output pipe */
1748 fp = popen(s, OWRITE);
1749 } else if (a == LE) { /* input pipe */
1750 fp = popen(s, OREAD);
1751 } else if (a == LT) { /* getline <file */
1752 fp = strcmp(s, "-") == 0 ? &stdin : Bopen(s, OREAD); /* "-" is stdin */
1753 } else /* can't happen */
1754 FATAL("illegal redirection %d", a);
1756 files[i].fname = tostring(s);
1763 char *filename(Biobuf *fp)
1767 for (i = 0; i < FOPEN_MAX; i++)
1768 if (fp == files[i].fp)
1769 return files[i].fname;
1773 Cell *closefile(Node **a, int)
1780 for (i = 0; i < FOPEN_MAX; i++)
1781 if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1782 if (files[i].mode == '|' || files[i].mode == LE)
1783 stat = pclose(files[i].fp);
1785 stat = Bterm(files[i].fp);
1787 WARNING( "i/o error occurred closing %s", files[i].fname );
1788 if (i > 2) /* don't do /dev/std... */
1789 xfree(files[i].fname);
1790 files[i].fname = nil; /* watch out for ref thru this */
1802 for (i = 0; i < FOPEN_MAX; i++)
1804 if (files[i].mode == '|' || files[i].mode == LE)
1805 stat = pclose(files[i].fp);
1807 stat = Bterm(files[i].fp);
1809 WARNING( "i/o error occurred while closing %s", files[i].fname );
1813 void flush_all(void)
1817 for (i = 0; i < FOPEN_MAX; i++)
1819 Bflush(files[i].fp);
1822 void backsub(char **pb_ptr, char **sptr_ptr);
1824 Cell *sub(Node **a, int) /* substitute command */
1826 char *sptr, *pb, *q;
1827 Cell *x, *y, *result;
1830 int bufsz = recsize;
1832 if ((buf = (char *) malloc(bufsz)) == nil)
1833 FATAL("out of memory in sub");
1834 x = execute(a[3]); /* target string */
1836 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1837 p = (void *) a[1]; /* regular expression */
1840 p = compre(getsval(y));
1844 y = execute(a[2]); /* replacement string */
1846 if (pmatch(p, t, t)) {
1848 adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1850 while (sptr < patbeg)
1853 while (*sptr != 0) {
1854 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1855 if (*sptr == '\\') {
1856 backsub(&pb, &sptr);
1857 } else if (*sptr == '&') {
1859 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1860 for (q = patbeg; q < patbeg+patlen; )
1866 if (pb > buf + bufsz)
1867 FATAL("sub result1 %.30s too big; can't happen", buf);
1868 sptr = patbeg + patlen;
1869 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1870 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1871 while ((*pb++ = *sptr++) != 0)
1874 if (pb > buf + bufsz)
1875 FATAL("sub result2 %.30s too big; can't happen", buf);
1876 setsval(x, buf); /* BUG: should be able to avoid copy */
1887 Cell *gsub(Node **a, int) /* global substitute */
1890 char *rptr, *sptr, *t, *pb, *c, *s;
1894 int bufsz = recsize;
1896 if ((buf = (char *)malloc(bufsz)) == nil)
1897 FATAL("out of memory in gsub");
1898 mflag = 0; /* if mflag == 0, can replace empty string */
1900 x = execute(a[3]); /* target string */
1902 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1903 p = (void *) a[1]; /* regular expression */
1911 y = execute(a[2]); /* replacement string */
1912 if (pmatch(p, t, c)) {
1916 if (patlen == 0 && *patbeg != 0) { /* matched empty string */
1917 if (mflag == 0) { /* can replace empty */
1920 while (*sptr != 0) {
1921 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1922 if (*sptr == '\\') {
1923 backsub(&pb, &sptr);
1924 } else if (*sptr == '&') {
1927 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1928 for (q = patbeg; q < patbeg+patlen; )
1934 if (*c == 0) /* at end */
1936 adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1938 if (pb > buf + bufsz) /* BUG: not sure of this test */
1939 FATAL("gsub result0 %.30s too big; can't happen", buf);
1942 else { /* matched nonempty string */
1945 adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
1946 while (sptr < patbeg)
1949 while (*sptr != 0) {
1950 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1951 if (*sptr == '\\') {
1952 backsub(&pb, &sptr);
1953 } else if (*sptr == '&') {
1956 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1957 for (q = patbeg; q < patbeg+patlen; )
1962 c = patbeg + patlen;
1963 if ((c[-1] == 0) || (*c == 0))
1965 if (pb > buf + bufsz)
1966 FATAL("gsub result1 %.30s too big; can't happen", buf);
1969 } while (pmatch(p, t, c));
1971 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
1972 while ((*pb++ = *sptr++) != 0)
1974 done: if (pb > buf + bufsz)
1975 FATAL("gsub result2 %.30s too big; can't happen", buf);
1977 setsval(x, buf); /* BUG: should be able to avoid copy + free */
1990 void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */
1991 { /* sptr[0] == '\\' */
1992 char *pb = *pb_ptr, *sptr = *sptr_ptr;
1994 if (sptr[1] == '\\') {
1995 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
1999 } else if (sptr[2] == '&') { /* \\& -> \ + matched */
2002 } else { /* \\x -> \\x */
2006 } else if (sptr[1] == '&') { /* literal & */
2009 } else /* literal \ */