1 /****************************************************************
2 Copyright (C) AT&T 1993
3 All Rights Reserved
4
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 of AT&T or any of its entities
11 not be used in advertising or publicity pertaining to
12 distribution of the software without specific, written prior
13 permission.
14
15 AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17 IN NO EVENT SHALL AT&T 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 ****************************************************************/
24
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"
33
34 #define FULLTAB 2 /* rehash when table gets this x full */
35 #define GROWTAB 4 /* grow table by this factor */
36
37 Array *symtab; /* main symbol table */
38
39 uchar **FS; /* initial field sep */
40 uchar **RS; /* initial record sep */
41 uchar **OFS; /* output field sep */
42 uchar **ORS; /* output record sep */
43 uchar **OFMT; /* output format for numbers */
44 uchar **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 uchar **FILENAME; /* current filename argument */
49 Awkfloat *ARGC; /* number of arguments from command line */
50 uchar **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 */
53
54 Cell *recloc; /* location of record */
55 Cell *nrloc; /* NR */
56 Cell *nfloc; /* NF */
57 Cell *fnrloc; /* FNR */
58 Array *ARGVtab; /* symbol table containing ARGV[...] */
59 Array *ENVtab; /* symbol table containing ENVIRON[...] */
60 Cell *rstartloc; /* RSTART */
61 Cell *rlengthloc; /* RLENGTH */
62 Cell *symtabloc; /* SYMTAB */
63
64 Cell *nullloc; /* a guaranteed empty cell */
65 Node *nullnode; /* zero&null, converted into a node for comparisons */
66
67 extern Cell *fldtab;
68
syminit(void)69 void syminit(void) /* initialize symbol table with builtin vars */
70 {
71 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 = valtonode(nullloc, CCON);
75
76 /* recloc = setsymtab("$0", record, 0.0, REC|STR|DONTFREE, symtab); */
77 /* has been done elsewhere */
78 recloc = &fldtab[0];
79 FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
80 RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
81 OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
82 ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
83 OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
84 CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
85 FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
86 nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
87 NF = &nfloc->fval;
88 nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
89 NR = &nrloc->fval;
90 fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
91 FNR = &fnrloc->fval;
92 SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
93 rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
94 RSTART = &rstartloc->fval;
95 rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
96 RLENGTH = &rlengthloc->fval;
97 symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
98 symtabloc->sval = (uchar *) symtab;
99 }
100
arginit(int ac,uchar * av[])101 void arginit(int ac, uchar *av[]) /* set up ARGV and ARGC */
102 {
103 Cell *cp;
104 int i;
105 uchar temp[5];
106
107 ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
108 cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
109 ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
110 cp->sval = (uchar *) ARGVtab;
111 for (i = 0; i < ac; i++) {
112 sprintf((char *)temp, "%d", i);
113 if (is_a_number(*av))
114 setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
115 else
116 setsymtab(temp, *av, 0.0, STR, ARGVtab);
117 av++;
118 }
119 }
120
envinit(uchar ** envp)121 void envinit(uchar **envp) /* set up ENVIRON variable */
122 {
123 Cell *cp;
124 uchar *p;
125
126 cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
127 ENVtab = makesymtab(NSYMTAB);
128 cp->sval = (uchar *) ENVtab;
129 for ( ; *envp; envp++) {
130 if ((p = (uchar *) strchr((char *) *envp, '=')) == NULL)
131 continue;
132 *p++ = 0; /* split into two strings at = */
133 if (is_a_number(p))
134 setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
135 else
136 setsymtab(*envp, p, 0.0, STR, ENVtab);
137 p[-1] = '='; /* restore in case env is passed down to a shell */
138 }
139 }
140
makesymtab(int n)141 Array *makesymtab(int n) /* make a new symbol table */
142 {
143 Array *ap;
144 Cell **tp;
145
146 ap = (Array *) malloc(sizeof(Array));
147 tp = (Cell **) calloc(n, sizeof(Cell *));
148 if (ap == NULL || tp == NULL)
149 ERROR "out of space in makesymtab" FATAL;
150 ap->nelem = 0;
151 ap->size = n;
152 ap->tab = tp;
153 return(ap);
154 }
155
freesymtab(Cell * ap)156 void freesymtab(Cell *ap) /* free a symbol table */
157 {
158 Cell *cp, *temp;
159 Array *tp;
160 int i;
161
162 if (!isarr(ap))
163 return;
164 tp = (Array *) ap->sval;
165 if (tp == NULL)
166 return;
167 for (i = 0; i < tp->size; i++) {
168 for (cp = tp->tab[i]; cp != NULL; cp = temp) {
169 xfree(cp->nval);
170 if (freeable(cp))
171 xfree(cp->sval);
172 temp = cp->cnext; /* avoids freeing then using */
173 free((char *) cp);
174 }
175 }
176 free((char *) (tp->tab));
177 free((char *) tp);
178 }
179
freeelem(Cell * ap,uchar * s)180 void freeelem(Cell *ap, uchar *s) /* free elem s from ap (i.e., ap["s"] */
181 {
182 Array *tp;
183 Cell *p, *prev = NULL;
184 int h;
185
186 tp = (Array *) ap->sval;
187 h = hash(s, tp->size);
188 for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
189 if (strcmp((char *) s, (char *) p->nval) == 0) {
190 if (prev == NULL) /* 1st one */
191 tp->tab[h] = p->cnext;
192 else /* middle somewhere */
193 prev->cnext = p->cnext;
194 if (freeable(p))
195 xfree(p->sval);
196 free(p->nval);
197 free((char *) p);
198 tp->nelem--;
199 return;
200 }
201 }
202
setsymtab(uchar * n,uchar * s,Awkfloat f,unsigned t,Array * tp)203 Cell *setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned t, Array *tp)
204 {
205 register int h;
206 register Cell *p;
207
208 if (n != NULL && (p = lookup(n, tp)) != NULL) {
209 dprintf( ("setsymtab found %o: n=%s s=\"%s\" f=%g t=%o\n",
210 p, p->nval, p->sval, p->fval, p->tval) );
211 return(p);
212 }
213 p = (Cell *) malloc(sizeof(Cell));
214 if (p == NULL)
215 ERROR "out of space for symbol table at %s", n FATAL;
216 p->nval = tostring(n);
217 p->sval = s ? tostring(s) : tostring("");
218 p->fval = f;
219 p->tval = t;
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 %o: n=%s s=\"%s\" f=%g t=%o\n",
227 p, p->nval, p->sval, p->fval, p->tval) );
228 return(p);
229 }
230
hash(uchar * s,int n)231 hash(uchar *s, int n) /* form hash value for string s */
232 {
233 register unsigned hashval;
234
235 for (hashval = 0; *s != '\0'; s++)
236 hashval = (*s + 31 * hashval);
237 return hashval % n;
238 }
239
rehash(Array * tp)240 void rehash(Array *tp) /* rehash items in small table into big one */
241 {
242 int i, nh, nsz;
243 Cell *cp, *op, **np;
244
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;
255 }
256 }
257 free((char *) (tp->tab));
258 tp->tab = np;
259 tp->size = nsz;
260 }
261
lookup(uchar * s,Array * tp)262 Cell *lookup(uchar *s, Array *tp) /* look for s in tp */
263 {
264 register Cell *p, *prev = NULL;
265 int h;
266
267 h = hash(s, tp->size);
268 for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
269 if (strcmp((char *) s, (char *) p->nval) == 0)
270 return(p); /* found it */
271 return(NULL); /* not found */
272 }
273
setfval(Cell * vp,Awkfloat f)274 Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
275 {
276 if ((vp->tval & (NUM | STR)) == 0)
277 funnyvar(vp, "assign to");
278 if (vp->tval & FLD) {
279 donerec = 0; /* mark $0 invalid */
280 if (vp-fldtab > *NF)
281 newfld(vp-fldtab);
282 dprintf( ("setting field %d to %g\n", vp-fldtab, f) );
283 } else if (vp->tval & REC) {
284 donefld = 0; /* mark $1... invalid */
285 donerec = 1;
286 }
287 vp->tval &= ~STR; /* mark string invalid */
288 vp->tval |= NUM; /* mark number ok */
289 dprintf( ("setfval %o: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
290 return vp->fval = f;
291 }
292
funnyvar(Cell * vp,char * rw)293 void funnyvar(Cell *vp, char *rw)
294 {
295 if (vp->tval & ARR)
296 ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
297 if (vp->tval & FCN)
298 ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
299 ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o",
300 vp, vp->nval, vp->sval, vp->fval, vp->tval WARNING;
301 }
302
setsval(Cell * vp,uchar * s)303 uchar *setsval(Cell *vp, uchar *s) /* set string val of a Cell */
304 {
305 if ((vp->tval & (NUM | STR)) == 0)
306 funnyvar(vp, "assign to");
307 if (vp->tval & FLD) {
308 donerec = 0; /* mark $0 invalid */
309 if (vp-fldtab > *NF)
310 newfld(vp-fldtab);
311 dprintf( ("setting field %d to %s\n", vp-fldtab, s) );
312 } else if (vp->tval & REC) {
313 donefld = 0; /* mark $1... invalid */
314 donerec = 1;
315 }
316 vp->tval &= ~NUM;
317 vp->tval |= STR;
318 if (freeable(vp))
319 xfree(vp->sval);
320 vp->tval &= ~DONTFREE;
321 dprintf( ("setsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
322 return(vp->sval = tostring(s));
323 }
324
r_getfval(Cell * vp)325 Awkfloat r_getfval(Cell *vp) /* get float val of a Cell */
326 {
327 if ((vp->tval & (NUM | STR)) == 0)
328 funnyvar(vp, "read value of");
329 if ((vp->tval & FLD) && donefld == 0)
330 fldbld();
331 else if ((vp->tval & REC) && donerec == 0)
332 recbld();
333 if (!isnum(vp)) { /* not a number */
334 vp->fval = atof(vp->sval); /* best guess */
335 if (is_a_number(vp->sval) && !(vp->tval&CON))
336 vp->tval |= NUM; /* make NUM only sparingly */
337 }
338 dprintf( ("getfval %o: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
339 return(vp->fval);
340 }
341
r_getsval(Cell * vp)342 uchar *r_getsval(Cell *vp) /* get string val of a Cell */
343 {
344 uchar s[100];
345 double dtemp;
346
347 if ((vp->tval & (NUM | STR)) == 0)
348 funnyvar(vp, "read value of");
349 if ((vp->tval & FLD) && donefld == 0)
350 fldbld();
351 else if ((vp->tval & REC) && donerec == 0)
352 recbld();
353 if ((vp->tval & STR) == 0) {
354 if (!(vp->tval&DONTFREE))
355 xfree(vp->sval);
356 if (modf(vp->fval, &dtemp) == 0) /* it's integral */
357 sprintf((char *)s, "%.20g", vp->fval);
358 else
359 sprintf((char *)s, (char *)*CONVFMT, vp->fval);
360 vp->sval = tostring(s);
361 vp->tval &= ~DONTFREE;
362 vp->tval |= STR;
363 }
364 dprintf( ("getsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, vp->sval, vp->tval) );
365 return(vp->sval);
366 }
367
tostring(uchar * s)368 uchar *tostring(uchar *s) /* make a copy of string s */
369 {
370 register uchar *p;
371
372 p = (uchar *) malloc(strlen((char *) s)+1);
373 if (p == NULL)
374 ERROR "out of space in tostring on %s", s FATAL;
375 strcpy((char *) p, (char *) s);
376 return(p);
377 }
378
qstring(uchar * s,int delim)379 uchar *qstring(uchar *s, int delim) /* collect string up to next delim */
380 {
381 uchar *q;
382 int c, n;
383
384 for (q = cbuf; (c = *s) != delim; s++) {
385 if (q >= cbuf + CBUFLEN - 1)
386 ERROR "string %.10s... too long", cbuf SYNTAX;
387 else if (c == '\n')
388 ERROR "newline in string %.10s...", cbuf SYNTAX;
389 else if (c != '\\')
390 *q++ = c;
391 else /* \something */
392 switch (c = *++s) {
393 case '\\': *q++ = '\\'; break;
394 case 'n': *q++ = '\n'; break;
395 case 't': *q++ = '\t'; break;
396 case 'b': *q++ = '\b'; break;
397 case 'f': *q++ = '\f'; break;
398 case 'r': *q++ = '\r'; break;
399 default:
400 if (!isdigit(c)) {
401 *q++ = c;
402 break;
403 }
404 n = c - '0';
405 if (isdigit(s[1])) {
406 n = 8 * n + *++s - '0';
407 if (isdigit(s[1]))
408 n = 8 * n + *++s - '0';
409 }
410 *q++ = n;
411 break;
412 }
413 }
414 *q = '\0';
415 return cbuf;
416 }
417