diff options
| author | Byron Rakitzis <byron@archone.tamu.edu> | 1992-05-27 00:00:01 +0100 |
|---|---|---|
| committer | Toby Goodwin <toby@paccrat.org> | 2015-05-16 21:22:56 +0100 |
| commit | 26bb34cf036027dfa22dfae8d8fc2f6bfd6acb75 (patch) | |
| tree | 589705b2492ce4681760846d9ca45600f0af298d /hash.c | |
release: rc-1.4
Diffstat (limited to 'hash.c')
| -rw-r--r-- | hash.c | 302 |
1 files changed, 302 insertions, 0 deletions
@@ -0,0 +1,302 @@ +/* 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 |