/* hash.c: hash table support for functions and variables. */
Functions and variables are cached in both internal and external
form for performance. Thus a variable which is never "dereferenced"
with a $ is passed on to rc's children untouched. This is not so
important for variables, but is a big win for functions, where a call
to yyparse() is involved.
static bool var_exportable(char *);
static bool fn_exportable(char *);
static int hash(char *, int);
static int find(char *, Htab
*, int);
static void free_fn(Function
*);
static int fused
, fsize
, vused
, vsize
;
static bool env_dirty
= TRUE
;
#define HASHSIZE 64 /* rc was debugged with HASHSIZE == 2; 64 is about right for normal use */
fp
= ealloc(sizeof(Htab
) * HASHSIZE
);
vp
= ealloc(sizeof(Htab
) * HASHSIZE
);
fsize
= vsize
= HASHSIZE
;
for (vpp
= vp
, fpp
= fp
, i
= 0; i
< HASHSIZE
; i
++, vpp
++, fpp
++)
vpp
->name
= fpp
->name
= NULL
;
#define ADV() {if ((c = *s++) == '\0') break;}
/* hash function courtesy of paul haahr */
static int hash(char *s
, int size
) {
n
+= (c
<< 17) ^ (c
<< 11) ^ (c
<< 5) ^ (c
>> 1);
n
^= (c
<< 14) + (c
<< 7) + (c
<< 4) + c
;
n
^= (~c
<< 11) | ((c
<< 3) ^ (c
>> 1));
n
-= (c
<< 16) | (c
<< 9) | (c
<< 2) | (c
& 3);
return n
& (size
- 1); /* need power of 2 size */
static bool rehash(Htab
*ht
) {
newhtab
= ealloc(newsize
* sizeof(Htab
));
for (i
= 0; i
< newsize
; i
++)
for (i
= newused
= 0; i
< size
; i
++)
if (ht
[i
].name
!= NULL
&& ht
[i
].name
!= dead
) {
j
= hash(ht
[i
].name
, newsize
);
while (newhtab
[j
].name
!= NULL
) {
newhtab
[j
].name
= ht
[i
].name
;
#define varfind(s) find(s, vp, vsize)
#define fnfind(s) find(s, fp, fsize)
static int find(char *s
, Htab
*ht
, int size
) {
while (ht
[h
].name
!= NULL
&& !streq(ht
[h
].name
, s
)) {
extern void *lookup(char *s
, Htab
*ht
) {
int h
= find(s
, ht
, ht
== fp
? fsize
: vsize
);
return (ht
[h
].name
== NULL
) ? NULL
: ht
[h
].p
;
extern Function
*get_fn_place(char *s
) {
if (fp
[h
].name
== NULL
) {
fp
[h
].p
= enew(Function
);
extern Variable
*get_var_place(char *s
, bool stack
) {
if (vp
[h
].name
== NULL
) {
vp
[h
].p
= enew(Variable
);
((Variable
*)vp
[h
].p
)->n
= NULL
;
if (stack
) { /* increase the stack by 1 */
} else { /* trample the top of the stack */
extern void delete_fn(char *s
) {
if (fp
[(h
+1)&(fsize
-1)].name
== NULL
) {
extern void delete_var(char *s
, bool stack
) {
if (v
->n
!= NULL
) { /* This is the top of a stack */
} else { /* else just empty */
} else { /* needs to be removed from the hash table */
if (vp
[(h
+1)&(vsize
-1)].name
== NULL
) {
static void free_fn(Function
*f
) {
extern void initenv(char **envp
) {
for (n
= 0; envp
[n
] != NULL
; n
++)
n
++; /* one for the null terminator */
env
= ealloc((envsize
= 2 * n
) * sizeof (char *));
for (; *envp
!= NULL
; envp
++)
if (strncmp(*envp
, "fn_", conststrlen("fn_")) == 0) {
if (!varassign_string(*envp
)) /* add to bozo env */
static bool var_exportable(char *s
) {
static char *notforexport
[] = {
"apid", "pid", "apids", "*", "ifs"
for (i
= 0; i
< arraysize(notforexport
); i
++)
if (streq(s
, notforexport
[i
]))
static bool fn_exportable(char *s
) {
if (strncmp(s
, "sig", conststrlen("sig")) == 0) { /* small speed hack */
for (i
= 0; i
< NUMOFSIGNALS
; i
++)
if (streq(s
, signals
[i
].name
))
extern char **makeenv() {
if (vsize
+ fsize
+ 1 + bozosize
> envsize
) {
envsize
= 2 * (bozosize
+ vsize
+ fsize
+ 1);
env
= erealloc(env
, envsize
* sizeof(char *));
for (i
= 0; i
< vsize
; i
++) {
if (vp
[i
].name
== NULL
|| vp
[i
].name
== dead
|| !var_exportable(vp
[i
].name
))
v
= varlookup_string(vp
[i
].name
);
for (i
= 0; i
< fsize
; i
++) {
if (fp
[i
].name
== NULL
|| fp
[i
].name
== dead
|| !fn_exportable(fp
[i
].name
))
env
[ep
++] = fnlookup_string(fp
[i
].name
);
qsort(env
, (size_t) ep
, sizeof(char *), starstrcmp
);
extern void whatare_all_vars() {
for (i
= 0; i
< vsize
; i
++)
if (vp
[i
].name
!= NULL
&& (s
= varlookup(vp
[i
].name
)) != NULL
)
prettyprint_var(1, vp
[i
].name
, s
);
for (i
= 0; i
< fsize
; i
++)
if (fp
[i
].name
!= NULL
&& fp
[i
].name
!= dead
)
prettyprint_fn(1, fp
[i
].name
, fnlookup(fp
[i
].name
));