165394Sbostic /****************************************************************
265394Sbostic Copyright (C) AT&T 1993
365394Sbostic All Rights Reserved
465394Sbostic
565394Sbostic Permission to use, copy, modify, and distribute this software and
665394Sbostic its documentation for any purpose and without fee is hereby
765394Sbostic granted, provided that the above copyright notice appear in all
865394Sbostic copies and that both that the copyright notice and this
965394Sbostic permission notice and warranty disclaimer appear in supporting
1065394Sbostic documentation, and that the name of AT&T or any of its entities
1165394Sbostic not be used in advertising or publicity pertaining to
1265394Sbostic distribution of the software without specific, written prior
1365394Sbostic permission.
1465394Sbostic
1565394Sbostic AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1665394Sbostic INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1765394Sbostic IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
1865394Sbostic SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1965394Sbostic WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
2065394Sbostic IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2165394Sbostic ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
2265394Sbostic THIS SOFTWARE.
2365394Sbostic ****************************************************************/
2465394Sbostic
2565394Sbostic #define DEBUG
2665394Sbostic #include <stdio.h>
2765394Sbostic #include <math.h>
2865394Sbostic #include <ctype.h>
2965394Sbostic #include <string.h>
3065394Sbostic #include <stdlib.h>
3165394Sbostic #include "awk.h"
3265394Sbostic #include "y.tab.h"
3365394Sbostic
3465394Sbostic #define FULLTAB 2 /* rehash when table gets this x full */
3565394Sbostic #define GROWTAB 4 /* grow table by this factor */
3665394Sbostic
3765394Sbostic Array *symtab; /* main symbol table */
3865394Sbostic
3965394Sbostic uchar **FS; /* initial field sep */
4065394Sbostic uchar **RS; /* initial record sep */
4165394Sbostic uchar **OFS; /* output field sep */
4265394Sbostic uchar **ORS; /* output record sep */
4365394Sbostic uchar **OFMT; /* output format for numbers */
4465394Sbostic uchar **CONVFMT; /* format for conversions in getsval */
4565394Sbostic Awkfloat *NF; /* number of fields in current record */
4665394Sbostic Awkfloat *NR; /* number of current record */
4765394Sbostic Awkfloat *FNR; /* number of current record in current file */
4865394Sbostic uchar **FILENAME; /* current filename argument */
4965394Sbostic Awkfloat *ARGC; /* number of arguments from command line */
5065394Sbostic uchar **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
5165394Sbostic Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
5265394Sbostic Awkfloat *RLENGTH; /* length of same */
5365394Sbostic
5465394Sbostic Cell *recloc; /* location of record */
5565394Sbostic Cell *nrloc; /* NR */
5665394Sbostic Cell *nfloc; /* NF */
5765394Sbostic Cell *fnrloc; /* FNR */
5865394Sbostic Array *ARGVtab; /* symbol table containing ARGV[...] */
5965394Sbostic Array *ENVtab; /* symbol table containing ENVIRON[...] */
6065394Sbostic Cell *rstartloc; /* RSTART */
6165394Sbostic Cell *rlengthloc; /* RLENGTH */
6265394Sbostic Cell *symtabloc; /* SYMTAB */
6365394Sbostic
6465394Sbostic Cell *nullloc; /* a guaranteed empty cell */
6565394Sbostic Node *nullnode; /* zero&null, converted into a node for comparisons */
6665394Sbostic
6765394Sbostic extern Cell *fldtab;
6865394Sbostic
syminit(void)6965394Sbostic void syminit(void) /* initialize symbol table with builtin vars */
7065394Sbostic {
7165394Sbostic setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
7265394Sbostic /* this is used for if(x)... tests: */
7365394Sbostic nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
7465394Sbostic nullnode = valtonode(nullloc, CCON);
7565394Sbostic
7665394Sbostic /* recloc = setsymtab("$0", record, 0.0, REC|STR|DONTFREE, symtab); */
7765394Sbostic /* has been done elsewhere */
7865394Sbostic recloc = &fldtab[0];
7965394Sbostic FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
8065394Sbostic RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
8165394Sbostic OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
8265394Sbostic ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
8365394Sbostic OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
8465394Sbostic CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
8565394Sbostic FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
8665394Sbostic nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
8765394Sbostic NF = &nfloc->fval;
8865394Sbostic nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
8965394Sbostic NR = &nrloc->fval;
9065394Sbostic fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
9165394Sbostic FNR = &fnrloc->fval;
9265394Sbostic SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
9365394Sbostic rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
9465394Sbostic RSTART = &rstartloc->fval;
9565394Sbostic rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
9665394Sbostic RLENGTH = &rlengthloc->fval;
9765394Sbostic symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
9865394Sbostic symtabloc->sval = (uchar *) symtab;
9965394Sbostic }
10065394Sbostic
arginit(int ac,uchar * av[])10165394Sbostic void arginit(int ac, uchar *av[]) /* set up ARGV and ARGC */
10265394Sbostic {
10365394Sbostic Cell *cp;
10465394Sbostic int i;
10565394Sbostic uchar temp[5];
10665394Sbostic
10765394Sbostic ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
10865394Sbostic cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
10965394Sbostic ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
11065394Sbostic cp->sval = (uchar *) ARGVtab;
11165394Sbostic for (i = 0; i < ac; i++) {
11265394Sbostic sprintf((char *)temp, "%d", i);
113*65396Sbostic if (is_a_number(*av))
11465394Sbostic setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
11565394Sbostic else
11665394Sbostic setsymtab(temp, *av, 0.0, STR, ARGVtab);
11765394Sbostic av++;
11865394Sbostic }
11965394Sbostic }
12065394Sbostic
envinit(uchar ** envp)12165394Sbostic void envinit(uchar **envp) /* set up ENVIRON variable */
12265394Sbostic {
12365394Sbostic Cell *cp;
12465394Sbostic uchar *p;
12565394Sbostic
12665394Sbostic cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
12765394Sbostic ENVtab = makesymtab(NSYMTAB);
12865394Sbostic cp->sval = (uchar *) ENVtab;
12965394Sbostic for ( ; *envp; envp++) {
13065394Sbostic if ((p = (uchar *) strchr((char *) *envp, '=')) == NULL)
13165394Sbostic continue;
13265394Sbostic *p++ = 0; /* split into two strings at = */
133*65396Sbostic if (is_a_number(p))
13465394Sbostic setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
13565394Sbostic else
13665394Sbostic setsymtab(*envp, p, 0.0, STR, ENVtab);
13765394Sbostic p[-1] = '='; /* restore in case env is passed down to a shell */
13865394Sbostic }
13965394Sbostic }
14065394Sbostic
makesymtab(int n)14165394Sbostic Array *makesymtab(int n) /* make a new symbol table */
14265394Sbostic {
14365394Sbostic Array *ap;
14465394Sbostic Cell **tp;
14565394Sbostic
14665394Sbostic ap = (Array *) malloc(sizeof(Array));
14765394Sbostic tp = (Cell **) calloc(n, sizeof(Cell *));
14865394Sbostic if (ap == NULL || tp == NULL)
14965394Sbostic ERROR "out of space in makesymtab" FATAL;
15065394Sbostic ap->nelem = 0;
15165394Sbostic ap->size = n;
15265394Sbostic ap->tab = tp;
15365394Sbostic return(ap);
15465394Sbostic }
15565394Sbostic
freesymtab(Cell * ap)15665394Sbostic void freesymtab(Cell *ap) /* free a symbol table */
15765394Sbostic {
15865394Sbostic Cell *cp, *temp;
15965394Sbostic Array *tp;
16065394Sbostic int i;
16165394Sbostic
16265394Sbostic if (!isarr(ap))
16365394Sbostic return;
16465394Sbostic tp = (Array *) ap->sval;
16565394Sbostic if (tp == NULL)
16665394Sbostic return;
16765394Sbostic for (i = 0; i < tp->size; i++) {
16865394Sbostic for (cp = tp->tab[i]; cp != NULL; cp = temp) {
16965394Sbostic xfree(cp->nval);
17065394Sbostic if (freeable(cp))
17165394Sbostic xfree(cp->sval);
17265394Sbostic temp = cp->cnext; /* avoids freeing then using */
17365394Sbostic free((char *) cp);
17465394Sbostic }
17565394Sbostic }
17665394Sbostic free((char *) (tp->tab));
17765394Sbostic free((char *) tp);
17865394Sbostic }
17965394Sbostic
freeelem(Cell * ap,uchar * s)18065394Sbostic void freeelem(Cell *ap, uchar *s) /* free elem s from ap (i.e., ap["s"] */
18165394Sbostic {
18265394Sbostic Array *tp;
18365394Sbostic Cell *p, *prev = NULL;
18465394Sbostic int h;
18565394Sbostic
18665394Sbostic tp = (Array *) ap->sval;
18765394Sbostic h = hash(s, tp->size);
18865394Sbostic for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
18965394Sbostic if (strcmp((char *) s, (char *) p->nval) == 0) {
19065394Sbostic if (prev == NULL) /* 1st one */
19165394Sbostic tp->tab[h] = p->cnext;
19265394Sbostic else /* middle somewhere */
19365394Sbostic prev->cnext = p->cnext;
19465394Sbostic if (freeable(p))
19565394Sbostic xfree(p->sval);
19665394Sbostic free(p->nval);
19765394Sbostic free((char *) p);
19865394Sbostic tp->nelem--;
19965394Sbostic return;
20065394Sbostic }
20165394Sbostic }
20265394Sbostic
setsymtab(uchar * n,uchar * s,Awkfloat f,unsigned t,Array * tp)20365394Sbostic Cell *setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned t, Array *tp)
20465394Sbostic {
20565394Sbostic register int h;
20665394Sbostic register Cell *p;
20765394Sbostic
20865394Sbostic if (n != NULL && (p = lookup(n, tp)) != NULL) {
20965394Sbostic dprintf( ("setsymtab found %o: n=%s s=\"%s\" f=%g t=%o\n",
21065394Sbostic p, p->nval, p->sval, p->fval, p->tval) );
21165394Sbostic return(p);
21265394Sbostic }
21365394Sbostic p = (Cell *) malloc(sizeof(Cell));
21465394Sbostic if (p == NULL)
21565394Sbostic ERROR "out of space for symbol table at %s", n FATAL;
21665394Sbostic p->nval = tostring(n);
21765394Sbostic p->sval = s ? tostring(s) : tostring("");
21865394Sbostic p->fval = f;
21965394Sbostic p->tval = t;
22065394Sbostic tp->nelem++;
22165394Sbostic if (tp->nelem > FULLTAB * tp->size)
22265394Sbostic rehash(tp);
22365394Sbostic h = hash(n, tp->size);
22465394Sbostic p->cnext = tp->tab[h];
22565394Sbostic tp->tab[h] = p;
22665394Sbostic dprintf( ("setsymtab set %o: n=%s s=\"%s\" f=%g t=%o\n",
22765394Sbostic p, p->nval, p->sval, p->fval, p->tval) );
22865394Sbostic return(p);
22965394Sbostic }
23065394Sbostic
hash(uchar * s,int n)23165394Sbostic hash(uchar *s, int n) /* form hash value for string s */
23265394Sbostic {
23365394Sbostic register unsigned hashval;
23465394Sbostic
23565394Sbostic for (hashval = 0; *s != '\0'; s++)
23665394Sbostic hashval = (*s + 31 * hashval);
23765394Sbostic return hashval % n;
23865394Sbostic }
23965394Sbostic
rehash(Array * tp)24065394Sbostic void rehash(Array *tp) /* rehash items in small table into big one */
24165394Sbostic {
24265394Sbostic int i, nh, nsz;
24365394Sbostic Cell *cp, *op, **np;
24465394Sbostic
24565394Sbostic nsz = GROWTAB * tp->size;
24665394Sbostic np = (Cell **) calloc(nsz, sizeof(Cell *));
24765394Sbostic if (np == NULL) /* can't do it, but can keep running. */
24865394Sbostic return; /* someone else will run out later. */
24965394Sbostic for (i = 0; i < tp->size; i++) {
25065394Sbostic for (cp = tp->tab[i]; cp; cp = op) {
25165394Sbostic op = cp->cnext;
25265394Sbostic nh = hash(cp->nval, nsz);
25365394Sbostic cp->cnext = np[nh];
25465394Sbostic np[nh] = cp;
25565394Sbostic }
25665394Sbostic }
25765394Sbostic free((char *) (tp->tab));
25865394Sbostic tp->tab = np;
25965394Sbostic tp->size = nsz;
26065394Sbostic }
26165394Sbostic
lookup(uchar * s,Array * tp)26265394Sbostic Cell *lookup(uchar *s, Array *tp) /* look for s in tp */
26365394Sbostic {
26465394Sbostic register Cell *p, *prev = NULL;
26565394Sbostic int h;
26665394Sbostic
26765394Sbostic h = hash(s, tp->size);
26865394Sbostic for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
26965394Sbostic if (strcmp((char *) s, (char *) p->nval) == 0)
27065394Sbostic return(p); /* found it */
27165394Sbostic return(NULL); /* not found */
27265394Sbostic }
27365394Sbostic
setfval(Cell * vp,Awkfloat f)27465394Sbostic Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
27565394Sbostic {
27665394Sbostic if ((vp->tval & (NUM | STR)) == 0)
27765394Sbostic funnyvar(vp, "assign to");
27865394Sbostic if (vp->tval & FLD) {
27965394Sbostic donerec = 0; /* mark $0 invalid */
28065394Sbostic if (vp-fldtab > *NF)
28165394Sbostic newfld(vp-fldtab);
28265394Sbostic dprintf( ("setting field %d to %g\n", vp-fldtab, f) );
28365394Sbostic } else if (vp->tval & REC) {
28465394Sbostic donefld = 0; /* mark $1... invalid */
28565394Sbostic donerec = 1;
28665394Sbostic }
28765394Sbostic vp->tval &= ~STR; /* mark string invalid */
28865394Sbostic vp->tval |= NUM; /* mark number ok */
28965394Sbostic dprintf( ("setfval %o: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
29065394Sbostic return vp->fval = f;
29165394Sbostic }
29265394Sbostic
funnyvar(Cell * vp,char * rw)29365394Sbostic void funnyvar(Cell *vp, char *rw)
29465394Sbostic {
29565394Sbostic if (vp->tval & ARR)
29665394Sbostic ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
29765394Sbostic if (vp->tval & FCN)
29865394Sbostic ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
29965394Sbostic ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o",
30065394Sbostic vp, vp->nval, vp->sval, vp->fval, vp->tval WARNING;
30165394Sbostic }
30265394Sbostic
setsval(Cell * vp,uchar * s)30365394Sbostic uchar *setsval(Cell *vp, uchar *s) /* set string val of a Cell */
30465394Sbostic {
30565394Sbostic if ((vp->tval & (NUM | STR)) == 0)
30665394Sbostic funnyvar(vp, "assign to");
30765394Sbostic if (vp->tval & FLD) {
30865394Sbostic donerec = 0; /* mark $0 invalid */
30965394Sbostic if (vp-fldtab > *NF)
31065394Sbostic newfld(vp-fldtab);
31165394Sbostic dprintf( ("setting field %d to %s\n", vp-fldtab, s) );
31265394Sbostic } else if (vp->tval & REC) {
31365394Sbostic donefld = 0; /* mark $1... invalid */
31465394Sbostic donerec = 1;
31565394Sbostic }
31665394Sbostic vp->tval &= ~NUM;
31765394Sbostic vp->tval |= STR;
31865394Sbostic if (freeable(vp))
31965394Sbostic xfree(vp->sval);
32065394Sbostic vp->tval &= ~DONTFREE;
32165394Sbostic dprintf( ("setsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
32265394Sbostic return(vp->sval = tostring(s));
32365394Sbostic }
32465394Sbostic
r_getfval(Cell * vp)32565394Sbostic Awkfloat r_getfval(Cell *vp) /* get float val of a Cell */
32665394Sbostic {
32765394Sbostic if ((vp->tval & (NUM | STR)) == 0)
32865394Sbostic funnyvar(vp, "read value of");
32965394Sbostic if ((vp->tval & FLD) && donefld == 0)
33065394Sbostic fldbld();
33165394Sbostic else if ((vp->tval & REC) && donerec == 0)
33265394Sbostic recbld();
33365394Sbostic if (!isnum(vp)) { /* not a number */
33465394Sbostic vp->fval = atof(vp->sval); /* best guess */
335*65396Sbostic if (is_a_number(vp->sval) && !(vp->tval&CON))
33665394Sbostic vp->tval |= NUM; /* make NUM only sparingly */
33765394Sbostic }
33865394Sbostic dprintf( ("getfval %o: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
33965394Sbostic return(vp->fval);
34065394Sbostic }
34165394Sbostic
r_getsval(Cell * vp)34265394Sbostic uchar *r_getsval(Cell *vp) /* get string val of a Cell */
34365394Sbostic {
34465394Sbostic uchar s[100];
34565394Sbostic double dtemp;
34665394Sbostic
34765394Sbostic if ((vp->tval & (NUM | STR)) == 0)
34865394Sbostic funnyvar(vp, "read value of");
34965394Sbostic if ((vp->tval & FLD) && donefld == 0)
35065394Sbostic fldbld();
35165394Sbostic else if ((vp->tval & REC) && donerec == 0)
35265394Sbostic recbld();
35365394Sbostic if ((vp->tval & STR) == 0) {
35465394Sbostic if (!(vp->tval&DONTFREE))
35565394Sbostic xfree(vp->sval);
35665394Sbostic if (modf(vp->fval, &dtemp) == 0) /* it's integral */
35765394Sbostic sprintf((char *)s, "%.20g", vp->fval);
35865394Sbostic else
35965394Sbostic sprintf((char *)s, (char *)*CONVFMT, vp->fval);
36065394Sbostic vp->sval = tostring(s);
36165394Sbostic vp->tval &= ~DONTFREE;
36265394Sbostic vp->tval |= STR;
36365394Sbostic }
36465394Sbostic dprintf( ("getsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, vp->sval, vp->tval) );
36565394Sbostic return(vp->sval);
36665394Sbostic }
36765394Sbostic
tostring(uchar * s)36865394Sbostic uchar *tostring(uchar *s) /* make a copy of string s */
36965394Sbostic {
37065394Sbostic register uchar *p;
37165394Sbostic
37265394Sbostic p = (uchar *) malloc(strlen((char *) s)+1);
37365394Sbostic if (p == NULL)
37465394Sbostic ERROR "out of space in tostring on %s", s FATAL;
37565394Sbostic strcpy((char *) p, (char *) s);
37665394Sbostic return(p);
37765394Sbostic }
37865394Sbostic
qstring(uchar * s,int delim)37965394Sbostic uchar *qstring(uchar *s, int delim) /* collect string up to next delim */
38065394Sbostic {
38165394Sbostic uchar *q;
38265394Sbostic int c, n;
38365394Sbostic
38465394Sbostic for (q = cbuf; (c = *s) != delim; s++) {
38565394Sbostic if (q >= cbuf + CBUFLEN - 1)
38665394Sbostic ERROR "string %.10s... too long", cbuf SYNTAX;
38765394Sbostic else if (c == '\n')
38865394Sbostic ERROR "newline in string %.10s...", cbuf SYNTAX;
38965394Sbostic else if (c != '\\')
39065394Sbostic *q++ = c;
39165394Sbostic else /* \something */
39265394Sbostic switch (c = *++s) {
39365394Sbostic case '\\': *q++ = '\\'; break;
39465394Sbostic case 'n': *q++ = '\n'; break;
39565394Sbostic case 't': *q++ = '\t'; break;
39665394Sbostic case 'b': *q++ = '\b'; break;
39765394Sbostic case 'f': *q++ = '\f'; break;
39865394Sbostic case 'r': *q++ = '\r'; break;
39965394Sbostic default:
40065394Sbostic if (!isdigit(c)) {
40165394Sbostic *q++ = c;
40265394Sbostic break;
40365394Sbostic }
40465394Sbostic n = c - '0';
40565394Sbostic if (isdigit(s[1])) {
40665394Sbostic n = 8 * n + *++s - '0';
40765394Sbostic if (isdigit(s[1]))
40865394Sbostic n = 8 * n + *++s - '0';
40965394Sbostic }
41065394Sbostic *q++ = n;
41165394Sbostic break;
41265394Sbostic }
41365394Sbostic }
41465394Sbostic *q = '\0';
41565394Sbostic return cbuf;
41665394Sbostic }
417