1*40411Sbostic /*-
2*40411Sbostic  * listConcat.c --
3*40411Sbostic  *	Function to concatentate two lists.
4*40411Sbostic  *
5*40411Sbostic  * Copyright (c) 1988 by the Regents of the University of California
6*40411Sbostic  *
7*40411Sbostic  * Permission to use, copy, modify, and distribute this
8*40411Sbostic  * software and its documentation for any purpose and without
9*40411Sbostic  * fee is hereby granted, provided that the above copyright
10*40411Sbostic  * notice appears in all copies.  Neither the University of California nor
11*40411Sbostic  * Adam de Boor makes any representations about the suitability of this
12*40411Sbostic  * software for any purpose.  It is provided "as is" without
13*40411Sbostic  * express or implied warranty.
14*40411Sbostic  *
15*40411Sbostic  */
16*40411Sbostic #ifndef lint
17*40411Sbostic static char *rcsid =
18*40411Sbostic "$Id: lstConcat.c,v 1.6 89/07/06 12:50:04 adam Exp $ SPRITE (Berkeley)";
19*40411Sbostic #endif lint
20*40411Sbostic 
21*40411Sbostic #include    "lstInt.h"
22*40411Sbostic 
23*40411Sbostic /*-
24*40411Sbostic  *-----------------------------------------------------------------------
25*40411Sbostic  * Lst_Concat --
26*40411Sbostic  *	Concatenate two lists. New elements are created to hold the data
27*40411Sbostic  *	elements, if specified, but the elements themselves are not copied.
28*40411Sbostic  *	If the elements should be duplicated to avoid confusion with another
29*40411Sbostic  *	list, the Lst_Duplicate function should be called first.
30*40411Sbostic  *	If LST_CONCLINK is specified, the second list is destroyed since
31*40411Sbostic  *	its pointers have been corrupted and the list is no longer useable.
32*40411Sbostic  *
33*40411Sbostic  * Results:
34*40411Sbostic  *	SUCCESS if all went well. FAILURE otherwise.
35*40411Sbostic  *
36*40411Sbostic  * Side Effects:
37*40411Sbostic  *	New elements are created and appended the the first list.
38*40411Sbostic  *-----------------------------------------------------------------------
39*40411Sbostic  */
40*40411Sbostic ReturnStatus
41*40411Sbostic Lst_Concat (l1, l2, flags)
42*40411Sbostic     Lst    	  	l1; 	/* The list to which l2 is to be appended */
43*40411Sbostic     Lst    	  	l2; 	/* The list to append to l1 */
44*40411Sbostic     int	   	  	flags;  /* LST_CONCNEW if LstNode's should be duplicated
45*40411Sbostic 				 * LST_CONCLINK if should just be relinked */
46*40411Sbostic {
47*40411Sbostic     register ListNode  	ln;     /* original LstNode */
48*40411Sbostic     register ListNode  	nln;    /* new LstNode */
49*40411Sbostic     register ListNode  	last;   /* the last element in the list. Keeps
50*40411Sbostic 				 * bookkeeping until the end */
51*40411Sbostic     register List 	list1 = (List)l1;
52*40411Sbostic     register List 	list2 = (List)l2;
53*40411Sbostic 
54*40411Sbostic     if (!LstValid (l1) || !LstValid (l2)) {
55*40411Sbostic 	return (FAILURE);
56*40411Sbostic     }
57*40411Sbostic 
58*40411Sbostic     if (flags == LST_CONCLINK) {
59*40411Sbostic 	if (list2->firstPtr != NilListNode) {
60*40411Sbostic 	    /*
61*40411Sbostic 	     * We set the nextPtr of the
62*40411Sbostic 	     * last element of list two to be NIL to make the loop easier and
63*40411Sbostic 	     * so we don't need an extra case should the first list turn
64*40411Sbostic 	     * out to be non-circular -- the final element will already point
65*40411Sbostic 	     * to NIL space and the first element will be untouched if it
66*40411Sbostic 	     * existed before and will also point to NIL space if it didn't.
67*40411Sbostic 	     */
68*40411Sbostic 	    list2->lastPtr->nextPtr = NilListNode;
69*40411Sbostic 	    /*
70*40411Sbostic 	     * So long as the second list isn't empty, we just link the
71*40411Sbostic 	     * first element of the second list to the last element of the
72*40411Sbostic 	     * first list. If the first list isn't empty, we then link the
73*40411Sbostic 	     * last element of the list to the first element of the second list
74*40411Sbostic 	     * The last element of the second list, if it exists, then becomes
75*40411Sbostic 	     * the last element of the first list.
76*40411Sbostic 	     */
77*40411Sbostic 	    list2->firstPtr->prevPtr = list1->lastPtr;
78*40411Sbostic 	    if (list1->lastPtr != NilListNode) {
79*40411Sbostic  		list1->lastPtr->nextPtr = list2->firstPtr;
80*40411Sbostic 	    }
81*40411Sbostic 	    list1->lastPtr = list2->lastPtr;
82*40411Sbostic 	}
83*40411Sbostic 	if (list1->isCirc && list1->firstPtr != NilListNode) {
84*40411Sbostic 	    /*
85*40411Sbostic 	     * If the first list is supposed to be circular and it is (now)
86*40411Sbostic 	     * non-empty, we must make sure it's circular by linking the
87*40411Sbostic 	     * first element to the last and vice versa
88*40411Sbostic 	     */
89*40411Sbostic 	    list1->firstPtr->prevPtr = list1->lastPtr;
90*40411Sbostic 	    list1->lastPtr->nextPtr = list1->firstPtr;
91*40411Sbostic 	}
92*40411Sbostic 	free ((Address)l2);
93*40411Sbostic     } else if (list2->firstPtr != NilListNode) {
94*40411Sbostic 	/*
95*40411Sbostic 	 * We set the nextPtr of the last element of list 2 to be nil to make
96*40411Sbostic 	 * the loop less difficult. The loop simply goes through the entire
97*40411Sbostic 	 * second list creating new LstNodes and filling in the nextPtr, and
98*40411Sbostic 	 * prevPtr to fit into l1 and its datum field from the
99*40411Sbostic 	 * datum field of the corresponding element in l2. The 'last' node
100*40411Sbostic 	 * follows the last of the new nodes along until the entire l2 has
101*40411Sbostic 	 * been appended. Only then does the bookkeeping catch up with the
102*40411Sbostic 	 * changes. During the first iteration of the loop, if 'last' is nil,
103*40411Sbostic 	 * the first list must have been empty so the newly-created node is
104*40411Sbostic 	 * made the first node of the list.
105*40411Sbostic 	 */
106*40411Sbostic 	list2->lastPtr->nextPtr = NilListNode;
107*40411Sbostic 	for (last = list1->lastPtr, ln = list2->firstPtr;
108*40411Sbostic 	     ln != NilListNode;
109*40411Sbostic 	     ln = ln->nextPtr)
110*40411Sbostic 	{
111*40411Sbostic 	    PAlloc (nln, ListNode);
112*40411Sbostic 	    nln->datum = ln->datum;
113*40411Sbostic 	    if (last != NilListNode) {
114*40411Sbostic 		last->nextPtr = nln;
115*40411Sbostic 	    } else {
116*40411Sbostic 		list1->firstPtr = nln;
117*40411Sbostic 	    }
118*40411Sbostic 	    nln->prevPtr = last;
119*40411Sbostic 	    nln->flags = nln->useCount = 0;
120*40411Sbostic 	    last = nln;
121*40411Sbostic 	}
122*40411Sbostic 
123*40411Sbostic 	/*
124*40411Sbostic 	 * Finish bookkeeping. The last new element becomes the last element
125*40411Sbostic 	 * of list one.
126*40411Sbostic 	 */
127*40411Sbostic 	list1->lastPtr = last;
128*40411Sbostic 
129*40411Sbostic 	/*
130*40411Sbostic 	 * The circularity of both list one and list two must be corrected
131*40411Sbostic 	 * for -- list one because of the new nodes added to it; list two
132*40411Sbostic 	 * because of the alteration of list2->lastPtr's nextPtr to ease the
133*40411Sbostic 	 * above for loop.
134*40411Sbostic 	 */
135*40411Sbostic 	if (list1->isCirc) {
136*40411Sbostic 	    list1->lastPtr->nextPtr = list1->firstPtr;
137*40411Sbostic 	    list1->firstPtr->prevPtr = list1->lastPtr;
138*40411Sbostic 	} else {
139*40411Sbostic 	    last->nextPtr = NilListNode;
140*40411Sbostic 	}
141*40411Sbostic 
142*40411Sbostic 	if (list2->isCirc) {
143*40411Sbostic 	    list2->lastPtr->nextPtr = list2->firstPtr;
144*40411Sbostic 	}
145*40411Sbostic     }
146*40411Sbostic 
147*40411Sbostic     return (SUCCESS);
148*40411Sbostic }
149*40411Sbostic 
150