Blob


1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
3 All Rights Reserved
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
13 permission.
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
22 THIS SOFTWARE.
23 ****************************************************************/
25 #define DEBUG
26 #include <stdio.h>
27 #include <math.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include "awk.h"
32 #include "y.tab.h"
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 */
54 Cell *nrloc; /* NR */
55 Cell *nfloc; /* NF */
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 */
65 Cell *literal0;
67 extern Cell **fldtab;
69 void syminit(void) /* initialize symbol table with builtin vars */
70 {
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);
84 NF = &nfloc->fval;
85 nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
86 NR = &nrloc->fval;
87 fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
88 FNR = &fnrloc->fval;
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;
96 }
98 void arginit(int ac, char **av) /* set up ARGV and ARGC */
99 {
100 Cell *cp;
101 int i;
102 char temp[50];
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);
110 if (is_number(*av))
111 setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
112 else
113 setsymtab(temp, *av, 0.0, STR, ARGVtab);
114 av++;
118 void envinit(char **envp) /* set up ENVIRON variable */
120 Cell *cp;
121 char *p;
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)
128 continue;
129 *p++ = 0; /* split into two strings at = */
130 if (is_number(p))
131 setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
132 else
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 */
140 Array *ap;
141 Cell **tp;
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");
147 ap->nelem = 0;
148 ap->size = n;
149 ap->tab = tp;
150 return(ap);
153 void freesymtab(Cell *ap) /* free a symbol table */
155 Cell *cp, *temp;
156 Array *tp;
157 int i;
159 if (!isarr(ap))
160 return;
161 tp = (Array *) ap->sval;
162 if (tp == NULL)
163 return;
164 for (i = 0; i < tp->size; i++) {
165 for (cp = tp->tab[i]; cp != NULL; cp = temp) {
166 xfree(cp->nval);
167 if (freeable(cp))
168 xfree(cp->sval);
169 temp = cp->cnext; /* avoids freeing then using */
170 free(cp);
172 tp->tab[i] = 0;
174 free(tp->tab);
175 free(tp);
178 void freeelem(Cell *ap, char *s) /* free elem s from ap (i.e., ap["s"] */
180 Array *tp;
181 Cell *p, *prev = NULL;
182 int h;
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;
192 if (freeable(p))
193 xfree(p->sval);
194 free(p->nval);
195 free(p);
196 tp->nelem--;
197 return;
201 Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp)
203 int h;
204 Cell *p;
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) );
209 return(p);
211 p = (Cell *) malloc(sizeof(Cell));
212 if (p == NULL)
213 FATAL("out of space for symbol table at %s", n);
214 p->nval = tostring(n);
215 p->sval = s ? tostring(s) : tostring("");
216 p->fval = f;
217 p->tval = t;
218 p->csub = CUNK;
219 p->ctype = OCELL;
220 tp->nelem++;
221 if (tp->nelem > FULLTAB * tp->size)
222 rehash(tp);
223 h = hash(n, tp->size);
224 p->cnext = tp->tab[h];
225 tp->tab[h] = p;
226 dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
227 p, p->nval, p->sval, p->fval, p->tval) );
228 return(p);
231 int hash(char *s, int n) /* form hash value for string s */
233 unsigned hashval;
235 for (hashval = 0; *s != '\0'; s++)
236 hashval = (*s + 31 * hashval);
237 return hashval % n;
240 void rehash(Array *tp) /* rehash items in small table into big one */
242 int i, nh, nsz;
243 Cell *cp, *op, **np;
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) {
251 op = cp->cnext;
252 nh = hash(cp->nval, nsz);
253 cp->cnext = np[nh];
254 np[nh] = cp;
257 free(tp->tab);
258 tp->tab = np;
259 tp->size = nsz;
262 Cell *lookup(char *s, Array *tp) /* look for s in tp */
264 Cell *p;
265 int h;
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 */
276 int fldno;
278 if ((vp->tval & (NUM | STR)) == 0)
279 funnyvar(vp, "assign to");
280 if (isfld(vp)) {
281 donerec = 0; /* mark $0 invalid */
282 fldno = atoi(vp->nval);
283 if (fldno > *NF)
284 newfld(fldno);
285 dprintf( ("setting field %d to %g\n", fldno, f) );
286 } else if (isrec(vp)) {
287 donefld = 0; /* mark $1... invalid */
288 donerec = 1;
290 if (freeable(vp))
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) );
295 return vp->fval = f;
298 void funnyvar(Cell *vp, char *rw)
300 if (isarr(vp))
301 FATAL("can't %s %s; it's an array name.", rw, vp->nval);
302 if (vp->tval & FCN)
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 */
310 char *t;
311 int fldno;
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");
316 if (isfld(vp)) {
317 donerec = 0; /* mark $0 invalid */
318 fldno = atoi(vp->nval);
319 if (fldno > *NF)
320 newfld(fldno);
321 dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
322 } else if (isrec(vp)) {
323 donefld = 0; /* mark $1... invalid */
324 donerec = 1;
326 t = tostring(s); /* in case it's self-assign */
327 vp->tval &= ~NUM;
328 vp->tval |= STR;
329 if (freeable(vp))
330 xfree(vp->sval);
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)
341 fldbld();
342 else if (isrec(vp) && donerec == 0)
343 recbld();
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) );
350 return(vp->fval);
353 char *getsval(Cell *vp) /* get string val of a Cell */
355 char s[100]; /* BUG: unchecked */
356 double dtemp;
358 if ((vp->tval & (NUM | STR)) == 0)
359 funnyvar(vp, "read value of");
360 if (isfld(vp) && donefld == 0)
361 fldbld();
362 else if (isrec(vp) && donerec == 0)
363 recbld();
364 if (isstr(vp) == 0) {
365 if (freeable(vp))
366 xfree(vp->sval);
367 if (modf(vp->fval, &dtemp) == 0) /* it's integral */
368 sprintf(s, "%.30g", vp->fval);
369 else
370 sprintf(s, *CONVFMT, vp->fval);
371 vp->sval = tostring(s);
372 vp->tval &= ~DONTFREE;
373 vp->tval |= STR;
375 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) );
376 return(vp->sval);
379 char *tostring(char *s) /* make a copy of string s */
381 char *p;
383 p = (char *) malloc(strlen(s)+1);
384 if (p == NULL)
385 FATAL("out of space in tostring on %s", s);
386 strcpy(p, s);
387 return(p);
390 char *qstring(char *s, int delim) /* collect string up to next delim */
392 char *os = s;
393 int c, n;
394 char *buf, *bp;
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++) {
399 if (c == '\n')
400 SYNTAX( "newline in string %.20s...", os );
401 else if (c != '\\')
402 *bp++ = c;
403 else { /* \something */
404 c = *++s;
405 if (c == 0) { /* \ at end */
406 *bp++ = '\\';
407 break; /* for loop */
409 switch (c) {
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;
416 default:
417 if (!isdigit(c)) {
418 *bp++ = c;
419 break;
421 n = c - '0';
422 if (isdigit(s[1])) {
423 n = 8 * n + *++s - '0';
424 if (isdigit(s[1]))
425 n = 8 * n + *++s - '0';
427 *bp++ = n;
428 break;
432 *bp++ = 0;
433 return buf;