/* $Header: /cvsroot/fbmuck/fbmuck/src/hashtab.c,v 1.3 2001/10/15 02:08:49 revar Exp $ */
/*
*
* $Log: hashtab.c,v $
* Revision 1.3 2001/10/15 02:08:49 revar
* Minor cleanups for possible Win32 port plans.
*
* Revision 1.2 2000/03/29 12:21:02 revar
* Reformatted all code into consistent format.
* Tabs are 4 spaces.
* Indents are one tab.
* Braces are generally K&R style.
* Added ARRAY_DIFF, ARRAY_INTERSECT and ARRAY_UNION to man.txt.
* Rewrote restart script as a bourne shell script.
*
* Revision 1.1.1.1 1999/12/16 03:23:29 revar
* Initial Sourceforge checkin, fb6.00a29
*
* Revision 1.1.1.1 1999/12/12 07:27:43 foxen
* Initial FB6 CVS checkin.
*
* Revision 1.1 1996/06/12 02:22:25 foxen
* Initial revision
*
* Revision 5.4 1994/03/14 12:20:58 foxen
* Fb5.20 release checkpoint.
*
* Revision 5.3 1994/03/14 12:08:46 foxen
* Initial portability mods and bugfixes.
*
* Revision 5.2 1994/01/18 20:52:20 foxen
* Version 5.15 release.
*
* Revision 5.1 1993/12/17 00:07:33 foxen
* initial revision.
*
* Revision 1.3 90/09/28 12:21:59 rearl
* Made some speed enhancements, fixed declarations of const char's.
*
* Revision 1.2 90/09/18 07:56:50 rearl
* Incorporated hash routines into TinyMUCK.
*
* Revision 1.1 90/09/16 22:45:01 rearl
* Initial revision
*
*
* Baseline code 90/09/12 code donated by Gazer, (dbriggs@nrao.edu)
* loosely based on hashing code in K&R II.
*
*/
#include "config.h"
#include "db.h"
#include "props.h"
#include "externs.h"
/* hash: compute hash value for a string
*
* this particular hash function is fairly simple. Note that it
* throws away the information from the 0x20 bit in the character.
* This means that upper and lower case letters will hash to the
* same value.
*/
unsigned int
hash(register const char *s, unsigned int hash_size)
{
unsigned int hashval;
for (hashval = 0; *s != '\0'; s++) {
hashval = (*s | 0x20) + 31 * hashval;
}
return hashval % hash_size;
}
/* find_hash: lookup a name in a hash table
*
* returns NULL if not found, otherwise a pointer to the data union.
*/
hash_data *
find_hash(register const char *s, hash_tab * table, unsigned int size)
{
register hash_entry *hp;
for (hp = table[hash(s, size)]; hp != NULL; hp = hp->next) {
if (string_compare(s, hp->name) == 0) {
return &(hp->dat); /* found */
}
}
return NULL; /* not found */
}
/* add_hash: add a string to a hash table
*
* will supercede old values in the table, returns pointer to
* the hash entry, or NULL on failure.
*
* NB: These hash routines assume that the names are static entities.
* The hash entries store only a pointer to the names. Be sure to
* make a static copy of the name before adding it to the table.
*/
hash_entry *
add_hash(register const char *name, hash_data data, hash_tab * table, unsigned int size)
{
register hash_entry *hp;
unsigned int hashval;
hashval = hash(name, size);
/* an inline find_hash */
for (hp = table[hashval]; hp != NULL; hp = hp->next) {
if (string_compare(name, hp->name) == 0) {
break;
}
}
/* If not found, set up a new entry */
if (hp == NULL) {
hp = (hash_entry *) malloc(sizeof(hash_entry));
if (hp == NULL) {
perror("add_hash: out of memory!");
abort(); /* can't allocate new entry -- die */
}
hp->next = table[hashval];
table[hashval] = hp;
hp->name = (char *) string_dup(name); /* This might be wasteful. */
if (hp->name == NULL) {
perror("add_hash: out of memory!");
abort(); /* can't allocate new entry -- die */
}
}
/* One way or another, the pointer is now valid */
hp->dat = data;
return hp;
}
/* free_hash: free a hash table entry
*
* frees the dynamically allocated hash table entry associated with
* a name. Returns 0 on success, or -1 if the name cannot be found.
*/
int
free_hash(register const char *name, hash_tab * table, unsigned int size)
{
register hash_entry **lp, *hp;
lp = &table[hash(name, size)];
for (hp = *lp; hp != NULL; lp = &(hp->next), hp = hp->next) {
if (string_compare(name, hp->name) == 0) {
*lp = hp->next; /* got it. fix the pointers */
free((void *) hp->name);
free((void *) hp);
return 0;
}
}
return -1; /* not found */
}
/* kill_hash: kill an entire hash table, by freeing every entry */
void
kill_hash(hash_tab * table, unsigned int size, int freeptrs)
{
register hash_entry *hp, *np;
unsigned int i;
for (i = 0; i < size; i++) {
for (hp = table[i]; hp != NULL; hp = np) {
np = hp->next; /* Don't dereference the pointer after */
free((void *) hp->name);
if (freeptrs) {
free((void *) hp->dat.pval);
}
free((void *) hp); /* we've freed it! */
}
table[i] = NULL;
}
}