140412Sbostic /*
262085Sbostic * Copyright (c) 1988, 1989, 1990, 1993
362085Sbostic * The Regents of the University of California. All rights reserved.
440411Sbostic *
540412Sbostic * This code is derived from software contributed to Berkeley by
640412Sbostic * Adam de Boor.
740411Sbostic *
842741Sbostic * %sccs.include.redist.c%
940411Sbostic */
1040412Sbostic
1140411Sbostic #ifndef lint
12*69094Schristos static char sccsid[] = "@(#)lstConcat.c 8.2 (Berkeley) 04/28/95";
1340412Sbostic #endif /* not lint */
1440411Sbostic
1540412Sbostic /*-
1640412Sbostic * listConcat.c --
1740412Sbostic * Function to concatentate two lists.
1840412Sbostic */
1940412Sbostic
2040411Sbostic #include "lstInt.h"
2140411Sbostic
2240411Sbostic /*-
2340411Sbostic *-----------------------------------------------------------------------
2440411Sbostic * Lst_Concat --
2540411Sbostic * Concatenate two lists. New elements are created to hold the data
2640411Sbostic * elements, if specified, but the elements themselves are not copied.
2740411Sbostic * If the elements should be duplicated to avoid confusion with another
2840411Sbostic * list, the Lst_Duplicate function should be called first.
2940411Sbostic * If LST_CONCLINK is specified, the second list is destroyed since
3040411Sbostic * its pointers have been corrupted and the list is no longer useable.
3140411Sbostic *
3240411Sbostic * Results:
3340411Sbostic * SUCCESS if all went well. FAILURE otherwise.
3440411Sbostic *
3540411Sbostic * Side Effects:
3640411Sbostic * New elements are created and appended the the first list.
3740411Sbostic *-----------------------------------------------------------------------
3840411Sbostic */
3940411Sbostic ReturnStatus
Lst_Concat(l1,l2,flags)4040411Sbostic Lst_Concat (l1, l2, flags)
4140411Sbostic Lst l1; /* The list to which l2 is to be appended */
4240411Sbostic Lst l2; /* The list to append to l1 */
4340411Sbostic int flags; /* LST_CONCNEW if LstNode's should be duplicated
4440411Sbostic * LST_CONCLINK if should just be relinked */
4540411Sbostic {
4640411Sbostic register ListNode ln; /* original LstNode */
4740411Sbostic register ListNode nln; /* new LstNode */
4840411Sbostic register ListNode last; /* the last element in the list. Keeps
4940411Sbostic * bookkeeping until the end */
5040411Sbostic register List list1 = (List)l1;
5140411Sbostic register List list2 = (List)l2;
5240411Sbostic
5340411Sbostic if (!LstValid (l1) || !LstValid (l2)) {
5440411Sbostic return (FAILURE);
5540411Sbostic }
5640411Sbostic
5740411Sbostic if (flags == LST_CONCLINK) {
5840411Sbostic if (list2->firstPtr != NilListNode) {
5940411Sbostic /*
6040411Sbostic * We set the nextPtr of the
6140411Sbostic * last element of list two to be NIL to make the loop easier and
6240411Sbostic * so we don't need an extra case should the first list turn
6340411Sbostic * out to be non-circular -- the final element will already point
6440411Sbostic * to NIL space and the first element will be untouched if it
6540411Sbostic * existed before and will also point to NIL space if it didn't.
6640411Sbostic */
6740411Sbostic list2->lastPtr->nextPtr = NilListNode;
6840411Sbostic /*
6940411Sbostic * So long as the second list isn't empty, we just link the
7040411Sbostic * first element of the second list to the last element of the
7140411Sbostic * first list. If the first list isn't empty, we then link the
7240411Sbostic * last element of the list to the first element of the second list
7340411Sbostic * The last element of the second list, if it exists, then becomes
7440411Sbostic * the last element of the first list.
7540411Sbostic */
7640411Sbostic list2->firstPtr->prevPtr = list1->lastPtr;
7740411Sbostic if (list1->lastPtr != NilListNode) {
7840411Sbostic list1->lastPtr->nextPtr = list2->firstPtr;
79*69094Schristos } else {
80*69094Schristos list1->firstPtr = list2->firstPtr;
8140411Sbostic }
8240411Sbostic list1->lastPtr = list2->lastPtr;
8340411Sbostic }
8440411Sbostic if (list1->isCirc && list1->firstPtr != NilListNode) {
8540411Sbostic /*
8640411Sbostic * If the first list is supposed to be circular and it is (now)
8740411Sbostic * non-empty, we must make sure it's circular by linking the
8840411Sbostic * first element to the last and vice versa
8940411Sbostic */
9040411Sbostic list1->firstPtr->prevPtr = list1->lastPtr;
9140411Sbostic list1->lastPtr->nextPtr = list1->firstPtr;
9240411Sbostic }
9340411Sbostic free ((Address)l2);
9440411Sbostic } else if (list2->firstPtr != NilListNode) {
9540411Sbostic /*
9640411Sbostic * We set the nextPtr of the last element of list 2 to be nil to make
9740411Sbostic * the loop less difficult. The loop simply goes through the entire
9840411Sbostic * second list creating new LstNodes and filling in the nextPtr, and
9940411Sbostic * prevPtr to fit into l1 and its datum field from the
10040411Sbostic * datum field of the corresponding element in l2. The 'last' node
10140411Sbostic * follows the last of the new nodes along until the entire l2 has
10240411Sbostic * been appended. Only then does the bookkeeping catch up with the
10340411Sbostic * changes. During the first iteration of the loop, if 'last' is nil,
10440411Sbostic * the first list must have been empty so the newly-created node is
10540411Sbostic * made the first node of the list.
10640411Sbostic */
10740411Sbostic list2->lastPtr->nextPtr = NilListNode;
10840411Sbostic for (last = list1->lastPtr, ln = list2->firstPtr;
10940411Sbostic ln != NilListNode;
11040411Sbostic ln = ln->nextPtr)
11140411Sbostic {
11240411Sbostic PAlloc (nln, ListNode);
11340411Sbostic nln->datum = ln->datum;
11440411Sbostic if (last != NilListNode) {
11540411Sbostic last->nextPtr = nln;
11640411Sbostic } else {
11740411Sbostic list1->firstPtr = nln;
11840411Sbostic }
11940411Sbostic nln->prevPtr = last;
12040411Sbostic nln->flags = nln->useCount = 0;
12140411Sbostic last = nln;
12240411Sbostic }
12340411Sbostic
12440411Sbostic /*
12540411Sbostic * Finish bookkeeping. The last new element becomes the last element
12640411Sbostic * of list one.
12740411Sbostic */
12840411Sbostic list1->lastPtr = last;
12940411Sbostic
13040411Sbostic /*
13140411Sbostic * The circularity of both list one and list two must be corrected
13240411Sbostic * for -- list one because of the new nodes added to it; list two
13340411Sbostic * because of the alteration of list2->lastPtr's nextPtr to ease the
13440411Sbostic * above for loop.
13540411Sbostic */
13640411Sbostic if (list1->isCirc) {
13740411Sbostic list1->lastPtr->nextPtr = list1->firstPtr;
13840411Sbostic list1->firstPtr->prevPtr = list1->lastPtr;
13940411Sbostic } else {
14040411Sbostic last->nextPtr = NilListNode;
14140411Sbostic }
14240411Sbostic
14340411Sbostic if (list2->isCirc) {
14440411Sbostic list2->lastPtr->nextPtr = list2->firstPtr;
14540411Sbostic }
14640411Sbostic }
14740411Sbostic
14840411Sbostic return (SUCCESS);
14940411Sbostic }
15040411Sbostic
151