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