1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
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
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
23 ****************************************************************/
25 #if HAVE_NBTOOL_CONFIG_H
26 #include "nbtool_config.h"
38 #define FULLTAB 2 /* rehash when table gets this x full */
39 #define GROWTAB 4 /* grow table by this factor */
41 Array
*symtab
; /* main symbol table */
43 char **FS
; /* initial field sep */
44 char **RS
; /* initial record sep */
45 char **OFS
; /* output field sep */
46 char **ORS
; /* output record sep */
47 char **OFMT
; /* output format for numbers */
48 char **CONVFMT
; /* format for conversions in getsval */
49 Awkfloat
*NF
; /* number of fields in current record */
50 Awkfloat
*NR
; /* number of current record */
51 Awkfloat
*FNR
; /* number of current record in current file */
52 char **FILENAME
; /* current filename argument */
53 Awkfloat
*ARGC
; /* number of arguments from command line */
54 char **SUBSEP
; /* subscript separator for a[i,j,k]; default \034 */
55 Awkfloat
*RSTART
; /* start of re matched with ~; origin 1 (!) */
56 Awkfloat
*RLENGTH
; /* length of same */
61 Cell
*fnrloc
; /* FNR */
62 Array
*ARGVtab
; /* symbol table containing ARGV[...] */
63 Array
*ENVtab
; /* symbol table containing ENVIRON[...] */
64 Cell
*rstartloc
; /* RSTART */
65 Cell
*rlengthloc
; /* RLENGTH */
66 Cell
*symtabloc
; /* SYMTAB */
68 Cell
*nullloc
; /* a guaranteed empty cell */
69 Node
*nullnode
; /* zero&null, converted into a node for comparisons */
74 void syminit(void) /* initialize symbol table with builtin vars */
76 literal0
= setsymtab("0", "0", 0.0, NUM
|STR
|CON
|DONTFREE
, symtab
);
77 /* this is used for if(x)... tests: */
78 nullloc
= setsymtab("$zero&null", "", 0.0, NUM
|STR
|CON
|DONTFREE
, symtab
);
79 nullnode
= celltonode(nullloc
, CCON
);
81 fsloc
= setsymtab("FS", " ", 0.0, STR
|DONTFREE
, symtab
);
83 RS
= &setsymtab("RS", "\n", 0.0, STR
|DONTFREE
, symtab
)->sval
;
84 OFS
= &setsymtab("OFS", " ", 0.0, STR
|DONTFREE
, symtab
)->sval
;
85 ORS
= &setsymtab("ORS", "\n", 0.0, STR
|DONTFREE
, symtab
)->sval
;
86 OFMT
= &setsymtab("OFMT", "%.6g", 0.0, STR
|DONTFREE
, symtab
)->sval
;
87 CONVFMT
= &setsymtab("CONVFMT", "%.6g", 0.0, STR
|DONTFREE
, symtab
)->sval
;
88 FILENAME
= &setsymtab("FILENAME", "", 0.0, STR
|DONTFREE
, symtab
)->sval
;
89 nfloc
= setsymtab("NF", "", 0.0, NUM
, symtab
);
91 nrloc
= setsymtab("NR", "", 0.0, NUM
, symtab
);
93 fnrloc
= setsymtab("FNR", "", 0.0, NUM
, symtab
);
95 SUBSEP
= &setsymtab("SUBSEP", "\034", 0.0, STR
|DONTFREE
, symtab
)->sval
;
96 rstartloc
= setsymtab("RSTART", "", 0.0, NUM
, symtab
);
97 RSTART
= &rstartloc
->fval
;
98 rlengthloc
= setsymtab("RLENGTH", "", 0.0, NUM
, symtab
);
99 RLENGTH
= &rlengthloc
->fval
;
100 symtabloc
= setsymtab("SYMTAB", "", 0.0, ARR
, symtab
);
101 symtabloc
->sval
= (char *) symtab
;
104 void arginit(int ac
, char **av
) /* set up ARGV and ARGC */
110 ARGC
= &setsymtab("ARGC", "", (Awkfloat
) ac
, NUM
, symtab
)->fval
;
111 cp
= setsymtab("ARGV", "", 0.0, ARR
, symtab
);
112 ARGVtab
= makesymtab(NSYMTAB
); /* could be (int) ARGC as well */
113 cp
->sval
= (char *) ARGVtab
;
114 for (i
= 0; i
< ac
; i
++) {
115 snprintf(temp
, sizeof(temp
), "%d", i
);
117 setsymtab(temp
, *av
, atof(*av
), STR
|NUM
, ARGVtab
);
119 setsymtab(temp
, *av
, 0.0, STR
, ARGVtab
);
124 void envinit(char **envp
) /* set up ENVIRON variable */
129 cp
= setsymtab("ENVIRON", "", 0.0, ARR
, symtab
);
130 ENVtab
= makesymtab(NSYMTAB
);
131 cp
->sval
= (char *) ENVtab
;
132 for ( ; *envp
; envp
++) {
133 if ((p
= strchr(*envp
, '=')) == NULL
)
135 if( p
== *envp
) /* no left hand side name in env string */
137 *p
++ = 0; /* split into two strings at = */
139 setsymtab(*envp
, p
, atof(p
), STR
|NUM
, ENVtab
);
141 setsymtab(*envp
, p
, 0.0, STR
, ENVtab
);
142 p
[-1] = '='; /* restore in case env is passed down to a shell */
146 Array
*makesymtab(int n
) /* make a new symbol table */
151 ap
= (Array
*) malloc(sizeof(Array
));
152 tp
= (Cell
**) calloc(n
, sizeof(Cell
*));
153 if (ap
== NULL
|| tp
== NULL
)
154 FATAL("out of space in makesymtab");
161 void freesymtab(Cell
*ap
) /* free a symbol table */
169 tp
= (Array
*) ap
->sval
;
172 for (i
= 0; i
< tp
->size
; i
++) {
173 for (cp
= tp
->tab
[i
]; cp
!= NULL
; cp
= temp
) {
177 temp
= cp
->cnext
; /* avoids freeing then using */
184 WARNING("can't happen: inconsistent element count freeing %s", ap
->nval
);
189 void freeelem(Cell
*ap
, const char *s
) /* free elem s from ap (i.e., ap["s"] */
192 Cell
*p
, *prev
= NULL
;
195 tp
= (Array
*) ap
->sval
;
196 h
= hash(s
, tp
->size
);
197 for (p
= tp
->tab
[h
]; p
!= NULL
; prev
= p
, p
= p
->cnext
)
198 if (strcmp(s
, p
->nval
) == 0) {
199 if (prev
== NULL
) /* 1st one */
200 tp
->tab
[h
] = p
->cnext
;
201 else /* middle somewhere */
202 prev
->cnext
= p
->cnext
;
212 Cell
*setsymtab(const char *n
, const char *s
, Awkfloat f
, unsigned t
, Array
*tp
)
220 if ((p
= lookup(n
, tp
)) != NULL
) {
221 dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
222 p
, NN(p
->nval
), NN(p
->sval
), p
->fval
, p
->tval
) );
225 p
= (Cell
*) malloc(sizeof(Cell
));
227 FATAL("out of space for symbol table at %s", n
);
228 p
->nval
= tostring(n
);
229 p
->sval
= s
? tostring(s
) : tostring("");
235 if (tp
->nelem
> FULLTAB
* tp
->size
)
237 h
= hash(n
, tp
->size
);
238 p
->cnext
= tp
->tab
[h
];
240 dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
241 p
, p
->nval
, p
->sval
, p
->fval
, p
->tval
) );
245 int hash(const char *s
, int n
) /* form hash value for string s */
249 for (hashval
= 0; *s
!= '\0'; s
++)
250 hashval
= (*s
+ 31 * hashval
);
254 void rehash(Array
*tp
) /* rehash items in small table into big one */
259 nsz
= GROWTAB
* tp
->size
;
260 np
= (Cell
**) calloc(nsz
, sizeof(Cell
*));
261 if (np
== NULL
) /* can't do it, but can keep running. */
262 return; /* someone else will run out later. */
263 for (i
= 0; i
< tp
->size
; i
++) {
264 for (cp
= tp
->tab
[i
]; cp
; cp
= op
) {
266 nh
= hash(cp
->nval
, nsz
);
276 Cell
*lookup(const char *s
, Array
*tp
) /* look for s in tp */
281 h
= hash(s
, tp
->size
);
282 for (p
= tp
->tab
[h
]; p
!= NULL
; p
= p
->cnext
)
283 if (strcmp(s
, p
->nval
) == 0)
284 return(p
); /* found it */
285 return(NULL
); /* not found */
288 Awkfloat
setfval(Cell
*vp
, Awkfloat f
) /* set float val of a Cell */
292 f
+= 0.0; /* normalise negative zero to positive zero */
293 if ((vp
->tval
& (NUM
| STR
)) == 0)
294 funnyvar(vp
, "assign to");
296 donerec
= 0; /* mark $0 invalid */
297 fldno
= atoi(vp
->nval
);
300 dprintf( ("setting field %d to %g\n", fldno
, f
) );
301 } else if (isrec(vp
)) {
302 donefld
= 0; /* mark $1... invalid */
306 xfree(vp
->sval
); /* free any previous string */
307 vp
->tval
&= ~STR
; /* mark string invalid */
308 vp
->tval
|= NUM
; /* mark number ok */
309 dprintf( ("setfval %p: %s = %g, t=%o\n", vp
, NN(vp
->nval
), f
, vp
->tval
) );
313 void funnyvar(Cell
*vp
, const char *rw
)
316 FATAL("can't %s %s; it's an array name.", rw
, vp
->nval
);
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
);
323 char *setsval(Cell
*vp
, const char *s
) /* set string val of a Cell */
328 dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
329 vp
, NN(vp
->nval
), s
, vp
->tval
, donerec
, donefld
) );
330 if ((vp
->tval
& (NUM
| STR
)) == 0)
331 funnyvar(vp
, "assign to");
333 donerec
= 0; /* mark $0 invalid */
334 fldno
= atoi(vp
->nval
);
337 dprintf( ("setting field %d to %s (%p)\n", fldno
, s
, s
) );
338 } else if (isrec(vp
)) {
339 donefld
= 0; /* mark $1... invalid */
342 t
= tostring(s
); /* in case it's self-assign */
347 vp
->tval
&= ~DONTFREE
;
348 dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
349 vp
, NN(vp
->nval
), t
,t
, vp
->tval
, donerec
, donefld
) );
350 return(vp
->sval
= t
);
353 Awkfloat
getfval(Cell
*vp
) /* get float val of a Cell */
355 if ((vp
->tval
& (NUM
| STR
)) == 0)
356 funnyvar(vp
, "read value of");
357 if (isfld(vp
) && donefld
== 0)
359 else if (isrec(vp
) && donerec
== 0)
361 if (!isnum(vp
)) { /* not a number */
362 vp
->fval
= atof(vp
->sval
); /* best guess */
363 if (is_number(vp
->sval
) && !(vp
->tval
&CON
))
364 vp
->tval
|= NUM
; /* make NUM only sparingly */
366 dprintf( ("getfval %p: %s = %g, t=%o\n", vp
, NN(vp
->nval
), vp
->fval
, vp
->tval
) );
370 static char *get_str_val(Cell
*vp
, char **fmt
) /* get string val of a Cell */
375 if ((vp
->tval
& (NUM
| STR
)) == 0)
376 funnyvar(vp
, "read value of");
377 if (isfld(vp
) && donefld
== 0)
379 else if (isrec(vp
) && donerec
== 0)
381 if (isstr(vp
) == 0) {
384 if (modf(vp
->fval
, &dtemp
) == 0) /* it's integral */
385 snprintf(s
, sizeof(s
), "%.30g", vp
->fval
);
387 snprintf(s
, sizeof(s
), *fmt
, vp
->fval
);
388 vp
->sval
= tostring(s
);
389 vp
->tval
&= ~DONTFREE
;
392 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp
, NN(vp
->nval
), vp
->sval
, vp
->sval
, vp
->tval
) );
396 char *getsval(Cell
*vp
) /* get string val of a Cell */
398 return get_str_val(vp
, CONVFMT
);
401 char *getpssval(Cell
*vp
) /* get string val of a Cell for print */
403 return get_str_val(vp
, OFMT
);
407 char *tostring(const char *s
) /* make a copy of string s */
413 FATAL("out of space in tostring on %s", s
);
417 char *tostringN(const char *s
, size_t n
) /* make a copy of string s */
423 FATAL("out of space in tostring on %s", s
);
428 char *qstring(const char *is
, int delim
) /* collect string up to next delim */
432 uschar
*s
= (uschar
*) is
;
435 if ((buf
= (uschar
*) malloc(strlen(is
)+3)) == NULL
)
436 FATAL( "out of space in qstring(%s)", s
);
437 for (bp
= buf
; (c
= *s
) != delim
; s
++) {
439 SYNTAX( "newline in string %.20s...", os
);
442 else { /* \something */
444 if (c
== 0) { /* \ at end */
446 break; /* for loop */
449 case '\\': *bp
++ = '\\'; break;
450 case 'n': *bp
++ = '\n'; break;
451 case 't': *bp
++ = '\t'; break;
452 case 'b': *bp
++ = '\b'; break;
453 case 'f': *bp
++ = '\f'; break;
454 case 'r': *bp
++ = '\r'; break;
462 n
= 8 * n
+ *++s
- '0';
464 n
= 8 * n
+ *++s
- '0';