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 */
77 if (&vp
->sval
== FS
|| &vp
->sval
== RS
||
78 &vp
->sval
== OFS
|| &vp
->sval
== ORS
||
79 &vp
->sval
== OFMT
|| &vp
->sval
== CONVFMT
||
80 &vp
->sval
== FILENAME
|| &vp
->sval
== SUBSEP
)
83 vp
->tval
&= ~DONTFREE
;
86 void syminit(void) /* initialize symbol table with builtin vars */
88 literal0
= setsymtab("0", "0", 0.0, NUM
|STR
|CON
|DONTFREE
, symtab
);
89 /* this is used for if(x)... tests: */
90 nullloc
= setsymtab("$zero&null", "", 0.0, NUM
|STR
|CON
|DONTFREE
, symtab
);
91 nullnode
= celltonode(nullloc
, CCON
);
93 fsloc
= setsymtab("FS", " ", 0.0, STR
|DONTFREE
, symtab
);
95 RS
= &setsymtab("RS", "\n", 0.0, STR
|DONTFREE
, symtab
)->sval
;
96 OFS
= &setsymtab("OFS", " ", 0.0, STR
|DONTFREE
, symtab
)->sval
;
97 ORS
= &setsymtab("ORS", "\n", 0.0, STR
|DONTFREE
, symtab
)->sval
;
98 OFMT
= &setsymtab("OFMT", "%.6g", 0.0, STR
|DONTFREE
, symtab
)->sval
;
99 CONVFMT
= &setsymtab("CONVFMT", "%.6g", 0.0, STR
|DONTFREE
, symtab
)->sval
;
100 FILENAME
= &setsymtab("FILENAME", "", 0.0, STR
|DONTFREE
, symtab
)->sval
;
101 nfloc
= setsymtab("NF", "", 0.0, NUM
, symtab
);
103 nrloc
= setsymtab("NR", "", 0.0, NUM
, symtab
);
105 fnrloc
= setsymtab("FNR", "", 0.0, NUM
, symtab
);
107 SUBSEP
= &setsymtab("SUBSEP", "\034", 0.0, STR
|DONTFREE
, symtab
)->sval
;
108 rstartloc
= setsymtab("RSTART", "", 0.0, NUM
, symtab
);
109 RSTART
= &rstartloc
->fval
;
110 rlengthloc
= setsymtab("RLENGTH", "", 0.0, NUM
, symtab
);
111 RLENGTH
= &rlengthloc
->fval
;
112 symtabloc
= setsymtab("SYMTAB", "", 0.0, ARR
, symtab
);
113 symtabloc
->sval
= (char *) symtab
;
116 void arginit(int ac
, char **av
) /* set up ARGV and ARGC */
122 ARGC
= &setsymtab("ARGC", "", (Awkfloat
) ac
, NUM
, symtab
)->fval
;
123 cp
= setsymtab("ARGV", "", 0.0, ARR
, symtab
);
124 ARGVtab
= makesymtab(NSYMTAB
); /* could be (int) ARGC as well */
125 cp
->sval
= (char *) ARGVtab
;
126 for (i
= 0; i
< ac
; i
++) {
127 snprintf(temp
, sizeof(temp
), "%d", i
);
129 setsymtab(temp
, *av
, atof(*av
), STR
|NUM
, ARGVtab
);
131 setsymtab(temp
, *av
, 0.0, STR
, ARGVtab
);
136 void envinit(char **envp
) /* set up ENVIRON variable */
141 cp
= setsymtab("ENVIRON", "", 0.0, ARR
, symtab
);
142 ENVtab
= makesymtab(NSYMTAB
);
143 cp
->sval
= (char *) ENVtab
;
144 for ( ; *envp
; envp
++) {
145 if ((p
= strchr(*envp
, '=')) == NULL
)
147 if( p
== *envp
) /* no left hand side name in env string */
149 *p
++ = 0; /* split into two strings at = */
151 setsymtab(*envp
, p
, atof(p
), STR
|NUM
, ENVtab
);
153 setsymtab(*envp
, p
, 0.0, STR
, ENVtab
);
154 p
[-1] = '='; /* restore in case env is passed down to a shell */
158 Array
*makesymtab(int n
) /* make a new symbol table */
163 ap
= malloc(sizeof(*ap
));
164 tp
= calloc(n
, sizeof(*tp
));
165 if (ap
== NULL
|| tp
== NULL
)
166 FATAL("out of space in makesymtab");
173 void freesymtab(Cell
*ap
) /* free a symbol table */
181 tp
= (Array
*) ap
->sval
;
184 for (i
= 0; i
< tp
->size
; i
++) {
185 for (cp
= tp
->tab
[i
]; cp
!= NULL
; cp
= temp
) {
189 temp
= cp
->cnext
; /* avoids freeing then using */
196 WARNING("can't happen: inconsistent element count freeing %s", ap
->nval
);
201 void freeelem(Cell
*ap
, const char *s
) /* free elem s from ap (i.e., ap["s"] */
204 Cell
*p
, *prev
= NULL
;
207 tp
= (Array
*) ap
->sval
;
208 h
= hash(s
, tp
->size
);
209 for (p
= tp
->tab
[h
]; p
!= NULL
; prev
= p
, p
= p
->cnext
)
210 if (strcmp(s
, p
->nval
) == 0) {
211 if (prev
== NULL
) /* 1st one */
212 tp
->tab
[h
] = p
->cnext
;
213 else /* middle somewhere */
214 prev
->cnext
= p
->cnext
;
224 Cell
*setsymtab(const char *n
, const char *s
, Awkfloat f
, unsigned t
, Array
*tp
)
232 if ((p
= lookup(n
, tp
)) != NULL
) {
233 dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
234 p
, NN(p
->nval
), NN(p
->sval
), p
->fval
, p
->tval
) );
237 p
= malloc(sizeof(*p
));
239 FATAL("out of space for symbol table at %s", n
);
240 p
->nval
= tostring(n
);
241 p
->sval
= s
? tostring(s
) : tostring("");
247 if (tp
->nelem
> FULLTAB
* tp
->size
)
249 h
= hash(n
, tp
->size
);
250 p
->cnext
= tp
->tab
[h
];
252 dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
253 p
, p
->nval
, p
->sval
, p
->fval
, p
->tval
) );
257 int hash(const char *s
, int n
) /* form hash value for string s */
261 for (hashval
= 0; *s
!= '\0'; s
++)
262 hashval
= (*s
+ 31 * hashval
);
266 void rehash(Array
*tp
) /* rehash items in small table into big one */
271 nsz
= GROWTAB
* tp
->size
;
272 np
= calloc(nsz
, sizeof(*np
));
273 if (np
== NULL
) /* can't do it, but can keep running. */
274 return; /* someone else will run out later. */
275 for (i
= 0; i
< tp
->size
; i
++) {
276 for (cp
= tp
->tab
[i
]; cp
; cp
= op
) {
278 nh
= hash(cp
->nval
, nsz
);
288 Cell
*lookup(const char *s
, Array
*tp
) /* look for s in tp */
293 h
= hash(s
, tp
->size
);
294 for (p
= tp
->tab
[h
]; p
!= NULL
; p
= p
->cnext
)
295 if (strcmp(s
, p
->nval
) == 0)
296 return(p
); /* found it */
297 return(NULL
); /* not found */
300 Awkfloat
setfval(Cell
*vp
, Awkfloat f
) /* set float val of a Cell */
304 f
+= 0.0; /* normalise negative zero to positive zero */
305 if ((vp
->tval
& (NUM
| STR
)) == 0)
306 funnyvar(vp
, "assign to");
308 donerec
= 0; /* mark $0 invalid */
309 fldno
= atoi(vp
->nval
);
312 dprintf( ("setting field %d to %g\n", fldno
, f
) );
313 } else if (&vp
->fval
== NF
) {
314 donerec
= 0; /* mark $0 invalid */
316 dprintf( ("setting NF to %g\n", f
) );
317 } else if (isrec(vp
)) {
318 donefld
= 0; /* mark $1... invalid */
322 xfree(vp
->sval
); /* free any previous string */
323 vp
->tval
&= ~STR
; /* mark string invalid */
324 vp
->tval
|= NUM
; /* mark number ok */
325 if (f
== -0) /* who would have thought this possible? */
327 dprintf( ("setfval %p: %s = %g, t=%o\n", vp
, NN(vp
->nval
), f
, vp
->tval
) );
331 void funnyvar(Cell
*vp
, const char *rw
)
334 FATAL("can't %s %s; it's an array name.", rw
, vp
->nval
);
336 FATAL("can't %s %s; it's a function.", rw
, vp
->nval
);
337 WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
338 vp
, vp
->nval
, vp
->sval
, vp
->fval
, vp
->tval
);
341 char *setsval(Cell
*vp
, const char *s
) /* set string val of a Cell */
347 dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
348 vp
, NN(vp
->nval
), s
, vp
->tval
, donerec
, donefld
) );
349 if ((vp
->tval
& (NUM
| STR
)) == 0)
350 funnyvar(vp
, "assign to");
352 donerec
= 0; /* mark $0 invalid */
353 fldno
= atoi(vp
->nval
);
356 dprintf( ("setting field %d to %s (%p)\n", fldno
, s
, s
) );
357 } else if (isrec(vp
)) {
358 donefld
= 0; /* mark $1... invalid */
361 t
= s
? tostring(s
) : tostring(""); /* in case it's self-assign */
367 dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
368 vp
, NN(vp
->nval
), t
,t
, vp
->tval
, donerec
, donefld
) );
371 if (&vp
->fval
== NF
) {
372 donerec
= 0; /* mark $0 invalid */
375 dprintf( ("setting NF to %g\n", f
) );
381 Awkfloat
getfval(Cell
*vp
) /* get float val of a Cell */
383 if ((vp
->tval
& (NUM
| STR
)) == 0)
384 funnyvar(vp
, "read value of");
385 if (isfld(vp
) && donefld
== 0)
387 else if (isrec(vp
) && donerec
== 0)
389 if (!isnum(vp
)) { /* not a number */
390 vp
->fval
= atof(vp
->sval
); /* best guess */
391 if (is_number(vp
->sval
) && !(vp
->tval
&CON
))
392 vp
->tval
|= NUM
; /* make NUM only sparingly */
394 dprintf( ("getfval %p: %s = %g, t=%o\n",
395 vp
, NN(vp
->nval
), vp
->fval
, vp
->tval
) );
399 static char *get_str_val(Cell
*vp
, char **fmt
) /* get string val of a Cell */
404 if ((vp
->tval
& (NUM
| STR
)) == 0)
405 funnyvar(vp
, "read value of");
406 if (isfld(vp
) && donefld
== 0)
408 else if (isrec(vp
) && donerec
== 0)
410 if (isstr(vp
) == 0) {
413 if (modf(vp
->fval
, &dtemp
) == 0) /* it's integral */
414 snprintf(s
, sizeof(s
), "%.30g", vp
->fval
);
416 snprintf(s
, sizeof(s
), *fmt
, vp
->fval
);
417 vp
->sval
= tostring(s
);
421 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n",
422 vp
, NN(vp
->nval
), vp
->sval
, vp
->sval
, vp
->tval
) );
426 char *getsval(Cell
*vp
) /* get string val of a Cell */
428 return get_str_val(vp
, CONVFMT
);
431 char *getpssval(Cell
*vp
) /* get string val of a Cell for print */
433 return get_str_val(vp
, OFMT
);
437 char *tostring(const char *s
) /* make a copy of string s */
443 FATAL("out of space in tostring on %s", s
);
447 Cell
*catstr(Cell
*a
, Cell
*b
) /* concatenate a and b */
451 char *sa
= getsval(a
);
452 char *sb
= getsval(b
);
453 size_t l
= strlen(sa
) + strlen(sb
) + 1;
456 FATAL("out of space concatenating %s and %s", sa
, sb
);
457 snprintf(p
, l
, "%s%s", sa
, sb
);
458 c
= setsymtab(p
, p
, 0.0, CON
|STR
|DONTFREE
, symtab
);
463 char *tostringN(const char *s
, size_t n
) /* make a copy of string s */
469 FATAL("out of space in tostring on %s", s
);
474 char *qstring(const char *is
, int delim
) /* collect string up to next delim */
478 const uschar
*s
= (const uschar
*) is
;
481 if ((buf
= malloc(strlen(is
)+3)) == NULL
)
482 FATAL( "out of space in qstring(%s)", s
);
483 for (bp
= buf
; (c
= *s
) != delim
; s
++) {
485 SYNTAX( "newline in string %.20s...", os
);
488 else { /* \something */
490 if (c
== 0) { /* \ at end */
492 break; /* for loop */
495 case '\\': *bp
++ = '\\'; break;
496 case 'n': *bp
++ = '\n'; break;
497 case 't': *bp
++ = '\t'; break;
498 case 'b': *bp
++ = '\b'; break;
499 case 'f': *bp
++ = '\f'; break;
500 case 'r': *bp
++ = '\r'; break;
508 n
= 8 * n
+ *++s
- '0';
510 n
= 8 * n
+ *++s
- '0';