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 if( p == *envp ) /* no left hand side name in env string */
131 *p++ = 0; /* split into two strings at = */
133 setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
135 setsymtab(*envp, p, 0.0, STR, ENVtab);
136 p[-1] = '='; /* restore in case env is passed down to a shell */
140 Array *makesymtab(int n) /* make a new symbol table */
145 ap = (Array *) malloc(sizeof(Array));
146 tp = (Cell **) calloc(n, sizeof(Cell *));
147 if (ap == NULL || tp == NULL)
148 FATAL("out of space in makesymtab");
155 void freesymtab(Cell *ap) /* free a symbol table */
163 tp = (Array *) ap->sval;
166 for (i = 0; i < tp->size; i++) {
167 for (cp = tp->tab[i]; cp != NULL; cp = temp) {
171 temp = cp->cnext; /* avoids freeing then using */
178 WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
183 void freeelem(Cell *ap, char *s) /* free elem s from ap (i.e., ap["s"] */
186 Cell *p, *prev = NULL;
189 tp = (Array *) ap->sval;
190 h = hash(s, tp->size);
191 for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
192 if (strcmp(s, p->nval) == 0) {
193 if (prev == NULL) /* 1st one */
194 tp->tab[h] = p->cnext;
195 else /* middle somewhere */
196 prev->cnext = p->cnext;
206 Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp)
211 if (n != NULL && (p = lookup(n, tp)) != NULL) {
212 dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
213 p, p->nval, p->sval, p->fval, p->tval) );
216 p = (Cell *) malloc(sizeof(Cell));
218 FATAL("out of space for symbol table at %s", n);
219 p->nval = tostring(n);
220 p->sval = s ? tostring(s) : tostring("");
226 if (tp->nelem > FULLTAB * tp->size)
228 h = hash(n, tp->size);
229 p->cnext = tp->tab[h];
231 dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
232 p, p->nval, p->sval, p->fval, p->tval) );
236 int hash(char *s, int n) /* form hash value for string s */
240 for (hashval = 0; *s != '\0'; s++)
241 hashval = (*s + 31 * hashval);
245 void rehash(Array *tp) /* rehash items in small table into big one */
250 nsz = GROWTAB * tp->size;
251 np = (Cell **) calloc(nsz, sizeof(Cell *));
252 if (np == NULL) /* can't do it, but can keep running. */
253 return; /* someone else will run out later. */
254 for (i = 0; i < tp->size; i++) {
255 for (cp = tp->tab[i]; cp; cp = op) {
257 nh = hash(cp->nval, nsz);
267 Cell *lookup(char *s, Array *tp) /* look for s in tp */
272 h = hash(s, tp->size);
273 for (p = tp->tab[h]; p != NULL; p = p->cnext)
274 if (strcmp(s, p->nval) == 0)
275 return(p); /* found it */
276 return(NULL); /* not found */
279 Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
283 if ((vp->tval & (NUM | STR)) == 0)
284 funnyvar(vp, "assign to");
286 donerec = 0; /* mark $0 invalid */
287 fldno = atoi(vp->nval);
290 dprintf( ("setting field %d to %g\n", fldno, f) );
291 } else if (isrec(vp)) {
292 donefld = 0; /* mark $1... invalid */
296 xfree(vp->sval); /* free any previous string */
297 vp->tval &= ~STR; /* mark string invalid */
298 vp->tval |= NUM; /* mark number ok */
299 dprintf( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
303 void funnyvar(Cell *vp, char *rw)
306 FATAL("can't %s %s; it's an array name.", rw, vp->nval);
308 FATAL("can't %s %s; it's a function.", rw, vp->nval);
309 WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
310 vp, vp->nval, vp->sval, vp->fval, vp->tval);
313 char *setsval(Cell *vp, char *s) /* set string val of a Cell */
318 dprintf( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
319 if ((vp->tval & (NUM | STR)) == 0)
320 funnyvar(vp, "assign to");
322 donerec = 0; /* mark $0 invalid */
323 fldno = atoi(vp->nval);
326 dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
327 } else if (isrec(vp)) {
328 donefld = 0; /* mark $1... invalid */
331 t = tostring(s); /* in case it's self-assign */
336 vp->tval &= ~DONTFREE;
337 dprintf( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) );
338 return(vp->sval = t);
341 Awkfloat getfval(Cell *vp) /* get float val of a Cell */
343 if ((vp->tval & (NUM | STR)) == 0)
344 funnyvar(vp, "read value of");
345 if (isfld(vp) && donefld == 0)
347 else if (isrec(vp) && donerec == 0)
349 if (!isnum(vp)) { /* not a number */
350 vp->fval = atof(vp->sval); /* best guess */
351 if (is_number(vp->sval) && !(vp->tval&CON))
352 vp->tval |= NUM; /* make NUM only sparingly */
354 dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
358 char *getsval(Cell *vp) /* get string val of a Cell */
360 char s[100]; /* BUG: unchecked */
363 if ((vp->tval & (NUM | STR)) == 0)
364 funnyvar(vp, "read value of");
365 if (isfld(vp) && donefld == 0)
367 else if (isrec(vp) && donerec == 0)
369 if (isstr(vp) == 0) {
372 if (modf(vp->fval, &dtemp) == 0) /* it's integral */
373 sprintf(s, "%.30g", vp->fval);
375 sprintf(s, *CONVFMT, vp->fval);
376 vp->sval = tostring(s);
377 vp->tval &= ~DONTFREE;
380 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) );
384 char *tostring(char *s) /* make a copy of string s */
388 p = (char *) malloc(strlen(s)+1);
390 FATAL("out of space in tostring on %s", s);
395 char *qstring(char *is, int delim) /* collect string up to next delim */
399 uschar *s = (uschar *) is;
402 if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
403 FATAL( "out of space in qstring(%s)", s);
404 for (bp = buf; (c = *s) != delim; s++) {
406 SYNTAX( "newline in string %.20s...", os );
409 else { /* \something */
411 if (c == 0) { /* \ at end */
413 break; /* for loop */
416 case '\\': *bp++ = '\\'; break;
417 case 'n': *bp++ = '\n'; break;
418 case 't': *bp++ = '\t'; break;
419 case 'b': *bp++ = '\b'; break;
420 case 'f': *bp++ = '\f'; break;
421 case 'r': *bp++ = '\r'; break;
429 n = 8 * n + *++s - '0';
431 n = 8 * n + *++s - '0';