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 ****************************************************************/
25 #include <sys/cdefs.h>
26 __FBSDID("$FreeBSD$");
40 #define tempfree(x) if (istemp(x)) tfree(x); else
45 void tempfree(Cell *p) {
46 if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
47 WARNING("bad csub %d in Cell %d %s",
48 p->csub, p->ctype, p->sval);
55 /* do we really need these? */
57 /* #ifndef FOPEN_MAX */
58 /* #define FOPEN_MAX _NFILE */
62 /* #ifndef FOPEN_MAX */
63 /* #define FOPEN_MAX 40 */ /* max number of open files */
66 /* #ifndef RAND_MAX */
67 /* #define RAND_MAX 32767 */ /* all that ansi guarantees */
71 extern int pairstack[];
73 Node *winner = NULL; /* root of parse tree */
74 Cell *tmps; /* free temporary cells for execution */
76 static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
77 Cell *True = &truecell;
78 static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
79 Cell *False = &falsecell;
80 static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
81 Cell *jbreak = &breakcell;
82 static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM };
83 Cell *jcont = &contcell;
84 static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
85 Cell *jnext = &nextcell;
86 static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM };
87 Cell *jnextfile = &nextfilecell;
88 static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
89 Cell *jexit = &exitcell;
90 static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM };
91 Cell *jret = &retcell;
92 static Cell tempcell ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE };
94 Node *curnode = NULL; /* the node being executed, for debugging */
96 /* buffer memory management */
97 int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
99 /* pbuf: address of pointer to buffer being managed
100 * psiz: address of buffer size variable
101 * minlen: minimum length of buffer needed
102 * quantum: buffer size quantum
103 * pbptr: address of movable pointer into buffer, or 0 if none
104 * whatrtn: name of the calling routine if failure should cause fatal error
106 * return 0 for realloc failure, !=0 for success
109 if (minlen > *psiz) {
111 int rminlen = quantum ? minlen % quantum : 0;
112 int boff = pbptr ? *pbptr - *pbuf : 0;
113 /* round up to next multiple of quantum */
115 minlen += quantum - rminlen;
116 tbuf = (char *) realloc(*pbuf, minlen);
117 dprintf( ("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, *pbuf, tbuf) );
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 */
142 Cell *(*proc)(Node **, int);
148 for (a = u; ; a = a->nnext) {
151 x = (Cell *) (a->narg[0]);
152 if (isfld(x) && !donefld)
154 else if (isrec(x) && !donerec)
158 if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */
159 FATAL("illegal statement");
160 proc = proctab[a->nobj-FIRSTTOKEN];
161 x = (*proc)(a->narg, a->nobj);
162 if (isfld(x) && !donefld)
164 else if (isrec(x) && !donerec)
170 if (a->nnext == NULL)
177 Cell *program(Node **a, int n) /* execute an awk program */
178 { /* a[0] = BEGIN, a[1] = body, a[2] = END */
181 if (setjmp(env) != 0)
183 if (a[0]) { /* BEGIN */
188 FATAL("illegal break, continue, next or nextfile from BEGIN");
192 while (getrec(&record, &recsize, 1) > 0) {
199 if (setjmp(env) != 0) /* handles exit within END */
201 if (a[2]) { /* END */
203 if (isbreak(x) || isnext(x) || iscont(x))
204 FATAL("illegal break, continue, next or nextfile from END");
211 struct Frame { /* stack frame for awk function calls */
212 int nargs; /* number of arguments in this call */
213 Cell *fcncell; /* pointer to Cell for function */
214 Cell **args; /* pointer to array of arguments after execute */
215 Cell *retval; /* return value */
218 #define NARGS 50 /* max args in a call */
220 struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
221 int nframe = 0; /* number of frames allocated */
222 struct Frame *fp = NULL; /* frame pointer. bottom level unused */
224 Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
226 static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE };
228 int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */
230 Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */
234 fcn = execute(a[0]); /* the function itself */
237 FATAL("calling undefined function %s", s);
239 fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
241 FATAL("out of space for stack frames calling %s", s);
243 for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
245 ndef = (int) fcn->fval; /* args in defn */
246 dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) );
248 WARNING("function %s called with %d args, uses only %d",
250 if (ncall + ndef > NARGS)
251 FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
252 for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */
253 dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) );
256 dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
257 i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval) );
259 FATAL("can't use function %s as argument in %s", y->nval, s);
261 args[i] = y; /* arrays by ref */
263 args[i] = copycell(y);
266 for ( ; i < ndef; i++) { /* add null args for ones not provided */
268 *args[i] = newcopycell;
270 fp++; /* now ok to up frame */
271 if (fp >= frame + nframe) {
272 int dfp = fp - frame; /* old index */
273 frame = (struct Frame *)
274 realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
276 FATAL("out of space for stack frames in %s", s);
281 fp->nargs = ndef; /* number defined with (excess are locals) */
282 fp->retval = gettemp();
284 dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) );
285 y = execute((Node *)(fcn->sval)); /* execute body */
286 dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) );
288 for (i = 0; i < ndef; i++) {
289 Cell *t = fp->args[i];
291 if (t->csub == CCOPY) {
297 oargs[i]->tval = t->tval;
298 oargs[i]->tval &= ~(STR|NUM|DONTFREE);
299 oargs[i]->sval = t->sval;
303 } else if (t != y) { /* kludge to prevent freeing twice */
306 } else if (t == y && t->csub == CCOPY) {
313 if (isexit(y) || isnext(y))
316 tempfree(y); /* don't free twice! */
318 z = fp->retval; /* return value */
319 dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
324 Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
329 y->csub = CCOPY; /* prevents freeing until call is over */
330 y->nval = x->nval; /* BUG? */
332 y->sval = tostring(x->sval);
334 y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */
335 /* is DONTFREE right? */
339 Cell *arg(Node **a, int n) /* nth argument of a function */
342 n = ptoi(a[0]); /* argument number, counting from 0 */
343 dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
345 FATAL("argument #%d of function %s was not supplied",
346 n+1, fp->fcncell->nval);
350 Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */
358 errorflag = (int) getfval(y);
365 if ((y->tval & (STR|NUM)) == (STR|NUM)) {
366 setsval(fp->retval, getsval(y));
367 fp->retval->fval = getfval(y);
368 fp->retval->tval |= NUM;
370 else if (y->tval & STR)
371 setsval(fp->retval, getsval(y));
372 else if (y->tval & NUM)
373 setfval(fp->retval, getfval(y));
374 else /* can't happen */
375 FATAL("bad type variable %d", y->tval);
388 default: /* can't happen */
389 FATAL("illegal jump type %d", n);
391 return 0; /* not reached */
394 Cell *awkgetline(Node **a, int n) /* get next line from specific input */
395 { /* a[0] is variable, a[1] is operator, a[2] is filename */
397 extern Cell **fldtab;
400 int bufsize = recsize;
403 if ((buf = (char *) malloc(bufsize)) == NULL)
404 FATAL("out of memory in getline");
406 fflush(stdout); /* in case someone is waiting for a prompt */
408 if (a[1] != NULL) { /* getline < file */
409 x = execute(a[2]); /* filename */
411 if (mode == '|') /* input pipe */
412 mode = LE; /* arbitrary flag */
413 fp = openfile(mode, getsval(x));
418 n = readrec(&buf, &bufsize, fp);
421 } else if (a[0] != NULL) { /* getline var <file */
425 } else { /* getline <file */
426 setsval(fldtab[0], buf);
427 if (is_number(fldtab[0]->sval)) {
428 fldtab[0]->fval = atof(fldtab[0]->sval);
429 fldtab[0]->tval |= NUM;
432 } else { /* bare getline; use current input */
433 if (a[0] == NULL) /* getline */
434 n = getrec(&record, &recsize, 1);
435 else { /* getline var */
436 n = getrec(&buf, &bufsize, 0);
442 setfval(r, (Awkfloat) n);
447 Cell *getnf(Node **a, int n) /* get NF */
451 return (Cell *) a[0];
454 Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
461 int nsub = strlen(*SUBSEP);
463 if ((buf = (char *) malloc(bufsz)) == NULL)
464 FATAL("out of memory in array");
466 x = execute(a[0]); /* Cell* for symbol table */
468 for (np = a[1]; np; np = np->nnext) {
469 y = execute(np); /* subscript */
471 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "array"))
472 FATAL("out of memory for %s[%s...]", x->nval, buf);
475 strcat(buf, *SUBSEP);
479 dprintf( ("making %s into an array\n", NN(x->nval)) );
482 x->tval &= ~(STR|NUM|DONTFREE);
484 x->sval = (char *) makesymtab(NSYMTAB);
486 z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
494 Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
499 int nsub = strlen(*SUBSEP);
501 x = execute(a[0]); /* Cell* for symbol table */
504 if (a[1] == 0) { /* delete the elements, not the table */
508 x->sval = (char *) makesymtab(NSYMTAB);
512 if ((buf = (char *) malloc(bufsz)) == NULL)
513 FATAL("out of memory in adelete");
515 for (np = a[1]; np; np = np->nnext) {
516 y = execute(np); /* subscript */
518 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "awkdelete"))
519 FATAL("out of memory deleting %s[%s...]", x->nval, buf);
522 strcat(buf, *SUBSEP);
532 Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
539 int nsub = strlen(*SUBSEP);
541 ap = execute(a[1]); /* array name */
543 dprintf( ("making %s into an array\n", ap->nval) );
546 ap->tval &= ~(STR|NUM|DONTFREE);
548 ap->sval = (char *) makesymtab(NSYMTAB);
550 if ((buf = (char *) malloc(bufsz)) == NULL) {
551 FATAL("out of memory in intest");
554 for (p = a[0]; p; p = p->nnext) {
555 x = execute(p); /* expr */
557 if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "intest"))
558 FATAL("out of memory deleting %s[%s...]", x->nval, buf);
562 strcat(buf, *SUBSEP);
564 k = lookup(buf, (Array *) ap->sval);
574 Cell *matchop(Node **a, int n) /* ~ and match() */
580 int (*mf)(fa *, const char *) = match, mode = 0;
586 x = execute(a[1]); /* a[1] = target text */
588 if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */
589 i = (*mf)((fa *) a[2], s);
591 y = execute(a[2]); /* a[2] = regular expr */
593 pfa = makedfa(t, mode);
599 int start = patbeg - s + 1;
602 setfval(rstartloc, (Awkfloat) start);
603 setfval(rlengthloc, (Awkfloat) patlen);
608 } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
615 Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
632 if ( !i ) return(False);
639 if (i) return(False);
641 default: /* can't happen */
642 FATAL("unknown boolean operator %d", n);
644 return 0; /*NOTREACHED*/
647 Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
655 if (x->tval&NUM && y->tval&NUM) {
656 j = x->fval - y->fval;
657 i = j<0? -1: (j>0? 1: 0);
659 i = strcoll(getsval(x), getsval(y));
664 case LT: if (i<0) return(True);
666 case LE: if (i<=0) return(True);
668 case NE: if (i!=0) return(True);
670 case EQ: if (i == 0) return(True);
672 case GE: if (i>=0) return(True);
674 case GT: if (i>0) return(True);
676 default: /* can't happen */
677 FATAL("unknown relational operator %d", n);
679 return 0; /*NOTREACHED*/
682 void tfree(Cell *a) /* free a tempcell */
685 dprintf( ("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval) );
689 FATAL("tempcell list is curdled");
694 Cell *gettemp(void) /* get a tempcell */
699 tmps = (Cell *) calloc(100, sizeof(Cell));
701 FATAL("out of space for temporaries");
702 for(i = 1; i < 100; i++)
703 tmps[i-1].cnext = &tmps[i];
712 Cell *indirect(Node **a, int n) /* $( a[0] ) */
720 val = getfval(x); /* freebsd: defend against super large field numbers */
721 if ((Awkfloat)INT_MAX < val)
722 FATAL("trying to access out of range field %s", x->nval);
724 if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */
725 FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
726 /* BUG: can x->nval ever be null??? */
729 x->ctype = OCELL; /* BUG? why are these needed? */
734 Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
757 m = (int) getfval(y);
764 n = (int) getfval(z);
772 dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
774 temp = s[n+m-1]; /* with thanks to John Linderman */
776 setsval(y, s + m - 1);
782 Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
785 char *s1, *s2, *p1, *p2, *q;
794 for (p1 = s1; *p1 != '\0'; p1++) {
795 for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
798 v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */
808 #define MAXNUMSIZE 50
810 int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like conversions */
817 int fmtwd; /* format width */
820 int bufsize = *pbufsize;
824 if ((fmt = (char *) malloc(fmtsz)) == NULL)
825 FATAL("out of memory in format()");
827 adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1");
837 /* have to be real careful in case this is a huge number, eg, %100000d */
841 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format2");
842 for (t = fmt; (*t++ = *s) != '\0'; s++) {
843 if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3"))
844 FATAL("format item %.30s... ran format() out of memory", os);
845 if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L')
846 break; /* the ansi panoply */
850 sprintf(t-1, "%d", fmtwd=(int) getfval(x));
853 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
854 t = fmt + strlen(fmt);
861 adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format4");
864 case 'f': case 'e': case 'g': case 'E': case 'G':
869 if(*(s-1) == 'l') break;
874 case 'o': case 'x': case 'X': case 'u':
875 flag = *(s-1) == 'l' ? 'd' : 'u';
884 WARNING("weird printf conversion %s", fmt);
889 FATAL("not enough args in printf(%s)", os);
895 adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5");
897 case '?': sprintf(p, "%s", fmt); /* unknown, so dump it too */
902 adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6");
906 case 'f': sprintf(p, fmt, getfval(x)); break;
907 case 'd': sprintf(p, fmt, (long) getfval(x)); break;
908 case 'u': sprintf(p, fmt, (int) getfval(x)); break;
914 if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7"))
915 FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
921 sprintf(p, fmt, (int) getfval(x));
923 *p++ = '\0'; /* explicit null byte */
924 *p = '\0'; /* next output will start here */
927 sprintf(p, fmt, getsval(x)[0]);
930 FATAL("can't happen: bad conversion %c in format()", flag);
938 for ( ; a; a = a->nnext) /* evaluate any remaining args */
945 Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
952 if ((buf = (char *) malloc(bufsz)) == NULL)
953 FATAL("out of memory in awksprintf");
956 if (format(&buf, &bufsz, getsval(x), y) == -1)
957 FATAL("sprintf string %.30s... too long. can't happen.", buf);
965 Cell *awkprintf(Node **a, int n) /* printf */
966 { /* a[0] is list of args, starting with format string */
967 /* a[1] is redirection operator, a[2] is redirection file */
975 if ((buf = (char *) malloc(bufsz)) == NULL)
976 FATAL("out of memory in awkprintf");
979 if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
980 FATAL("printf string %.30s... too long. can't happen.", buf);
983 /* fputs(buf, stdout); */
984 fwrite(buf, len, 1, stdout);
986 FATAL("write error on stdout");
988 fp = redirect(ptoi(a[1]), a[2]);
989 /* fputs(buf, fp); */
990 fwrite(buf, len, 1, fp);
993 FATAL("write error on %s", filename(fp));
999 Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
1026 FATAL("division by zero");
1031 FATAL("division by zero in mod");
1039 if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1040 i = ipow(i, (int) j);
1042 i = errcheck(pow(i, j), "pow");
1044 default: /* can't happen */
1045 FATAL("illegal arithmetic operator %d", n);
1051 double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
1064 Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
1072 k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1073 if (n == PREINCR || n == PREDECR) {
1084 Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
1085 { /* this is subtle; don't muck with it. */
1092 if (n == ASSIGN) { /* ordinary assignment */
1093 if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
1094 ; /* leave alone unless it's a field */
1095 else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1096 setsval(x, getsval(y));
1097 x->fval = getfval(y);
1101 setsval(x, getsval(y));
1103 setfval(x, getfval(y));
1105 funnyvar(y, "read value of");
1123 FATAL("division by zero in /=");
1128 FATAL("division by zero in %%=");
1133 if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1134 xf = ipow(xf, (int) yf);
1136 xf = errcheck(pow(xf, yf), "pow");
1139 FATAL("illegal assignment operator %d", n);
1147 Cell *cat(Node **a, int q) /* a[0] cat a[1] */
1157 n1 = strlen(x->sval);
1158 n2 = strlen(y->sval);
1159 s = (char *) malloc(n1 + n2 + 1);
1161 FATAL("out of space concatenating %.15s... and %.15s...",
1164 strcpy(s+n1, y->sval);
1173 Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
1189 Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
1195 if (pairstack[pair] == 0) {
1198 pairstack[pair] = 1;
1201 if (pairstack[pair] == 1) {
1204 pairstack[pair] = 0;
1212 Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
1214 Cell *x = 0, *y, *ap;
1217 char *t, temp, num[50], *fs = 0;
1218 int n, tempstat, arg3type;
1220 y = execute(a[0]); /* source string */
1222 arg3type = ptoi(a[3]);
1223 if (a[2] == 0) /* fs string */
1225 else if (arg3type == STRING) { /* split(str,arr,"string") */
1228 } else if (arg3type == REGEXPR)
1229 fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
1231 FATAL("illegal type of split");
1233 ap = execute(a[1]); /* array name */
1235 dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs) );
1238 ap->sval = (char *) makesymtab(NSYMTAB);
1241 if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) { /* reg expr */
1243 if (arg3type == REGEXPR) { /* it's ready already */
1246 pfa = makedfa(fs, 1);
1248 if (nematch(pfa,s)) {
1249 tempstat = pfa->initstat;
1253 sprintf(num, "%d", n);
1257 setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1259 setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1261 s = patbeg + patlen;
1262 if (*(patbeg+patlen-1) == 0 || *s == 0) {
1264 sprintf(num, "%d", n);
1265 setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1266 pfa->initstat = tempstat;
1269 } while (nematch(pfa,s));
1270 pfa->initstat = tempstat; /* bwk: has to be here to reset */
1271 /* cf gsub and refldbld */
1274 sprintf(num, "%d", n);
1276 setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1278 setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1281 } else if (sep == ' ') {
1283 while (*s == ' ' || *s == '\t' || *s == '\n')
1291 while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1294 sprintf(num, "%d", n);
1296 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1298 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1303 } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
1304 for (n = 0; *s != 0; s++) {
1307 sprintf(num, "%d", n);
1310 if (isdigit((uschar)buf[0]))
1311 setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1313 setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1315 } else if (*s != 0) {
1319 while (*s != sep && *s != '\n' && *s != '\0')
1323 sprintf(num, "%d", n);
1325 setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1327 setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1335 if (a[2] != 0 && arg3type == STRING) {
1344 Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
1359 Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
1367 } else if (a[2] != 0) {
1374 Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
1388 if (isnext(x) || isexit(x) || isret(x))
1394 Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
1402 if (isnext(x) || isexit(x) || isret(x))
1412 Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
1421 if (!istrue(x)) return(x);
1425 if (isbreak(x)) /* turn off break */
1427 if (isnext(x) || isexit(x) || isret(x))
1435 Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1437 Cell *x, *vp, *arrayp, *cp, *ncp;
1442 arrayp = execute(a[1]);
1443 if (!isarr(arrayp)) {
1446 tp = (Array *) arrayp->sval;
1448 for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1449 for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1450 setsval(vp, cp->nval);
1457 if (isnext(x) || isexit(x) || isret(x)) {
1467 Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
1475 void flush_all(void);
1479 nextarg = a[1]->nnext;
1483 u = ((Array *) x->sval)->nelem; /* GROT. should be function*/
1485 u = strlen(getsval(x));
1488 u = errcheck(log(getfval(x)), "log"); break;
1490 modf(getfval(x), &u); break;
1492 u = errcheck(exp(getfval(x)), "exp"); break;
1494 u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1496 u = sin(getfval(x)); break;
1498 u = cos(getfval(x)); break;
1501 WARNING("atan2 requires two arguments; returning 1.0");
1504 y = execute(a[1]->nnext);
1505 u = atan2(getfval(x), getfval(y));
1507 nextarg = nextarg->nnext;
1511 fflush(stdout); /* in case something is buffered already */
1512 u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */
1515 /* in principle, rand() returns something in 0..RAND_MAX */
1516 u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1519 if (isrec(x)) /* no argument provided */
1520 u = time((time_t *)0);
1523 srand((unsigned int) u);
1527 buf = tostring(getsval(x));
1528 if (t == FTOUPPER) {
1529 for (p = buf; *p; p++)
1530 if (islower((uschar) *p))
1531 *p = toupper((uschar)*p);
1533 for (p = buf; *p; p++)
1534 if (isupper((uschar) *p))
1535 *p = tolower((uschar)*p);
1543 if (isrec(x) || strlen(getsval(x)) == 0) {
1544 flush_all(); /* fflush() or fflush("") -> all */
1546 } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
1551 default: /* can't happen */
1552 FATAL("illegal function type %d", t);
1559 WARNING("warning: function has too many arguments");
1560 for ( ; nextarg; nextarg = nextarg->nnext)
1566 Cell *printstat(Node **a, int n) /* print a[0] */
1572 if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
1575 fp = redirect(ptoi(a[1]), a[2]);
1576 for (x = a[0]; x != NULL; x = x->nnext) {
1578 fputs(getpssval(y), fp);
1580 if (x->nnext == NULL)
1588 FATAL("write error on %s", filename(fp));
1592 Cell *nullproc(Node **a, int n)
1600 FILE *redirect(int a, Node *b) /* set up all i/o redirections */
1608 fp = openfile(a, fname);
1610 FATAL("can't open file %s", fname);
1618 int mode; /* '|', 'a', 'w' => LE/LT, GT */
1619 } files[FOPEN_MAX] ={
1620 { NULL, "/dev/stdin", LT }, /* watch out: don't free this! */
1621 { NULL, "/dev/stdout", GT },
1622 { NULL, "/dev/stderr", GT }
1625 void stdinit(void) /* in case stdin, etc., are not constants */
1627 files[0].fp = stdin;
1628 files[1].fp = stdout;
1629 files[2].fp = stderr;
1632 FILE *openfile(int a, const char *us)
1639 FATAL("null file name in print or getline");
1640 for (i=0; i < FOPEN_MAX; i++)
1641 if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1642 if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1647 if (a == FFLUSH) /* didn't find it, so don't create it! */
1650 for (i=0; i < FOPEN_MAX; i++)
1651 if (files[i].fp == 0)
1654 FATAL("%s makes too many open files", s);
1655 fflush(stdout); /* force a semblance of order */
1659 } else if (a == APPEND) {
1661 m = GT; /* so can mix > and >> */
1662 } else if (a == '|') { /* output pipe */
1664 } else if (a == LE) { /* input pipe */
1666 } else if (a == LT) { /* getline <file */
1667 fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
1668 } else /* can't happen */
1669 FATAL("illegal redirection %d", a);
1671 files[i].fname = tostring(s);
1678 const char *filename(FILE *fp)
1682 for (i = 0; i < FOPEN_MAX; i++)
1683 if (fp == files[i].fp)
1684 return files[i].fname;
1688 Cell *closefile(Node **a, int n)
1697 for (i = 0; i < FOPEN_MAX; i++) {
1698 if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1699 if (ferror(files[i].fp))
1700 WARNING( "i/o error occurred on %s", files[i].fname );
1701 if (files[i].mode == '|' || files[i].mode == LE)
1702 stat = pclose(files[i].fp);
1704 stat = fclose(files[i].fp);
1706 WARNING( "i/o error occurred closing %s", files[i].fname );
1707 if (i > 2) /* don't do /dev/std... */
1708 xfree(files[i].fname);
1709 files[i].fname = NULL; /* watch out for ref thru this */
1715 setfval(x, (Awkfloat) stat);
1723 for (i = 0; i < FOPEN_MAX; i++) {
1725 if (ferror(files[i].fp))
1726 WARNING( "i/o error occurred on %s", files[i].fname );
1727 if (files[i].mode == '|' || files[i].mode == LE)
1728 stat = pclose(files[i].fp);
1730 stat = fclose(files[i].fp);
1732 WARNING( "i/o error occurred while closing %s", files[i].fname );
1737 void flush_all(void)
1741 for (i = 0; i < FOPEN_MAX; i++)
1743 fflush(files[i].fp);
1746 void backsub(char **pb_ptr, char **sptr_ptr);
1748 Cell *sub(Node **a, int nnn) /* substitute command */
1750 char *sptr, *pb, *q;
1751 Cell *x, *y, *result;
1754 int bufsz = recsize;
1756 if ((buf = (char *) malloc(bufsz)) == NULL)
1757 FATAL("out of memory in sub");
1758 x = execute(a[3]); /* target string */
1760 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1761 pfa = (fa *) a[1]; /* regular expression */
1764 pfa = makedfa(getsval(y), 1);
1767 y = execute(a[2]); /* replacement string */
1769 if (pmatch(pfa, t)) {
1771 adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1773 while (sptr < patbeg)
1776 while (*sptr != 0) {
1777 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1778 if (*sptr == '\\') {
1779 backsub(&pb, &sptr);
1780 } else if (*sptr == '&') {
1782 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1783 for (q = patbeg; q < patbeg+patlen; )
1789 if (pb > buf + bufsz)
1790 FATAL("sub result1 %.30s too big; can't happen", buf);
1791 sptr = patbeg + patlen;
1792 if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1793 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1794 while ((*pb++ = *sptr++) != 0)
1797 if (pb > buf + bufsz)
1798 FATAL("sub result2 %.30s too big; can't happen", buf);
1799 setsval(x, buf); /* BUG: should be able to avoid copy */
1808 Cell *gsub(Node **a, int nnn) /* global substitute */
1811 char *rptr, *sptr, *t, *pb, *q;
1814 int mflag, tempstat, num;
1815 int bufsz = recsize;
1817 if ((buf = (char *) malloc(bufsz)) == NULL)
1818 FATAL("out of memory in gsub");
1819 mflag = 0; /* if mflag == 0, can replace empty string */
1821 x = execute(a[3]); /* target string */
1823 if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1824 pfa = (fa *) a[1]; /* regular expression */
1827 pfa = makedfa(getsval(y), 1);
1830 y = execute(a[2]); /* replacement string */
1831 if (pmatch(pfa, t)) {
1832 tempstat = pfa->initstat;
1837 if (patlen == 0 && *patbeg != 0) { /* matched empty string */
1838 if (mflag == 0) { /* can replace empty */
1841 while (*sptr != 0) {
1842 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1843 if (*sptr == '\\') {
1844 backsub(&pb, &sptr);
1845 } else if (*sptr == '&') {
1847 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1848 for (q = patbeg; q < patbeg+patlen; )
1854 if (*t == 0) /* at end */
1856 adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1858 if (pb > buf + bufsz) /* BUG: not sure of this test */
1859 FATAL("gsub result0 %.30s too big; can't happen", buf);
1862 else { /* matched nonempty string */
1865 adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
1866 while (sptr < patbeg)
1869 while (*sptr != 0) {
1870 adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1871 if (*sptr == '\\') {
1872 backsub(&pb, &sptr);
1873 } else if (*sptr == '&') {
1875 adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1876 for (q = patbeg; q < patbeg+patlen; )
1881 t = patbeg + patlen;
1882 if (patlen == 0 || *t == 0 || *(t-1) == 0)
1884 if (pb > buf + bufsz)
1885 FATAL("gsub result1 %.30s too big; can't happen", buf);
1888 } while (pmatch(pfa,t));
1890 adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
1891 while ((*pb++ = *sptr++) != 0)
1893 done: if (pb > buf + bufsz)
1894 FATAL("gsub result2 %.30s too big; can't happen", buf);
1896 setsval(x, buf); /* BUG: should be able to avoid copy + free */
1897 pfa->initstat = tempstat;
1908 void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */
1909 { /* sptr[0] == '\\' */
1910 char *pb = *pb_ptr, *sptr = *sptr_ptr;
1912 if (sptr[1] == '\\') {
1913 if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
1917 } else if (sptr[2] == '&') { /* \\& -> \ + matched */
1920 } else { /* \\x -> \\x */
1924 } else if (sptr[1] == '&') { /* literal & */
1927 } else /* literal \ */