1*40412Sbostic /* 2*40412Sbostic * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 3*40412Sbostic * All rights reserved. 440411Sbostic * 5*40412Sbostic * This code is derived from software contributed to Berkeley by 6*40412Sbostic * Adam de Boor. 740411Sbostic * 8*40412Sbostic * Redistribution and use in source and binary forms are permitted 9*40412Sbostic * provided that the above copyright notice and this paragraph are 10*40412Sbostic * duplicated in all such forms and that any documentation, 11*40412Sbostic * advertising materials, and other materials related to such 12*40412Sbostic * distribution and use acknowledge that the software was developed 13*40412Sbostic * by the University of California, Berkeley. The name of the 14*40412Sbostic * University may not be used to endorse or promote products derived 15*40412Sbostic * from this software without specific prior written permission. 16*40412Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17*40412Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18*40412Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1940411Sbostic */ 20*40412Sbostic 2140411Sbostic #ifndef lint 22*40412Sbostic static char sccsid[] = "@(#)lstConcat.c 5.2 (Berkeley) 03/11/90"; 23*40412Sbostic #endif /* not lint */ 2440411Sbostic 25*40412Sbostic /*- 26*40412Sbostic * listConcat.c -- 27*40412Sbostic * Function to concatentate two lists. 28*40412Sbostic */ 29*40412Sbostic 3040411Sbostic #include "lstInt.h" 3140411Sbostic 3240411Sbostic /*- 3340411Sbostic *----------------------------------------------------------------------- 3440411Sbostic * Lst_Concat -- 3540411Sbostic * Concatenate two lists. New elements are created to hold the data 3640411Sbostic * elements, if specified, but the elements themselves are not copied. 3740411Sbostic * If the elements should be duplicated to avoid confusion with another 3840411Sbostic * list, the Lst_Duplicate function should be called first. 3940411Sbostic * If LST_CONCLINK is specified, the second list is destroyed since 4040411Sbostic * its pointers have been corrupted and the list is no longer useable. 4140411Sbostic * 4240411Sbostic * Results: 4340411Sbostic * SUCCESS if all went well. FAILURE otherwise. 4440411Sbostic * 4540411Sbostic * Side Effects: 4640411Sbostic * New elements are created and appended the the first list. 4740411Sbostic *----------------------------------------------------------------------- 4840411Sbostic */ 4940411Sbostic ReturnStatus 5040411Sbostic Lst_Concat (l1, l2, flags) 5140411Sbostic Lst l1; /* The list to which l2 is to be appended */ 5240411Sbostic Lst l2; /* The list to append to l1 */ 5340411Sbostic int flags; /* LST_CONCNEW if LstNode's should be duplicated 5440411Sbostic * LST_CONCLINK if should just be relinked */ 5540411Sbostic { 5640411Sbostic register ListNode ln; /* original LstNode */ 5740411Sbostic register ListNode nln; /* new LstNode */ 5840411Sbostic register ListNode last; /* the last element in the list. Keeps 5940411Sbostic * bookkeeping until the end */ 6040411Sbostic register List list1 = (List)l1; 6140411Sbostic register List list2 = (List)l2; 6240411Sbostic 6340411Sbostic if (!LstValid (l1) || !LstValid (l2)) { 6440411Sbostic return (FAILURE); 6540411Sbostic } 6640411Sbostic 6740411Sbostic if (flags == LST_CONCLINK) { 6840411Sbostic if (list2->firstPtr != NilListNode) { 6940411Sbostic /* 7040411Sbostic * We set the nextPtr of the 7140411Sbostic * last element of list two to be NIL to make the loop easier and 7240411Sbostic * so we don't need an extra case should the first list turn 7340411Sbostic * out to be non-circular -- the final element will already point 7440411Sbostic * to NIL space and the first element will be untouched if it 7540411Sbostic * existed before and will also point to NIL space if it didn't. 7640411Sbostic */ 7740411Sbostic list2->lastPtr->nextPtr = NilListNode; 7840411Sbostic /* 7940411Sbostic * So long as the second list isn't empty, we just link the 8040411Sbostic * first element of the second list to the last element of the 8140411Sbostic * first list. If the first list isn't empty, we then link the 8240411Sbostic * last element of the list to the first element of the second list 8340411Sbostic * The last element of the second list, if it exists, then becomes 8440411Sbostic * the last element of the first list. 8540411Sbostic */ 8640411Sbostic list2->firstPtr->prevPtr = list1->lastPtr; 8740411Sbostic if (list1->lastPtr != NilListNode) { 8840411Sbostic list1->lastPtr->nextPtr = list2->firstPtr; 8940411Sbostic } 9040411Sbostic list1->lastPtr = list2->lastPtr; 9140411Sbostic } 9240411Sbostic if (list1->isCirc && list1->firstPtr != NilListNode) { 9340411Sbostic /* 9440411Sbostic * If the first list is supposed to be circular and it is (now) 9540411Sbostic * non-empty, we must make sure it's circular by linking the 9640411Sbostic * first element to the last and vice versa 9740411Sbostic */ 9840411Sbostic list1->firstPtr->prevPtr = list1->lastPtr; 9940411Sbostic list1->lastPtr->nextPtr = list1->firstPtr; 10040411Sbostic } 10140411Sbostic free ((Address)l2); 10240411Sbostic } else if (list2->firstPtr != NilListNode) { 10340411Sbostic /* 10440411Sbostic * We set the nextPtr of the last element of list 2 to be nil to make 10540411Sbostic * the loop less difficult. The loop simply goes through the entire 10640411Sbostic * second list creating new LstNodes and filling in the nextPtr, and 10740411Sbostic * prevPtr to fit into l1 and its datum field from the 10840411Sbostic * datum field of the corresponding element in l2. The 'last' node 10940411Sbostic * follows the last of the new nodes along until the entire l2 has 11040411Sbostic * been appended. Only then does the bookkeeping catch up with the 11140411Sbostic * changes. During the first iteration of the loop, if 'last' is nil, 11240411Sbostic * the first list must have been empty so the newly-created node is 11340411Sbostic * made the first node of the list. 11440411Sbostic */ 11540411Sbostic list2->lastPtr->nextPtr = NilListNode; 11640411Sbostic for (last = list1->lastPtr, ln = list2->firstPtr; 11740411Sbostic ln != NilListNode; 11840411Sbostic ln = ln->nextPtr) 11940411Sbostic { 12040411Sbostic PAlloc (nln, ListNode); 12140411Sbostic nln->datum = ln->datum; 12240411Sbostic if (last != NilListNode) { 12340411Sbostic last->nextPtr = nln; 12440411Sbostic } else { 12540411Sbostic list1->firstPtr = nln; 12640411Sbostic } 12740411Sbostic nln->prevPtr = last; 12840411Sbostic nln->flags = nln->useCount = 0; 12940411Sbostic last = nln; 13040411Sbostic } 13140411Sbostic 13240411Sbostic /* 13340411Sbostic * Finish bookkeeping. The last new element becomes the last element 13440411Sbostic * of list one. 13540411Sbostic */ 13640411Sbostic list1->lastPtr = last; 13740411Sbostic 13840411Sbostic /* 13940411Sbostic * The circularity of both list one and list two must be corrected 14040411Sbostic * for -- list one because of the new nodes added to it; list two 14140411Sbostic * because of the alteration of list2->lastPtr's nextPtr to ease the 14240411Sbostic * above for loop. 14340411Sbostic */ 14440411Sbostic if (list1->isCirc) { 14540411Sbostic list1->lastPtr->nextPtr = list1->firstPtr; 14640411Sbostic list1->firstPtr->prevPtr = list1->lastPtr; 14740411Sbostic } else { 14840411Sbostic last->nextPtr = NilListNode; 14940411Sbostic } 15040411Sbostic 15140411Sbostic if (list2->isCirc) { 15240411Sbostic list2->lastPtr->nextPtr = list2->firstPtr; 15340411Sbostic } 15440411Sbostic } 15540411Sbostic 15640411Sbostic return (SUCCESS); 15740411Sbostic } 15840411Sbostic 159