diff options
Diffstat (limited to 'usr/src/cmd/awk/run.c')
-rw-r--r-- | usr/src/cmd/awk/run.c | 653 |
1 files changed, 449 insertions, 204 deletions
diff --git a/usr/src/cmd/awk/run.c b/usr/src/cmd/awk/run.c index 29529bdb84..211ba8e39f 100644 --- a/usr/src/cmd/awk/run.c +++ b/usr/src/cmd/awk/run.c @@ -56,41 +56,41 @@ #include <setjmp.h> #include <math.h> #include <time.h> +#include <sys/wait.h> #include "awk.h" #include "y.tab.h" #define tempfree(x) if (istemp(x)) tfree(x) -#ifndef FOPEN_MAX -#define FOPEN_MAX 15 /* max number of open files, from ANSI std. */ -#endif - - static jmp_buf env; +extern Awkfloat srand_seed; static Cell *execute(Node *); static Cell *gettemp(void), *copycell(Cell *); static FILE *openfile(int, const char *), *redirect(int, Node *); Node *winner = NULL; /* root of parse tree */ - static Cell *tmps; /* free temporary cells for execution */ -static Cell truecell = { OBOOL, BTRUE, 0, 0, 1.0, NUM }; +static Cell truecell = { OBOOL, BTRUE, NULL, NULL, 1.0, NUM, NULL }; Cell *True = &truecell; -static Cell falsecell = { OBOOL, BFALSE, 0, 0, 0.0, NUM }; +static Cell falsecell = { OBOOL, BFALSE, NULL, NULL, 0.0, NUM, NULL }; Cell *False = &falsecell; -static Cell breakcell = { OJUMP, JBREAK, 0, 0, 0.0, NUM }; +static Cell breakcell = { OJUMP, JBREAK, NULL, NULL, 0.0, NUM, NULL }; Cell *jbreak = &breakcell; -static Cell contcell = { OJUMP, JCONT, 0, 0, 0.0, NUM }; +static Cell contcell = { OJUMP, JCONT, NULL, NULL, 0.0, NUM, NULL }; Cell *jcont = &contcell; -static Cell nextcell = { OJUMP, JNEXT, 0, 0, 0.0, NUM }; +static Cell nextcell = { OJUMP, JNEXT, NULL, NULL, 0.0, NUM, NULL }; Cell *jnext = &nextcell; -static Cell exitcell = { OJUMP, JEXIT, 0, 0, 0.0, NUM }; +static Cell nextfilecell = { OJUMP, JNEXTFILE, NULL, NULL, 0.0, + NUM, NULL }; +Cell *jnextfile = &nextfilecell; +static Cell exitcell = { OJUMP, JEXIT, NULL, NULL, 0.0, NUM, NULL }; Cell *jexit = &exitcell; -static Cell retcell = { OJUMP, JRET, 0, 0, 0.0, NUM }; +static Cell retcell = { OJUMP, JRET, NULL, NULL, 0.0, NUM, NULL }; Cell *jret = &retcell; -static Cell tempcell = { OCELL, CTEMP, 0, 0, 0.0, NUM }; +static Cell tempcell = { OCELL, CTEMP, NULL, "", 0.0, + NUM|STR|DONTFREE, NULL }; Node *curnode = NULL; /* the node being executed, for debugging */ @@ -140,6 +140,9 @@ adjbuf(char **pbuf, size_t *psiz, size_t minlen, size_t quantum, char **pbptr, void run(Node *a) /* execution of parse tree starts here */ { + extern void stdinit(void); + + stdinit(); (void) execute(a); closeall(); } @@ -198,13 +201,13 @@ program(Node **a, int n) if (isexit(x)) return (True); if (isjump(x)) { - FATAL("illegal break, continue, or next from BEGIN"); + FATAL("illegal break, continue, next or nextfile " + "from BEGIN"); } tempfree(x); } -loop: if (a[1] || a[2]) - while (getrec(&record, &recsize) > 0) { + while (getrec(&record, &recsize, 1) > 0) { x = execute(a[1]); if (isexit(x)) break; @@ -215,10 +218,9 @@ ex: goto ex1; if (a[2]) { /* END */ x = execute(a[2]); - if (iscont(x)) /* read some more */ - goto loop; - if (isbreak(x) || isnext(x)) - FATAL("illegal break or next from END"); + if (isbreak(x) || isnext(x) || iscont(x)) + FATAL("illegal break, continue, next or nextfile " + "from END"); tempfree(x); } ex1: @@ -232,7 +234,7 @@ struct Frame { /* stack frame for awk function calls */ Cell *retval; /* return value */ }; -#define NARGS 30 /* max args in a call */ +#define NARGS 50 /* max args in a call */ struct Frame *frame = NULL; /* base of stack frames; dynamically alloc'd */ int nframe = 0; /* number of frames allocated */ @@ -243,7 +245,7 @@ Cell * call(Node **a, int n) /* function call. very kludgy and fragile */ { static Cell newcopycell = - { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE }; + { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE, NULL }; int i, ncall, ndef; /* handles potential double freeing when fcn & param share a tempcell */ int freed = 0; @@ -324,6 +326,7 @@ call(Node **a, int n) /* function call. very kludgy and fragile */ if (i >= ncall) { freesymtab(t); t->csub = CTEMP; + tempfree(t); } else { oargs[i]->tval = t->tval; oargs[i]->tval &= ~(STR|NUM|DONTFREE); @@ -331,10 +334,13 @@ call(Node **a, int n) /* function call. very kludgy and fragile */ tempfree(t); } } - } else { + } else if (t != y) { /* kludge to prevent freeing twice */ + t->csub = CTEMP; + tempfree(t); + } else if (t == y && t->csub == CCOPY) { t->csub = CTEMP; tempfree(t); - if (t == y) freed = 1; + freed = 1; } } tempfree(fcn); @@ -355,13 +361,18 @@ copycell(Cell *x) /* make a copy of a cell in a temp */ { Cell *y; + /* copy is not constant or field */ + y = gettemp(); + y->tval = x->tval & ~(CON|FLD|REC); y->csub = CCOPY; /* prevents freeing until call is over */ - y->nval = x->nval; - y->sval = x->sval ? tostring(x->sval) : NULL; + y->nval = x->nval; /* BUG? */ + if (isstr(x)) { + y->sval = tostring(x->sval); + y->tval &= ~DONTFREE; + } else + y->tval |= DONTFREE; y->fval = x->fval; - /* copy is not constant or field is DONTFREE right? */ - y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); return (y); } @@ -412,6 +423,9 @@ jump(Node **a, int n) /* break, continue, next, nextfile, return */ return (jret); case NEXT: return (jnext); + case NEXTFILE: + nextfile(); + return (jnextfile); case BREAK: return (jbreak); case CONTINUE: @@ -428,11 +442,14 @@ awkgetline(Node **a, int n) /* get next line from specific input */ { /* a[0] is variable, a[1] is operator, a[2] is filename */ Cell *r, *x; - char *buf; FILE *fp; - size_t len; + char *buf; + size_t bufsize = recsize; int mode; + if ((buf = (char *)malloc(bufsize)) == NULL) + FATAL("out of memory in getline"); + (void) fflush(stdout); /* in case someone is waiting for a prompt */ r = gettemp(); if (a[1] != NULL) { /* getline < file */ @@ -442,38 +459,36 @@ awkgetline(Node **a, int n) /* get next line from specific input */ mode = LE; /* arbitrary flag */ fp = openfile(mode, getsval(x)); tempfree(x); - buf = NULL; if (fp == NULL) n = -1; else - n = readrec(&buf, &len, fp); - if (n > 0) { - if (a[0] != NULL) { /* getline var <file */ - (void) setsval(execute(a[0]), buf); - } else { /* getline <file */ - if (!(recloc->tval & DONTFREE)) - xfree(recloc->sval); - expand_buf(&record, &recsize, len); - (void) memcpy(record, buf, len); - record[len] = '\0'; - recloc->sval = record; - recloc->tval = REC | STR | DONTFREE; - donerec = 1; donefld = 0; + n = readrec(&buf, &bufsize, fp); + /*LINTED if*/ + if (n <= 0) { + ; + } else if (a[0] != NULL) { /* getline var <file */ + x = execute(a[0]); + (void) setsval(x, buf); + tempfree(x); + } else { /* getline <file */ + (void) setsval(recloc, buf); + if (is_number(recloc->sval)) { + recloc->fval = atof(recloc->sval); + recloc->tval |= NUM; } } - if (buf != NULL) - free(buf); } else { /* bare getline; use current input */ if (a[0] == NULL) /* getline */ - n = getrec(&record, &recsize); + n = getrec(&record, &recsize, 1); else { /* getline var */ - init_buf(&buf, &len, LINE_INCR); - n = getrec(&buf, &len); - (void) setsval(execute(a[0]), buf); - free(buf); + n = getrec(&buf, &bufsize, 0); + x = execute(a[0]); + (void) setsval(x, buf); + tempfree(x); } } (void) setfval(r, (Awkfloat)n); + free(buf); return (r); } @@ -494,23 +509,26 @@ array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ char *s; Node *np; char *buf; - size_t bsize, tlen, len, slen; + size_t bufsz = recsize; + size_t tlen = 0, len, nsub; + + if ((buf = (char *)malloc(bufsz)) == NULL) + FATAL("out of memory in array"); x = execute(a[0]); /* Cell* for symbol table */ - init_buf(&buf, &bsize, LINE_INCR); buf[0] = '\0'; - tlen = 0; - slen = strlen(*SUBSEP); for (np = a[1]; np != NULL; np = np->nnext) { y = execute(np); /* subscript */ s = getsval(y); len = strlen(s); - expand_buf(&buf, &bsize, tlen + len + slen); + nsub = strlen(getsval(subseploc)); + (void) adjbuf(&buf, &bufsz, tlen + len + nsub + 1, + recsize, 0, "array"); (void) memcpy(&buf[tlen], s, len); tlen += len; if (np->nnext) { - (void) memcpy(&buf[tlen], *SUBSEP, slen); - tlen += slen; + (void) memcpy(&buf[tlen], *SUBSEP, nsub); + tlen += nsub; } buf[tlen] = '\0'; tempfree(y); @@ -538,33 +556,53 @@ awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ { Cell *x, *y; Node *np; - char *buf, *s; - size_t bsize, tlen, slen, len; + char *s; + size_t nsub; + size_t tlen = 0, len; x = execute(a[0]); /* Cell* for symbol table */ - if (!isarr(x)) - return (True); - init_buf(&buf, &bsize, LINE_INCR); - buf[0] = '\0'; - tlen = 0; - slen = strlen(*SUBSEP); - for (np = a[1]; np != NULL; np = np->nnext) { - y = execute(np); /* subscript */ - s = getsval(y); - len = strlen(s); - expand_buf(&buf, &bsize, tlen + len + slen); - (void) memcpy(&buf[tlen], s, len); - tlen += len; - if (np->nnext) { - (void) memcpy(&buf[tlen], *SUBSEP, slen); - tlen += slen; + if (x == symtabloc) { + FATAL("cannot delete SYMTAB or its elements"); + } + if (!isarr(x)) { + dprintf(("making %s into an array\n", x->nval)); + if (freeable(x)) + xfree(x->sval); + x->tval &= ~(STR|NUM|DONTFREE); + x->tval |= ARR; + x->sval = (char *)makesymtab(NSYMTAB); + } + if (a[1] == NULL) { /* delete the elements, not the table */ + freesymtab(x); + x->tval &= ~STR; + x->tval |= ARR; + x->sval = (char *)makesymtab(NSYMTAB); + } else { + size_t bufsz = recsize; + char *buf; + if ((buf = (char *)malloc(bufsz)) == NULL) + FATAL("out of memory in awkdelete"); + buf[0] = '\0'; + for (np = a[1]; np != NULL; np = np->nnext) { + y = execute(np); /* subscript */ + s = getsval(y); + len = strlen(s); + nsub = strlen(getsval(subseploc)); + (void) adjbuf(&buf, &bufsz, tlen + len + nsub + 1, + recsize, 0, "awkdelete"); + (void) memcpy(&buf[tlen], s, len); + tlen += len; + if (np->nnext) { + (void) memcpy(&buf[tlen], *SUBSEP, nsub); + tlen += nsub; + } + buf[tlen] = '\0'; + tempfree(y); } - buf[tlen] = '\0'; - tempfree(y); + freeelem(x, buf); + free(buf); } - freeelem(x, buf); tempfree(x); - free(buf); return (True); } @@ -576,26 +614,36 @@ intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */ Node *p; char *buf; char *s; - size_t bsize, tlen, slen, len; + size_t bufsz = recsize; + size_t nsub; + size_t tlen = 0, len; ap = execute(a[1]); /* array name */ - if (!isarr(ap)) - FATAL("%s is not an array", ap->nval); - init_buf(&buf, &bsize, LINE_INCR); + if (!isarr(ap)) { + dprintf(("making %s into an array\n", ap->nval)); + if (freeable(ap)) + xfree(ap->sval); + ap->tval &= ~(STR|NUM|DONTFREE); + ap->tval |= ARR; + ap->sval = (char *)makesymtab(NSYMTAB); + } + if ((buf = (char *)malloc(bufsz)) == NULL) { + FATAL("out of memory in intest"); + } buf[0] = '\0'; - tlen = 0; - slen = strlen(*SUBSEP); for (p = a[0]; p != NULL; p = p->nnext) { x = execute(p); /* expr */ s = getsval(x); len = strlen(s); - expand_buf(&buf, &bsize, tlen + len + slen); + nsub = strlen(getsval(subseploc)); + (void) adjbuf(&buf, &bufsz, tlen + len + nsub + 1, + recsize, 0, "intest"); (void) memcpy(&buf[tlen], s, len); tlen += len; tempfree(x); if (p->nnext) { - (void) memcpy(&buf[tlen], *SUBSEP, slen); - tlen += slen; + (void) memcpy(&buf[tlen], *SUBSEP, nsub); + tlen += nsub; } buf[tlen] = '\0'; } @@ -755,14 +803,21 @@ gettemp(void) /* get a tempcell */ Cell * indirect(Node **a, int n) /* $( a[0] ) */ { + Awkfloat val; Cell *x; int m; char *s; x = execute(a[0]); - m = (int)getfval(x); + + /* freebsd: defend against super large field numbers */ + val = getfval(x); + if ((Awkfloat)INT_MAX < val) + FATAL("trying to access out of range field %s", x->nval); + m = (int)val; if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */ - FATAL("illegal field $(%s)", s); + FATAL("illegal field $(%s), name \"%s\"", s, x->nval); + /* BUG: can x->nval ever be null??? */ tempfree(x); x = fieldadr(m); x->ctype = OCELL; /* BUG? why are these needed? */ @@ -848,20 +903,26 @@ sindex(Node **a, int nnn) /* index(a[0], a[1]) */ return (z); } -void -format(char **bufp, char *s, Node *a) +#define MAXNUMSIZE 50 + +/* printf-like conversions */ +int +format(char **pbuf, int *pbufsize, const char *s, Node *a) { char *fmt; const char *os; Cell *x; - int flag = 0, len; - char *buf; - size_t bufsize, fmtsize, cnt, tcnt, ret; + int flag = 0, n, len; + int fmtwd; /* format width */ + char *buf = *pbuf; + size_t bufsize = *pbufsize; + size_t fmtsz = recsize; + size_t cnt, tcnt, ret; - init_buf(&buf, &bufsize, LINE_INCR); - init_buf(&fmt, &fmtsize, LINE_INCR); os = s; cnt = 0; + if ((fmt = (char *)malloc(fmtsz)) == NULL) + FATAL("out of memory in format()"); while (*s) { if (*s != '%') { expand_buf(&buf, &bufsize, cnt); @@ -874,14 +935,24 @@ format(char **bufp, char *s, Node *a) s += 2; continue; } + /* + * have to be real careful in case this is a huge number, + * eg, "%100000d". + */ + fmtwd = atoi(s+1); + if (fmtwd < 0) + fmtwd = -fmtwd; for (tcnt = 0; ; s++) { - expand_buf(&fmt, &fmtsize, tcnt); + expand_buf(&fmt, &fmtsz, tcnt); fmt[tcnt++] = *s; if (*s == '\0') break; if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L') break; /* the ansi panoply */ + if (*s == '$') { + FATAL("'$' not permitted in awk formats"); + } if (*s == '*') { if (a == NULL) { FATAL("not enough args in printf(%s) " @@ -890,42 +961,50 @@ format(char **bufp, char *s, Node *a) x = execute(a); a = a->nnext; tcnt--; - expand_buf(&fmt, &fmtsize, tcnt + 12); - ret = sprintf(&fmt[tcnt], "%d", - (int)getfval(x)); + expand_buf(&fmt, &fmtsz, tcnt + 12); + fmtwd = (int)getfval(x); + ret = sprintf(&fmt[tcnt], "%d", fmtwd); + if (fmtwd < 0) + fmtwd = -fmtwd; tcnt += ret; tempfree(x); } } fmt[tcnt] = '\0'; + if (fmtwd < 0) + fmtwd = -fmtwd; switch (*s) { + case 'a': case 'A': + flag = *s; + break; case 'f': case 'e': case 'g': case 'E': case 'G': - flag = 1; + flag = 'f'; break; case 'd': case 'i': - flag = 2; + flag = 'd'; if (*(s-1) == 'l') break; fmt[tcnt - 1] = 'l'; - expand_buf(&fmt, &fmtsize, tcnt); + expand_buf(&fmt, &fmtsz, tcnt); fmt[tcnt++] = 'd'; fmt[tcnt] = '\0'; break; case 'o': case 'x': case 'X': case 'u': - flag = *(s-1) == 'l' ? 2 : 3; + flag = *(s-1) == 'l' ? 'd' : 'u'; break; case 's': - flag = 4; + flag = 's'; break; case 'c': - flag = 5; + flag = 'c'; break; default: - flag = 0; + WARNING("weird printf conversion %s", fmt); + flag = '?'; break; } - if (flag == 0) { + if (flag == '?') { len = strlen(fmt); expand_buf(&buf, &bufsize, cnt + len); (void) memcpy(&buf[cnt], fmt, len); @@ -939,59 +1018,76 @@ format(char **bufp, char *s, Node *a) } x = execute(a); a = a->nnext; - for (;;) { - /* make sure we have at least 1 byte space */ - expand_buf(&buf, &bufsize, cnt + 1); - len = bufsize - cnt; - switch (flag) { - case 1: - /*LINTED*/ - ret = snprintf(&buf[cnt], len, - fmt, getfval(x)); - break; - case 2: + n = MAXNUMSIZE; + if (fmtwd > n) + n = fmtwd; +retry: + /* make sure we have at least 1 byte space */ + (void) adjbuf(&buf, &bufsize, 1 + n + cnt, + recsize, NULL, "format5"); + len = bufsize - cnt; + switch (flag) { + case 'a': + case 'A': + case 'f': + /*LINTED*/ + ret = snprintf(&buf[cnt], len, + fmt, getfval(x)); + break; + case 'd': + /*LINTED*/ + ret = snprintf(&buf[cnt], len, + fmt, (long)getfval(x)); + break; + case 'u': + /*LINTED*/ + ret = snprintf(&buf[cnt], len, + fmt, (int)getfval(x)); + break; + case 's': + /*LINTED*/ + ret = snprintf(&buf[cnt], len, + fmt, getsval(x)); + break; + case 'c': + if (!isnum(x)) { /*LINTED*/ ret = snprintf(&buf[cnt], len, - fmt, (long)getfval(x)); + fmt, getsval(x)[0]); break; - case 3: + } + if (getfval(x)) { /*LINTED*/ ret = snprintf(&buf[cnt], len, fmt, (int)getfval(x)); - break; - case 4: - /*LINTED*/ - ret = snprintf(&buf[cnt], len, - fmt, getsval(x)); - break; - case 5: - if (isnum(x)) { - /*LINTED*/ - ret = snprintf(&buf[cnt], len, - fmt, (int)getfval(x)); - } else { - /*LINTED*/ - ret = snprintf(&buf[cnt], len, - fmt, getsval(x)[0]); - } - break; - default: - ret = 0; + } else { + /* explicit null byte */ + buf[cnt] = '\0'; + /* next output will start here */ + buf[cnt + 1] = '\0'; + ret = 1; } - if (ret < len) - break; - expand_buf(&buf, &bufsize, cnt + ret); + break; + default: + FATAL("can't happen: " + "bad conversion %c in format()", flag); + } + if (ret >= len) { + (void) adjbuf(&buf, &bufsize, cnt + ret + 1, + recsize, NULL, "format6"); + goto retry; } tempfree(x); cnt += ret; s++; } buf[cnt] = '\0'; + free(fmt); for (; a != NULL; a = a->nnext) /* evaluate any remaining args */ (void) execute(a); - *bufp = tostring(buf); - free(buf); - free(fmt); + *pbuf = buf; + *pbufsize = bufsize; + return (cnt); } /*ARGSUSED*/ @@ -1001,10 +1097,14 @@ awksprintf(Node **a, int n) /* sprintf(a[0]) */ Cell *x; Node *y; char *buf; + int bufsz = 3 * recsize; + if ((buf = (char *)malloc(bufsz)) == NULL) + FATAL("out of memory in awksprintf"); y = a[0]->nnext; x = execute(a[0]); - format(&buf, getsval(x), y); + if (format(&buf, &bufsz, getsval(x), y) == -1) + FATAL("sprintf string %.30s... too long. can't happen.", buf); tempfree(x); x = gettemp(); x->sval = buf; @@ -1022,17 +1122,26 @@ awkprintf(Node **a, int n) /* printf */ Cell *x; Node *y; char *buf; + int len; + int bufsz = 3 * recsize; + if ((buf = (char *)malloc(bufsz)) == NULL) + FATAL("out of memory in awkprintf"); y = a[0]->nnext; x = execute(a[0]); - format(&buf, getsval(x), y); + if ((len = format(&buf, &bufsz, getsval(x), y)) == -1) + FATAL("printf string %.30s... too long. can't happen.", buf); tempfree(x); if (a[1] == NULL) { - (void) fputs(buf, stdout); + (void) fwrite(buf, len, 1, stdout); + if (ferror(stdout)) + FATAL("write error on stdout"); } else { fp = redirect(ptoi(a[1]), a[2]); - (void) fputs(buf, fp); + (void) fwrite(buf, len, 1, fp); (void) fflush(fp); + if (ferror(fp)) + FATAL("write error on %s", filename(fp)); } free(buf); return (True); @@ -1048,7 +1157,7 @@ arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */ x = execute(a[0]); i = getfval(x); tempfree(x); - if (n != UMINUS) { + if (n != UMINUS && n != UPLUS) { y = execute(a[1]); j = getfval(y); tempfree(y); @@ -1078,6 +1187,8 @@ arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */ case UMINUS: i = -i; break; + case UPLUS: /* handled by getfval(), above */ + break; case POWER: if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */ i = ipow(i, (int)j); @@ -1138,7 +1249,13 @@ assign(Node **a, int n) y = execute(a[1]); x = execute(a[0]); /* order reversed from before... */ if (n == ASSIGN) { /* ordinary assignment */ - if ((y->tval & (STR|NUM)) == (STR|NUM)) { + /*LINTED if*/ + if (x == y && !(x->tval & (FLD|REC)) && x != nfloc) { + /* + * If this is a self-assignment, we leave things alone, + * unless it's a field or NF. + */ + } else if ((y->tval & (STR|NUM)) == (STR|NUM)) { (void) setsval(x, getsval(y)); x->fval = getfval(y); x->tval |= NUM; @@ -1195,26 +1312,26 @@ cat(Node **a, int q) /* a[0] cat a[1] */ { Cell *x, *y, *z; int n1, n2; - char *s; + char *s = NULL; + size_t ssz = 0; x = execute(a[0]); + n1 = strlen(getsval(x)); + (void) adjbuf(&s, &ssz, n1 + 1, recsize, 0, "cat1"); + (void) strncpy(s, x->sval, ssz); + y = execute(a[1]); - (void) getsval(x); - (void) getsval(y); - n1 = strlen(x->sval); - n2 = strlen(y->sval); - s = (char *)malloc(n1 + n2 + 1); - if (s == NULL) { - FATAL("out of space concatenating %.15s... and %.15s...", - x->sval, y->sval); - } - (void) strcpy(s, x->sval); - (void) strcpy(s + n1, y->sval); + n2 = strlen(getsval(y)); + (void) adjbuf(&s, &ssz, n1 + n2 + 1, recsize, 0, "cat2"); + (void) strncpy(s + n1, y->sval, ssz - n1); + tempfree(x); tempfree(y); + z = gettemp(); z->sval = s; z->tval = STR; + return (z); } @@ -1273,20 +1390,22 @@ dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */ Cell * split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ { - Cell *x, *y, *ap; - char *s; + Cell *x = NULL, *y, *ap; + char *s, *origs; + char *fs, *origfs = NULL; int sep; - char *t, temp, num[50], *fs = NULL; + char *t, temp, num[50]; int n, tempstat, arg3type; y = execute(a[0]); /* source string */ - s = getsval(y); + origs = s = tostring(getsval(y)); arg3type = ptoi(a[3]); - if (a[2] == NULL) /* fs string */ - fs = *FS; + if (a[2] == NULL) /* fs string */ + fs = getsval(fsloc); else if (arg3type == STRING) { /* split(str,arr,"string") */ x = execute(a[2]); - fs = getsval(x); + origfs = fs = tostring(getsval(x)); + tempfree(x); } else if (arg3type == REGEXPR) fs = "(regexpr)"; /* split(str,arr,/regexpr/) */ else @@ -1300,6 +1419,15 @@ split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ ap->sval = (char *)makesymtab(NSYMTAB); n = 0; + if (arg3type == REGEXPR && strlen((char *)((fa*)a[2])->restr) == 0) { + /* + * split(s, a, //); have to arrange things such that it looks + * like an empty separator. + */ + arg3type = 0; + fs = ""; + sep = 0; + } if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) { /* reg expr */ fa *pfa; @@ -1338,6 +1466,9 @@ split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ goto spdone; } } while (nematch(pfa, s)); + /* bwk: has to be here to reset */ + /* cf gsub and refldbld */ + pfa->initstat = tempstat; } n++; (void) sprintf(num, "%d", n); @@ -1380,6 +1511,23 @@ spdone: if (*s != '\0') s++; } + } else if (sep == '\0') { /* split(s, a, "") => 1 char/elem */ + for (n = 0; *s != 0; s++) { + char buf[2]; + n++; + (void) sprintf(num, "%d", n); + buf[0] = *s; + buf[1] = '\0'; + if (isdigit((uschar)buf[0])) { + (void) setsymtab(num, buf, atof(buf), + /*LINTED align*/ + STR|NUM, (Array *)ap->sval); + } else { + (void) setsymtab(num, buf, 0.0, + /*LINTED align*/ + STR, (Array *)ap->sval); + } + } } else if (*s != '\0') { for (;;) { n++; @@ -1405,9 +1553,8 @@ spdone: } tempfree(ap); tempfree(y); - if (a[2] != NULL && arg3type == STRING) { - tempfree(x); - } + free(origs); + free(origfs); x = gettemp(); x->tval = NUM; x->fval = n; @@ -1528,7 +1675,12 @@ instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */ vp = execute(a[0]); arrayp = execute(a[1]); if (!isarr(arrayp)) { - FATAL("%s is not an array", arrayp->nval); + dprintf(("making %s into an array\n", arrayp->nval)); + if (freeable(arrayp)) + xfree(arrayp->sval); + arrayp->tval &= ~(STR|NUM|DONTFREE); + arrayp->tval |= ARR; + arrayp->sval = (char *)makesymtab(NSYMTAB); } /*LINTED align*/ tp = (Array *)arrayp->sval; @@ -1559,15 +1711,25 @@ bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */ Cell *x, *y; Awkfloat u; int t; + Awkfloat tmp; char *p, *buf; Node *nextarg; + FILE *fp; + void flush_all(void); + int status = 0; t = ptoi(a[0]); x = execute(a[1]); nextarg = a[1]->nnext; switch (t) { case FLENGTH: - u = (Awkfloat)strlen(getsval(x)); break; + if (isarr(x)) { + /* LINTED align */ + u = ((Array *)x->sval)->nelem; + } else { + u = strlen(getsval(x)); + } + break; case FLOG: u = errcheck(log(getfval(x)), "log"); break; case FINT: @@ -1594,8 +1756,18 @@ bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */ case FSYSTEM: /* in case something is buffered already */ (void) fflush(stdout); - /* 256 is unix-dep */ - u = (Awkfloat)system(getsval(x)) / 256; + status = system(getsval(x)); + u = status; + if (status != -1) { + if (WIFEXITED(status)) { + u = WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + u = WTERMSIG(status) + 256; + if (WCOREDUMP(status)) + u += 256; + } else /* something else?!? */ + u = 0; + } break; case FRAND: /* in principle, rand() returns something in 0..RAND_MAX */ @@ -1606,7 +1778,10 @@ bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */ u = time((time_t *)0); else u = getfval(x); - srand((int)u); u = (int)u; + tmp = u; + srand((unsigned int) u); + u = srand_seed; + srand_seed = tmp; break; case FTOUPPER: case FTOLOWER: @@ -1625,6 +1800,15 @@ bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */ (void) setsval(x, buf); free(buf); return (x); + case FFLUSH: + if (isrec(x) || strlen(getsval(x)) == 0) { + flush_all(); /* fflush() or fflush("") -> all */ + u = 0; + } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL) + u = EOF; + else + u = fflush(fp); + break; default: /* can't happen */ FATAL("illegal function type %d", t); break; @@ -1654,15 +1838,17 @@ printstat(Node **a, int n) /* print a[0] */ fp = redirect(ptoi(a[1]), a[2]); for (x = a[0]; x != NULL; x = x->nnext) { y = execute(x); - (void) fputs(getsval(y), fp); + (void) fputs(getpssval(y), fp); tempfree(y); if (x->nnext == NULL) - (void) fputs(*ORS, fp); + (void) fputs(getsval(orsloc), fp); else - (void) fputs(*OFS, fp); + (void) fputs(getsval(ofsloc), fp); } if (a[1] != NULL) (void) fflush(fp); + if (ferror(fp)) + FATAL("write error on %s", filename(fp)); return (True); } @@ -1673,11 +1859,6 @@ nullproc(Node **a, int n) return (0); } -struct { - FILE *fp; - char *fname; - int mode; /* '|', 'a', 'w' */ -} files[FOPEN_MAX]; static FILE * redirect(int a, Node *b) /* set up all i/o redirections */ @@ -1695,6 +1876,32 @@ redirect(int a, Node *b) /* set up all i/o redirections */ return (fp); } +struct files { + FILE *fp; + const char *fname; + int mode; /* '|', 'a', 'w' => LE/LT, GT */ +} *files; + +int nfiles; + +void +stdinit(void) /* in case stdin, etc., are not constants */ +{ + nfiles = FOPEN_MAX; + files = calloc(nfiles, sizeof (*files)); + if (files == NULL) + FATAL("can't allocate file memory for %u files", nfiles); + files[0].fp = stdin; + files[0].fname = "/dev/stdin"; + files[0].mode = LT; + files[1].fp = stdout; + files[1].fname = "/dev/stdout"; + files[1].mode = GT; + files[2].fp = stderr; + files[2].fname = "/dev/stderr"; + files[2].mode = GT; +} + static FILE * openfile(int a, const char *s) { @@ -1703,34 +1910,47 @@ openfile(int a, const char *s) if (*s == '\0') FATAL("null file name in print or getline"); - for (i = 0; i < FOPEN_MAX; i++) { + for (i = 0; i < nfiles; i++) { if (files[i].fname && strcmp(s, files[i].fname) == 0) { if (a == files[i].mode || (a == APPEND && files[i].mode == GT)) { return (files[i].fp); } + if (a == FFLUSH) + return (files[i].fp); } } - for (i = 0; i < FOPEN_MAX; i++) { + if (a == FFLUSH) /* didn't find it, so don't create it! */ + return (NULL); + + for (i = 0; i < nfiles; i++) { if (files[i].fp == 0) break; } - if (i >= FOPEN_MAX) - FATAL("%s makes too many open files", s); + if (i >= nfiles) { + struct files *nf; + int nnf = nfiles + FOPEN_MAX; + nf = realloc(files, nnf * sizeof (*nf)); + if (nf == NULL) + FATAL("cannot grow files for %s and %d files", s, nnf); + (void) memset(&nf[nfiles], 0, FOPEN_MAX * sizeof (*nf)); + nfiles = nnf; + files = nf; + } (void) fflush(stdout); /* force a semblance of order */ m = a; if (a == GT) { - fp = fopen(s, "w"); + fp = fopen(s, "wF"); } else if (a == APPEND) { - fp = fopen(s, "a"); + fp = fopen(s, "aF"); m = GT; /* so can mix > and >> */ } else if (a == '|') { /* output pipe */ - fp = popen(s, "w"); + fp = popen(s, "wF"); } else if (a == LE) { /* input pipe */ - fp = popen(s, "r"); + fp = popen(s, "rF"); } else if (a == LT) { /* getline <file */ fp = strcmp(s, "-") == 0 ? - stdin : fopen(s, "r"); /* "-" is stdin */ + stdin : fopen(s, "rF"); /* "-" is stdin */ } else /* can't happen */ FATAL("illegal redirection %d", a); if (fp != NULL) { @@ -1741,6 +1961,17 @@ openfile(int a, const char *s) return (fp); } +const char * +filename(FILE *fp) +{ + int i; + + for (i = 0; i < nfiles; i++) + if (fp == files[i].fp) + return (files[i].fname); + return ("???"); +} + /*ARGSUSED*/ Cell * closefile(Node **a, int n) @@ -1750,7 +1981,8 @@ closefile(Node **a, int n) x = execute(a[0]); (void) getsval(x); - for (i = 0; i < FOPEN_MAX; i++) { + stat = -1; + for (i = 0; i < nfiles; i++) { if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) { if (ferror(files[i].fp)) { WARNING("i/o error occurred on %s", @@ -1764,14 +1996,17 @@ closefile(Node **a, int n) WARNING("i/o error occurred closing %s", files[i].fname); } - xfree(files[i].fname); + if (i > 2) /* don't do /dev/std... */ + xfree(files[i].fname); /* watch out for ref thru this */ files[i].fname = NULL; files[i].fp = NULL; } } tempfree(x); - return (True); + x = gettemp(); + (void) setfval(x, (Awkfloat) stat); + return (x); } static void @@ -1779,7 +2014,7 @@ closeall(void) { int i, stat; - for (i = 0; i < FOPEN_MAX; i++) { + for (i = 0; i < nfiles; i++) { if (files[i].fp) { if (ferror(files[i].fp)) { WARNING("i/o error occurred on %s", @@ -1797,6 +2032,16 @@ closeall(void) } } +void +flush_all(void) +{ + int i; + + for (i = 0; i < nfiles; i++) + if (files[i].fp) + (void) fflush(files[i].fp); +} + /*ARGSUSED*/ Cell * sub(Node **a, int nnn) /* substitute command */ @@ -1978,7 +2223,6 @@ gsub(Node **a, int nnn) /* global substitute */ done: buf[cnt] = '\0'; (void) setsval(x, buf); - free(buf); pfa->initstat = tempstat; } tempfree(x); @@ -1986,5 +2230,6 @@ gsub(Node **a, int nnn) /* global substitute */ x = gettemp(); x->tval = NUM; x->fval = num; + free(buf); return (x); } |