Home | History | Annotate | Line # | Download | only in make
lst.c revision 1.30
      1 /* $NetBSD: lst.c,v 1.30 2020/08/22 16:00:52 skrll Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1988, 1989, 1990, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * Adam de Boor.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #include <assert.h>
     36 #include <stdint.h>
     37 
     38 #include "make.h"
     39 
     40 #ifndef MAKE_NATIVE
     41 static char rcsid[] = "$NetBSD: lst.c,v 1.30 2020/08/22 16:00:52 skrll Exp $";
     42 #else
     43 #include <sys/cdefs.h>
     44 #ifndef lint
     45 __RCSID("$NetBSD: lst.c,v 1.30 2020/08/22 16:00:52 skrll Exp $");
     46 #endif /* not lint */
     47 #endif
     48 
     49 struct ListNode {
     50     struct ListNode *prev;	/* previous element in list */
     51     struct ListNode *next;	/* next in list */
     52     uint8_t useCount;		/* Count of functions using the node.
     53 				 * node may not be deleted until count
     54 				 * goes to 0 */
     55     Boolean deleted;		/* List node should be removed when done */
     56     void *datum;		/* datum associated with this element */
     57 };
     58 
     59 typedef enum {
     60     Head, Middle, Tail, Unknown
     61 } Where;
     62 
     63 struct List {
     64     LstNode first;		/* first node in list */
     65     LstNode last;		/* last node in list */
     66 
     67     /* fields for sequential access */
     68     Boolean isOpen;		/* true if list has been Lst_Open'ed */
     69     Where lastAccess;		/* Where in the list the last access was */
     70     LstNode curr;		/* current node, if open. NULL if
     71 				 * *just* opened */
     72     LstNode prev;		/* Previous node, if open. Used by Lst_Remove */
     73 };
     74 
     75 static ReturnStatus Lst_AtEnd(Lst, void *);
     76 
     77 static Boolean
     78 LstIsValid(Lst list)
     79 {
     80     return list != NULL;
     81 }
     82 
     83 static Boolean
     84 LstNodeIsValid(LstNode node)
     85 {
     86     return node != NULL;
     87 }
     88 
     89 /* Allocate and initialize a list node.
     90  *
     91  * The fields 'prev' and 'next' must be initialized by the caller.
     92  */
     93 static LstNode
     94 LstNodeNew(void *datum)
     95 {
     96     LstNode node = bmake_malloc(sizeof *node);
     97     node->useCount = 0;
     98     node->deleted = FALSE;
     99     node->datum = datum;
    100     return node;
    101 }
    102 
    103 static Boolean
    104 LstIsEmpty(Lst list)
    105 {
    106     return list->first == NULL;
    107 }
    108 
    109 /* Create and initialize a new, empty list. */
    110 Lst
    111 Lst_Init(void)
    112 {
    113     Lst list = bmake_malloc(sizeof *list);
    114 
    115     list->first = NULL;
    116     list->last = NULL;
    117     list->isOpen = FALSE;
    118     list->lastAccess = Unknown;
    119 
    120     return list;
    121 }
    122 
    123 /* Duplicate an entire list, usually by copying the datum pointers.
    124  * If copyProc is given, that function is used to create the new datum from the
    125  * old datum, usually by creating a copy of it.
    126  * Return the new list, or NULL on failure. */
    127 Lst
    128 Lst_Duplicate(Lst list, DuplicateProc *copyProc)
    129 {
    130     Lst newList;
    131     LstNode node;
    132 
    133     if (!LstIsValid(list)) {
    134 	return NULL;
    135     }
    136 
    137     newList = Lst_Init();
    138 
    139     node = list->first;
    140     while (node != NULL) {
    141 	if (copyProc != NULL) {
    142 	    if (Lst_AtEnd(newList, copyProc(node->datum)) == FAILURE) {
    143 		return NULL;
    144 	    }
    145 	} else if (Lst_AtEnd(newList, node->datum) == FAILURE) {
    146 	    return NULL;
    147 	}
    148 
    149 	node = node->next;
    150     }
    151 
    152     return newList;
    153 }
    154 
    155 /* Destroy a list and free all its resources. If the freeProc is given, it is
    156  * called with the datum from each node in turn before the node is freed. */
    157 void
    158 Lst_Destroy(Lst list, FreeProc *freeProc)
    159 {
    160     LstNode node;
    161     LstNode next = NULL;
    162 
    163     if (list == NULL)
    164 	return;
    165 
    166     /* To ease scanning */
    167     if (list->last != NULL)
    168 	list->last->next = NULL;
    169     else {
    170 	free(list);
    171 	return;
    172     }
    173 
    174     if (freeProc) {
    175 	for (node = list->first; node != NULL; node = next) {
    176 	    next = node->next;
    177 	    freeProc(node->datum);
    178 	    free(node);
    179 	}
    180     } else {
    181 	for (node = list->first; node != NULL; node = next) {
    182 	    next = node->next;
    183 	    free(node);
    184 	}
    185     }
    186 
    187     free(list);
    188 }
    189 
    190 /*
    191  * Functions to modify a list
    192  */
    193 
    194 /* Insert a new node with the given piece of data before the given node in the
    195  * given list. */
    196 static ReturnStatus
    197 LstInsertBefore(Lst list, LstNode node, void *datum)
    198 {
    199     LstNode newNode;
    200 
    201     /*
    202      * check validity of arguments
    203      */
    204     if (LstIsValid(list) && (LstIsEmpty(list) && node == NULL))
    205 	goto ok;
    206 
    207     if (!LstIsValid(list) || LstIsEmpty(list) || !LstNodeIsValid(node)) {
    208 	return FAILURE;
    209     }
    210 
    211     ok:
    212     newNode = LstNodeNew(datum);
    213 
    214     if (node == NULL) {
    215 	newNode->prev = newNode->next = NULL;
    216 	list->first = list->last = newNode;
    217     } else {
    218 	newNode->prev = node->prev;
    219 	newNode->next = node;
    220 
    221 	if (newNode->prev != NULL) {
    222 	    newNode->prev->next = newNode;
    223 	}
    224 	node->prev = newNode;
    225 
    226 	if (node == list->first) {
    227 	    list->first = newNode;
    228 	}
    229     }
    230 
    231     return SUCCESS;
    232 }
    233 
    234 /* Insert a new node with the given piece of data before the given node in the
    235  * given list. */
    236 void
    237 Lst_InsertBeforeS(Lst list, LstNode node, void *datum)
    238 {
    239     LstNode newNode;
    240 
    241     assert(LstIsValid(list));
    242     assert(!LstIsEmpty(list));
    243     assert(LstNodeIsValid(node));
    244     assert(datum != NULL);
    245 
    246     newNode = LstNodeNew(datum);
    247     newNode->prev = node->prev;
    248     newNode->next = node;
    249 
    250     if (node->prev != NULL) {
    251 	node->prev->next = newNode;
    252     }
    253     node->prev = newNode;
    254 
    255     if (node == list->first) {
    256 	list->first = newNode;
    257     }
    258 }
    259 
    260 /* Insert a new node with the given piece of data after the given node in the
    261  * given list. */
    262 static ReturnStatus
    263 LstInsertAfter(Lst list, LstNode node, void *datum)
    264 {
    265     LstNode newNode;
    266 
    267     if (LstIsValid(list) && (node == NULL && LstIsEmpty(list))) {
    268 	goto ok;
    269     }
    270 
    271     if (!LstIsValid(list) || LstIsEmpty(list) || !LstNodeIsValid(node)) {
    272 	return FAILURE;
    273     }
    274     ok:
    275 
    276     newNode = LstNodeNew(datum);
    277 
    278     if (node == NULL) {
    279 	newNode->next = newNode->prev = NULL;
    280 	list->first = list->last = newNode;
    281     } else {
    282 	newNode->prev = node;
    283 	newNode->next = node->next;
    284 
    285 	node->next = newNode;
    286 	if (newNode->next != NULL) {
    287 	    newNode->next->prev = newNode;
    288 	}
    289 
    290 	if (node == list->last) {
    291 	    list->last = newNode;
    292 	}
    293     }
    294 
    295     return SUCCESS;
    296 }
    297 
    298 /* Add a piece of data at the front of the given list. */
    299 ReturnStatus
    300 Lst_AtFront(Lst list, void *datum)
    301 {
    302     LstNode front = Lst_First(list);
    303     return LstInsertBefore(list, front, datum);
    304 }
    305 
    306 /* Add a piece of data at the end of the given list. */
    307 ReturnStatus
    308 Lst_AtEnd(Lst list, void *datum)
    309 {
    310     LstNode end = Lst_Last(list);
    311     return LstInsertAfter(list, end, datum);
    312 }
    313 
    314 /* Add a piece of data at the start of the given list. */
    315 void
    316 Lst_PrependS(Lst list, void *datum)
    317 {
    318     LstNode node;
    319 
    320     assert(LstIsValid(list));
    321     assert(datum != NULL);
    322 
    323     node = LstNodeNew(datum);
    324     node->prev = NULL;
    325     node->next = list->first;
    326 
    327     if (list->first == NULL) {
    328 	list->first = node;
    329 	list->last = node;
    330     } else {
    331 	list->first->prev = node;
    332 	list->first = node;
    333     }
    334 }
    335 
    336 /* Add a piece of data at the end of the given list. */
    337 void
    338 Lst_AppendS(Lst list, void *datum)
    339 {
    340     LstNode node;
    341 
    342     assert(LstIsValid(list));
    343     assert(datum != NULL);
    344 
    345     node = LstNodeNew(datum);
    346     node->prev = list->last;
    347     node->next = NULL;
    348 
    349     if (list->last == NULL) {
    350 	list->first = node;
    351 	list->last = node;
    352     } else {
    353 	list->last->next = node;
    354 	list->last = node;
    355     }
    356 }
    357 
    358 /* Remove the given node from the given list.
    359  * The datum stored in the node must be freed by the caller, if necessary. */
    360 void
    361 Lst_RemoveS(Lst list, LstNode node)
    362 {
    363     assert(LstIsValid(list));
    364     assert(LstNodeIsValid(node));
    365 
    366     /*
    367      * unlink it from the list
    368      */
    369     if (node->next != NULL) {
    370 	node->next->prev = node->prev;
    371     }
    372     if (node->prev != NULL) {
    373 	node->prev->next = node->next;
    374     }
    375 
    376     /*
    377      * if either the first or last of the list point to this node,
    378      * adjust them accordingly
    379      */
    380     if (list->first == node) {
    381 	list->first = node->next;
    382     }
    383     if (list->last == node) {
    384 	list->last = node->prev;
    385     }
    386 
    387     /*
    388      * Sequential access stuff. If the node we're removing is the current
    389      * node in the list, reset the current node to the previous one. If the
    390      * previous one was non-existent (prev == NULL), we set the
    391      * end to be Unknown, since it is.
    392      */
    393     if (list->isOpen && list->curr == node) {
    394 	list->curr = list->prev;
    395 	if (list->curr == NULL) {
    396 	    list->lastAccess = Unknown;
    397 	}
    398     }
    399 
    400     /*
    401      * note that the datum is unmolested. The caller must free it as
    402      * necessary and as expected.
    403      */
    404     if (node->useCount == 0) {
    405 	free(node);
    406     } else {
    407 	node->deleted = TRUE;
    408     }
    409 }
    410 
    411 /* Replace the datum in the given node with the new datum. */
    412 void
    413 Lst_ReplaceS(LstNode node, void *datum)
    414 {
    415     node->datum = datum;
    416 }
    417 
    418 
    419 /*
    420  * Node-specific functions
    421  */
    422 
    423 /* Return the first node from the given list, or NULL if the list is empty or
    424  * invalid. */
    425 LstNode
    426 Lst_First(Lst list)
    427 {
    428     if (!LstIsValid(list) || LstIsEmpty(list)) {
    429 	return NULL;
    430     } else {
    431 	return list->first;
    432     }
    433 }
    434 
    435 /* Return the last node from the given list, or NULL if the list is empty or
    436  * invalid. */
    437 LstNode
    438 Lst_Last(Lst list)
    439 {
    440     if (!LstIsValid(list) || LstIsEmpty(list)) {
    441 	return NULL;
    442     } else {
    443 	return list->last;
    444     }
    445 }
    446 
    447 /* Return the successor to the given node on its list, or NULL. */
    448 LstNode
    449 Lst_Succ(LstNode node)
    450 {
    451     if (node == NULL) {
    452 	return NULL;
    453     } else {
    454 	return node->next;
    455     }
    456 }
    457 
    458 /* Return the predecessor to the given node on its list, or NULL. */
    459 LstNode
    460 Lst_Prev(LstNode node)
    461 {
    462     if (node == NULL) {
    463 	return NULL;
    464     } else {
    465 	return node->prev;
    466     }
    467 }
    468 
    469 /* Return the datum stored in the given node. */
    470 void *
    471 Lst_DatumS(LstNode node)
    472 {
    473     assert(LstNodeIsValid(node));
    474     return node->datum;
    475 }
    476 
    477 
    478 /*
    479  * Functions for entire lists
    480  */
    481 
    482 /* Return TRUE if the given list is empty or invalid. */
    483 Boolean
    484 Lst_IsEmpty(Lst list)
    485 {
    486     return !LstIsValid(list) || LstIsEmpty(list);
    487 }
    488 
    489 /* Return the first node from the given list for which the given comparison
    490  * function returns 0, or NULL if none of the nodes matches. */
    491 LstNode
    492 Lst_Find(Lst list, const void *cmpData, int (*cmp)(const void *, const void *))
    493 {
    494     return Lst_FindFrom(list, Lst_First(list), cmpData, cmp);
    495 }
    496 
    497 /* Return the first node from the given list, starting at the given node, for
    498  * which the given comparison function returns 0, or NULL if none of the nodes
    499  * matches. */
    500 LstNode
    501 Lst_FindFrom(Lst list, LstNode node, const void *cmpData,
    502 	     int (*cmp)(const void *, const void *))
    503 {
    504     LstNode tln;
    505 
    506     if (!LstIsValid(list) || LstIsEmpty(list) || !LstNodeIsValid(node)) {
    507 	return NULL;
    508     }
    509 
    510     tln = node;
    511 
    512     do {
    513 	if ((*cmp)(tln->datum, cmpData) == 0)
    514 	    return tln;
    515 	tln = tln->next;
    516     } while (tln != node && tln != NULL);
    517 
    518     return NULL;
    519 }
    520 
    521 /* Return the first node that contains the given datum, or NULL. */
    522 LstNode
    523 Lst_MemberS(Lst list, void *datum)
    524 {
    525     LstNode node;
    526 
    527     assert(LstIsValid(list));
    528     assert(datum != NULL);
    529 
    530     for (node = list->first; node != NULL; node = node->next) {
    531 	if (node->datum == datum) {
    532 	    return node;
    533 	}
    534     }
    535 
    536     return NULL;
    537 }
    538 
    539 /* Apply the given function to each element of the given list. The function
    540  * should return 0 if traversal should continue and non-zero if it should
    541  * abort. */
    542 int
    543 Lst_ForEach(Lst list, int (*proc)(void *, void *), void *procData)
    544 {
    545     return Lst_ForEachFrom(list, Lst_First(list), proc, procData);
    546 }
    547 
    548 /* Apply the given function to each element of the given list, starting from
    549  * the given node. The function should return 0 if traversal should continue,
    550  * and non-zero if it should abort. */
    551 int
    552 Lst_ForEachFrom(Lst list, LstNode node,
    553 		int (*proc)(void *, void *), void *procData)
    554 {
    555     LstNode tln = node;
    556     LstNode next;
    557     Boolean done;
    558     int result;
    559 
    560     if (!LstIsValid(list) || LstIsEmpty(list)) {
    561 	return 0;
    562     }
    563 
    564     do {
    565 	/*
    566 	 * Take care of having the current element deleted out from under
    567 	 * us.
    568 	 */
    569 
    570 	next = tln->next;
    571 
    572 	/*
    573 	 * We're done with the traversal if
    574 	 *  - the next node to examine is the first in the queue or
    575 	 *    doesn't exist and
    576 	 *  - nothing's been added after the current node (check this
    577 	 *    after proc() has been called).
    578 	 */
    579 	done = (next == NULL || next == list->first);
    580 
    581 	tln->useCount++;
    582 	result = (*proc)(tln->datum, procData);
    583 	tln->useCount--;
    584 
    585 	/*
    586 	 * Now check whether a node has been added.
    587 	 * Note: this doesn't work if this node was deleted before
    588 	 *       the new node was added.
    589 	 */
    590 	if (next != tln->next) {
    591 	    next = tln->next;
    592 	    done = 0;
    593 	}
    594 
    595 	if (tln->deleted) {
    596 	    free((char *)tln);
    597 	}
    598 	tln = next;
    599     } while (!result && !LstIsEmpty(list) && !done);
    600 
    601     return result;
    602 }
    603 
    604 /* Concatenate two lists. New nodes are created to hold the data elements,
    605  * if specified, but the data themselves are not copied. If the data
    606  * should be duplicated to avoid confusion with another list, the Lst_Duplicate
    607  * function should be called first. If LST_CONCLINK is specified, the second
    608  * list is destroyed since its pointers have been corrupted and the list is no
    609  * longer usable.
    610  *
    611  * Input:
    612  *	list1		The list to which list2 is to be appended
    613  *	list2		The list to append to list1
    614  *	flags		LST_CONCNEW if the list nodes should be duplicated
    615  *			LST_CONCLINK if the list nodes should just be relinked
    616  */
    617 ReturnStatus
    618 Lst_Concat(Lst list1, Lst list2, int flags)
    619 {
    620     LstNode node;	/* original node */
    621     LstNode newNode;
    622     LstNode last;	/* the last element in the list.
    623 			 * Keeps bookkeeping until the end */
    624 
    625     if (!LstIsValid(list1) || !LstIsValid(list2)) {
    626 	return FAILURE;
    627     }
    628 
    629     if (flags == LST_CONCLINK) {
    630 	if (list2->first != NULL) {
    631 	    /*
    632 	     * So long as the second list isn't empty, we just link the
    633 	     * first element of the second list to the last element of the
    634 	     * first list. If the first list isn't empty, we then link the
    635 	     * last element of the list to the first element of the second list
    636 	     * The last element of the second list, if it exists, then becomes
    637 	     * the last element of the first list.
    638 	     */
    639 	    list2->first->prev = list1->last;
    640 	    if (list1->last != NULL) {
    641 		list1->last->next = list2->first;
    642 	    } else {
    643 		list1->first = list2->first;
    644 	    }
    645 	    list1->last = list2->last;
    646 	}
    647 	free(list2);
    648     } else if (list2->first != NULL) {
    649 	/*
    650 	 * We set the 'next' of the last element of list 2 to be nil to make
    651 	 * the loop less difficult. The loop simply goes through the entire
    652 	 * second list creating new LstNodes and filling in the 'next', and
    653 	 * 'prev' to fit into list1 and its datum field from the
    654 	 * datum field of the corresponding element in list2. The 'last' node
    655 	 * follows the last of the new nodes along until the entire list2 has
    656 	 * been appended. Only then does the bookkeeping catch up with the
    657 	 * changes. During the first iteration of the loop, if 'last' is nil,
    658 	 * the first list must have been empty so the newly-created node is
    659 	 * made the first node of the list.
    660 	 */
    661 	list2->last->next = NULL;
    662 	for (last = list1->last, node = list2->first;
    663 	     node != NULL;
    664 	     node = node->next)
    665 	{
    666 	    newNode = LstNodeNew(node->datum);
    667 	    if (last != NULL) {
    668 		last->next = newNode;
    669 	    } else {
    670 		list1->first = newNode;
    671 	    }
    672 	    newNode->prev = last;
    673 	    last = newNode;
    674 	}
    675 
    676 	/*
    677 	 * Finish bookkeeping. The last new element becomes the last element
    678 	 * of list one.
    679 	 */
    680 	list1->last = last;
    681 	last->next = NULL;
    682     }
    683 
    684     return SUCCESS;
    685 }
    686 
    687 /* Copy the element data from src to the start of dst. */
    688 void
    689 Lst_PrependAllS(Lst dst, Lst src)
    690 {
    691     LstNode node;
    692     for (node = src->last; node != NULL; node = node->prev)
    693         Lst_PrependS(dst, node->datum);
    694 }
    695 
    696 /* Copy the element data from src to the end of dst. */
    697 void
    698 Lst_AppendAllS(Lst dst, Lst src)
    699 {
    700     LstNode node;
    701     for (node = src->first; node != NULL; node = node->next)
    702         Lst_AppendS(dst, node->datum);
    703 }
    704 
    705 /*
    706  * these functions are for dealing with a list as a table, of sorts.
    707  * An idea of the "current element" is kept and used by all the functions
    708  * between Lst_Open() and Lst_Close().
    709  *
    710  * The sequential functions access the list in a slightly different way.
    711  * CurPtr points to their idea of the current node in the list and they
    712  * access the list based on it.
    713  */
    714 
    715 /* Open a list for sequential access. A list can still be searched, etc.,
    716  * without confusing these functions. */
    717 ReturnStatus
    718 Lst_Open(Lst list)
    719 {
    720     if (!LstIsValid(list)) {
    721 	return FAILURE;
    722     }
    723     Lst_OpenS(list);
    724     return SUCCESS;
    725 }
    726 
    727 /* Open a list for sequential access. A list can still be searched, etc.,
    728  * without confusing these functions. */
    729 void
    730 Lst_OpenS(Lst list)
    731 {
    732     assert(LstIsValid(list));
    733 
    734     /* XXX: This assertion fails for NetBSD's "build.sh -j1 tools", somewhere
    735      * between "dependall ===> compat" and "dependall ===> binstall".
    736      * Building without the "-j1" succeeds though. */
    737     if (DEBUG(LINT) && list->isOpen)
    738 	Parse_Error(PARSE_WARNING, "Internal inconsistency: list opened twice");
    739 
    740     list->isOpen = TRUE;
    741     list->lastAccess = LstIsEmpty(list) ? Head : Unknown;
    742     list->curr = NULL;
    743 }
    744 
    745 /* Return the next node for the given list, or NULL if the end has been
    746  * reached. */
    747 LstNode
    748 Lst_NextS(Lst list)
    749 {
    750     LstNode node;
    751 
    752     assert(LstIsValid(list));
    753     assert(list->isOpen);
    754 
    755     list->prev = list->curr;
    756 
    757     if (list->curr == NULL) {
    758 	if (list->lastAccess == Unknown) {
    759 	    /*
    760 	     * If we're just starting out, lastAccess will be Unknown.
    761 	     * Then we want to start this thing off in the right
    762 	     * direction -- at the start with lastAccess being Middle.
    763 	     */
    764 	    list->curr = node = list->first;
    765 	    list->lastAccess = Middle;
    766 	} else {
    767 	    node = NULL;
    768 	    list->lastAccess = Tail;
    769 	}
    770     } else {
    771 	node = list->curr->next;
    772 	list->curr = node;
    773 
    774 	if (node == list->first || node == NULL) {
    775 	    /*
    776 	     * If back at the front, then we've hit the end...
    777 	     */
    778 	    list->lastAccess = Tail;
    779 	} else {
    780 	    /*
    781 	     * Reset to Middle if gone past first.
    782 	     */
    783 	    list->lastAccess = Middle;
    784 	}
    785     }
    786 
    787     return node;
    788 }
    789 
    790 /* Close a list which was opened for sequential access. */
    791 void
    792 Lst_CloseS(Lst list)
    793 {
    794     assert(LstIsValid(list));
    795     assert(list->isOpen);
    796 
    797     list->isOpen = FALSE;
    798     list->lastAccess = Unknown;
    799 }
    800 
    801 
    802 /*
    803  * for using the list as a queue
    804  */
    805 
    806 /* Add the datum to the tail of the given list. */
    807 void
    808 Lst_EnqueueS(Lst list, void *datum)
    809 {
    810     Lst_AppendS(list, datum);
    811 }
    812 
    813 /* Remove and return the datum at the head of the given list. */
    814 void *
    815 Lst_DequeueS(Lst list)
    816 {
    817     void *datum;
    818 
    819     assert(LstIsValid(list));
    820     assert(!LstIsEmpty(list));
    821 
    822     datum = list->first->datum;
    823     Lst_RemoveS(list, list->first);
    824     assert(datum != NULL);
    825     return datum;
    826 }
    827