tran.c - 9base - revived minimalist port of Plan 9 userland to Unix | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tran.c (11856B) | |
--- | |
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 … | |
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 fil… | |
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]; defaul… | |
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 co… | |
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,… | |
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)->sv… | |
81 CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symta… | |
82 FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)… | |
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)… | |
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 … | |
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 dow… | |
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 … | |
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… | |
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=%… | |
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 on… | |
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 runn… | |
248 return; /* someone else will run out late… | |
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-… | |
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-… | |
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, … | |
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->nva… | |
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 sparing… | |
348 } | |
349 dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fv… | |
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->nva… | |
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 de… | |
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 } | |
435 |