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