/*
 * $Header: /cvsroot/csrc/continuity/mecha/hsh_dep.c,v 1.7 2004/01/23
 * 15:38:14 aleigh Exp $
 */

/*
 * Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved
 * 
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright
 * notice above does not evidence any actual or intended publication of such
 * source code.
 * 
 * Use, disclosure, copying, distribution, or transmission of this code without
 * express permission is prohibited.
 */

/*
 * TA/hashlist general purpose hasing algorithm system. Alex Leigh,
 * 1994,1997,1999, 2000 $Id: hsh_dep.c,v 1.9 2004/03/18 15:04:15 aleigh Exp $
 */

/*
 * hsh provides a general purpose, efficient data storage and retrieval
 * system. The alogrithm can store an arbitrary list of sequential
 * name/keyvalue pairs, each list being keyed by a character string.
 * 
 */

#include "../include/csys.h"

struct hshSentry {
    char *name;
    char *value;
    struct hshSentry *next;
};
typedef struct hshSentry hshTentry;

struct hshSnode {
    struct hshSentry *entry;
    char *name;
    struct hshSnode *next;
};
typedef struct hshSnode hshTnode;

struct hshShash {
    struct hshSnode *t;
};
typedef struct hshShash hshThash;

struct hshSlist {
    struct hshSnode *nodes[65536];
    int ref;
};
typedef struct hshSlist hshTlist;

#define _HSH_DEP_C
#include "../include/mecha.h"

/*****************
 * Tradidtional hash list implementation DEPRECATED
 * This interface has worked well for a long time, but was originally
 * designed to do something else, as evidenced by all the now
 * reundant structures. Use of the void interface is therefore
 * encouraged.
 *****************/

hshTnode *hshFlist_node_find(hshTlist * list, char *name)
{
    return list->nodes[hshFhash(name)];
}

/*
 * Search a node for a given entry and return a pointer to it.
 */
hshTentry *hshFnode_find_entry(hshTnode * node, char *str)
{
    hshTentry *e;

    if (node->entry == NULL)
        return NULL;

    e = node->entry;

    while (1) {
        if (strcmp(str, e->name) == 0)
            return e;
        if (e->next == NULL)
            break;
        e = e->next;
    }
    return NULL;
}

hshTentry *hshFlist_find_entry(hshTlist * list, char *nname, char *ename)
{
    hshTnode *n;
    hshTentry *e;

    n = (hshTnode *) hshFlist_node_find(list, nname);


    if (n == NULL)
        return NULL;

    e = (hshTentry *) hshFnode_find_entry(n, ename);

    return e;

}

char *hshFnode_find_value(hshTnode * node, char *str)
{
    hshTentry *e;


    e = hshFnode_find_entry(node, str);
    if (e == NULL)
        return NULL;
    return e->value;
}

/*
 * aleigh- Free a hashlist entry structure. The structure should already be
 * unreferenced, or you'll break any pre-existing references to it.
 */
void hshFentry_free(hshTentry * entry)
{
    if (entry->name != NULL)
        free(entry->name);
    if (entry->value != NULL)
        free(entry->value);
    free(entry);
}

/*
 * aleigh- Free a node, and any entries that may be associated with it. You
 * better be sure all the references are gone to the node.
 */
void hshFnode_free(hshTnode * node)
{
    hshTentry *p, *np = NULL;

    p = node->entry;

    while (1) {
        if (p == NULL)
            break;
        np = p->next;
        hshFentry_free(p);
        p = np;
    }

    if (node->entry != NULL)
        hshFentry_free(node->entry);
    free(node);
}

/*
 * aleigh- Create a hash node out of system memory via malloc(). The node is
 * the root unit of the hashlist.
 */
hshTnode *hshFnode_create(char *name)
{
    hshTnode *n;

    n = (hshTnode *) malloc(sizeof(hshTnode));
    /* memFclear(n, sizeof(hshTnode)); */
    memFclear(n, sizeof(hshTnode));

    n->name = (char *) malloc(strlen(name) + 1);
    memFclear(n->name, strlen(name) + 1);
    memFcopy(name, n->name, strlen(name));

    return n;
}

void hshFnode_entry_add(hshTnode * n, hshTentry * e)
{
    e->next = n->entry;
    n->entry = e;
}

hshTnode *hshFnode_entry_alloc(void)
{
    hshTnode *n;

    n = (hshTnode *) malloc(sizeof(hshTnode));
    memFclear(n, sizeof(hshTnode));

    return n;
}

hshTentry *hshFnode_entry_insert(hshTnode * node, char *n, char *v)
{
    hshTentry *e;

    e = (hshTentry *) malloc(sizeof(hshTentry));
    memFclear(e, sizeof(hshTentry));

    e->name = (char *) malloc(strlen(n) + 1);
    memFclear(e->name, strlen(n) + 1);
    e->value = (char *) malloc(strlen(v) + 1);
    memFclear(e->value, strlen(v) + 1);

    memFcopy(n, e->name, strlen(n));
    memFcopy(v, e->value, strlen(v));

    hshFnode_entry_add(node, e);

    return e;
}

hshTentry *hshFlist_entry_insert(hshTlist * list, char *l, char *n,
                                 char *v)
{
    hshTnode *node;
    hshTentry *entry;

    node = hshFlist_node_find(list, l);
    if (node == NULL) {
        node = hshFnode_create(l);
        hshFlist_node_add(list, node);
    }
    entry = hshFnode_entry_insert(node, n, v);

    return entry;
}

hshTlist *hshFlist_create(void)
{
    hshTlist *p;

    p = (hshTlist *) malloc(sizeof(hshTlist));
    memFclear(p, sizeof(hshTlist));
    /* memFclear(p, sizeof(hshTlist)); */

    return p;
}

void hshFlist_node_add(hshTlist * list, hshTnode * node)
{
    unsigned int hash;

    hash = hshFhash(node->name);

    if (list->nodes[hash] == NULL) {
        list->nodes[hash] = node;
    } else {
        node->next = list->nodes[hash];
        list->nodes[hash] = node;
    }
}

void hashFlist_dump(hshTlist * list, unsigned int len)
{
    struct hshSnode *n;
    size_t i;

    for (i = 0; i < len; i++) {
        n = list->nodes[i];
        if (n->name == NULL) {
            printf("node %d - (NULL)\n", i);
        } else {
            printf("node %d - %s\n", i, n->name);
        }
    }
}
