ntdll: Fix export and calling convention of RtlUlonglongByteSwap().
[wine.git] / libs / xml2 / list.c
blob12a7c009277cff091ccaf0ad090964e952ed2ba8
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 * MERCHANTABILITY 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 if (l == NULL)
103 return(NULL);
104 for(lk = l->sentinel->next;lk != l->sentinel && l->linkCompare(lk->data, data) <0 ;lk = lk->next);
105 return lk;
109 * xmlListHigherSearch:
110 * @l: a list
111 * @data: a data
113 * Search data in the ordered list walking backward from the end
115 * Returns the link containing the data or NULL
117 static xmlLinkPtr
118 xmlListHigherSearch(xmlListPtr l, void *data)
120 xmlLinkPtr lk;
122 if (l == NULL)
123 return(NULL);
124 for(lk = l->sentinel->prev;lk != l->sentinel && l->linkCompare(lk->data, data) >0 ;lk = lk->prev);
125 return lk;
129 * xmlListSearch:
130 * @l: a list
131 * @data: a data
133 * Search data in the list
135 * Returns the link containing the data or NULL
137 static xmlLinkPtr
138 xmlListLinkSearch(xmlListPtr l, void *data)
140 xmlLinkPtr lk;
141 if (l == NULL)
142 return(NULL);
143 lk = xmlListLowerSearch(l, data);
144 if (lk == l->sentinel)
145 return NULL;
146 else {
147 if (l->linkCompare(lk->data, data) ==0)
148 return lk;
149 return NULL;
154 * xmlListLinkReverseSearch:
155 * @l: a list
156 * @data: a data
158 * Search data in the list processing backward
160 * Returns the link containing the data or NULL
162 static xmlLinkPtr
163 xmlListLinkReverseSearch(xmlListPtr l, void *data)
165 xmlLinkPtr lk;
166 if (l == NULL)
167 return(NULL);
168 lk = xmlListHigherSearch(l, data);
169 if (lk == l->sentinel)
170 return NULL;
171 else {
172 if (l->linkCompare(lk->data, data) ==0)
173 return lk;
174 return NULL;
179 * xmlListCreate:
180 * @deallocator: an optional deallocator function
181 * @compare: an optional comparison function
183 * Create a new list
185 * Returns the new list or NULL in case of error
187 xmlListPtr
188 xmlListCreate(xmlListDeallocator deallocator, xmlListDataCompare compare)
190 xmlListPtr l;
191 if (NULL == (l = (xmlListPtr )xmlMalloc( sizeof(xmlList)))) {
192 xmlGenericError(xmlGenericErrorContext,
193 "Cannot initialize memory for list");
194 return (NULL);
196 /* Initialize the list to NULL */
197 memset(l, 0, sizeof(xmlList));
199 /* Add the sentinel */
200 if (NULL ==(l->sentinel = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) {
201 xmlGenericError(xmlGenericErrorContext,
202 "Cannot initialize memory for sentinel");
203 xmlFree(l);
204 return (NULL);
206 l->sentinel->next = l->sentinel;
207 l->sentinel->prev = l->sentinel;
208 l->sentinel->data = NULL;
210 /* If there is a link deallocator, use it */
211 if (deallocator != NULL)
212 l->linkDeallocator = deallocator;
213 /* If there is a link comparator, use it */
214 if (compare != NULL)
215 l->linkCompare = compare;
216 else /* Use our own */
217 l->linkCompare = xmlLinkCompare;
218 return l;
222 * xmlListSearch:
223 * @l: a list
224 * @data: a search value
226 * Search the list for an existing value of @data
228 * Returns the value associated to @data or NULL in case of error
230 void *
231 xmlListSearch(xmlListPtr l, void *data)
233 xmlLinkPtr lk;
234 if (l == NULL)
235 return(NULL);
236 lk = xmlListLinkSearch(l, data);
237 if (lk)
238 return (lk->data);
239 return NULL;
243 * xmlListReverseSearch:
244 * @l: a list
245 * @data: a search value
247 * Search the list in reverse order for an existing value of @data
249 * Returns the value associated to @data or NULL in case of error
251 void *
252 xmlListReverseSearch(xmlListPtr l, void *data)
254 xmlLinkPtr lk;
255 if (l == NULL)
256 return(NULL);
257 lk = xmlListLinkReverseSearch(l, data);
258 if (lk)
259 return (lk->data);
260 return NULL;
264 * xmlListInsert:
265 * @l: a list
266 * @data: the data
268 * Insert data in the ordered list at the beginning for this value
270 * Returns 0 in case of success, 1 in case of failure
273 xmlListInsert(xmlListPtr l, void *data)
275 xmlLinkPtr lkPlace, lkNew;
277 if (l == NULL)
278 return(1);
279 lkPlace = xmlListLowerSearch(l, data);
280 /* Add the new link */
281 lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
282 if (lkNew == NULL) {
283 xmlGenericError(xmlGenericErrorContext,
284 "Cannot initialize memory for new link");
285 return (1);
287 lkNew->data = data;
288 lkPlace = lkPlace->prev;
289 lkNew->next = lkPlace->next;
290 (lkPlace->next)->prev = lkNew;
291 lkPlace->next = lkNew;
292 lkNew->prev = lkPlace;
293 return 0;
297 * xmlListAppend:
298 * @l: a list
299 * @data: the data
301 * Insert data in the ordered list at the end for this value
303 * Returns 0 in case of success, 1 in case of failure
305 int xmlListAppend(xmlListPtr l, void *data)
307 xmlLinkPtr lkPlace, lkNew;
309 if (l == NULL)
310 return(1);
311 lkPlace = xmlListHigherSearch(l, data);
312 /* Add the new link */
313 lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
314 if (lkNew == NULL) {
315 xmlGenericError(xmlGenericErrorContext,
316 "Cannot initialize memory for new link");
317 return (1);
319 lkNew->data = data;
320 lkNew->next = lkPlace->next;
321 (lkPlace->next)->prev = lkNew;
322 lkPlace->next = lkNew;
323 lkNew->prev = lkPlace;
324 return 0;
328 * xmlListDelete:
329 * @l: a list
331 * Deletes the list and its associated data
333 void xmlListDelete(xmlListPtr l)
335 if (l == NULL)
336 return;
338 xmlListClear(l);
339 xmlFree(l->sentinel);
340 xmlFree(l);
344 * xmlListRemoveFirst:
345 * @l: a list
346 * @data: list data
348 * Remove the first instance associated to data in the list
350 * Returns 1 if a deallocation occurred, or 0 if not found
353 xmlListRemoveFirst(xmlListPtr l, void *data)
355 xmlLinkPtr lk;
357 if (l == NULL)
358 return(0);
359 /*Find the first instance of this data */
360 lk = xmlListLinkSearch(l, data);
361 if (lk != NULL) {
362 xmlLinkDeallocator(l, lk);
363 return 1;
365 return 0;
369 * xmlListRemoveLast:
370 * @l: a list
371 * @data: list data
373 * Remove the last instance associated to data in the list
375 * Returns 1 if a deallocation occurred, or 0 if not found
378 xmlListRemoveLast(xmlListPtr l, void *data)
380 xmlLinkPtr lk;
382 if (l == NULL)
383 return(0);
384 /*Find the last instance of this data */
385 lk = xmlListLinkReverseSearch(l, data);
386 if (lk != NULL) {
387 xmlLinkDeallocator(l, lk);
388 return 1;
390 return 0;
394 * xmlListRemoveAll:
395 * @l: a list
396 * @data: list data
398 * Remove the all instance associated to data in the list
400 * Returns the number of deallocation, or 0 if not found
403 xmlListRemoveAll(xmlListPtr l, void *data)
405 int count=0;
407 if (l == NULL)
408 return(0);
410 while(xmlListRemoveFirst(l, data))
411 count++;
412 return count;
416 * xmlListClear:
417 * @l: a list
419 * Remove the all data in the list
421 void
422 xmlListClear(xmlListPtr l)
424 xmlLinkPtr lk;
426 if (l == NULL)
427 return;
428 lk = l->sentinel->next;
429 while(lk != l->sentinel) {
430 xmlLinkPtr next = lk->next;
432 xmlLinkDeallocator(l, lk);
433 lk = next;
438 * xmlListEmpty:
439 * @l: a list
441 * Is the list empty ?
443 * Returns 1 if the list is empty, 0 if not empty and -1 in case of error
446 xmlListEmpty(xmlListPtr l)
448 if (l == NULL)
449 return(-1);
450 return (l->sentinel->next == l->sentinel);
454 * xmlListFront:
455 * @l: a list
457 * Get the first element in the list
459 * Returns the first element in the list, or NULL
461 xmlLinkPtr
462 xmlListFront(xmlListPtr l)
464 if (l == NULL)
465 return(NULL);
466 return (l->sentinel->next);
470 * xmlListEnd:
471 * @l: a list
473 * Get the last element in the list
475 * Returns the last element in the list, or NULL
477 xmlLinkPtr
478 xmlListEnd(xmlListPtr l)
480 if (l == NULL)
481 return(NULL);
482 return (l->sentinel->prev);
486 * xmlListSize:
487 * @l: a list
489 * Get the number of elements in the list
491 * Returns the number of elements in the list or -1 in case of error
494 xmlListSize(xmlListPtr l)
496 xmlLinkPtr lk;
497 int count=0;
499 if (l == NULL)
500 return(-1);
501 /* TODO: keep a counter in xmlList instead */
502 for(lk = l->sentinel->next; lk != l->sentinel; lk = lk->next, count++);
503 return count;
507 * xmlListPopFront:
508 * @l: a list
510 * Removes the first element in the list
512 void
513 xmlListPopFront(xmlListPtr l)
515 if(!xmlListEmpty(l))
516 xmlLinkDeallocator(l, l->sentinel->next);
520 * xmlListPopBack:
521 * @l: a list
523 * Removes the last element in the list
525 void
526 xmlListPopBack(xmlListPtr l)
528 if(!xmlListEmpty(l))
529 xmlLinkDeallocator(l, l->sentinel->prev);
533 * xmlListPushFront:
534 * @l: a list
535 * @data: new data
537 * add the new data at the beginning of the list
539 * Returns 1 if successful, 0 otherwise
542 xmlListPushFront(xmlListPtr l, void *data)
544 xmlLinkPtr lkPlace, lkNew;
546 if (l == NULL)
547 return(0);
548 lkPlace = l->sentinel;
549 /* Add the new link */
550 lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
551 if (lkNew == NULL) {
552 xmlGenericError(xmlGenericErrorContext,
553 "Cannot initialize memory for new link");
554 return (0);
556 lkNew->data = data;
557 lkNew->next = lkPlace->next;
558 (lkPlace->next)->prev = lkNew;
559 lkPlace->next = lkNew;
560 lkNew->prev = lkPlace;
561 return 1;
565 * xmlListPushBack:
566 * @l: a list
567 * @data: new data
569 * add the new data at the end of the list
571 * Returns 1 if successful, 0 otherwise
574 xmlListPushBack(xmlListPtr l, void *data)
576 xmlLinkPtr lkPlace, lkNew;
578 if (l == NULL)
579 return(0);
580 lkPlace = l->sentinel->prev;
581 /* Add the new link */
582 if (NULL ==(lkNew = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) {
583 xmlGenericError(xmlGenericErrorContext,
584 "Cannot initialize memory for new link");
585 return (0);
587 lkNew->data = data;
588 lkNew->next = lkPlace->next;
589 (lkPlace->next)->prev = lkNew;
590 lkPlace->next = lkNew;
591 lkNew->prev = lkPlace;
592 return 1;
596 * xmlLinkGetData:
597 * @lk: a link
599 * See Returns.
601 * Returns a pointer to the data referenced from this link
603 void *
604 xmlLinkGetData(xmlLinkPtr lk)
606 if (lk == NULL)
607 return(NULL);
608 return lk->data;
612 * xmlListReverse:
613 * @l: a list
615 * Reverse the order of the elements in the list
617 void
618 xmlListReverse(xmlListPtr l)
620 xmlLinkPtr lk;
621 xmlLinkPtr lkPrev;
623 if (l == NULL)
624 return;
625 lkPrev = l->sentinel;
626 for (lk = l->sentinel->next; lk != l->sentinel; lk = lk->next) {
627 lkPrev->next = lkPrev->prev;
628 lkPrev->prev = lk;
629 lkPrev = lk;
631 /* Fix up the last node */
632 lkPrev->next = lkPrev->prev;
633 lkPrev->prev = lk;
637 * xmlListSort:
638 * @l: a list
640 * Sort all the elements in the list
642 void
643 xmlListSort(xmlListPtr l)
645 xmlListPtr lTemp;
647 if (l == NULL)
648 return;
649 if(xmlListEmpty(l))
650 return;
652 /* I think that the real answer is to implement quicksort, the
653 * alternative is to implement some list copying procedure which
654 * would be based on a list copy followed by a clear followed by
655 * an insert. This is slow...
658 if (NULL ==(lTemp = xmlListDup(l)))
659 return;
660 xmlListClear(l);
661 xmlListMerge(l, lTemp);
662 xmlListDelete(lTemp);
663 return;
667 * xmlListWalk:
668 * @l: a list
669 * @walker: a processing function
670 * @user: a user parameter passed to the walker function
672 * Walk all the element of the first from first to last and
673 * apply the walker function to it
675 void
676 xmlListWalk(xmlListPtr l, xmlListWalker walker, void *user) {
677 xmlLinkPtr lk;
679 if ((l == NULL) || (walker == NULL))
680 return;
681 for(lk = l->sentinel->next; lk != l->sentinel; lk = lk->next) {
682 if((walker(lk->data, user)) == 0)
683 break;
688 * xmlListReverseWalk:
689 * @l: a list
690 * @walker: a processing function
691 * @user: a user parameter passed to the walker function
693 * Walk all the element of the list in reverse order and
694 * apply the walker function to it
696 void
697 xmlListReverseWalk(xmlListPtr l, xmlListWalker walker, void *user) {
698 xmlLinkPtr lk;
700 if ((l == NULL) || (walker == NULL))
701 return;
702 for(lk = l->sentinel->prev; lk != l->sentinel; lk = lk->prev) {
703 if((walker(lk->data, user)) == 0)
704 break;
709 * xmlListMerge:
710 * @l1: the original list
711 * @l2: the new list
713 * include all the elements of the second list in the first one and
714 * clear the second list
716 void
717 xmlListMerge(xmlListPtr l1, xmlListPtr l2)
719 xmlListCopy(l1, l2);
720 xmlListClear(l2);
724 * xmlListDup:
725 * @old: the list
727 * Duplicate the list
729 * Returns a new copy of the list or NULL in case of error
731 xmlListPtr
732 xmlListDup(const xmlListPtr old)
734 xmlListPtr cur;
736 if (old == NULL)
737 return(NULL);
738 /* Hmmm, how to best deal with allocation issues when copying
739 * lists. If there is a de-allocator, should responsibility lie with
740 * the new list or the old list. Surely not both. I'll arbitrarily
741 * set it to be the old list for the time being whilst I work out
742 * the answer
744 if (NULL ==(cur = xmlListCreate(NULL, old->linkCompare)))
745 return (NULL);
746 if (0 != xmlListCopy(cur, old))
747 return NULL;
748 return cur;
752 * xmlListCopy:
753 * @cur: the new list
754 * @old: the old list
756 * Move all the element from the old list in the new list
758 * Returns 0 in case of success 1 in case of error
761 xmlListCopy(xmlListPtr cur, const xmlListPtr old)
763 /* Walk the old tree and insert the data into the new one */
764 xmlLinkPtr lk;
766 if ((old == NULL) || (cur == NULL))
767 return(1);
768 for(lk = old->sentinel->next; lk != old->sentinel; lk = lk->next) {
769 if (0 !=xmlListInsert(cur, lk->data)) {
770 xmlListDelete(cur);
771 return (1);
774 return (0);
776 /* xmlListUnique() */
777 /* xmlListSwap */