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, const 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(const char *n, const 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, NN(p->nval), NN(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(const 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(const 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, NN(vp->nval), f, vp->tval) );
303 void funnyvar(Cell *vp, const 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, const char *s) /* set string val of a Cell */
318 dprintf( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, NN(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, NN(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, NN(vp->nval), vp->fval, vp->tval) );
358 static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */
361 char s[100]; /* BUG: unchecked */
364 if ((vp->tval & (NUM | STR)) == 0)
365 funnyvar(vp, "read value of");
366 if (isfld(vp) && donefld == 0)
368 else if (isrec(vp) && donerec == 0)
370 if (isstr(vp) == 0) {
373 if (modf(vp->fval, &dtemp) == 0) /* it's integral */
374 sprintf(s, "%.30g", vp->fval);
376 sprintf(s, *fmt, vp->fval);
377 vp->sval = tostring(s);
378 vp->tval &= ~DONTFREE;
381 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) );
385 char *getsval(Cell *vp) /* get string val of a Cell */
387 return get_str_val(vp, CONVFMT);
390 char *getpssval(Cell *vp) /* get string val of a Cell for print */
392 return get_str_val(vp, OFMT);
396 char *tostring(const char *s) /* make a copy of string s */
400 p = (char *) malloc(strlen(s)+1);
402 FATAL("out of space in tostring on %s", s);
407 char *qstring(const char *is, int delim) /* collect string up to next delim */
411 uschar *s = (uschar *) is;
414 if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
415 FATAL( "out of space in qstring(%s)", s);
416 for (bp = buf; (c = *s) != delim; s++) {
418 SYNTAX( "newline in string %.20s...", os );
421 else { /* \something */
423 if (c == 0) { /* \ at end */
425 break; /* for loop */
428 case '\\': *bp++ = '\\'; break;
429 case 'n': *bp++ = '\n'; break;
430 case 't': *bp++ = '\t'; break;
431 case 'b': *bp++ = '\b'; break;
432 case 'f': *bp++ = '\f'; break;
433 case 'r': *bp++ = '\r'; break;
441 n = 8 * n + *++s - '0';
443 n = 8 * n + *++s - '0';