BSD 4_4_Lite1 development
[unix-history] / usr / src / contrib / rc-1.4 / hash.c
CommitLineData
cebbdce6
C
1/* hash.c: hash table support for functions and variables. */
2
3/*
4 Functions and variables are cached in both internal and external
5 form for performance. Thus a variable which is never "dereferenced"
6 with a $ is passed on to rc's children untouched. This is not so
7 important for variables, but is a big win for functions, where a call
8 to yyparse() is involved.
9*/
10
11#include "rc.h"
12#include "sigmsgs.h"
13
14static bool var_exportable(char *);
15static bool fn_exportable(char *);
16static int hash(char *, int);
17static int find(char *, Htab *, int);
18static void free_fn(Function *);
19
20Htab *fp;
21Htab *vp;
22static int fused, fsize, vused, vsize;
23static char **env;
24static int bozosize;
25static int envsize;
26static bool env_dirty = TRUE;
27static char *dead = "";
28
29#define HASHSIZE 64 /* rc was debugged with HASHSIZE == 2; 64 is about right for normal use */
30
31extern void inithash() {
32 Htab *fpp, *vpp;
33 int i;
34 fp = ealloc(sizeof(Htab) * HASHSIZE);
35 vp = ealloc(sizeof(Htab) * HASHSIZE);
36 fused = vused = 0;
37 fsize = vsize = HASHSIZE;
38 for (vpp = vp, fpp = fp, i = 0; i < HASHSIZE; i++, vpp++, fpp++)
39 vpp->name = fpp->name = NULL;
40}
41
42#define ADV() {if ((c = *s++) == '\0') break;}
43
44/* hash function courtesy of paul haahr */
45
46static int hash(char *s, int size) {
47 int c, n = 0;
48 while (1) {
49 ADV();
50 n += (c << 17) ^ (c << 11) ^ (c << 5) ^ (c >> 1);
51 ADV();
52 n ^= (c << 14) + (c << 7) + (c << 4) + c;
53 ADV();
54 n ^= (~c << 11) | ((c << 3) ^ (c >> 1));
55 ADV();
56 n -= (c << 16) | (c << 9) | (c << 2) | (c & 3);
57 }
58 if (n < 0)
59 n = ~n;
60 return n & (size - 1); /* need power of 2 size */
61}
62
63static bool rehash(Htab *ht) {
64 int i, j, size;
65 int newsize, newused;
66 Htab *newhtab;
67 if (ht == fp) {
68 if (fsize > 2 * fused)
69 return FALSE;
70 size = fsize;
71 } else {
72 if (vsize > 2 * vused)
73 return FALSE;
74 size = vsize;
75 }
76 newsize = 2 * size;
77 newhtab = ealloc(newsize * sizeof(Htab));
78 for (i = 0; i < newsize; i++)
79 newhtab[i].name = NULL;
80 for (i = newused = 0; i < size; i++)
81 if (ht[i].name != NULL && ht[i].name != dead) {
82 newused++;
83 j = hash(ht[i].name, newsize);
84 while (newhtab[j].name != NULL) {
85 j++;
86 j &= (newsize - 1);
87 }
88 newhtab[j].name = ht[i].name;
89 newhtab[j].p = ht[i].p;
90 }
91 if (ht == fp) {
92 fused = newused;
93 fp = newhtab;
94 fsize = newsize;
95 } else {
96 vused = newused;
97 vp = newhtab;
98 vsize = newsize;
99 }
100 efree(ht);
101 return TRUE;
102}
103
104#define varfind(s) find(s, vp, vsize)
105#define fnfind(s) find(s, fp, fsize)
106
107static int find(char *s, Htab *ht, int size) {
108 int h = hash(s, size);
109 while (ht[h].name != NULL && !streq(ht[h].name, s)) {
110 h++;
111 h &= size - 1;
112 }
113 return h;
114}
115
116extern void *lookup(char *s, Htab *ht) {
117 int h = find(s, ht, ht == fp ? fsize : vsize);
118 return (ht[h].name == NULL) ? NULL : ht[h].p;
119}
120
121extern Function *get_fn_place(char *s) {
122 int h = fnfind(s);
123 env_dirty = TRUE;
124 if (fp[h].name == NULL) {
125 if (rehash(fp))
126 h = fnfind(s);
127 fused++;
128 fp[h].name = ecpy(s);
129 fp[h].p = enew(Function);
130 } else
131 free_fn(fp[h].p);
132 return fp[h].p;
133}
134
135extern Variable *get_var_place(char *s, bool stack) {
136 Variable *new;
137 int h = varfind(s);
138
139 env_dirty = TRUE;
140
141 if (vp[h].name == NULL) {
142 if (rehash(vp))
143 h = varfind(s);
144 vused++;
145 vp[h].name = ecpy(s);
146 vp[h].p = enew(Variable);
147 ((Variable *)vp[h].p)->n = NULL;
148 return vp[h].p;
149 } else {
150 if (stack) { /* increase the stack by 1 */
151 new = enew(Variable);
152 new->n = vp[h].p;
153 return vp[h].p = new;
154 } else { /* trample the top of the stack */
155 new = vp[h].p;
156 efree(new->extdef);
157 listfree(new->def);
158 return new;
159 }
160 }
161}
162
163extern void delete_fn(char *s) {
164 int h = fnfind(s);
165 if (fp[h].name == NULL)
166 return; /* not found */
167 env_dirty = TRUE;
168 free_fn(fp[h].p);
169 efree(fp[h].p);
170 efree(fp[h].name);
171 if (fp[(h+1)&(fsize-1)].name == NULL) {
172 --fused;
173 fp[h].name = NULL;
174 } else {
175 fp[h].name = dead;
176 }
177}
178
179extern void delete_var(char *s, bool stack) {
180 int h = varfind(s);
181 Variable *v;
182 if (vp[h].name == NULL)
183 return; /* not found */
184 env_dirty = TRUE;
185 v = vp[h].p;
186 efree(v->extdef);
187 listfree(v->def);
188 if (v->n != NULL) { /* This is the top of a stack */
189 if (stack) { /* pop */
190 vp[h].p = v->n;
191 efree(v);
192 } else { /* else just empty */
193 v->extdef = NULL;
194 v->def = NULL;
195 }
196 } else { /* needs to be removed from the hash table */
197 efree(v);
198 efree(vp[h].name);
199 if (vp[(h+1)&(vsize-1)].name == NULL) {
200 --vused;
201 vp[h].name = NULL;
202 } else {
203 vp[h].name = dead;
204 }
205 }
206}
207
208static void free_fn(Function *f) {
209 treefree(f->def);
210 efree(f->extdef);
211}
212
213extern void initenv(char **envp) {
214 int n;
215 for (n = 0; envp[n] != NULL; n++)
216 ;
217 n++; /* one for the null terminator */
218 if (n < HASHSIZE)
219 n = HASHSIZE;
220 env = ealloc((envsize = 2 * n) * sizeof (char *));
221 for (; *envp != NULL; envp++)
222 if (strncmp(*envp, "fn_", conststrlen("fn_")) == 0) {
223 if (!dashpee)
224 fnassign_string(*envp);
225 } else {
226 if (!varassign_string(*envp)) /* add to bozo env */
227 env[bozosize++] = *envp;
228 }
229}
230
231static bool var_exportable(char *s) {
232 static char *notforexport[] = {
233 "apid", "pid", "apids", "*", "ifs"
234 };
235 int i;
236 for (i = 0; i < arraysize(notforexport); i++)
237 if (streq(s, notforexport[i]))
238 return FALSE;
239 return TRUE;
240}
241
242static bool fn_exportable(char *s) {
243 int i;
244 if (strncmp(s, "sig", conststrlen("sig")) == 0) { /* small speed hack */
245 for (i = 0; i < NUMOFSIGNALS; i++)
246 if (streq(s, signals[i].name))
247 return FALSE;
248 if (streq(s, "sigexit"))
249 return FALSE;
250 }
251 return TRUE;
252}
253
254extern char **makeenv() {
255 int ep, i;
256 char *v;
257 if (!env_dirty)
258 return env;
259 env_dirty = FALSE;
260 ep = bozosize;
261 if (vsize + fsize + 1 + bozosize > envsize) {
262 envsize = 2 * (bozosize + vsize + fsize + 1);
263 env = erealloc(env, envsize * sizeof(char *));
264 }
265 for (i = 0; i < vsize; i++) {
266 if (vp[i].name == NULL || vp[i].name == dead || !var_exportable(vp[i].name))
267 continue;
268 v = varlookup_string(vp[i].name);
269 if (v != NULL)
270 env[ep++] = v;
271 }
272 for (i = 0; i < fsize; i++) {
273 if (fp[i].name == NULL || fp[i].name == dead || !fn_exportable(fp[i].name))
274 continue;
275 env[ep++] = fnlookup_string(fp[i].name);
276 }
277 env[ep] = NULL;
278 qsort(env, (size_t) ep, sizeof(char *), starstrcmp);
279 return env;
280}
281
282extern void whatare_all_vars() {
283 int i;
284 List *s;
285 for (i = 0; i < vsize; i++)
286 if (vp[i].name != NULL && (s = varlookup(vp[i].name)) != NULL)
287 prettyprint_var(1, vp[i].name, s);
288 for (i = 0; i < fsize; i++)
289 if (fp[i].name != NULL && fp[i].name != dead)
290 prettyprint_fn(1, fp[i].name, fnlookup(fp[i].name));
291}