]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/awk/tran.c
merge
[plan9front.git] / sys / src / cmd / awk / tran.c
1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
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 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.
14
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 ****************************************************************/
24
25 #include <u.h>
26 #include <libc.h>
27 #include <ctype.h>
28 #include <bio.h>
29 #include "awk.h"
30 #include "y.tab.h"
31
32 #define FULLTAB 2       /* rehash when table gets this x full */
33 #define GROWTAB 4       /* grow table by this factor */
34
35 Array   *symtab;        /* main symbol table */
36
37 char    **FS;           /* initial field sep */
38 char    **RS;           /* initial record sep */
39 char    **OFS;          /* output field sep */
40 char    **ORS;          /* output record sep */
41 char    **OFMT;         /* output format for numbers */
42 char    **CONVFMT;      /* format for conversions in getsval */
43 Awkfloat *NF;           /* number of fields in current record */
44 Awkfloat *NR;           /* number of current record */
45 Awkfloat *FNR;          /* number of current record in current file */
46 char    **FILENAME;     /* current filename argument */
47 Awkfloat *AARGC;                /* number of arguments from command line */
48 char    **SUBSEP;       /* subscript separator for a[i,j,k]; default \034 */
49 Awkfloat *RSTART;       /* start of re matched with ~; origin 1 (!) */
50 Awkfloat *RLENGTH;      /* length of same */
51
52 Cell    *nrloc;         /* NR */
53 Cell    *nfloc;         /* NF */
54 Cell    *fnrloc;        /* FNR */
55 Array   *ARGVtab;       /* symbol table containing ARGV[...] */
56 Array   *ENVtab;        /* symbol table containing ENVIRON[...] */
57 Cell    *rstartloc;     /* RSTART */
58 Cell    *rlengthloc;    /* RLENGTH */
59 Cell    *symtabloc;     /* SYMTAB */
60
61 Cell    *nullloc;       /* a guaranteed empty cell */
62 Node    *nullnode;      /* zero&null, converted into a node for comparisons */
63 Cell    *literal0;
64
65 extern Cell **fldtab;
66
67 void syminit(void)      /* initialize symbol table with builtin vars */
68 {
69         literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
70         /* this is used for if(x)... tests: */
71         nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
72         nullnode = celltonode(nullloc, CCON);
73
74         FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
75         RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
76         OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
77         ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
78         OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
79         CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
80         FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
81         nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
82         NF = &nfloc->fval;
83         nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
84         NR = &nrloc->fval;
85         fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
86         FNR = &fnrloc->fval;
87         SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
88         rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
89         RSTART = &rstartloc->fval;
90         rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
91         RLENGTH = &rlengthloc->fval;
92         symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
93         symtabloc->sval = (char *) symtab;
94 }
95
96 void arginit(int ac, char **av) /* set up ARGV and ARGC */
97 {
98         Cell *cp;
99         int i;
100         char temp[50];
101
102         AARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
103         cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
104         ARGVtab = makesymtab(NSYMTAB);  /* could be (int) ARGC as well */
105         cp->sval = (char *) ARGVtab;
106         for (i = 0; i < ac; i++) {
107                 sprint(temp, "%d", i);
108                 if (is_number(*av))
109                         setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
110                 else
111                         setsymtab(temp, *av, 0.0, STR, ARGVtab);
112                 av++;
113         }
114 }
115
116 void envinit(void)      /* set up ENVIRON variable */
117 {
118         int     fd, i, n;
119         char    *k, *v;
120         Dir     *buf;
121
122         ENVtab = makesymtab(NSYMTAB);
123         if ((fd = open("/env", OREAD)) < 0)
124                 return;
125
126         buf = nil;
127         while((n = dirread(fd, &buf)) > 0) {
128                 for (i = 0; i < n; i++) {
129                         k = buf[i].name;
130                         if(strncmp(k, "fn#", 3) == 0)
131                                 continue;
132                         if ((v = getenv(k)) == nil)
133                                 continue;
134                         if (is_number(v))
135                                 setsymtab(k, v, atof(v), STR|NUM, ENVtab);
136                         else
137                                 setsymtab(k, v, 0.0, STR, ENVtab);
138                         free(v);
139                 }
140                 free(buf);
141                 buf = nil;
142         }
143
144         close(fd);
145 }
146
147 Array *makesymtab(int n)        /* make a new symbol table */
148 {
149         Array *ap;
150         Cell **tp;
151
152         ap = (Array *) malloc(sizeof(Array));
153         tp = (Cell **) calloc(n, sizeof(Cell *));
154         if (ap == nil || tp == nil)
155                 FATAL("out of space in makesymtab");
156         ap->nelemt = 0;
157         ap->size = n;
158         ap->tab = tp;
159         return(ap);
160 }
161
162 void freesymtab(Cell *ap)       /* free a symbol table */
163 {
164         Cell *cp, *temp;
165         Array *tp;
166         int i;
167
168         if (!isarr(ap))
169                 return;
170         tp = (Array *) ap->sval;
171         if (tp == nil)
172                 return;
173         for (i = 0; i < tp->size; i++) {
174                 for (cp = tp->tab[i]; cp != nil; cp = temp) {
175                         xfree(cp->nval);
176                         if (freeable(cp))
177                                 xfree(cp->sval);
178                         temp = cp->cnext;       /* avoids freeing then using */
179                         free(cp); 
180                 }
181                 tp->tab[i] = 0;
182         }
183         free(tp->tab);
184         free(tp);
185 }
186
187 void freeelem(Cell *ap, char *s)        /* free elem s from ap (i.e., ap["s"] */
188 {
189         Array *tp;
190         Cell *p, *prev = nil;
191         int h;
192         
193         tp = (Array *) ap->sval;
194         h = hash(s, tp->size);
195         for (p = tp->tab[h]; p != nil; prev = p, p = p->cnext)
196                 if (strcmp(s, p->nval) == 0) {
197                         if (prev == nil)        /* 1st one */
198                                 tp->tab[h] = p->cnext;
199                         else                    /* middle somewhere */
200                                 prev->cnext = p->cnext;
201                         if (freeable(p))
202                                 xfree(p->sval);
203                         free(p->nval);
204                         free(p);
205                         tp->nelemt--;
206                         return;
207                 }
208 }
209
210 Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp)
211 {
212         int h;
213         Cell *p;
214
215         if (n != nil && (p = lookup(n, tp)) != nil) {
216                    dprint( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
217                         p, p->nval, p->sval, p->fval, p->tval) );
218                 return(p);
219         }
220         p = (Cell *) malloc(sizeof(Cell));
221         if (p == nil)
222                 FATAL("out of space for symbol table at %s", n);
223         p->nval = tostring(n);
224         p->fval = f;
225         if(tp == symtab && strcmp(n, "ENVIRON") == 0 && !safe) {
226                 envinit();
227                 p->sval = (char *) ENVtab;
228                 p->tval = ARR;
229         } else {
230                 p->sval = s ? tostring(s) : tostring("");
231                 p->tval = t;
232         }
233         p->csub = CUNK;
234         p->ctype = OCELL;
235         tp->nelemt++;
236         if (tp->nelemt > FULLTAB * tp->size)
237                 rehash(tp);
238         h = hash(n, tp->size);
239         p->cnext = tp->tab[h];
240         tp->tab[h] = p;
241            dprint( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
242                 p, p->nval, p->sval, p->fval, p->tval) );
243         return(p);
244 }
245
246 int hash(char *s, int n)        /* form hash value for string s */
247 {
248         unsigned hashval;
249
250         for (hashval = 0; *s != '\0'; s++)
251                 hashval = (*s + 31 * hashval);
252         return hashval % n;
253 }
254
255 void rehash(Array *tp)  /* rehash items in small table into big one */
256 {
257         int i, nh, nsz;
258         Cell *cp, *op, **np;
259
260         nsz = GROWTAB * tp->size;
261         np = (Cell **) calloc(nsz, sizeof(Cell *));
262         if (np == nil)          /* can't do it, but can keep running. */
263                 return;         /* someone else will run out later. */
264         for (i = 0; i < tp->size; i++) {
265                 for (cp = tp->tab[i]; cp; cp = op) {
266                         op = cp->cnext;
267                         nh = hash(cp->nval, nsz);
268                         cp->cnext = np[nh];
269                         np[nh] = cp;
270                 }
271         }
272         free(tp->tab);
273         tp->tab = np;
274         tp->size = nsz;
275 }
276
277 Cell *lookup(char *s, Array *tp)        /* look for s in tp */
278 {
279         Cell *p;
280         int h;
281
282         h = hash(s, tp->size);
283         for (p = tp->tab[h]; p != nil; p = p->cnext)
284                 if (strcmp(s, p->nval) == 0)
285                         return(p);      /* found it */
286         return(nil);                    /* not found */
287 }
288
289 Awkfloat setfval(Cell *vp, Awkfloat f)  /* set float val of a Cell */
290 {
291         int fldno;
292
293         if ((vp->tval & (NUM | STR)) == 0) 
294                 funnyvar(vp, "assign to");
295         if (isfld(vp)) {
296                 donerec = 0;    /* mark $0 invalid */
297                 fldno = atoi(vp->nval);
298                 if (fldno > *NF)
299                         newfld(fldno);
300                    dprint( ("setting field %d to %g\n", fldno, f) );
301         } else if (isrec(vp)) {
302                 donefld = 0;    /* mark $1... invalid */
303                 donerec = 1;
304         }
305         if (freeable(vp))
306                 xfree(vp->sval); /* free any previous string */
307         vp->tval &= ~STR;       /* mark string invalid */
308         vp->tval |= NUM;        /* mark number ok */
309            dprint( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
310         return vp->fval = f;
311 }
312
313 void funnyvar(Cell *vp, char *rw)
314 {
315         if (isarr(vp))
316                 FATAL("can't %s %s; it's an array name.", rw, vp->nval);
317         if (vp->tval & FCN)
318                 FATAL("can't %s %s; it's a function.", rw, vp->nval);
319         WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
320                 vp, vp->nval, vp->sval, vp->fval, vp->tval);
321 }
322
323 char *setsval(Cell *vp, char *s)        /* set string val of a Cell */
324 {
325         char *t;
326         int fldno;
327
328            dprint( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
329         if ((vp->tval & (NUM | STR)) == 0)
330                 funnyvar(vp, "assign to");
331         if (isfld(vp)) {
332                 donerec = 0;    /* mark $0 invalid */
333                 fldno = atoi(vp->nval);
334                 if (fldno > *NF)
335                         newfld(fldno);
336                    dprint( ("setting field %d to %s (%p)\n", fldno, s, s) );
337         } else if (isrec(vp)) {
338                 donefld = 0;    /* mark $1... invalid */
339                 donerec = 1;
340         }
341         t = tostring(s);        /* in case it's self-assign */
342         vp->tval &= ~NUM;
343         vp->tval |= STR;
344         if (freeable(vp))
345                 xfree(vp->sval);
346         vp->tval &= ~DONTFREE;
347            dprint( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) );
348         return(vp->sval = t);
349 }
350
351 Awkfloat getfval(Cell *vp)      /* get float val of a Cell */
352 {
353         if ((vp->tval & (NUM | STR)) == 0)
354                 funnyvar(vp, "read value of");
355         if (isfld(vp) && donefld == 0)
356                 fldbld();
357         else if (isrec(vp) && donerec == 0)
358                 recbld();
359         if (!isnum(vp)) {       /* not a number */
360                 vp->fval = atof(vp->sval);      /* best guess */
361                 if (is_number(vp->sval) && !(vp->tval&CON))
362                         vp->tval |= NUM;        /* make NUM only sparingly */
363         }
364            dprint( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
365         return(vp->fval);
366 }
367
368 char *getsval(Cell *vp) /* get string val of a Cell */
369 {
370         char s[100];    /* BUG: unchecked */
371         double dtemp;
372
373         if ((vp->tval & (NUM | STR)) == 0)
374                 funnyvar(vp, "read value of");
375         if (isfld(vp) && donefld == 0)
376                 fldbld();
377         else if (isrec(vp) && donerec == 0)
378                 recbld();
379         if (isstr(vp) == 0) {
380                 if (freeable(vp))
381                         xfree(vp->sval);
382                 if (modf(vp->fval, &dtemp) == 0)        /* it's integral */
383                         sprint(s, "%.30g", vp->fval);
384                 else
385                         sprint(s, *CONVFMT, vp->fval);
386                 vp->sval = tostring(s);
387                 vp->tval &= ~DONTFREE;
388                 vp->tval |= STR;
389         }
390            dprint( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) );
391         return(vp->sval);
392 }
393
394 char *tostring(char *s) /* make a copy of string s */
395 {
396         char *p;
397
398         p = (char *) malloc(strlen(s)+1);
399         if (p == nil)
400                 FATAL("out of space in tostring on %s", s);
401         strcpy(p, s);
402         return(p);
403 }
404
405 char *qstring(char *s, int delim)       /* collect string up to next delim */
406 {
407         char *os = s;
408         int c, n;
409         char *buf, *bp;
410
411         if ((buf = (char *) malloc(strlen(s)+3)) == nil)
412                 FATAL( "out of space in qstring(%s)", s);
413         for (bp = buf; (c = *s) != delim; s++) {
414                 if (c == '\n')
415                         SYNTAX( "newline in string %.20s...", os );
416                 else if (c != '\\')
417                         *bp++ = c;
418                 else {  /* \something */
419                         c = *++s;
420                         if (c == 0) {   /* \ at end */
421                                 *bp++ = '\\';
422                                 break;  /* for loop */
423                         }       
424                         switch (c) {
425                         case '\\':      *bp++ = '\\'; break;
426                         case 'n':       *bp++ = '\n'; break;
427                         case 't':       *bp++ = '\t'; break;
428                         case 'b':       *bp++ = '\b'; break;
429                         case 'f':       *bp++ = '\f'; break;
430                         case 'r':       *bp++ = '\r'; break;
431                         default:
432                                 if (!isdigit(c)) {
433                                         *bp++ = c;
434                                         break;
435                                 }
436                                 n = c - '0';
437                                 if (isdigit(s[1])) {
438                                         n = 8 * n + *++s - '0';
439                                         if (isdigit(s[1]))
440                                                 n = 8 * n + *++s - '0';
441                                 }
442                                 *bp++ = n;
443                                 break;
444                         }
445                 }
446         }
447         *bp = 0;
448         return buf;
449 }