xref: /dflybsd-src/contrib/cvs-1.12/src/hash.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1*86d7f5d3SJohn Marino /*
2*86d7f5d3SJohn Marino  * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
3*86d7f5d3SJohn Marino  *
4*86d7f5d3SJohn Marino  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5*86d7f5d3SJohn Marino  *                                  and others.
6*86d7f5d3SJohn Marino  *
7*86d7f5d3SJohn Marino  * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8*86d7f5d3SJohn Marino  *
9*86d7f5d3SJohn Marino  * You may distribute under the terms of the GNU General Public License as
10*86d7f5d3SJohn Marino  * specified in the README file that comes with the CVS source distribution.
11*86d7f5d3SJohn Marino  *
12*86d7f5d3SJohn Marino  * Polk's hash list manager.  So cool.
13*86d7f5d3SJohn Marino  */
14*86d7f5d3SJohn Marino 
15*86d7f5d3SJohn Marino #include "cvs.h"
16*86d7f5d3SJohn Marino 
17*86d7f5d3SJohn Marino /* Global caches.  The idea is that we maintain a linked list of "free"d
18*86d7f5d3SJohn Marino    nodes or lists, and get new items from there.  It has been suggested
19*86d7f5d3SJohn Marino    to use an obstack instead, but off the top of my head, I'm not sure
20*86d7f5d3SJohn Marino    that would gain enough to be worth worrying about.  */
21*86d7f5d3SJohn Marino static List *listcache = NULL;
22*86d7f5d3SJohn Marino static Node *nodecache = NULL;
23*86d7f5d3SJohn Marino 
24*86d7f5d3SJohn Marino static void freenode_mem (Node * p);
25*86d7f5d3SJohn Marino 
26*86d7f5d3SJohn Marino /* hash function */
27*86d7f5d3SJohn Marino static int
hashp(const char * key)28*86d7f5d3SJohn Marino hashp (const char *key)
29*86d7f5d3SJohn Marino {
30*86d7f5d3SJohn Marino     unsigned int h = 0;
31*86d7f5d3SJohn Marino     unsigned int g;
32*86d7f5d3SJohn Marino 
33*86d7f5d3SJohn Marino     assert(key != NULL);
34*86d7f5d3SJohn Marino 
35*86d7f5d3SJohn Marino     while (*key != 0)
36*86d7f5d3SJohn Marino     {
37*86d7f5d3SJohn Marino 	unsigned int c = *key++;
38*86d7f5d3SJohn Marino 	/* The FOLD_FN_CHAR is so that findnode_fn works.  */
39*86d7f5d3SJohn Marino 	h = (h << 4) + FOLD_FN_CHAR (c);
40*86d7f5d3SJohn Marino 	if ((g = h & 0xf0000000) != 0)
41*86d7f5d3SJohn Marino 	    h = (h ^ (g >> 24)) ^ g;
42*86d7f5d3SJohn Marino     }
43*86d7f5d3SJohn Marino 
44*86d7f5d3SJohn Marino     return h % HASHSIZE;
45*86d7f5d3SJohn Marino }
46*86d7f5d3SJohn Marino 
47*86d7f5d3SJohn Marino 
48*86d7f5d3SJohn Marino 
49*86d7f5d3SJohn Marino /*
50*86d7f5d3SJohn Marino  * create a new list (or get an old one from the cache)
51*86d7f5d3SJohn Marino  */
52*86d7f5d3SJohn Marino List *
getlist(void)53*86d7f5d3SJohn Marino getlist (void)
54*86d7f5d3SJohn Marino {
55*86d7f5d3SJohn Marino     int i;
56*86d7f5d3SJohn Marino     List *list;
57*86d7f5d3SJohn Marino     Node *node;
58*86d7f5d3SJohn Marino 
59*86d7f5d3SJohn Marino     if (listcache != NULL)
60*86d7f5d3SJohn Marino     {
61*86d7f5d3SJohn Marino 	/* get a list from the cache and clear it */
62*86d7f5d3SJohn Marino 	list = listcache;
63*86d7f5d3SJohn Marino 	listcache = listcache->next;
64*86d7f5d3SJohn Marino 	list->next = NULL;
65*86d7f5d3SJohn Marino 	for (i = 0; i < HASHSIZE; i++)
66*86d7f5d3SJohn Marino 	    list->hasharray[i] = NULL;
67*86d7f5d3SJohn Marino     }
68*86d7f5d3SJohn Marino     else
69*86d7f5d3SJohn Marino     {
70*86d7f5d3SJohn Marino 	/* make a new list from scratch */
71*86d7f5d3SJohn Marino 	list = xmalloc (sizeof (List));
72*86d7f5d3SJohn Marino 	memset (list, 0, sizeof (List));
73*86d7f5d3SJohn Marino 	node = getnode ();
74*86d7f5d3SJohn Marino 	list->list = node;
75*86d7f5d3SJohn Marino 	node->type = HEADER;
76*86d7f5d3SJohn Marino 	node->next = node->prev = node;
77*86d7f5d3SJohn Marino     }
78*86d7f5d3SJohn Marino     return list;
79*86d7f5d3SJohn Marino }
80*86d7f5d3SJohn Marino 
81*86d7f5d3SJohn Marino 
82*86d7f5d3SJohn Marino 
83*86d7f5d3SJohn Marino /*
84*86d7f5d3SJohn Marino  * Free up a list.  For accessing globals which might be accessed via interrupt
85*86d7f5d3SJohn Marino  * handlers, it can be assumed that the first action of this function will be
86*86d7f5d3SJohn Marino  * to set the *listp to NULL.
87*86d7f5d3SJohn Marino  */
88*86d7f5d3SJohn Marino void
dellist(List ** listp)89*86d7f5d3SJohn Marino dellist (List **listp)
90*86d7f5d3SJohn Marino {
91*86d7f5d3SJohn Marino     int i;
92*86d7f5d3SJohn Marino     Node *p;
93*86d7f5d3SJohn Marino     List *tmp;
94*86d7f5d3SJohn Marino 
95*86d7f5d3SJohn Marino     if (*listp == NULL)
96*86d7f5d3SJohn Marino 	return;
97*86d7f5d3SJohn Marino 
98*86d7f5d3SJohn Marino     tmp = *listp;
99*86d7f5d3SJohn Marino     *listp = NULL;
100*86d7f5d3SJohn Marino 
101*86d7f5d3SJohn Marino     p = tmp->list;
102*86d7f5d3SJohn Marino 
103*86d7f5d3SJohn Marino     /* free each node in the list (except header) */
104*86d7f5d3SJohn Marino     while (p->next != p)
105*86d7f5d3SJohn Marino 	delnode (p->next);
106*86d7f5d3SJohn Marino 
107*86d7f5d3SJohn Marino     /* free any list-private data, without freeing the actual header */
108*86d7f5d3SJohn Marino     freenode_mem (p);
109*86d7f5d3SJohn Marino 
110*86d7f5d3SJohn Marino     /* free up the header nodes for hash lists (if any) */
111*86d7f5d3SJohn Marino     for (i = 0; i < HASHSIZE; i++)
112*86d7f5d3SJohn Marino     {
113*86d7f5d3SJohn Marino 	if ((p = tmp->hasharray[i]) != NULL)
114*86d7f5d3SJohn Marino 	{
115*86d7f5d3SJohn Marino 	    /* put the nodes into the cache */
116*86d7f5d3SJohn Marino #ifndef NOCACHE
117*86d7f5d3SJohn Marino 	    p->type = NT_UNKNOWN;
118*86d7f5d3SJohn Marino 	    p->next = nodecache;
119*86d7f5d3SJohn Marino 	    nodecache = p;
120*86d7f5d3SJohn Marino #else
121*86d7f5d3SJohn Marino 	    /* If NOCACHE is defined we turn off the cache.  This can make
122*86d7f5d3SJohn Marino 	       it easier to tools to determine where items were allocated
123*86d7f5d3SJohn Marino 	       and freed, for tracking down memory leaks and the like.  */
124*86d7f5d3SJohn Marino 	    free (p);
125*86d7f5d3SJohn Marino #endif
126*86d7f5d3SJohn Marino 	}
127*86d7f5d3SJohn Marino     }
128*86d7f5d3SJohn Marino 
129*86d7f5d3SJohn Marino     /* put it on the cache */
130*86d7f5d3SJohn Marino #ifndef NOCACHE
131*86d7f5d3SJohn Marino     tmp->next = listcache;
132*86d7f5d3SJohn Marino     listcache = tmp;
133*86d7f5d3SJohn Marino #else
134*86d7f5d3SJohn Marino     free (tmp->list);
135*86d7f5d3SJohn Marino     free (tmp);
136*86d7f5d3SJohn Marino #endif
137*86d7f5d3SJohn Marino }
138*86d7f5d3SJohn Marino 
139*86d7f5d3SJohn Marino 
140*86d7f5d3SJohn Marino 
141*86d7f5d3SJohn Marino /*
142*86d7f5d3SJohn Marino  * remove a node from it's list (maybe hash list too)
143*86d7f5d3SJohn Marino  */
144*86d7f5d3SJohn Marino void
removenode(Node * p)145*86d7f5d3SJohn Marino removenode (Node *p)
146*86d7f5d3SJohn Marino {
147*86d7f5d3SJohn Marino     if (!p) return;
148*86d7f5d3SJohn Marino 
149*86d7f5d3SJohn Marino     /* take it out of the list */
150*86d7f5d3SJohn Marino     p->next->prev = p->prev;
151*86d7f5d3SJohn Marino     p->prev->next = p->next;
152*86d7f5d3SJohn Marino 
153*86d7f5d3SJohn Marino     /* if it was hashed, remove it from there too */
154*86d7f5d3SJohn Marino     if (p->hashnext)
155*86d7f5d3SJohn Marino     {
156*86d7f5d3SJohn Marino 	p->hashnext->hashprev = p->hashprev;
157*86d7f5d3SJohn Marino 	p->hashprev->hashnext = p->hashnext;
158*86d7f5d3SJohn Marino     }
159*86d7f5d3SJohn Marino }
160*86d7f5d3SJohn Marino 
161*86d7f5d3SJohn Marino 
162*86d7f5d3SJohn Marino 
163*86d7f5d3SJohn Marino void
mergelists(List * dest,List ** src)164*86d7f5d3SJohn Marino mergelists (List *dest, List **src)
165*86d7f5d3SJohn Marino {
166*86d7f5d3SJohn Marino     Node *head, *p, *n;
167*86d7f5d3SJohn Marino 
168*86d7f5d3SJohn Marino     head = (*src)->list;
169*86d7f5d3SJohn Marino     for (p = head->next; p != head; p = n)
170*86d7f5d3SJohn Marino     {
171*86d7f5d3SJohn Marino 	n = p->next;
172*86d7f5d3SJohn Marino 	removenode (p);
173*86d7f5d3SJohn Marino 	addnode (dest, p);
174*86d7f5d3SJohn Marino     }
175*86d7f5d3SJohn Marino     dellist (src);
176*86d7f5d3SJohn Marino }
177*86d7f5d3SJohn Marino 
178*86d7f5d3SJohn Marino 
179*86d7f5d3SJohn Marino 
180*86d7f5d3SJohn Marino /*
181*86d7f5d3SJohn Marino  * get a new list node
182*86d7f5d3SJohn Marino  */
183*86d7f5d3SJohn Marino Node *
getnode(void)184*86d7f5d3SJohn Marino getnode (void)
185*86d7f5d3SJohn Marino {
186*86d7f5d3SJohn Marino     Node *p;
187*86d7f5d3SJohn Marino 
188*86d7f5d3SJohn Marino     if (nodecache != NULL)
189*86d7f5d3SJohn Marino     {
190*86d7f5d3SJohn Marino 	/* get one from the cache */
191*86d7f5d3SJohn Marino 	p = nodecache;
192*86d7f5d3SJohn Marino 	nodecache = p->next;
193*86d7f5d3SJohn Marino     }
194*86d7f5d3SJohn Marino     else
195*86d7f5d3SJohn Marino     {
196*86d7f5d3SJohn Marino 	/* make a new one */
197*86d7f5d3SJohn Marino 	p = xmalloc (sizeof (Node));
198*86d7f5d3SJohn Marino     }
199*86d7f5d3SJohn Marino 
200*86d7f5d3SJohn Marino     /* always make it clean */
201*86d7f5d3SJohn Marino     memset (p, 0, sizeof (Node));
202*86d7f5d3SJohn Marino     p->type = NT_UNKNOWN;
203*86d7f5d3SJohn Marino 
204*86d7f5d3SJohn Marino     return p;
205*86d7f5d3SJohn Marino }
206*86d7f5d3SJohn Marino 
207*86d7f5d3SJohn Marino 
208*86d7f5d3SJohn Marino 
209*86d7f5d3SJohn Marino /*
210*86d7f5d3SJohn Marino  * remove a node from it's list (maybe hash list too) and free it
211*86d7f5d3SJohn Marino  */
212*86d7f5d3SJohn Marino void
delnode(Node * p)213*86d7f5d3SJohn Marino delnode (Node *p)
214*86d7f5d3SJohn Marino {
215*86d7f5d3SJohn Marino     if (!p) return;
216*86d7f5d3SJohn Marino     /* remove it */
217*86d7f5d3SJohn Marino     removenode (p);
218*86d7f5d3SJohn Marino     /* free up the storage */
219*86d7f5d3SJohn Marino     freenode (p);
220*86d7f5d3SJohn Marino }
221*86d7f5d3SJohn Marino 
222*86d7f5d3SJohn Marino 
223*86d7f5d3SJohn Marino 
224*86d7f5d3SJohn Marino /*
225*86d7f5d3SJohn Marino  * free up the storage associated with a node
226*86d7f5d3SJohn Marino  */
227*86d7f5d3SJohn Marino static void
freenode_mem(Node * p)228*86d7f5d3SJohn Marino freenode_mem (Node *p)
229*86d7f5d3SJohn Marino {
230*86d7f5d3SJohn Marino     if (p->delproc != NULL)
231*86d7f5d3SJohn Marino 	p->delproc (p);			/* call the specified delproc */
232*86d7f5d3SJohn Marino     else
233*86d7f5d3SJohn Marino     {
234*86d7f5d3SJohn Marino 	if (p->data != NULL)		/* otherwise free() it if necessary */
235*86d7f5d3SJohn Marino 	    free (p->data);
236*86d7f5d3SJohn Marino     }
237*86d7f5d3SJohn Marino     if (p->key != NULL)			/* free the key if necessary */
238*86d7f5d3SJohn Marino 	free (p->key);
239*86d7f5d3SJohn Marino 
240*86d7f5d3SJohn Marino     /* to be safe, re-initialize these */
241*86d7f5d3SJohn Marino     p->key = p->data = NULL;
242*86d7f5d3SJohn Marino     p->delproc = NULL;
243*86d7f5d3SJohn Marino }
244*86d7f5d3SJohn Marino 
245*86d7f5d3SJohn Marino 
246*86d7f5d3SJohn Marino 
247*86d7f5d3SJohn Marino /*
248*86d7f5d3SJohn Marino  * free up the storage associated with a node and recycle it
249*86d7f5d3SJohn Marino  */
250*86d7f5d3SJohn Marino void
freenode(Node * p)251*86d7f5d3SJohn Marino freenode (Node *p)
252*86d7f5d3SJohn Marino {
253*86d7f5d3SJohn Marino     /* first free the memory */
254*86d7f5d3SJohn Marino     freenode_mem (p);
255*86d7f5d3SJohn Marino 
256*86d7f5d3SJohn Marino     /* then put it in the cache */
257*86d7f5d3SJohn Marino #ifndef NOCACHE
258*86d7f5d3SJohn Marino     p->type = NT_UNKNOWN;
259*86d7f5d3SJohn Marino     p->next = nodecache;
260*86d7f5d3SJohn Marino     nodecache = p;
261*86d7f5d3SJohn Marino #else
262*86d7f5d3SJohn Marino     free (p);
263*86d7f5d3SJohn Marino #endif
264*86d7f5d3SJohn Marino }
265*86d7f5d3SJohn Marino 
266*86d7f5d3SJohn Marino 
267*86d7f5d3SJohn Marino 
268*86d7f5d3SJohn Marino /*
269*86d7f5d3SJohn Marino  * Link item P into list LIST before item MARKER.  If P->KEY is non-NULL and
270*86d7f5d3SJohn Marino  * that key is already in the hash table, return -1 without modifying any
271*86d7f5d3SJohn Marino  * parameter.
272*86d7f5d3SJohn Marino  *
273*86d7f5d3SJohn Marino  * return 0 on success
274*86d7f5d3SJohn Marino  */
275*86d7f5d3SJohn Marino int
insert_before(List * list,Node * marker,Node * p)276*86d7f5d3SJohn Marino insert_before (List *list, Node *marker, Node *p)
277*86d7f5d3SJohn Marino {
278*86d7f5d3SJohn Marino     if (p->key != NULL)			/* hash it too? */
279*86d7f5d3SJohn Marino     {
280*86d7f5d3SJohn Marino 	int hashval;
281*86d7f5d3SJohn Marino 	Node *q;
282*86d7f5d3SJohn Marino 
283*86d7f5d3SJohn Marino 	hashval = hashp (p->key);
284*86d7f5d3SJohn Marino 	if (list->hasharray[hashval] == NULL)	/* make a header for list? */
285*86d7f5d3SJohn Marino 	{
286*86d7f5d3SJohn Marino 	    q = getnode ();
287*86d7f5d3SJohn Marino 	    q->type = HEADER;
288*86d7f5d3SJohn Marino 	    list->hasharray[hashval] = q->hashnext = q->hashprev = q;
289*86d7f5d3SJohn Marino 	}
290*86d7f5d3SJohn Marino 
291*86d7f5d3SJohn Marino 	/* put it into the hash list if it's not already there */
292*86d7f5d3SJohn Marino 	for (q = list->hasharray[hashval]->hashnext;
293*86d7f5d3SJohn Marino 	     q != list->hasharray[hashval]; q = q->hashnext)
294*86d7f5d3SJohn Marino 	{
295*86d7f5d3SJohn Marino 	    if (strcmp (p->key, q->key) == 0)
296*86d7f5d3SJohn Marino 		return -1;
297*86d7f5d3SJohn Marino 	}
298*86d7f5d3SJohn Marino 	q = list->hasharray[hashval];
299*86d7f5d3SJohn Marino 	p->hashprev = q->hashprev;
300*86d7f5d3SJohn Marino 	p->hashnext = q;
301*86d7f5d3SJohn Marino 	p->hashprev->hashnext = p;
302*86d7f5d3SJohn Marino 	q->hashprev = p;
303*86d7f5d3SJohn Marino     }
304*86d7f5d3SJohn Marino 
305*86d7f5d3SJohn Marino     p->next = marker;
306*86d7f5d3SJohn Marino     p->prev = marker->prev;
307*86d7f5d3SJohn Marino     marker->prev->next = p;
308*86d7f5d3SJohn Marino     marker->prev = p;
309*86d7f5d3SJohn Marino 
310*86d7f5d3SJohn Marino     return 0;
311*86d7f5d3SJohn Marino }
312*86d7f5d3SJohn Marino 
313*86d7f5d3SJohn Marino 
314*86d7f5d3SJohn Marino 
315*86d7f5d3SJohn Marino /*
316*86d7f5d3SJohn Marino  * insert item p at end of list "list" (maybe hash it too) if hashing and it
317*86d7f5d3SJohn Marino  * already exists, return -1 and don't actually put it in the list
318*86d7f5d3SJohn Marino  *
319*86d7f5d3SJohn Marino  * return 0 on success
320*86d7f5d3SJohn Marino  */
321*86d7f5d3SJohn Marino int
addnode(List * list,Node * p)322*86d7f5d3SJohn Marino addnode (List *list, Node *p)
323*86d7f5d3SJohn Marino {
324*86d7f5d3SJohn Marino   return insert_before (list, list->list, p);
325*86d7f5d3SJohn Marino }
326*86d7f5d3SJohn Marino 
327*86d7f5d3SJohn Marino 
328*86d7f5d3SJohn Marino 
329*86d7f5d3SJohn Marino /*
330*86d7f5d3SJohn Marino  * Like addnode, but insert p at the front of `list'.  This bogosity is
331*86d7f5d3SJohn Marino  * necessary to preserve last-to-first output order for some RCS functions.
332*86d7f5d3SJohn Marino  */
333*86d7f5d3SJohn Marino int
addnode_at_front(List * list,Node * p)334*86d7f5d3SJohn Marino addnode_at_front (List *list, Node *p)
335*86d7f5d3SJohn Marino {
336*86d7f5d3SJohn Marino   return insert_before (list, list->list->next, p);
337*86d7f5d3SJohn Marino }
338*86d7f5d3SJohn Marino 
339*86d7f5d3SJohn Marino 
340*86d7f5d3SJohn Marino 
341*86d7f5d3SJohn Marino /* Look up an entry in hash list table and return a pointer to the
342*86d7f5d3SJohn Marino  * node.  Return NULL if not found or if list is NULL.  Abort with a fatal
343*86d7f5d3SJohn Marino  * error for errors.
344*86d7f5d3SJohn Marino  */
345*86d7f5d3SJohn Marino Node *
findnode(List * list,const char * key)346*86d7f5d3SJohn Marino findnode (List *list, const char *key)
347*86d7f5d3SJohn Marino {
348*86d7f5d3SJohn Marino     Node *head, *p;
349*86d7f5d3SJohn Marino 
350*86d7f5d3SJohn Marino     if ((list == NULL))
351*86d7f5d3SJohn Marino 	return NULL;
352*86d7f5d3SJohn Marino 
353*86d7f5d3SJohn Marino     assert (key != NULL);
354*86d7f5d3SJohn Marino 
355*86d7f5d3SJohn Marino     head = list->hasharray[hashp (key)];
356*86d7f5d3SJohn Marino     if (head == NULL)
357*86d7f5d3SJohn Marino 	/* Not found.  */
358*86d7f5d3SJohn Marino 	return NULL;
359*86d7f5d3SJohn Marino 
360*86d7f5d3SJohn Marino     for (p = head->hashnext; p != head; p = p->hashnext)
361*86d7f5d3SJohn Marino 	if (strcmp (p->key, key) == 0)
362*86d7f5d3SJohn Marino 	    return p;
363*86d7f5d3SJohn Marino     return NULL;
364*86d7f5d3SJohn Marino }
365*86d7f5d3SJohn Marino 
366*86d7f5d3SJohn Marino 
367*86d7f5d3SJohn Marino 
368*86d7f5d3SJohn Marino /*
369*86d7f5d3SJohn Marino  * Like findnode, but for a filename.
370*86d7f5d3SJohn Marino  */
371*86d7f5d3SJohn Marino Node *
findnode_fn(List * list,const char * key)372*86d7f5d3SJohn Marino findnode_fn (List *list, const char *key)
373*86d7f5d3SJohn Marino {
374*86d7f5d3SJohn Marino     Node *head, *p;
375*86d7f5d3SJohn Marino 
376*86d7f5d3SJohn Marino     /* This probably should be "assert (list != NULL)" (or if not we
377*86d7f5d3SJohn Marino        should document the current behavior), but only if we check all
378*86d7f5d3SJohn Marino        the callers to see if any are relying on this behavior.  */
379*86d7f5d3SJohn Marino     if (list == NULL)
380*86d7f5d3SJohn Marino 	return NULL;
381*86d7f5d3SJohn Marino 
382*86d7f5d3SJohn Marino     assert (key != NULL);
383*86d7f5d3SJohn Marino 
384*86d7f5d3SJohn Marino     head = list->hasharray[hashp (key)];
385*86d7f5d3SJohn Marino     if (head == NULL)
386*86d7f5d3SJohn Marino 	return NULL;
387*86d7f5d3SJohn Marino 
388*86d7f5d3SJohn Marino     for (p = head->hashnext; p != head; p = p->hashnext)
389*86d7f5d3SJohn Marino 	if (fncmp (p->key, key) == 0)
390*86d7f5d3SJohn Marino 	    return p;
391*86d7f5d3SJohn Marino     return NULL;
392*86d7f5d3SJohn Marino }
393*86d7f5d3SJohn Marino 
394*86d7f5d3SJohn Marino 
395*86d7f5d3SJohn Marino 
396*86d7f5d3SJohn Marino /*
397*86d7f5d3SJohn Marino  * walk a list with a specific proc
398*86d7f5d3SJohn Marino  */
399*86d7f5d3SJohn Marino int
walklist(List * list,int (* proc)(Node *,void *),void * closure)400*86d7f5d3SJohn Marino walklist (List *list, int (*proc) (Node *, void *), void *closure)
401*86d7f5d3SJohn Marino {
402*86d7f5d3SJohn Marino     Node *head, *p;
403*86d7f5d3SJohn Marino     int err = 0;
404*86d7f5d3SJohn Marino 
405*86d7f5d3SJohn Marino #ifdef HAVE_PRINTF_PTR
406*86d7f5d3SJohn Marino     TRACE (TRACE_FLOW, "walklist ( list=%p, proc=%p, closure=%p )",
407*86d7f5d3SJohn Marino 	   (void *)list, (void *)proc, (void *)closure);
408*86d7f5d3SJohn Marino #else
409*86d7f5d3SJohn Marino     TRACE (TRACE_FLOW, "walklist ( list=%lx, proc=%lx, closure=%lx )",
410*86d7f5d3SJohn Marino 	   (unsigned long)list,(unsigned long) proc,
411*86d7f5d3SJohn Marino 	   (unsigned long)closure);
412*86d7f5d3SJohn Marino #endif
413*86d7f5d3SJohn Marino 
414*86d7f5d3SJohn Marino     if (list == NULL)
415*86d7f5d3SJohn Marino 	return 0;
416*86d7f5d3SJohn Marino 
417*86d7f5d3SJohn Marino     head = list->list;
418*86d7f5d3SJohn Marino     for (p = head->next; p != head; p = p->next)
419*86d7f5d3SJohn Marino 	err += proc (p, closure);
420*86d7f5d3SJohn Marino     return err;
421*86d7f5d3SJohn Marino }
422*86d7f5d3SJohn Marino 
423*86d7f5d3SJohn Marino 
424*86d7f5d3SJohn Marino 
425*86d7f5d3SJohn Marino int
list_isempty(List * list)426*86d7f5d3SJohn Marino list_isempty (List *list)
427*86d7f5d3SJohn Marino {
428*86d7f5d3SJohn Marino     return list == NULL || list->list->next == list->list;
429*86d7f5d3SJohn Marino }
430*86d7f5d3SJohn Marino 
431*86d7f5d3SJohn Marino 
432*86d7f5d3SJohn Marino 
433*86d7f5d3SJohn Marino static int (*client_comp) (const Node *, const Node *);
434*86d7f5d3SJohn Marino 
435*86d7f5d3SJohn Marino static int
qsort_comp(const void * elem1,const void * elem2)436*86d7f5d3SJohn Marino qsort_comp (const void *elem1, const void *elem2)
437*86d7f5d3SJohn Marino {
438*86d7f5d3SJohn Marino     Node **node1 = (Node **) elem1;
439*86d7f5d3SJohn Marino     Node **node2 = (Node **) elem2;
440*86d7f5d3SJohn Marino     return client_comp (*node1, *node2);
441*86d7f5d3SJohn Marino }
442*86d7f5d3SJohn Marino 
443*86d7f5d3SJohn Marino 
444*86d7f5d3SJohn Marino 
445*86d7f5d3SJohn Marino /*
446*86d7f5d3SJohn Marino  * sort the elements of a list (in place)
447*86d7f5d3SJohn Marino  */
448*86d7f5d3SJohn Marino void
sortlist(List * list,int (* comp)(const Node *,const Node *))449*86d7f5d3SJohn Marino sortlist (List *list, int (*comp) (const Node *, const Node *))
450*86d7f5d3SJohn Marino {
451*86d7f5d3SJohn Marino     Node *head, *remain, *p, **array;
452*86d7f5d3SJohn Marino     int i, n;
453*86d7f5d3SJohn Marino 
454*86d7f5d3SJohn Marino     if (list == NULL)
455*86d7f5d3SJohn Marino 	return;
456*86d7f5d3SJohn Marino 
457*86d7f5d3SJohn Marino     /* save the old first element of the list */
458*86d7f5d3SJohn Marino     head = list->list;
459*86d7f5d3SJohn Marino     remain = head->next;
460*86d7f5d3SJohn Marino 
461*86d7f5d3SJohn Marino     /* count the number of nodes in the list */
462*86d7f5d3SJohn Marino     n = 0;
463*86d7f5d3SJohn Marino     for (p = remain; p != head; p = p->next)
464*86d7f5d3SJohn Marino 	n++;
465*86d7f5d3SJohn Marino 
466*86d7f5d3SJohn Marino     /* allocate an array of nodes and populate it */
467*86d7f5d3SJohn Marino     array = xnmalloc (n, sizeof (Node *));
468*86d7f5d3SJohn Marino     i = 0;
469*86d7f5d3SJohn Marino     for (p = remain; p != head; p = p->next)
470*86d7f5d3SJohn Marino 	array[i++] = p;
471*86d7f5d3SJohn Marino 
472*86d7f5d3SJohn Marino     /* sort the array of nodes */
473*86d7f5d3SJohn Marino     client_comp = comp;
474*86d7f5d3SJohn Marino     qsort (array, n, sizeof(Node *), qsort_comp);
475*86d7f5d3SJohn Marino 
476*86d7f5d3SJohn Marino     /* rebuild the list from beginning to end */
477*86d7f5d3SJohn Marino     head->next = head->prev = head;
478*86d7f5d3SJohn Marino     for (i = 0; i < n; i++)
479*86d7f5d3SJohn Marino     {
480*86d7f5d3SJohn Marino 	p = array[i];
481*86d7f5d3SJohn Marino 	p->next = head;
482*86d7f5d3SJohn Marino 	p->prev = head->prev;
483*86d7f5d3SJohn Marino 	p->prev->next = p;
484*86d7f5d3SJohn Marino 	head->prev = p;
485*86d7f5d3SJohn Marino     }
486*86d7f5d3SJohn Marino 
487*86d7f5d3SJohn Marino     /* release the array of nodes */
488*86d7f5d3SJohn Marino     free (array);
489*86d7f5d3SJohn Marino }
490*86d7f5d3SJohn Marino 
491*86d7f5d3SJohn Marino 
492*86d7f5d3SJohn Marino 
493*86d7f5d3SJohn Marino /*
494*86d7f5d3SJohn Marino  * compare two files list node (for sort)
495*86d7f5d3SJohn Marino  */
496*86d7f5d3SJohn Marino int
fsortcmp(const Node * p,const Node * q)497*86d7f5d3SJohn Marino fsortcmp (const Node *p, const Node *q)
498*86d7f5d3SJohn Marino {
499*86d7f5d3SJohn Marino     return strcmp (p->key, q->key);
500*86d7f5d3SJohn Marino }
501*86d7f5d3SJohn Marino 
502*86d7f5d3SJohn Marino 
503*86d7f5d3SJohn Marino 
504*86d7f5d3SJohn Marino /* Debugging functions.  Quite useful to call from within gdb. */
505*86d7f5d3SJohn Marino 
506*86d7f5d3SJohn Marino 
507*86d7f5d3SJohn Marino static char *
nodetypestring(Ntype type)508*86d7f5d3SJohn Marino nodetypestring (Ntype type)
509*86d7f5d3SJohn Marino {
510*86d7f5d3SJohn Marino     switch (type) {
511*86d7f5d3SJohn Marino     case NT_UNKNOWN:	return "UNKNOWN";
512*86d7f5d3SJohn Marino     case HEADER:	return "HEADER";
513*86d7f5d3SJohn Marino     case ENTRIES:	return "ENTRIES";
514*86d7f5d3SJohn Marino     case FILES:		return "FILES";
515*86d7f5d3SJohn Marino     case LIST:		return "LIST";
516*86d7f5d3SJohn Marino     case RCSNODE:	return "RCSNODE";
517*86d7f5d3SJohn Marino     case RCSVERS:	return "RCSVERS";
518*86d7f5d3SJohn Marino     case DIRS:		return "DIRS";
519*86d7f5d3SJohn Marino     case UPDATE:	return "UPDATE";
520*86d7f5d3SJohn Marino     case LOCK:		return "LOCK";
521*86d7f5d3SJohn Marino     case NDBMNODE:	return "NDBMNODE";
522*86d7f5d3SJohn Marino     case FILEATTR:	return "FILEATTR";
523*86d7f5d3SJohn Marino     case VARIABLE:	return "VARIABLE";
524*86d7f5d3SJohn Marino     case RCSFIELD:	return "RCSFIELD";
525*86d7f5d3SJohn Marino     case RCSCMPFLD:	return "RCSCMPFLD";
526*86d7f5d3SJohn Marino     }
527*86d7f5d3SJohn Marino 
528*86d7f5d3SJohn Marino     return "<trash>";
529*86d7f5d3SJohn Marino }
530*86d7f5d3SJohn Marino 
531*86d7f5d3SJohn Marino 
532*86d7f5d3SJohn Marino 
533*86d7f5d3SJohn Marino static int
printnode(Node * node,void * closure)534*86d7f5d3SJohn Marino printnode (Node *node, void *closure)
535*86d7f5d3SJohn Marino {
536*86d7f5d3SJohn Marino     if (node == NULL)
537*86d7f5d3SJohn Marino     {
538*86d7f5d3SJohn Marino 	(void) printf("NULL node.\n");
539*86d7f5d3SJohn Marino 	return 0;
540*86d7f5d3SJohn Marino     }
541*86d7f5d3SJohn Marino 
542*86d7f5d3SJohn Marino #ifdef HAVE_PRINTF_PTR
543*86d7f5d3SJohn Marino     (void) printf("Node at %p: type = %s, key = %p = \"%s\", data = %p, next = %p, prev = %p\n",
544*86d7f5d3SJohn Marino 	   (void *) node, nodetypestring(node->type),
545*86d7f5d3SJohn Marino 	   (void *) node->key, node->key, node->data,
546*86d7f5d3SJohn Marino 	   (void *) node->next, (void *) node->prev);
547*86d7f5d3SJohn Marino #else
548*86d7f5d3SJohn Marino     (void) printf("Node at 0x%lx: type = %s, key = 0x%lx = \"%s\", data = 0x%lx, next = 0x%lx, prev = 0x%lx\n",
549*86d7f5d3SJohn Marino 	   (unsigned long) node, nodetypestring(node->type),
550*86d7f5d3SJohn Marino 	   (unsigned long) node->key, node->key, (unsigned long) node->data,
551*86d7f5d3SJohn Marino 	   (unsigned long) node->next, (unsigned long) node->prev);
552*86d7f5d3SJohn Marino #endif
553*86d7f5d3SJohn Marino 
554*86d7f5d3SJohn Marino     return 0;
555*86d7f5d3SJohn Marino }
556*86d7f5d3SJohn Marino 
557*86d7f5d3SJohn Marino 
558*86d7f5d3SJohn Marino 
559*86d7f5d3SJohn Marino /* This is global, not static, so that its name is unique and to avoid
560*86d7f5d3SJohn Marino    compiler warnings about it not being used.  But it is not used by CVS;
561*86d7f5d3SJohn Marino    it exists so one can call it from a debugger.  */
562*86d7f5d3SJohn Marino 
563*86d7f5d3SJohn Marino void
printlist(List * list)564*86d7f5d3SJohn Marino printlist (List *list)
565*86d7f5d3SJohn Marino {
566*86d7f5d3SJohn Marino     if (list == NULL)
567*86d7f5d3SJohn Marino     {
568*86d7f5d3SJohn Marino 	(void) printf("NULL list.\n");
569*86d7f5d3SJohn Marino 	return;
570*86d7f5d3SJohn Marino     }
571*86d7f5d3SJohn Marino 
572*86d7f5d3SJohn Marino #ifdef HAVE_PRINTF_PTR
573*86d7f5d3SJohn Marino     (void) printf("List at %p: list = %p, HASHSIZE = %d, next = %p\n",
574*86d7f5d3SJohn Marino 	   (void *) list, (void *) list->list, HASHSIZE, (void *) list->next);
575*86d7f5d3SJohn Marino #else
576*86d7f5d3SJohn Marino     (void) printf("List at 0x%lx: list = 0x%lx, HASHSIZE = %d, next = 0x%lx\n",
577*86d7f5d3SJohn Marino 	   (unsigned long) list, (unsigned long) list->list, HASHSIZE,
578*86d7f5d3SJohn Marino 	   (unsigned long) list->next);
579*86d7f5d3SJohn Marino #endif
580*86d7f5d3SJohn Marino 
581*86d7f5d3SJohn Marino     (void) walklist(list, printnode, NULL);
582*86d7f5d3SJohn Marino 
583*86d7f5d3SJohn Marino     return;
584*86d7f5d3SJohn Marino }
585