7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 #pragma ident "%Z%%M% %I% %E% SMI"
31
32 #define DEBUG
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include <string.h>
37 #include "awk.h"
38 #include "y.tab.h"
39
40 #define FULLTAB 2 /* rehash when table gets this x full */
41 #define GROWTAB 4 /* grow table by this factor */
42
43 Array *symtab; /* main symbol table */
44
45 uchar **FS; /* initial field sep */
46 uchar **RS; /* initial record sep */
47 uchar **OFS; /* output field sep */
48 uchar **ORS; /* output record sep */
49 uchar **OFMT; /* output format for numbers */
50 Awkfloat *NF; /* number of fields in current record */
51 Awkfloat *NR; /* number of current record */
52 Awkfloat *FNR; /* number of current record in current file */
53 uchar **FILENAME; /* current filename argument */
54 Awkfloat *ARGC; /* number of arguments from command line */
55 uchar **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
56 Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
57 Awkfloat *RLENGTH; /* length of same */
58
59 Cell *recloc; /* location of record */
60 Cell *nrloc; /* NR */
61 Cell *nfloc; /* NF */
62 Cell *fnrloc; /* FNR */
63 Array *ARGVtab; /* symbol table containing ARGV[...] */
64 Array *ENVtab; /* symbol table containing ENVIRON[...] */
65 Cell *rstartloc; /* RSTART */
66 Cell *rlengthloc; /* RLENGTH */
67 Cell *symtabloc; /* SYMTAB */
68
69 Cell *nullloc;
70 Node *nullnode; /* zero&null, converted into a node for comparisons */
71
72 static void rehash(Array *);
73
74 void
75 syminit(void)
76 {
77 init_buf(&record, &record_size, LINE_INCR);
78
79 /* initialize $0 */
80 recloc = getfld(0);
81 recloc->nval = (uchar *)"$0";
82 recloc->sval = record;
83 recloc->tval = REC|STR|DONTFREE;
84
85 symtab = makesymtab(NSYMTAB);
86 (void) setsymtab((uchar *)"0", (uchar *)"0", 0.0,
87 NUM|STR|CON|DONTFREE, symtab);
88 /* this is used for if(x)... tests: */
89 nullloc = setsymtab((uchar *)"$zero&null", (uchar *)"", 0.0,
90 NUM|STR|CON|DONTFREE, symtab);
91 nullnode = valtonode(nullloc, CCON);
92 FS = &setsymtab((uchar *)"FS", (uchar *)" ", 0.0,
93 STR|DONTFREE, symtab)->sval;
94 RS = &setsymtab((uchar *)"RS", (uchar *)"\n", 0.0,
95 STR|DONTFREE, symtab)->sval;
96 OFS = &setsymtab((uchar *)"OFS", (uchar *)" ", 0.0,
97 STR|DONTFREE, symtab)->sval;
98 ORS = &setsymtab((uchar *)"ORS", (uchar *)"\n", 0.0,
99 STR|DONTFREE, symtab)->sval;
100 OFMT = &setsymtab((uchar *)"OFMT", (uchar *)"%.6g", 0.0,
101 STR|DONTFREE, symtab)->sval;
102 FILENAME = &setsymtab((uchar *)"FILENAME", (uchar *)"-", 0.0,
103 STR|DONTFREE, symtab)->sval;
104 nfloc = setsymtab((uchar *)"NF", (uchar *)"", 0.0, NUM, symtab);
105 NF = &nfloc->fval;
106 nrloc = setsymtab((uchar *)"NR", (uchar *)"", 0.0, NUM, symtab);
107 NR = &nrloc->fval;
108 fnrloc = setsymtab((uchar *)"FNR", (uchar *)"", 0.0, NUM, symtab);
109 FNR = &fnrloc->fval;
110 SUBSEP = &setsymtab((uchar *)"SUBSEP", (uchar *)"\034", 0.0,
111 STR|DONTFREE, symtab)->sval;
112 rstartloc = setsymtab((uchar *)"RSTART", (uchar *)"", 0.0,
113 NUM, symtab);
114 RSTART = &rstartloc->fval;
115 rlengthloc = setsymtab((uchar *)"RLENGTH", (uchar *)"", 0.0,
116 NUM, symtab);
117 RLENGTH = &rlengthloc->fval;
118 symtabloc = setsymtab((uchar *)"SYMTAB", (uchar *)"", 0.0, ARR, symtab);
119 symtabloc->sval = (uchar *)symtab;
120 }
121
122 void
123 arginit(int ac, uchar *av[])
124 {
125 Cell *cp;
126 int i;
127 uchar temp[11];
128
129 /* first make FILENAME first real argument */
130 for (i = 1; i < ac; i++) {
131 if (!isclvar(av[i])) {
132 (void) setsval(lookup((uchar *)"FILENAME", symtab),
133 av[i]);
134 break;
135 }
136 }
137 ARGC = &setsymtab((uchar *)"ARGC", (uchar *)"", (Awkfloat)ac,
138 NUM, symtab)->fval;
139 cp = setsymtab((uchar *)"ARGV", (uchar *)"", 0.0, ARR, symtab);
140 ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
141 cp->sval = (uchar *) ARGVtab;
142 for (i = 0; i < ac; i++) {
143 (void) sprintf((char *)temp, "%d", i);
144 if (is_number(*av)) {
145 (void) setsymtab(temp, *av, atof((const char *)*av),
146 STR|NUM, ARGVtab);
147 } else {
148 (void) setsymtab(temp, *av, 0.0, STR, ARGVtab);
149 }
150 av++;
151 }
152 }
153
154 void
155 envinit(uchar *envp[])
156 {
157 Cell *cp;
158 uchar *p;
159
160 cp = setsymtab((uchar *)"ENVIRON", (uchar *)"", 0.0, ARR, symtab);
161 ENVtab = makesymtab(NSYMTAB);
162 cp->sval = (uchar *) ENVtab;
163 for (; *envp; envp++) {
164 if ((p = (uchar *)strchr((char *)*envp, '=')) == NULL)
165 continue;
166 *p++ = 0; /* split into two strings at = */
167 if (is_number(p)) {
168 (void) setsymtab(*envp, p, atof((const char *)p),
169 STR|NUM, ENVtab);
170 } else {
171 (void) setsymtab(*envp, p, 0.0, STR, ENVtab);
172 }
173 /* restore in case env is passed down to a shell */
174 p[-1] = '=';
175 }
176 }
177
178 Array *
179 makesymtab(int n)
180 {
181 Array *ap;
182 Cell **tp;
183
184 ap = (Array *)malloc(sizeof (Array));
185 tp = (Cell **)calloc(n, sizeof (Cell *));
186 if (ap == NULL || tp == NULL)
187 ERROR "out of space in makesymtab" FATAL;
188 ap->nelem = 0;
189 ap->size = n;
190 ap->tab = tp;
191 return (ap);
192 }
193
194 void
195 freesymtab(Cell *ap) /* free symbol table */
196 {
197 Cell *cp, *next;
198 Array *tp;
199 int i;
200
201 if (!isarr(ap))
202 return;
203 /*LINTED align*/
204 tp = (Array *)ap->sval;
205 if (tp == NULL)
206 return;
207 for (i = 0; i < tp->size; i++) {
208 for (cp = tp->tab[i]; cp != NULL; cp = next) {
209 next = cp->cnext;
210 xfree(cp->nval);
211 if (freeable(cp))
212 xfree(cp->sval);
213 free(cp);
214 }
215 }
216 free(tp->tab);
217 free(tp);
218 }
219
220 void
221 freeelem(Cell *ap, uchar *s) /* free elem s from ap (i.e., ap["s"] */
222 {
223 Array *tp;
224 Cell *p, *prev = NULL;
225 int h;
226
227 /*LINTED align*/
228 tp = (Array *)ap->sval;
229 h = hash(s, tp->size);
230 for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
231 if (strcmp((char *)s, (char *)p->nval) == 0) {
232 if (prev == NULL) /* 1st one */
233 tp->tab[h] = p->cnext;
234 else /* middle somewhere */
235 prev->cnext = p->cnext;
236 if (freeable(p))
237 xfree(p->sval);
238 free(p->nval);
239 free(p);
240 tp->nelem--;
241 return;
242 }
243 }
244
245 Cell *
246 setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned int t, Array *tp)
247 {
248 register int h;
249 register Cell *p;
250
251 if (n != NULL && (p = lookup(n, tp)) != NULL) {
252 dprintf(("setsymtab found %p: n=%s", (void *)p, p->nval));
253 dprintf((" s=\"%s\" f=%g t=%p\n",
254 p->sval, p->fval, (void *)p->tval));
255 return (p);
256 }
257 p = (Cell *)malloc(sizeof (Cell));
258 if (p == NULL)
259 ERROR "symbol table overflow at %s", n FATAL;
260 p->nval = tostring(n);
261 p->sval = s ? tostring(s) : tostring((uchar *)"");
262 p->fval = f;
263 p->tval = t;
264 p->csub = 0;
265
266 tp->nelem++;
267 if (tp->nelem > FULLTAB * tp->size)
268 rehash(tp);
269 h = hash(n, tp->size);
270 p->cnext = tp->tab[h];
271 tp->tab[h] = p;
272 dprintf(("setsymtab set %p: n=%s", (void *)p, p->nval));
273 dprintf((" s=\"%s\" f=%g t=%p\n", p->sval, p->fval, (void *)p->tval));
274 return (p);
275 }
276
277 int
278 hash(uchar *s, int n) /* form hash value for string s */
279 {
280 register unsigned hashval;
281
282 for (hashval = 0; *s != '\0'; s++)
283 hashval = (*s + 31 * hashval);
284 return (hashval % n);
285 }
286
287 static void
288 rehash(Array *tp) /* rehash items in small table into big one */
289 {
290 int i, nh, nsz;
291 Cell *cp, *op, **np;
292
293 nsz = GROWTAB * tp->size;
294 np = (Cell **)calloc(nsz, sizeof (Cell *));
295 if (np == NULL)
296 ERROR "out of space in rehash" FATAL;
297 for (i = 0; i < tp->size; i++) {
298 for (cp = tp->tab[i]; cp; cp = op) {
299 op = cp->cnext;
300 nh = hash(cp->nval, nsz);
301 cp->cnext = np[nh];
302 np[nh] = cp;
303 }
304 }
305 free(tp->tab);
306 tp->tab = np;
307 tp->size = nsz;
308 }
309
310 Cell *
311 lookup(uchar *s, Array *tp) /* look for s in tp */
312 {
313 register Cell *p;
314 int h;
315
316 h = hash(s, tp->size);
317 for (p = tp->tab[h]; p != NULL; p = p->cnext) {
318 if (strcmp((char *)s, (char *)p->nval) == 0)
319 return (p); /* found it */
320 }
321 return (NULL); /* not found */
322 }
323
324 Awkfloat
325 setfval(Cell *vp, Awkfloat f)
326 {
327 int i;
328
329 if ((vp->tval & (NUM | STR)) == 0)
330 funnyvar(vp, "assign to");
331 if (vp->tval & FLD) {
332 donerec = 0; /* mark $0 invalid */
333 i = fldidx(vp);
334 if (i > *NF)
335 newfld(i);
336 dprintf(("setting field %d to %g\n", i, f));
337 } else if (vp->tval & REC) {
338 donefld = 0; /* mark $1... invalid */
339 donerec = 1;
340 }
341 vp->tval &= ~STR; /* mark string invalid */
342 vp->tval |= NUM; /* mark number ok */
343 dprintf(("setfval %p: %s = %g, t=%p\n", (void *)vp,
344 vp->nval ? vp->nval : (unsigned char *)"NULL",
345 f, (void *)vp->tval));
346 return (vp->fval = f);
347 }
348
349 void
350 funnyvar(Cell *vp, char *rw)
351 {
352 if (vp->tval & ARR)
353 ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
354 if (vp->tval & FCN)
355 ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
356 ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o",
357 vp, vp->nval, vp->sval, vp->fval, vp->tval CONT;
358 }
359
360 uchar *
361 setsval(Cell *vp, uchar *s)
362 {
363 int i;
364
365 if ((vp->tval & (NUM | STR)) == 0)
366 funnyvar(vp, "assign to");
367 if (vp->tval & FLD) {
368 donerec = 0; /* mark $0 invalid */
369 i = fldidx(vp);
370 if (i > *NF)
371 newfld(i);
372 dprintf(("setting field %d to %s\n", i, s));
373 } else if (vp->tval & REC) {
374 donefld = 0; /* mark $1... invalid */
375 donerec = 1;
376 }
377 vp->tval &= ~NUM;
378 vp->tval |= STR;
379 if (freeable(vp))
380 xfree(vp->sval);
381 vp->tval &= ~DONTFREE;
382 dprintf(("setsval %p: %s = \"%s\", t=%p\n",
383 (void *)vp,
384 vp->nval ? (char *)vp->nval : "",
385 s,
386 (void *)(vp->tval ? (char *)vp->tval : "")));
387 return (vp->sval = tostring(s));
388 }
389
390 Awkfloat
391 r_getfval(Cell *vp)
392 {
393 if ((vp->tval & (NUM | STR)) == 0)
394 funnyvar(vp, "read value of");
395 if ((vp->tval & FLD) && donefld == 0)
396 fldbld();
397 else if ((vp->tval & REC) && donerec == 0)
398 recbld();
399 if (!isnum(vp)) { /* not a number */
400 vp->fval = atof((const char *)vp->sval); /* best guess */
401 if (is_number(vp->sval) && !(vp->tval&CON))
402 vp->tval |= NUM; /* make NUM only sparingly */
403 }
404 dprintf(("getfval %p: %s = %g, t=%p\n",
405 (void *)vp, vp->nval, vp->fval, (void *)vp->tval));
406 return (vp->fval);
407 }
408
409 uchar *
410 r_getsval(Cell *vp)
411 {
412 uchar s[256];
413
414 if ((vp->tval & (NUM | STR)) == 0)
415 funnyvar(vp, "read value of");
416 if ((vp->tval & FLD) && donefld == 0)
417 fldbld();
418 else if ((vp->tval & REC) && donerec == 0)
419 recbld();
420 if ((vp->tval & STR) == 0) {
421 if (!(vp->tval&DONTFREE))
422 xfree(vp->sval);
423 if ((long long)vp->fval == vp->fval) {
424 (void) snprintf((char *)s, sizeof (s),
425 "%.20g", vp->fval);
426 } else {
427 /*LINTED*/
428 (void) snprintf((char *)s, sizeof (s),
429 (char *)*OFMT, vp->fval);
430 }
431 vp->sval = tostring(s);
432 vp->tval &= ~DONTFREE;
433 vp->tval |= STR;
434 }
435 dprintf(("getsval %p: %s = \"%s\", t=%p\n",
436 (void *)vp,
437 vp->nval ? (char *)vp->nval : "",
438 vp->sval ? (char *)vp->sval : "",
439 (void *)vp->tval));
440 return (vp->sval);
441 }
442
443 uchar *
444 tostring(uchar *s)
445 {
446 register uchar *p;
447
448 p = (uchar *)malloc(strlen((char *)s)+1);
449 if (p == NULL)
450 ERROR "out of space in tostring on %s", s FATAL;
451 (void) strcpy((char *)p, (char *)s);
452 return (p);
453 }
454
455 uchar *
456 qstring(uchar *s, int delim) /* collect string up to delim */
457 {
458 uchar *cbuf, *ret;
459 int c, n;
460 size_t cbufsz, cnt;
461
462 init_buf(&cbuf, &cbufsz, LINE_INCR);
463
464 for (cnt = 0; (c = *s) != delim; s++) {
465 if (c == '\n') {
466 ERROR "newline in string %.10s...", cbuf SYNTAX;
467 } else if (c != '\\') {
468 expand_buf(&cbuf, &cbufsz, cnt);
469 cbuf[cnt++] = c;
470 } else { /* \something */
471 expand_buf(&cbuf, &cbufsz, cnt);
472 switch (c = *++s) {
473 case '\\': cbuf[cnt++] = '\\'; break;
474 case 'n': cbuf[cnt++] = '\n'; break;
475 case 't': cbuf[cnt++] = '\t'; break;
476 case 'b': cbuf[cnt++] = '\b'; break;
477 case 'f': cbuf[cnt++] = '\f'; break;
478 case 'r': cbuf[cnt++] = '\r'; break;
479 default:
480 if (!isdigit(c)) {
481 cbuf[cnt++] = c;
482 break;
483 }
484 n = c - '0';
485 if (isdigit(s[1])) {
486 n = 8 * n + *++s - '0';
487 if (isdigit(s[1]))
488 n = 8 * n + *++s - '0';
489 }
490 cbuf[cnt++] = n;
491 break;
492 }
493 }
494 }
495 cbuf[cnt] = '\0';
496 ret = tostring(cbuf);
497 free(cbuf);
498 return (ret);
499 }
|
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright (C) Lucent Technologies 1997
29 * All Rights Reserved
30 *
31 * Permission to use, copy, modify, and distribute this software and
32 * its documentation for any purpose and without fee is hereby
33 * granted, provided that the above copyright notice appear in all
34 * copies and that both that the copyright notice and this
35 * permission notice and warranty disclaimer appear in supporting
36 * documentation, and that the name Lucent Technologies or any of
37 * its entities not be used in advertising or publicity pertaining
38 * to distribution of the software without specific, written prior
39 * permission.
40 *
41 * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
42 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
43 * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
44 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
45 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
46 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
47 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
48 * THIS SOFTWARE.
49 */
50
51 #define DEBUG
52 #include <math.h>
53 #include "awk.h"
54 #include "y.tab.h"
55
56 #define FULLTAB 2 /* rehash when table gets this x full */
57 #define GROWTAB 4 /* grow table by this factor */
58
59 Array *symtab; /* main symbol table */
60
61 uchar **FS; /* initial field sep */
62 uchar **RS; /* initial record sep */
63 uchar **OFS; /* output field sep */
64 uchar **ORS; /* output record sep */
65 uchar **OFMT; /* output format for numbers */
66 uchar **CONVFMT; /* format for conversions in getsval */
67 Awkfloat *NF; /* number of fields in current record */
68 Awkfloat *NR; /* number of current record */
69 Awkfloat *FNR; /* number of current record in current file */
70 uchar **FILENAME; /* current filename argument */
71 Awkfloat *ARGC; /* number of arguments from command line */
72 uchar **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
73 Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
74 Awkfloat *RLENGTH; /* length of same */
75
76 Cell *fsloc; /* FS */
77 Cell *nrloc; /* NR */
78 Cell *nfloc; /* NF */
79 Cell *fnrloc; /* FNR */
80 Array *ARGVtab; /* symbol table containing ARGV[...] */
81 Array *ENVtab; /* symbol table containing ENVIRON[...] */
82 Cell *rstartloc; /* RSTART */
83 Cell *rlengthloc; /* RLENGTH */
84 Cell *symtabloc; /* SYMTAB */
85
86 Cell *nullloc; /* a guaranteed empty cell */
87 Node *nullnode; /* zero&null, converted into a node for comparisons */
88 Cell *literal0;
89
90 static void rehash(Array *);
91
92 void
93 syminit(void) /* initialize symbol table with builtin vars */
94 {
95 literal0 = setsymtab((uchar *)"0", (uchar *)"0", 0.0,
96 NUM|STR|CON|DONTFREE, symtab);
97 /* this is used for if(x)... tests: */
98 nullloc = setsymtab((uchar *)"$zero&null", (uchar *)"", 0.0,
99 NUM|STR|CON|DONTFREE, symtab);
100 nullnode = celltonode(nullloc, CCON);
101
102 fsloc = setsymtab((uchar *)"FS", (uchar *)" ", 0.0,
103 STR|DONTFREE, symtab);
104 FS = &fsloc->sval;
105 RS = &setsymtab((uchar *)"RS", (uchar *)"\n", 0.0,
106 STR|DONTFREE, symtab)->sval;
107 OFS = &setsymtab((uchar *)"OFS", (uchar *)" ", 0.0,
108 STR|DONTFREE, symtab)->sval;
109 ORS = &setsymtab((uchar *)"ORS", (uchar *)"\n", 0.0,
110 STR|DONTFREE, symtab)->sval;
111 OFMT = &setsymtab((uchar *)"OFMT", (uchar *)"%.6g", 0.0,
112 STR|DONTFREE, symtab)->sval;
113 CONVFMT = &setsymtab((uchar *)"CONVFMT", (uchar *)"%.6g", 0.0,
114 STR|DONTFREE, symtab)->sval;
115 FILENAME = &setsymtab((uchar *)"FILENAME", (uchar *)"-", 0.0,
116 STR|DONTFREE, symtab)->sval;
117 nfloc = setsymtab((uchar *)"NF", (uchar *)"", 0.0, NUM, symtab);
118 NF = &nfloc->fval;
119 nrloc = setsymtab((uchar *)"NR", (uchar *)"", 0.0, NUM, symtab);
120 NR = &nrloc->fval;
121 fnrloc = setsymtab((uchar *)"FNR", (uchar *)"", 0.0, NUM, symtab);
122 FNR = &fnrloc->fval;
123 SUBSEP = &setsymtab((uchar *)"SUBSEP", (uchar *)"\034", 0.0,
124 STR|DONTFREE, symtab)->sval;
125 rstartloc = setsymtab((uchar *)"RSTART", (uchar *)"", 0.0,
126 NUM, symtab);
127 RSTART = &rstartloc->fval;
128 rlengthloc = setsymtab((uchar *)"RLENGTH", (uchar *)"", 0.0,
129 NUM, symtab);
130 RLENGTH = &rlengthloc->fval;
131 symtabloc = setsymtab((uchar *)"SYMTAB", (uchar *)"", 0.0, ARR, symtab);
132 symtabloc->sval = (uchar *)symtab;
133 }
134
135 void
136 arginit(int ac, uchar *av[]) /* set up ARGV and ARGC */
137 {
138 Cell *cp;
139 int i;
140 uchar temp[50];
141
142 ARGC = &setsymtab((uchar *)"ARGC", (uchar *)"", (Awkfloat)ac,
143 NUM, symtab)->fval;
144 cp = setsymtab((uchar *)"ARGV", (uchar *)"", 0.0, ARR, symtab);
145 ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
146 cp->sval = (uchar *)ARGVtab;
147 for (i = 0; i < ac; i++) {
148 (void) sprintf((char *)temp, "%d", i);
149 if (is_number(*av)) {
150 (void) setsymtab(temp, *av, atof((const char *)*av),
151 STR|NUM, ARGVtab);
152 } else {
153 (void) setsymtab(temp, *av, 0.0, STR, ARGVtab);
154 }
155 av++;
156 }
157 }
158
159 void
160 envinit(uchar **envp) /* set up ENVIRON variable */
161 {
162 Cell *cp;
163 uchar *p;
164
165 cp = setsymtab((uchar *)"ENVIRON", (uchar *)"", 0.0, ARR, symtab);
166 ENVtab = makesymtab(NSYMTAB);
167 cp->sval = (uchar *)ENVtab;
168 for (; *envp; envp++) {
169 if ((p = (uchar *)strchr((char *)*envp, '=')) == NULL)
170 continue;
171 if (p == *envp) /* no left hand side name in env string */
172 continue;
173 *p++ = 0; /* split into two strings at = */
174 if (is_number(p)) {
175 (void) setsymtab(*envp, p, atof((const char *)p),
176 STR|NUM, ENVtab);
177 } else {
178 (void) setsymtab(*envp, p, 0.0, STR, ENVtab);
179 }
180 /* restore in case env is passed down to a shell */
181 p[-1] = '=';
182 }
183 }
184
185 Array *
186 makesymtab(int n) /* make a new symbol table */
187 {
188 Array *ap;
189 Cell **tp;
190
191 ap = (Array *)malloc(sizeof (Array));
192 tp = (Cell **)calloc(n, sizeof (Cell *));
193 if (ap == NULL || tp == NULL)
194 FATAL("out of space in makesymtab");
195 ap->nelem = 0;
196 ap->size = n;
197 ap->tab = tp;
198 return (ap);
199 }
200
201 void
202 freesymtab(Cell *ap) /* free symbol table */
203 {
204 Cell *cp, *temp;
205 Array *tp;
206 int i;
207
208 if (!isarr(ap))
209 return;
210 /*LINTED align*/
211 tp = (Array *)ap->sval;
212 if (tp == NULL)
213 return;
214 for (i = 0; i < tp->size; i++) {
215 for (cp = tp->tab[i]; cp != NULL; cp = temp) {
216 xfree(cp->nval);
217 if (freeable(cp))
218 xfree(cp->sval);
219 /* avoids freeing then using */
220 temp = cp->cnext;
221 free(cp);
222 tp->nelem--;
223 }
224 tp->tab[i] = 0;
225 }
226 if (tp->nelem != 0)
227 WARNING("can't happen: inconsistent element count freeing %s",
228 ap->nval);
229 free(tp->tab);
230 free(tp);
231 }
232
233 void
234 freeelem(Cell *ap, const uchar *s) /* free elem s from ap (i.e., ap["s"] */
235 {
236 Array *tp;
237 Cell *p, *prev = NULL;
238 int h;
239
240 /*LINTED align*/
241 tp = (Array *)ap->sval;
242 h = hash(s, tp->size);
243 for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
244 if (strcmp((char *)s, (char *)p->nval) == 0) {
245 if (prev == NULL) /* 1st one */
246 tp->tab[h] = p->cnext;
247 else /* middle somewhere */
248 prev->cnext = p->cnext;
249 if (freeable(p))
250 xfree(p->sval);
251 free(p->nval);
252 free(p);
253 tp->nelem--;
254 return;
255 }
256 }
257
258 Cell *
259 setsymtab(const uchar *n, const uchar *s, Awkfloat f, unsigned int t,
260 Array *tp)
261 {
262 int h;
263 Cell *p;
264
265 if (n != NULL && (p = lookup(n, tp)) != NULL) {
266 dprintf(("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
267 (void *)p, p->nval, p->sval, p->fval, p->tval));
268 return (p);
269 }
270 p = (Cell *)malloc(sizeof (Cell));
271 if (p == NULL)
272 FATAL("out of space for symbol table at %s", n);
273 p->nval = tostring(n);
274 p->sval = s ? tostring(s) : tostring((uchar *)"");
275 p->fval = f;
276 p->tval = t;
277 p->csub = CUNK;
278 p->ctype = OCELL;
279 tp->nelem++;
280 if (tp->nelem > FULLTAB * tp->size)
281 rehash(tp);
282 h = hash(n, tp->size);
283 p->cnext = tp->tab[h];
284 tp->tab[h] = p;
285 dprintf(("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
286 (void *)p, p->nval, p->sval, p->fval, p->tval));
287 return (p);
288 }
289
290 int
291 hash(const uchar *s, int n) /* form hash value for string s */
292 {
293 unsigned hashval;
294
295 for (hashval = 0; *s != '\0'; s++)
296 hashval = (*s + 31 * hashval);
297 return (hashval % n);
298 }
299
300 static void
301 rehash(Array *tp) /* rehash items in small table into big one */
302 {
303 int i, nh, nsz;
304 Cell *cp, *op, **np;
305
306 nsz = GROWTAB * tp->size;
307 np = (Cell **)calloc(nsz, sizeof (Cell *));
308 if (np == NULL) /* can't do it, but can keep running. */
309 return; /* someone else will run out later. */
310 for (i = 0; i < tp->size; i++) {
311 for (cp = tp->tab[i]; cp; cp = op) {
312 op = cp->cnext;
313 nh = hash(cp->nval, nsz);
314 cp->cnext = np[nh];
315 np[nh] = cp;
316 }
317 }
318 free(tp->tab);
319 tp->tab = np;
320 tp->size = nsz;
321 }
322
323 Cell *
324 lookup(const uchar *s, Array *tp) /* look for s in tp */
325 {
326 Cell *p;
327 int h;
328
329 h = hash(s, tp->size);
330 for (p = tp->tab[h]; p != NULL; p = p->cnext) {
331 if (strcmp((char *)s, (char *)p->nval) == 0)
332 return (p); /* found it */
333 }
334 return (NULL); /* not found */
335 }
336
337 Awkfloat
338 setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
339 {
340 int fldno;
341
342 if ((vp->tval & (NUM | STR)) == 0)
343 funnyvar(vp, "assign to");
344 if (isfld(vp)) {
345 donerec = 0; /* mark $0 invalid */
346 fldno = atoi((char *)vp->nval);
347 if (fldno > *NF)
348 newfld(fldno);
349 dprintf(("setting field %d to %g\n", fldno, f));
350 } else if (isrec(vp)) {
351 donefld = 0; /* mark $1... invalid */
352 donerec = 1;
353 }
354 if (freeable(vp))
355 xfree(vp->sval); /* free any previous string */
356 vp->tval &= ~STR; /* mark string invalid */
357 vp->tval |= NUM; /* mark number ok */
358 if (f == -0) /* who would have thought this possible? */
359 f = 0;
360 dprintf(("setfval %p: %s = %g, t=%o\n", (void *)vp,
361 vp->nval, f, vp->tval));
362 return (vp->fval = f);
363 }
364
365 void
366 funnyvar(Cell *vp, char *rw)
367 {
368 if (isarr(vp))
369 FATAL("can't %s %s; it's an array name.", rw, vp->nval);
370 if (vp->tval & FCN)
371 FATAL("can't %s %s; it's a function.", rw, vp->nval);
372 WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
373 vp, vp->nval, vp->sval, vp->fval, vp->tval);
374 }
375
376 uchar *
377 setsval(Cell *vp, const uchar *s) /* set string val of a Cell */
378 {
379 uchar *t;
380 int fldno;
381
382 dprintf(("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
383 (void*)vp, vp->nval, s, vp->tval, donerec, donefld));
384 if ((vp->tval & (NUM | STR)) == 0)
385 funnyvar(vp, "assign to");
386 if (isfld(vp)) {
387 donerec = 0; /* mark $0 invalid */
388 fldno = atoi((const char *)vp->nval);
389 if (fldno > *NF)
390 newfld(fldno);
391 dprintf(("setting field %d to %s (%p)\n", fldno, s, (void *)s));
392 } else if (isrec(vp)) {
393 donefld = 0; /* mark $1... invalid */
394 donerec = 1;
395 }
396 t = tostring(s); /* in case it's self-assign */
397 if (freeable(vp))
398 xfree(vp->sval);
399 vp->tval &= ~NUM;
400 vp->tval |= STR;
401 vp->tval &= ~DONTFREE;
402 dprintf(("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
403 (void *)vp, vp->nval, t, (void *)t, vp->tval, donerec, donefld));
404 return (vp->sval = t);
405 }
406
407 Awkfloat
408 getfval(Cell *vp) /* get float val of a Cell */
409 {
410 if ((vp->tval & (NUM | STR)) == 0)
411 funnyvar(vp, "read value of");
412 if (isfld(vp) && donefld == 0)
413 fldbld();
414 else if (isrec(vp) && donerec == 0)
415 recbld();
416 if (!isnum(vp)) { /* not a number */
417 vp->fval = atof((const char *)vp->sval); /* best guess */
418 if (is_number(vp->sval) && !(vp->tval & CON))
419 vp->tval |= NUM; /* make NUM only sparingly */
420 }
421 dprintf(("getfval %p: %s = %g, t=%o\n",
422 (void *)vp, vp->nval, vp->fval, vp->tval));
423 return (vp->fval);
424 }
425
426 static uchar *
427 get_str_val(Cell *vp, uchar **fmt) /* get string val of a Cell */
428 {
429 uchar s[100]; /* BUG: unchecked */
430 double dtemp;
431
432 if ((vp->tval & (NUM | STR)) == 0)
433 funnyvar(vp, "read value of");
434 if (isfld(vp) && donefld == 0)
435 fldbld();
436 else if (isrec(vp) && donerec == 0)
437 recbld();
438 if (isstr(vp) == 0) {
439 if (freeable(vp))
440 xfree(vp->sval);
441 /* it's integral */
442 if (modf((long long)vp->fval, &dtemp) == 0) {
443 (void) snprintf((char *)s, sizeof (s),
444 "%.30g", vp->fval);
445 } else {
446 /*LINTED*/
447 (void) snprintf((char *)s, sizeof (s),
448 (char *)*fmt, vp->fval);
449 }
450 vp->sval = tostring(s);
451 vp->tval &= ~DONTFREE;
452 vp->tval |= STR;
453 }
454 dprintf(("getsval %p: %s = \"%s (%p)\", t=%o\n",
455 (void *)vp, vp->nval, vp->sval, (void *)vp->sval, vp->tval));
456 return (vp->sval);
457 }
458
459 uchar *
460 getsval(Cell *vp) /* get string val of a Cell */
461 {
462 return (get_str_val(vp, CONVFMT));
463 }
464
465 uchar *
466 getpssval(Cell *vp) /* get string val of a Cell for print */
467 {
468 return (get_str_val(vp, OFMT));
469 }
470
471 uchar *
472 tostring(const uchar *s) /* make a copy of string s */
473 {
474 uchar *p;
475
476 p = (uchar *)malloc(strlen((char *)s)+1);
477 if (p == NULL)
478 FATAL("out of space in tostring on %s", s);
479 (void) strcpy((char *)p, (char *)s);
480 return (p);
481 }
482
483 uchar *
484 qstring(const uchar *is, int delim) /* collect string up to delim */
485 {
486 const uchar *os = is;
487 int c, n;
488 uchar *s = (uchar *)is;
489 uchar *buf, *bp;
490
491 if ((buf = (uchar *)malloc(strlen((char *)is)+3)) == NULL)
492 FATAL("out of space in qstring(%s)", s);
493 for (bp = buf; (c = *s) != delim; s++) {
494 if (c == '\n') {
495 SYNTAX("newline in string %.20s...", os);
496 } else if (c != '\\') {
497 *bp++ = c;
498 } else { /* \something */
499 c = *++s;
500 if (c == 0) { /* \ at end */
501 *bp++ = '\\';
502 break; /* for loop */
503 }
504 switch (c) {
505 case '\\': *bp++ = '\\'; break;
506 case 'n': *bp++ = '\n'; break;
507 case 't': *bp++ = '\t'; break;
508 case 'b': *bp++ = '\b'; break;
509 case 'f': *bp++ = '\f'; break;
510 case 'r': *bp++ = '\r'; break;
511 default:
512 if (!isdigit(c)) {
513 *bp++ = c;
514 break;
515 }
516 n = c - '0';
517 if (isdigit(s[1])) {
518 n = 8 * n + *++s - '0';
519 if (isdigit(s[1]))
520 n = 8 * n + *++s - '0';
521 }
522 *bp++ = n;
523 break;
524 }
525 }
526 }
527 *bp++ = 0;
528 return (buf);
529 }
|