home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1992, Brian Berliner and Jeff Polk
- *
- * You may distribute under the terms of the GNU General Public License as
- * specified in the README file that comes with the CVS 1.3 kit.
- *
- * Polk's hash list manager. So cool.
- */
-
- #include "cvs.h"
-
- #ifndef lint
- static char rcsid[] = "@(#)hash.c 1.14 92/03/31";
- #endif
-
- /* global caches */
- static List *listcache = NULL;
- static Node *nodecache = NULL;
-
- #if __STDC__
- static void freenode_mem (Node * p);
- #else
- static void freenode_mem ();
- #endif /* __STDC__ */
-
- /* hash function */
- static int
- hashp (key)
- char *key;
- {
- register char *p;
- register int n = 0;
-
- for (p = key; *p; p++)
- n += *p;
-
- return (n % HASHSIZE);
- }
-
- /*
- * create a new list (or get an old one from the cache)
- */
- List *
- getlist ()
- {
- int i;
- List *list;
- Node *node;
-
- if (listcache != NULL)
- {
- /* get a list from the cache and clear it */
- list = listcache;
- listcache = listcache->next;
- list->next = (List *) NULL;
- for (i = 0; i < HASHSIZE; i++)
- list->hasharray[i] = (Node *) NULL;
- }
- else
- {
- /* make a new list from scratch */
- list = (List *) xmalloc (sizeof (List));
- bzero ((char *) list, sizeof (List));
- node = getnode ();
- list->list = node;
- node->type = HEADER;
- node->next = node->prev = node;
- }
- return (list);
- }
-
- /*
- * free up a list
- */
- void
- dellist (listp)
- List **listp;
- {
- int i;
- Node *p;
-
- if (*listp == (List *) NULL)
- return;
-
- p = (*listp)->list;
-
- /* free each node in the list (except header) */
- while (p->next != p)
- delnode (p->next);
-
- /* free any list-private data, without freeing the actual header */
- freenode_mem (p);
-
- /* free up the header nodes for hash lists (if any) */
- for (i = 0; i < HASHSIZE; i++)
- {
- if ((p = (*listp)->hasharray[i]) != (Node *) NULL)
- {
- /* put the nodes into the cache */
- p->type = UNKNOWN;
- p->next = nodecache;
- nodecache = p;
- }
- }
-
- /* put it on the cache */
- (*listp)->next = listcache;
- listcache = *listp;
- *listp = (List *) NULL;
- }
-
- /*
- * get a new list node
- */
- Node *
- getnode ()
- {
- Node *p;
-
- if (nodecache != (Node *) NULL)
- {
- /* get one from the cache */
- p = nodecache;
- nodecache = p->next;
- }
- else
- {
- /* make a new one */
- p = (Node *) xmalloc (sizeof (Node));
- }
-
- /* always make it clean */
- bzero ((char *) p, sizeof (Node));
- p->type = UNKNOWN;
-
- return (p);
- }
-
- /*
- * remove a node from it's list (maybe hash list too) and free it
- */
- void
- delnode (p)
- Node *p;
- {
- if (p == (Node *) NULL)
- return;
-
- /* take it out of the list */
- p->next->prev = p->prev;
- p->prev->next = p->next;
-
- /* if it was hashed, remove it from there too */
- if (p->hashnext != (Node *) NULL)
- {
- p->hashnext->hashprev = p->hashprev;
- p->hashprev->hashnext = p->hashnext;
- }
-
- /* free up the storage */
- freenode (p);
- }
-
- /*
- * free up the storage associated with a node
- */
- static void
- freenode_mem (p)
- Node *p;
- {
- if (p->delproc != (void (*) ()) NULL)
- p->delproc (p); /* call the specified delproc */
- else
- {
- if (p->data != NULL) /* otherwise free() it if necessary */
- free (p->data);
- }
- if (p->key != NULL) /* free the key if necessary */
- free (p->key);
-
- /* to be safe, re-initialize these */
- p->key = p->data = (char *) NULL;
- p->delproc = (void (*) ()) NULL;
- }
-
- /*
- * free up the storage associated with a node and recycle it
- */
- void
- freenode (p)
- Node *p;
- {
- /* first free the memory */
- freenode_mem (p);
-
- /* then put it in the cache */
- p->type = UNKNOWN;
- p->next = nodecache;
- nodecache = p;
- }
-
- /*
- * insert item p at end of list "list" (maybe hash it too) if hashing and it
- * already exists, return -1 and don't actually put it in the list
- *
- * return 0 on success
- */
- int
- addnode (list, p)
- List *list;
- Node *p;
- {
- int hashval;
- Node *q;
-
- if (p->key != NULL) /* hash it too? */
- {
- hashval = hashp (p->key);
- if (list->hasharray[hashval] == NULL) /* make a header for list? */
- {
- q = getnode ();
- q->type = HEADER;
- list->hasharray[hashval] = q->hashnext = q->hashprev = q;
- }
-
- /* put it into the hash list if it's not already there */
- for (q = list->hasharray[hashval]->hashnext;
- q != list->hasharray[hashval]; q = q->hashnext)
- {
- if (strcmp (p->key, q->key) == 0)
- return (-1);
- }
- q = list->hasharray[hashval];
- p->hashprev = q->hashprev;
- p->hashnext = q;
- p->hashprev->hashnext = p;
- q->hashprev = p;
- }
-
- /* put it into the regular list */
- p->prev = list->list->prev;
- p->next = list->list;
- list->list->prev->next = p;
- list->list->prev = p;
-
- return (0);
- }
-
- /*
- * look up an entry in hash list table
- */
- Node *
- findnode (list, key)
- List *list;
- char *key;
- {
- Node *head, *p;
-
- if (list == (List *) NULL)
- return ((Node *) NULL);
-
- head = list->hasharray[hashp (key)];
- if (head == (Node *) NULL)
- return ((Node *) NULL);
-
- for (p = head->hashnext; p != head; p = p->hashnext)
- if (strcmp (p->key, key) == 0)
- return (p);
- return ((Node *) NULL);
- }
-
- /*
- * walk a list with a specific proc
- */
- int
- walklist (list, proc)
- List *list;
- int (*proc) ();
- {
- Node *head, *p;
- int err = 0;
-
- if (list == NULL)
- return (0);
-
- head = list->list;
- for (p = head->next; p != head; p = p->next)
- err += proc (p);
- return (err);
- }
-
- /*
- * sort the elements of a list (in place)
- */
- void
- sortlist (list, comp)
- List *list;
- int (*comp) ();
- {
- Node *head, *remain, *p, *q;
-
- /* save the old first element of the list */
- head = list->list;
- remain = head->next;
-
- /* make the header node into a null list of it's own */
- head->next = head->prev = head;
-
- /* while there are nodes remaining, do insert sort */
- while (remain != head)
- {
- /* take one from the list */
- p = remain;
- remain = remain->next;
-
- /* traverse the sorted list looking for the place to insert it */
- for (q = head->next; q != head; q = q->next)
- {
- if (comp (p, q) < 0)
- {
- /* p comes before q */
- p->next = q;
- p->prev = q->prev;
- p->prev->next = p;
- q->prev = p;
- break;
- }
- }
- if (q == head)
- {
- /* it belongs at the end of the list */
- p->next = head;
- p->prev = head->prev;
- p->prev->next = p;
- head->prev = p;
- }
- }
- }
-