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