1b3307321Smrg/** ------------------------------------------------------------------------
2b3307321Smrg	This file contains routines for manipulating generic lists.
3b3307321Smrg	Lists are implemented with a "harness".  In other words, each
4b3307321Smrg	node in the list consists of two pointers, one to the data item
5b3307321Smrg	and one to the next node in the list.  The head of the list is
6b3307321Smrg	the same struct as each node, but the "item" ptr is used to point
7b3307321Smrg	to the current member of the list (used by the first_in_list and
8b3307321Smrg	next_in_list functions).
9b3307321Smrg
10b3307321SmrgCopyright 1994 Hewlett-Packard Co.
11b3307321SmrgCopyright 1996, 1998  The Open Group
12b3307321Smrg
13b3307321SmrgPermission to use, copy, modify, distribute, and sell this software and its
14b3307321Smrgdocumentation for any purpose is hereby granted without fee, provided that
15b3307321Smrgthe above copyright notice appear in all copies and that both that
16b3307321Smrgcopyright notice and this permission notice appear in supporting
17b3307321Smrgdocumentation.
18b3307321Smrg
19b3307321SmrgThe above copyright notice and this permission notice shall be included
20b3307321Smrgin all copies or substantial portions of the Software.
21b3307321Smrg
22b3307321SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23b3307321SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24b3307321SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25b3307321SmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
26b3307321SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27b3307321SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28b3307321SmrgOTHER DEALINGS IN THE SOFTWARE.
29b3307321Smrg
30b3307321SmrgExcept as contained in this notice, the name of The Open Group shall
31b3307321Smrgnot be used in advertising or otherwise to promote the sale, use or
32b3307321Smrgother dealings in this Software without prior written authorization
33b3307321Smrgfrom The Open Group.
34b3307321Smrg
35b3307321Smrg  ----------------------------------------------------------------------- **/
36b3307321Smrg
37b3307321Smrg#include <stdio.h>
38b3307321Smrg#include <stdlib.h>
39b3307321Smrg
40b3307321Smrg#include "list.h"
41b3307321Smrg
42b3307321Smrg
43b3307321Smrg/** ------------------------------------------------------------------------
44b3307321Smrg	Sets the pointers of the specified list to NULL.
45b3307321Smrg    --------------------------------------------------------------------- **/
4674b97a6cSmrgvoid
4774b97a6cSmrgzero_list(list_ptr lp)
48b3307321Smrg{
49b3307321Smrg    lp->next = NULL;
50b3307321Smrg    lp->ptr.item = NULL;
51b3307321Smrg}
52b3307321Smrg
53b3307321Smrg/** ------------------------------------------------------------------------
54b3307321Smrg	Adds item to the list pointed to by lp.  Finds the end of the
55b3307321Smrg	list, then mallocs a new list node onto the end of the list.
56b3307321Smrg	The item pointer in the new node is set to "item" passed in,
57b3307321Smrg	and the next pointer in the new node is set to NULL.
58b3307321Smrg	Returns 1 if successful, 0 if the malloc failed.
59b3307321Smrg    -------------------------------------------------------------------- **/
6074b97a6cSmrgint
6174b97a6cSmrgadd_to_list(list_ptr lp, void *item)
62b3307321Smrg{
63b3307321Smrg    while (lp->next) {
6474b97a6cSmrg        lp = lp->next;
65b3307321Smrg    }
666728f30eSmrg    if ((lp->next = malloc(sizeof(list_item))) == NULL) {
67b3307321Smrg
6874b97a6cSmrg        return 0;
69b3307321Smrg    }
70b3307321Smrg    lp->next->ptr.item = item;
71b3307321Smrg    lp->next->next = NULL;
72b3307321Smrg
73b3307321Smrg    return 1;
74b3307321Smrg}
75b3307321Smrg
76b3307321Smrg
77b3307321Smrg/** ------------------------------------------------------------------------
7874a3f230Smrg	Creates a new list and sets its pointers to NULL.
79b3307321Smrg	Returns a pointer to the new list.
80b3307321Smrg    -------------------------------------------------------------------- **/
8174b97a6cSmrglist_ptr
8274b97a6cSmrgnew_list(void)
83b3307321Smrg{
84b3307321Smrg    list_ptr lp;
85b3307321Smrg
866728f30eSmrg    if ((lp = malloc(sizeof(list_item)))) {
8774b97a6cSmrg        lp->next = NULL;
8874b97a6cSmrg        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    -------------------------------------------------------------------- **/
10474b97a6cSmrglist_ptr
10574b97a6cSmrgdup_list_head(list_ptr lp, int start_at_curr)
106b3307321Smrg{
10774a3f230Smrg    list_ptr new_listp;
108b3307321Smrg
1096728f30eSmrg    if ((new_listp = malloc(sizeof(list_item))) == NULL) {
110b3307321Smrg
11174b97a6cSmrg        return (list_ptr) NULL;
112b3307321Smrg    }
11374a3f230Smrg    new_listp->next = start_at_curr ? lp->ptr.curr : lp->next;
11474a3f230Smrg    new_listp->ptr.curr = lp->ptr.curr;
115b3307321Smrg
11674a3f230Smrg    return new_listp;
117b3307321Smrg}
118b3307321Smrg
119b3307321Smrg
1206728f30eSmrg#ifdef BUILD_UNUSED
121b3307321Smrg/** ------------------------------------------------------------------------
122b3307321Smrg	Returns the number of items in the list.
123b3307321Smrg    -------------------------------------------------------------------- **/
12474b97a6cSmrgunsigned int
12574b97a6cSmrglist_length(list_ptr lp)
126b3307321Smrg{
127b3307321Smrg    unsigned int count = 0;
128b3307321Smrg
129b3307321Smrg    while (lp->next) {
13074b97a6cSmrg        count++;
13174b97a6cSmrg        lp = lp->next;
132b3307321Smrg    }
133b3307321Smrg
134b3307321Smrg    return count;
135b3307321Smrg}
136b3307321Smrg
137b3307321Smrg
138b3307321Smrg/** ------------------------------------------------------------------------
1396728f30eSmrg	Scans through list, looking for a node whose ptr.item is equal to
140b3307321Smrg	the "item" passed in.  "Equal" here means the same address - no
141b3307321Smrg	attempt is made to match equivalent values stored in different
142b3307321Smrg	locations.  If a match is found, that node is deleted from the
143b3307321Smrg	list.  Storage for the node is freed, but not for the item itself.
144b3307321Smrg	Returns a pointer to the item, so the caller can free it if it
145b3307321Smrg	so desires.  If a match is not found, returns NULL.
146b3307321Smrg    -------------------------------------------------------------------- **/
14774b97a6cSmrgvoid *
14874b97a6cSmrgdelete_from_list(list_ptr lp, void *item)
149b3307321Smrg{
150b3307321Smrg    list_ptr new_next;
151b3307321Smrg
152b3307321Smrg    while (lp->next) {
15374b97a6cSmrg        if (lp->next->ptr.item == item) {
15474b97a6cSmrg            new_next = lp->next->next;
15574b97a6cSmrg            free(lp->next);
15674b97a6cSmrg            lp->next = new_next;
15774b97a6cSmrg
15874b97a6cSmrg            return item;
15974b97a6cSmrg        }
16074b97a6cSmrg        lp = lp->next;
161b3307321Smrg    }
162b3307321Smrg
163b3307321Smrg    return NULL;
164b3307321Smrg}
1656728f30eSmrg#endif /* BUILD_UNUSED */
166b3307321Smrg
167b3307321Smrg
168b3307321Smrg/** ------------------------------------------------------------------------
169b3307321Smrg	Deletes each node in the list *except the head*.  This allows
170b3307321Smrg	the deletion of lists where the head is not malloced or created
17174a3f230Smrg	with new_list().  If free_items is true, each item pointed to
172b3307321Smrg	from the node is freed, in addition to the node itself.
173b3307321Smrg    -------------------------------------------------------------------- **/
17474b97a6cSmrgvoid
17574b97a6cSmrgdelete_list(list_ptr lp, int free_items)
176b3307321Smrg{
177b3307321Smrg    while (lp->next) {
1786728f30eSmrg        list_ptr del_node = lp->next;
1796728f30eSmrg        void *item = del_node->ptr.item;
18074b97a6cSmrg        lp->next = del_node->next;
18174b97a6cSmrg        free(del_node);
18274b97a6cSmrg        if (free_items) {
18374b97a6cSmrg            free(item);
18474b97a6cSmrg        }
185b3307321Smrg    }
186b3307321Smrg}
187b3307321Smrg
18874b97a6cSmrgvoid
18974b97a6cSmrgdelete_list_destroying(list_ptr lp, void destructor(void *item))
190b3307321Smrg{
191b3307321Smrg    while (lp->next) {
1926728f30eSmrg        list_ptr del_node = lp->next;
1936728f30eSmrg        void *item = del_node->ptr.item;
19474b97a6cSmrg        lp->next = del_node->next;
19574b97a6cSmrg        free(del_node);
19674b97a6cSmrg        if (destructor) {
19774b97a6cSmrg            destructor(item);
19874b97a6cSmrg        }
199b3307321Smrg    }
200b3307321Smrg}
201b3307321Smrg
202b3307321Smrg
203b3307321Smrg/** ------------------------------------------------------------------------
204b3307321Smrg	Returns a ptr to the first *item* (not list node) in the list.
205b3307321Smrg	Sets the list head node's curr ptr to the first node in the list.
206b3307321Smrg	Returns NULL if the list is empty.
207b3307321Smrg    -------------------------------------------------------------------- **/
20874b97a6cSmrgvoid *
20974b97a6cSmrgfirst_in_list(list_ptr lp)
210b3307321Smrg{
21174b97a6cSmrg    if (!lp) {
212b3307321Smrg
21374b97a6cSmrg        return NULL;
214b3307321Smrg    }
215b3307321Smrg    lp->ptr.curr = lp->next;
216b3307321Smrg
217b3307321Smrg    return lp->ptr.curr ? lp->ptr.curr->ptr.item : NULL;
218b3307321Smrg}
219b3307321Smrg
220b3307321Smrg/** ------------------------------------------------------------------------
221b3307321Smrg	Returns a ptr to the next *item* (not list node) in the list.
222b3307321Smrg	Sets the list head node's curr ptr to the next node in the list.
223b3307321Smrg	first_in_list must have been called prior.
224b3307321Smrg	Returns NULL if no next item.
225b3307321Smrg    -------------------------------------------------------------------- **/
22674b97a6cSmrgvoid *
22774b97a6cSmrgnext_in_list(list_ptr lp)
228b3307321Smrg{
22974b97a6cSmrg    if (!lp) {
230b3307321Smrg
23174b97a6cSmrg        return NULL;
232b3307321Smrg    }
233b3307321Smrg    if (lp->ptr.curr) {
23474b97a6cSmrg        lp->ptr.curr = lp->ptr.curr->next;
235b3307321Smrg    }
236b3307321Smrg
237b3307321Smrg    return lp->ptr.curr ? lp->ptr.curr->ptr.item : NULL;
238b3307321Smrg}
239b3307321Smrg
2406728f30eSmrg#ifdef BUILD_UNUSED
24174b97a6cSmrgint
24274b97a6cSmrglist_is_empty(list_ptr lp)
243b3307321Smrg{
244b3307321Smrg    return (lp == NULL || lp->next == NULL);
245b3307321Smrg}
2466728f30eSmrg#endif  /* BUILD_UNUSED */
247