dsrc isn't necessary for this repo
[client-tools.git] / src / external / 3rd / library / libxml / list.c
blob18a82973e5c36109e71c4f54dcd18909e8c31ca2
1 /*
2 * list.c: lists handling implementation
4 * Copyright (C) 2000 Gary Pennington and Daniel Veillard.
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
11 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
12 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
13 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
15 * Author: Gary.Pennington@uk.sun.com
18 #define IN_LIBXML
19 #include "libxml.h"
21 #include <stdlib.h>
22 #include <string.h>
23 #include <libxml/xmlmemory.h>
24 #include <libxml/list.h>
25 #include <libxml/globals.h>
28 * Type definition are kept internal
31 struct _xmlLink
33 struct _xmlLink *next;
34 struct _xmlLink *prev;
35 void *data;
38 struct _xmlList
40 xmlLinkPtr sentinel;
41 void (*linkDeallocator)(xmlLinkPtr );
42 int (*linkCompare)(const void *, const void*);
45 /************************************************************************
46 * *
47 * Interfaces *
48 * *
49 ************************************************************************/
51 /**
52 * xmlLinkDeallocator:
53 * @l: a list
54 * @lk: a link
56 * Unlink and deallocate @lk from list @l
58 static void
59 xmlLinkDeallocator(xmlListPtr l, xmlLinkPtr lk)
61 (lk->prev)->next = lk->next;
62 (lk->next)->prev = lk->prev;
63 if(l->linkDeallocator)
64 l->linkDeallocator(lk);
65 xmlFree(lk);
68 /**
69 * xmlLinkCompare:
70 * @data0: first data
71 * @data1: second data
73 * Compares two arbitrary data
75 * Returns -1, 0 or 1 depending on whether data1 is greater equal or smaller
76 * than data0
78 static int
79 xmlLinkCompare(const void *data0, const void *data1)
81 if (data0 < data1)
82 return (-1);
83 else if (data0 == data1)
84 return (0);
85 return (1);
88 /**
89 * xmlListLowerSearch:
90 * @l: a list
91 * @data: a data
93 * Search data in the ordered list walking from the beginning
95 * Returns the link containing the data or NULL
97 static xmlLinkPtr
98 xmlListLowerSearch(xmlListPtr l, void *data)
100 xmlLinkPtr lk;
102 for(lk = l->sentinel->next;lk != l->sentinel && l->linkCompare(lk->data, data) <0 ;lk = lk->next);
103 return lk;
107 * xmlListHigherSearch:
108 * @l: a list
109 * @data: a data
111 * Search data in the ordered list walking backward from the end
113 * Returns the link containing the data or NULL
115 static xmlLinkPtr
116 xmlListHigherSearch(xmlListPtr l, void *data)
118 xmlLinkPtr lk;
120 for(lk = l->sentinel->prev;lk != l->sentinel && l->linkCompare(lk->data, data) >0 ;lk = lk->prev);
121 return lk;
125 * xmlListSearch:
126 * @l: a list
127 * @data: a data
129 * Search data in the list
131 * Returns the link containing the data or NULL
133 static xmlLinkPtr
134 xmlListLinkSearch(xmlListPtr l, void *data)
136 xmlLinkPtr lk;
137 lk = xmlListLowerSearch(l, data);
138 if (lk == l->sentinel)
139 return NULL;
140 else {
141 if (l->linkCompare(lk->data, data) ==0)
142 return lk;
143 return NULL;
148 * xmlListLinkReverseSearch:
149 * @l: a list
150 * @data: a data
152 * Search data in the list processing backward
154 * Returns the link containing the data or NULL
156 static xmlLinkPtr
157 xmlListLinkReverseSearch(xmlListPtr l, void *data)
159 xmlLinkPtr lk;
160 lk = xmlListHigherSearch(l, data);
161 if (lk == l->sentinel)
162 return NULL;
163 else {
164 if (l->linkCompare(lk->data, data) ==0)
165 return lk;
166 return NULL;
171 * xmlListCreate:
172 * @deallocator: an optional deallocator function
173 * @compare: an optional comparison function
175 * Create a new list
177 * Returns the new list or NULL in case of error
179 xmlListPtr
180 xmlListCreate(xmlListDeallocator deallocator, xmlListDataCompare compare)
182 xmlListPtr l;
183 if (NULL == (l = (xmlListPtr )xmlMalloc( sizeof(xmlList)))) {
184 xmlGenericError(xmlGenericErrorContext,
185 "Cannot initialize memory for list");
186 return (NULL);
188 /* Initialize the list to NULL */
189 memset(l, 0, sizeof(xmlList));
191 /* Add the sentinel */
192 if (NULL ==(l->sentinel = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) {
193 xmlGenericError(xmlGenericErrorContext,
194 "Cannot initialize memory for sentinel");
195 xmlFree(l);
196 return (NULL);
198 l->sentinel->next = l->sentinel;
199 l->sentinel->prev = l->sentinel;
200 l->sentinel->data = NULL;
202 /* If there is a link deallocator, use it */
203 if (deallocator != NULL)
204 l->linkDeallocator = deallocator;
205 /* If there is a link comparator, use it */
206 if (compare != NULL)
207 l->linkCompare = compare;
208 else /* Use our own */
209 l->linkCompare = xmlLinkCompare;
210 return l;
214 * xmlListSearch:
215 * @l: a list
216 * @data: a search value
218 * Search the list for an existing value of @data
220 * Returns the value associated to @data or NULL in case of error
222 void *
223 xmlListSearch(xmlListPtr l, void *data)
225 xmlLinkPtr lk;
226 lk = xmlListLinkSearch(l, data);
227 if (lk)
228 return (lk->data);
229 return NULL;
233 * xmlListReverseSearch:
234 * @l: a list
235 * @data: a search value
237 * Search the list in reverse order for an existing value of @data
239 * Returns the value associated to @data or NULL in case of error
241 void *
242 xmlListReverseSearch(xmlListPtr l, void *data)
244 xmlLinkPtr lk;
245 lk = xmlListLinkReverseSearch(l, data);
246 if (lk)
247 return (lk->data);
248 return NULL;
252 * xmlListInsert:
253 * @l: a list
254 * @data: the data
256 * Insert data in the ordered list at the beginning for this value
258 * Returns 0 in case of success, 1 in case of failure
261 xmlListInsert(xmlListPtr l, void *data)
263 xmlLinkPtr lkPlace, lkNew;
265 lkPlace = xmlListLowerSearch(l, data);
266 /* Add the new link */
267 lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
268 if (lkNew == NULL) {
269 xmlGenericError(xmlGenericErrorContext,
270 "Cannot initialize memory for new link");
271 return (1);
273 lkNew->data = data;
274 lkPlace = lkPlace->prev;
275 lkNew->next = lkPlace->next;
276 (lkPlace->next)->prev = lkNew;
277 lkPlace->next = lkNew;
278 lkNew->prev = lkPlace;
279 return 0;
283 * xmlListAppend:
284 * @l: a list
285 * @data: the data
287 * Insert data in the ordered list at the end for this value
289 * Returns 0 in case of success, 1 in case of failure
291 int xmlListAppend(xmlListPtr l, void *data)
293 xmlLinkPtr lkPlace, lkNew;
295 lkPlace = xmlListHigherSearch(l, data);
296 /* Add the new link */
297 lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
298 if (lkNew == NULL) {
299 xmlGenericError(xmlGenericErrorContext,
300 "Cannot initialize memory for new link");
301 return (0);
303 lkNew->data = data;
304 lkNew->next = lkPlace->next;
305 (lkPlace->next)->prev = lkNew;
306 lkPlace->next = lkNew;
307 lkNew->prev = lkPlace;
308 return 1;
312 * xmlListDelete:
313 * @l: a list
315 * Deletes the list and its associated data
317 void xmlListDelete(xmlListPtr l)
319 xmlListClear(l);
320 xmlFree(l->sentinel);
321 xmlFree(l);
325 * xmlListRemoveFirst:
326 * @l: a list
327 * @data: list data
329 * Remove the first instance associated to data in the list
331 * Returns 1 if a deallocation occured, or 0 if not found
334 xmlListRemoveFirst(xmlListPtr l, void *data)
336 xmlLinkPtr lk;
338 /*Find the first instance of this data */
339 lk = xmlListLinkSearch(l, data);
340 if (lk != NULL) {
341 xmlLinkDeallocator(l, lk);
342 return 1;
344 return 0;
348 * xmlListRemoveLast:
349 * @l: a list
350 * @data: list data
352 * Remove the last instance associated to data in the list
354 * Returns 1 if a deallocation occured, or 0 if not found
357 xmlListRemoveLast(xmlListPtr l, void *data)
359 xmlLinkPtr lk;
361 /*Find the last instance of this data */
362 lk = xmlListLinkReverseSearch(l, data);
363 if (lk != NULL) {
364 xmlLinkDeallocator(l, lk);
365 return 1;
367 return 0;
371 * xmlListRemoveAll:
372 * @l: a list
373 * @data: list data
375 * Remove the all instance associated to data in the list
377 * Returns the number of deallocation, or 0 if not found
380 xmlListRemoveAll(xmlListPtr l, void *data)
382 int count=0;
385 while(xmlListRemoveFirst(l, data))
386 count++;
387 return count;
391 * xmlListClear:
392 * @l: a list
394 * Remove the all data in the list
396 void
397 xmlListClear(xmlListPtr l)
399 xmlLinkPtr lk = l->sentinel->next;
401 while(lk != l->sentinel) {
402 xmlLinkPtr next = lk->next;
404 xmlLinkDeallocator(l, lk);
405 lk = next;
410 * xmlListEmpty:
411 * @l: a list
413 * Is the list empty ?
415 * Returns 1 if the list is empty, 0 otherwise
418 xmlListEmpty(xmlListPtr l)
420 return (l->sentinel->next == l->sentinel);
424 * xmlListFront:
425 * @l: a list
427 * Get the first element in the list
429 * Returns the first element in the list, or NULL
431 xmlLinkPtr
432 xmlListFront(xmlListPtr l)
434 return (l->sentinel->next);
438 * xmlListEnd:
439 * @l: a list
441 * Get the last element in the list
443 * Returns the last element in the list, or NULL
445 xmlLinkPtr
446 xmlListEnd(xmlListPtr l)
448 return (l->sentinel->prev);
452 * xmlListSize:
453 * @l: a list
455 * Get the number of elements in the list
457 * Returns the number of elements in the list
460 xmlListSize(xmlListPtr l)
462 xmlLinkPtr lk;
463 int count=0;
465 /* TODO: keep a counter in xmlList instead */
466 for(lk = l->sentinel->next; lk != l->sentinel; lk = lk->next, count++);
467 return count;
471 * xmlListPopFront:
472 * @l: a list
474 * Removes the first element in the list
476 void
477 xmlListPopFront(xmlListPtr l)
479 if(!xmlListEmpty(l))
480 xmlLinkDeallocator(l, l->sentinel->next);
484 * xmlListPopBack:
485 * @l: a list
487 * Removes the last element in the list
489 void
490 xmlListPopBack(xmlListPtr l)
492 if(!xmlListEmpty(l))
493 xmlLinkDeallocator(l, l->sentinel->prev);
497 * xmlListPushFront:
498 * @l: a list
499 * @data: new data
501 * add the new data at the beginning of the list
503 * Returns 1 if successful, 0 otherwise
506 xmlListPushFront(xmlListPtr l, void *data)
508 xmlLinkPtr lkPlace, lkNew;
510 lkPlace = l->sentinel;
511 /* Add the new link */
512 lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
513 if (lkNew == NULL) {
514 xmlGenericError(xmlGenericErrorContext,
515 "Cannot initialize memory for new link");
516 return (0);
518 lkNew->data = data;
519 lkNew->next = lkPlace->next;
520 (lkPlace->next)->prev = lkNew;
521 lkPlace->next = lkNew;
522 lkNew->prev = lkPlace;
523 return 1;
527 * xmlListPushBack:
528 * @l: a list
529 * @data: new data
531 * add the new data at the end of the list
533 * Returns 1 if successful, 0 otherwise
536 xmlListPushBack(xmlListPtr l, void *data)
538 xmlLinkPtr lkPlace, lkNew;
540 lkPlace = l->sentinel->prev;
541 /* Add the new link */
542 if (NULL ==(lkNew = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) {
543 xmlGenericError(xmlGenericErrorContext,
544 "Cannot initialize memory for new link");
545 return (0);
547 lkNew->data = data;
548 lkNew->next = lkPlace->next;
549 (lkPlace->next)->prev = lkNew;
550 lkPlace->next = lkNew;
551 lkNew->prev = lkPlace;
552 return 1;
556 * xmlLinkGetData:
557 * @lk: a link
559 * See Returns.
561 * Returns a pointer to the data referenced from this link
563 void *
564 xmlLinkGetData(xmlLinkPtr lk)
566 return lk->data;
570 * xmlListReverse:
571 * @l: a list
573 * Reverse the order of the elements in the list
575 void
576 xmlListReverse(xmlListPtr l) {
577 xmlLinkPtr lk;
578 xmlLinkPtr lkPrev = l->sentinel;
580 for(lk = l->sentinel->next; lk != l->sentinel; lk = lk->next) {
581 lkPrev->next = lkPrev->prev;
582 lkPrev->prev = lk;
583 lkPrev = lk;
585 /* Fix up the last node */
586 lkPrev->next = lkPrev->prev;
587 lkPrev->prev = lk;
591 * xmlListSort:
592 * @l: a list
594 * Sort all the elements in the list
596 void
597 xmlListSort(xmlListPtr l)
599 xmlListPtr lTemp;
601 if(xmlListEmpty(l))
602 return;
604 /* I think that the real answer is to implement quicksort, the
605 * alternative is to implement some list copying procedure which
606 * would be based on a list copy followed by a clear followed by
607 * an insert. This is slow...
610 if (NULL ==(lTemp = xmlListDup(l)))
611 return;
612 xmlListClear(l);
613 xmlListMerge(l, lTemp);
614 xmlListDelete(lTemp);
615 return;
619 * xmlListWalk:
620 * @l: a list
621 * @walker: a processing function
622 * @user: a user parameter passed to the walker function
624 * Walk all the element of the first from first to last and
625 * apply the walker function to it
627 void
628 xmlListWalk(xmlListPtr l, xmlListWalker walker, const void *user) {
629 xmlLinkPtr lk;
631 for(lk = l->sentinel->next; lk != l->sentinel; lk = lk->next) {
632 if((walker(lk->data, user)) == 0)
633 break;
638 * xmlListReverseWalk:
639 * @l: a list
640 * @walker: a processing function
641 * @user: a user parameter passed to the walker function
643 * Walk all the element of the list in reverse order and
644 * apply the walker function to it
646 void
647 xmlListReverseWalk(xmlListPtr l, xmlListWalker walker, const void *user) {
648 xmlLinkPtr lk;
650 for(lk = l->sentinel->prev; lk != l->sentinel; lk = lk->prev) {
651 if((walker(lk->data, user)) == 0)
652 break;
657 * xmlListMerge:
658 * @l1: the original list
659 * @l2: the new list
661 * include all the elements of the second list in the first one and
662 * clear the second list
664 void
665 xmlListMerge(xmlListPtr l1, xmlListPtr l2)
667 xmlListCopy(l1, l2);
668 xmlListClear(l2);
672 * xmlListDup:
673 * @old: the list
675 * Duplicate the list
677 * Returns a new copy of the list or NULL in case of error
679 xmlListPtr
680 xmlListDup(const xmlListPtr old)
682 xmlListPtr cur;
683 /* Hmmm, how to best deal with allocation issues when copying
684 * lists. If there is a de-allocator, should responsibility lie with
685 * the new list or the old list. Surely not both. I'll arbitrarily
686 * set it to be the old list for the time being whilst I work out
687 * the answer
689 if (NULL ==(cur = xmlListCreate(NULL, old->linkCompare)))
690 return (NULL);
691 if (0 != xmlListCopy(cur, old))
692 return NULL;
693 return cur;
697 * xmlListCopy:
698 * @cur: the new list
699 * @old: the old list
701 * Move all the element from the old list in the new list
703 * Returns 0 in case of success 1 in case of error
706 xmlListCopy(xmlListPtr cur, const xmlListPtr old)
708 /* Walk the old tree and insert the data into the new one */
709 xmlLinkPtr lk;
711 for(lk = old->sentinel->next; lk != old->sentinel; lk = lk->next) {
712 if (0 !=xmlListInsert(cur, lk->data)) {
713 xmlListDelete(cur);
714 return (1);
717 return (0);
719 /* xmlListUnique() */
720 /* xmlListSwap */