PageRenderTime 23ms CodeModel.GetById 11ms app.highlight 8ms RepoModel.GetById 2ms app.codeStats 0ms

/usr.bin/make/lst.c

https://bitbucket.org/freebsd/freebsd-head/
C | 344 lines | 155 code | 33 blank | 156 comment | 53 complexity | 03c110306a1c073274519c22656cba75 MD5 | raw file
  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 "util.h"
 45
 46/**
 47 * Lst_Append
 48 *	Create a new node and add it to the given list after the given node.
 49 *
 50 * Arguments:
 51 *	l	affected list
 52 *	ln	node after which to append the datum
 53 *	d	said datum
 54 *
 55 * Side Effects:
 56 *	A new LstNode is created and linked in to the List. The lastPtr
 57 *	field of the List will be altered if ln is the last node in the
 58 *	list. lastPtr and firstPtr will alter if the list was empty and
 59 *	ln was NULL.
 60 */
 61void
 62Lst_Append(Lst *list, LstNode *ln, void *d)
 63{
 64	LstNode *nLNode;
 65
 66	nLNode = emalloc(sizeof(*nLNode));
 67	nLNode->datum = d;
 68
 69	if (ln == NULL) {
 70		nLNode->nextPtr = nLNode->prevPtr = NULL;
 71		list->firstPtr = list->lastPtr = nLNode;
 72	} else {
 73		nLNode->prevPtr = ln;
 74		nLNode->nextPtr = ln->nextPtr;
 75
 76		ln->nextPtr = nLNode;
 77		if (nLNode->nextPtr != NULL) {
 78			nLNode->nextPtr->prevPtr = nLNode;
 79		}
 80
 81		if (ln == list->lastPtr) {
 82			list->lastPtr = nLNode;
 83		}
 84	}
 85}
 86
 87/**
 88 * Lst_Concat
 89 *	Concatenate two lists. New elements are created to hold the data
 90 *	elements, if specified, but the elements themselves are not copied.
 91 *	If the elements should be duplicated to avoid confusion with another
 92 *	list, the Lst_Duplicate function should be called first.
 93 *
 94 * Arguments:
 95 *	list1	The list to which list2 is to be appended
 96 *	list2	The list to append to list1
 97 *	flags	LST_CONCNEW if LstNode's should be duplicated
 98 *		LST_CONCLINK if should just be relinked
 99 *
100 * Side Effects:
101 *	New elements are created and appended the first list.
102 */
103void
104Lst_Concat(Lst *list1, Lst *list2, int flags)
105{
106	LstNode	*ln;	/* original LstNode */
107	LstNode	*nln;	/* new LstNode */
108	LstNode	*last;	/* the last element in the list. Keeps
109			 * bookkeeping until the end */
110
111	if (list2->firstPtr == NULL)
112		return;
113
114	if (flags == LST_CONCLINK) {
115		/*
116		 * Link the first element of the second list to the last
117		 * element of the first list. If the first list isn't empty,
118		 * we then link the last element of the list to the first
119		 * element of the second list. The last element of the second
120		 * list, if it exists, then becomes the last element of the
121		 * first list.
122		 */
123		list2->firstPtr->prevPtr = list1->lastPtr;
124		if (list1->lastPtr != NULL)
125			list1->lastPtr->nextPtr = list2->firstPtr;
126		else
127			list1->firstPtr = list2->firstPtr;
128		list1->lastPtr = list2->lastPtr;
129
130		Lst_Init(list2);
131	} else {
132		/*
133		 * The loop simply goes through the entire second list creating
134		 * new LstNodes and filling in the nextPtr, and prevPtr to fit
135		 * into list1 and its datum field from the datum field of the
136		 * corresponding element in list2. The 'last' node follows the
137		 * last of the new nodes along until the entire list2 has been
138		 * appended. Only then does the bookkeeping catch up with the
139		 * changes. During the first iteration of the loop, if 'last'
140		 * is NULL, the first list must have been empty so the
141		 * newly-created node is made the first node of the list.
142		 */
143		for (last = list1->lastPtr, ln = list2->firstPtr;
144		    ln != NULL;
145		    ln = ln->nextPtr) {
146			nln = emalloc(sizeof(*nln));
147			nln->datum = ln->datum;
148			if (last != NULL) {
149				last->nextPtr = nln;
150			} else {
151				list1->firstPtr = nln;
152			}
153			nln->prevPtr = last;
154			last = nln;
155		}
156
157		/*
158		 * Finish bookkeeping. The last new element becomes the last
159		 * element of list one.
160		 */
161		list1->lastPtr = last;
162		last->nextPtr = NULL;
163	}
164}
165
166/**
167 * Lst_DeQueue
168 *	Remove and return the datum at the head of the given list.
169 *
170 * Results:
171 *	The datum in the node at the head or (ick) NULL if the list
172 *	is empty.
173 *
174 * Side Effects:
175 *	The head node is removed from the list.
176 */
177void *
178Lst_DeQueue(Lst *l)
179{
180	void *rd;
181	LstNode *tln;
182
183	tln = Lst_First(l);
184	if (tln == NULL) {
185		return (NULL);
186	}
187
188	rd = tln->datum;
189	Lst_Remove(l, tln);
190	return (rd);
191}
192
193/**
194 * Lst_Destroy
195 *	Destroy a list and free all its resources. If the freeProc is
196 *	given, it is called with the datum from each node in turn before
197 *	the node is freed.
198 *
199 * Side Effects:
200 *	The given list is freed in its entirety.
201 */
202void
203Lst_Destroy(Lst *list, FreeProc *freeProc)
204{
205	LstNode *ln;
206
207	if (list->firstPtr == NULL)
208		return;
209
210	if (freeProc != NOFREE) {
211		while ((ln = list->firstPtr) != NULL) {
212			list->firstPtr = ln->nextPtr;
213			(*freeProc)(ln->datum);
214			free(ln);
215		}
216	} else {
217		while ((ln = list->firstPtr) != NULL) {
218			list->firstPtr = ln->nextPtr;
219			free(ln);
220		}
221	}
222	list->lastPtr = NULL;
223}
224
225/**
226 * Lst_Duplicate
227 *	Duplicate an entire list. If a function to copy a void * is
228 *	given, the individual client elements will be duplicated as well.
229 *
230 * Arguments:
231 *	dst	the destination list (initialized)
232 *	src	the list to duplicate
233 *	copyProc A function to duplicate each void
234 */
235void
236Lst_Duplicate(Lst *dst, Lst *src, DuplicateProc *copyProc)
237{
238	LstNode *ln;
239
240	ln = src->firstPtr;
241	while (ln != NULL) {
242		if (copyProc != NOCOPY)
243			Lst_AtEnd(dst, (*copyProc)(ln->datum));
244		else
245			Lst_AtEnd(dst, ln->datum);
246		ln = ln->nextPtr;
247	}
248}
249
250/**
251 * Lst_Insert
252 *	Insert a new node with the given piece of data before the given
253 *	node in the given list.
254 *
255 * Parameters:
256 *	l	list to manipulate
257 *	ln	node before which to insert d
258 *	d	datum to be inserted
259 *
260 * Side Effects:
261 *	the firstPtr field will be changed if ln is the first node in the
262 *	list.
263 */
264void
265Lst_Insert(Lst *list, LstNode *ln, void *d)
266{
267	LstNode *nLNode;	/* new lnode for d */
268
269	nLNode = emalloc(sizeof(*nLNode));
270	nLNode->datum = d;
271
272	if (ln == NULL) {
273		nLNode->prevPtr = nLNode->nextPtr = NULL;
274		list->firstPtr = list->lastPtr = nLNode;
275	} else {
276		nLNode->prevPtr = ln->prevPtr;
277		nLNode->nextPtr = ln;
278
279		if (nLNode->prevPtr != NULL) {
280			nLNode->prevPtr->nextPtr = nLNode;
281		}
282		ln->prevPtr = nLNode;
283
284		if (ln == list->firstPtr) {
285			list->firstPtr = nLNode;
286		}
287	}
288}
289
290LstNode *
291Lst_Member(Lst *list, void *d)
292{
293	LstNode *lNode;
294
295	lNode = list->firstPtr;
296	if (lNode == NULL) {
297		return (NULL);
298	}
299
300	do {
301		if (lNode->datum == d) {
302			return (lNode);
303		}
304		lNode = lNode->nextPtr;
305	} while (lNode != NULL && lNode != list->firstPtr);
306
307	return (NULL);
308}
309
310/**
311 * Lst_Remove
312 *	Remove the given node from the given list.
313 *
314 * Side Effects:
315 *	The list's firstPtr will be set to NULL if ln is the last
316 *	node on the list. firsPtr and lastPtr will be altered if ln is
317 *	either the first or last node, respectively, on the list.
318 */
319void
320Lst_Remove(Lst *list, LstNode *ln)
321{
322	/*
323	 * unlink it from the list
324	 */
325	if (ln->nextPtr != NULL)
326		/* unlink from the backward chain */
327		ln->nextPtr->prevPtr = ln->prevPtr;
328	else
329		/* this was the last element */
330		list->lastPtr = ln->prevPtr;
331
332	if (ln->prevPtr != NULL)
333		/* unlink from the forward chain */
334		ln->prevPtr->nextPtr = ln->nextPtr;
335	else
336		/* this was the first element */
337		list->firstPtr = ln->nextPtr;
338
339	/*
340	 * note that the datum is unmolested. The caller must free it as
341	 * necessary and as expected.
342	 */
343	free(ln);
344}