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 */
72 execl("/bin/rc", "rc", "-c", s, nil);
81 FATAL("Out of memory");
82 if(status->pid == pid)
87 if(status->msg[0] != '\0') {
95 /* buffer memory management */
96 int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
98 /* pbuf: address of pointer to buffer being managed
99 * psiz: address of buffer size variable
100 * minlen: minimum length of buffer needed
101 * quantum: buffer size quantum
102 * pbptr: address of movable pointer into buffer, or 0 if none
103 * whatrtn: name of the calling routine if failure should cause fatal error
105 * return 0 for realloc failure, !=0 for success
108 if (minlen > *psiz) {
110 int rminlen = quantum ? minlen % quantum : 0;
111 int boff = pbptr ? *pbptr - *pbuf : 0;
112 /* round up to next multiple of quantum */
114 minlen += quantum - rminlen;
115 tbuf = (char *) realloc(*pbuf, minlen);
118 FATAL("out of memory in %s", whatrtn);
124 *pbptr = tbuf + boff;
129 void run(Node *a) /* execution of parse tree starts here */
131 extern void stdinit(void);
138 Cell *execute(Node *u) /* execute a node of the parse tree */
141 Cell *(*proc)(Node **, int);
147 for (a = u; ; a = a->nnext) {
150 x = (Cell *) (a->narg[0]);
151 if (isfld(x) && !donefld)
153 else if (isrec(x) && !donerec)
158 if (notlegal(nobj)) /* probably a Cell* but too risky to print */
159 FATAL("illegal statement");
160 proc = proctab[nobj-FIRSTTOKEN];
161 x = (*proc)(a->narg, nobj);
162 if (isfld(x) && !donefld)
164 else if (isrec(x) && !donerec)
178 Cell *program(Node **a, int) /* execute an awk program */
179 { /* a[0] = BEGIN, a[1] = body, a[2] = END */
182 if (setjmp(env) != 0)
184 if (a[0]) { /* BEGIN */
189 FATAL("illegal break, continue, next or nextfile from BEGIN");
194 while (getrec(&record, &recsize, 1) > 0) {
202 if (setjmp(env) != 0) /* handles exit within END */
204 if (a[2]) { /* END */
206 if (isbreak(x) || isnext(x) || iscont(x))
207 FATAL("illegal break, continue, next or nextfile from END");
215 struct Frame { /* stack frame for awk function calls */
216 int nargs; /* number of arguments in this call */
217 Cell *fcncell; /* pointer to Cell for function */
218 Cell **args; /* pointer to array of arguments after execute */
219 Cell *retval; /* return value */
222 #define NARGS 50 /* max args in a call */
224 struct Frame *frame = nil; /* base of stack frames; dynamically allocated */
225 int nframe = 0; /* number of frames allocated */
226 struct Frame *fp = nil; /* frame pointer. bottom level unused */
228 Cell *call(Node **a, int) /* function call. very kludgy and fragile */
230 static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
233 Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */
237 fcn = execute(a[0]); /* the function itself */
240 FATAL("calling undefined function %s", s);
242 fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
244 FATAL("out of space for stack frames calling %s", s);
246 for (ncall = 0, x = a[1]; x != nil; x = x->nnext) /* args in call */
248 ndef = (int) fcn->fval; /* args in defn */
249 dprint( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
251 WARNING("function %s called with %d args, uses only %d",
253 if (ncall + ndef > NARGS)
254 FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
255 for (i = 0, x = a[1]; x != nil; i++, x = x->nnext) { /* get call args */
256 dprint( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
259 dprint( ("args[%d]: %s %f <%s>, t=%o\n",
260 i, y->nval, y->fval, isarr(y) ? "(array)" : y->sval, y->tval) );
262 FATAL("can't use function %s as argument in %s", y->nval, s);
264 args[i] = y; /* arrays by ref */
266 args[i] = copycell(y);
270 for ( ; i < ndef; i++) { /* add null args for ones not provided */
272 *args[i] = newcopycell;
274 fp++; /* now ok to up frame */
275 if (fp >= frame + nframe) {
276 int dfp = fp - frame; /* old index */
277 frame = (struct Frame *)
278 realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
280 FATAL("out of space for stack frames in %s", s);
285 fp->nargs = ndef; /* number defined with (excess are locals) */
286 fp->retval = gettemp();
288 dprint( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
289 y = execute((Node *)(fcn->sval)); /* execute body */
290 dprint( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
292 for (i = 0; i < ndef; i++) {
293 Cell *t = fp->args[i];
295 if (t->csub == CCOPY) {
302 oargs[i]->tval = t->tval;
303 oargs[i]->tval &= ~(STR|NUM|DONTFREE);
304 oargs[i]->sval = t->sval;
309 } else if (t != y) { /* kludge to prevent freeing twice */
317 if (isexit(y) || isnext(y) || isnextfile(y))
320 tfree(y); /* this can free twice! */
321 z = fp->retval; /* return value */
322 dprint( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
327 Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
332 y->csub = CCOPY; /* prevents freeing until call is over */
333 y->nval = x->nval; /* BUG? */
334 y->sval = x->sval ? tostring(x->sval) : nil;
336 y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */
337 /* is DONTFREE right? */
341 Cell *arg(Node **a, int n) /* nth argument of a function */
344 n = ptoi(a[0]); /* argument number, counting from 0 */
345 dprint( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
347 FATAL("argument #%d of function %s was not supplied",
348 n+1, fp->fcncell->nval);
352 Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */
360 errorflag = (int) getfval(y);
368 if ((y->tval & (STR|NUM)) == (STR|NUM)) {
369 setsval(fp->retval, getsval(y));
370 fp->retval->fval = getfval(y);
371 fp->retval->tval |= NUM;
373 else if (y->tval & STR)
374 setsval(fp->retval, getsval(y));
375 else if (y->tval & NUM)
376 setfval(fp->retval, getfval(y));
377 else /* can't happen */
378 FATAL("bad type variable %d", y->tval);
392 default: /* can't happen */
393 FATAL("illegal jump type %d", n);
395 return 0; /* not reached */
398 Cell *getline(Node **a, int n) /* get next line from specific input */
399 { /* a[0] is variable, a[1] is operator, a[2] is filename */
401 extern Cell **fldtab;
404 int bufsize = recsize;
407 if ((buf = (char *) malloc(bufsize)) == nil)
408 FATAL("out of memory in getline");
410 Bflush(&stdout); /* in case someone is waiting for a prompt */
412 if (a[1] != nil) { /* getline < file */
413 x = execute(a[2]); /* filename */
415 if (mode == '|') /* input pipe */
416 mode = LE; /* arbitrary flag */
417 fp = openfile(mode, getsval(x));
423 n = readrec(&buf, &bufsize, fp);
426 } else if (a[0] != nil) { /* getline var <file */
431 } else { /* getline <file */
432 setsval(fldtab[0], buf);
433 if (is_number(fldtab[0]->sval)) {
434 fldtab[0]->fval = atof(fldtab[0]->sval);
435 fldtab[0]->tval |= NUM;
438 } else { /* bare getline; use current input */
439 if (a[0] == nil) /* getline */
440 n = getrec(&record, &recsize, 1);
441 else { /* getline var */
442 n = getrec(&buf, &bufsize, 0);
449 setfval(r, (Awkfloat) n);
454 Cell *getnf(Node **a, int) /* get NF */
458 return (Cell *) a[0];
461 Cell *array(Node **a, int) /* a[0] is symtab, a[1] is list of subscripts */
468 int nsub = strlen(*SUBSEP);
470 if ((buf = (char *) malloc(bufsz)) == nil)
471 FATAL("out of memory in array");
473 x = execute(a[0]); /* Cell* for symbol table */
475 for (np = a[1]; np; np = np->nnext) {
476 y = execute(np); /* subscript */
478 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
479 FATAL("out of memory for %s[%s...]", x->nval, buf);
482 strcat(buf, *SUBSEP);
487 dprint( ("making %s into an array\n", x->nval) );
490 x->tval &= ~(STR|NUM|DONTFREE);
492 x->sval = (char *) makesymtab(NSYMTAB);
494 z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
503 Cell *awkdelete(Node **a, int) /* a[0] is symtab, a[1] is list of subscripts */
508 int nsub = strlen(*SUBSEP);
510 x = execute(a[0]); /* Cell* for symbol table */
513 if (a[1] == 0) { /* delete the elements, not the table */
517 x->sval = (char *) makesymtab(NSYMTAB);
521 if ((buf = (char *) malloc(bufsz)) == nil)
522 FATAL("out of memory in adelete");
524 for (np = a[1]; np; np = np->nnext) {
525 y = execute(np); /* subscript */
527 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
528 FATAL("out of memory deleting %s[%s...]", x->nval, buf);
531 strcat(buf, *SUBSEP);
543 Cell *intest(Node **a, int) /* a[0] is index (list), a[1] is symtab */
550 int nsub = strlen(*SUBSEP);
552 ap = execute(a[1]); /* array name */
554 dprint( ("making %s into an array\n", ap->nval) );
557 ap->tval &= ~(STR|NUM|DONTFREE);
559 ap->sval = (char *) makesymtab(NSYMTAB);
561 if ((buf = (char *) malloc(bufsz)) == nil) {
562 FATAL("out of memory in intest");
565 for (p = a[0]; p; p = p->nnext) {
566 x = execute(p); /* expr */
568 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
569 FATAL("out of memory deleting %s[%s...]", x->nval, buf);
574 strcat(buf, *SUBSEP);
576 k = lookup(buf, (Array *) ap->sval);
587 Cell *matchop(Node **a, int n) /* ~ and match() */
594 x = execute(a[1]); /* a[1] = target text */
596 if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */
599 y = execute(a[2]); /* a[2] = regular expr */
612 int start = utfnlen(s, patbeg-s)+1;
615 setfval(rstartloc, (Awkfloat) start);
616 setfval(rlengthloc, (Awkfloat) utfnlen(patbeg, patlen));
621 } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
628 Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
647 if ( !i ) return(False);
655 if (i) return(False);
657 default: /* can't happen */
658 FATAL("unknown boolean operator %d", n);
660 return 0; /*NOTREACHED*/
663 Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
671 if (x->tval&NUM && y->tval&NUM) {
672 j = x->fval - y->fval;
673 i = j<0? -1: (j>0? 1: 0);
675 i = strcmp(getsval(x), getsval(y));
682 case LT: if (i<0) return(True);
684 case LE: if (i<=0) return(True);
686 case NE: if (i!=0) return(True);
688 case EQ: if (i == 0) return(True);
690 case GE: if (i>=0) return(True);
692 case GT: if (i>0) return(True);
694 default: /* can't happen */
695 FATAL("unknown relational operator %d", n);
697 return 0; /*NOTREACHED*/
700 void tfree(Cell *a) /* free a tempcell */
703 dprint( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) );
707 FATAL("tempcell list is curdled");
712 Cell *gettemp(void) /* get a tempcell */
717 tmps = (Cell *) calloc(100, sizeof(Cell));
719 FATAL("out of space for temporaries");
720 for(i = 1; i < 100; i++)
721 tmps[i-1].cnext = &tmps[i];
730 Cell *indirect(Node **a, int) /* $( a[0] ) */
737 m = (int) getfval(x);
738 if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */
739 FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
740 /* BUG: can x->nval ever be null??? */
744 x->ctype = OCELL; /* BUG? why are these needed? */
749 Cell *substr(Node **a, int) /* substr(a[0], a[1], a[2]) */
762 k = utfnlen(s, strlen(s)) + 1;
776 m = (int) getfval(y);
784 n = (int) getfval(z);
793 dprint( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
796 s += chartorune(&r, s);
797 for (p = s; *p && n--; p += chartorune(&r, p))
799 temp = *p; /* with thanks to John Linderman */
808 Cell *sindex(Node **a, int) /* index(a[0], a[1]) */
811 char *s1, *s2, *p1, *p2, *q;
820 for (p1 = s1; *p1 != '\0'; p1++) {
821 for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
824 v = (Awkfloat) utfnlen(s1, p1-s1) + 1; /* origin 1 */
836 #define MAXNUMSIZE 50
838 int format(char **pbuf, int *pbufsize, char *s, Node *a) /* printf-like conversions */
844 int fmtwd; /* format width */
847 int bufsize = *pbufsize;
851 if ((fmt = (char *) malloc(fmtsz)) == nil)
852 FATAL("out of memory in format()");
854 adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format");
864 /* have to be real careful in case this is a huge number, eg, %100000d */
868 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
869 for (t = fmt; (*t++ = *s) != '\0'; s++) {
870 if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0))
871 FATAL("format item %.30s... ran format() out of memory", os);
872 if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
873 break; /* the ansi panoply */
877 sprint(t-1, "%d", fmtwd=(int) getfval(x));
880 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
881 t = fmt + strlen(fmt);
889 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
892 case 'f': case 'e': case 'g': case 'E': case 'G':
897 if(*(s-1) == 'l') break;
903 flag = *(s-1) == 'l' ? 2 : 3;
908 case 'o': case 'x': case 'X':
909 flag = *(s-1) == 'l' ? 2 : 3;
918 WARNING("weird printf conversion %s", fmt);
923 FATAL("not enough args in printf(%s)", os);
929 adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
931 case 0: sprint(p, "%s", fmt); /* unknown, so dump it too */
936 adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
940 case 1: sprint(p, fmt, getfval(x)); break;
941 case 2: sprint(p, fmt, (long) getfval(x)); break;
942 case 3: sprint(p, fmt, (int) getfval(x)); break;
948 if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
949 FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
955 *p++ = (uchar)getfval(x);
962 if((*p = getsval(x)[0]) != '\0')
975 for ( ; a; a = a->nnext) /* evaluate any remaining args */
982 Cell *awksprintf(Node **a, int) /* sprint(a[0]) */
989 if ((buf = (char *) malloc(bufsz)) == nil)
990 FATAL("out of memory in awksprint");
993 if (format(&buf, &bufsz, getsval(x), y) == -1)
994 FATAL("sprint string %.30s... too long. can't happen.", buf);
1003 Cell *awkprintf(Node **a, int) /* printf */
1004 { /* a[0] is list of args, starting with format string */
1005 /* a[1] is redirection operator, a[2] is redirection file */
1011 int bufsz=3*recsize;
1013 if ((buf = (char *) malloc(bufsz)) == nil)
1014 FATAL("out of memory in awkprintf");
1017 if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
1018 FATAL("printf string %.30s... too long. can't happen.", buf);
1021 fp = a[1]? redirect(ptoi(a[1]), a[2]): &stdout;
1022 if(Bwrite(fp, buf, len) < 0)
1023 FATAL("write error on %s", filename(fp));
1024 if(fp != &stdout) Bflush(fp);
1029 Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
1058 FATAL("division by zero");
1063 FATAL("division by zero in mod");
1071 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1072 i = ipow(i, (int) j);
1074 i = errcheck(pow(i, j), "pow");
1076 default: /* can't happen */
1077 FATAL("illegal arithmetic operator %d", n);
1083 double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
1096 Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
1104 k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1105 if (n == PREINCR || n == PREDECR) {
1117 Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
1118 { /* this is subtle; don't muck with it. */
1125 if (n == ASSIGN) { /* ordinary assignment */
1126 if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
1127 goto Free; /* leave alone unless it's a field */
1128 if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1129 setsval(x, getsval(y));
1130 x->fval = getfval(y);
1134 setsval(x, getsval(y));
1136 setfval(x, getfval(y));
1138 funnyvar(y, "read value of");
1158 FATAL("division by zero in /=");
1163 FATAL("division by zero in %%=");
1168 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1169 xf = ipow(xf, (int) yf);
1171 xf = errcheck(pow(xf, yf), "pow");
1174 FATAL("illegal assignment operator %d", n);
1183 Cell *cat(Node **a, int) /* a[0] cat a[1] */
1193 n1 = strlen(x->sval);
1194 n2 = strlen(y->sval);
1195 s = (char *) malloc(n1 + n2 + 1);
1197 FATAL("out of space concatenating %.15s... and %.15s...",
1200 strcpy(s+n1, y->sval);
1211 Cell *pastat(Node **a, int) /* a[0] { a[1] } */
1228 Cell *dopa2(Node **a, int) /* a[0], a[1] { a[2] } */
1234 if (pairstack[pair] == 0) {
1237 pairstack[pair] = 1;
1241 if (pairstack[pair] == 1) {
1244 pairstack[pair] = 0;
1253 Cell *split(Node **a, int) /* split(a[0], a[1], a[2]); a[3] is type */
1255 Cell *x = 0, *y, *ap;
1256 char *s, *t, *fs = 0;
1258 int n, nb, sep, arg3type;
1260 y = execute(a[0]); /* source string */
1262 arg3type = ptoi(a[3]);
1263 if (a[2] == 0) /* fs string */
1265 else if (arg3type == STRING) { /* split(str,arr,"string") */
1268 } else if (arg3type == REGEXPR)
1269 fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
1271 FATAL("illegal type of split");
1273 ap = execute(a[1]); /* array name */
1275 y->tval |= DONTFREE; /* split(a[x], a); */
1278 dprint( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
1281 ap->sval = (char *) makesymtab(NSYMTAB);
1284 if ((*s != '\0' && strlen(fs) > 1) || arg3type == REGEXPR) { /* reg expr */
1286 if (arg3type == REGEXPR) { /* it's ready already */
1292 if (nematch(p,s,t)) {
1295 sprint(num, "%d", n);
1299 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1301 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1303 t = patbeg + patlen;
1304 if (t[-1] == 0 || *t == 0) {
1306 sprint(num, "%d", n);
1307 setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1310 } while (nematch(p,s,t));
1313 sprint(num, "%d", n);
1315 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1317 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1321 } else if (sep == ' ') {
1323 while (*s == ' ' || *s == '\t' || *s == '\n')
1331 while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1334 sprint(num, "%d", n);
1336 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1338 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1343 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
1344 for (n = 0; *s != 0; s += nb) {
1349 snprint(num, sizeof num, "%d", n);
1350 nb = chartorune(&r, s);
1351 memmove(buf, s, nb);
1353 if (isdigit(buf[0]))
1354 setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1356 setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1358 } else if (*s != 0) {
1362 while (*s != sep && *s != '\n' && *s != '\0')
1366 sprint(num, "%d", n);
1368 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1370 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1380 if (a[2] != 0 && arg3type == STRING)
1389 Cell *condexpr(Node **a, int) /* a[0] ? a[1] : a[2] */
1406 Cell *ifstat(Node **a, int) /* if (a[0]) a[1]; else a[2] */
1415 } else if (a[2] != 0) {
1423 Cell *whilestat(Node **a, int) /* while (a[0]) a[1] */
1438 if (isnext(x) || isexit(x) || isret(x))
1445 Cell *dostat(Node **a, int) /* do a[0]; while(a[1]) */
1453 if (isnext(x) || isnextfile(x) || isexit(x) || isret(x))
1465 Cell *forstat(Node **a, int) /* for (a[0]; a[1]; a[2]) a[3] */
1481 if (isbreak(x)) /* turn off break */
1483 if (isnext(x) || isexit(x) || isret(x))
1493 Cell *instat(Node **a, int) /* for (a[0] in a[1]) a[2] */
1495 Cell *x, *vp, *arrayp, *cp, *ncp;
1500 arrayp = execute(a[1]);
1501 if (!isarr(arrayp)) {
1504 tp = (Array *) arrayp->sval;
1507 for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1508 for (cp = tp->tab[i]; cp != nil; cp = ncp) {
1509 setsval(vp, cp->nval);
1517 if (isnext(x) || isexit(x) || isret(x)) {
1529 Cell *bltin(Node **a, int) /* builtin functions. a[0] is type, a[1] is arg list */
1539 void flush_all(void);
1543 nextarg = a[1]->nnext;
1547 u = ((Array *) x->sval)->nelemt; /* GROT. should be function*/
1550 u = (Awkfloat) utfnlen(p, strlen(p));
1554 u = errcheck(log(getfval(x)), "log"); break;
1556 modf(getfval(x), &u); break;
1558 u = errcheck(exp(getfval(x)), "exp"); break;
1560 u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1562 u = sin(getfval(x)); break;
1564 u = cos(getfval(x)); break;
1567 WARNING("atan2 requires two arguments; returning 1.0");
1570 y = execute(a[1]->nnext);
1571 u = atan2(getfval(x), getfval(y));
1574 nextarg = nextarg->nnext;
1578 Bflush(&stdout); /* in case something is buffered already */
1579 u = (Awkfloat) system(getsval(x));
1582 /* in principle, rand() returns something in 0..RAND_MAX */
1583 u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1586 if (isrec(x)) /* no argument provided */
1590 srand((unsigned int) u);
1594 buf = tostring(getsval(x));
1595 if (t == FTOUPPER) {
1596 for (p = buf; *p; p++)
1600 for (p = buf; *p; p++)
1611 if (isrec(x) || strlen(getsval(x)) == 0) {
1612 flush_all(); /* fflush() or fflush("") -> all */
1614 } else if ((fp = openfile(FFLUSH, getsval(x))) == nil)
1620 wc = (int)getfval(x);
1621 mbc[runetochar(mbc, &wc)] = 0;
1627 default: /* can't happen */
1628 FATAL("illegal function type %d", t);
1636 WARNING("warning: function has too many arguments");
1637 for ( ; nextarg; nextarg = nextarg->nnext)
1643 Cell *printstat(Node **a, int) /* print a[0] */
1650 if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
1653 fp = redirect(ptoi(a[1]), a[2]);
1654 for (x = a[0]; x != nil; x = x->nnext) {
1656 Bwrite(fp, getsval(y), strlen(getsval(y)));
1659 if (x->nnext == nil)
1660 r = Bprint(fp, "%s", *ORS);
1662 r = Bprint(fp, "%s", *OFS);
1664 FATAL("write error on %s", filename(fp));
1667 FATAL("write error on %s", filename(fp));
1671 Cell *nullproc(Node **, int)
1677 Biobuf *redirect(int a, Node *b) /* set up all i/o redirections */
1685 fp = openfile(a, fname);
1687 FATAL("can't open file %s", fname);
1696 int mode; /* '|', 'a', 'w' => LE/LT, GT */
1697 } files[FOPEN_MAX] ={
1698 { nil, "/dev/stdin", LT }, /* watch out: don't free this! */
1699 { nil, "/dev/stdout", GT },
1700 { nil, "/dev/stderr", GT }
1703 void stdinit(void) /* in case stdin, etc., are not constants */
1705 files[0].fp = &stdin;
1706 files[1].fp = &stdout;
1707 files[2].fp = &stderr;
1710 Biobuf *openfile(int a, char *us)
1717 FATAL("null file name in print or getline");
1718 for (i=0; i < FOPEN_MAX; i++)
1719 if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1720 if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1725 if (a == FFLUSH) /* didn't find it, so don't create it! */
1728 for (i=0; i < FOPEN_MAX; i++)
1729 if (files[i].fp == 0)
1732 FATAL("%s makes too many open files", s);
1733 Bflush(&stdout); /* force a semblance of order */
1736 fp = Bopen(s, OWRITE);
1737 } else if (a == APPEND) {
1738 fp = Bopen(s, OWRITE);
1740 m = GT; /* so can mix > and >> */
1741 } else if (a == '|') { /* output pipe */
1742 fp = popen(s, OWRITE);
1743 } else if (a == LE) { /* input pipe */
1744 fp = popen(s, OREAD);
1745 } else if (a == LT) { /* getline <file */
1746 fp = strcmp(s, "-") == 0 ? &stdin : Bopen(s, OREAD); /* "-" is stdin */
1747 } else /* can't happen */
1748 FATAL("illegal redirection %d", a);
1750 files[i].fname = tostring(s);
1757 char *filename(Biobuf *fp)
1761 for (i = 0; i < FOPEN_MAX; i++)
1762 if (fp == files[i].fp)
1763 return files[i].fname;
1767 Cell *closefile(Node **a, int)
1774 for (i = 0; i < FOPEN_MAX; i++)
1775 if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1776 if (files[i].mode == '|' || files[i].mode == LE)
1777 stat = pclose(files[i].fp);
1779 stat = Bterm(files[i].fp);
1781 WARNING( "i/o error occurred closing %s", files[i].fname );
1782 if (i > 2) /* don't do /dev/std... */
1783 xfree(files[i].fname);
1784 files[i].fname = nil; /* watch out for ref thru this */
1796 for (i = 0; i < FOPEN_MAX; i++)
1798 if (files[i].mode == '|' || files[i].mode == LE)
1799 stat = pclose(files[i].fp);
1801 stat = Bterm(files[i].fp);
1803 WARNING( "i/o error occurred while closing %s", files[i].fname );
1807 void flush_all(void)
1811 for (i = 0; i < FOPEN_MAX; i++)
1813 Bflush(files[i].fp);
1816 void backsub(char **pb_ptr, char **sptr_ptr);
1818 Cell *sub(Node **a, int) /* substitute command */
1820 char *sptr, *pb, *q;
1821 Cell *x, *y, *result;
1824 int bufsz = recsize;
1826 if ((buf = (char *) malloc(bufsz)) == nil)
1827 FATAL("out of memory in sub");
1828 x = execute(a[3]); /* target string */
1830 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1831 p = (void *) a[1]; /* regular expression */
1834 p = compre(getsval(y));
1838 y = execute(a[2]); /* replacement string */
1840 if (pmatch(p, t, t)) {
1842 adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1844 while (sptr < patbeg)
1847 while (*sptr != 0) {
1848 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1849 if (*sptr == '\\') {
1850 backsub(&pb, &sptr);
1851 } else if (*sptr == '&') {
1853 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1854 for (q = patbeg; q < patbeg+patlen; )
1860 if (pb > buf + bufsz)
1861 FATAL("sub result1 %.30s too big; can't happen", buf);
1862 sptr = patbeg + patlen;
1863 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1864 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1865 while ((*pb++ = *sptr++) != 0)
1868 if (pb > buf + bufsz)
1869 FATAL("sub result2 %.30s too big; can't happen", buf);
1870 setsval(x, buf); /* BUG: should be able to avoid copy */
1881 Cell *gsub(Node **a, int) /* global substitute */
1884 char *rptr, *sptr, *t, *pb, *c, *s;
1888 int bufsz = recsize;
1890 if ((buf = (char *)malloc(bufsz)) == nil)
1891 FATAL("out of memory in gsub");
1892 mflag = 0; /* if mflag == 0, can replace empty string */
1894 x = execute(a[3]); /* target string */
1896 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1897 p = (void *) a[1]; /* regular expression */
1905 y = execute(a[2]); /* replacement string */
1906 if (pmatch(p, t, c)) {
1910 if (patlen == 0 && *patbeg != 0) { /* matched empty string */
1911 if (mflag == 0) { /* can replace empty */
1914 while (*sptr != 0) {
1915 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1916 if (*sptr == '\\') {
1917 backsub(&pb, &sptr);
1918 } else if (*sptr == '&') {
1921 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1922 for (q = patbeg; q < patbeg+patlen; )
1928 if (*c == 0) /* at end */
1930 adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1932 if (pb > buf + bufsz) /* BUG: not sure of this test */
1933 FATAL("gsub result0 %.30s too big; can't happen", buf);
1936 else { /* matched nonempty string */
1939 adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
1940 while (sptr < patbeg)
1943 while (*sptr != 0) {
1944 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1945 if (*sptr == '\\') {
1946 backsub(&pb, &sptr);
1947 } else if (*sptr == '&') {
1950 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1951 for (q = patbeg; q < patbeg+patlen; )
1956 c = patbeg + patlen;
1957 if ((c[-1] == 0) || (*c == 0))
1959 if (pb > buf + bufsz)
1960 FATAL("gsub result1 %.30s too big; can't happen", buf);
1963 } while (pmatch(p, t, c));
1965 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
1966 while ((*pb++ = *sptr++) != 0)
1968 done: if (pb > buf + bufsz)
1969 FATAL("gsub result2 %.30s too big; can't happen", buf);
1971 setsval(x, buf); /* BUG: should be able to avoid copy + free */
1984 void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */
1985 { /* sptr[0] == '\\' */
1986 char *pb = *pb_ptr, *sptr = *sptr_ptr;
1988 if (sptr[1] == '\\') {
1989 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
1993 } else if (sptr[2] == '&') { /* \\& -> \ + matched */
1996 } else { /* \\x -> \\x */
2000 } else if (sptr[1] == '&') { /* literal & */
2003 } else /* literal \ */