xref: /freebsd/contrib/bmake/lst.c (revision 2c3632d14fe37fa35c262ee9fb66835be0a52621)
1*2c3632d1SSimon J. Gerraty /* $NetBSD: lst.c,v 1.60 2020/08/31 05:56:02 rillig Exp $ */
2*2c3632d1SSimon J. Gerraty 
3*2c3632d1SSimon J. Gerraty /*
4*2c3632d1SSimon J. Gerraty  * Copyright (c) 1988, 1989, 1990, 1993
5*2c3632d1SSimon J. Gerraty  *	The Regents of the University of California.  All rights reserved.
6*2c3632d1SSimon J. Gerraty  *
7*2c3632d1SSimon J. Gerraty  * This code is derived from software contributed to Berkeley by
8*2c3632d1SSimon J. Gerraty  * Adam de Boor.
9*2c3632d1SSimon J. Gerraty  *
10*2c3632d1SSimon J. Gerraty  * Redistribution and use in source and binary forms, with or without
11*2c3632d1SSimon J. Gerraty  * modification, are permitted provided that the following conditions
12*2c3632d1SSimon J. Gerraty  * are met:
13*2c3632d1SSimon J. Gerraty  * 1. Redistributions of source code must retain the above copyright
14*2c3632d1SSimon J. Gerraty  *    notice, this list of conditions and the following disclaimer.
15*2c3632d1SSimon J. Gerraty  * 2. Redistributions in binary form must reproduce the above copyright
16*2c3632d1SSimon J. Gerraty  *    notice, this list of conditions and the following disclaimer in the
17*2c3632d1SSimon J. Gerraty  *    documentation and/or other materials provided with the distribution.
18*2c3632d1SSimon J. Gerraty  * 3. Neither the name of the University nor the names of its contributors
19*2c3632d1SSimon J. Gerraty  *    may be used to endorse or promote products derived from this software
20*2c3632d1SSimon J. Gerraty  *    without specific prior written permission.
21*2c3632d1SSimon J. Gerraty  *
22*2c3632d1SSimon J. Gerraty  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23*2c3632d1SSimon J. Gerraty  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24*2c3632d1SSimon J. Gerraty  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25*2c3632d1SSimon J. Gerraty  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26*2c3632d1SSimon J. Gerraty  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27*2c3632d1SSimon J. Gerraty  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28*2c3632d1SSimon J. Gerraty  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29*2c3632d1SSimon J. Gerraty  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30*2c3632d1SSimon J. Gerraty  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31*2c3632d1SSimon J. Gerraty  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*2c3632d1SSimon J. Gerraty  * SUCH DAMAGE.
33*2c3632d1SSimon J. Gerraty  */
34*2c3632d1SSimon J. Gerraty 
35*2c3632d1SSimon J. Gerraty #ifdef HAVE_CONFIG_H
36*2c3632d1SSimon J. Gerraty # include "config.h"
37*2c3632d1SSimon J. Gerraty #endif
38*2c3632d1SSimon J. Gerraty 
39*2c3632d1SSimon J. Gerraty #ifdef HAVE_INTTYPES_H
40*2c3632d1SSimon J. Gerraty #include <inttypes.h>
41*2c3632d1SSimon J. Gerraty #elif defined(HAVE_STDINT_H)
42*2c3632d1SSimon J. Gerraty #include <stdint.h>
43*2c3632d1SSimon J. Gerraty #endif
44*2c3632d1SSimon J. Gerraty 
45*2c3632d1SSimon J. Gerraty #include "make.h"
46*2c3632d1SSimon J. Gerraty 
47*2c3632d1SSimon J. Gerraty #ifndef MAKE_NATIVE
48*2c3632d1SSimon J. Gerraty static char rcsid[] = "$NetBSD: lst.c,v 1.60 2020/08/31 05:56:02 rillig Exp $";
49*2c3632d1SSimon J. Gerraty #else
50*2c3632d1SSimon J. Gerraty #include <sys/cdefs.h>
51*2c3632d1SSimon J. Gerraty #ifndef lint
52*2c3632d1SSimon J. Gerraty __RCSID("$NetBSD: lst.c,v 1.60 2020/08/31 05:56:02 rillig Exp $");
53*2c3632d1SSimon J. Gerraty #endif /* not lint */
54*2c3632d1SSimon J. Gerraty #endif
55*2c3632d1SSimon J. Gerraty 
56*2c3632d1SSimon J. Gerraty struct ListNode {
57*2c3632d1SSimon J. Gerraty     struct ListNode *prev;	/* previous element in list */
58*2c3632d1SSimon J. Gerraty     struct ListNode *next;	/* next in list */
59*2c3632d1SSimon J. Gerraty     uint8_t useCount;		/* Count of functions using the node.
60*2c3632d1SSimon J. Gerraty 				 * node may not be deleted until count
61*2c3632d1SSimon J. Gerraty 				 * goes to 0 */
62*2c3632d1SSimon J. Gerraty     Boolean deleted;		/* List node should be removed when done */
63*2c3632d1SSimon J. Gerraty     union {
64*2c3632d1SSimon J. Gerraty 	void *datum;		/* datum associated with this element */
65*2c3632d1SSimon J. Gerraty 	const GNode *gnode;	/* alias, just for debugging */
66*2c3632d1SSimon J. Gerraty 	const char *str;	/* alias, just for debugging */
67*2c3632d1SSimon J. Gerraty     };
68*2c3632d1SSimon J. Gerraty };
69*2c3632d1SSimon J. Gerraty 
70*2c3632d1SSimon J. Gerraty typedef enum {
71*2c3632d1SSimon J. Gerraty     Head, Middle, Tail, Unknown
72*2c3632d1SSimon J. Gerraty } Where;
73*2c3632d1SSimon J. Gerraty 
74*2c3632d1SSimon J. Gerraty struct List {
75*2c3632d1SSimon J. Gerraty     LstNode first;		/* first node in list */
76*2c3632d1SSimon J. Gerraty     LstNode last;		/* last node in list */
77*2c3632d1SSimon J. Gerraty 
78*2c3632d1SSimon J. Gerraty     /* fields for sequential access */
79*2c3632d1SSimon J. Gerraty     Boolean isOpen;		/* true if list has been Lst_Open'ed */
80*2c3632d1SSimon J. Gerraty     Where lastAccess;		/* Where in the list the last access was */
81*2c3632d1SSimon J. Gerraty     LstNode curr;		/* current node, if open. NULL if
82*2c3632d1SSimon J. Gerraty 				 * *just* opened */
83*2c3632d1SSimon J. Gerraty     LstNode prev;		/* Previous node, if open. Used by Lst_Remove */
84*2c3632d1SSimon J. Gerraty };
85*2c3632d1SSimon J. Gerraty 
86*2c3632d1SSimon J. Gerraty /* Allocate and initialize a list node.
87*2c3632d1SSimon J. Gerraty  *
88*2c3632d1SSimon J. Gerraty  * The fields 'prev' and 'next' must be initialized by the caller.
89*2c3632d1SSimon J. Gerraty  */
90*2c3632d1SSimon J. Gerraty static LstNode
91*2c3632d1SSimon J. Gerraty LstNodeNew(void *datum)
92*2c3632d1SSimon J. Gerraty {
93*2c3632d1SSimon J. Gerraty     LstNode node = bmake_malloc(sizeof *node);
94*2c3632d1SSimon J. Gerraty     node->useCount = 0;
95*2c3632d1SSimon J. Gerraty     node->deleted = FALSE;
96*2c3632d1SSimon J. Gerraty     node->datum = datum;
97*2c3632d1SSimon J. Gerraty     return node;
98*2c3632d1SSimon J. Gerraty }
99*2c3632d1SSimon J. Gerraty 
100*2c3632d1SSimon J. Gerraty static Boolean
101*2c3632d1SSimon J. Gerraty LstIsEmpty(Lst list)
102*2c3632d1SSimon J. Gerraty {
103*2c3632d1SSimon J. Gerraty     return list->first == NULL;
104*2c3632d1SSimon J. Gerraty }
105*2c3632d1SSimon J. Gerraty 
106*2c3632d1SSimon J. Gerraty /* Create and initialize a new, empty list. */
107*2c3632d1SSimon J. Gerraty Lst
108*2c3632d1SSimon J. Gerraty Lst_Init(void)
109*2c3632d1SSimon J. Gerraty {
110*2c3632d1SSimon J. Gerraty     Lst list = bmake_malloc(sizeof *list);
111*2c3632d1SSimon J. Gerraty 
112*2c3632d1SSimon J. Gerraty     list->first = NULL;
113*2c3632d1SSimon J. Gerraty     list->last = NULL;
114*2c3632d1SSimon J. Gerraty     list->isOpen = FALSE;
115*2c3632d1SSimon J. Gerraty     list->lastAccess = Unknown;
116*2c3632d1SSimon J. Gerraty 
117*2c3632d1SSimon J. Gerraty     return list;
118*2c3632d1SSimon J. Gerraty }
119*2c3632d1SSimon J. Gerraty 
120*2c3632d1SSimon J. Gerraty /* Duplicate an entire list, usually by copying the datum pointers.
121*2c3632d1SSimon J. Gerraty  * If copyProc is given, that function is used to create the new datum from the
122*2c3632d1SSimon J. Gerraty  * old datum, usually by creating a copy of it. */
123*2c3632d1SSimon J. Gerraty Lst
124*2c3632d1SSimon J. Gerraty Lst_Copy(Lst list, LstCopyProc copyProc)
125*2c3632d1SSimon J. Gerraty {
126*2c3632d1SSimon J. Gerraty     Lst newList;
127*2c3632d1SSimon J. Gerraty     LstNode node;
128*2c3632d1SSimon J. Gerraty 
129*2c3632d1SSimon J. Gerraty     assert(list != NULL);
130*2c3632d1SSimon J. Gerraty 
131*2c3632d1SSimon J. Gerraty     newList = Lst_Init();
132*2c3632d1SSimon J. Gerraty 
133*2c3632d1SSimon J. Gerraty     for (node = list->first; node != NULL; node = node->next) {
134*2c3632d1SSimon J. Gerraty 	void *datum = copyProc != NULL ? copyProc(node->datum) : node->datum;
135*2c3632d1SSimon J. Gerraty 	Lst_Append(newList, datum);
136*2c3632d1SSimon J. Gerraty     }
137*2c3632d1SSimon J. Gerraty 
138*2c3632d1SSimon J. Gerraty     return newList;
139*2c3632d1SSimon J. Gerraty }
140*2c3632d1SSimon J. Gerraty 
141*2c3632d1SSimon J. Gerraty /* Free a list and all its nodes. The list data itself are not freed though. */
142*2c3632d1SSimon J. Gerraty void
143*2c3632d1SSimon J. Gerraty Lst_Free(Lst list)
144*2c3632d1SSimon J. Gerraty {
145*2c3632d1SSimon J. Gerraty     LstNode node;
146*2c3632d1SSimon J. Gerraty     LstNode next;
147*2c3632d1SSimon J. Gerraty 
148*2c3632d1SSimon J. Gerraty     assert(list != NULL);
149*2c3632d1SSimon J. Gerraty 
150*2c3632d1SSimon J. Gerraty     for (node = list->first; node != NULL; node = next) {
151*2c3632d1SSimon J. Gerraty 	next = node->next;
152*2c3632d1SSimon J. Gerraty 	free(node);
153*2c3632d1SSimon J. Gerraty     }
154*2c3632d1SSimon J. Gerraty 
155*2c3632d1SSimon J. Gerraty     free(list);
156*2c3632d1SSimon J. Gerraty }
157*2c3632d1SSimon J. Gerraty 
158*2c3632d1SSimon J. Gerraty /* Destroy a list and free all its resources. The freeProc is called with the
159*2c3632d1SSimon J. Gerraty  * datum from each node in turn before the node is freed. */
160*2c3632d1SSimon J. Gerraty void
161*2c3632d1SSimon J. Gerraty Lst_Destroy(Lst list, LstFreeProc freeProc)
162*2c3632d1SSimon J. Gerraty {
163*2c3632d1SSimon J. Gerraty     LstNode node;
164*2c3632d1SSimon J. Gerraty     LstNode next;
165*2c3632d1SSimon J. Gerraty 
166*2c3632d1SSimon J. Gerraty     assert(list != NULL);
167*2c3632d1SSimon J. Gerraty     assert(freeProc != NULL);
168*2c3632d1SSimon J. Gerraty 
169*2c3632d1SSimon J. Gerraty     for (node = list->first; node != NULL; node = next) {
170*2c3632d1SSimon J. Gerraty 	next = node->next;
171*2c3632d1SSimon J. Gerraty 	freeProc(node->datum);
172*2c3632d1SSimon J. Gerraty 	free(node);
173*2c3632d1SSimon J. Gerraty     }
174*2c3632d1SSimon J. Gerraty 
175*2c3632d1SSimon J. Gerraty     free(list);
176*2c3632d1SSimon J. Gerraty }
177*2c3632d1SSimon J. Gerraty 
178*2c3632d1SSimon J. Gerraty /*
179*2c3632d1SSimon J. Gerraty  * Functions to modify a list
180*2c3632d1SSimon J. Gerraty  */
181*2c3632d1SSimon J. Gerraty 
182*2c3632d1SSimon J. Gerraty /* Insert a new node with the given piece of data before the given node in the
183*2c3632d1SSimon J. Gerraty  * given list. */
184*2c3632d1SSimon J. Gerraty void
185*2c3632d1SSimon J. Gerraty Lst_InsertBefore(Lst list, LstNode node, void *datum)
186*2c3632d1SSimon J. Gerraty {
187*2c3632d1SSimon J. Gerraty     LstNode newNode;
188*2c3632d1SSimon J. Gerraty 
189*2c3632d1SSimon J. Gerraty     assert(list != NULL);
190*2c3632d1SSimon J. Gerraty     assert(!LstIsEmpty(list));
191*2c3632d1SSimon J. Gerraty     assert(node != NULL);
192*2c3632d1SSimon J. Gerraty     assert(datum != NULL);
193*2c3632d1SSimon J. Gerraty 
194*2c3632d1SSimon J. Gerraty     newNode = LstNodeNew(datum);
195*2c3632d1SSimon J. Gerraty     newNode->prev = node->prev;
196*2c3632d1SSimon J. Gerraty     newNode->next = node;
197*2c3632d1SSimon J. Gerraty 
198*2c3632d1SSimon J. Gerraty     if (node->prev != NULL) {
199*2c3632d1SSimon J. Gerraty 	node->prev->next = newNode;
200*2c3632d1SSimon J. Gerraty     }
201*2c3632d1SSimon J. Gerraty     node->prev = newNode;
202*2c3632d1SSimon J. Gerraty 
203*2c3632d1SSimon J. Gerraty     if (node == list->first) {
204*2c3632d1SSimon J. Gerraty 	list->first = newNode;
205*2c3632d1SSimon J. Gerraty     }
206*2c3632d1SSimon J. Gerraty }
207*2c3632d1SSimon J. Gerraty 
208*2c3632d1SSimon J. Gerraty /* Add a piece of data at the start of the given list. */
209*2c3632d1SSimon J. Gerraty void
210*2c3632d1SSimon J. Gerraty Lst_Prepend(Lst list, void *datum)
211*2c3632d1SSimon J. Gerraty {
212*2c3632d1SSimon J. Gerraty     LstNode node;
213*2c3632d1SSimon J. Gerraty 
214*2c3632d1SSimon J. Gerraty     assert(list != NULL);
215*2c3632d1SSimon J. Gerraty     assert(datum != NULL);
216*2c3632d1SSimon J. Gerraty 
217*2c3632d1SSimon J. Gerraty     node = LstNodeNew(datum);
218*2c3632d1SSimon J. Gerraty     node->prev = NULL;
219*2c3632d1SSimon J. Gerraty     node->next = list->first;
220*2c3632d1SSimon J. Gerraty 
221*2c3632d1SSimon J. Gerraty     if (list->first == NULL) {
222*2c3632d1SSimon J. Gerraty 	list->first = node;
223*2c3632d1SSimon J. Gerraty 	list->last = node;
224*2c3632d1SSimon J. Gerraty     } else {
225*2c3632d1SSimon J. Gerraty 	list->first->prev = node;
226*2c3632d1SSimon J. Gerraty 	list->first = node;
227*2c3632d1SSimon J. Gerraty     }
228*2c3632d1SSimon J. Gerraty }
229*2c3632d1SSimon J. Gerraty 
230*2c3632d1SSimon J. Gerraty /* Add a piece of data at the end of the given list. */
231*2c3632d1SSimon J. Gerraty void
232*2c3632d1SSimon J. Gerraty Lst_Append(Lst list, void *datum)
233*2c3632d1SSimon J. Gerraty {
234*2c3632d1SSimon J. Gerraty     LstNode node;
235*2c3632d1SSimon J. Gerraty 
236*2c3632d1SSimon J. Gerraty     assert(list != NULL);
237*2c3632d1SSimon J. Gerraty     assert(datum != NULL);
238*2c3632d1SSimon J. Gerraty 
239*2c3632d1SSimon J. Gerraty     node = LstNodeNew(datum);
240*2c3632d1SSimon J. Gerraty     node->prev = list->last;
241*2c3632d1SSimon J. Gerraty     node->next = NULL;
242*2c3632d1SSimon J. Gerraty 
243*2c3632d1SSimon J. Gerraty     if (list->last == NULL) {
244*2c3632d1SSimon J. Gerraty 	list->first = node;
245*2c3632d1SSimon J. Gerraty 	list->last = node;
246*2c3632d1SSimon J. Gerraty     } else {
247*2c3632d1SSimon J. Gerraty 	list->last->next = node;
248*2c3632d1SSimon J. Gerraty 	list->last = node;
249*2c3632d1SSimon J. Gerraty     }
250*2c3632d1SSimon J. Gerraty }
251*2c3632d1SSimon J. Gerraty 
252*2c3632d1SSimon J. Gerraty /* Remove the given node from the given list.
253*2c3632d1SSimon J. Gerraty  * The datum stored in the node must be freed by the caller, if necessary. */
254*2c3632d1SSimon J. Gerraty void
255*2c3632d1SSimon J. Gerraty Lst_Remove(Lst list, LstNode node)
256*2c3632d1SSimon J. Gerraty {
257*2c3632d1SSimon J. Gerraty     assert(list != NULL);
258*2c3632d1SSimon J. Gerraty     assert(node != NULL);
259*2c3632d1SSimon J. Gerraty 
260*2c3632d1SSimon J. Gerraty     /*
261*2c3632d1SSimon J. Gerraty      * unlink it from the list
262*2c3632d1SSimon J. Gerraty      */
263*2c3632d1SSimon J. Gerraty     if (node->next != NULL) {
264*2c3632d1SSimon J. Gerraty 	node->next->prev = node->prev;
265*2c3632d1SSimon J. Gerraty     }
266*2c3632d1SSimon J. Gerraty     if (node->prev != NULL) {
267*2c3632d1SSimon J. Gerraty 	node->prev->next = node->next;
268*2c3632d1SSimon J. Gerraty     }
269*2c3632d1SSimon J. Gerraty 
270*2c3632d1SSimon J. Gerraty     /*
271*2c3632d1SSimon J. Gerraty      * if either the first or last of the list point to this node,
272*2c3632d1SSimon J. Gerraty      * adjust them accordingly
273*2c3632d1SSimon J. Gerraty      */
274*2c3632d1SSimon J. Gerraty     if (list->first == node) {
275*2c3632d1SSimon J. Gerraty 	list->first = node->next;
276*2c3632d1SSimon J. Gerraty     }
277*2c3632d1SSimon J. Gerraty     if (list->last == node) {
278*2c3632d1SSimon J. Gerraty 	list->last = node->prev;
279*2c3632d1SSimon J. Gerraty     }
280*2c3632d1SSimon J. Gerraty 
281*2c3632d1SSimon J. Gerraty     /*
282*2c3632d1SSimon J. Gerraty      * Sequential access stuff. If the node we're removing is the current
283*2c3632d1SSimon J. Gerraty      * node in the list, reset the current node to the previous one. If the
284*2c3632d1SSimon J. Gerraty      * previous one was non-existent (prev == NULL), we set the
285*2c3632d1SSimon J. Gerraty      * end to be Unknown, since it is.
286*2c3632d1SSimon J. Gerraty      */
287*2c3632d1SSimon J. Gerraty     if (list->isOpen && list->curr == node) {
288*2c3632d1SSimon J. Gerraty 	list->curr = list->prev;
289*2c3632d1SSimon J. Gerraty 	if (list->curr == NULL) {
290*2c3632d1SSimon J. Gerraty 	    list->lastAccess = Unknown;
291*2c3632d1SSimon J. Gerraty 	}
292*2c3632d1SSimon J. Gerraty     }
293*2c3632d1SSimon J. Gerraty 
294*2c3632d1SSimon J. Gerraty     /*
295*2c3632d1SSimon J. Gerraty      * note that the datum is unmolested. The caller must free it as
296*2c3632d1SSimon J. Gerraty      * necessary and as expected.
297*2c3632d1SSimon J. Gerraty      */
298*2c3632d1SSimon J. Gerraty     if (node->useCount == 0) {
299*2c3632d1SSimon J. Gerraty 	free(node);
300*2c3632d1SSimon J. Gerraty     } else {
301*2c3632d1SSimon J. Gerraty 	node->deleted = TRUE;
302*2c3632d1SSimon J. Gerraty     }
303*2c3632d1SSimon J. Gerraty }
304*2c3632d1SSimon J. Gerraty 
305*2c3632d1SSimon J. Gerraty /* Replace the datum in the given node with the new datum. */
306*2c3632d1SSimon J. Gerraty void
307*2c3632d1SSimon J. Gerraty LstNode_Set(LstNode node, void *datum)
308*2c3632d1SSimon J. Gerraty {
309*2c3632d1SSimon J. Gerraty     assert(node != NULL);
310*2c3632d1SSimon J. Gerraty     assert(datum != NULL);
311*2c3632d1SSimon J. Gerraty 
312*2c3632d1SSimon J. Gerraty     node->datum = datum;
313*2c3632d1SSimon J. Gerraty }
314*2c3632d1SSimon J. Gerraty 
315*2c3632d1SSimon J. Gerraty /* Replace the datum in the given node to NULL. */
316*2c3632d1SSimon J. Gerraty void
317*2c3632d1SSimon J. Gerraty LstNode_SetNull(LstNode node)
318*2c3632d1SSimon J. Gerraty {
319*2c3632d1SSimon J. Gerraty     assert(node != NULL);
320*2c3632d1SSimon J. Gerraty 
321*2c3632d1SSimon J. Gerraty     node->datum = NULL;
322*2c3632d1SSimon J. Gerraty }
323*2c3632d1SSimon J. Gerraty 
324*2c3632d1SSimon J. Gerraty 
325*2c3632d1SSimon J. Gerraty /*
326*2c3632d1SSimon J. Gerraty  * Node-specific functions
327*2c3632d1SSimon J. Gerraty  */
328*2c3632d1SSimon J. Gerraty 
329*2c3632d1SSimon J. Gerraty /* Return the first node from the given list, or NULL if the list is empty. */
330*2c3632d1SSimon J. Gerraty LstNode
331*2c3632d1SSimon J. Gerraty Lst_First(Lst list)
332*2c3632d1SSimon J. Gerraty {
333*2c3632d1SSimon J. Gerraty     assert(list != NULL);
334*2c3632d1SSimon J. Gerraty 
335*2c3632d1SSimon J. Gerraty     return list->first;
336*2c3632d1SSimon J. Gerraty }
337*2c3632d1SSimon J. Gerraty 
338*2c3632d1SSimon J. Gerraty /* Return the last node from the given list, or NULL if the list is empty. */
339*2c3632d1SSimon J. Gerraty LstNode
340*2c3632d1SSimon J. Gerraty Lst_Last(Lst list)
341*2c3632d1SSimon J. Gerraty {
342*2c3632d1SSimon J. Gerraty     assert(list != NULL);
343*2c3632d1SSimon J. Gerraty 
344*2c3632d1SSimon J. Gerraty     return list->last;
345*2c3632d1SSimon J. Gerraty }
346*2c3632d1SSimon J. Gerraty 
347*2c3632d1SSimon J. Gerraty /* Return the successor to the given node on its list, or NULL. */
348*2c3632d1SSimon J. Gerraty LstNode
349*2c3632d1SSimon J. Gerraty LstNode_Next(LstNode node)
350*2c3632d1SSimon J. Gerraty {
351*2c3632d1SSimon J. Gerraty     assert(node != NULL);
352*2c3632d1SSimon J. Gerraty 
353*2c3632d1SSimon J. Gerraty     return node->next;
354*2c3632d1SSimon J. Gerraty }
355*2c3632d1SSimon J. Gerraty 
356*2c3632d1SSimon J. Gerraty /* Return the predecessor to the given node on its list, or NULL. */
357*2c3632d1SSimon J. Gerraty LstNode
358*2c3632d1SSimon J. Gerraty LstNode_Prev(LstNode node)
359*2c3632d1SSimon J. Gerraty {
360*2c3632d1SSimon J. Gerraty     assert(node != NULL);
361*2c3632d1SSimon J. Gerraty     return node->prev;
362*2c3632d1SSimon J. Gerraty }
363*2c3632d1SSimon J. Gerraty 
364*2c3632d1SSimon J. Gerraty /* Return the datum stored in the given node. */
365*2c3632d1SSimon J. Gerraty void *
366*2c3632d1SSimon J. Gerraty LstNode_Datum(LstNode node)
367*2c3632d1SSimon J. Gerraty {
368*2c3632d1SSimon J. Gerraty     assert(node != NULL);
369*2c3632d1SSimon J. Gerraty     return node->datum;
370*2c3632d1SSimon J. Gerraty }
371*2c3632d1SSimon J. Gerraty 
372*2c3632d1SSimon J. Gerraty 
373*2c3632d1SSimon J. Gerraty /*
374*2c3632d1SSimon J. Gerraty  * Functions for entire lists
375*2c3632d1SSimon J. Gerraty  */
376*2c3632d1SSimon J. Gerraty 
377*2c3632d1SSimon J. Gerraty /* Return TRUE if the given list is empty. */
378*2c3632d1SSimon J. Gerraty Boolean
379*2c3632d1SSimon J. Gerraty Lst_IsEmpty(Lst list)
380*2c3632d1SSimon J. Gerraty {
381*2c3632d1SSimon J. Gerraty     assert(list != NULL);
382*2c3632d1SSimon J. Gerraty 
383*2c3632d1SSimon J. Gerraty     return LstIsEmpty(list);
384*2c3632d1SSimon J. Gerraty }
385*2c3632d1SSimon J. Gerraty 
386*2c3632d1SSimon J. Gerraty /* Return the first node from the list for which the match function returns
387*2c3632d1SSimon J. Gerraty  * TRUE, or NULL if none of the nodes matched. */
388*2c3632d1SSimon J. Gerraty LstNode
389*2c3632d1SSimon J. Gerraty Lst_Find(Lst list, LstFindProc match, const void *matchArgs)
390*2c3632d1SSimon J. Gerraty {
391*2c3632d1SSimon J. Gerraty     return Lst_FindFrom(list, Lst_First(list), match, matchArgs);
392*2c3632d1SSimon J. Gerraty }
393*2c3632d1SSimon J. Gerraty 
394*2c3632d1SSimon J. Gerraty /* Return the first node from the list, starting at the given node, for which
395*2c3632d1SSimon J. Gerraty  * the match function returns TRUE, or NULL if none of the nodes matches.
396*2c3632d1SSimon J. Gerraty  *
397*2c3632d1SSimon J. Gerraty  * The start node may be NULL, in which case nothing is found. This allows
398*2c3632d1SSimon J. Gerraty  * for passing Lst_First or LstNode_Next as the start node. */
399*2c3632d1SSimon J. Gerraty LstNode
400*2c3632d1SSimon J. Gerraty Lst_FindFrom(Lst list, LstNode node, LstFindProc match, const void *matchArgs)
401*2c3632d1SSimon J. Gerraty {
402*2c3632d1SSimon J. Gerraty     LstNode tln;
403*2c3632d1SSimon J. Gerraty 
404*2c3632d1SSimon J. Gerraty     assert(list != NULL);
405*2c3632d1SSimon J. Gerraty     assert(match != NULL);
406*2c3632d1SSimon J. Gerraty 
407*2c3632d1SSimon J. Gerraty     for (tln = node; tln != NULL; tln = tln->next) {
408*2c3632d1SSimon J. Gerraty 	if (match(tln->datum, matchArgs))
409*2c3632d1SSimon J. Gerraty 	    return tln;
410*2c3632d1SSimon J. Gerraty     }
411*2c3632d1SSimon J. Gerraty 
412*2c3632d1SSimon J. Gerraty     return NULL;
413*2c3632d1SSimon J. Gerraty }
414*2c3632d1SSimon J. Gerraty 
415*2c3632d1SSimon J. Gerraty /* Return the first node that contains the given datum, or NULL. */
416*2c3632d1SSimon J. Gerraty LstNode
417*2c3632d1SSimon J. Gerraty Lst_FindDatum(Lst list, const void *datum)
418*2c3632d1SSimon J. Gerraty {
419*2c3632d1SSimon J. Gerraty     LstNode node;
420*2c3632d1SSimon J. Gerraty 
421*2c3632d1SSimon J. Gerraty     assert(list != NULL);
422*2c3632d1SSimon J. Gerraty     assert(datum != NULL);
423*2c3632d1SSimon J. Gerraty 
424*2c3632d1SSimon J. Gerraty     for (node = list->first; node != NULL; node = node->next) {
425*2c3632d1SSimon J. Gerraty 	if (node->datum == datum) {
426*2c3632d1SSimon J. Gerraty 	    return node;
427*2c3632d1SSimon J. Gerraty 	}
428*2c3632d1SSimon J. Gerraty     }
429*2c3632d1SSimon J. Gerraty 
430*2c3632d1SSimon J. Gerraty     return NULL;
431*2c3632d1SSimon J. Gerraty }
432*2c3632d1SSimon J. Gerraty 
433*2c3632d1SSimon J. Gerraty /* Apply the given function to each element of the given list. The function
434*2c3632d1SSimon J. Gerraty  * should return 0 if traversal should continue and non-zero if it should
435*2c3632d1SSimon J. Gerraty  * abort. */
436*2c3632d1SSimon J. Gerraty int
437*2c3632d1SSimon J. Gerraty Lst_ForEach(Lst list, LstActionProc proc, void *procData)
438*2c3632d1SSimon J. Gerraty {
439*2c3632d1SSimon J. Gerraty     if (LstIsEmpty(list))
440*2c3632d1SSimon J. Gerraty 	return 0;		/* XXX: Document what this value means. */
441*2c3632d1SSimon J. Gerraty     return Lst_ForEachFrom(list, Lst_First(list), proc, procData);
442*2c3632d1SSimon J. Gerraty }
443*2c3632d1SSimon J. Gerraty 
444*2c3632d1SSimon J. Gerraty /* Apply the given function to each element of the given list, starting from
445*2c3632d1SSimon J. Gerraty  * the given node. The function should return 0 if traversal should continue,
446*2c3632d1SSimon J. Gerraty  * and non-zero if it should abort. */
447*2c3632d1SSimon J. Gerraty int
448*2c3632d1SSimon J. Gerraty Lst_ForEachFrom(Lst list, LstNode node,
449*2c3632d1SSimon J. Gerraty 		 LstActionProc proc, void *procData)
450*2c3632d1SSimon J. Gerraty {
451*2c3632d1SSimon J. Gerraty     LstNode tln = node;
452*2c3632d1SSimon J. Gerraty     LstNode next;
453*2c3632d1SSimon J. Gerraty     Boolean done;
454*2c3632d1SSimon J. Gerraty     int result;
455*2c3632d1SSimon J. Gerraty 
456*2c3632d1SSimon J. Gerraty     assert(list != NULL);
457*2c3632d1SSimon J. Gerraty     assert(node != NULL);
458*2c3632d1SSimon J. Gerraty     assert(proc != NULL);
459*2c3632d1SSimon J. Gerraty 
460*2c3632d1SSimon J. Gerraty     do {
461*2c3632d1SSimon J. Gerraty 	/*
462*2c3632d1SSimon J. Gerraty 	 * Take care of having the current element deleted out from under
463*2c3632d1SSimon J. Gerraty 	 * us.
464*2c3632d1SSimon J. Gerraty 	 */
465*2c3632d1SSimon J. Gerraty 
466*2c3632d1SSimon J. Gerraty 	next = tln->next;
467*2c3632d1SSimon J. Gerraty 
468*2c3632d1SSimon J. Gerraty 	/*
469*2c3632d1SSimon J. Gerraty 	 * We're done with the traversal if
470*2c3632d1SSimon J. Gerraty 	 *  - the next node to examine doesn't exist and
471*2c3632d1SSimon J. Gerraty 	 *  - nothing's been added after the current node (check this
472*2c3632d1SSimon J. Gerraty 	 *    after proc() has been called).
473*2c3632d1SSimon J. Gerraty 	 */
474*2c3632d1SSimon J. Gerraty 	done = next == NULL;
475*2c3632d1SSimon J. Gerraty 
476*2c3632d1SSimon J. Gerraty 	tln->useCount++;
477*2c3632d1SSimon J. Gerraty 	result = (*proc)(tln->datum, procData);
478*2c3632d1SSimon J. Gerraty 	tln->useCount--;
479*2c3632d1SSimon J. Gerraty 
480*2c3632d1SSimon J. Gerraty 	/*
481*2c3632d1SSimon J. Gerraty 	 * Now check whether a node has been added.
482*2c3632d1SSimon J. Gerraty 	 * Note: this doesn't work if this node was deleted before
483*2c3632d1SSimon J. Gerraty 	 *       the new node was added.
484*2c3632d1SSimon J. Gerraty 	 */
485*2c3632d1SSimon J. Gerraty 	if (next != tln->next) {
486*2c3632d1SSimon J. Gerraty 	    next = tln->next;
487*2c3632d1SSimon J. Gerraty 	    done = 0;
488*2c3632d1SSimon J. Gerraty 	}
489*2c3632d1SSimon J. Gerraty 
490*2c3632d1SSimon J. Gerraty 	if (tln->deleted) {
491*2c3632d1SSimon J. Gerraty 	    free((char *)tln);
492*2c3632d1SSimon J. Gerraty 	}
493*2c3632d1SSimon J. Gerraty 	tln = next;
494*2c3632d1SSimon J. Gerraty     } while (!result && !LstIsEmpty(list) && !done);
495*2c3632d1SSimon J. Gerraty 
496*2c3632d1SSimon J. Gerraty     return result;
497*2c3632d1SSimon J. Gerraty }
498*2c3632d1SSimon J. Gerraty 
499*2c3632d1SSimon J. Gerraty /* Move all nodes from list2 to the end of list1.
500*2c3632d1SSimon J. Gerraty  * List2 is destroyed and freed. */
501*2c3632d1SSimon J. Gerraty void
502*2c3632d1SSimon J. Gerraty Lst_MoveAll(Lst list1, Lst list2)
503*2c3632d1SSimon J. Gerraty {
504*2c3632d1SSimon J. Gerraty     assert(list1 != NULL);
505*2c3632d1SSimon J. Gerraty     assert(list2 != NULL);
506*2c3632d1SSimon J. Gerraty 
507*2c3632d1SSimon J. Gerraty     if (list2->first != NULL) {
508*2c3632d1SSimon J. Gerraty 	list2->first->prev = list1->last;
509*2c3632d1SSimon J. Gerraty 	if (list1->last != NULL) {
510*2c3632d1SSimon J. Gerraty 	    list1->last->next = list2->first;
511*2c3632d1SSimon J. Gerraty 	} else {
512*2c3632d1SSimon J. Gerraty 	    list1->first = list2->first;
513*2c3632d1SSimon J. Gerraty 	}
514*2c3632d1SSimon J. Gerraty 	list1->last = list2->last;
515*2c3632d1SSimon J. Gerraty     }
516*2c3632d1SSimon J. Gerraty     free(list2);
517*2c3632d1SSimon J. Gerraty }
518*2c3632d1SSimon J. Gerraty 
519*2c3632d1SSimon J. Gerraty /* Copy the element data from src to the start of dst. */
520*2c3632d1SSimon J. Gerraty void
521*2c3632d1SSimon J. Gerraty Lst_PrependAll(Lst dst, Lst src)
522*2c3632d1SSimon J. Gerraty {
523*2c3632d1SSimon J. Gerraty     LstNode node;
524*2c3632d1SSimon J. Gerraty     for (node = src->last; node != NULL; node = node->prev)
525*2c3632d1SSimon J. Gerraty 	Lst_Prepend(dst, node->datum);
526*2c3632d1SSimon J. Gerraty }
527*2c3632d1SSimon J. Gerraty 
528*2c3632d1SSimon J. Gerraty /* Copy the element data from src to the end of dst. */
529*2c3632d1SSimon J. Gerraty void
530*2c3632d1SSimon J. Gerraty Lst_AppendAll(Lst dst, Lst src)
531*2c3632d1SSimon J. Gerraty {
532*2c3632d1SSimon J. Gerraty     LstNode node;
533*2c3632d1SSimon J. Gerraty     for (node = src->first; node != NULL; node = node->next)
534*2c3632d1SSimon J. Gerraty 	Lst_Append(dst, node->datum);
535*2c3632d1SSimon J. Gerraty }
536*2c3632d1SSimon J. Gerraty 
537*2c3632d1SSimon J. Gerraty /*
538*2c3632d1SSimon J. Gerraty  * these functions are for dealing with a list as a table, of sorts.
539*2c3632d1SSimon J. Gerraty  * An idea of the "current element" is kept and used by all the functions
540*2c3632d1SSimon J. Gerraty  * between Lst_Open() and Lst_Close().
541*2c3632d1SSimon J. Gerraty  *
542*2c3632d1SSimon J. Gerraty  * The sequential functions access the list in a slightly different way.
543*2c3632d1SSimon J. Gerraty  * CurPtr points to their idea of the current node in the list and they
544*2c3632d1SSimon J. Gerraty  * access the list based on it.
545*2c3632d1SSimon J. Gerraty  */
546*2c3632d1SSimon J. Gerraty 
547*2c3632d1SSimon J. Gerraty /* Open a list for sequential access. A list can still be searched, etc.,
548*2c3632d1SSimon J. Gerraty  * without confusing these functions. */
549*2c3632d1SSimon J. Gerraty void
550*2c3632d1SSimon J. Gerraty Lst_Open(Lst list)
551*2c3632d1SSimon J. Gerraty {
552*2c3632d1SSimon J. Gerraty     assert(list != NULL);
553*2c3632d1SSimon J. Gerraty     assert(!list->isOpen);
554*2c3632d1SSimon J. Gerraty 
555*2c3632d1SSimon J. Gerraty     list->isOpen = TRUE;
556*2c3632d1SSimon J. Gerraty     list->lastAccess = LstIsEmpty(list) ? Head : Unknown;
557*2c3632d1SSimon J. Gerraty     list->curr = NULL;
558*2c3632d1SSimon J. Gerraty }
559*2c3632d1SSimon J. Gerraty 
560*2c3632d1SSimon J. Gerraty /* Return the next node for the given list, or NULL if the end has been
561*2c3632d1SSimon J. Gerraty  * reached. */
562*2c3632d1SSimon J. Gerraty LstNode
563*2c3632d1SSimon J. Gerraty Lst_Next(Lst list)
564*2c3632d1SSimon J. Gerraty {
565*2c3632d1SSimon J. Gerraty     LstNode node;
566*2c3632d1SSimon J. Gerraty 
567*2c3632d1SSimon J. Gerraty     assert(list != NULL);
568*2c3632d1SSimon J. Gerraty     assert(list->isOpen);
569*2c3632d1SSimon J. Gerraty 
570*2c3632d1SSimon J. Gerraty     list->prev = list->curr;
571*2c3632d1SSimon J. Gerraty 
572*2c3632d1SSimon J. Gerraty     if (list->curr == NULL) {
573*2c3632d1SSimon J. Gerraty 	if (list->lastAccess == Unknown) {
574*2c3632d1SSimon J. Gerraty 	    /*
575*2c3632d1SSimon J. Gerraty 	     * If we're just starting out, lastAccess will be Unknown.
576*2c3632d1SSimon J. Gerraty 	     * Then we want to start this thing off in the right
577*2c3632d1SSimon J. Gerraty 	     * direction -- at the start with lastAccess being Middle.
578*2c3632d1SSimon J. Gerraty 	     */
579*2c3632d1SSimon J. Gerraty 	    list->curr = node = list->first;
580*2c3632d1SSimon J. Gerraty 	    list->lastAccess = Middle;
581*2c3632d1SSimon J. Gerraty 	} else {
582*2c3632d1SSimon J. Gerraty 	    node = NULL;
583*2c3632d1SSimon J. Gerraty 	    list->lastAccess = Tail;
584*2c3632d1SSimon J. Gerraty 	}
585*2c3632d1SSimon J. Gerraty     } else {
586*2c3632d1SSimon J. Gerraty 	node = list->curr->next;
587*2c3632d1SSimon J. Gerraty 	list->curr = node;
588*2c3632d1SSimon J. Gerraty 
589*2c3632d1SSimon J. Gerraty 	if (node == list->first || node == NULL) {
590*2c3632d1SSimon J. Gerraty 	    /*
591*2c3632d1SSimon J. Gerraty 	     * If back at the front, then we've hit the end...
592*2c3632d1SSimon J. Gerraty 	     */
593*2c3632d1SSimon J. Gerraty 	    list->lastAccess = Tail;
594*2c3632d1SSimon J. Gerraty 	} else {
595*2c3632d1SSimon J. Gerraty 	    /*
596*2c3632d1SSimon J. Gerraty 	     * Reset to Middle if gone past first.
597*2c3632d1SSimon J. Gerraty 	     */
598*2c3632d1SSimon J. Gerraty 	    list->lastAccess = Middle;
599*2c3632d1SSimon J. Gerraty 	}
600*2c3632d1SSimon J. Gerraty     }
601*2c3632d1SSimon J. Gerraty 
602*2c3632d1SSimon J. Gerraty     return node;
603*2c3632d1SSimon J. Gerraty }
604*2c3632d1SSimon J. Gerraty 
605*2c3632d1SSimon J. Gerraty /* Close a list which was opened for sequential access. */
606*2c3632d1SSimon J. Gerraty void
607*2c3632d1SSimon J. Gerraty Lst_Close(Lst list)
608*2c3632d1SSimon J. Gerraty {
609*2c3632d1SSimon J. Gerraty     assert(list != NULL);
610*2c3632d1SSimon J. Gerraty     assert(list->isOpen);
611*2c3632d1SSimon J. Gerraty 
612*2c3632d1SSimon J. Gerraty     list->isOpen = FALSE;
613*2c3632d1SSimon J. Gerraty     list->lastAccess = Unknown;
614*2c3632d1SSimon J. Gerraty }
615*2c3632d1SSimon J. Gerraty 
616*2c3632d1SSimon J. Gerraty 
617*2c3632d1SSimon J. Gerraty /*
618*2c3632d1SSimon J. Gerraty  * for using the list as a queue
619*2c3632d1SSimon J. Gerraty  */
620*2c3632d1SSimon J. Gerraty 
621*2c3632d1SSimon J. Gerraty /* Add the datum to the tail of the given list. */
622*2c3632d1SSimon J. Gerraty void
623*2c3632d1SSimon J. Gerraty Lst_Enqueue(Lst list, void *datum)
624*2c3632d1SSimon J. Gerraty {
625*2c3632d1SSimon J. Gerraty     Lst_Append(list, datum);
626*2c3632d1SSimon J. Gerraty }
627*2c3632d1SSimon J. Gerraty 
628*2c3632d1SSimon J. Gerraty /* Remove and return the datum at the head of the given list. */
629*2c3632d1SSimon J. Gerraty void *
630*2c3632d1SSimon J. Gerraty Lst_Dequeue(Lst list)
631*2c3632d1SSimon J. Gerraty {
632*2c3632d1SSimon J. Gerraty     void *datum;
633*2c3632d1SSimon J. Gerraty 
634*2c3632d1SSimon J. Gerraty     assert(list != NULL);
635*2c3632d1SSimon J. Gerraty     assert(!LstIsEmpty(list));
636*2c3632d1SSimon J. Gerraty 
637*2c3632d1SSimon J. Gerraty     datum = list->first->datum;
638*2c3632d1SSimon J. Gerraty     Lst_Remove(list, list->first);
639*2c3632d1SSimon J. Gerraty     assert(datum != NULL);
640*2c3632d1SSimon J. Gerraty     return datum;
641*2c3632d1SSimon J. Gerraty }
642