Annotation of embedaddon/libxml2/list.c, revision 1.1.1.2
1.1 misho 1: /*
2: * list.c: lists handling implementation
3: *
4: * Copyright (C) 2000 Gary Pennington and Daniel Veillard.
5: *
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.
9: *
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.
14: *
15: * Author: Gary.Pennington@uk.sun.com
16: */
17:
18: #define IN_LIBXML
19: #include "libxml.h"
20:
21: #include <stdlib.h>
22: #include <string.h>
23: #include <libxml/xmlmemory.h>
24: #include <libxml/list.h>
25: #include <libxml/globals.h>
26:
27: /*
28: * Type definition are kept internal
29: */
30:
31: struct _xmlLink
32: {
33: struct _xmlLink *next;
34: struct _xmlLink *prev;
35: void *data;
36: };
37:
38: struct _xmlList
39: {
40: xmlLinkPtr sentinel;
41: void (*linkDeallocator)(xmlLinkPtr );
42: int (*linkCompare)(const void *, const void*);
43: };
44:
45: /************************************************************************
46: * *
47: * Interfaces *
48: * *
49: ************************************************************************/
50:
51: /**
52: * xmlLinkDeallocator:
53: * @l: a list
54: * @lk: a link
55: *
56: * Unlink and deallocate @lk from list @l
57: */
58: static void
59: xmlLinkDeallocator(xmlListPtr l, xmlLinkPtr lk)
60: {
61: (lk->prev)->next = lk->next;
62: (lk->next)->prev = lk->prev;
63: if(l->linkDeallocator)
64: l->linkDeallocator(lk);
65: xmlFree(lk);
66: }
67:
68: /**
69: * xmlLinkCompare:
70: * @data0: first data
71: * @data1: second data
72: *
73: * Compares two arbitrary data
74: *
75: * Returns -1, 0 or 1 depending on whether data1 is greater equal or smaller
76: * than data0
77: */
78: static int
79: xmlLinkCompare(const void *data0, const void *data1)
80: {
81: if (data0 < data1)
82: return (-1);
83: else if (data0 == data1)
84: return (0);
85: return (1);
86: }
87:
88: /**
89: * xmlListLowerSearch:
90: * @l: a list
91: * @data: a data
92: *
93: * Search data in the ordered list walking from the beginning
94: *
95: * Returns the link containing the data or NULL
96: */
1.1.1.2 ! misho 97: static xmlLinkPtr
! 98: xmlListLowerSearch(xmlListPtr l, void *data)
1.1 misho 99: {
100: xmlLinkPtr lk;
101:
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);
1.1.1.2 ! misho 105: return lk;
1.1 misho 106: }
107:
108: /**
109: * xmlListHigherSearch:
110: * @l: a list
111: * @data: a data
112: *
113: * Search data in the ordered list walking backward from the end
114: *
115: * Returns the link containing the data or NULL
116: */
1.1.1.2 ! misho 117: static xmlLinkPtr
! 118: xmlListHigherSearch(xmlListPtr l, void *data)
1.1 misho 119: {
120: xmlLinkPtr lk;
121:
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);
1.1.1.2 ! misho 125: return lk;
1.1 misho 126: }
127:
128: /**
129: * xmlListSearch:
130: * @l: a list
131: * @data: a data
132: *
133: * Search data in the list
134: *
135: * Returns the link containing the data or NULL
136: */
1.1.1.2 ! misho 137: static xmlLinkPtr
! 138: xmlListLinkSearch(xmlListPtr l, void *data)
1.1 misho 139: {
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;
150: }
151: }
152:
153: /**
154: * xmlListLinkReverseSearch:
155: * @l: a list
156: * @data: a data
157: *
158: * Search data in the list processing backward
159: *
160: * Returns the link containing the data or NULL
161: */
1.1.1.2 ! misho 162: static xmlLinkPtr
! 163: xmlListLinkReverseSearch(xmlListPtr l, void *data)
1.1 misho 164: {
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;
175: }
176: }
177:
178: /**
179: * xmlListCreate:
180: * @deallocator: an optional deallocator function
181: * @compare: an optional comparison function
182: *
183: * Create a new list
184: *
185: * Returns the new list or NULL in case of error
186: */
187: xmlListPtr
188: xmlListCreate(xmlListDeallocator deallocator, xmlListDataCompare compare)
189: {
190: xmlListPtr l;
191: if (NULL == (l = (xmlListPtr )xmlMalloc( sizeof(xmlList)))) {
1.1.1.2 ! misho 192: xmlGenericError(xmlGenericErrorContext,
1.1 misho 193: "Cannot initialize memory for list");
194: return (NULL);
195: }
196: /* Initialize the list to NULL */
197: memset(l, 0, sizeof(xmlList));
1.1.1.2 ! misho 198:
1.1 misho 199: /* Add the sentinel */
200: if (NULL ==(l->sentinel = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) {
1.1.1.2 ! misho 201: xmlGenericError(xmlGenericErrorContext,
1.1 misho 202: "Cannot initialize memory for sentinel");
203: xmlFree(l);
204: return (NULL);
205: }
206: l->sentinel->next = l->sentinel;
207: l->sentinel->prev = l->sentinel;
208: l->sentinel->data = NULL;
1.1.1.2 ! misho 209:
1.1 misho 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;
219: }
1.1.1.2 ! misho 220:
1.1 misho 221: /**
222: * xmlListSearch:
223: * @l: a list
224: * @data: a search value
225: *
226: * Search the list for an existing value of @data
227: *
228: * Returns the value associated to @data or NULL in case of error
229: */
230: void *
1.1.1.2 ! misho 231: xmlListSearch(xmlListPtr l, void *data)
1.1 misho 232: {
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;
240: }
241:
242: /**
243: * xmlListReverseSearch:
244: * @l: a list
245: * @data: a search value
246: *
247: * Search the list in reverse order for an existing value of @data
248: *
249: * Returns the value associated to @data or NULL in case of error
250: */
251: void *
1.1.1.2 ! misho 252: xmlListReverseSearch(xmlListPtr l, void *data)
1.1 misho 253: {
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;
261: }
262:
263: /**
264: * xmlListInsert:
265: * @l: a list
266: * @data: the data
267: *
268: * Insert data in the ordered list at the beginning for this value
269: *
270: * Returns 0 in case of success, 1 in case of failure
271: */
272: int
1.1.1.2 ! misho 273: xmlListInsert(xmlListPtr l, void *data)
1.1 misho 274: {
275: xmlLinkPtr lkPlace, lkNew;
276:
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) {
1.1.1.2 ! misho 283: xmlGenericError(xmlGenericErrorContext,
1.1 misho 284: "Cannot initialize memory for new link");
285: return (1);
286: }
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;
294: }
295:
296: /**
297: * xmlListAppend:
298: * @l: a list
299: * @data: the data
300: *
301: * Insert data in the ordered list at the end for this value
302: *
303: * Returns 0 in case of success, 1 in case of failure
304: */
1.1.1.2 ! misho 305: int xmlListAppend(xmlListPtr l, void *data)
1.1 misho 306: {
307: xmlLinkPtr lkPlace, lkNew;
308:
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) {
1.1.1.2 ! misho 315: xmlGenericError(xmlGenericErrorContext,
1.1 misho 316: "Cannot initialize memory for new link");
317: return (1);
318: }
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;
325: }
326:
327: /**
328: * xmlListDelete:
329: * @l: a list
330: *
331: * Deletes the list and its associated data
332: */
333: void xmlListDelete(xmlListPtr l)
334: {
335: if (l == NULL)
336: return;
337:
338: xmlListClear(l);
339: xmlFree(l->sentinel);
340: xmlFree(l);
341: }
342:
343: /**
344: * xmlListRemoveFirst:
345: * @l: a list
346: * @data: list data
347: *
348: * Remove the first instance associated to data in the list
349: *
350: * Returns 1 if a deallocation occured, or 0 if not found
351: */
352: int
353: xmlListRemoveFirst(xmlListPtr l, void *data)
354: {
355: xmlLinkPtr lk;
1.1.1.2 ! misho 356:
1.1 misho 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;
364: }
365: return 0;
366: }
367:
368: /**
369: * xmlListRemoveLast:
370: * @l: a list
371: * @data: list data
372: *
373: * Remove the last instance associated to data in the list
374: *
375: * Returns 1 if a deallocation occured, or 0 if not found
376: */
377: int
378: xmlListRemoveLast(xmlListPtr l, void *data)
379: {
380: xmlLinkPtr lk;
1.1.1.2 ! misho 381:
1.1 misho 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;
389: }
390: return 0;
391: }
392:
393: /**
394: * xmlListRemoveAll:
395: * @l: a list
396: * @data: list data
397: *
398: * Remove the all instance associated to data in the list
399: *
400: * Returns the number of deallocation, or 0 if not found
401: */
402: int
403: xmlListRemoveAll(xmlListPtr l, void *data)
404: {
405: int count=0;
1.1.1.2 ! misho 406:
1.1 misho 407: if (l == NULL)
408: return(0);
409:
410: while(xmlListRemoveFirst(l, data))
411: count++;
412: return count;
413: }
414:
415: /**
416: * xmlListClear:
417: * @l: a list
418: *
419: * Remove the all data in the list
420: */
421: void
422: xmlListClear(xmlListPtr l)
423: {
424: xmlLinkPtr lk;
1.1.1.2 ! misho 425:
1.1 misho 426: if (l == NULL)
427: return;
428: lk = l->sentinel->next;
429: while(lk != l->sentinel) {
430: xmlLinkPtr next = lk->next;
431:
432: xmlLinkDeallocator(l, lk);
433: lk = next;
434: }
435: }
436:
437: /**
438: * xmlListEmpty:
439: * @l: a list
440: *
441: * Is the list empty ?
442: *
443: * Returns 1 if the list is empty, 0 if not empty and -1 in case of error
444: */
445: int
446: xmlListEmpty(xmlListPtr l)
447: {
448: if (l == NULL)
449: return(-1);
450: return (l->sentinel->next == l->sentinel);
451: }
452:
453: /**
454: * xmlListFront:
455: * @l: a list
456: *
457: * Get the first element in the list
458: *
459: * Returns the first element in the list, or NULL
460: */
1.1.1.2 ! misho 461: xmlLinkPtr
1.1 misho 462: xmlListFront(xmlListPtr l)
463: {
464: if (l == NULL)
465: return(NULL);
466: return (l->sentinel->next);
467: }
1.1.1.2 ! misho 468:
1.1 misho 469: /**
470: * xmlListEnd:
471: * @l: a list
472: *
473: * Get the last element in the list
474: *
475: * Returns the last element in the list, or NULL
476: */
1.1.1.2 ! misho 477: xmlLinkPtr
1.1 misho 478: xmlListEnd(xmlListPtr l)
479: {
480: if (l == NULL)
481: return(NULL);
482: return (l->sentinel->prev);
483: }
1.1.1.2 ! misho 484:
1.1 misho 485: /**
486: * xmlListSize:
487: * @l: a list
488: *
489: * Get the number of elements in the list
490: *
491: * Returns the number of elements in the list or -1 in case of error
492: */
493: int
494: xmlListSize(xmlListPtr l)
495: {
496: xmlLinkPtr lk;
497: int count=0;
498:
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;
504: }
505:
506: /**
507: * xmlListPopFront:
508: * @l: a list
509: *
510: * Removes the first element in the list
511: */
512: void
513: xmlListPopFront(xmlListPtr l)
514: {
515: if(!xmlListEmpty(l))
516: xmlLinkDeallocator(l, l->sentinel->next);
517: }
518:
519: /**
520: * xmlListPopBack:
521: * @l: a list
522: *
523: * Removes the last element in the list
524: */
525: void
526: xmlListPopBack(xmlListPtr l)
527: {
528: if(!xmlListEmpty(l))
529: xmlLinkDeallocator(l, l->sentinel->prev);
530: }
531:
532: /**
533: * xmlListPushFront:
534: * @l: a list
535: * @data: new data
536: *
537: * add the new data at the beginning of the list
538: *
539: * Returns 1 if successful, 0 otherwise
540: */
541: int
1.1.1.2 ! misho 542: xmlListPushFront(xmlListPtr l, void *data)
1.1 misho 543: {
544: xmlLinkPtr lkPlace, lkNew;
545:
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) {
1.1.1.2 ! misho 552: xmlGenericError(xmlGenericErrorContext,
1.1 misho 553: "Cannot initialize memory for new link");
554: return (0);
555: }
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;
562: }
563:
564: /**
565: * xmlListPushBack:
566: * @l: a list
567: * @data: new data
568: *
569: * add the new data at the end of the list
570: *
571: * Returns 1 if successful, 0 otherwise
572: */
573: int
1.1.1.2 ! misho 574: xmlListPushBack(xmlListPtr l, void *data)
1.1 misho 575: {
576: xmlLinkPtr lkPlace, lkNew;
577:
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)))) {
1.1.1.2 ! misho 583: xmlGenericError(xmlGenericErrorContext,
1.1 misho 584: "Cannot initialize memory for new link");
585: return (0);
586: }
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;
593: }
594:
595: /**
596: * xmlLinkGetData:
597: * @lk: a link
598: *
599: * See Returns.
600: *
601: * Returns a pointer to the data referenced from this link
602: */
603: void *
604: xmlLinkGetData(xmlLinkPtr lk)
605: {
606: if (lk == NULL)
607: return(NULL);
608: return lk->data;
609: }
610:
611: /**
612: * xmlListReverse:
613: * @l: a list
614: *
615: * Reverse the order of the elements in the list
616: */
617: void
618: xmlListReverse(xmlListPtr l)
619: {
620: xmlLinkPtr lk;
621: xmlLinkPtr lkPrev;
622:
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;
630: }
631: /* Fix up the last node */
632: lkPrev->next = lkPrev->prev;
633: lkPrev->prev = lk;
634: }
635:
636: /**
637: * xmlListSort:
638: * @l: a list
639: *
640: * Sort all the elements in the list
641: */
642: void
643: xmlListSort(xmlListPtr l)
644: {
645: xmlListPtr lTemp;
1.1.1.2 ! misho 646:
1.1 misho 647: if (l == NULL)
648: return;
649: if(xmlListEmpty(l))
650: return;
651:
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...
656: */
657:
658: if (NULL ==(lTemp = xmlListDup(l)))
659: return;
660: xmlListClear(l);
661: xmlListMerge(l, lTemp);
662: xmlListDelete(lTemp);
663: return;
664: }
665:
666: /**
667: * xmlListWalk:
668: * @l: a list
669: * @walker: a processing function
670: * @user: a user parameter passed to the walker function
671: *
672: * Walk all the element of the first from first to last and
673: * apply the walker function to it
674: */
675: void
676: xmlListWalk(xmlListPtr l, xmlListWalker walker, const void *user) {
677: xmlLinkPtr lk;
678:
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;
684: }
685: }
686:
687: /**
688: * xmlListReverseWalk:
689: * @l: a list
690: * @walker: a processing function
691: * @user: a user parameter passed to the walker function
692: *
693: * Walk all the element of the list in reverse order and
694: * apply the walker function to it
695: */
696: void
697: xmlListReverseWalk(xmlListPtr l, xmlListWalker walker, const void *user) {
698: xmlLinkPtr lk;
699:
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;
705: }
706: }
707:
708: /**
709: * xmlListMerge:
710: * @l1: the original list
711: * @l2: the new list
712: *
713: * include all the elements of the second list in the first one and
714: * clear the second list
715: */
716: void
717: xmlListMerge(xmlListPtr l1, xmlListPtr l2)
718: {
719: xmlListCopy(l1, l2);
720: xmlListClear(l2);
721: }
722:
723: /**
724: * xmlListDup:
725: * @old: the list
726: *
727: * Duplicate the list
1.1.1.2 ! misho 728: *
1.1 misho 729: * Returns a new copy of the list or NULL in case of error
730: */
1.1.1.2 ! misho 731: xmlListPtr
1.1 misho 732: xmlListDup(const xmlListPtr old)
733: {
734: xmlListPtr cur;
735:
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
743: */
744: if (NULL ==(cur = xmlListCreate(NULL, old->linkCompare)))
745: return (NULL);
746: if (0 != xmlListCopy(cur, old))
747: return NULL;
748: return cur;
749: }
750:
751: /**
752: * xmlListCopy:
753: * @cur: the new list
754: * @old: the old list
755: *
756: * Move all the element from the old list in the new list
1.1.1.2 ! misho 757: *
1.1 misho 758: * Returns 0 in case of success 1 in case of error
759: */
760: int
761: xmlListCopy(xmlListPtr cur, const xmlListPtr old)
762: {
763: /* Walk the old tree and insert the data into the new one */
764: xmlLinkPtr lk;
765:
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);
772: }
773: }
1.1.1.2 ! misho 774: return (0);
1.1 misho 775: }
776: /* xmlListUnique() */
777: /* xmlListSwap */
778: #define bottom_list
779: #include "elfgcchack.h"
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>