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