lst.c revision 1.67
11.67Srillig/* $NetBSD: lst.c,v 1.67 2020/09/24 07:11:29 rillig Exp $ */
21.1Srillig
31.1Srillig/*
41.1Srillig * Copyright (c) 1988, 1989, 1990, 1993
51.1Srillig *	The Regents of the University of California.  All rights reserved.
61.1Srillig *
71.1Srillig * This code is derived from software contributed to Berkeley by
81.1Srillig * Adam de Boor.
91.1Srillig *
101.1Srillig * Redistribution and use in source and binary forms, with or without
111.1Srillig * modification, are permitted provided that the following conditions
121.1Srillig * are met:
131.1Srillig * 1. Redistributions of source code must retain the above copyright
141.1Srillig *    notice, this list of conditions and the following disclaimer.
151.1Srillig * 2. Redistributions in binary form must reproduce the above copyright
161.1Srillig *    notice, this list of conditions and the following disclaimer in the
171.1Srillig *    documentation and/or other materials provided with the distribution.
181.1Srillig * 3. Neither the name of the University nor the names of its contributors
191.1Srillig *    may be used to endorse or promote products derived from this software
201.1Srillig *    without specific prior written permission.
211.1Srillig *
221.1Srillig * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
231.1Srillig * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
241.1Srillig * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
251.1Srillig * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
261.1Srillig * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
271.1Srillig * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
281.1Srillig * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
291.1Srillig * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
301.1Srillig * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
311.1Srillig * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
321.1Srillig * SUCH DAMAGE.
331.1Srillig */
341.1Srillig
351.30Sskrll#include <stdint.h>
361.8Srillig
371.19Srillig#include "make.h"
381.1Srillig
391.67SrilligMAKE_RCSID("$NetBSD: lst.c,v 1.67 2020/09/24 07:11:29 rillig Exp $");
401.1Srillig
411.13Srilligstruct ListNode {
421.15Srillig    struct ListNode *prev;	/* previous element in list */
431.15Srillig    struct ListNode *next;	/* next in list */
441.7Srillig    uint8_t useCount;		/* Count of functions using the node.
451.4Srillig				 * node may not be deleted until count
461.4Srillig				 * goes to 0 */
471.7Srillig    Boolean deleted;		/* List node should be removed when done */
481.39Srillig    union {
491.39Srillig	void *datum;		/* datum associated with this element */
501.39Srillig	const GNode *gnode;	/* alias, just for debugging */
511.39Srillig	const char *str;	/* alias, just for debugging */
521.39Srillig    };
531.13Srillig};
541.1Srillig
551.1Srilligtypedef enum {
561.1Srillig    Head, Middle, Tail, Unknown
571.1Srillig} Where;
581.1Srillig
591.13Srilligstruct List {
601.65Srillig    ListNode *first;		/* first node in list */
611.65Srillig    ListNode *last;		/* last node in list */
621.20Srillig
631.20Srillig    /* fields for sequential access */
641.21Srillig    Boolean isOpen;		/* true if list has been Lst_Open'ed */
651.15Srillig    Where lastAccess;		/* Where in the list the last access was */
661.65Srillig    ListNode *curr;		/* current node, if open. NULL if
671.4Srillig				 * *just* opened */
681.65Srillig    ListNode *prev;		/* Previous node, if open. Used by Lst_Remove */
691.13Srillig};
701.1Srillig
711.22Srillig/* Allocate and initialize a list node.
721.22Srillig *
731.22Srillig * The fields 'prev' and 'next' must be initialized by the caller.
741.22Srillig */
751.65Srilligstatic ListNode *
761.12SrilligLstNodeNew(void *datum)
771.12Srillig{
781.65Srillig    ListNode *node = bmake_malloc(sizeof *node);
791.16Srillig    node->useCount = 0;
801.16Srillig    node->deleted = FALSE;
811.16Srillig    node->datum = datum;
821.16Srillig    return node;
831.12Srillig}
841.12Srillig
851.2Srilligstatic Boolean
861.65SrilligLstIsEmpty(List *list)
871.2Srillig{
881.16Srillig    return list->first == NULL;
891.2Srillig}
901.1Srillig
911.5Srillig/* Create and initialize a new, empty list. */
921.65SrilligList *
931.5SrilligLst_Init(void)
941.1Srillig{
951.65Srillig    List *list = bmake_malloc(sizeof *list);
961.1Srillig
971.16Srillig    list->first = NULL;
981.16Srillig    list->last = NULL;
991.16Srillig    list->isOpen = FALSE;
1001.16Srillig    list->lastAccess = Unknown;
1011.1Srillig
1021.16Srillig    return list;
1031.1Srillig}
1041.1Srillig
1051.14Srillig/* Duplicate an entire list, usually by copying the datum pointers.
1061.14Srillig * If copyProc is given, that function is used to create the new datum from the
1071.35Srillig * old datum, usually by creating a copy of it. */
1081.65SrilligList *
1091.65SrilligLst_Copy(List *list, LstCopyProc copyProc)
1101.1Srillig{
1111.65Srillig    List *newList;
1121.65Srillig    ListNode *node;
1131.1Srillig
1141.52Srillig    assert(list != NULL);
1151.1Srillig
1161.16Srillig    newList = Lst_Init();
1171.1Srillig
1181.35Srillig    for (node = list->first; node != NULL; node = node->next) {
1191.35Srillig	void *datum = copyProc != NULL ? copyProc(node->datum) : node->datum;
1201.50Srillig	Lst_Append(newList, datum);
1211.1Srillig    }
1221.1Srillig
1231.16Srillig    return newList;
1241.1Srillig}
1251.1Srillig
1261.42Srillig/* Free a list and all its nodes. The list data itself are not freed though. */
1271.42Srilligvoid
1281.65SrilligLst_Free(List *list)
1291.42Srillig{
1301.65Srillig    ListNode *node;
1311.65Srillig    ListNode *next;
1321.42Srillig
1331.52Srillig    assert(list != NULL);
1341.42Srillig
1351.42Srillig    for (node = list->first; node != NULL; node = next) {
1361.42Srillig	next = node->next;
1371.42Srillig	free(node);
1381.42Srillig    }
1391.42Srillig
1401.42Srillig    free(list);
1411.42Srillig}
1421.42Srillig
1431.59Srillig/* Destroy a list and free all its resources. The freeProc is called with the
1441.59Srillig * datum from each node in turn before the node is freed. */
1451.1Srilligvoid
1461.65SrilligLst_Destroy(List *list, LstFreeProc freeProc)
1471.1Srillig{
1481.65Srillig    ListNode *node;
1491.65Srillig    ListNode *next;
1501.1Srillig
1511.52Srillig    assert(list != NULL);
1521.42Srillig    assert(freeProc != NULL);
1531.1Srillig
1541.42Srillig    for (node = list->first; node != NULL; node = next) {
1551.42Srillig	next = node->next;
1561.42Srillig	freeProc(node->datum);
1571.42Srillig	free(node);
1581.1Srillig    }
1591.1Srillig
1601.1Srillig    free(list);
1611.1Srillig}
1621.1Srillig
1631.1Srillig/*
1641.1Srillig * Functions to modify a list
1651.1Srillig */
1661.1Srillig
1671.14Srillig/* Insert a new node with the given piece of data before the given node in the
1681.14Srillig * given list. */
1691.26Srilligvoid
1701.65SrilligLst_InsertBefore(List *list, ListNode *node, void *datum)
1711.26Srillig{
1721.65Srillig    ListNode *newNode;
1731.26Srillig
1741.52Srillig    assert(list != NULL);
1751.26Srillig    assert(!LstIsEmpty(list));
1761.52Srillig    assert(node != NULL);
1771.26Srillig    assert(datum != NULL);
1781.26Srillig
1791.26Srillig    newNode = LstNodeNew(datum);
1801.26Srillig    newNode->prev = node->prev;
1811.26Srillig    newNode->next = node;
1821.26Srillig
1831.26Srillig    if (node->prev != NULL) {
1841.26Srillig	node->prev->next = newNode;
1851.26Srillig    }
1861.26Srillig    node->prev = newNode;
1871.26Srillig
1881.26Srillig    if (node == list->first) {
1891.26Srillig	list->first = newNode;
1901.26Srillig    }
1911.26Srillig}
1921.26Srillig
1931.22Srillig/* Add a piece of data at the start of the given list. */
1941.22Srilligvoid
1951.65SrilligLst_Prepend(List *list, void *datum)
1961.22Srillig{
1971.65Srillig    ListNode *node;
1981.22Srillig
1991.52Srillig    assert(list != NULL);
2001.22Srillig    assert(datum != NULL);
2011.22Srillig
2021.22Srillig    node = LstNodeNew(datum);
2031.22Srillig    node->prev = NULL;
2041.22Srillig    node->next = list->first;
2051.22Srillig
2061.22Srillig    if (list->first == NULL) {
2071.22Srillig	list->first = node;
2081.22Srillig	list->last = node;
2091.22Srillig    } else {
2101.22Srillig	list->first->prev = node;
2111.22Srillig	list->first = node;
2121.22Srillig    }
2131.22Srillig}
2141.22Srillig
2151.21Srillig/* Add a piece of data at the end of the given list. */
2161.21Srilligvoid
2171.65SrilligLst_Append(List *list, void *datum)
2181.21Srillig{
2191.65Srillig    ListNode *node;
2201.21Srillig
2211.52Srillig    assert(list != NULL);
2221.21Srillig    assert(datum != NULL);
2231.21Srillig
2241.21Srillig    node = LstNodeNew(datum);
2251.21Srillig    node->prev = list->last;
2261.21Srillig    node->next = NULL;
2271.21Srillig
2281.21Srillig    if (list->last == NULL) {
2291.21Srillig	list->first = node;
2301.21Srillig	list->last = node;
2311.21Srillig    } else {
2321.21Srillig	list->last->next = node;
2331.21Srillig	list->last = node;
2341.21Srillig    }
2351.21Srillig}
2361.21Srillig
2371.8Srillig/* Remove the given node from the given list.
2381.8Srillig * The datum stored in the node must be freed by the caller, if necessary. */
2391.8Srilligvoid
2401.65SrilligLst_Remove(List *list, ListNode *node)
2411.1Srillig{
2421.52Srillig    assert(list != NULL);
2431.52Srillig    assert(node != NULL);
2441.1Srillig
2451.1Srillig    /*
2461.1Srillig     * unlink it from the list
2471.1Srillig     */
2481.16Srillig    if (node->next != NULL) {
2491.16Srillig	node->next->prev = node->prev;
2501.1Srillig    }
2511.16Srillig    if (node->prev != NULL) {
2521.16Srillig	node->prev->next = node->next;
2531.1Srillig    }
2541.1Srillig
2551.1Srillig    /*
2561.15Srillig     * if either the first or last of the list point to this node,
2571.1Srillig     * adjust them accordingly
2581.1Srillig     */
2591.16Srillig    if (list->first == node) {
2601.16Srillig	list->first = node->next;
2611.1Srillig    }
2621.16Srillig    if (list->last == node) {
2631.16Srillig	list->last = node->prev;
2641.1Srillig    }
2651.1Srillig
2661.1Srillig    /*
2671.1Srillig     * Sequential access stuff. If the node we're removing is the current
2681.1Srillig     * node in the list, reset the current node to the previous one. If the
2691.15Srillig     * previous one was non-existent (prev == NULL), we set the
2701.1Srillig     * end to be Unknown, since it is.
2711.1Srillig     */
2721.16Srillig    if (list->isOpen && list->curr == node) {
2731.15Srillig	list->curr = list->prev;
2741.15Srillig	if (list->curr == NULL) {
2751.15Srillig	    list->lastAccess = Unknown;
2761.1Srillig	}
2771.1Srillig    }
2781.1Srillig
2791.1Srillig    /*
2801.1Srillig     * note that the datum is unmolested. The caller must free it as
2811.1Srillig     * necessary and as expected.
2821.1Srillig     */
2831.16Srillig    if (node->useCount == 0) {
2841.16Srillig	free(node);
2851.1Srillig    } else {
2861.16Srillig	node->deleted = TRUE;
2871.1Srillig    }
2881.1Srillig}
2891.1Srillig
2901.8Srillig/* Replace the datum in the given node with the new datum. */
2911.8Srilligvoid
2921.65SrilligLstNode_Set(ListNode *node, void *datum)
2931.1Srillig{
2941.52Srillig    assert(node != NULL);
2951.37Srillig    assert(datum != NULL);
2961.37Srillig
2971.16Srillig    node->datum = datum;
2981.1Srillig}
2991.1Srillig
3001.37Srillig/* Replace the datum in the given node to NULL. */
3011.37Srilligvoid
3021.65SrilligLstNode_SetNull(ListNode *node)
3031.37Srillig{
3041.52Srillig    assert(node != NULL);
3051.37Srillig
3061.37Srillig    node->datum = NULL;
3071.37Srillig}
3081.37Srillig
3091.1Srillig
3101.1Srillig/*
3111.1Srillig * Node-specific functions
3121.1Srillig */
3131.1Srillig
3141.42Srillig/* Return the first node from the given list, or NULL if the list is empty. */
3151.65SrilligListNode *
3161.65SrilligLst_First(List *list)
3171.42Srillig{
3181.52Srillig    assert(list != NULL);
3191.42Srillig
3201.42Srillig    return list->first;
3211.42Srillig}
3221.42Srillig
3231.42Srillig/* Return the last node from the given list, or NULL if the list is empty. */
3241.65SrilligListNode *
3251.65SrilligLst_Last(List *list)
3261.42Srillig{
3271.52Srillig    assert(list != NULL);
3281.42Srillig
3291.42Srillig    return list->last;
3301.42Srillig}
3311.42Srillig
3321.6Srillig/* Return the successor to the given node on its list, or NULL. */
3331.65SrilligListNode *
3341.65SrilligLstNode_Next(ListNode *node)
3351.42Srillig{
3361.52Srillig    assert(node != NULL);
3371.42Srillig
3381.42Srillig    return node->next;
3391.42Srillig}
3401.42Srillig
3411.6Srillig/* Return the predecessor to the given node on its list, or NULL. */
3421.65SrilligListNode *
3431.65SrilligLstNode_Prev(ListNode *node)
3441.1Srillig{
3451.52Srillig    assert(node != NULL);
3461.33Srillig    return node->prev;
3471.1Srillig}
3481.1Srillig
3491.28Srillig/* Return the datum stored in the given node. */
3501.1Srilligvoid *
3511.65SrilligLstNode_Datum(ListNode *node)
3521.1Srillig{
3531.52Srillig    assert(node != NULL);
3541.28Srillig    return node->datum;
3551.1Srillig}
3561.1Srillig
3571.1Srillig
3581.1Srillig/*
3591.1Srillig * Functions for entire lists
3601.1Srillig */
3611.1Srillig
3621.42Srillig/* Return TRUE if the given list is empty. */
3631.42SrilligBoolean
3641.65SrilligLst_IsEmpty(List *list)
3651.42Srillig{
3661.52Srillig    assert(list != NULL);
3671.42Srillig
3681.42Srillig    return LstIsEmpty(list);
3691.42Srillig}
3701.42Srillig
3711.53Srillig/* Return the first node from the list for which the match function returns
3721.53Srillig * TRUE, or NULL if none of the nodes matched. */
3731.65SrilligListNode *
3741.65SrilligLst_Find(List *list, LstFindProc match, const void *matchArgs)
3751.53Srillig{
3761.55Srillig    return Lst_FindFrom(list, Lst_First(list), match, matchArgs);
3771.53Srillig}
3781.53Srillig
3791.53Srillig/* Return the first node from the list, starting at the given node, for which
3801.53Srillig * the match function returns TRUE, or NULL if none of the nodes matches.
3811.53Srillig *
3821.53Srillig * The start node may be NULL, in which case nothing is found. This allows
3831.56Srillig * for passing Lst_First or LstNode_Next as the start node. */
3841.65SrilligListNode *
3851.65SrilligLst_FindFrom(List *list, ListNode *node, LstFindProc match, const void *matchArgs)
3861.53Srillig{
3871.65Srillig    ListNode *tln;
3881.53Srillig
3891.53Srillig    assert(list != NULL);
3901.53Srillig    assert(match != NULL);
3911.53Srillig
3921.53Srillig    for (tln = node; tln != NULL; tln = tln->next) {
3931.53Srillig	if (match(tln->datum, matchArgs))
3941.53Srillig	    return tln;
3951.53Srillig    }
3961.53Srillig
3971.53Srillig    return NULL;
3981.53Srillig}
3991.53Srillig
4001.14Srillig/* Return the first node that contains the given datum, or NULL. */
4011.65SrilligListNode *
4021.65SrilligLst_FindDatum(List *list, const void *datum)
4031.1Srillig{
4041.65Srillig    ListNode *node;
4051.1Srillig
4061.52Srillig    assert(list != NULL);
4071.29Srillig    assert(datum != NULL);
4081.1Srillig
4091.29Srillig    for (node = list->first; node != NULL; node = node->next) {
4101.16Srillig	if (node->datum == datum) {
4111.16Srillig	    return node;
4121.1Srillig	}
4131.29Srillig    }
4141.1Srillig
4151.1Srillig    return NULL;
4161.1Srillig}
4171.1Srillig
4181.67Srilligstatic int Lst_ForEachFrom(List *, ListNode *, LstActionUntilProc, void *);
4191.66Srillig
4201.14Srillig/* Apply the given function to each element of the given list. The function
4211.14Srillig * should return 0 if traversal should continue and non-zero if it should
4221.14Srillig * abort. */
4231.1Srilligint
4241.67SrilligLst_ForEachUntil(List *list, LstActionUntilProc proc, void *procData)
4251.42Srillig{
4261.42Srillig    if (LstIsEmpty(list))
4271.42Srillig	return 0;		/* XXX: Document what this value means. */
4281.50Srillig    return Lst_ForEachFrom(list, Lst_First(list), proc, procData);
4291.42Srillig}
4301.42Srillig
4311.14Srillig/* Apply the given function to each element of the given list, starting from
4321.14Srillig * the given node. The function should return 0 if traversal should continue,
4331.14Srillig * and non-zero if it should abort. */
4341.1Srilligint
4351.65SrilligLst_ForEachFrom(List *list, ListNode *node,
4361.67Srillig		 LstActionUntilProc proc, void *procData)
4371.1Srillig{
4381.65Srillig    ListNode *tln = node;
4391.65Srillig    ListNode *next;
4401.4Srillig    Boolean done;
4411.4Srillig    int result;
4421.1Srillig
4431.52Srillig    assert(list != NULL);
4441.52Srillig    assert(node != NULL);
4451.42Srillig    assert(proc != NULL);
4461.1Srillig
4471.1Srillig    do {
4481.1Srillig	/*
4491.1Srillig	 * Take care of having the current element deleted out from under
4501.1Srillig	 * us.
4511.1Srillig	 */
4521.1Srillig
4531.15Srillig	next = tln->next;
4541.1Srillig
4551.1Srillig	/*
4561.1Srillig	 * We're done with the traversal if
4571.38Srillig	 *  - the next node to examine doesn't exist and
4581.1Srillig	 *  - nothing's been added after the current node (check this
4591.1Srillig	 *    after proc() has been called).
4601.1Srillig	 */
4611.38Srillig	done = next == NULL;
4621.1Srillig
4631.17Srillig	tln->useCount++;
4641.16Srillig	result = (*proc)(tln->datum, procData);
4651.17Srillig	tln->useCount--;
4661.1Srillig
4671.1Srillig	/*
4681.1Srillig	 * Now check whether a node has been added.
4691.1Srillig	 * Note: this doesn't work if this node was deleted before
4701.1Srillig	 *       the new node was added.
4711.1Srillig	 */
4721.15Srillig	if (next != tln->next) {
4731.15Srillig	    next = tln->next;
4741.4Srillig	    done = 0;
4751.1Srillig	}
4761.1Srillig
4771.7Srillig	if (tln->deleted) {
4781.1Srillig	    free((char *)tln);
4791.1Srillig	}
4801.1Srillig	tln = next;
4811.1Srillig    } while (!result && !LstIsEmpty(list) && !done);
4821.1Srillig
4831.1Srillig    return result;
4841.1Srillig}
4851.1Srillig
4861.34Srillig/* Move all nodes from list2 to the end of list1.
4871.34Srillig * List2 is destroyed and freed. */
4881.34Srilligvoid
4891.65SrilligLst_MoveAll(List *list1, List *list2)
4901.1Srillig{
4911.52Srillig    assert(list1 != NULL);
4921.52Srillig    assert(list2 != NULL);
4931.1Srillig
4941.34Srillig    if (list2->first != NULL) {
4951.34Srillig	list2->first->prev = list1->last;
4961.34Srillig	if (list1->last != NULL) {
4971.34Srillig	    list1->last->next = list2->first;
4981.34Srillig	} else {
4991.34Srillig	    list1->first = list2->first;
5001.1Srillig	}
5011.34Srillig	list1->last = list2->last;
5021.1Srillig    }
5031.34Srillig    free(list2);
5041.1Srillig}
5051.1Srillig
5061.22Srillig/* Copy the element data from src to the start of dst. */
5071.22Srilligvoid
5081.65SrilligLst_PrependAll(List *dst, List *src)
5091.22Srillig{
5101.65Srillig    ListNode *node;
5111.22Srillig    for (node = src->last; node != NULL; node = node->prev)
5121.50Srillig	Lst_Prepend(dst, node->datum);
5131.22Srillig}
5141.22Srillig
5151.22Srillig/* Copy the element data from src to the end of dst. */
5161.22Srilligvoid
5171.65SrilligLst_AppendAll(List *dst, List *src)
5181.22Srillig{
5191.65Srillig    ListNode *node;
5201.22Srillig    for (node = src->first; node != NULL; node = node->next)
5211.50Srillig	Lst_Append(dst, node->datum);
5221.22Srillig}
5231.1Srillig
5241.1Srillig/*
5251.1Srillig * these functions are for dealing with a list as a table, of sorts.
5261.1Srillig * An idea of the "current element" is kept and used by all the functions
5271.1Srillig * between Lst_Open() and Lst_Close().
5281.1Srillig *
5291.1Srillig * The sequential functions access the list in a slightly different way.
5301.1Srillig * CurPtr points to their idea of the current node in the list and they
5311.1Srillig * access the list based on it.
5321.1Srillig */
5331.1Srillig
5341.14Srillig/* Open a list for sequential access. A list can still be searched, etc.,
5351.14Srillig * without confusing these functions. */
5361.10Srilligvoid
5371.65SrilligLst_Open(List *list)
5381.10Srillig{
5391.52Srillig    assert(list != NULL);
5401.60Srillig    assert(!list->isOpen);
5411.10Srillig
5421.16Srillig    list->isOpen = TRUE;
5431.16Srillig    list->lastAccess = LstIsEmpty(list) ? Head : Unknown;
5441.16Srillig    list->curr = NULL;
5451.10Srillig}
5461.10Srillig
5471.10Srillig/* Return the next node for the given list, or NULL if the end has been
5481.10Srillig * reached. */
5491.65SrilligListNode *
5501.65SrilligLst_Next(List *list)
5511.1Srillig{
5521.65Srillig    ListNode *node;
5531.1Srillig
5541.52Srillig    assert(list != NULL);
5551.9Srillig    assert(list->isOpen);
5561.1Srillig
5571.15Srillig    list->prev = list->curr;
5581.1Srillig
5591.15Srillig    if (list->curr == NULL) {
5601.15Srillig	if (list->lastAccess == Unknown) {
5611.1Srillig	    /*
5621.15Srillig	     * If we're just starting out, lastAccess will be Unknown.
5631.1Srillig	     * Then we want to start this thing off in the right
5641.15Srillig	     * direction -- at the start with lastAccess being Middle.
5651.1Srillig	     */
5661.16Srillig	    list->curr = node = list->first;
5671.15Srillig	    list->lastAccess = Middle;
5681.1Srillig	} else {
5691.16Srillig	    node = NULL;
5701.15Srillig	    list->lastAccess = Tail;
5711.1Srillig	}
5721.1Srillig    } else {
5731.16Srillig	node = list->curr->next;
5741.16Srillig	list->curr = node;
5751.1Srillig
5761.16Srillig	if (node == list->first || node == NULL) {
5771.1Srillig	    /*
5781.1Srillig	     * If back at the front, then we've hit the end...
5791.1Srillig	     */
5801.15Srillig	    list->lastAccess = Tail;
5811.1Srillig	} else {
5821.1Srillig	    /*
5831.1Srillig	     * Reset to Middle if gone past first.
5841.1Srillig	     */
5851.15Srillig	    list->lastAccess = Middle;
5861.1Srillig	}
5871.1Srillig    }
5881.1Srillig
5891.16Srillig    return node;
5901.1Srillig}
5911.1Srillig
5921.10Srillig/* Close a list which was opened for sequential access. */
5931.1Srilligvoid
5941.65SrilligLst_Close(List *list)
5951.1Srillig{
5961.52Srillig    assert(list != NULL);
5971.16Srillig    assert(list->isOpen);
5981.1Srillig
5991.10Srillig    list->isOpen = FALSE;
6001.15Srillig    list->lastAccess = Unknown;
6011.1Srillig}
6021.1Srillig
6031.1Srillig
6041.1Srillig/*
6051.1Srillig * for using the list as a queue
6061.1Srillig */
6071.1Srillig
6081.14Srillig/* Add the datum to the tail of the given list. */
6091.25Srilligvoid
6101.65SrilligLst_Enqueue(List *list, void *datum)
6111.1Srillig{
6121.50Srillig    Lst_Append(list, datum);
6131.1Srillig}
6141.1Srillig
6151.25Srillig/* Remove and return the datum at the head of the given list. */
6161.1Srilligvoid *
6171.65SrilligLst_Dequeue(List *list)
6181.1Srillig{
6191.16Srillig    void *datum;
6201.1Srillig
6211.52Srillig    assert(list != NULL);
6221.25Srillig    assert(!LstIsEmpty(list));
6231.1Srillig
6241.25Srillig    datum = list->first->datum;
6251.50Srillig    Lst_Remove(list, list->first);
6261.25Srillig    assert(datum != NULL);
6271.16Srillig    return datum;
6281.1Srillig}
6291.61Srillig
6301.61Srilligvoid
6311.61SrilligStack_Init(Stack *stack)
6321.61Srillig{
6331.61Srillig    stack->len = 0;
6341.61Srillig    stack->cap = 10;
6351.61Srillig    stack->items = bmake_malloc(stack->cap * sizeof stack->items[0]);
6361.61Srillig}
6371.61Srillig
6381.61SrilligBoolean Stack_IsEmpty(Stack *stack)
6391.61Srillig{
6401.61Srillig    return stack->len == 0;
6411.61Srillig}
6421.61Srillig
6431.61Srilligvoid Stack_Push(Stack *stack, void *datum)
6441.61Srillig{
6451.61Srillig    if (stack->len >= stack->cap) {
6461.62Srillig	stack->cap *= 2;
6471.61Srillig	stack->items = bmake_realloc(stack->items,
6481.61Srillig				     stack->cap * sizeof stack->items[0]);
6491.61Srillig    }
6501.61Srillig    stack->items[stack->len] = datum;
6511.61Srillig    stack->len++;
6521.61Srillig}
6531.61Srillig
6541.61Srilligvoid *Stack_Pop(Stack *stack)
6551.61Srillig{
6561.64Srillig    void *datum;
6571.64Srillig
6581.61Srillig    assert(stack->len > 0);
6591.61Srillig    stack->len--;
6601.64Srillig    datum = stack->items[stack->len];
6611.64Srillig#ifdef CLEANUP
6621.64Srillig    stack->items[stack->len] = NULL;
6631.64Srillig#endif
6641.64Srillig    return datum;
6651.61Srillig}
6661.61Srillig
6671.61Srilligvoid Stack_Done(Stack *stack)
6681.61Srillig{
6691.61Srillig    free(stack->items);
6701.61Srillig}
671