Annotation of src/usr.bin/awk/tran.c, Revision 1.3
1.3 ! kstailey 1: /* $OpenBSD$ */
1.1 tholo 2: /****************************************************************
1.3 ! kstailey 3: Copyright (C) Lucent Technologies 1997
1.1 tholo 4: All Rights Reserved
5:
6: Permission to use, copy, modify, and distribute this software and
7: its documentation for any purpose and without fee is hereby
8: granted, provided that the above copyright notice appear in all
9: copies and that both that the copyright notice and this
10: permission notice and warranty disclaimer appear in supporting
1.3 ! kstailey 11: documentation, and that the name Lucent Technologies or any of
! 12: its entities not be used in advertising or publicity pertaining
! 13: to distribution of the software without specific, written prior
! 14: permission.
! 15:
! 16: LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
! 17: INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
! 18: IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
! 19: SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 20: WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
! 21: IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
! 22: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
! 23: THIS SOFTWARE.
1.1 tholo 24: ****************************************************************/
25:
26: #define DEBUG
27: #include <stdio.h>
28: #include <math.h>
29: #include <ctype.h>
30: #include <string.h>
31: #include <stdlib.h>
32: #include "awk.h"
1.3 ! kstailey 33: #include "ytab.h"
1.1 tholo 34:
35: #define FULLTAB 2 /* rehash when table gets this x full */
36: #define GROWTAB 4 /* grow table by this factor */
37:
38: Array *symtab; /* main symbol table */
39:
40: char **FS; /* initial field sep */
41: char **RS; /* initial record sep */
42: char **OFS; /* output field sep */
43: char **ORS; /* output record sep */
44: char **OFMT; /* output format for numbers */
45: char **CONVFMT; /* format for conversions in getsval */
46: Awkfloat *NF; /* number of fields in current record */
47: Awkfloat *NR; /* number of current record */
48: Awkfloat *FNR; /* number of current record in current file */
49: char **FILENAME; /* current filename argument */
50: Awkfloat *ARGC; /* number of arguments from command line */
51: char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
52: Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
53: Awkfloat *RLENGTH; /* length of same */
54:
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 */
1.3 ! kstailey 66: Cell *literal0;
1.1 tholo 67:
1.3 ! kstailey 68: extern Cell **fldtab;
1.1 tholo 69:
70: void syminit(void) /* initialize symbol table with builtin vars */
71: {
1.3 ! kstailey 72: literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
1.1 tholo 73: /* this is used for if(x)... tests: */
74: nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
1.3 ! kstailey 75: nullnode = celltonode(nullloc, CCON);
1.1 tholo 76:
77: FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
78: RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
79: OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
80: ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
81: OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
82: CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
1.2 millert 83: FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
1.1 tholo 84: nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
85: NF = &nfloc->fval;
86: nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
87: NR = &nrloc->fval;
88: fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
89: FNR = &fnrloc->fval;
90: SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
91: rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
92: RSTART = &rstartloc->fval;
93: rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
94: RLENGTH = &rlengthloc->fval;
95: symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
96: symtabloc->sval = (char *) symtab;
97: }
98:
1.3 ! kstailey 99: void arginit(int ac, char **av) /* set up ARGV and ARGC */
1.1 tholo 100: {
101: Cell *cp;
102: int i;
1.3 ! kstailey 103: char temp[50];
1.1 tholo 104:
105: ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
106: cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
107: ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
108: cp->sval = (char *) ARGVtab;
109: for (i = 0; i < ac; i++) {
1.3 ! kstailey 110: sprintf(temp, "%d", i);
1.1 tholo 111: if (isnumber(*av))
112: setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
113: else
114: setsymtab(temp, *av, 0.0, STR, ARGVtab);
115: av++;
116: }
117: }
118:
119: void envinit(char **envp) /* set up ENVIRON variable */
120: {
121: Cell *cp;
122: char *p;
123:
124: cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
125: ENVtab = makesymtab(NSYMTAB);
126: cp->sval = (char *) ENVtab;
127: for ( ; *envp; envp++) {
1.3 ! kstailey 128: if ((p = strchr(*envp, '=')) == NULL)
1.1 tholo 129: continue;
130: *p++ = 0; /* split into two strings at = */
131: if (isnumber(p))
132: setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
133: else
134: setsymtab(*envp, p, 0.0, STR, ENVtab);
135: p[-1] = '='; /* restore in case env is passed down to a shell */
136: }
137: }
138:
139: Array *makesymtab(int n) /* make a new symbol table */
140: {
141: Array *ap;
142: Cell **tp;
143:
144: ap = (Array *) malloc(sizeof(Array));
145: tp = (Cell **) calloc(n, sizeof(Cell *));
146: if (ap == NULL || tp == NULL)
147: ERROR "out of space in makesymtab" FATAL;
148: ap->nelem = 0;
149: ap->size = n;
150: ap->tab = tp;
151: return(ap);
152: }
153:
154: void freesymtab(Cell *ap) /* free a symbol table */
155: {
156: Cell *cp, *temp;
157: Array *tp;
158: int i;
159:
160: if (!isarr(ap))
161: return;
162: tp = (Array *) ap->sval;
163: if (tp == NULL)
164: return;
165: for (i = 0; i < tp->size; i++) {
166: for (cp = tp->tab[i]; cp != NULL; cp = temp) {
167: xfree(cp->nval);
168: if (freeable(cp))
169: xfree(cp->sval);
170: temp = cp->cnext; /* avoids freeing then using */
1.3 ! kstailey 171: free(cp);
1.1 tholo 172: }
173: tp->tab[i] = 0;
174: }
1.3 ! kstailey 175: free(tp->tab);
! 176: free(tp);
1.1 tholo 177: }
178:
179: void freeelem(Cell *ap, char *s) /* free elem s from ap (i.e., ap["s"] */
180: {
181: Array *tp;
182: Cell *p, *prev = NULL;
183: int h;
184:
185: tp = (Array *) ap->sval;
186: h = hash(s, tp->size);
187: for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
1.3 ! kstailey 188: if (strcmp(s, p->nval) == 0) {
1.1 tholo 189: if (prev == NULL) /* 1st one */
190: tp->tab[h] = p->cnext;
191: else /* middle somewhere */
192: prev->cnext = p->cnext;
193: if (freeable(p))
194: xfree(p->sval);
195: free(p->nval);
1.3 ! kstailey 196: free(p);
1.1 tholo 197: tp->nelem--;
198: return;
199: }
200: }
201:
202: Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp)
203: {
204: int h;
205: Cell *p;
206:
207: if (n != NULL && (p = lookup(n, tp)) != NULL) {
1.3 ! kstailey 208: dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
1.1 tholo 209: p, p->nval, p->sval, p->fval, p->tval) );
210: return(p);
211: }
212: p = (Cell *) malloc(sizeof(Cell));
213: if (p == NULL)
214: ERROR "out of space for symbol table at %s", n FATAL;
215: p->nval = tostring(n);
216: p->sval = s ? tostring(s) : tostring("");
217: p->fval = f;
218: p->tval = t;
219: p->csub = CUNK;
220: p->ctype = OCELL;
221: tp->nelem++;
222: if (tp->nelem > FULLTAB * tp->size)
223: rehash(tp);
224: h = hash(n, tp->size);
225: p->cnext = tp->tab[h];
226: tp->tab[h] = p;
1.3 ! kstailey 227: dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
1.1 tholo 228: p, p->nval, p->sval, p->fval, p->tval) );
229: return(p);
230: }
231:
232: int hash(char *s, int n) /* form hash value for string s */
233: {
234: unsigned hashval;
235:
236: for (hashval = 0; *s != '\0'; s++)
237: hashval = (*s + 31 * hashval);
238: return hashval % n;
239: }
240:
241: void rehash(Array *tp) /* rehash items in small table into big one */
242: {
243: int i, nh, nsz;
244: Cell *cp, *op, **np;
245:
246: nsz = GROWTAB * tp->size;
247: np = (Cell **) calloc(nsz, sizeof(Cell *));
248: if (np == NULL) /* can't do it, but can keep running. */
249: return; /* someone else will run out later. */
250: for (i = 0; i < tp->size; i++) {
251: for (cp = tp->tab[i]; cp; cp = op) {
252: op = cp->cnext;
253: nh = hash(cp->nval, nsz);
254: cp->cnext = np[nh];
255: np[nh] = cp;
256: }
257: }
1.3 ! kstailey 258: free(tp->tab);
1.1 tholo 259: tp->tab = np;
260: tp->size = nsz;
261: }
262:
263: Cell *lookup(char *s, Array *tp) /* look for s in tp */
264: {
265: Cell *p, *prev = NULL;
266: int h;
267:
268: h = hash(s, tp->size);
269: for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
1.3 ! kstailey 270: if (strcmp(s, p->nval) == 0)
1.1 tholo 271: return(p); /* found it */
272: return(NULL); /* not found */
273: }
274:
275: Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
276: {
1.3 ! kstailey 277: int fldno;
! 278:
1.1 tholo 279: if ((vp->tval & (NUM | STR)) == 0)
280: funnyvar(vp, "assign to");
1.3 ! kstailey 281: if (isfld(vp)) {
1.1 tholo 282: donerec = 0; /* mark $0 invalid */
1.3 ! kstailey 283: fldno = atoi(vp->nval);
! 284: if (fldno > *NF)
! 285: newfld(fldno);
! 286: dprintf( ("setting field %d to %g\n", fldno, f) );
! 287: } else if (isrec(vp)) {
1.1 tholo 288: donefld = 0; /* mark $1... invalid */
289: donerec = 1;
290: }
291: vp->tval &= ~STR; /* mark string invalid */
292: vp->tval |= NUM; /* mark number ok */
1.3 ! kstailey 293: dprintf( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
1.1 tholo 294: return vp->fval = f;
295: }
296:
297: void funnyvar(Cell *vp, char *rw)
298: {
1.3 ! kstailey 299: if (isarr(vp))
1.1 tholo 300: ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
301: if (vp->tval & FCN)
302: ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
303: ERROR "funny variable %p: n=%s s=\"%s\" f=%g t=%o",
304: vp, vp->nval, vp->sval, vp->fval, vp->tval WARNING;
305: }
306:
307: char *setsval(Cell *vp, char *s) /* set string val of a Cell */
308: {
309: char *t;
1.3 ! kstailey 310: int fldno;
1.1 tholo 311:
1.3 ! kstailey 312: dprintf( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
1.1 tholo 313: if ((vp->tval & (NUM | STR)) == 0)
314: funnyvar(vp, "assign to");
1.3 ! kstailey 315: if (isfld(vp)) {
1.1 tholo 316: donerec = 0; /* mark $0 invalid */
1.3 ! kstailey 317: fldno = atoi(vp->nval);
! 318: if (fldno > *NF)
! 319: newfld(fldno);
! 320: dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
! 321: } else if (isrec(vp)) {
1.1 tholo 322: donefld = 0; /* mark $1... invalid */
323: donerec = 1;
324: }
325: t = tostring(s); /* in case it's self-assign */
326: vp->tval &= ~NUM;
327: vp->tval |= STR;
328: if (freeable(vp))
329: xfree(vp->sval);
330: vp->tval &= ~DONTFREE;
1.3 ! kstailey 331: dprintf( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) );
1.1 tholo 332: return(vp->sval = t);
333: }
334:
335: Awkfloat getfval(Cell *vp) /* get float val of a Cell */
336: {
337: if ((vp->tval & (NUM | STR)) == 0)
338: funnyvar(vp, "read value of");
1.3 ! kstailey 339: if (isfld(vp) && donefld == 0)
1.1 tholo 340: fldbld();
1.3 ! kstailey 341: else if (isrec(vp) && donerec == 0)
1.1 tholo 342: recbld();
343: if (!isnum(vp)) { /* not a number */
344: vp->fval = atof(vp->sval); /* best guess */
345: if (isnumber(vp->sval) && !(vp->tval&CON))
346: vp->tval |= NUM; /* make NUM only sparingly */
347: }
1.3 ! kstailey 348: dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
1.1 tholo 349: return(vp->fval);
350: }
351:
352: char *getsval(Cell *vp) /* get string val of a Cell */
353: {
1.3 ! kstailey 354: char s[100]; /* BUG: unchecked */
1.1 tholo 355: double dtemp;
356:
357: if ((vp->tval & (NUM | STR)) == 0)
358: funnyvar(vp, "read value of");
1.3 ! kstailey 359: if (isfld(vp) && donefld == 0)
1.1 tholo 360: fldbld();
1.3 ! kstailey 361: else if (isrec(vp) && donerec == 0)
1.1 tholo 362: recbld();
1.3 ! kstailey 363: if (isstr(vp) == 0) {
! 364: if (freeable(vp))
1.1 tholo 365: xfree(vp->sval);
366: if (modf(vp->fval, &dtemp) == 0) /* it's integral */
1.3 ! kstailey 367: sprintf(s, "%.30g", vp->fval);
1.1 tholo 368: else
1.3 ! kstailey 369: sprintf(s, *CONVFMT, vp->fval);
1.1 tholo 370: vp->sval = tostring(s);
371: vp->tval &= ~DONTFREE;
372: vp->tval |= STR;
373: }
1.3 ! kstailey 374: dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) );
1.1 tholo 375: return(vp->sval);
376: }
377:
378: char *tostring(char *s) /* make a copy of string s */
379: {
380: char *p;
381:
1.3 ! kstailey 382: p = (char *) malloc(strlen(s)+1);
1.1 tholo 383: if (p == NULL)
384: ERROR "out of space in tostring on %s", s FATAL;
1.3 ! kstailey 385: strcpy(p, s);
1.1 tholo 386: return(p);
387: }
388:
389: char *qstring(char *s, int delim) /* collect string up to next delim */
390: {
391: int c, n;
1.3 ! kstailey 392: char *buf = 0, *bp;
1.1 tholo 393:
1.3 ! kstailey 394: if ((buf = (char *) malloc(strlen(s)+3)) == NULL)
! 395: ERROR "out of space in qstring(%s)", s);
! 396: for (bp = buf; (c = *s) != delim; s++) {
1.1 tholo 397: if (c == '\n')
1.3 ! kstailey 398: ERROR "newline in string %.10s...", buf SYNTAX;
1.1 tholo 399: else if (c != '\\')
1.3 ! kstailey 400: *bp++ = c;
! 401: else { /* \something */
1.1 tholo 402: switch (c = *++s) {
1.3 ! kstailey 403: case '\\': *bp++ = '\\'; break;
! 404: case 'n': *bp++ = '\n'; break;
! 405: case 't': *bp++ = '\t'; break;
! 406: case 'b': *bp++ = '\b'; break;
! 407: case 'f': *bp++ = '\f'; break;
! 408: case 'r': *bp++ = '\r'; break;
1.1 tholo 409: default:
410: if (!isdigit(c)) {
1.3 ! kstailey 411: *bp++ = c;
1.1 tholo 412: break;
413: }
414: n = c - '0';
415: if (isdigit(s[1])) {
416: n = 8 * n + *++s - '0';
417: if (isdigit(s[1]))
418: n = 8 * n + *++s - '0';
419: }
1.3 ! kstailey 420: *bp++ = n;
1.1 tholo 421: break;
422: }
1.3 ! kstailey 423: }
1.1 tholo 424: }
1.3 ! kstailey 425: *bp++ = 0;
! 426: return buf;
1.1 tholo 427: }