Cell *cat(Node **a, int q) /* a[0] cat a[1] */ { Cell *x, *y, *z; int n1, n2; char *s; x = execute(a[0]); y = execute(a[1]); getsval(x); getsval(y); n1 = strlen(x->sval); n2 = strlen(y->sval); s = (char *) malloc(n1 + n2 + 1); if (s == NULL) ERROR "out of space concatenating %.15s... and %.15s...", x->sval, y->sval FATAL; strcpy(s, x->sval); strcpy(s+n1, y->sval); tempfree(y); z = gettemp(); z->sval = s; z->tval = STR; tempfree(x); return(z); }
Cell *adelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ { Cell *x, *y; Node *np; char buf[RECSIZE], *s; x = execute(a[0]); /* Cell* for symbol table */ if (!isarr(x)) return true; if (a[1] == 0) { /* delete the elements, not the table */ freesymtab(x); x->tval &= ~STR; x->tval |= ARR; x->sval = (char *) makesymtab(NSYMTAB); } else { buf[0] = 0; for (np = a[1]; np; np = np->nnext) { y = execute(np); /* subscript */ s = getsval(y); strcat(buf, s); if (np->nnext) strcat(buf, *SUBSEP); tempfree(y); } freeelem(x, buf); } tempfree(x); return true; }
Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */ { Cell *x, *ap, *k; Node *p; char buf[RECSIZE]; char *s; ap = execute(a[1]); /* array name */ 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); } buf[0] = 0; for (p = a[0]; p; p = p->nnext) { x = execute(p); /* expr */ s = getsval(x); strcat(buf, s); tempfree(x); if (p->nnext) strcat(buf, *SUBSEP); } k = lookup(buf, (Array *) ap->sval); tempfree(ap); if (k == NULL) return(false); else return(true); }
Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */ { Cell *x, *vp, *arrayp, *cp, *ncp; Array *tp; int i; vp = execute(a[0]); arrayp = execute(a[1]); if (!isarr(arrayp)) { return true; } tp = (Array *) arrayp->sval; tempfree(arrayp); for (i = 0; i < tp->size; i++) { /* this routine knows too much */ for (cp = tp->tab[i]; cp != NULL; cp = ncp) { setsval(vp, cp->nval); ncp = cp->cnext; x = execute(a[2]); if (isbreak(x)) { tempfree(vp); return true; } if (isnext(x) || isexit(x) || isret(x)) { tempfree(vp); return(x); } tempfree(x); } } return true; }
Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ { Cell *x, *y, *z; char *s; Node *np; char buf[RECSIZE]; x = execute(a[0]); /* Cell* for symbol table */ buf[0] = 0; for (np = a[1]; np; np = np->nnext) { y = execute(np); /* subscript */ s = getsval(y); strcat(buf, s); /* BUG: unchecked! */ if (np->nnext) strcat(buf, *SUBSEP); tempfree(y); } 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); } z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval); z->ctype = OCELL; z->csub = CVAR; tempfree(x); return(z); }
Cell *program(Node **a, int n) /* execute an awk program */ { /* a[0] = BEGIN, a[1] = body, a[2] = END */ Cell *x; if (setjmp(env) != 0) goto ex; if (a[0]) { /* BEGIN */ x = execute(a[0]); if (isexit(x)) return(true); if (isjump(x)) ERROR "illegal break, continue, next or nextfile from BEGIN" FATAL; tempfree(x); } if (a[1] || a[2]) while (getrec(record) > 0) { x = execute(a[1]); if (isexit(x)) break; tempfree(x); } ex: if (setjmp(env) != 0) /* handles exit within END */ goto ex1; if (a[2]) { /* END */ x = execute(a[2]); if (isbreak(x) || isnext(x) || iscont(x)) ERROR "illegal break, continue, next or nextfile from END" FATAL; tempfree(x); } ex1: return(true); }
Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */ { Cell *x, *y, *z; char *s1, *s2, *p1, *p2, *q; Awkfloat v = 0.0; x = execute(a[0]); s1 = getsval(x); y = execute(a[1]); s2 = getsval(y); z = gettemp(); for (p1 = s1; *p1 != '\0'; p1++) { for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++) ; if (*p2 == '\0') { v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */ break; } } tempfree(x); tempfree(y); setfval(z, v); return(z); }
Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */ { Cell *x, *y; int i; x = execute(a[0]); i = istrue(x); tempfree(x); switch (n) { case BOR: if (i) return(true); y = execute(a[1]); i = istrue(y); tempfree(y); if (i) return(true); else return(false); case AND: if ( !i ) return(false); y = execute(a[1]); i = istrue(y); tempfree(y); if (i) return(true); else return(false); case NOT: if (i) return(false); else return(true); default: /* can't happen */ ERROR "unknown boolean operator %d", n FATAL; } return 0; /*NOTREACHED*/ }
Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */ { int i; Cell *x, *y; Awkfloat j; x = execute(a[0]); y = execute(a[1]); if (x->tval&NUM && y->tval&NUM) { j = x->fval - y->fval; i = j<0? -1: (j>0? 1: 0); } else { i = strcmp(getsval(x), getsval(y)); } tempfree(x); tempfree(y); switch (n) { case LT: if (i<0) return(true); else return(false); case LE: if (i<=0) return(true); else return(false); case NE: if (i!=0) return(true); else return(false); case EQ: if (i == 0) return(true); else return(false); case GE: if (i>=0) return(true); else return(false); case GT: if (i>0) return(true); else return(false); default: /* can't happen */ ERROR "unknown relational operator %d", n FATAL; } return 0; /*NOTREACHED*/ }
Cell *sub(Node **a, int nnn) /* substitute command */ { char *sptr, *pb, *q; Cell *x, *y, *result; char *t, *buf; fa *pfa; int bufsz = recsize; if ((buf = (char *) malloc(bufsz)) == NULL) FATAL("out of memory in sub"); x = execute(a[3]); /* target string */ t = getsval(x); if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ pfa = (fa *) a[1]; /* regular expression */ else { y = execute(a[1]); pfa = makedfa(getsval(y), 1); tempfree(y); } y = execute(a[2]); /* replacement string */ result = False; if (pmatch(pfa, t)) { sptr = t; adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub"); pb = buf; while (sptr < patbeg) *pb++ = *sptr++; sptr = getsval(y); while (*sptr != 0) { adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub"); if (*sptr == '\\') { backsub(&pb, &sptr); } else if (*sptr == '&') { sptr++; adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub"); for (q = patbeg; q < patbeg+patlen; ) *pb++ = *q++; } else *pb++ = *sptr++; } *pb = '\0'; if (pb > buf + bufsz) FATAL("sub result1 %.30s too big; can't happen", buf); sptr = patbeg + patlen; if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) { adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub"); while ((*pb++ = *sptr++) != 0) ; } if (pb > buf + bufsz) FATAL("sub result2 %.30s too big; can't happen", buf); setsval(x, buf); /* BUG: should be able to avoid copy */ result = True;; } tempfree(x); tempfree(y); free(buf); return result; }
Cell *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; extern Cell **fldtab; FILE *fp; char *buf; int bufsize = recsize; int mode; if ((buf = (char *) malloc(bufsize)) == NULL) FATAL("out of memory in getline"); fflush(stdout); /* in case someone is waiting for a prompt */ r = gettemp(); if (a[1] != NULL) { /* getline < file */ x = execute(a[2]); /* filename */ mode = ptoi(a[1]); if (mode == '|') /* input pipe */ mode = LE; /* arbitrary flag */ fp = openfile(mode, getsval(x)); tempfree(x); if (fp == NULL) n = -1; else n = readrec(&buf, &bufsize, fp); if (n <= 0) { ; } else if (a[0] != NULL) { /* getline var <file */ x = execute(a[0]); setsval(x, buf); tempfree(x); } else { /* getline <file */ setsval(fldtab[0], buf); if (is_number(fldtab[0]->sval)) { fldtab[0]->fval = atof(fldtab[0]->sval); fldtab[0]->tval |= NUM; } } } else { /* bare getline; use current input */ if (a[0] == NULL) /* getline */ n = getrec(&record, &recsize, 1); else { /* getline var */ n = getrec(&buf, &bufsize, 0); x = execute(a[0]); setsval(x, buf); tempfree(x); } } setfval(r, (Awkfloat) n); free(buf); return r; }
Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */ { Awkfloat i, j = 0; double v; Cell *x, *y, *z; x = execute(a[0]); i = getfval(x); tempfree(x); if (n != UMINUS) { y = execute(a[1]); j = getfval(y); tempfree(y); } z = gettemp(); switch (n) { case ADD: i += j; break; case MINUS: i -= j; break; case MULT: i *= j; break; case DIVIDE: if (j == 0) ERROR "division by zero" FATAL; i /= j; break; case MOD: if (j == 0) ERROR "division by zero in mod" FATAL; modf(i/j, &v); i = i - j * v; break; case UMINUS: i = -i; break; case POWER: if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */ i = ipow(i, (int) j); else i = errcheck(pow(i, j), "pow"); break; default: /* can't happen */ ERROR "illegal arithmetic operator %d", n FATAL; } setfval(z, i); return(z); }
Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */ { Cell *x; x = execute(a[0]); if (istrue(x)) { tempfree(x); x = execute(a[1]); } else if (a[2] != 0) { tempfree(x); x = execute(a[2]); } return(x); }
Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */ { Cell *x; x = execute(a[0]); if (istrue(x)) { tempfree(x); x = execute(a[1]); } else { tempfree(x); x = execute(a[2]); } return(x); }
Cell *sub(Node **a, int nnn) /* substitute command */ { register uchar *sptr, *pb, *q; register Cell *x, *y, *result; uchar buf[SUBSIZE], *t; fa *pfa; x = execute(a[3]); /* target string */ t = getsval(x); if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ pfa = (fa *) a[1]; /* regular expression */ else { y = execute(a[1]); pfa = makedfa(getsval(y), 1); tempfree(y); } y = execute(a[2]); /* replacement string */ result = false; if (pmatch(pfa, t)) { pb = buf; sptr = t; while (sptr < patbeg) *pb++ = *sptr++; sptr = getsval(y); while (*sptr != 0 && pb < buf + SUBSIZE - 1) if (*sptr == '\\' && *(sptr+1) == '&') { sptr++; /* skip \, */ *pb++ = *sptr++; /* add & */ } else if (*sptr == '&') { sptr++; for (q = patbeg; q < patbeg+patlen; ) *pb++ = *q++; } else *pb++ = *sptr++; *pb = '\0'; if (pb >= buf + SUBSIZE) ERROR "sub() result %30s too big", buf FATAL; sptr = patbeg + patlen; if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) while (*pb++ = *sptr++) ; if (pb >= buf + SUBSIZE) ERROR "sub() result %.30s too big", buf FATAL; setsval(x, buf); result = true;; } tempfree(x); tempfree(y); return result; }
Cell *execute(Node *u) /* execute a node of the parse tree */ { Cell *(*proc)(Node **, int); Cell *x; Node *a; if (u == NULL) return(true); for (a = u; ; a = a->nnext) { curnode = a; if (isvalue(a)) { x = (Cell *) (a->narg[0]); if ((x->tval & FLD) && !donefld) fldbld(); else if ((x->tval & REC) && !donerec) recbld(); return(x); } if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */ ERROR "illegal statement" FATAL; proc = proctab[a->nobj-FIRSTTOKEN]; x = (*proc)(a->narg, a->nobj); if ((x->tval & FLD) && !donefld) fldbld(); else if ((x->tval & REC) && !donerec) recbld(); if (isexpr(a)) return(x); if (isjump(x)) return(x); if (a->nnext == NULL) return(x); tempfree(x); } }
Cell *closefile(Node **a, int n) { Cell *x; int i, stat; n = n; x = execute(a[0]); getsval(x); 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", files[i].fname ); if (files[i].mode == '|' || files[i].mode == LE) stat = pclose(files[i].fp); else stat = fclose(files[i].fp); if (stat == EOF) WARNING( "i/o error occurred closing %s", files[i].fname ); if (i > 2) /* don't do /dev/std... */ xfree(files[i].fname); files[i].fname = NULL; /* watch out for ref thru this */ files[i].fp = NULL; } } tempfree(x); x = gettemp(); setfval(x, (Awkfloat) stat); return(x); }
Cell *printstat(Node **a, int n) /* print a[0] */ { Node *x; Cell *y; FILE *fp; if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */ fp = stdout; else fp = redirect(ptoi(a[1]), a[2]); for (x = a[0]; x != NULL; x = x->nnext) { y = execute(x); fputs(getpssval(y), fp); tempfree(y); if (x->nnext == NULL) fputs(*ORS, fp); else fputs(*OFS, fp); } if (a[1] != 0) fflush(fp); if (ferror(fp)) FATAL("write error on %s", filename(fp)); return(True); }
Cell *awkprintf(Node **a, int n) /* printf */ { /* a[0] is list of args, starting with format string */ /* a[1] is redirection operator, a[2] is redirection file */ FILE *fp; 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]); 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) { /* fputs(buf, stdout); */ fwrite(buf, len, 1, stdout); if (ferror(stdout)) FATAL("write error on stdout"); } else { fp = redirect(ptoi(a[1]), a[2]); /* fputs(buf, fp); */ fwrite(buf, len, 1, fp); fflush(fp); if (ferror(fp)) FATAL("write error on %s", filename(fp)); } free(buf); return(True); }
Cell *closefile(Node **a, int n) { register Cell *x; int i, stat; n; x = execute(a[0]); getsval(x); for (i = 0; i < FOPEN_MAX; i++) if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) { if (ferror(files[i].fp)) ERROR "i/o error occurred on %s", files[i].fname WARNING; if (files[i].mode == '|' || files[i].mode == LE) stat = pclose(files[i].fp); else stat = fclose(files[i].fp); if (stat == EOF) ERROR "i/o error occurred closing %s", files[i].fname WARNING; if (i > 2) /* don't do /dev/std... */ xfree(files[i].fname); files[i].fname = NULL; /* watch out for ref thru this */ files[i].fp = NULL; } tempfree(x); return(true); }
Cell *printstat(Node **a, int n) /* print a[0] */ { register Node *x; register Cell *y; FILE *fp; if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */ fp = stdout; else fp = redirect((int)a[1], a[2]); for (x = a[0]; x != NULL; x = x->nnext) { y = execute(x); fputs((char *)getsval(y), fp); tempfree(y); if (x->nnext == NULL) fputs((char *)*ORS, fp); else fputs((char *)*OFS, fp); } if (a[1] != 0) fflush(fp); if (ferror(fp)) ERROR "write error on %s", filename(fp) FATAL; return(true); }
Cell *awkprintf(Node **a, int n) /* printf */ { /* a[0] is list of args, starting with format string */ /* a[1] is redirection operator, a[2] is redirection file */ FILE *fp; Cell *x; Node *y; char buf[3*RECSIZE]; y = a[0]->nnext; x = execute(a[0]); if (format(buf, sizeof buf, getsval(x), y) == -1) ERROR "printf string %.30s... too long", buf FATAL; tempfree(x); if (a[1] == NULL) { fputs((char *)buf, stdout); if (ferror(stdout)) ERROR "write error on stdout" FATAL; } else { fp = redirect((int)a[1], a[2]); fputs((char *)buf, fp); fflush(fp); if (ferror(fp)) ERROR "write error on %s", filename(fp) FATAL; } return(true); }
Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */ { Cell *x; for (;;) { x = execute(a[0]); if (isbreak(x)) return true; if (isnext(x) || isnextfile(x) || isexit(x) || isret(x)) return(x); tempfree(x); x = execute(a[1]); if (!istrue(x)) return(x); tempfree(x); } }
Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */ { Cell *x; for (;;) { x = execute(a[0]); if (!istrue(x)) return(x); tempfree(x); x = execute(a[1]); if (isbreak(x)) { x = true; return(x); } if (isnext(x) || isexit(x) || isret(x)) return(x); tempfree(x); } }
Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */ { Cell *y; switch (n) { case EXIT: if (a[0] != NULL) { y = execute(a[0]); errorflag = getfval(y); tempfree(y); } longjmp(env, 1); case RETURN: if (a[0] != NULL) { y = execute(a[0]); if ((y->tval & (STR|NUM)) == (STR|NUM)) { setsval(fp->retval, getsval(y)); fp->retval->fval = getfval(y); fp->retval->tval |= NUM; } else if (y->tval & STR) setsval(fp->retval, getsval(y)); else if (y->tval & NUM) setfval(fp->retval, getfval(y)); else /* can't happen */ ERROR "bad type variable %d", y->tval FATAL; tempfree(y); } return(jret); case NEXT: return(jnext); case NEXTFILE: nextfile(); return(jnextfile); case BREAK: return(jbreak); case CONTINUE: return(jcont); default: /* can't happen */ ERROR "illegal jump type %d", n FATAL; } return 0; /* not reached */ }
Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */ { Cell *x, *ap, *k; Node *p; char *buf; char *s; int bufsz = recsize; int nsub = strlen(*SUBSEP); ap = execute(a[1]); /* array name */ 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; for (p = a[0]; p; p = p->nnext) { x = execute(p); /* expr */ s = getsval(x); if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "intest")) FATAL("out of memory deleting %s[%s...]", x->nval, buf); strcat(buf, s); tempfree(x); if (p->nnext) strcat(buf, *SUBSEP); } k = lookup(buf, (Array *) ap->sval); tempfree(ap); free(buf); if (k == NULL) return(False); else return(True); }
Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ { Cell *x, *y, *z; char *s; Node *np; char *buf; int bufsz = recsize; int nsub = strlen(*SUBSEP); if ((buf = (char *) malloc(bufsz)) == NULL) FATAL("out of memory in array"); x = execute(a[0]); /* Cell* for symbol table */ buf[0] = 0; for (np = a[1]; np; np = np->nnext) { y = execute(np); /* subscript */ s = getsval(y); if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "array")) FATAL("out of memory for %s[%s...]", x->nval, buf); strcat(buf, s); if (np->nnext) strcat(buf, *SUBSEP); tempfree(y); } if (!isarr(x)) { dprintf( ("making %s into an array\n", NN(x->nval)) ); if (freeable(x)) xfree(x->sval); x->tval &= ~(STR|NUM|DONTFREE); x->tval |= ARR; x->sval = (char *) makesymtab(NSYMTAB); } z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval); z->ctype = OCELL; z->csub = CVAR; tempfree(x); free(buf); return(z); }
Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */ { Cell *x; int pair; pair = (int) a[3]; if (pairstack[pair] == 0) { x = execute(a[0]); if (istrue(x)) pairstack[pair] = 1; tempfree(x); } if (pairstack[pair] == 1) { x = execute(a[1]); if (istrue(x)) pairstack[pair] = 0; tempfree(x); x = execute(a[2]); return(x); } return(false); }
Cell *matchop(Node **a, int n) /* ~ and match() */ { Cell *x, *y; char *s, *t; int i; fa *pfa; int (*mf)(fa *, char *) = match, mode = 0; if (n == MATCHFCN) { mf = pmatch; mode = 1; } x = execute(a[1]); /* a[1] = target text */ s = getsval(x); if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */ i = (*mf)((fa *) a[2], s); else { y = execute(a[2]); /* a[2] = regular expr */ t = getsval(y); pfa = makedfa(t, mode); i = (*mf)(pfa, s); tempfree(y); } tempfree(x); if (n == MATCHFCN) { int start = patbeg - s + 1; if (patlen < 0) start = 0; setfval(rstartloc, (Awkfloat) start); setfval(rlengthloc, (Awkfloat) patlen); x = gettemp(); x->tval = NUM; x->fval = start; return x; } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0)) return(true); else return(false); }
Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */ { Cell *x; x = execute(a[0]); tempfree(x); for (;;) { if (a[1]!=0) { x = execute(a[1]); if (!istrue(x)) return(x); else tempfree(x); } x = execute(a[3]); if (isbreak(x)) /* turn off break */ return true; if (isnext(x) || isexit(x) || isret(x)) return(x); tempfree(x); x = execute(a[2]); tempfree(x); } }