]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.bin/make/lst.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / usr.bin / make / lst.c
1 /*-
2  * Copyright (c) 1988, 1989, 1990, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Adam de Boor.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD$
33  */
34
35 /*-
36  * lst.c --
37  *      Routines to maintain a linked list of objects.
38  */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42
43 #include "lst.h"
44 #include "make.h"
45 #include "util.h"
46
47 /**
48  * Lst_Append
49  *      Create a new node and add it to the given list after the given node.
50  *
51  * Arguments:
52  *      l       affected list
53  *      ln      node after which to append the datum
54  *      d       said datum
55  *
56  * Side Effects:
57  *      A new LstNode is created and linked in to the List. The lastPtr
58  *      field of the List will be altered if ln is the last node in the
59  *      list. lastPtr and firstPtr will alter if the list was empty and
60  *      ln was NULL.
61  */
62 void
63 Lst_Append(Lst *list, LstNode *ln, void *d)
64 {
65         LstNode *nLNode;
66
67         nLNode = emalloc(sizeof(*nLNode));
68         nLNode->datum = d;
69
70         if (ln == NULL) {
71                 nLNode->nextPtr = nLNode->prevPtr = NULL;
72                 list->firstPtr = list->lastPtr = nLNode;
73         } else {
74                 nLNode->prevPtr = ln;
75                 nLNode->nextPtr = ln->nextPtr;
76
77                 ln->nextPtr = nLNode;
78                 if (nLNode->nextPtr != NULL) {
79                         nLNode->nextPtr->prevPtr = nLNode;
80                 }
81
82                 if (ln == list->lastPtr) {
83                         list->lastPtr = nLNode;
84                 }
85         }
86 }
87
88 /**
89  * Lst_Concat
90  *      Concatenate two lists. New elements are created to hold the data
91  *      elements, if specified, but the elements themselves are not copied.
92  *      If the elements should be duplicated to avoid confusion with another
93  *      list, the Lst_Duplicate function should be called first.
94  *
95  * Arguments:
96  *      list1   The list to which list2 is to be appended
97  *      list2   The list to append to list1
98  *      flags   LST_CONCNEW if LstNode's should be duplicated
99  *              LST_CONCLINK if should just be relinked
100  *
101  * Side Effects:
102  *      New elements are created and appended the the first list.
103  */
104 void
105 Lst_Concat(Lst *list1, Lst *list2, int flags)
106 {
107         LstNode *ln;    /* original LstNode */
108         LstNode *nln;   /* new LstNode */
109         LstNode *last;  /* the last element in the list. Keeps
110                          * bookkeeping until the end */
111
112         if (list2->firstPtr == NULL)
113                 return;
114
115         if (flags == LST_CONCLINK) {
116                 /*
117                  * Link the first element of the second list to the last
118                  * element of the first list. If the first list isn't empty,
119                  * we then link the last element of the list to the first
120                  * element of the second list. The last element of the second
121                  * list, if it exists, then becomes the last element of the
122                  * first list.
123                  */
124                 list2->firstPtr->prevPtr = list1->lastPtr;
125                 if (list1->lastPtr != NULL)
126                         list1->lastPtr->nextPtr = list2->firstPtr;
127                 else
128                         list1->firstPtr = list2->firstPtr;
129                 list1->lastPtr = list2->lastPtr;
130
131                 Lst_Init(list2);
132         } else {
133                 /*
134                  * The loop simply goes through the entire second list creating
135                  * new LstNodes and filling in the nextPtr, and prevPtr to fit
136                  * into list1 and its datum field from the datum field of the
137                  * corresponding element in list2. The 'last' node follows the
138                  * last of the new nodes along until the entire list2 has been
139                  * appended. Only then does the bookkeeping catch up with the
140                  * changes. During the first iteration of the loop, if 'last'
141                  * is NULL, the first list must have been empty so the
142                  * newly-created node is made the first node of the list.
143                  */
144                 for (last = list1->lastPtr, ln = list2->firstPtr;
145                     ln != NULL;
146                     ln = ln->nextPtr) {
147                         nln = emalloc(sizeof(*nln));
148                         nln->datum = ln->datum;
149                         if (last != NULL) {
150                                 last->nextPtr = nln;
151                         } else {
152                                 list1->firstPtr = nln;
153                         }
154                         nln->prevPtr = last;
155                         last = nln;
156                 }
157
158                 /*
159                  * Finish bookkeeping. The last new element becomes the last
160                  * element of list one.
161                  */
162                 list1->lastPtr = last;
163                 last->nextPtr = NULL;
164         }
165 }
166
167 /**
168  * Lst_DeQueue
169  *      Remove and return the datum at the head of the given list.
170  *
171  * Results:
172  *      The datum in the node at the head or (ick) NULL if the list
173  *      is empty.
174  *
175  * Side Effects:
176  *      The head node is removed from the list.
177  */
178 void *
179 Lst_DeQueue(Lst *l)
180 {
181         void *rd;
182         LstNode *tln;
183
184         tln = Lst_First(l);
185         if (tln == NULL) {
186                 return (NULL);
187         }
188
189         rd = tln->datum;
190         Lst_Remove(l, tln);
191         return (rd);
192 }
193
194 /**
195  * Lst_Destroy
196  *      Destroy a list and free all its resources. If the freeProc is
197  *      given, it is called with the datum from each node in turn before
198  *      the node is freed.
199  *
200  * Side Effects:
201  *      The given list is freed in its entirety.
202  */
203 void
204 Lst_Destroy(Lst *list, FreeProc *freeProc)
205 {
206         LstNode *ln;
207
208         if (list->firstPtr == NULL)
209                 return;
210
211         if (freeProc != NOFREE) {
212                 while ((ln = list->firstPtr) != NULL) {
213                         list->firstPtr = ln->nextPtr;
214                         (*freeProc)(ln->datum);
215                         free(ln);
216                 }
217         } else {
218                 while ((ln = list->firstPtr) != NULL) {
219                         list->firstPtr = ln->nextPtr;
220                         free(ln);
221                 }
222         }
223         list->lastPtr = NULL;
224 }
225
226 /**
227  * Lst_Duplicate
228  *      Duplicate an entire list. If a function to copy a void * is
229  *      given, the individual client elements will be duplicated as well.
230  *
231  * Arguments:
232  *      dst     the destination list (initialized)
233  *      src     the list to duplicate
234  *      copyProc A function to duplicate each void
235  */
236 void
237 Lst_Duplicate(Lst *dst, Lst *src, DuplicateProc *copyProc)
238 {
239         LstNode *ln;
240
241         ln = src->firstPtr;
242         while (ln != NULL) {
243                 if (copyProc != NOCOPY)
244                         Lst_AtEnd(dst, (*copyProc)(ln->datum));
245                 else
246                         Lst_AtEnd(dst, ln->datum);
247                 ln = ln->nextPtr;
248         }
249 }
250
251 /**
252  * Lst_Insert
253  *      Insert a new node with the given piece of data before the given
254  *      node in the given list.
255  *
256  * Parameters:
257  *      l       list to manipulate
258  *      ln      node before which to insert d
259  *      d       datum to be inserted
260  *
261  * Side Effects:
262  *      the firstPtr field will be changed if ln is the first node in the
263  *      list.
264  */
265 void
266 Lst_Insert(Lst *list, LstNode *ln, void *d)
267 {
268         LstNode *nLNode;        /* new lnode for d */
269
270         nLNode = emalloc(sizeof(*nLNode));
271         nLNode->datum = d;
272
273         if (ln == NULL) {
274                 nLNode->prevPtr = nLNode->nextPtr = NULL;
275                 list->firstPtr = list->lastPtr = nLNode;
276         } else {
277                 nLNode->prevPtr = ln->prevPtr;
278                 nLNode->nextPtr = ln;
279
280                 if (nLNode->prevPtr != NULL) {
281                         nLNode->prevPtr->nextPtr = nLNode;
282                 }
283                 ln->prevPtr = nLNode;
284
285                 if (ln == list->firstPtr) {
286                         list->firstPtr = nLNode;
287                 }
288         }
289 }
290
291 LstNode *
292 Lst_Member(Lst *list, void *d)
293 {
294         LstNode *lNode;
295
296         lNode = list->firstPtr;
297         if (lNode == NULL) {
298                 return (NULL);
299         }
300
301         do {
302                 if (lNode->datum == d) {
303                         return (lNode);
304                 }
305                 lNode = lNode->nextPtr;
306         } while (lNode != NULL && lNode != list->firstPtr);
307
308         return (NULL);
309 }
310
311 /**
312  * Lst_Remove
313  *      Remove the given node from the given list.
314  *
315  * Side Effects:
316  *      The list's firstPtr will be set to NULL if ln is the last
317  *      node on the list. firsPtr and lastPtr will be altered if ln is
318  *      either the first or last node, respectively, on the list.
319  */
320 void
321 Lst_Remove(Lst *list, LstNode *ln)
322 {
323         /*
324          * unlink it from the list
325          */
326         if (ln->nextPtr != NULL)
327                 /* unlink from the backward chain */
328                 ln->nextPtr->prevPtr = ln->prevPtr;
329         else
330                 /* this was the last element */
331                 list->lastPtr = ln->prevPtr;
332
333         if (ln->prevPtr != NULL)
334                 /* unlink from the forward chain */
335                 ln->prevPtr->nextPtr = ln->nextPtr;
336         else
337                 /* this was the first element */
338                 list->firstPtr = ln->nextPtr;
339
340         /*
341          * note that the datum is unmolested. The caller must free it as
342          * necessary and as expected.
343          */
344         free(ln);
345 }