| #include <stdlib.h> |
| #include <string.h> |
| #include "hash.h" |
| #include "util.h" |
| |
| #define HASHSIZE 4093 |
| |
| static int hash_value(char *name); |
| |
| |
| |
| struct s_hash ** |
| alloc_hash_table(void) |
| { |
| |
| /* Creates a hash table with HASHSIZE different locations (hash values). */ |
| |
| struct s_hash **hash_table; |
| |
| hash_table = (struct s_hash **)my_calloc(sizeof(struct s_hash *), |
| HASHSIZE); |
| return (hash_table); |
| } |
| |
| |
| void |
| free_hash_table(struct s_hash **hash_table) |
| { |
| |
| /* Frees all the storage associated with a hash table. */ |
| |
| int i; |
| struct s_hash *h_ptr, *temp_ptr; |
| |
| for(i = 0; i < HASHSIZE; i++) |
| { |
| h_ptr = hash_table[i]; |
| while(h_ptr != NULL) |
| { |
| free(h_ptr->name); |
| temp_ptr = h_ptr->next; |
| free(h_ptr); |
| h_ptr = temp_ptr; |
| } |
| } |
| |
| free(hash_table); |
| } |
| |
| |
| struct s_hash_iterator |
| start_hash_table_iterator(void) |
| { |
| |
| /* Call this routine before you start going through all the elements in * |
| * a hash table. It sets the internal indices to the start of the table. */ |
| |
| struct s_hash_iterator hash_iterator; |
| |
| hash_iterator.i = -1; |
| hash_iterator.h_ptr = NULL; |
| return (hash_iterator); |
| } |
| |
| |
| struct s_hash * |
| get_next_hash(struct s_hash **hash_table, |
| struct s_hash_iterator *hash_iterator) |
| { |
| |
| /* Returns the next occupied hash entry, and moves the iterator structure * |
| * forward so the next call gets the next entry. */ |
| |
| int i; |
| struct s_hash *h_ptr; |
| |
| i = hash_iterator->i; |
| h_ptr = hash_iterator->h_ptr; |
| |
| while(h_ptr == NULL) |
| { |
| i++; |
| if(i >= HASHSIZE) |
| return (NULL); /* End of table */ |
| |
| h_ptr = hash_table[i]; |
| } |
| |
| hash_iterator->h_ptr = h_ptr->next; |
| hash_iterator->i = i; |
| return (h_ptr); |
| } |
| |
| |
| struct s_hash * |
| insert_in_hash_table(struct s_hash **hash_table, |
| char *name, |
| int next_free_index) |
| { |
| |
| /* Adds the string pointed to by name to the hash table, and returns the * |
| * hash structure created or updated. If name is already in the hash table * |
| * the count member of that hash element is incremented. Otherwise a new * |
| * hash entry with a count of zero and an index of next_free_index is * |
| * created. */ |
| |
| int i; |
| struct s_hash *h_ptr, *prev_ptr; |
| |
| i = hash_value(name); |
| prev_ptr = NULL; |
| h_ptr = hash_table[i]; |
| |
| while(h_ptr != NULL) |
| { |
| if(strcmp(h_ptr->name, name) == 0) |
| { |
| h_ptr->count++; |
| return (h_ptr); |
| } |
| |
| prev_ptr = h_ptr; |
| h_ptr = h_ptr->next; |
| } |
| |
| /* Name string wasn't in the hash table. Add it. */ |
| |
| h_ptr = (struct s_hash *)my_malloc(sizeof(struct s_hash)); |
| if(prev_ptr == NULL) |
| { |
| hash_table[i] = h_ptr; |
| } |
| else |
| { |
| prev_ptr->next = h_ptr; |
| } |
| h_ptr->next = NULL; |
| h_ptr->index = next_free_index; |
| h_ptr->count = 1; |
| h_ptr->name = (char *)my_malloc((strlen(name) + 1) * sizeof(char)); |
| strcpy(h_ptr->name, name); |
| return (h_ptr); |
| } |
| |
| |
| struct s_hash * |
| get_hash_entry(struct s_hash **hash_table, |
| char *name) |
| { |
| |
| /* Returns the hash entry with this name, or NULL if there is no * |
| * corresponding entry. */ |
| |
| int i; |
| struct s_hash *h_ptr; |
| |
| i = hash_value(name); |
| h_ptr = hash_table[i]; |
| |
| while(h_ptr != NULL) |
| { |
| if(strcmp(h_ptr->name, name) == 0) |
| return (h_ptr); |
| |
| h_ptr = h_ptr->next; |
| } |
| |
| return (NULL); |
| } |
| |
| |
| static int |
| hash_value(char *name) |
| { |
| |
| /* Creates a hash key from a character string. Only the first character and * |
| * the last 8 characters of the string are used -- that may be dumb. */ |
| |
| int i, k; |
| int val = 0, mult = 1; |
| |
| i = strlen(name); |
| k = max(i - 8, 0); |
| for(i = strlen(name) - 1; i >= k; i--) |
| { |
| val += mult * ((int)name[i]); |
| mult *= 7; |
| } |
| val += (int)name[0]; |
| val %= HASHSIZE; |
| return (val); |
| } |