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