123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- /****************************************************************
- Copyright (C) Lucent Technologies 1997
- All Rights Reserved
- Permission to use, copy, modify, and distribute this software and
- its documentation for any purpose and without fee is hereby
- granted, provided that the above copyright notice appear in all
- copies and that both that the copyright notice and this
- permission notice and warranty disclaimer appear in supporting
- documentation, and that the name Lucent Technologies or any of
- its entities not be used in advertising or publicity pertaining
- to distribution of the software without specific, written prior
- permission.
- LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
- IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
- SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
- IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
- THIS SOFTWARE.
- ****************************************************************/
- #define DEBUG
- #include <stdio.h>
- #include <math.h>
- #include <ctype.h>
- #include <string.h>
- #include <stdlib.h>
- #include "awk.h"
- #include "y.tab.h"
- #define FULLTAB 2 /* rehash when table gets this x full */
- #define GROWTAB 4 /* grow table by this factor */
- Array *symtab; /* main symbol table */
- char **FS; /* initial field sep */
- char **RS; /* initial record sep */
- char **OFS; /* output field sep */
- char **ORS; /* output record sep */
- char **OFMT; /* output format for numbers */
- char **CONVFMT; /* format for conversions in getsval */
- Awkfloat *NF; /* number of fields in current record */
- Awkfloat *NR; /* number of current record */
- Awkfloat *FNR; /* number of current record in current file */
- char **FILENAME; /* current filename argument */
- Awkfloat *ARGC; /* number of arguments from command line */
- char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
- Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
- Awkfloat *RLENGTH; /* length of same */
- Cell *nrloc; /* NR */
- Cell *nfloc; /* NF */
- Cell *fnrloc; /* FNR */
- Array *ARGVtab; /* symbol table containing ARGV[...] */
- Array *ENVtab; /* symbol table containing ENVIRON[...] */
- Cell *rstartloc; /* RSTART */
- Cell *rlengthloc; /* RLENGTH */
- Cell *symtabloc; /* SYMTAB */
- Cell *nullloc; /* a guaranteed empty cell */
- Node *nullnode; /* zero&null, converted into a node for comparisons */
- Cell *literal0;
- extern Cell **fldtab;
- void syminit(void) /* initialize symbol table with builtin vars */
- {
- literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
- /* this is used for if(x)... tests: */
- nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
- nullnode = celltonode(nullloc, CCON);
- FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
- RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
- OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
- ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
- OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
- CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
- FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
- nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
- NF = &nfloc->fval;
- nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
- NR = &nrloc->fval;
- fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
- FNR = &fnrloc->fval;
- SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
- rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
- RSTART = &rstartloc->fval;
- rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
- RLENGTH = &rlengthloc->fval;
- symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
- symtabloc->sval = (char *) symtab;
- }
- void arginit(int ac, char **av) /* set up ARGV and ARGC */
- {
- Cell *cp;
- int i;
- char temp[50];
- ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
- cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
- ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
- cp->sval = (char *) ARGVtab;
- for (i = 0; i < ac; i++) {
- sprintf(temp, "%d", i);
- if (is_number(*av))
- setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
- else
- setsymtab(temp, *av, 0.0, STR, ARGVtab);
- av++;
- }
- }
- void envinit(char **envp) /* set up ENVIRON variable */
- {
- Cell *cp;
- char *p;
- cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
- ENVtab = makesymtab(NSYMTAB);
- cp->sval = (char *) ENVtab;
- for ( ; *envp; envp++) {
- if ((p = strchr(*envp, '=')) == NULL)
- continue;
- *p++ = 0; /* split into two strings at = */
- if (is_number(p))
- setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
- else
- setsymtab(*envp, p, 0.0, STR, ENVtab);
- p[-1] = '='; /* restore in case env is passed down to a shell */
- }
- }
- Array *makesymtab(int n) /* make a new symbol table */
- {
- Array *ap;
- Cell **tp;
- ap = (Array *) malloc(sizeof(Array));
- tp = (Cell **) calloc(n, sizeof(Cell *));
- if (ap == NULL || tp == NULL)
- FATAL("out of space in makesymtab");
- ap->nelem = 0;
- ap->size = n;
- ap->tab = tp;
- return(ap);
- }
- void freesymtab(Cell *ap) /* free a symbol table */
- {
- Cell *cp, *temp;
- Array *tp;
- int i;
- if (!isarr(ap))
- return;
- tp = (Array *) ap->sval;
- if (tp == NULL)
- return;
- for (i = 0; i < tp->size; i++) {
- for (cp = tp->tab[i]; cp != NULL; cp = temp) {
- xfree(cp->nval);
- if (freeable(cp))
- xfree(cp->sval);
- temp = cp->cnext; /* avoids freeing then using */
- free(cp);
- }
- tp->tab[i] = 0;
- }
- free(tp->tab);
- free(tp);
- }
- void freeelem(Cell *ap, char *s) /* free elem s from ap (i.e., ap["s"] */
- {
- Array *tp;
- Cell *p, *prev = NULL;
- int h;
-
- tp = (Array *) ap->sval;
- h = hash(s, tp->size);
- for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
- if (strcmp(s, p->nval) == 0) {
- if (prev == NULL) /* 1st one */
- tp->tab[h] = p->cnext;
- else /* middle somewhere */
- prev->cnext = p->cnext;
- if (freeable(p))
- xfree(p->sval);
- free(p->nval);
- free(p);
- tp->nelem--;
- return;
- }
- }
- Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp)
- {
- int h;
- Cell *p;
- if (n != NULL && (p = lookup(n, tp)) != NULL) {
- dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
- p, p->nval, p->sval, p->fval, p->tval) );
- return(p);
- }
- p = (Cell *) malloc(sizeof(Cell));
- if (p == NULL)
- FATAL("out of space for symbol table at %s", n);
- p->nval = tostring(n);
- p->sval = s ? tostring(s) : tostring("");
- p->fval = f;
- p->tval = t;
- p->csub = CUNK;
- p->ctype = OCELL;
- tp->nelem++;
- if (tp->nelem > FULLTAB * tp->size)
- rehash(tp);
- h = hash(n, tp->size);
- p->cnext = tp->tab[h];
- tp->tab[h] = p;
- dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
- p, p->nval, p->sval, p->fval, p->tval) );
- return(p);
- }
- int hash(char *s, int n) /* form hash value for string s */
- {
- unsigned hashval;
- for (hashval = 0; *s != '\0'; s++)
- hashval = (*s + 31 * hashval);
- return hashval % n;
- }
- void rehash(Array *tp) /* rehash items in small table into big one */
- {
- int i, nh, nsz;
- Cell *cp, *op, **np;
- nsz = GROWTAB * tp->size;
- np = (Cell **) calloc(nsz, sizeof(Cell *));
- if (np == NULL) /* can't do it, but can keep running. */
- return; /* someone else will run out later. */
- for (i = 0; i < tp->size; i++) {
- for (cp = tp->tab[i]; cp; cp = op) {
- op = cp->cnext;
- nh = hash(cp->nval, nsz);
- cp->cnext = np[nh];
- np[nh] = cp;
- }
- }
- free(tp->tab);
- tp->tab = np;
- tp->size = nsz;
- }
- Cell *lookup(char *s, Array *tp) /* look for s in tp */
- {
- Cell *p;
- int h;
- h = hash(s, tp->size);
- for (p = tp->tab[h]; p != NULL; p = p->cnext)
- if (strcmp(s, p->nval) == 0)
- return(p); /* found it */
- return(NULL); /* not found */
- }
- Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
- {
- int fldno;
- if ((vp->tval & (NUM | STR)) == 0)
- funnyvar(vp, "assign to");
- if (isfld(vp)) {
- donerec = 0; /* mark $0 invalid */
- fldno = atoi(vp->nval);
- if (fldno > *NF)
- newfld(fldno);
- dprintf( ("setting field %d to %g\n", fldno, f) );
- } else if (isrec(vp)) {
- donefld = 0; /* mark $1... invalid */
- donerec = 1;
- }
- if (freeable(vp))
- xfree(vp->sval); /* free any previous string */
- vp->tval &= ~STR; /* mark string invalid */
- vp->tval |= NUM; /* mark number ok */
- dprintf( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
- return vp->fval = f;
- }
- void funnyvar(Cell *vp, char *rw)
- {
- if (isarr(vp))
- FATAL("can't %s %s; it's an array name.", rw, vp->nval);
- if (vp->tval & FCN)
- FATAL("can't %s %s; it's a function.", rw, vp->nval);
- WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
- vp, vp->nval, vp->sval, vp->fval, vp->tval);
- }
- char *setsval(Cell *vp, char *s) /* set string val of a Cell */
- {
- char *t;
- int fldno;
- dprintf( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
- if ((vp->tval & (NUM | STR)) == 0)
- funnyvar(vp, "assign to");
- if (isfld(vp)) {
- donerec = 0; /* mark $0 invalid */
- fldno = atoi(vp->nval);
- if (fldno > *NF)
- newfld(fldno);
- dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
- } else if (isrec(vp)) {
- donefld = 0; /* mark $1... invalid */
- donerec = 1;
- }
- t = tostring(s); /* in case it's self-assign */
- vp->tval &= ~NUM;
- vp->tval |= STR;
- if (freeable(vp))
- xfree(vp->sval);
- vp->tval &= ~DONTFREE;
- dprintf( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) );
- return(vp->sval = t);
- }
- Awkfloat getfval(Cell *vp) /* get float val of a Cell */
- {
- if ((vp->tval & (NUM | STR)) == 0)
- funnyvar(vp, "read value of");
- if (isfld(vp) && donefld == 0)
- fldbld();
- else if (isrec(vp) && donerec == 0)
- recbld();
- if (!isnum(vp)) { /* not a number */
- vp->fval = atof(vp->sval); /* best guess */
- if (is_number(vp->sval) && !(vp->tval&CON))
- vp->tval |= NUM; /* make NUM only sparingly */
- }
- dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
- return(vp->fval);
- }
- char *getsval(Cell *vp) /* get string val of a Cell */
- {
- char s[100]; /* BUG: unchecked */
- double dtemp;
- if ((vp->tval & (NUM | STR)) == 0)
- funnyvar(vp, "read value of");
- if (isfld(vp) && donefld == 0)
- fldbld();
- else if (isrec(vp) && donerec == 0)
- recbld();
- if (isstr(vp) == 0) {
- if (freeable(vp))
- xfree(vp->sval);
- if (modf(vp->fval, &dtemp) == 0) /* it's integral */
- sprintf(s, "%.30g", vp->fval);
- else
- sprintf(s, *CONVFMT, vp->fval);
- vp->sval = tostring(s);
- vp->tval &= ~DONTFREE;
- vp->tval |= STR;
- }
- dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) );
- return(vp->sval);
- }
- char *tostring(char *s) /* make a copy of string s */
- {
- char *p;
- p = (char *) malloc(strlen(s)+1);
- if (p == NULL)
- FATAL("out of space in tostring on %s", s);
- strcpy(p, s);
- return(p);
- }
- char *qstring(char *s, int delim) /* collect string up to next delim */
- {
- char *os = s;
- int c, n;
- char *buf, *bp;
- if ((buf = (char *) malloc(strlen(s)+3)) == NULL)
- FATAL( "out of space in qstring(%s)", s);
- for (bp = buf; (c = *s) != delim; s++) {
- if (c == '\n')
- SYNTAX( "newline in string %.20s...", os );
- else if (c != '\\')
- *bp++ = c;
- else { /* \something */
- c = *++s;
- if (c == 0) { /* \ at end */
- *bp++ = '\\';
- break; /* for loop */
- }
- switch (c) {
- case '\\': *bp++ = '\\'; break;
- case 'n': *bp++ = '\n'; break;
- case 't': *bp++ = '\t'; break;
- case 'b': *bp++ = '\b'; break;
- case 'f': *bp++ = '\f'; break;
- case 'r': *bp++ = '\r'; break;
- default:
- if (!isdigit(c)) {
- *bp++ = c;
- break;
- }
- n = c - '0';
- if (isdigit(s[1])) {
- n = 8 * n + *++s - '0';
- if (isdigit(s[1]))
- n = 8 * n + *++s - '0';
- }
- *bp++ = n;
- break;
- }
- }
- }
- *bp++ = 0;
- return buf;
- }
|