|
|
1.1 root 1: /*
2: Copyright (c) 1989 AT&T
3: All Rights Reserved
4:
5: THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.
6:
7: The copyright notice above does not evidence any
8: actual or intended publication of such source code.
9: */
10:
11: #define DEBUG
12: #include <stdio.h>
13: #include <math.h>
14: #include <ctype.h>
15: #include <string.h>
16: #include <stdlib.h>
17: #include "awk.h"
18: #include "y.tab.h"
19:
20: #define FULLTAB 2 /* rehash when table gets this x full */
21: #define GROWTAB 4 /* grow table by this factor */
22:
23: Array *symtab; /* main symbol table */
24:
25: uchar **FS; /* initial field sep */
26: uchar **RS; /* initial record sep */
27: uchar **OFS; /* output field sep */
28: uchar **ORS; /* output record sep */
29: uchar **OFMT; /* output format for numbers*/
30: Awkfloat *NF; /* number of fields in current record */
31: Awkfloat *NR; /* number of current record */
32: Awkfloat *FNR; /* number of current record in current file */
33: uchar **FILENAME; /* current filename argument */
34: Awkfloat *ARGC; /* number of arguments from command line */
35: uchar **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
36: Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
37: Awkfloat *RLENGTH; /* length of same */
38:
39: Cell *recloc; /* location of record */
40: Cell *nrloc; /* NR */
41: Cell *nfloc; /* NF */
42: Cell *fnrloc; /* FNR */
43: Array *ARGVtab; /* symbol table containing ARGV[...] */
44: Array *ENVtab; /* symbol table containing ENVIRON[...] */
45: Cell *rstartloc; /* RSTART */
46: Cell *rlengthloc; /* RLENGTH */
47: Cell *symtabloc; /* SYMTAB */
48:
49: Cell *nullloc;
50: Node *nullnode; /* zero&null, converted into a node for comparisons */
51:
52: extern Cell *fldtab;
53:
54: void syminit(void)
55: {
56: /* symtab = makesymtab(NSYMTAB); */
57: setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
58: /* this is used for if(x)... tests: */
59: nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
60: nullnode = valtonode(nullloc, CCON);
61: /* recloc = setsymtab("$0", record, 0.0, REC|STR|DONTFREE, symtab); */
62: recloc = &fldtab[0];
63: FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
64: RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
65: OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
66: ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
67: OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
68: FILENAME = &setsymtab("FILENAME", "-", 0.0, STR|DONTFREE, symtab)->sval;
69: nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
70: NF = &nfloc->fval;
71: nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
72: NR = &nrloc->fval;
73: fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
74: FNR = &fnrloc->fval;
75: SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
76: rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
77: RSTART = &rstartloc->fval;
78: rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
79: RLENGTH = &rlengthloc->fval;
80: symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
81: symtabloc->sval = (uchar *) symtab;
82: }
83:
84: void arginit(int ac, uchar *av[])
85: {
86: Cell *cp;
87: int i;
88: uchar temp[5];
89:
90: for (i = 1; i < ac; i++) /* first make FILENAME first real argument */
91: if (!isclvar(av[i])) {
92: setsval(lookup("FILENAME", symtab), av[i]);
93: break;
94: }
95: ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
96: cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
97: ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
98: cp->sval = (uchar *) ARGVtab;
99: for (i = 0; i < ac; i++) {
100: sprintf((char *)temp, "%d", i);
101: if (isnumber(*av))
102: setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
103: else
104: setsymtab(temp, *av, 0.0, STR, ARGVtab);
105: av++;
106: }
107: }
108:
109: void envinit(uchar **envp)
110: {
111: Cell *cp;
112: uchar *p;
113:
114: cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
115: ENVtab = makesymtab(NSYMTAB);
116: cp->sval = (uchar *) ENVtab;
117: for ( ; *envp; envp++) {
118: if ((p = (uchar *) strchr((char *) *envp, '=')) == NULL) /* index() on bsd */
119: continue;
120: *p++ = 0; /* split into two strings at = */
121: if (isnumber(p))
122: setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
123: else
124: setsymtab(*envp, p, 0.0, STR, ENVtab);
125: p[-1] = '='; /* restore in case env is passed down to a shell */
126: }
127: }
128:
129: Array *makesymtab(int n)
130: {
131: Array *ap;
132: Cell **tp;
133:
134: ap = (Array *) malloc(sizeof(Array));
135: tp = (Cell **) calloc(n, sizeof(Cell *));
136: if (ap == NULL || tp == NULL)
137: ERROR "out of space in makesymtab" FATAL;
138: ap->nelem = 0;
139: ap->size = n;
140: ap->tab = tp;
141: return(ap);
142: }
143:
144: void freesymtab(Cell *ap) /* free symbol table */
145: {
146: Cell *cp, *temp;
147: Array *tp;
148: int i;
149:
150: if (!isarr(ap))
151: return;
152: tp = (Array *) ap->sval;
153: if (tp == NULL)
154: return;
155: for (i = 0; i < tp->size; i++) {
156: for (cp = tp->tab[i]; cp != NULL; cp = temp) {
157: xfree(cp->nval);
158: if (freeable(cp))
159: xfree(cp->sval);
160: temp = cp->cnext; /* avoids freeing then using */
161: free((char *) cp);
162: }
163: }
164: free((char *) (tp->tab));
165: free((char *) tp);
166: }
167:
168: void freeelem(Cell *ap, uchar *s) /* free elem s from ap (i.e., ap["s"] */
169: {
170: Array *tp;
171: Cell *p, *prev = NULL;
172: int h;
173:
174: tp = (Array *) ap->sval;
175: h = hash(s, tp->size);
176: for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
177: if (strcmp((char *) s, (char *) p->nval) == 0) {
178: if (prev == NULL) /* 1st one */
179: tp->tab[h] = p->cnext;
180: else /* middle somewhere */
181: prev->cnext = p->cnext;
182: if (freeable(p))
183: xfree(p->sval);
184: free(p->nval);
185: free((char *) p);
186: tp->nelem--;
187: return;
188: }
189: }
190:
191: Cell *setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned t, Array *tp)
192: {
193: register int h;
194: register Cell *p;
195:
196: if (n != NULL && (p = lookup(n, tp)) != NULL) {
197: dprintf( ("setsymtab found %o: n=%s", p, p->nval) );
198: dprintf( (" s=\"%s\" f=%g t=%o\n", p->sval, p->fval, p->tval) );
199: return(p);
200: }
201: p = (Cell *) malloc(sizeof(Cell));
202: if (p == NULL)
203: ERROR "out of space for symbol table at %s", n FATAL;
204: p->nval = tostring(n);
205: p->sval = s ? tostring(s) : tostring("");
206: p->fval = f;
207: p->tval = t;
208: tp->nelem++;
209: if (tp->nelem > FULLTAB * tp->size)
210: rehash(tp);
211: h = hash(n, tp->size);
212: p->cnext = tp->tab[h];
213: tp->tab[h] = p;
214: dprintf( ("setsymtab set %o: n=%s", p, p->nval) );
215: dprintf( (" s=\"%s\" f=%g t=%o\n", p->sval, p->fval, p->tval) );
216: return(p);
217: }
218:
219: hash(uchar *s, int n) /* form hash value for string s */
220: {
221: register unsigned hashval;
222:
223: for (hashval = 0; *s != '\0'; s++)
224: hashval = (*s + 31 * hashval);
225: return hashval % n;
226: }
227:
228: void rehash(Array *tp) /* rehash items in small table into big one */
229: {
230: int i, nh, nsz;
231: Cell *cp, *op, **np;
232:
233: nsz = GROWTAB * tp->size;
234: np = (Cell **) calloc(nsz, sizeof(Cell *));
235: if (np == NULL) /* can't do it, but can keep running. */
236: return; /* someone else will run out later. */
237: for (i = 0; i < tp->size; i++) {
238: for (cp = tp->tab[i]; cp; cp = op) {
239: op = cp->cnext;
240: nh = hash(cp->nval, nsz);
241: cp->cnext = np[nh];
242: np[nh] = cp;
243: }
244: }
245: free((char *) (tp->tab));
246: tp->tab = np;
247: tp->size = nsz;
248: }
249:
250: Cell *lookup(uchar *s, Array *tp) /* look for s in tp */
251: {
252: register Cell *p, *prev = NULL;
253: int h;
254:
255: h = hash(s, tp->size);
256: for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
257: if (strcmp((char *) s, (char *) p->nval) == 0)
258: return(p); /* found it */
259: return(NULL); /* not found */
260: }
261:
262: Awkfloat setfval(Cell *vp, Awkfloat f)
263: {
264: if ((vp->tval & (NUM | STR)) == 0)
265: funnyvar(vp, "assign to");
266: if (vp->tval & FLD) {
267: donerec = 0; /* mark $0 invalid */
268: if (vp-fldtab > *NF)
269: newfld(vp-fldtab);
270: dprintf( ("setting field %d to %g\n", vp-fldtab, f) );
271: } else if (vp->tval & REC) {
272: donefld = 0; /* mark $1... invalid */
273: donerec = 1;
274: }
275: vp->tval &= ~STR; /* mark string invalid */
276: vp->tval |= NUM; /* mark number ok */
277: dprintf( ("setfval %o: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
278: return vp->fval = f;
279: }
280:
281: void funnyvar(Cell *vp, char *rw)
282: {
283: if (vp->tval & ARR)
284: ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
285: if (vp->tval & FCN)
286: ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
287: ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o",
288: vp, vp->nval, vp->sval, vp->fval, vp->tval WARNING;
289: }
290:
291: uchar *setsval(Cell *vp, uchar *s)
292: {
293: if ((vp->tval & (NUM | STR)) == 0)
294: funnyvar(vp, "assign to");
295: if (vp->tval & FLD) {
296: donerec = 0; /* mark $0 invalid */
297: if (vp-fldtab > *NF)
298: newfld(vp-fldtab);
299: dprintf( ("setting field %d to %s\n", vp-fldtab, s) );
300: } else if (vp->tval & REC) {
301: donefld = 0; /* mark $1... invalid */
302: donerec = 1;
303: }
304: vp->tval &= ~NUM;
305: vp->tval |= STR;
306: if (freeable(vp))
307: xfree(vp->sval);
308: vp->tval &= ~DONTFREE;
309: dprintf( ("setsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
310: return(vp->sval = tostring(s));
311: }
312:
313: Awkfloat r_getfval(Cell *vp)
314: {
315: /* if (vp->tval & ARR)
316: ERROR "illegal reference to array %s", vp->nval FATAL;
317: return 0.0; */
318: if ((vp->tval & (NUM | STR)) == 0)
319: funnyvar(vp, "read value of");
320: if ((vp->tval & FLD) && donefld == 0)
321: fldbld();
322: else if ((vp->tval & REC) && donerec == 0)
323: recbld();
324: if (!isnum(vp)) { /* not a number */
325: vp->fval = atof(vp->sval); /* best guess */
326: if (isnumber(vp->sval) && !(vp->tval&CON))
327: vp->tval |= NUM; /* make NUM only sparingly */
328: }
329: dprintf( ("getfval %o: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
330: return(vp->fval);
331: }
332:
333: uchar *r_getsval(Cell *vp)
334: {
335: uchar s[100];
336: double dtemp;
337:
338: /* if (vp->tval & ARR)
339: ERROR "illegal reference to array %s", vp->nval FATAL;
340: return ""; */
341: if ((vp->tval & (NUM | STR)) == 0)
342: funnyvar(vp, "read value of");
343: if ((vp->tval & FLD) && donefld == 0)
344: fldbld();
345: else if ((vp->tval & REC) && donerec == 0)
346: recbld();
347: if ((vp->tval & STR) == 0) {
348: if (!(vp->tval&DONTFREE))
349: xfree(vp->sval);
350: if (modf(vp->fval, &dtemp) == 0) /* it's integral */
351: sprintf((char *)s, "%.20g", vp->fval);
352: else
353: sprintf((char *)s, (char *)*OFMT, vp->fval);
354: vp->sval = tostring(s);
355: vp->tval &= ~DONTFREE;
356: vp->tval |= STR;
357: }
358: dprintf( ("getsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, vp->sval, vp->tval) );
359: return(vp->sval);
360: }
361:
362: uchar *tostring(uchar *s)
363: {
364: register uchar *p;
365:
366: p = (uchar *) malloc(strlen((char *) s)+1);
367: if (p == NULL)
368: ERROR "out of space in tostring on %s", s FATAL;
369: strcpy((char *) p, (char *) s);
370: return(p);
371: }
372:
373: uchar *qstring(uchar *s, int delim) /* collect string up to delim */
374: {
375: uchar *q;
376: int c, n;
377:
378: for (q = cbuf; (c = *s) != delim; s++) {
379: if (q >= cbuf + CBUFLEN - 1)
380: ERROR "string %.10s... too long", cbuf SYNTAX;
381: else if (c == '\n')
382: ERROR "newline in string %.10s...", cbuf SYNTAX;
383: else if (c != '\\')
384: *q++ = c;
385: else /* \something */
386: switch (c = *++s) {
387: case '\\': *q++ = '\\'; break;
388: case 'n': *q++ = '\n'; break;
389: case 't': *q++ = '\t'; break;
390: case 'b': *q++ = '\b'; break;
391: case 'f': *q++ = '\f'; break;
392: case 'r': *q++ = '\r'; break;
393: default:
394: if (!isdigit(c)) {
395: *q++ = c;
396: break;
397: }
398: n = c - '0';
399: if (isdigit(s[1])) {
400: n = 8 * n + *++s - '0';
401: if (isdigit(s[1]))
402: n = 8 * n + *++s - '0';
403: }
404: *q++ = n;
405: break;
406: }
407: }
408: *q = '\0';
409: return cbuf;
410: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.