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