1 /*
2  * $LynxId: HTList.c,v 1.19 2013/01/04 00:31:27 tom Exp $
3  *
4  *	A small List class					      HTList.c
5  *	==================
6  *
7  *	A list is represented as a sequence of linked nodes of type HTList.
8  *	The first node is a header which contains no object.
9  *	New nodes are inserted between the header and the rest of the list.
10  */
11 
12 #include <HTUtils.h>
13 #include <HTList.h>
14 
15 #include <LYLeaks.h>
16 
17 /*	Create list.
18 */
HTList_new(void)19 HTList *HTList_new(void)
20 {
21     HTList *newList;
22 
23     if ((newList = typeMalloc(HTList)) == NULL)
24 	  outofmem(__FILE__, "HTList_new");
25 
26     assert(newList != NULL);
27 
28     newList->object = NULL;
29     newList->next = NULL;
30 
31     return newList;
32 }
33 
34 /*	Delete list.
35 */
HTList_delete(HTList * me)36 void HTList_delete(HTList *me)
37 {
38     HTList *current;
39 
40     while ((current = me)) {
41 	me = me->next;
42 	FREE(current);
43     }
44 
45     return;
46 }
47 
48 /*	Reverse order of elements in list.
49  */
HTList_reverse(HTList * start)50 HTList *HTList_reverse(HTList *start)
51 {
52     HTList *cur, *succ;
53 
54     if (!(start && start->next && (cur = start->next->next)))
55 	return start;
56     start->next->next = NULL;
57     while (cur) {
58 	succ = cur->next;
59 	cur->next = start->next;
60 	start->next = cur;
61 	cur = succ;
62     }
63     return start;
64 }
65 
66 /*	Append a list to another.
67  *
68  *	If successful, the second list will become empty but not freed.
69  */
HTList_appendList(HTList * start,HTList * tail)70 HTList *HTList_appendList(HTList *start,
71 			  HTList *tail)
72 {
73     HTList *temp = start;
74 
75     if (!start) {
76 	CTRACE((tfp,
77 		"HTList: Trying to append list %p to a nonexisting list\n",
78 		(void *) tail));
79 	return NULL;
80     }
81     if (!(tail && tail->next))
82 	return start;
83 
84     while (temp->next)
85 	temp = temp->next;
86 
87     temp->next = tail->next;
88     tail->next = NULL;		/* tail is now an empty list */
89     return start;
90 }
91 
92 /*	Link object to START of list (so it is pointed to by the head).
93  *
94  *	Unlike HTList_addObject(), it does not malloc memory for HTList entry,
95  *	it use already allocated memory which should not be free'd by any
96  *	list operations (optimization).
97  */
HTList_linkObject(HTList * me,void * newObject,HTList * newNode)98 void HTList_linkObject(HTList *me, void *newObject,
99 		       HTList *newNode)
100 {
101     if (me) {
102 	if (newNode->object == NULL && newNode->next == NULL) {
103 	    /*  It is safe: */
104 	    newNode->object = newObject;
105 	    newNode->next = me->next;
106 	    me->next = newNode;
107 
108 	} else {
109 	    /*
110 	     * This node is already linked to some list (probably this one), so
111 	     * refuse changing node pointers to keep the list valid!!!
112 	     */
113 	    CTRACE((tfp, "*** HTList: Refuse linking already linked obj "));
114 	    CTRACE((tfp, "%p, node %p, list %p\n",
115 		    (void *) newObject, (void *) newNode, (void *) me));
116 	}
117 
118     } else {
119 	CTRACE((tfp,
120 		"HTList: Trying to link object %p to a nonexisting list\n",
121 		newObject));
122     }
123 
124     return;
125 }
126 
127 /*      Add object to START of list (so it is pointed to by the head).
128 */
HTList_addObject(HTList * me,void * newObject)129 void HTList_addObject(HTList *me, void *newObject)
130 {
131     HTList *newNode;
132 
133     if (me) {
134 	if ((newNode = typeMalloc(HTList)) == NULL)
135 	      outofmem(__FILE__, "HTList_addObject");
136 
137 	assert(newNode != NULL);
138 
139 	newNode->object = newObject;
140 	newNode->next = me->next;
141 	me->next = newNode;
142 
143     } else {
144 	CTRACE((tfp, "HTList: Trying to add object %p to a nonexisting list\n",
145 		newObject));
146     }
147 
148     return;
149 }
150 
151 /*      Append object to END of list (furthest from the head).
152 */
HTList_appendObject(HTList * me,void * newObject)153 void HTList_appendObject(HTList *me, void *newObject)
154 {
155     HTList *temp = me;
156 
157     if (temp && newObject) {
158 	while (temp->next)
159 	    temp = temp->next;
160 	HTList_addObject(temp, newObject);
161     }
162 
163     return;
164 }
165 
166 /*	Insert an object into the list at a specified position.
167  *      If position is 0, this places the object at the head of the list
168  *      and is equivalent to HTList_addObject().
169  */
HTList_insertObjectAt(HTList * me,void * newObject,int pos)170 void HTList_insertObjectAt(HTList *me, void *newObject,
171 			   int pos)
172 {
173     HTList *newNode;
174     HTList *temp = me;
175     HTList *prevNode;
176     int Pos = pos;
177 
178     if (!temp) {
179 	CTRACE((tfp, "HTList: Trying to add object %p to a nonexisting list\n",
180 		newObject));
181 	return;
182     }
183     if (Pos < 0) {
184 	Pos = 0;
185 	CTRACE((tfp, "HTList: Treating negative object position %d as %d.\n",
186 		pos, Pos));
187     }
188 
189     prevNode = temp;
190     while ((temp = temp->next)) {
191 	if (Pos == 0) {
192 	    if ((newNode = typeMalloc(HTList)) == NULL)
193 		  outofmem(__FILE__, "HTList_addObjectAt");
194 
195 	    assert(newNode != NULL);
196 
197 	    newNode->object = newObject;
198 	    newNode->next = temp;
199 	    if (prevNode)
200 		prevNode->next = newNode;
201 	    return;
202 	}
203 	prevNode = temp;
204 	Pos--;
205     }
206     if (Pos >= 0)
207 	HTList_addObject(prevNode, newObject);
208 
209     return;
210 }
211 
212 /*	Unlink specified object from list.
213  *	It does not free memory.
214  */
HTList_unlinkObject(HTList * me,void * oldObject)215 BOOL HTList_unlinkObject(HTList *me, void *oldObject)
216 {
217     HTList *temp = me;
218     HTList *prevNode;
219 
220     if (temp && oldObject) {
221 	while (temp->next) {
222 	    prevNode = temp;
223 	    temp = temp->next;
224 	    if (temp->object == oldObject) {
225 		prevNode->next = temp->next;
226 		temp->next = NULL;
227 		temp->object = NULL;
228 		return YES;	/* Success */
229 	    }
230 	}
231     }
232     return NO;			/* object not found or NULL list */
233 }
234 
235 /*	Remove specified object from list.
236 */
HTList_removeObject(HTList * me,void * oldObject)237 BOOL HTList_removeObject(HTList *me, void *oldObject)
238 {
239     HTList *temp = me;
240     HTList *prevNode;
241 
242     if (temp && oldObject) {
243 	while (temp->next) {
244 	    prevNode = temp;
245 	    temp = temp->next;
246 	    if (temp->object == oldObject) {
247 		prevNode->next = temp->next;
248 		FREE(temp);
249 		return YES;	/* Success */
250 	    }
251 	}
252     }
253     return NO;			/* object not found or NULL list */
254 }
255 
256 /*	Remove object at a given position in the list, where 0 is the
257  *	object pointed to by the head (returns a pointer to the element
258  *	(->object) for the object, and NULL if the list is empty, or
259  *	if it doesn't exist - Yuk!).
260  */
HTList_removeObjectAt(HTList * me,int position)261 void *HTList_removeObjectAt(HTList *me, int position)
262 {
263     HTList *temp = me;
264     HTList *prevNode;
265     int pos = position;
266     void *result = NULL;
267 
268     if (temp != NULL && pos >= 0) {
269 	prevNode = temp;
270 	while ((temp = temp->next) != NULL) {
271 	    if (pos == 0) {
272 		prevNode->next = temp->next;
273 		result = temp->object;
274 		FREE(temp);
275 		break;
276 	    }
277 	    prevNode = temp;
278 	    pos--;
279 	}
280     }
281 
282     return result;
283 }
284 
285 /*	Unlink object from START of list (the Last one inserted
286  *	via HTList_linkObject(), and pointed to by the head).
287  *	It does not free memory.
288  */
HTList_unlinkLastObject(HTList * me)289 void *HTList_unlinkLastObject(HTList *me)
290 {
291     HTList *lastNode;
292     void *lastObject;
293 
294     if (me && me->next) {
295 	lastNode = me->next;
296 	lastObject = lastNode->object;
297 	me->next = lastNode->next;
298 	lastNode->next = NULL;
299 	lastNode->object = NULL;
300 	return lastObject;
301 
302     } else {			/* Empty list */
303 	return NULL;
304     }
305 }
306 
307 /*	Remove object from START of list (the Last one inserted
308  *	via HTList_addObject(), and pointed to by the head).
309  */
HTList_removeLastObject(HTList * me)310 void *HTList_removeLastObject(HTList *me)
311 {
312     HTList *lastNode;
313     void *lastObject;
314 
315     if (me && me->next) {
316 	lastNode = me->next;
317 	lastObject = lastNode->object;
318 	me->next = lastNode->next;
319 	FREE(lastNode);
320 	return lastObject;
321 
322     } else {			/* Empty list */
323 	return NULL;
324     }
325 }
326 
327 /*	Remove object from END of list (the First one inserted
328  *	via HTList_addObject(), and furthest from the head).
329  */
HTList_removeFirstObject(HTList * me)330 void *HTList_removeFirstObject(HTList *me)
331 {
332     HTList *temp = me;
333     HTList *prevNode;
334     void *firstObject;
335 
336     if (!temp)
337 	return NULL;
338 
339     prevNode = temp;
340     if (temp->next) {
341 	while (temp->next) {
342 	    prevNode = temp;
343 	    temp = temp->next;
344 	}
345 	firstObject = temp->object;
346 	prevNode->next = NULL;
347 	FREE(temp);
348 	return firstObject;
349 
350     } else {			/* Empty list */
351 	return NULL;
352     }
353 }
354 
355 /*	Determine total number of objects in the list,
356  *	not counting the head.
357  */
HTList_count(HTList * me)358 int HTList_count(HTList *me)
359 {
360     HTList *temp = me;
361     int count = 0;
362 
363     if (temp)
364 	while ((temp = temp->next))
365 	    count++;
366 
367     return count;
368 }
369 
370 /*	Determine position of an object in the list (a value of 0
371  *	means it is pointed to by the head; returns -1 if not found).
372  */
HTList_indexOf(HTList * me,void * object)373 int HTList_indexOf(HTList *me, void *object)
374 {
375     HTList *temp = me;
376     int position = 0;
377 
378     if (temp) {
379 	while ((temp = temp->next)) {
380 	    if (temp->object == object)
381 		return position;
382 	    position++;
383 	}
384     }
385 
386     return -1;			/* Object not in the list */
387 }
388 
389 /*	Return pointer to the object at a specified position in the list,
390  *	where 0 is the object pointed to by the head (returns NULL if
391  *	the list is empty, or if it doesn't exist - Yuk!).
392  */
HTList_objectAt(HTList * me,int position)393 void *HTList_objectAt(HTList *me, int position)
394 {
395     HTList *temp = me;
396     int pos = position;
397 
398     if (!temp || pos < 0)
399 	return NULL;
400 
401     while ((temp = temp->next)) {
402 	if (pos == 0)
403 	    return temp->object;
404 	pos--;
405     }
406 
407     return NULL;		/* Reached the end of the list */
408 }
409