home *** CD-ROM | disk | FTP | other *** search
- /* 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.
- */
-
- #include "rc.h"
- #include "sigmsgs.h"
-
- 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 *);
-
- Htab *fp;
- Htab *vp;
- static int fused, fsize, vused, vsize;
- static char **env;
- static int bozosize;
- static int envsize;
- static bool env_dirty = TRUE;
- static char *dead = "";
-
- #define HASHSIZE 64 /* rc was debugged with HASHSIZE == 2; 64 is about right for normal use */
-
- extern void inithash() {
- Htab *fpp, *vpp;
- int i;
- fp = ealloc(sizeof(Htab) * HASHSIZE);
- vp = ealloc(sizeof(Htab) * HASHSIZE);
- fused = vused = 0;
- 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) {
- int c, n = 0;
- while (1) {
- ADV();
- n += (c << 17) ^ (c << 11) ^ (c << 5) ^ (c >> 1);
- ADV();
- n ^= (c << 14) + (c << 7) + (c << 4) + c;
- ADV();
- n ^= (~c << 11) | ((c << 3) ^ (c >> 1));
- ADV();
- n -= (c << 16) | (c << 9) | (c << 2) | (c & 3);
- }
- if (n < 0)
- n = ~n;
- return n & (size - 1); /* need power of 2 size */
- }
-
- static bool rehash(Htab *ht) {
- int i, j, size;
- int newsize, newused;
- Htab *newhtab;
- if (ht == fp) {
- if (fsize > 2 * fused)
- return FALSE;
- size = fsize;
- } else {
- if (vsize > 2 * vused)
- return FALSE;
- size = vsize;
- }
- newsize = 2 * size;
- newhtab = ealloc(newsize * sizeof(Htab));
- for (i = 0; i < newsize; i++)
- newhtab[i].name = NULL;
- for (i = newused = 0; i < size; i++)
- if (ht[i].name != NULL && ht[i].name != dead) {
- newused++;
- j = hash(ht[i].name, newsize);
- while (newhtab[j].name != NULL) {
- j++;
- j &= (newsize - 1);
- }
- newhtab[j].name = ht[i].name;
- newhtab[j].p = ht[i].p;
- }
- if (ht == fp) {
- fused = newused;
- fp = newhtab;
- fsize = newsize;
- } else {
- vused = newused;
- vp = newhtab;
- vsize = newsize;
- }
- efree(ht);
- return TRUE;
- }
-
- #define varfind(s) find(s, vp, vsize)
- #define fnfind(s) find(s, fp, fsize)
-
- static int find(char *s, Htab *ht, int size) {
- int h = hash(s, size);
- while (ht[h].name != NULL && !streq(ht[h].name, s)) {
- h++;
- h &= size - 1;
- }
- return h;
- }
-
- 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) {
- int h = fnfind(s);
- env_dirty = TRUE;
- if (fp[h].name == NULL) {
- if (rehash(fp))
- h = fnfind(s);
- fused++;
- fp[h].name = ecpy(s);
- fp[h].p = enew(Function);
- } else
- free_fn(fp[h].p);
- return fp[h].p;
- }
-
- extern Variable *get_var_place(char *s, bool stack) {
- Variable *new;
- int h = varfind(s);
-
- env_dirty = TRUE;
-
- if (vp[h].name == NULL) {
- if (rehash(vp))
- h = varfind(s);
- vused++;
- vp[h].name = ecpy(s);
- vp[h].p = enew(Variable);
- ((Variable *)vp[h].p)->n = NULL;
- return vp[h].p;
- } else {
- if (stack) { /* increase the stack by 1 */
- new = enew(Variable);
- new->n = vp[h].p;
- return vp[h].p = new;
- } else { /* trample the top of the stack */
- new = vp[h].p;
- efree(new->extdef);
- listfree(new->def);
- return new;
- }
- }
- }
-
- extern void delete_fn(char *s) {
- int h = fnfind(s);
- if (fp[h].name == NULL)
- return; /* not found */
- env_dirty = TRUE;
- free_fn(fp[h].p);
- efree(fp[h].p);
- efree(fp[h].name);
- if (fp[(h+1)&(fsize-1)].name == NULL) {
- --fused;
- fp[h].name = NULL;
- } else {
- fp[h].name = dead;
- }
- }
-
- extern void delete_var(char *s, bool stack) {
- int h = varfind(s);
- Variable *v;
- if (vp[h].name == NULL)
- return; /* not found */
- env_dirty = TRUE;
- v = vp[h].p;
- efree(v->extdef);
- listfree(v->def);
- if (v->n != NULL) { /* This is the top of a stack */
- if (stack) { /* pop */
- vp[h].p = v->n;
- efree(v);
- } else { /* else just empty */
- v->extdef = NULL;
- v->def = NULL;
- }
- } else { /* needs to be removed from the hash table */
- efree(v);
- efree(vp[h].name);
- if (vp[(h+1)&(vsize-1)].name == NULL) {
- --vused;
- vp[h].name = NULL;
- } else {
- vp[h].name = dead;
- }
- }
- }
-
- static void free_fn(Function *f) {
- treefree(f->def);
- efree(f->extdef);
- }
-
- extern void initenv(char **envp) {
- int n;
- for (n = 0; envp[n] != NULL; n++)
- ;
- n++; /* one for the null terminator */
- if (n < HASHSIZE)
- n = HASHSIZE;
- env = ealloc((envsize = 2 * n) * sizeof (char *));
- for (; *envp != NULL; envp++)
- if (strncmp(*envp, "fn_", conststrlen("fn_")) == 0) {
- if (!dashpee)
- fnassign_string(*envp);
- } else {
- if (!varassign_string(*envp)) /* add to bozo env */
- env[bozosize++] = *envp;
- }
- }
-
- static bool var_exportable(char *s) {
- static char *notforexport[] = {
- "apid", "pid", "apids", "*", "ifs"
- };
- int i;
- for (i = 0; i < arraysize(notforexport); i++)
- if (streq(s, notforexport[i]))
- return FALSE;
- return TRUE;
- }
-
- static bool fn_exportable(char *s) {
- int i;
- if (strncmp(s, "sig", conststrlen("sig")) == 0) { /* small speed hack */
- for (i = 0; i < NUMOFSIGNALS; i++)
- if (streq(s, signals[i].name))
- return FALSE;
- if (streq(s, "sigexit"))
- return FALSE;
- }
- return TRUE;
- }
-
- extern char **makeenv() {
- int ep, i;
- char *v;
- if (!env_dirty)
- return env;
- env_dirty = FALSE;
- ep = bozosize;
- 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))
- continue;
- v = varlookup_string(vp[i].name);
- if (v != NULL)
- env[ep++] = v;
- }
- for (i = 0; i < fsize; i++) {
- if (fp[i].name == NULL || fp[i].name == dead || !fn_exportable(fp[i].name))
- continue;
- env[ep++] = fnlookup_string(fp[i].name);
- }
- env[ep] = NULL;
- qsort(env, (SIZE_T) ep, sizeof(char *), starstrcmp);
- return env;
- }
-
- extern void whatare_all_vars() {
- int i;
- List *s;
- 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));
- }
-
- /* fake getenv() for readline() follows: */
-
- #ifdef READLINE
- extern char *getenv(const char *name) {
- List *s;
- if (name == NULL || vp == NULL || (s = varlookup((char *) name)) == NULL)
- return NULL;
- return s->w;
- }
- #endif
-