list.c revision b3307321
1b3307321Smrg/* $Xorg: list.c,v 1.5 2001/02/09 02:06:03 xorgcvs Exp $ */
2b3307321Smrg/** ------------------------------------------------------------------------
3b3307321Smrg	This file contains routines for manipulating generic lists.
4b3307321Smrg	Lists are implemented with a "harness".  In other words, each
5b3307321Smrg	node in the list consists of two pointers, one to the data item
6b3307321Smrg	and one to the next node in the list.  The head of the list is
7b3307321Smrg	the same struct as each node, but the "item" ptr is used to point
8b3307321Smrg	to the current member of the list (used by the first_in_list and
9b3307321Smrg	next_in_list functions).
10b3307321Smrg
11b3307321SmrgCopyright 1994 Hewlett-Packard Co.
12b3307321SmrgCopyright 1996, 1998  The Open Group
13b3307321Smrg
14b3307321SmrgPermission to use, copy, modify, distribute, and sell this software and its
15b3307321Smrgdocumentation for any purpose is hereby granted without fee, provided that
16b3307321Smrgthe above copyright notice appear in all copies and that both that
17b3307321Smrgcopyright notice and this permission notice appear in supporting
18b3307321Smrgdocumentation.
19b3307321Smrg
20b3307321SmrgThe above copyright notice and this permission notice shall be included
21b3307321Smrgin all copies or substantial portions of the Software.
22b3307321Smrg
23b3307321SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24b3307321SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25b3307321SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
26b3307321SmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
27b3307321SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
28b3307321SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
29b3307321SmrgOTHER DEALINGS IN THE SOFTWARE.
30b3307321Smrg
31b3307321SmrgExcept as contained in this notice, the name of The Open Group shall
32b3307321Smrgnot be used in advertising or otherwise to promote the sale, use or
33b3307321Smrgother dealings in this Software without prior written authorization
34b3307321Smrgfrom The Open Group.
35b3307321Smrg
36b3307321Smrg  ----------------------------------------------------------------------- **/
37b3307321Smrg/* $XFree86: xc/programs/xwd/list.c,v 3.6 2001/12/14 20:02:33 dawes Exp $ */
38b3307321Smrg
39b3307321Smrg#include <stdio.h>
40b3307321Smrg#include <stdlib.h>
41b3307321Smrg
42b3307321Smrg#include "list.h"
43b3307321Smrg
44b3307321Smrg
45b3307321Smrg/** ------------------------------------------------------------------------
46b3307321Smrg	Sets the pointers of the specified list to NULL.
47b3307321Smrg    --------------------------------------------------------------------- **/
48b3307321Smrgvoid zero_list(list_ptr lp)
49b3307321Smrg{
50b3307321Smrg    lp->next = NULL;
51b3307321Smrg    lp->ptr.item = NULL;
52b3307321Smrg}
53b3307321Smrg
54b3307321Smrg
55b3307321Smrg/** ------------------------------------------------------------------------
56b3307321Smrg	Adds item to the list pointed to by lp.  Finds the end of the
57b3307321Smrg	list, then mallocs a new list node onto the end of the list.
58b3307321Smrg	The item pointer in the new node is set to "item" passed in,
59b3307321Smrg	and the next pointer in the new node is set to NULL.
60b3307321Smrg	Returns 1 if successful, 0 if the malloc failed.
61b3307321Smrg    -------------------------------------------------------------------- **/
62b3307321Smrgint add_to_list(list_ptr lp, void *item)
63b3307321Smrg{
64b3307321Smrg    while (lp->next) {
65b3307321Smrg	lp = lp->next;
66b3307321Smrg    }
67b3307321Smrg    if ((lp->next = (list_ptr) malloc( sizeof( list_item))) == NULL) {
68b3307321Smrg
69b3307321Smrg	return 0;
70b3307321Smrg    }
71b3307321Smrg    lp->next->ptr.item = item;
72b3307321Smrg    lp->next->next = NULL;
73b3307321Smrg
74b3307321Smrg    return 1;
75b3307321Smrg}
76b3307321Smrg
77b3307321Smrg
78b3307321Smrg/** ------------------------------------------------------------------------
79b3307321Smrg	Creates a new list and sets its pointers to NULL.
80b3307321Smrg	Returns a pointer to the new list.
81b3307321Smrg    -------------------------------------------------------------------- **/
82b3307321Smrglist_ptr new_list ()
83b3307321Smrg{
84b3307321Smrg    list_ptr lp;
85b3307321Smrg
86b3307321Smrg    if ((lp = (list_ptr) malloc( sizeof( list_item)))) {
87b3307321Smrg	lp->next = NULL;
88b3307321Smrg	lp->ptr.item = NULL;
89b3307321Smrg    }
90b3307321Smrg
91b3307321Smrg    return lp;
92b3307321Smrg}
93b3307321Smrg
94b3307321Smrg
95b3307321Smrg/** ------------------------------------------------------------------------
96b3307321Smrg	Creates a new list head, pointing to the same list as the one
97b3307321Smrg	passed in.  If start_at_curr is TRUE, the new list's first item
98b3307321Smrg	is the "current" item (as set by calls to first/next_in_list()).
99b3307321Smrg	If start_at_curr is FALSE, the first item in the new list is the
100b3307321Smrg	same as the first item in the old list.  In either case, the
101b3307321Smrg	curr pointer in the new list is the same as in the old list.
102b3307321Smrg	Returns a pointer to the new list head.
103b3307321Smrg    -------------------------------------------------------------------- **/
104b3307321Smrglist_ptr dup_list_head(list_ptr lp, int start_at_curr)
105b3307321Smrg{
106b3307321Smrg    list_ptr new_list;
107b3307321Smrg
108b3307321Smrg    if ((new_list = (list_ptr) malloc( sizeof( list_item))) == NULL) {
109b3307321Smrg
110b3307321Smrg        return (list_ptr)NULL;
111b3307321Smrg    }
112b3307321Smrg    new_list->next = start_at_curr ? lp->ptr.curr : lp->next;
113b3307321Smrg    new_list->ptr.curr = lp->ptr.curr;
114b3307321Smrg
115b3307321Smrg    return new_list;
116b3307321Smrg}
117b3307321Smrg
118b3307321Smrg
119b3307321Smrg/** ------------------------------------------------------------------------
120b3307321Smrg	Returns the number of items in the list.
121b3307321Smrg    -------------------------------------------------------------------- **/
122b3307321Smrgunsigned int list_length(list_ptr lp)
123b3307321Smrg{
124b3307321Smrg    unsigned int count = 0;
125b3307321Smrg
126b3307321Smrg    while (lp->next) {
127b3307321Smrg	count++;
128b3307321Smrg	lp = lp->next;
129b3307321Smrg    }
130b3307321Smrg
131b3307321Smrg    return count;
132b3307321Smrg}
133b3307321Smrg
134b3307321Smrg
135b3307321Smrg/** ------------------------------------------------------------------------
136b3307321Smrg	Scans thru list, looking for a node whose ptr.item is equal to
137b3307321Smrg	the "item" passed in.  "Equal" here means the same address - no
138b3307321Smrg	attempt is made to match equivalent values stored in different
139b3307321Smrg	locations.  If a match is found, that node is deleted from the
140b3307321Smrg	list.  Storage for the node is freed, but not for the item itself.
141b3307321Smrg	Returns a pointer to the item, so the caller can free it if it
142b3307321Smrg	so desires.  If a match is not found, returns NULL.
143b3307321Smrg    -------------------------------------------------------------------- **/
144b3307321Smrgvoid *delete_from_list(list_ptr lp, void *item)
145b3307321Smrg{
146b3307321Smrg    list_ptr new_next;
147b3307321Smrg
148b3307321Smrg    while (lp->next) {
149b3307321Smrg	if (lp->next->ptr.item == item) {
150b3307321Smrg	    new_next = lp->next->next;
151b3307321Smrg	    free (lp->next);
152b3307321Smrg	    lp->next = new_next;
153b3307321Smrg
154b3307321Smrg	    return item;
155b3307321Smrg	}
156b3307321Smrg	lp = lp->next;
157b3307321Smrg    }
158b3307321Smrg
159b3307321Smrg    return NULL;
160b3307321Smrg}
161b3307321Smrg
162b3307321Smrg
163b3307321Smrg/** ------------------------------------------------------------------------
164b3307321Smrg	Deletes each node in the list *except the head*.  This allows
165b3307321Smrg	the deletion of lists where the head is not malloced or created
166b3307321Smrg	with new_list().  If free_items is true, each item pointed to
167b3307321Smrg	from the node is freed, in addition to the node itself.
168b3307321Smrg    -------------------------------------------------------------------- **/
169b3307321Smrgvoid delete_list(list_ptr lp, int free_items)
170b3307321Smrg{
171b3307321Smrg    list_ptr del_node;
172b3307321Smrg    void *item;
173b3307321Smrg
174b3307321Smrg    while (lp->next) {
175b3307321Smrg	del_node = lp->next;
176b3307321Smrg	item = del_node->ptr.item;
177b3307321Smrg	lp->next = del_node->next;
178b3307321Smrg	free (del_node);
179b3307321Smrg	if (free_items) {
180b3307321Smrg	    free( item);
181b3307321Smrg	}
182b3307321Smrg    }
183b3307321Smrg}
184b3307321Smrg
185b3307321Smrgvoid delete_list_destroying(list_ptr lp, void destructor(void *item))
186b3307321Smrg{
187b3307321Smrg    list_ptr del_node;
188b3307321Smrg    void *item;
189b3307321Smrg
190b3307321Smrg    while (lp->next) {
191b3307321Smrg	del_node = lp->next;
192b3307321Smrg	item = del_node->ptr.item;
193b3307321Smrg	lp->next = del_node->next;
194b3307321Smrg	free( del_node);
195b3307321Smrg	if (destructor) {
196b3307321Smrg	    destructor( item);
197b3307321Smrg	}
198b3307321Smrg    }
199b3307321Smrg}
200b3307321Smrg
201b3307321Smrg
202b3307321Smrg/** ------------------------------------------------------------------------
203b3307321Smrg	Returns a ptr to the first *item* (not list node) in the list.
204b3307321Smrg	Sets the list head node's curr ptr to the first node in the list.
205b3307321Smrg	Returns NULL if the list is empty.
206b3307321Smrg    -------------------------------------------------------------------- **/
207b3307321Smrgvoid * first_in_list(list_ptr lp)
208b3307321Smrg{
209b3307321Smrg    if (! lp) {
210b3307321Smrg
211b3307321Smrg	return NULL;
212b3307321Smrg    }
213b3307321Smrg    lp->ptr.curr = lp->next;
214b3307321Smrg
215b3307321Smrg    return lp->ptr.curr ? lp->ptr.curr->ptr.item : NULL;
216b3307321Smrg}
217b3307321Smrg
218b3307321Smrg/** ------------------------------------------------------------------------
219b3307321Smrg	Returns a ptr to the next *item* (not list node) in the list.
220b3307321Smrg	Sets the list head node's curr ptr to the next node in the list.
221b3307321Smrg	first_in_list must have been called prior.
222b3307321Smrg	Returns NULL if no next item.
223b3307321Smrg    -------------------------------------------------------------------- **/
224b3307321Smrgvoid * next_in_list(list_ptr lp)
225b3307321Smrg{
226b3307321Smrg    if (! lp) {
227b3307321Smrg
228b3307321Smrg	return NULL;
229b3307321Smrg    }
230b3307321Smrg    if (lp->ptr.curr) {
231b3307321Smrg	lp->ptr.curr = lp->ptr.curr->next;
232b3307321Smrg    }
233b3307321Smrg
234b3307321Smrg    return lp->ptr.curr ? lp->ptr.curr->ptr.item : NULL;
235b3307321Smrg}
236b3307321Smrg
237b3307321Smrgint list_is_empty(list_ptr lp)
238b3307321Smrg{
239b3307321Smrg    return (lp == NULL || lp->next == NULL);
240b3307321Smrg}
241b3307321Smrg
242