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
= malloc(sizeof(*ap
));
152 tp
= calloc(n
, sizeof(*tp
));
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
= malloc(sizeof(*p
));
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
= calloc(nsz
, sizeof(*np
));
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 (&vp
->fval
== NF
) {
302 donerec
= 0; /* mark $0 invalid */
304 dprintf( ("setting NF to %g\n", f
) );
305 } else if (isrec(vp
)) {
306 donefld
= 0; /* mark $1... invalid */
310 xfree(vp
->sval
); /* free any previous string */
311 vp
->tval
&= ~STR
; /* mark string invalid */
312 vp
->tval
|= NUM
; /* mark number ok */
313 dprintf( ("setfval %p: %s = %g, t=%o\n", vp
, NN(vp
->nval
), f
, vp
->tval
) );
317 void funnyvar(Cell
*vp
, const char *rw
)
320 FATAL("can't %s %s; it's an array name.", rw
, vp
->nval
);
322 FATAL("can't %s %s; it's a function.", rw
, vp
->nval
);
323 WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
324 vp
, vp
->nval
, vp
->sval
, vp
->fval
, vp
->tval
);
327 char *setsval(Cell
*vp
, const char *s
) /* set string val of a Cell */
333 dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
334 vp
, NN(vp
->nval
), s
, vp
->tval
, donerec
, donefld
) );
335 if ((vp
->tval
& (NUM
| STR
)) == 0)
336 funnyvar(vp
, "assign to");
338 donerec
= 0; /* mark $0 invalid */
339 fldno
= atoi(vp
->nval
);
342 dprintf( ("setting field %d to %s (%p)\n", fldno
, s
, s
) );
343 } else if (isrec(vp
)) {
344 donefld
= 0; /* mark $1... invalid */
347 t
= tostring(s
); /* in case it's self-assign */
352 vp
->tval
&= ~DONTFREE
;
353 dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
354 vp
, NN(vp
->nval
), t
,t
, vp
->tval
, donerec
, donefld
) );
357 if (&vp
->fval
== NF
) {
358 donerec
= 0; /* mark $0 invalid */
361 dprintf( ("setting NF to %g\n", f
) );
367 Awkfloat
getfval(Cell
*vp
) /* get float val of a Cell */
369 if ((vp
->tval
& (NUM
| STR
)) == 0)
370 funnyvar(vp
, "read value of");
371 if (isfld(vp
) && donefld
== 0)
373 else if (isrec(vp
) && donerec
== 0)
375 if (!isnum(vp
)) { /* not a number */
376 vp
->fval
= atof(vp
->sval
); /* best guess */
377 if (is_number(vp
->sval
) && !(vp
->tval
&CON
))
378 vp
->tval
|= NUM
; /* make NUM only sparingly */
380 dprintf( ("getfval %p: %s = %g, t=%o\n", vp
, NN(vp
->nval
), vp
->fval
, vp
->tval
) );
384 static char *get_str_val(Cell
*vp
, char **fmt
) /* get string val of a Cell */
389 if ((vp
->tval
& (NUM
| STR
)) == 0)
390 funnyvar(vp
, "read value of");
391 if (isfld(vp
) && donefld
== 0)
393 else if (isrec(vp
) && donerec
== 0)
395 if (isstr(vp
) == 0) {
398 if (modf(vp
->fval
, &dtemp
) == 0) /* it's integral */
399 snprintf(s
, sizeof(s
), "%.30g", vp
->fval
);
401 snprintf(s
, sizeof(s
), *fmt
, vp
->fval
);
402 vp
->sval
= tostring(s
);
403 vp
->tval
&= ~DONTFREE
;
406 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp
, NN(vp
->nval
), vp
->sval
, vp
->sval
, vp
->tval
) );
410 char *getsval(Cell
*vp
) /* get string val of a Cell */
412 return get_str_val(vp
, CONVFMT
);
415 char *getpssval(Cell
*vp
) /* get string val of a Cell for print */
417 return get_str_val(vp
, OFMT
);
421 char *tostring(const char *s
) /* make a copy of string s */
427 FATAL("out of space in tostring on %s", s
);
431 Cell
*catstr(Cell
*a
, Cell
*b
) /* concatenate a and b */
435 char *sa
= getsval(a
);
436 char *sb
= getsval(b
);
437 size_t l
= strlen(sa
) + strlen(sb
) + 1;
440 FATAL("out of space concatenating %s and %s", sa
, sb
);
441 snprintf(p
, l
, "%s%s", sa
, sb
);
442 c
= setsymtab(p
, p
, 0.0, CON
|STR
|DONTFREE
, symtab
);
447 char *tostringN(const char *s
, size_t n
) /* make a copy of string s */
453 FATAL("out of space in tostring on %s", s
);
458 char *qstring(const char *is
, int delim
) /* collect string up to next delim */
462 const uschar
*s
= (const uschar
*) is
;
465 if ((buf
= malloc(strlen(is
)+3)) == NULL
)
466 FATAL( "out of space in qstring(%s)", s
);
467 for (bp
= buf
; (c
= *s
) != delim
; s
++) {
469 SYNTAX( "newline in string %.20s...", os
);
472 else { /* \something */
474 if (c
== 0) { /* \ at end */
476 break; /* for loop */
479 case '\\': *bp
++ = '\\'; break;
480 case 'n': *bp
++ = '\n'; break;
481 case 't': *bp
++ = '\t'; break;
482 case 'b': *bp
++ = '\b'; break;
483 case 'f': *bp
++ = '\f'; break;
484 case 'r': *bp
++ = '\r'; break;
492 n
= 8 * n
+ *++s
- '0';
494 n
= 8 * n
+ *++s
- '0';