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;
910 case 'o': case 'x': case 'X':
911 flag = *(s-1) == 'l' ? 2 : 3;
920 WARNING("weird printf conversion %s", fmt);
925 FATAL("not enough args in printf(%s)", os);
931 adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
933 case 0: sprint(p, "%s", fmt); /* unknown, so dump it too */
938 adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
942 case 1: sprint(p, fmt, getfval(x)); break;
943 case 2: sprint(p, fmt, (long) getfval(x)); break;
944 case 3: sprint(p, fmt, (int) getfval(x)); break;
950 if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
951 FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
957 *p++ = (uchar)getfval(x);
964 if((*p = getsval(x)[0]) != '\0')
977 for ( ; a; a = a->nnext) /* evaluate any remaining args */
984 Cell *awksprintf(Node **a, int) /* sprint(a[0]) */
991 if ((buf = (char *) malloc(bufsz)) == nil)
992 FATAL("out of memory in awksprint");
995 if (format(&buf, &bufsz, getsval(x), y) == -1)
996 FATAL("sprint string %.30s... too long. can't happen.", buf);
1005 Cell *awkprintf(Node **a, int) /* printf */
1006 { /* a[0] is list of args, starting with format string */
1007 /* a[1] is redirection operator, a[2] is redirection file */
1013 int bufsz=3*recsize;
1015 if ((buf = (char *) malloc(bufsz)) == nil)
1016 FATAL("out of memory in awkprintf");
1019 if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
1020 FATAL("printf string %.30s... too long. can't happen.", buf);
1024 /* fputs(buf, stdout); */
1025 if (Bwrite(&stdout, buf, len) < 0)
1026 FATAL("write error on stdout");
1029 fp = redirect(ptoi(a[1]), a[2]);
1030 /* fputs(buf, fp); */
1031 if(Bwrite(fp, buf, len) < 0)
1032 FATAL("write error on %s", filename(fp));
1039 Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
1068 FATAL("division by zero");
1073 FATAL("division by zero in mod");
1081 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1082 i = ipow(i, (int) j);
1084 i = errcheck(pow(i, j), "pow");
1086 default: /* can't happen */
1087 FATAL("illegal arithmetic operator %d", n);
1093 double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
1106 Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
1114 k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1115 if (n == PREINCR || n == PREDECR) {
1127 Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
1128 { /* this is subtle; don't muck with it. */
1135 if (n == ASSIGN) { /* ordinary assignment */
1136 if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
1137 goto Free; /* leave alone unless it's a field */
1138 if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1139 setsval(x, getsval(y));
1140 x->fval = getfval(y);
1144 setsval(x, getsval(y));
1146 setfval(x, getfval(y));
1148 funnyvar(y, "read value of");
1168 FATAL("division by zero in /=");
1173 FATAL("division by zero in %%=");
1178 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1179 xf = ipow(xf, (int) yf);
1181 xf = errcheck(pow(xf, yf), "pow");
1184 FATAL("illegal assignment operator %d", n);
1193 Cell *cat(Node **a, int) /* a[0] cat a[1] */
1203 n1 = strlen(x->sval);
1204 n2 = strlen(y->sval);
1205 s = (char *) malloc(n1 + n2 + 1);
1207 FATAL("out of space concatenating %.15s... and %.15s...",
1210 strcpy(s+n1, y->sval);
1221 Cell *pastat(Node **a, int) /* a[0] { a[1] } */
1238 Cell *dopa2(Node **a, int) /* a[0], a[1] { a[2] } */
1244 if (pairstack[pair] == 0) {
1247 pairstack[pair] = 1;
1251 if (pairstack[pair] == 1) {
1254 pairstack[pair] = 0;
1263 Cell *split(Node **a, int) /* split(a[0], a[1], a[2]); a[3] is type */
1265 Cell *x = 0, *y, *ap;
1266 char *s, *t, *fs = 0;
1268 int n, nb, sep, arg3type;
1270 y = execute(a[0]); /* source string */
1272 arg3type = ptoi(a[3]);
1273 if (a[2] == 0) /* fs string */
1275 else if (arg3type == STRING) { /* split(str,arr,"string") */
1278 } else if (arg3type == REGEXPR)
1279 fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
1281 FATAL("illegal type of split");
1283 ap = execute(a[1]); /* array name */
1285 y->tval |= DONTFREE; /* split(a[x], a); */
1288 dprint( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
1291 ap->sval = (char *) makesymtab(NSYMTAB);
1294 if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) { /* reg expr */
1296 if (arg3type == REGEXPR) { /* it's ready already */
1302 if (nematch(p,s,t)) {
1305 sprint(num, "%d", n);
1309 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1311 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1313 t = patbeg + patlen;
1314 if (t[-1] == 0 || *t == 0) {
1316 sprint(num, "%d", n);
1317 setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1320 } while (nematch(p,s,t));
1323 sprint(num, "%d", n);
1325 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1327 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1331 } else if (sep == ' ') {
1333 while (*s == ' ' || *s == '\t' || *s == '\n')
1341 while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1344 sprint(num, "%d", n);
1346 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1348 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1353 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
1354 for (n = 0; *s != 0; s += nb) {
1359 snprint(num, sizeof num, "%d", n);
1360 nb = chartorune(&r, s);
1361 memmove(buf, s, nb);
1363 if (isdigit(buf[0]))
1364 setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1366 setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1368 } else if (*s != 0) {
1372 while (*s != sep && *s != '\n' && *s != '\0')
1376 sprint(num, "%d", n);
1378 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1380 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1390 if (a[2] != 0 && arg3type == STRING)
1399 Cell *condexpr(Node **a, int) /* a[0] ? a[1] : a[2] */
1416 Cell *ifstat(Node **a, int) /* if (a[0]) a[1]; else a[2] */
1425 } else if (a[2] != 0) {
1433 Cell *whilestat(Node **a, int) /* while (a[0]) a[1] */
1448 if (isnext(x) || isexit(x) || isret(x))
1455 Cell *dostat(Node **a, int) /* do a[0]; while(a[1]) */
1463 if (isnext(x) || isnextfile(x) || isexit(x) || isret(x))
1475 Cell *forstat(Node **a, int) /* for (a[0]; a[1]; a[2]) a[3] */
1491 if (isbreak(x)) /* turn off break */
1493 if (isnext(x) || isexit(x) || isret(x))
1503 Cell *instat(Node **a, int) /* for (a[0] in a[1]) a[2] */
1505 Cell *x, *vp, *arrayp, *cp, *ncp;
1510 arrayp = execute(a[1]);
1511 if (!isarr(arrayp)) {
1514 tp = (Array *) arrayp->sval;
1517 for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1518 for (cp = tp->tab[i]; cp != nil; cp = ncp) {
1519 setsval(vp, cp->nval);
1527 if (isnext(x) || isexit(x) || isret(x)) {
1539 Cell *bltin(Node **a, int) /* builtin functions. a[0] is type, a[1] is arg list */
1549 void flush_all(void);
1553 nextarg = a[1]->nnext;
1557 u = ((Array *) x->sval)->nelemt; /* GROT. should be function*/
1560 u = (Awkfloat) utfnlen(p, strlen(p));
1564 u = errcheck(log(getfval(x)), "log"); break;
1566 modf(getfval(x), &u); break;
1568 u = errcheck(exp(getfval(x)), "exp"); break;
1570 u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1572 u = sin(getfval(x)); break;
1574 u = cos(getfval(x)); break;
1577 WARNING("atan2 requires two arguments; returning 1.0");
1580 y = execute(a[1]->nnext);
1581 u = atan2(getfval(x), getfval(y));
1584 nextarg = nextarg->nnext;
1588 Bflush(&stdout); /* in case something is buffered already */
1589 u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */
1592 /* in principle, rand() returns something in 0..RAND_MAX */
1593 u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1596 if (isrec(x)) /* no argument provided */
1600 srand((unsigned int) u);
1604 buf = tostring(getsval(x));
1605 if (t == FTOUPPER) {
1606 for (p = buf; *p; p++)
1610 for (p = buf; *p; p++)
1621 if (isrec(x) || strlen(getsval(x)) == 0) {
1622 flush_all(); /* fflush() or fflush("") -> all */
1624 } else if ((fp = openfile(FFLUSH, getsval(x))) == nil)
1630 wc = (int)getfval(x);
1631 mbc[runetochar(mbc, &wc)] = 0;
1637 default: /* can't happen */
1638 FATAL("illegal function type %d", t);
1646 WARNING("warning: function has too many arguments");
1647 for ( ; nextarg; nextarg = nextarg->nnext)
1653 Cell *printstat(Node **a, int) /* print a[0] */
1660 if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
1663 fp = redirect(ptoi(a[1]), a[2]);
1664 for (x = a[0]; x != nil; x = x->nnext) {
1666 Bwrite(fp, getsval(y), strlen(getsval(y)));
1669 if (x->nnext == nil)
1670 r = Bprint(fp, "%s", *ORS);
1672 r = Bprint(fp, "%s", *OFS);
1674 FATAL("write error on %s", filename(fp));
1677 FATAL("write error on %s", filename(fp));
1681 Cell *nullproc(Node **, int)
1687 Biobuf *redirect(int a, Node *b) /* set up all i/o redirections */
1695 fp = openfile(a, fname);
1697 FATAL("can't open file %s", fname);
1706 int mode; /* '|', 'a', 'w' => LE/LT, GT */
1707 } files[FOPEN_MAX] ={
1708 { nil, "/dev/stdin", LT }, /* watch out: don't free this! */
1709 { nil, "/dev/stdout", GT },
1710 { nil, "/dev/stderr", GT }
1713 void stdinit(void) /* in case stdin, etc., are not constants */
1715 files[0].fp = &stdin;
1716 files[1].fp = &stdout;
1717 files[2].fp = &stderr;
1720 Biobuf *openfile(int a, char *us)
1727 FATAL("null file name in print or getline");
1728 for (i=0; i < FOPEN_MAX; i++)
1729 if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1730 if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1735 if (a == FFLUSH) /* didn't find it, so don't create it! */
1738 for (i=0; i < FOPEN_MAX; i++)
1739 if (files[i].fp == 0)
1742 FATAL("%s makes too many open files", s);
1743 Bflush(&stdout); /* force a semblance of order */
1746 fp = Bopen(s, OWRITE);
1747 } else if (a == APPEND) {
1748 fp = Bopen(s, OWRITE);
1750 m = GT; /* so can mix > and >> */
1751 } else if (a == '|') { /* output pipe */
1752 fp = popen(s, OWRITE);
1753 } else if (a == LE) { /* input pipe */
1754 fp = popen(s, OREAD);
1755 } else if (a == LT) { /* getline <file */
1756 fp = strcmp(s, "-") == 0 ? &stdin : Bopen(s, OREAD); /* "-" is stdin */
1757 } else /* can't happen */
1758 FATAL("illegal redirection %d", a);
1760 files[i].fname = tostring(s);
1767 char *filename(Biobuf *fp)
1771 for (i = 0; i < FOPEN_MAX; i++)
1772 if (fp == files[i].fp)
1773 return files[i].fname;
1777 Cell *closefile(Node **a, int)
1784 for (i = 0; i < FOPEN_MAX; i++)
1785 if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1786 if (files[i].mode == '|' || files[i].mode == LE)
1787 stat = pclose(files[i].fp);
1789 stat = Bterm(files[i].fp);
1791 WARNING( "i/o error occurred closing %s", files[i].fname );
1792 if (i > 2) /* don't do /dev/std... */
1793 xfree(files[i].fname);
1794 files[i].fname = nil; /* watch out for ref thru this */
1806 for (i = 0; i < FOPEN_MAX; i++)
1808 if (files[i].mode == '|' || files[i].mode == LE)
1809 stat = pclose(files[i].fp);
1811 stat = Bterm(files[i].fp);
1813 WARNING( "i/o error occurred while closing %s", files[i].fname );
1817 void flush_all(void)
1821 for (i = 0; i < FOPEN_MAX; i++)
1823 Bflush(files[i].fp);
1826 void backsub(char **pb_ptr, char **sptr_ptr);
1828 Cell *sub(Node **a, int) /* substitute command */
1830 char *sptr, *pb, *q;
1831 Cell *x, *y, *result;
1834 int bufsz = recsize;
1836 if ((buf = (char *) malloc(bufsz)) == nil)
1837 FATAL("out of memory in sub");
1838 x = execute(a[3]); /* target string */
1840 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1841 p = (void *) a[1]; /* regular expression */
1844 p = compre(getsval(y));
1848 y = execute(a[2]); /* replacement string */
1850 if (pmatch(p, t, t)) {
1852 adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1854 while (sptr < patbeg)
1857 while (*sptr != 0) {
1858 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1859 if (*sptr == '\\') {
1860 backsub(&pb, &sptr);
1861 } else if (*sptr == '&') {
1863 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1864 for (q = patbeg; q < patbeg+patlen; )
1870 if (pb > buf + bufsz)
1871 FATAL("sub result1 %.30s too big; can't happen", buf);
1872 sptr = patbeg + patlen;
1873 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1874 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1875 while ((*pb++ = *sptr++) != 0)
1878 if (pb > buf + bufsz)
1879 FATAL("sub result2 %.30s too big; can't happen", buf);
1880 setsval(x, buf); /* BUG: should be able to avoid copy */
1891 Cell *gsub(Node **a, int) /* global substitute */
1894 char *rptr, *sptr, *t, *pb, *c, *s;
1898 int bufsz = recsize;
1900 if ((buf = (char *)malloc(bufsz)) == nil)
1901 FATAL("out of memory in gsub");
1902 mflag = 0; /* if mflag == 0, can replace empty string */
1904 x = execute(a[3]); /* target string */
1906 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1907 p = (void *) a[1]; /* regular expression */
1915 y = execute(a[2]); /* replacement string */
1916 if (pmatch(p, t, c)) {
1920 if (patlen == 0 && *patbeg != 0) { /* matched empty string */
1921 if (mflag == 0) { /* can replace empty */
1924 while (*sptr != 0) {
1925 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1926 if (*sptr == '\\') {
1927 backsub(&pb, &sptr);
1928 } else if (*sptr == '&') {
1931 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1932 for (q = patbeg; q < patbeg+patlen; )
1938 if (*c == 0) /* at end */
1940 adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1942 if (pb > buf + bufsz) /* BUG: not sure of this test */
1943 FATAL("gsub result0 %.30s too big; can't happen", buf);
1946 else { /* matched nonempty string */
1949 adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
1950 while (sptr < patbeg)
1953 while (*sptr != 0) {
1954 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1955 if (*sptr == '\\') {
1956 backsub(&pb, &sptr);
1957 } else if (*sptr == '&') {
1960 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1961 for (q = patbeg; q < patbeg+patlen; )
1966 c = patbeg + patlen;
1967 if ((c[-1] == 0) || (*c == 0))
1969 if (pb > buf + bufsz)
1970 FATAL("gsub result1 %.30s too big; can't happen", buf);
1973 } while (pmatch(p, t, c));
1975 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
1976 while ((*pb++ = *sptr++) != 0)
1978 done: if (pb > buf + bufsz)
1979 FATAL("gsub result2 %.30s too big; can't happen", buf);
1981 setsval(x, buf); /* BUG: should be able to avoid copy + free */
1994 void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */
1995 { /* sptr[0] == '\\' */
1996 char *pb = *pb_ptr, *sptr = *sptr_ptr;
1998 if (sptr[1] == '\\') {
1999 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
2003 } else if (sptr[2] == '&') { /* \\& -> \ + matched */
2006 } else { /* \\x -> \\x */
2010 } else if (sptr[1] == '&') { /* literal & */
2013 } else /* literal \ */