]> 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(char **envp)       /* set up ENVIRON variable */
117 {
118         Cell *cp;
119         char *p;
120
121         cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
122         ENVtab = makesymtab(NSYMTAB);
123         cp->sval = (char *) ENVtab;
124         for ( ; *envp; envp++) {
125                 if ((p = strchr(*envp, '=')) == nil)
126                         continue;
127                 *p++ = 0;       /* split into two strings at = */
128                 if (is_number(p))
129                         setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
130                 else
131                         setsymtab(*envp, p, 0.0, STR, ENVtab);
132                 p[-1] = '=';    /* restore in case env is passed down to a shell */
133         }
134 }
135
136 Array *makesymtab(int n)        /* make a new symbol table */
137 {
138         Array *ap;
139         Cell **tp;
140
141         ap = (Array *) malloc(sizeof(Array));
142         tp = (Cell **) calloc(n, sizeof(Cell *));
143         if (ap == nil || tp == nil)
144                 FATAL("out of space in makesymtab");
145         ap->nelemt = 0;
146         ap->size = n;
147         ap->tab = tp;
148         return(ap);
149 }
150
151 void freesymtab(Cell *ap)       /* free a symbol table */
152 {
153         Cell *cp, *temp;
154         Array *tp;
155         int i;
156
157         if (!isarr(ap))
158                 return;
159         tp = (Array *) ap->sval;
160         if (tp == nil)
161                 return;
162         for (i = 0; i < tp->size; i++) {
163                 for (cp = tp->tab[i]; cp != nil; cp = temp) {
164                         xfree(cp->nval);
165                         if (freeable(cp))
166                                 xfree(cp->sval);
167                         temp = cp->cnext;       /* avoids freeing then using */
168                         free(cp); 
169                 }
170                 tp->tab[i] = 0;
171         }
172         free(tp->tab);
173         free(tp);
174 }
175
176 void freeelem(Cell *ap, char *s)        /* free elem s from ap (i.e., ap["s"] */
177 {
178         Array *tp;
179         Cell *p, *prev = nil;
180         int h;
181         
182         tp = (Array *) ap->sval;
183         h = hash(s, tp->size);
184         for (p = tp->tab[h]; p != nil; prev = p, p = p->cnext)
185                 if (strcmp(s, p->nval) == 0) {
186                         if (prev == nil)        /* 1st one */
187                                 tp->tab[h] = p->cnext;
188                         else                    /* middle somewhere */
189                                 prev->cnext = p->cnext;
190                         if (freeable(p))
191                                 xfree(p->sval);
192                         free(p->nval);
193                         free(p);
194                         tp->nelemt--;
195                         return;
196                 }
197 }
198
199 Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp)
200 {
201         int h;
202         Cell *p;
203
204         if (n != nil && (p = lookup(n, tp)) != nil) {
205                    dprint( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
206                         p, p->nval, p->sval, p->fval, p->tval) );
207                 return(p);
208         }
209         p = (Cell *) malloc(sizeof(Cell));
210         if (p == nil)
211                 FATAL("out of space for symbol table at %s", n);
212         p->nval = tostring(n);
213         p->sval = s ? tostring(s) : tostring("");
214         p->fval = f;
215         p->tval = t;
216         p->csub = CUNK;
217         p->ctype = OCELL;
218         tp->nelemt++;
219         if (tp->nelemt > FULLTAB * tp->size)
220                 rehash(tp);
221         h = hash(n, tp->size);
222         p->cnext = tp->tab[h];
223         tp->tab[h] = p;
224            dprint( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
225                 p, p->nval, p->sval, p->fval, p->tval) );
226         return(p);
227 }
228
229 int hash(char *s, int n)        /* form hash value for string s */
230 {
231         unsigned hashval;
232
233         for (hashval = 0; *s != '\0'; s++)
234                 hashval = (*s + 31 * hashval);
235         return hashval % n;
236 }
237
238 void rehash(Array *tp)  /* rehash items in small table into big one */
239 {
240         int i, nh, nsz;
241         Cell *cp, *op, **np;
242
243         nsz = GROWTAB * tp->size;
244         np = (Cell **) calloc(nsz, sizeof(Cell *));
245         if (np == nil)          /* can't do it, but can keep running. */
246                 return;         /* someone else will run out later. */
247         for (i = 0; i < tp->size; i++) {
248                 for (cp = tp->tab[i]; cp; cp = op) {
249                         op = cp->cnext;
250                         nh = hash(cp->nval, nsz);
251                         cp->cnext = np[nh];
252                         np[nh] = cp;
253                 }
254         }
255         free(tp->tab);
256         tp->tab = np;
257         tp->size = nsz;
258 }
259
260 Cell *lookup(char *s, Array *tp)        /* look for s in tp */
261 {
262         Cell *p;
263         int h;
264
265         h = hash(s, tp->size);
266         for (p = tp->tab[h]; p != nil; p = p->cnext)
267                 if (strcmp(s, p->nval) == 0)
268                         return(p);      /* found it */
269         return(nil);                    /* not found */
270 }
271
272 Awkfloat setfval(Cell *vp, Awkfloat f)  /* set float val of a Cell */
273 {
274         int fldno;
275
276         if ((vp->tval & (NUM | STR)) == 0) 
277                 funnyvar(vp, "assign to");
278         if (isfld(vp)) {
279                 donerec = 0;    /* mark $0 invalid */
280                 fldno = atoi(vp->nval);
281                 if (fldno > *NF)
282                         newfld(fldno);
283                    dprint( ("setting field %d to %g\n", fldno, f) );
284         } else if (isrec(vp)) {
285                 donefld = 0;    /* mark $1... invalid */
286                 donerec = 1;
287         }
288         if (freeable(vp))
289                 xfree(vp->sval); /* free any previous string */
290         vp->tval &= ~STR;       /* mark string invalid */
291         vp->tval |= NUM;        /* mark number ok */
292            dprint( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
293         return vp->fval = f;
294 }
295
296 void funnyvar(Cell *vp, char *rw)
297 {
298         if (isarr(vp))
299                 FATAL("can't %s %s; it's an array name.", rw, vp->nval);
300         if (vp->tval & FCN)
301                 FATAL("can't %s %s; it's a function.", rw, vp->nval);
302         WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
303                 vp, vp->nval, vp->sval, vp->fval, vp->tval);
304 }
305
306 char *setsval(Cell *vp, char *s)        /* set string val of a Cell */
307 {
308         char *t;
309         int fldno;
310
311            dprint( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
312         if ((vp->tval & (NUM | STR)) == 0)
313                 funnyvar(vp, "assign to");
314         if (isfld(vp)) {
315                 donerec = 0;    /* mark $0 invalid */
316                 fldno = atoi(vp->nval);
317                 if (fldno > *NF)
318                         newfld(fldno);
319                    dprint( ("setting field %d to %s (%p)\n", fldno, s, s) );
320         } else if (isrec(vp)) {
321                 donefld = 0;    /* mark $1... invalid */
322                 donerec = 1;
323         }
324         t = tostring(s);        /* in case it's self-assign */
325         vp->tval &= ~NUM;
326         vp->tval |= STR;
327         if (freeable(vp))
328                 xfree(vp->sval);
329         vp->tval &= ~DONTFREE;
330            dprint( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) );
331         return(vp->sval = t);
332 }
333
334 Awkfloat getfval(Cell *vp)      /* get float val of a Cell */
335 {
336         if ((vp->tval & (NUM | STR)) == 0)
337                 funnyvar(vp, "read value of");
338         if (isfld(vp) && donefld == 0)
339                 fldbld();
340         else if (isrec(vp) && donerec == 0)
341                 recbld();
342         if (!isnum(vp)) {       /* not a number */
343                 vp->fval = atof(vp->sval);      /* best guess */
344                 if (is_number(vp->sval) && !(vp->tval&CON))
345                         vp->tval |= NUM;        /* make NUM only sparingly */
346         }
347            dprint( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
348         return(vp->fval);
349 }
350
351 char *getsval(Cell *vp) /* get string val of a Cell */
352 {
353         char s[100];    /* BUG: unchecked */
354         double dtemp;
355
356         if ((vp->tval & (NUM | STR)) == 0)
357                 funnyvar(vp, "read value of");
358         if (isfld(vp) && donefld == 0)
359                 fldbld();
360         else if (isrec(vp) && donerec == 0)
361                 recbld();
362         if (isstr(vp) == 0) {
363                 if (freeable(vp))
364                         xfree(vp->sval);
365                 if (modf(vp->fval, &dtemp) == 0)        /* it's integral */
366                         sprint(s, "%.30g", vp->fval);
367                 else
368                         sprint(s, *CONVFMT, vp->fval);
369                 vp->sval = tostring(s);
370                 vp->tval &= ~DONTFREE;
371                 vp->tval |= STR;
372         }
373            dprint( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) );
374         return(vp->sval);
375 }
376
377 char *tostring(char *s) /* make a copy of string s */
378 {
379         char *p;
380
381         p = (char *) malloc(strlen(s)+1);
382         if (p == nil)
383                 FATAL("out of space in tostring on %s", s);
384         strcpy(p, s);
385         return(p);
386 }
387
388 char *qstring(char *s, int delim)       /* collect string up to next delim */
389 {
390         char *os = s;
391         int c, n;
392         char *buf, *bp;
393
394         if ((buf = (char *) malloc(strlen(s)+3)) == nil)
395                 FATAL( "out of space in qstring(%s)", s);
396         for (bp = buf; (c = *s) != delim; s++) {
397                 if (c == '\n')
398                         SYNTAX( "newline in string %.20s...", os );
399                 else if (c != '\\')
400                         *bp++ = c;
401                 else {  /* \something */
402                         c = *++s;
403                         if (c == 0) {   /* \ at end */
404                                 *bp++ = '\\';
405                                 break;  /* for loop */
406                         }       
407                         switch (c) {
408                         case '\\':      *bp++ = '\\'; break;
409                         case 'n':       *bp++ = '\n'; break;
410                         case 't':       *bp++ = '\t'; break;
411                         case 'b':       *bp++ = '\b'; break;
412                         case 'f':       *bp++ = '\f'; break;
413                         case 'r':       *bp++ = '\r'; break;
414                         default:
415                                 if (!isdigit(c)) {
416                                         *bp++ = c;
417                                         break;
418                                 }
419                                 n = c - '0';
420                                 if (isdigit(s[1])) {
421                                         n = 8 * n + *++s - '0';
422                                         if (isdigit(s[1]))
423                                                 n = 8 * n + *++s - '0';
424                                 }
425                                 *bp++ = n;
426                                 break;
427                         }
428                 }
429         }
430         *bp = 0;
431         return buf;
432 }