mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-08 00:23:14 +00:00
* Merged version 2.1 of GoAhead webserver. This update was submitted by Antti P Miettinen <antti.p.miettinen@nokia.com>. * NOTES, base64.c, ejIntrn.h, emfdb.c, emfdb.h, md5.h, md5c.c, um.c, um.h: New files. * wbase64.c: Removed. * Makefile.am, asp.c, balloc.c, default.c, ej.h, ejlex.c, ejparse.c, form.c, h.c, handler.c, mime.c, misc.c, ringq.c, rom.c, security.c, socket.c, sym.c, uemf.c, uemf.h, url.c, value.c, webcomp.c, webmain.c, webpage.c, webrom.c, webs.c, webs.h, websuemf.c, wsIntrn.h: Modified.
474 lines
11 KiB
C
474 lines
11 KiB
C
/*
|
|
* sym.c -- Symbol Table module
|
|
*
|
|
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
|
|
*
|
|
* See the file "license.txt" for usage and redistribution license requirements
|
|
*/
|
|
|
|
/******************************** Description *********************************/
|
|
/*
|
|
* This module implements a highly efficient generic symbol table with
|
|
* update and access routines. Symbols are simple character strings and
|
|
* the values they take can be flexible types as defined by value_t.
|
|
* This modules allows multiple symbol tables to be created.
|
|
*/
|
|
|
|
/********************************* Includes ***********************************/
|
|
|
|
#if UEMF
|
|
#include "uemf.h"
|
|
#else
|
|
#include "basic/basicInternal.h"
|
|
#endif
|
|
|
|
/********************************* Defines ************************************/
|
|
|
|
typedef struct { /* Symbol table descriptor */
|
|
int inuse; /* Is this entry in use */
|
|
int hash_size; /* Size of the table below */
|
|
sym_t **hash_table; /* Allocated at run time */
|
|
} sym_tabent_t;
|
|
|
|
/********************************* Globals ************************************/
|
|
|
|
static sym_tabent_t **sym; /* List of symbol tables */
|
|
static int symMax; /* One past the max symbol table */
|
|
static int symOpenCount = 0; /* Count of apps using sym */
|
|
|
|
static int htIndex; /* Current location in table */
|
|
static sym_t* next; /* Next symbol in iteration */
|
|
|
|
/**************************** Forward Declarations ****************************/
|
|
|
|
static int hashIndex(sym_tabent_t *tp, char_t *name);
|
|
static sym_t *hash(sym_tabent_t *tp, char_t *name);
|
|
static int calcPrime(int size);
|
|
|
|
/*********************************** Code *************************************/
|
|
/*
|
|
* Open the symbol table subSystem.
|
|
*/
|
|
|
|
int symSubOpen()
|
|
{
|
|
if (++symOpenCount == 1) {
|
|
symMax = 0;
|
|
sym = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Close the symbol table subSystem.
|
|
*/
|
|
|
|
void symSubClose()
|
|
{
|
|
if (--symOpenCount <= 0) {
|
|
symOpenCount = 0;
|
|
}
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Create a symbol table.
|
|
*/
|
|
|
|
sym_fd_t symOpen(int hash_size)
|
|
{
|
|
sym_fd_t sd;
|
|
sym_tabent_t *tp;
|
|
|
|
a_assert(hash_size > 2);
|
|
|
|
/*
|
|
* Create a new handle for this symbol table
|
|
*/
|
|
if ((sd = hAlloc((void***) &sym)) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Create a new symbol table structure and zero
|
|
*/
|
|
if ((tp = (sym_tabent_t*) balloc(B_L, sizeof(sym_tabent_t))) == NULL) {
|
|
symMax = hFree((void***) &sym, sd);
|
|
return -1;
|
|
}
|
|
memset(tp, 0, sizeof(sym_tabent_t));
|
|
if (sd >= symMax) {
|
|
symMax = sd + 1;
|
|
}
|
|
a_assert(0 <= sd && sd < symMax);
|
|
sym[sd] = tp;
|
|
|
|
/*
|
|
* Now create the hash table for fast indexing.
|
|
*/
|
|
tp->hash_size = calcPrime(hash_size);
|
|
tp->hash_table = (sym_t**) balloc(B_L, tp->hash_size * sizeof(sym_t*));
|
|
a_assert(tp->hash_table);
|
|
memset(tp->hash_table, 0, tp->hash_size * sizeof(sym_t*));
|
|
|
|
return sd;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Close this symbol table. Call a cleanup function to allow the caller
|
|
* to free resources associated with each symbol table entry.
|
|
*/
|
|
|
|
void symClose(sym_fd_t sd)
|
|
{
|
|
sym_tabent_t *tp;
|
|
sym_t *sp, *forw;
|
|
int i;
|
|
|
|
a_assert(0 <= sd && sd < symMax);
|
|
tp = sym[sd];
|
|
a_assert(tp);
|
|
|
|
/*
|
|
* Free all symbols in the hash table, then the hash table itself.
|
|
*/
|
|
for (i = 0; i < tp->hash_size; i++) {
|
|
for (sp = tp->hash_table[i]; sp; sp = forw) {
|
|
forw = sp->forw;
|
|
valueFree(&sp->name);
|
|
valueFree(&sp->content);
|
|
bfree(B_L, (void*) sp);
|
|
sp = forw;
|
|
}
|
|
}
|
|
bfree(B_L, (void*) tp->hash_table);
|
|
|
|
symMax = hFree((void***) &sym, sd);
|
|
bfree(B_L, (void*) tp);
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Return the first symbol in the hashtable if there is one. This call is used
|
|
* as the first step in traversing the table. A call to symFirst should be
|
|
* followed by calls to symNext to get all the rest of the entries.
|
|
*/
|
|
|
|
sym_t* symFirst(sym_fd_t sd)
|
|
{
|
|
sym_tabent_t *tp;
|
|
sym_t *sp, *forw;
|
|
int i;
|
|
|
|
a_assert(0 <= sd && sd < symMax);
|
|
tp = sym[sd];
|
|
a_assert(tp);
|
|
|
|
/*
|
|
* Find the first symbol in the hashtable and return a pointer to it.
|
|
*/
|
|
for (i = 0; i < tp->hash_size; i++) {
|
|
for (sp = tp->hash_table[i]; sp; sp = forw) {
|
|
forw = sp->forw;
|
|
|
|
if (forw == NULL) {
|
|
htIndex = i + 1;
|
|
next = tp->hash_table[htIndex];
|
|
} else {
|
|
htIndex = i;
|
|
next = forw;
|
|
}
|
|
return sp;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Return the next symbol in the hashtable if there is one. See symFirst.
|
|
*/
|
|
|
|
sym_t* symNext(sym_fd_t sd)
|
|
{
|
|
sym_tabent_t *tp;
|
|
sym_t *sp, *forw;
|
|
int i;
|
|
|
|
a_assert(0 <= sd && sd < symMax);
|
|
tp = sym[sd];
|
|
a_assert(tp);
|
|
|
|
/*
|
|
* Find the first symbol in the hashtable and return a pointer to it.
|
|
*/
|
|
for (i = htIndex; i < tp->hash_size; i++) {
|
|
for (sp = next; sp; sp = forw) {
|
|
forw = sp->forw;
|
|
|
|
if (forw == NULL) {
|
|
htIndex = i + 1;
|
|
next = tp->hash_table[htIndex];
|
|
} else {
|
|
htIndex = i;
|
|
next = forw;
|
|
}
|
|
return sp;
|
|
}
|
|
next = tp->hash_table[i + 1];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Lookup a symbol and return a pointer to the symbol entry. If not present
|
|
* then return a NULL.
|
|
*/
|
|
|
|
sym_t *symLookup(sym_fd_t sd, char_t *name)
|
|
{
|
|
sym_tabent_t *tp;
|
|
sym_t *sp;
|
|
char_t *cp;
|
|
|
|
a_assert(0 <= sd && sd < symMax);
|
|
if ((tp = sym[sd]) == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (name == NULL || *name == '\0') {
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Do an initial hash and then follow the link chain to find the right entry
|
|
*/
|
|
for (sp = hash(tp, name); sp; sp = sp->forw) {
|
|
cp = sp->name.value.string;
|
|
if (cp[0] == name[0] && gstrcmp(cp, name) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
return sp;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Enter a symbol into the table. If already there, update its value.
|
|
* Always succeeds if memory available. We allocate a copy of "name" here
|
|
* so it can be a volatile variable. The value "v" is just a copy of the
|
|
* passed in value, so it MUST be persistent.
|
|
*/
|
|
|
|
sym_t *symEnter(sym_fd_t sd, char_t *name, value_t v, int arg)
|
|
{
|
|
sym_tabent_t *tp;
|
|
sym_t *sp, *last;
|
|
char_t *cp;
|
|
int hindex;
|
|
|
|
a_assert(name);
|
|
a_assert(0 <= sd && sd < symMax);
|
|
tp = sym[sd];
|
|
a_assert(tp);
|
|
|
|
/*
|
|
* Calculate the first daisy-chain from the hash table. If non-zero, then
|
|
* we have daisy-chain, so scan it and look for the symbol.
|
|
*/
|
|
last = NULL;
|
|
hindex = hashIndex(tp, name);
|
|
if ((sp = tp->hash_table[hindex]) != NULL) {
|
|
for (; sp; sp = sp->forw) {
|
|
cp = sp->name.value.string;
|
|
if (cp[0] == name[0] && gstrcmp(cp, name) == 0) {
|
|
break;
|
|
}
|
|
last = sp;
|
|
}
|
|
if (sp) {
|
|
/*
|
|
* Found, so update the value
|
|
* If the caller stores handles which require freeing, they
|
|
* will be lost here. It is the callers responsibility to free
|
|
* resources before overwriting existing contents. We will here
|
|
* free allocated strings which occur due to value_instring().
|
|
* We should consider providing the cleanup function on the open rather
|
|
* than the close and then we could call it here and solve the problem.
|
|
*/
|
|
if (sp->content.valid) {
|
|
valueFree(&sp->content);
|
|
}
|
|
sp->content = v;
|
|
sp->arg = arg;
|
|
return sp;
|
|
}
|
|
/*
|
|
* Not found so allocate and append to the daisy-chain
|
|
*/
|
|
sp = (sym_t*) balloc(B_L, sizeof(sym_t));
|
|
if (sp == NULL) {
|
|
return NULL;
|
|
}
|
|
sp->name = valueString(name, VALUE_ALLOCATE);
|
|
sp->content = v;
|
|
sp->forw = (sym_t*) NULL;
|
|
sp->arg = arg;
|
|
last->forw = sp;
|
|
|
|
} else {
|
|
/*
|
|
* Daisy chain is empty so we need to start the chain
|
|
*/
|
|
sp = (sym_t*) balloc(B_L, sizeof(sym_t));
|
|
if (sp == NULL) {
|
|
return NULL;
|
|
}
|
|
tp->hash_table[hindex] = sp;
|
|
tp->hash_table[hashIndex(tp, name)] = sp;
|
|
|
|
sp->forw = (sym_t*) NULL;
|
|
sp->content = v;
|
|
sp->arg = arg;
|
|
sp->name = valueString(name, VALUE_ALLOCATE);
|
|
}
|
|
return sp;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Delete a symbol from a table
|
|
*/
|
|
|
|
int symDelete(sym_fd_t sd, char_t *name)
|
|
{
|
|
sym_tabent_t *tp;
|
|
sym_t *sp, *last;
|
|
char_t *cp;
|
|
int hindex;
|
|
|
|
a_assert(name && *name);
|
|
a_assert(0 <= sd && sd < symMax);
|
|
tp = sym[sd];
|
|
a_assert(tp);
|
|
|
|
/*
|
|
* Calculate the first daisy-chain from the hash table. If non-zero, then
|
|
* we have daisy-chain, so scan it and look for the symbol.
|
|
*/
|
|
last = NULL;
|
|
hindex = hashIndex(tp, name);
|
|
if ((sp = tp->hash_table[hindex]) != NULL) {
|
|
for ( ; sp; sp = sp->forw) {
|
|
cp = sp->name.value.string;
|
|
if (cp[0] == name[0] && gstrcmp(cp, name) == 0) {
|
|
break;
|
|
}
|
|
last = sp;
|
|
}
|
|
}
|
|
if (sp == (sym_t*) NULL) { /* Not Found */
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Unlink and free the symbol. Last will be set if the element to be deleted
|
|
* is not first in the chain.
|
|
*/
|
|
if (last) {
|
|
last->forw = sp->forw;
|
|
} else {
|
|
tp->hash_table[hindex] = sp->forw;
|
|
}
|
|
valueFree(&sp->name);
|
|
valueFree(&sp->content);
|
|
bfree(B_L, (void*) sp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Hash a symbol and return a pointer to the hash daisy-chain list
|
|
* All symbols reside on the chain (ie. none stored in the hash table itself)
|
|
*/
|
|
|
|
static sym_t *hash(sym_tabent_t *tp, char_t *name)
|
|
{
|
|
a_assert(tp);
|
|
|
|
return tp->hash_table[hashIndex(tp, name)];
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Compute the hash function and return an index into the hash table
|
|
* We use a basic additive function that is then made modulo the size of the
|
|
* table.
|
|
*/
|
|
|
|
static int hashIndex(sym_tabent_t *tp, char_t *name)
|
|
{
|
|
unsigned int sum;
|
|
int i;
|
|
|
|
a_assert(tp);
|
|
/*
|
|
* Add in each character shifted up progressively by 7 bits. The shift
|
|
* amount is rounded so as to not shift too far. It thus cycles with each
|
|
* new cycle placing character shifted up by one bit.
|
|
*/
|
|
i = 0;
|
|
sum = 0;
|
|
while (*name) {
|
|
sum += (((int) *name++) << i);
|
|
i = (i + 7) % (BITS(int) - BITSPERBYTE);
|
|
}
|
|
return sum % tp->hash_size;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Check if this number is a prime
|
|
*/
|
|
|
|
static int isPrime(int n)
|
|
{
|
|
int i, max;
|
|
|
|
a_assert(n > 0);
|
|
|
|
max = n / 2;
|
|
for (i = 2; i <= max; i++) {
|
|
if (n % i == 0) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
* Calculate the largest prime smaller than size.
|
|
*/
|
|
|
|
static int calcPrime(int size)
|
|
{
|
|
int count;
|
|
|
|
a_assert(size > 0);
|
|
|
|
for (count = size; count > 0; count--) {
|
|
if (isPrime(count)) {
|
|
return count;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|