/*
* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
- * [Knuth] The Art of Computer Programming, part 3 (6.4)
+ * [Knuth] The Art of Computer Programming, part 3 (6.4)
*/
-/*
- * The non-reentrant version use a global space for storing the hash table.
- */
-static struct hsearch_data htab;
-
/*
* The reentrant version has no static variables to maintain the state.
* Instead the interface of all functions is extended to take an argument
* which describes the current status.
*/
typedef struct _ENTRY {
- unsigned int used;
+ int used;
ENTRY entry;
} _ENTRY;
return number % div != 0;
}
-int hcreate(size_t nel)
-{
- return hcreate_r(nel, &htab);
-}
-
/*
* Before using the hash table we must allocate memory for it.
* Test for an existing table are done. We allocate one element
* The contents of the table is zeroed, especially the field used
* becomes zero.
*/
+
int hcreate_r(size_t nel, struct hsearch_data *htab)
{
/* Test for correct arguments. */
/*
* hdestroy()
*/
-void hdestroy(void)
-{
- hdestroy_r(&htab);
-}
/*
* After using the hash table it has to be destroyed. The used memory can
* be freed and the local static variable can be marked as not used.
*/
+
void hdestroy_r(struct hsearch_data *htab)
{
int i;
/* free used memory */
for (i = 1; i <= htab->size; ++i) {
- if (htab->table[i].used) {
+ if (htab->table[i].used > 0) {
ENTRY *ep = &htab->table[i].entry;
free(ep->key);
* example for functions like hdelete().
*/
-ENTRY *hsearch(ENTRY item, ACTION action)
+/*
+ * hstrstr_r - return index to entry whose key and/or data contains match
+ */
+int hstrstr_r(const char *match, int last_idx, ENTRY ** retval,
+ struct hsearch_data *htab)
{
- ENTRY *result;
+ unsigned int idx;
- (void) hsearch_r(item, action, &result, &htab);
+ for (idx = last_idx + 1; idx < htab->size; ++idx) {
+ if (htab->table[idx].used <= 0)
+ continue;
+ if (strstr(htab->table[idx].entry.key, match) ||
+ strstr(htab->table[idx].entry.data, match)) {
+ *retval = &htab->table[idx].entry;
+ return idx;
+ }
+ }
- return result;
+ __set_errno(ESRCH);
+ *retval = NULL;
+ return 0;
+}
+
+int hmatch_r(const char *match, int last_idx, ENTRY ** retval,
+ struct hsearch_data *htab)
+{
+ unsigned int idx;
+ size_t key_len = strlen(match);
+
+ for (idx = last_idx + 1; idx < htab->size; ++idx) {
+ if (htab->table[idx].used <= 0)
+ continue;
+ if (!strncmp(match, htab->table[idx].entry.key, key_len)) {
+ *retval = &htab->table[idx].entry;
+ return idx;
+ }
+ }
+
+ __set_errno(ESRCH);
+ *retval = NULL;
+ return 0;
}
int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
unsigned int count;
unsigned int len = strlen(item.key);
unsigned int idx;
+ unsigned int first_deleted = 0;
/* Compute an value for the given string. Perhaps use a better method. */
hval = len;
if (htab->table[idx].used) {
/*
- * Further action might be required according to the
+ * Further action might be required according to the
* action value.
*/
unsigned hval2;
+ if (htab->table[idx].used == -1
+ && !first_deleted)
+ first_deleted = idx;
+
if (htab->table[idx].used == hval
&& strcmp(item.key, htab->table[idx].entry.key) == 0) {
/* Overwrite existing value? */
do {
/*
- * Because SIZE is prime this guarantees to
- * step through all available indices.
+ * Because SIZE is prime this guarantees to
+ * step through all available indices.
*/
if (idx <= hval2)
idx = htab->size + idx - hval2;
/* An empty bucket has been found. */
if (action == ENTER) {
/*
- * If table is full and another entry should be
- * entered return with error.
+ * If table is full and another entry should be
+ * entered return with error.
*/
if (htab->filled == htab->size) {
__set_errno(ENOMEM);
* Create new entry;
* create copies of item.key and item.data
*/
+ if (first_deleted)
+ idx = first_deleted;
+
htab->table[idx].used = hval;
htab->table[idx].entry.key = strdup(item.key);
htab->table[idx].entry.data = strdup(item.data);
* do that.
*/
-int hdelete(const char *key)
-{
- return hdelete_r(key, &htab);
-}
-
int hdelete_r(const char *key, struct hsearch_data *htab)
{
ENTRY e, *ep;
free(ep->key);
free(ep->data);
- htab->table[idx].used = 0;
+ htab->table[idx].used = -1;
--htab->filled;
* bytes in the string will be '\0'-padded.
*/
-ssize_t hexport(const char sep, char **resp, size_t size)
-{
- return hexport_r(&htab, sep, resp, size);
-}
-
static int cmpkey(const void *p1, const void *p2)
{
ENTRY *e1 = *(ENTRY **) p1;
*/
for (i = 1, n = 0, totlen = 0; i <= htab->size; ++i) {
- if (htab->table[i].used) {
+ if (htab->table[i].used > 0) {
ENTRY *ep = &htab->table[i].entry;
list[n++] = ep;
* '\0' and '\n' have really been tested.
*/
-int himport(const char *env, size_t size, const char sep, int flag)
-{
- return himport_r(&htab, env, size, sep, flag);
-}
-
int himport_r(struct hsearch_data *htab,
const char *env, size_t size, const char sep, int flag)
{