1 /* $NetBSD: lst.c,v 1.4 2020/08/09 20:49:15 rillig 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 "lst.h" 36 #include "make_malloc.h" 37 38 #ifndef MAKE_NATIVE 39 static char rcsid[] = "$NetBSD: lst.c,v 1.4 2020/08/09 20:49:15 rillig Exp $"; 40 #else 41 #include <sys/cdefs.h> 42 #ifndef lint 43 __RCSID("$NetBSD: lst.c,v 1.4 2020/08/09 20:49:15 rillig Exp $"); 44 #endif /* not lint */ 45 #endif 46 47 typedef struct ListNode { 48 struct ListNode *prevPtr; /* previous element in list */ 49 struct ListNode *nextPtr; /* next in list */ 50 unsigned int useCount: 8, /* Count of functions using the node. 51 * node may not be deleted until count 52 * goes to 0 */ 53 flags: 8; /* Node status flags */ 54 void *datum; /* datum associated with this element */ 55 } *ListNode; 56 /* 57 * Flags required for synchronization 58 */ 59 #define LN_DELETED 0x0001 /* List node should be removed when done */ 60 61 typedef enum { 62 Head, Middle, Tail, Unknown 63 } Where; 64 65 typedef struct List { 66 ListNode firstPtr; /* first node in list */ 67 ListNode lastPtr; /* last node in list */ 68 Boolean isCirc; /* true if the list should be considered 69 * circular */ 70 /* 71 * fields for sequential access 72 */ 73 Where atEnd; /* Where in the list the last access was */ 74 Boolean isOpen; /* true if list has been Lst_Open'ed */ 75 ListNode curPtr; /* current node, if open. NULL if 76 * *just* opened */ 77 ListNode prevPtr; /* Previous node, if open. Used by 78 * Lst_Remove */ 79 } *List; 80 81 /* 82 * PAlloc (var, ptype) -- 83 * Allocate a pointer-typedef structure 'ptype' into the variable 'var' 84 */ 85 #define PAlloc(var, ptype) \ 86 var = (ptype) bmake_malloc(sizeof *(var)) 87 88 /* 89 * LstValid -- 90 * Return TRUE if the list is valid 91 */ 92 static Boolean 93 LstValid(Lst l) 94 { 95 return l != NULL; 96 } 97 98 /* 99 * LstNodeValid -- 100 * Return TRUE if the list node is valid 101 */ 102 static Boolean 103 LstNodeValid(LstNode ln) 104 { 105 return ln != NULL; 106 } 107 108 /* 109 * LstIsEmpty (l) -- 110 * TRUE if the list l is empty. 111 */ 112 static Boolean 113 LstIsEmpty(Lst l) 114 { 115 return l->firstPtr == NULL; 116 } 117 118 /*- 119 *----------------------------------------------------------------------- 120 * Lst_Init -- 121 * Create and initialize a new list. 122 * 123 * Input: 124 * circ TRUE if the list should be made circular 125 * 126 * Results: 127 * The created list. 128 * 129 * Side Effects: 130 * A list is created, what else? 131 * 132 *----------------------------------------------------------------------- 133 */ 134 Lst 135 Lst_Init(Boolean circ) 136 { 137 List nList; 138 139 PAlloc (nList, List); 140 141 nList->firstPtr = NULL; 142 nList->lastPtr = NULL; 143 nList->isOpen = FALSE; 144 nList->isCirc = circ; 145 nList->atEnd = Unknown; 146 147 return nList; 148 } 149 150 /*- 151 *----------------------------------------------------------------------- 152 * Lst_Duplicate -- 153 * Duplicate an entire list. If a function to copy a void *is 154 * given, the individual client elements will be duplicated as well. 155 * 156 * Input: 157 * l the list to duplicate 158 * copyProc A function to duplicate each void * 159 * 160 * Results: 161 * The new Lst structure or NULL if failure. 162 * 163 * Side Effects: 164 * A new list is created. 165 *----------------------------------------------------------------------- 166 */ 167 Lst 168 Lst_Duplicate(Lst l, DuplicateProc *copyProc) 169 { 170 Lst nl; 171 ListNode ln; 172 List list = l; 173 174 if (!LstValid(l)) { 175 return NULL; 176 } 177 178 nl = Lst_Init(list->isCirc); 179 if (nl == NULL) { 180 return NULL; 181 } 182 183 ln = list->firstPtr; 184 while (ln != NULL) { 185 if (copyProc != NULL) { 186 if (Lst_AtEnd(nl, copyProc(ln->datum)) == FAILURE) { 187 return NULL; 188 } 189 } else if (Lst_AtEnd(nl, ln->datum) == FAILURE) { 190 return NULL; 191 } 192 193 if (list->isCirc && ln == list->lastPtr) { 194 ln = NULL; 195 } else { 196 ln = ln->nextPtr; 197 } 198 } 199 200 return nl; 201 } 202 203 /*- 204 *----------------------------------------------------------------------- 205 * Lst_Destroy -- 206 * Destroy a list and free all its resources. If the freeProc is 207 * given, it is called with the datum from each node in turn before 208 * the node is freed. 209 * 210 * Results: 211 * None. 212 * 213 * Side Effects: 214 * The given list is freed in its entirety. 215 * 216 *----------------------------------------------------------------------- 217 */ 218 void 219 Lst_Destroy(Lst list, FreeProc *freeProc) 220 { 221 ListNode ln; 222 ListNode tln = NULL; 223 224 if (list == NULL) 225 return; 226 227 /* To ease scanning */ 228 if (list->lastPtr != NULL) 229 list->lastPtr->nextPtr = NULL; 230 else { 231 free(list); 232 return; 233 } 234 235 if (freeProc) { 236 for (ln = list->firstPtr; ln != NULL; ln = tln) { 237 tln = ln->nextPtr; 238 freeProc(ln->datum); 239 free(ln); 240 } 241 } else { 242 for (ln = list->firstPtr; ln != NULL; ln = tln) { 243 tln = ln->nextPtr; 244 free(ln); 245 } 246 } 247 248 free(list); 249 } 250 251 /* 252 * Functions to modify a list 253 */ 254 255 /*- 256 *----------------------------------------------------------------------- 257 * Lst_InsertBefore -- 258 * Insert a new node with the given piece of data before the given 259 * node in the given list. 260 * 261 * Input: 262 * l list to manipulate 263 * ln node before which to insert d 264 * d datum to be inserted 265 * 266 * Results: 267 * SUCCESS or FAILURE. 268 * 269 * Side Effects: 270 * the firstPtr field will be changed if ln is the first node in the 271 * list. 272 * 273 *----------------------------------------------------------------------- 274 */ 275 ReturnStatus 276 Lst_InsertBefore(Lst l, LstNode ln, void *d) 277 { 278 ListNode nLNode; /* new lnode for d */ 279 ListNode lNode = ln; 280 List list = l; 281 282 283 /* 284 * check validity of arguments 285 */ 286 if (LstValid(l) && (LstIsEmpty(l) && ln == NULL)) 287 goto ok; 288 289 if (!LstValid(l) || LstIsEmpty(l) || !LstNodeValid(ln)) { 290 return FAILURE; 291 } 292 293 ok: 294 PAlloc (nLNode, ListNode); 295 296 nLNode->datum = d; 297 nLNode->useCount = nLNode->flags = 0; 298 299 if (ln == NULL) { 300 if (list->isCirc) { 301 nLNode->prevPtr = nLNode->nextPtr = nLNode; 302 } else { 303 nLNode->prevPtr = nLNode->nextPtr = NULL; 304 } 305 list->firstPtr = list->lastPtr = nLNode; 306 } else { 307 nLNode->prevPtr = lNode->prevPtr; 308 nLNode->nextPtr = lNode; 309 310 if (nLNode->prevPtr != NULL) { 311 nLNode->prevPtr->nextPtr = nLNode; 312 } 313 lNode->prevPtr = nLNode; 314 315 if (lNode == list->firstPtr) { 316 list->firstPtr = nLNode; 317 } 318 } 319 320 return SUCCESS; 321 } 322 323 /*- 324 *----------------------------------------------------------------------- 325 * Lst_InsertAfter -- 326 * Create a new node and add it to the given list after the given node. 327 * 328 * Input: 329 * l affected list 330 * ln node after which to append the datum 331 * d said datum 332 * 333 * Results: 334 * SUCCESS if all went well. 335 * 336 * Side Effects: 337 * A new ListNode is created and linked in to the List. The lastPtr 338 * field of the List will be altered if ln is the last node in the 339 * list. lastPtr and firstPtr will alter if the list was empty and 340 * ln was NULL. 341 * 342 *----------------------------------------------------------------------- 343 */ 344 ReturnStatus 345 Lst_InsertAfter(Lst l, LstNode ln, void *d) 346 { 347 List list; 348 ListNode lNode; 349 ListNode nLNode; 350 351 if (LstValid(l) && (ln == NULL && LstIsEmpty(l))) { 352 goto ok; 353 } 354 355 if (!LstValid(l) || LstIsEmpty(l) || !LstNodeValid(ln)) { 356 return FAILURE; 357 } 358 ok: 359 360 list = l; 361 lNode = ln; 362 363 PAlloc (nLNode, ListNode); 364 nLNode->datum = d; 365 nLNode->useCount = nLNode->flags = 0; 366 367 if (lNode == NULL) { 368 if (list->isCirc) { 369 nLNode->nextPtr = nLNode->prevPtr = nLNode; 370 } else { 371 nLNode->nextPtr = nLNode->prevPtr = NULL; 372 } 373 list->firstPtr = list->lastPtr = nLNode; 374 } else { 375 nLNode->prevPtr = lNode; 376 nLNode->nextPtr = lNode->nextPtr; 377 378 lNode->nextPtr = nLNode; 379 if (nLNode->nextPtr != NULL) { 380 nLNode->nextPtr->prevPtr = nLNode; 381 } 382 383 if (lNode == list->lastPtr) { 384 list->lastPtr = nLNode; 385 } 386 } 387 388 return SUCCESS; 389 } 390 391 /*- 392 *----------------------------------------------------------------------- 393 * Lst_AtFront -- 394 * Place a piece of data at the front of a list 395 * 396 * Results: 397 * SUCCESS or FAILURE 398 * 399 * Side Effects: 400 * A new ListNode is created and stuck at the front of the list. 401 * hence, firstPtr (and possible lastPtr) in the list are altered. 402 * 403 *----------------------------------------------------------------------- 404 */ 405 ReturnStatus 406 Lst_AtFront(Lst l, void *d) 407 { 408 LstNode front; 409 410 front = Lst_First(l); 411 return Lst_InsertBefore(l, front, d); 412 } 413 414 /*- 415 *----------------------------------------------------------------------- 416 * Lst_AtEnd -- 417 * Add a node to the end of the given list 418 * 419 * Input: 420 * l List to which to add the datum 421 * d Datum to add 422 * 423 * Results: 424 * SUCCESS if life is good. 425 * 426 * Side Effects: 427 * A new ListNode is created and added to the list. 428 * 429 *----------------------------------------------------------------------- 430 */ 431 ReturnStatus 432 Lst_AtEnd(Lst l, void *d) 433 { 434 LstNode end; 435 436 end = Lst_Last(l); 437 return Lst_InsertAfter(l, end, d); 438 } 439 440 /*- 441 *----------------------------------------------------------------------- 442 * Lst_Remove -- 443 * Remove the given node from the given list. 444 * 445 * Results: 446 * SUCCESS or FAILURE. 447 * 448 * Side Effects: 449 * The list's firstPtr will be set to NULL if ln is the last 450 * node on the list. firsPtr and lastPtr will be altered if ln is 451 * either the first or last node, respectively, on the list. 452 * 453 *----------------------------------------------------------------------- 454 */ 455 ReturnStatus 456 Lst_Remove(Lst l, LstNode ln) 457 { 458 List list = l; 459 ListNode lNode = ln; 460 461 if (!LstValid(l) || !LstNodeValid(ln)) { 462 return FAILURE; 463 } 464 465 /* 466 * unlink it from the list 467 */ 468 if (lNode->nextPtr != NULL) { 469 lNode->nextPtr->prevPtr = lNode->prevPtr; 470 } 471 if (lNode->prevPtr != NULL) { 472 lNode->prevPtr->nextPtr = lNode->nextPtr; 473 } 474 475 /* 476 * if either the firstPtr or lastPtr of the list point to this node, 477 * adjust them accordingly 478 */ 479 if (list->firstPtr == lNode) { 480 list->firstPtr = lNode->nextPtr; 481 } 482 if (list->lastPtr == lNode) { 483 list->lastPtr = lNode->prevPtr; 484 } 485 486 /* 487 * Sequential access stuff. If the node we're removing is the current 488 * node in the list, reset the current node to the previous one. If the 489 * previous one was non-existent (prevPtr == NULL), we set the 490 * end to be Unknown, since it is. 491 */ 492 if (list->isOpen && (list->curPtr == lNode)) { 493 list->curPtr = list->prevPtr; 494 if (list->curPtr == NULL) { 495 list->atEnd = Unknown; 496 } 497 } 498 499 /* 500 * the only way firstPtr can still point to ln is if ln is the last 501 * node on the list (the list is circular, so lNode->nextptr == lNode in 502 * this case). The list is, therefore, empty and is marked as such 503 */ 504 if (list->firstPtr == lNode) { 505 list->firstPtr = NULL; 506 } 507 508 /* 509 * note that the datum is unmolested. The caller must free it as 510 * necessary and as expected. 511 */ 512 if (lNode->useCount == 0) { 513 free(ln); 514 } else { 515 lNode->flags |= LN_DELETED; 516 } 517 518 return SUCCESS; 519 } 520 521 /*- 522 *----------------------------------------------------------------------- 523 * Lst_Replace -- 524 * Replace the datum in the given node with the new datum 525 * 526 * Results: 527 * SUCCESS or FAILURE. 528 * 529 * Side Effects: 530 * The datum field fo the node is altered. 531 * 532 *----------------------------------------------------------------------- 533 */ 534 ReturnStatus 535 Lst_Replace(LstNode ln, void *d) 536 { 537 if (ln == NULL) { 538 return FAILURE; 539 } else { 540 (ln)->datum = d; 541 return SUCCESS; 542 } 543 } 544 545 546 /* 547 * Node-specific functions 548 */ 549 550 /*- 551 *----------------------------------------------------------------------- 552 * Lst_First -- 553 * Return the first node on the given list. 554 * 555 * Results: 556 * The first node or NULL if the list is empty. 557 * 558 * Side Effects: 559 * None. 560 * 561 *----------------------------------------------------------------------- 562 */ 563 LstNode 564 Lst_First(Lst l) 565 { 566 if (!LstValid(l) || LstIsEmpty(l)) { 567 return NULL; 568 } else { 569 return l->firstPtr; 570 } 571 } 572 573 /*- 574 *----------------------------------------------------------------------- 575 * Lst_Last -- 576 * Return the last node on the list l. 577 * 578 * Results: 579 * The requested node or NULL if the list is empty. 580 * 581 * Side Effects: 582 * None. 583 * 584 *----------------------------------------------------------------------- 585 */ 586 LstNode 587 Lst_Last(Lst l) 588 { 589 if (!LstValid(l) || LstIsEmpty(l)) { 590 return NULL; 591 } else { 592 return l->lastPtr; 593 } 594 } 595 596 /*- 597 *----------------------------------------------------------------------- 598 * Lst_Succ -- 599 * Return the successor to the given node on its list. 600 * 601 * Results: 602 * The successor of the node, if it exists (note that on a circular 603 * list, if the node is the only one in the list, it is its own 604 * successor). 605 * 606 * Side Effects: 607 * None. 608 * 609 *----------------------------------------------------------------------- 610 */ 611 LstNode 612 Lst_Succ(LstNode ln) 613 { 614 if (ln == NULL) { 615 return NULL; 616 } else { 617 return ln->nextPtr; 618 } 619 } 620 621 /*- 622 *----------------------------------------------------------------------- 623 * Lst_Prev -- 624 * Return the predecessor to the given node on its list. 625 * 626 * Results: 627 * The predecessor of the node, if it exists (note that on a circular 628 * list, if the node is the only one in the list, it is its own 629 * predecessor). 630 * 631 * Side Effects: 632 * None. 633 * 634 *----------------------------------------------------------------------- 635 */ 636 LstNode 637 Lst_Prev(LstNode ln) 638 { 639 if (ln == NULL) { 640 return NULL; 641 } else { 642 return ln->prevPtr; 643 } 644 } 645 646 /*- 647 *----------------------------------------------------------------------- 648 * Lst_Datum -- 649 * Return the datum stored in the given node. 650 * 651 * Results: 652 * The datum or NULL if the node is invalid. 653 * 654 * Side Effects: 655 * None. 656 * 657 *----------------------------------------------------------------------- 658 */ 659 void * 660 Lst_Datum(LstNode ln) 661 { 662 if (ln != NULL) { 663 return ln->datum; 664 } else { 665 return NULL; 666 } 667 } 668 669 670 /* 671 * Functions for entire lists 672 */ 673 674 /*- 675 *----------------------------------------------------------------------- 676 * Lst_IsEmpty -- 677 * Return TRUE if the given list is empty. 678 * 679 * Results: 680 * TRUE if the list is empty, FALSE otherwise. 681 * 682 * Side Effects: 683 * None. 684 * 685 * A list is considered empty if its firstPtr == NULL (or if 686 * the list itself is NULL). 687 *----------------------------------------------------------------------- 688 */ 689 Boolean 690 Lst_IsEmpty(Lst l) 691 { 692 return !LstValid(l) || LstIsEmpty(l); 693 } 694 695 /*- 696 *----------------------------------------------------------------------- 697 * Lst_Find -- 698 * Find a node on the given list using the given comparison function 699 * and the given datum. 700 * 701 * Results: 702 * The found node or NULL if none matches. 703 * 704 * Side Effects: 705 * None. 706 * 707 *----------------------------------------------------------------------- 708 */ 709 LstNode 710 Lst_Find(Lst l, const void *d, int (*cProc)(const void *, const void *)) 711 { 712 return Lst_FindFrom(l, Lst_First(l), d, cProc); 713 } 714 715 /*- 716 *----------------------------------------------------------------------- 717 * Lst_FindFrom -- 718 * Search for a node starting and ending with the given one on the 719 * given list using the passed datum and comparison function to 720 * determine when it has been found. 721 * 722 * Results: 723 * The found node or NULL 724 * 725 * Side Effects: 726 * None. 727 * 728 *----------------------------------------------------------------------- 729 */ 730 LstNode 731 Lst_FindFrom(Lst l, LstNode ln, const void *d, 732 int (*cProc)(const void *, const void *)) 733 { 734 ListNode tln; 735 736 if (!LstValid(l) || LstIsEmpty(l) || !LstNodeValid(ln)) { 737 return NULL; 738 } 739 740 tln = ln; 741 742 do { 743 if ((*cProc)(tln->datum, d) == 0) 744 return tln; 745 tln = tln->nextPtr; 746 } while (tln != ln && tln != NULL); 747 748 return NULL; 749 } 750 751 /*- 752 * See if a given datum is on a given list. 753 */ 754 LstNode 755 Lst_Member(Lst l, void *d) 756 { 757 List list = l; 758 ListNode lNode; 759 760 if (list == NULL) { 761 return NULL; 762 } 763 lNode = list->firstPtr; 764 if (lNode == NULL) { 765 return NULL; 766 } 767 768 do { 769 if (lNode->datum == d) { 770 return lNode; 771 } 772 lNode = lNode->nextPtr; 773 } while (lNode != NULL && lNode != list->firstPtr); 774 775 return NULL; 776 } 777 778 /*- 779 *----------------------------------------------------------------------- 780 * Lst_ForEach -- 781 * Apply the given function to each element of the given list. The 782 * function should return 0 if Lst_ForEach should continue and non- 783 * zero if it should abort. 784 * 785 * Results: 786 * None. 787 * 788 * Side Effects: 789 * Only those created by the passed-in function. 790 * 791 *----------------------------------------------------------------------- 792 */ 793 /*VARARGS2*/ 794 int 795 Lst_ForEach(Lst l, int (*proc)(void *, void *), void *d) 796 { 797 return Lst_ForEachFrom(l, Lst_First(l), proc, d); 798 } 799 800 /*- 801 *----------------------------------------------------------------------- 802 * Lst_ForEachFrom -- 803 * Apply the given function to each element of the given list, 804 * starting from a given point. 805 * 806 * If the list is circular, the application will wrap around to the 807 * beginning of the list again. 808 * 809 * The function should return 0 if traversal should continue, and 810 * non-zero if it should abort. 811 * 812 * Results: 813 * None. 814 * 815 * Side Effects: 816 * Only those created by the passed-in function. 817 * 818 *----------------------------------------------------------------------- 819 */ 820 /*VARARGS2*/ 821 int 822 Lst_ForEachFrom(Lst l, LstNode ln, int (*proc)(void *, void *), 823 void *d) 824 { 825 ListNode tln = ln; 826 List list = l; 827 ListNode next; 828 Boolean done; 829 int result; 830 831 if (!LstValid(list) || LstIsEmpty(list)) { 832 return 0; 833 } 834 835 do { 836 /* 837 * Take care of having the current element deleted out from under 838 * us. 839 */ 840 841 next = tln->nextPtr; 842 843 /* 844 * We're done with the traversal if 845 * - the next node to examine is the first in the queue or 846 * doesn't exist and 847 * - nothing's been added after the current node (check this 848 * after proc() has been called). 849 */ 850 done = (next == NULL || next == list->firstPtr); 851 852 (void)tln->useCount++; 853 result = (*proc)(tln->datum, d); 854 (void)tln->useCount--; 855 856 /* 857 * Now check whether a node has been added. 858 * Note: this doesn't work if this node was deleted before 859 * the new node was added. 860 */ 861 if (next != tln->nextPtr) { 862 next = tln->nextPtr; 863 done = 0; 864 } 865 866 if (tln->flags & LN_DELETED) { 867 free((char *)tln); 868 } 869 tln = next; 870 } while (!result && !LstIsEmpty(list) && !done); 871 872 return result; 873 } 874 875 /*- 876 *----------------------------------------------------------------------- 877 * Lst_Concat -- 878 * Concatenate two lists. New elements are created to hold the data 879 * elements, if specified, but the elements themselves are not copied. 880 * If the elements should be duplicated to avoid confusion with another 881 * list, the Lst_Duplicate function should be called first. 882 * If LST_CONCLINK is specified, the second list is destroyed since 883 * its pointers have been corrupted and the list is no longer useable. 884 * 885 * Input: 886 * l1 The list to which l2 is to be appended 887 * l2 The list to append to l1 888 * flags LST_CONCNEW if LstNode's should be duplicated 889 * LST_CONCLINK if should just be relinked 890 * 891 * Results: 892 * SUCCESS if all went well. FAILURE otherwise. 893 * 894 * Side Effects: 895 * New elements are created and appended the first list. 896 *----------------------------------------------------------------------- 897 */ 898 ReturnStatus 899 Lst_Concat(Lst l1, Lst l2, int flags) 900 { 901 ListNode ln; /* original LstNode */ 902 ListNode nln; /* new LstNode */ 903 ListNode last; /* the last element in the list. Keeps 904 * bookkeeping until the end */ 905 List list1 = l1; 906 List list2 = l2; 907 908 if (!LstValid(l1) || !LstValid(l2)) { 909 return FAILURE; 910 } 911 912 if (flags == LST_CONCLINK) { 913 if (list2->firstPtr != NULL) { 914 /* 915 * We set the nextPtr of the 916 * last element of list two to be NIL to make the loop easier and 917 * so we don't need an extra case should the first list turn 918 * out to be non-circular -- the final element will already point 919 * to NIL space and the first element will be untouched if it 920 * existed before and will also point to NIL space if it didn't. 921 */ 922 list2->lastPtr->nextPtr = NULL; 923 /* 924 * So long as the second list isn't empty, we just link the 925 * first element of the second list to the last element of the 926 * first list. If the first list isn't empty, we then link the 927 * last element of the list to the first element of the second list 928 * The last element of the second list, if it exists, then becomes 929 * the last element of the first list. 930 */ 931 list2->firstPtr->prevPtr = list1->lastPtr; 932 if (list1->lastPtr != NULL) { 933 list1->lastPtr->nextPtr = list2->firstPtr; 934 } else { 935 list1->firstPtr = list2->firstPtr; 936 } 937 list1->lastPtr = list2->lastPtr; 938 } 939 if (list1->isCirc && list1->firstPtr != NULL) { 940 /* 941 * If the first list is supposed to be circular and it is (now) 942 * non-empty, we must make sure it's circular by linking the 943 * first element to the last and vice versa 944 */ 945 list1->firstPtr->prevPtr = list1->lastPtr; 946 list1->lastPtr->nextPtr = list1->firstPtr; 947 } 948 free(l2); 949 } else if (list2->firstPtr != NULL) { 950 /* 951 * We set the nextPtr of the last element of list 2 to be nil to make 952 * the loop less difficult. The loop simply goes through the entire 953 * second list creating new LstNodes and filling in the nextPtr, and 954 * prevPtr to fit into l1 and its datum field from the 955 * datum field of the corresponding element in l2. The 'last' node 956 * follows the last of the new nodes along until the entire l2 has 957 * been appended. Only then does the bookkeeping catch up with the 958 * changes. During the first iteration of the loop, if 'last' is nil, 959 * the first list must have been empty so the newly-created node is 960 * made the first node of the list. 961 */ 962 list2->lastPtr->nextPtr = NULL; 963 for (last = list1->lastPtr, ln = list2->firstPtr; 964 ln != NULL; 965 ln = ln->nextPtr) 966 { 967 PAlloc (nln, ListNode); 968 nln->datum = ln->datum; 969 if (last != NULL) { 970 last->nextPtr = nln; 971 } else { 972 list1->firstPtr = nln; 973 } 974 nln->prevPtr = last; 975 nln->flags = nln->useCount = 0; 976 last = nln; 977 } 978 979 /* 980 * Finish bookkeeping. The last new element becomes the last element 981 * of list one. 982 */ 983 list1->lastPtr = last; 984 985 /* 986 * The circularity of both list one and list two must be corrected 987 * for -- list one because of the new nodes added to it; list two 988 * because of the alteration of list2->lastPtr's nextPtr to ease the 989 * above for loop. 990 */ 991 if (list1->isCirc) { 992 list1->lastPtr->nextPtr = list1->firstPtr; 993 list1->firstPtr->prevPtr = list1->lastPtr; 994 } else { 995 last->nextPtr = NULL; 996 } 997 998 if (list2->isCirc) { 999 list2->lastPtr->nextPtr = list2->firstPtr; 1000 } 1001 } 1002 1003 return SUCCESS; 1004 } 1005 1006 1007 /* 1008 * these functions are for dealing with a list as a table, of sorts. 1009 * An idea of the "current element" is kept and used by all the functions 1010 * between Lst_Open() and Lst_Close(). 1011 * 1012 * The sequential functions access the list in a slightly different way. 1013 * CurPtr points to their idea of the current node in the list and they 1014 * access the list based on it. 1015 * 1016 * If the list is circular, Lst_Next and Lst_Prev will go around the list 1017 * forever. Lst_IsAtEnd must be used to determine when to stop. 1018 */ 1019 1020 /*- 1021 *----------------------------------------------------------------------- 1022 * Lst_Open -- 1023 * Open a list for sequential access. A list can still be searched, 1024 * etc., without confusing these functions. 1025 * 1026 * Results: 1027 * SUCCESS or FAILURE. 1028 * 1029 * Side Effects: 1030 * isOpen is set TRUE and curPtr is set to NULL so the 1031 * other sequential functions know it was just opened and can choose 1032 * the first element accessed based on this. 1033 * 1034 *----------------------------------------------------------------------- 1035 */ 1036 ReturnStatus 1037 Lst_Open(Lst l) 1038 { 1039 if (LstValid(l) == FALSE) { 1040 return FAILURE; 1041 } 1042 l->isOpen = TRUE; 1043 l->atEnd = LstIsEmpty(l) ? Head : Unknown; 1044 l->curPtr = NULL; 1045 1046 return SUCCESS; 1047 } 1048 1049 /*- 1050 *----------------------------------------------------------------------- 1051 * Lst_Next -- 1052 * Return the next node for the given list. 1053 * 1054 * Results: 1055 * The next node or NULL if the list has yet to be opened. Also 1056 * if the list is non-circular and the end has been reached, NULL 1057 * is returned. 1058 * 1059 * Side Effects: 1060 * the curPtr field is updated. 1061 * 1062 *----------------------------------------------------------------------- 1063 */ 1064 LstNode 1065 Lst_Next(Lst l) 1066 { 1067 ListNode tln; 1068 List list = l; 1069 1070 if ((LstValid(l) == FALSE) || 1071 (list->isOpen == FALSE)) { 1072 return NULL; 1073 } 1074 1075 list->prevPtr = list->curPtr; 1076 1077 if (list->curPtr == NULL) { 1078 if (list->atEnd == Unknown) { 1079 /* 1080 * If we're just starting out, atEnd will be Unknown. 1081 * Then we want to start this thing off in the right 1082 * direction -- at the start with atEnd being Middle. 1083 */ 1084 list->curPtr = tln = list->firstPtr; 1085 list->atEnd = Middle; 1086 } else { 1087 tln = NULL; 1088 list->atEnd = Tail; 1089 } 1090 } else { 1091 tln = list->curPtr->nextPtr; 1092 list->curPtr = tln; 1093 1094 if (tln == list->firstPtr || tln == NULL) { 1095 /* 1096 * If back at the front, then we've hit the end... 1097 */ 1098 list->atEnd = Tail; 1099 } else { 1100 /* 1101 * Reset to Middle if gone past first. 1102 */ 1103 list->atEnd = Middle; 1104 } 1105 } 1106 1107 return tln; 1108 } 1109 1110 /*- 1111 *----------------------------------------------------------------------- 1112 * Lst_IsAtEnd -- 1113 * Return true if have reached the end of the given list. 1114 * 1115 * Results: 1116 * TRUE if at the end of the list (this includes the list not being 1117 * open or being invalid) or FALSE if not. We return TRUE if the list 1118 * is invalid or unopend so as to cause the caller to exit its loop 1119 * asap, the assumption being that the loop is of the form 1120 * while (!Lst_IsAtEnd (l)) { 1121 * ... 1122 * } 1123 * 1124 * Side Effects: 1125 * None. 1126 * 1127 *----------------------------------------------------------------------- 1128 */ 1129 Boolean 1130 Lst_IsAtEnd(Lst l) 1131 { 1132 List list = l; 1133 1134 return !LstValid(l) || !list->isOpen || 1135 list->atEnd == Head || list->atEnd == Tail; 1136 } 1137 1138 /*- 1139 *----------------------------------------------------------------------- 1140 * Lst_Close -- 1141 * Close a list which was opened for sequential access. 1142 * 1143 * Input: 1144 * l The list to close 1145 * 1146 * Results: 1147 * None. 1148 * 1149 * Side Effects: 1150 * The list is closed. 1151 * 1152 *----------------------------------------------------------------------- 1153 */ 1154 void 1155 Lst_Close(Lst l) 1156 { 1157 List list = l; 1158 1159 if (LstValid(l) == TRUE) { 1160 list->isOpen = FALSE; 1161 list->atEnd = Unknown; 1162 } 1163 } 1164 1165 1166 /* 1167 * for using the list as a queue 1168 */ 1169 1170 /*- 1171 *----------------------------------------------------------------------- 1172 * Lst_EnQueue -- 1173 * Add the datum to the tail of the given list. 1174 * 1175 * Results: 1176 * SUCCESS or FAILURE as returned by Lst_InsertAfter. 1177 * 1178 * Side Effects: 1179 * the lastPtr field is altered all the time and the firstPtr field 1180 * will be altered if the list used to be empty. 1181 * 1182 *----------------------------------------------------------------------- 1183 */ 1184 ReturnStatus 1185 Lst_EnQueue(Lst l, void *d) 1186 { 1187 if (LstValid(l) == FALSE) { 1188 return FAILURE; 1189 } 1190 1191 return Lst_InsertAfter(l, Lst_Last(l), d); 1192 } 1193 1194 /*- 1195 *----------------------------------------------------------------------- 1196 * Lst_DeQueue -- 1197 * Remove and return the datum at the head of the given list. 1198 * 1199 * Results: 1200 * The datum in the node at the head or NULL if the list 1201 * is empty. 1202 * 1203 * Side Effects: 1204 * The head node is removed from the list. 1205 * 1206 *----------------------------------------------------------------------- 1207 */ 1208 void * 1209 Lst_DeQueue(Lst l) 1210 { 1211 void *rd; 1212 ListNode tln; 1213 1214 tln = Lst_First(l); 1215 if (tln == NULL) { 1216 return NULL; 1217 } 1218 1219 rd = tln->datum; 1220 if (Lst_Remove(l, tln) == FAILURE) { 1221 return NULL; 1222 } else { 1223 return rd; 1224 } 1225 } 1226