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 ****************************************************************/
34 #define FULLTAB 2 /* rehash when table gets this x full */
35 #define GROWTAB 4 /* grow table by this factor */
37 Array *symtab; /* main symbol table */
39 char **FS; /* initial field sep */
40 char **RS; /* initial record sep */
41 char **OFS; /* output field sep */
42 char **ORS; /* output record sep */
43 char **OFMT; /* output format for numbers */
44 char **CONVFMT; /* format for conversions in getsval */
45 Awkfloat *NF; /* number of fields in current record */
46 Awkfloat *NR; /* number of current record */
47 Awkfloat *FNR; /* number of current record in current file */
48 char **FILENAME; /* current filename argument */
49 Awkfloat *ARGC; /* number of arguments from command line */
50 char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
51 Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
52 Awkfloat *RLENGTH; /* length of same */
56 Cell *fnrloc; /* FNR */
57 Array *ARGVtab; /* symbol table containing ARGV[...] */
58 Array *ENVtab; /* symbol table containing ENVIRON[...] */
59 Cell *rstartloc; /* RSTART */
60 Cell *rlengthloc; /* RLENGTH */
61 Cell *symtabloc; /* SYMTAB */
63 Cell *nullloc; /* a guaranteed empty cell */
64 Node *nullnode; /* zero&null, converted into a node for comparisons */
69 void syminit(void) /* initialize symbol table with builtin vars */
71 literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
72 /* this is used for if(x)... tests: */
73 nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
74 nullnode = celltonode(nullloc, CCON);
76 FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
77 RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
78 OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
79 ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
80 OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
81 CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
82 FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
83 nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
85 nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
87 fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
89 SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
90 rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
91 RSTART = &rstartloc->fval;
92 rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
93 RLENGTH = &rlengthloc->fval;
94 symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
95 symtabloc->sval = (char *) symtab;
98 void arginit(int ac, char **av) /* set up ARGV and ARGC */
104 ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
105 cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
106 ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
107 cp->sval = (char *) ARGVtab;
108 for (i = 0; i < ac; i++) {
109 sprintf(temp, "%d", i);
111 setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
113 setsymtab(temp, *av, 0.0, STR, ARGVtab);
118 void envinit(char **envp) /* set up ENVIRON variable */
123 cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
124 ENVtab = makesymtab(NSYMTAB);
125 cp->sval = (char *) ENVtab;
126 for ( ; *envp; envp++) {
127 if ((p = strchr(*envp, '=')) == NULL)
129 *p++ = 0; /* split into two strings at = */
131 setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
133 setsymtab(*envp, p, 0.0, STR, ENVtab);
134 p[-1] = '='; /* restore in case env is passed down to a shell */
138 Array *makesymtab(int n) /* make a new symbol table */
143 ap = (Array *) malloc(sizeof(Array));
144 tp = (Cell **) calloc(n, sizeof(Cell *));
145 if (ap == NULL || tp == NULL)
146 FATAL("out of space in makesymtab");
153 void freesymtab(Cell *ap) /* free a symbol table */
161 tp = (Array *) ap->sval;
164 for (i = 0; i < tp->size; i++) {
165 for (cp = tp->tab[i]; cp != NULL; cp = temp) {
169 temp = cp->cnext; /* avoids freeing then using */
178 void freeelem(Cell *ap, char *s) /* free elem s from ap (i.e., ap["s"] */
181 Cell *p, *prev = NULL;
184 tp = (Array *) ap->sval;
185 h = hash(s, tp->size);
186 for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
187 if (strcmp(s, p->nval) == 0) {
188 if (prev == NULL) /* 1st one */
189 tp->tab[h] = p->cnext;
190 else /* middle somewhere */
191 prev->cnext = p->cnext;
201 Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp)
206 if (n != NULL && (p = lookup(n, tp)) != NULL) {
207 dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
208 p, p->nval, p->sval, p->fval, p->tval) );
211 p = (Cell *) malloc(sizeof(Cell));
213 FATAL("out of space for symbol table at %s", n);
214 p->nval = tostring(n);
215 p->sval = s ? tostring(s) : tostring("");
221 if (tp->nelem > FULLTAB * tp->size)
223 h = hash(n, tp->size);
224 p->cnext = tp->tab[h];
226 dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
227 p, p->nval, p->sval, p->fval, p->tval) );
231 int hash(char *s, int n) /* form hash value for string s */
235 for (hashval = 0; *s != '\0'; s++)
236 hashval = (*s + 31 * hashval);
240 void rehash(Array *tp) /* rehash items in small table into big one */
245 nsz = GROWTAB * tp->size;
246 np = (Cell **) calloc(nsz, sizeof(Cell *));
247 if (np == NULL) /* can't do it, but can keep running. */
248 return; /* someone else will run out later. */
249 for (i = 0; i < tp->size; i++) {
250 for (cp = tp->tab[i]; cp; cp = op) {
252 nh = hash(cp->nval, nsz);
262 Cell *lookup(char *s, Array *tp) /* look for s in tp */
267 h = hash(s, tp->size);
268 for (p = tp->tab[h]; p != NULL; p = p->cnext)
269 if (strcmp(s, p->nval) == 0)
270 return(p); /* found it */
271 return(NULL); /* not found */
274 Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
278 if ((vp->tval & (NUM | STR)) == 0)
279 funnyvar(vp, "assign to");
281 donerec = 0; /* mark $0 invalid */
282 fldno = atoi(vp->nval);
285 dprintf( ("setting field %d to %g\n", fldno, f) );
286 } else if (isrec(vp)) {
287 donefld = 0; /* mark $1... invalid */
291 xfree(vp->sval); /* free any previous string */
292 vp->tval &= ~STR; /* mark string invalid */
293 vp->tval |= NUM; /* mark number ok */
294 dprintf( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
298 void funnyvar(Cell *vp, char *rw)
301 FATAL("can't %s %s; it's an array name.", rw, vp->nval);
303 FATAL("can't %s %s; it's a function.", rw, vp->nval);
304 WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
305 vp, vp->nval, vp->sval, vp->fval, vp->tval);
308 char *setsval(Cell *vp, char *s) /* set string val of a Cell */
313 dprintf( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
314 if ((vp->tval & (NUM | STR)) == 0)
315 funnyvar(vp, "assign to");
317 donerec = 0; /* mark $0 invalid */
318 fldno = atoi(vp->nval);
321 dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
322 } else if (isrec(vp)) {
323 donefld = 0; /* mark $1... invalid */
326 t = tostring(s); /* in case it's self-assign */
331 vp->tval &= ~DONTFREE;
332 dprintf( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) );
333 return(vp->sval = t);
336 Awkfloat getfval(Cell *vp) /* get float val of a Cell */
338 if ((vp->tval & (NUM | STR)) == 0)
339 funnyvar(vp, "read value of");
340 if (isfld(vp) && donefld == 0)
342 else if (isrec(vp) && donerec == 0)
344 if (!isnum(vp)) { /* not a number */
345 vp->fval = atof(vp->sval); /* best guess */
346 if (is_number(vp->sval) && !(vp->tval&CON))
347 vp->tval |= NUM; /* make NUM only sparingly */
349 dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
353 char *getsval(Cell *vp) /* get string val of a Cell */
355 char s[100]; /* BUG: unchecked */
358 if ((vp->tval & (NUM | STR)) == 0)
359 funnyvar(vp, "read value of");
360 if (isfld(vp) && donefld == 0)
362 else if (isrec(vp) && donerec == 0)
364 if (isstr(vp) == 0) {
367 if (modf(vp->fval, &dtemp) == 0) /* it's integral */
368 sprintf(s, "%.30g", vp->fval);
370 sprintf(s, *CONVFMT, vp->fval);
371 vp->sval = tostring(s);
372 vp->tval &= ~DONTFREE;
375 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) );
379 char *tostring(char *s) /* make a copy of string s */
383 p = (char *) malloc(strlen(s)+1);
385 FATAL("out of space in tostring on %s", s);
390 char *qstring(char *s, int delim) /* collect string up to next delim */
396 if ((buf = (char *) malloc(strlen(s)+3)) == NULL)
397 FATAL( "out of space in qstring(%s)", s);
398 for (bp = buf; (c = *s) != delim; s++) {
400 SYNTAX( "newline in string %.20s...", os );
403 else { /* \something */
405 if (c == 0) { /* \ at end */
407 break; /* for loop */
410 case '\\': *bp++ = '\\'; break;
411 case 'n': *bp++ = '\n'; break;
412 case 't': *bp++ = '\t'; break;
413 case 'b': *bp++ = '\b'; break;
414 case 'f': *bp++ = '\f'; break;
415 case 'r': *bp++ = '\r'; break;
423 n = 8 * n + *++s - '0';
425 n = 8 * n + *++s - '0';