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