source: rtems/cpukit/httpd/sym.c @ 9b05600

4.104.114.84.95
Last change on this file since 9b05600 was c1cdaa0, checked in by Joel Sherrill <joel.sherrill@…>, on 10/27/99 at 12:50:33

Patch from Emmanuel Raguet <raguet@…> and Eric Valette
<valette@…> to add a port of the GoAhead? web server
(httpd) to the RTEMS build tree. They have successfully used
this BSP on i386/pc386 and PowerPC/mcp750.

Mark and Joel spoke with Nick Berliner <nickb@…> on
26 Oct 1999 about this port and got verbal approval to include
it in RTEMS distributions.

  • Property mode set to 100644
File size: 10.2 KB
Line 
1/*
2 * sym.c -- Symbol Table module
3 *
4 * Copyright (c) GoAhead Software Inc., 1995-1999. All Rights Reserved.
5 *
6 * See the file "license.txt" for usage and redistribution license requirements
7 */
8
9/******************************** Description *********************************/
10/*
11 *      This module implements a highly efficient generic symbol table with
12 *      update and access routines.  Symbols are simple character strings and
13 *      the values they take can be flexible types as defined by value_t.
14 *      This modules allows multiple symbol tables to be created.
15 */
16
17/********************************* Includes ***********************************/
18
19#if UEMF
20        #include        "uemf.h"
21#else
22        #include        "basic/basicInternal.h"
23#endif
24
25/********************************* Defines ************************************/
26
27typedef struct {                                                /* Symbol table descriptor */
28        int             inuse;                                          /* Is this entry in use */
29        int             hash_size;                                      /* Size of the table below */
30        sym_t   **hash_table;                           /* Allocated at run time */
31} sym_tabent_t;
32
33/********************************* Globals ************************************/
34
35static sym_tabent_t             **sym;                  /* List of symbol tables */
36static int                              sym_max;                /* One past the max symbol table */
37
38static int              htIndex;                                /* Current location in table */
39static sym_t*   next;                                   /* Next symbol in iteration */
40
41/**************************** Forward Declarations ****************************/
42
43static int              hashIndex(sym_tabent_t *tp, char_t *name);
44static sym_t    *hash(sym_tabent_t *tp, char_t *name);
45static int              calc_prime(int size);
46
47/*********************************** Code *************************************/
48/*
49 *      Create a symbol table.
50 */
51
52sym_fd_t symOpen(int hash_size)
53{
54        sym_fd_t                sd;
55        sym_tabent_t    *tp;
56
57        a_assert(hash_size > 2);
58
59/*
60 *      Create a new handle for this symbol table
61 */
62        if ((sd = hAlloc((void***) &sym)) < 0) {
63                return -1;
64        }
65
66/*
67 *      Create a new symbol table structure and zero
68 */
69        if ((tp = (sym_tabent_t*) balloc(B_L, sizeof(sym_tabent_t))) == NULL) {
70                sym_max = hFree((void***) &sym, sd);
71                return -1;
72        }
73        memset(tp, 0, sizeof(sym_tabent_t));
74        if (sd >= sym_max) {
75                sym_max = sd + 1;
76        }
77        a_assert(0 <= sd && sd < sym_max);
78        sym[sd] = tp;
79
80/*
81 *      Now create the hash table for fast indexing.
82 */
83        tp->hash_size = calc_prime(hash_size);
84        tp->hash_table = (sym_t**) balloc(B_L, tp->hash_size * sizeof(sym_t*));
85        a_assert(tp->hash_table);
86        memset(tp->hash_table, 0, tp->hash_size * sizeof(sym_t*));
87
88        return sd;
89}
90
91/******************************************************************************/
92/*
93 *      Close this symbol table. Call a cleanup function to allow the caller
94 *      to free resources associated with each symbol table entry.
95 */
96
97void symClose(sym_fd_t sd, void (*cleanup)(sym_t *symp))
98{
99        sym_tabent_t    *tp;
100        sym_t                   *sp, *forw;
101        int                     i;
102
103        a_assert(0 <= sd && sd < sym_max);
104        tp = sym[sd];
105        a_assert(tp);
106
107/*
108 *      Free all symbols in the hash table, then the hash table itself.
109 */
110        for (i = 0; i < tp->hash_size; i++) {
111                for (sp = tp->hash_table[i]; sp; sp = forw) {
112                        forw = sp->forw;
113                        if (cleanup) {
114                                (*cleanup)(sp);
115                        }
116                        valueFree(&sp->name);
117                        bfree(B_L, (void*) sp);
118                        sp = forw;
119                }
120        }
121        bfree(B_L, (void*) tp->hash_table);
122
123        sym_max = hFree((void***) &sym, sd);
124        bfree(B_L, (void*) tp);
125}
126
127/******************************************************************************/
128/*
129 *      Default callback for freeing the value.
130 */
131
132void symFreeVar(sym_t* sp)
133{
134        valueFree(&sp->content);
135}
136
137/******************************************************************************/
138/*
139 *      Return the first symbol in the hashtable if there is one. This call is used
140 *      as the first step in traversing the table. A call to symFirst should be
141 *      followed by calls to symNext to get all the rest of the entries.
142 */
143
144sym_t* symFirst(sym_fd_t sd)
145{
146        sym_tabent_t    *tp;
147        sym_t                   *sp, *forw;
148        int                     i;
149
150        a_assert(0 <= sd && sd < sym_max);
151        tp = sym[sd];
152        a_assert(tp);
153
154/*
155 *      Find the first symbol in the hashtable and return a pointer to it.
156 */
157        for (i = 0; i < tp->hash_size; i++) {
158                for (sp = tp->hash_table[i]; sp; sp = forw) {
159                        forw = sp->forw;
160
161                        if (forw == NULL) {
162                                htIndex = i + 1;
163                                next = tp->hash_table[htIndex];
164                        } else {
165                                htIndex = i;
166                                next = forw;
167                        }
168                        return sp;
169                }
170        }
171        return NULL;
172}
173
174/******************************************************************************/
175/*
176 *      Return the next symbol in the hashtable if there is one. See symFirst.
177 */
178
179sym_t* symNext(sym_fd_t sd)
180{
181        sym_tabent_t    *tp;
182        sym_t                   *sp, *forw;
183        int                     i;
184
185        a_assert(0 <= sd && sd < sym_max);
186        tp = sym[sd];
187        a_assert(tp);
188
189/*
190 *      Find the first symbol in the hashtable and return a pointer to it.
191 */
192        for (i = htIndex; i < tp->hash_size; i++) {
193                for (sp = next; sp; sp = forw) {
194                        forw = sp->forw;
195
196                        if (forw == NULL) {
197                                htIndex = i + 1;
198                                next = tp->hash_table[htIndex];
199                        } else {
200                                htIndex = i;
201                                next = forw;
202                        }
203                        return sp;
204                }
205                next = tp->hash_table[i + 1];
206        }
207        return NULL;
208}
209
210/******************************************************************************/
211/*
212 *      Lookup a symbol and return a pointer to the symbol entry. If not present
213 *      then return a NULL.
214 */
215
216sym_t *symLookup(sym_fd_t sd, char_t *name)
217{
218        sym_tabent_t    *tp;
219        sym_t                   *sp;
220        char_t                  *cp;
221
222        a_assert(0 <= sd && sd < sym_max);
223        tp = sym[sd];
224        a_assert(tp);
225
226        if (name == NULL || *name == '\0') {
227                return NULL;
228        }
229
230/*
231 *      Do an initial hash and then follow the link chain to find the right entry
232 */
233        for (sp = hash(tp, name); sp; sp = sp->forw) {
234                cp = sp->name.value.string;
235                if (cp[0] == name[0] && gstrcmp(cp, name) == 0) {
236                        break;
237                }
238        }
239        return sp;
240}
241
242/******************************************************************************/
243/*
244 *      Enter a symbol into the table.  If already there, update its value.
245 *      Always succeeds if memory available.
246 */
247
248sym_t *symEnter(sym_fd_t sd, char_t *name, value_t v, int arg)
249{
250        sym_tabent_t    *tp;
251        sym_t                   *sp, *last;
252        char_t                  *cp;
253        int                             hindex;
254
255        a_assert(name && *name);
256        a_assert(0 <= sd && sd < sym_max);
257        tp = sym[sd];
258        a_assert(tp);
259
260/*
261 *      Calculate the first daisy-chain from the hash table.  If non-zero, then
262 *      we have daisy-chain, so scan it and look for the symbol.
263 */
264        last = NULL;
265        hindex = hashIndex(tp, name);
266        if ((sp = tp->hash_table[hindex]) != NULL) {
267                for (; sp; sp = sp->forw) {
268                        cp = sp->name.value.string;
269                        if (cp[0] == name[0] && gstrcmp(cp, name) == 0) {
270                                break;
271                        }
272                        last = sp;
273                }
274                if (sp) {
275/*
276 *                      Found, so update the value
277 *                      If the caller stores handles which require freeing, they
278 *                      will be lost here. It is the callers responsibility to free
279 *                      resources before overwriting existing contents. We will here
280 *                      free allocated strings which occur due to value_instring().
281 *                      We should consider providing the cleanup function on the open rather
282 *                      than the close and then we could call it here and solve the problem.
283 */
284                        if (sp->content.valid) {
285                                valueFree(&sp->content);
286                        }
287                        sp->content = v;
288                        sp->arg = arg;
289                        return sp;
290                }
291/*
292 *              Not found so allocate and append to the daisy-chain
293 */
294                sp = (sym_t*) balloc(B_L, sizeof(sym_t));
295                if (sp == NULL) {
296                        return NULL;
297                }
298                sp->name = valueString(name, VALUE_ALLOCATE);
299                sp->content = v;
300                sp->forw = (sym_t*) NULL;
301                sp->arg = arg;
302                last->forw = sp;
303
304        } else {
305/*
306 *              Daisy chain is empty so we need to start the chain
307 */
308                sp = (sym_t*) balloc(B_L, sizeof(sym_t));
309                if (sp == NULL) {
310                        return NULL;
311                }
312                tp->hash_table[hindex] = sp;
313                tp->hash_table[hashIndex(tp, name)] = sp;
314
315                sp->forw = (sym_t*) NULL;
316                sp->content = v;
317                sp->arg = arg;
318                sp->name = valueString(name, VALUE_ALLOCATE);
319        }
320        return sp;
321}
322
323/******************************************************************************/
324/*
325 *      Delete a symbol from a table
326 */
327
328int symDelete(sym_fd_t sd, char_t *name)
329{
330        sym_tabent_t    *tp;
331        sym_t                   *sp, *last;
332        char_t                  *cp;
333        int                             hindex;
334
335        a_assert(name && *name);
336        a_assert(0 <= sd && sd < sym_max);
337        tp = sym[sd];
338        a_assert(tp);
339
340/*
341 *      Calculate the first daisy-chain from the hash table.  If non-zero, then
342 *      we have daisy-chain, so scan it and look for the symbol.
343 */
344        last = NULL;
345        hindex = hashIndex(tp, name);
346        if ((sp = tp->hash_table[hindex]) != NULL) {
347                for ( ; sp; sp = sp->forw) {
348                        cp = sp->name.value.string;
349                        if (cp[0] == name[0] && gstrcmp(cp, name) == 0) {
350                                break;
351                        }
352                        last = sp;
353                }
354        }
355        if (sp == (sym_t*) NULL) {                              /* Not Found */
356                return -1;
357        }
358       
359/*
360 *      Unlink and free the symbol. Last will be set if the element to be deleted
361 *      is not first in the chain.
362 */
363        if (last) {
364                last->forw = sp->forw;
365        } else {
366                tp->hash_table[hindex] = sp->forw;
367        }
368        valueFree(&sp->name);
369        bfree(B_L, (void*) sp);
370
371        return 0;
372}
373
374/******************************************************************************/
375/*
376 *      Hash a symbol and return a pointer to the hash daisy-chain list
377 *      All symbols reside on the chain (ie. none stored in the hash table itself)
378 */
379
380static sym_t *hash(sym_tabent_t *tp, char_t *name)
381{
382        a_assert(tp);
383
384        return tp->hash_table[hashIndex(tp, name)];
385}
386
387/******************************************************************************/
388/*
389 *      Compute the hash function and return an index into the hash table
390 *      We use a basic additive function that is then made modulo the size of the
391 *      table.
392 */
393
394static int hashIndex(sym_tabent_t *tp, char_t *name)
395{
396        unsigned int    sum;
397        int                     i;
398
399        a_assert(tp);
400/*
401 *      Add in each character shifted up progressively by 7 bits. The shift
402 *      amount is rounded so as to not shift too far.  It thus cycles with each
403 *      new cycle placing character shifted up by one bit.
404 */
405        i = 0;
406        sum = 0;
407        while (*name) {
408                sum += (((int) *name++) << i);
409                i = (i + 7) % (BITS(int) - BITSPERBYTE);
410        }
411        return sum % tp->hash_size;
412}
413
414/******************************************************************************/
415/*
416 *      Check if this number is a prime
417 */
418
419static int is_prime(int n)
420{
421        int     i;
422
423        a_assert(n > 0);
424
425        for (i = 2; i < n; i++) {
426                if (n % i == 0) {
427                        return 0;
428                }
429        }
430        return 1;
431}
432
433/******************************************************************************/
434/*
435 *      Calculate the largest prime smaller than size.
436 */
437
438static int calc_prime(int size)
439{
440        int count;
441
442        a_assert(size > 0);
443
444        for (count = size; count > 0; count--) {
445                if (is_prime(count)) {
446                        return count;
447                }
448        }
449        return 1;
450}
451
452/******************************************************************************/
Note: See TracBrowser for help on using the repository browser.