Line | Count | Source (jump to first uncovered line) |
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 | | * MERCHANTABILITY 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/xmlerror.h> |
25 | | #include <libxml/list.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 | 724 | { |
61 | 724 | (lk->prev)->next = lk->next; |
62 | 724 | (lk->next)->prev = lk->prev; |
63 | 724 | if(l->linkDeallocator) |
64 | 724 | l->linkDeallocator(lk); |
65 | 724 | xmlFree(lk); |
66 | 724 | } |
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 | 0 | { |
81 | 0 | if (data0 < data1) |
82 | 0 | return (-1); |
83 | 0 | else if (data0 == data1) |
84 | 0 | return (0); |
85 | 0 | return (1); |
86 | 0 | } |
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 | | */ |
97 | | static xmlLinkPtr |
98 | | xmlListLowerSearch(xmlListPtr l, void *data) |
99 | 0 | { |
100 | 0 | xmlLinkPtr lk; |
101 | |
|
102 | 0 | if (l == NULL) |
103 | 0 | return(NULL); |
104 | 0 | for(lk = l->sentinel->next;lk != l->sentinel && l->linkCompare(lk->data, data) <0 ;lk = lk->next); |
105 | 0 | return lk; |
106 | 0 | } |
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 | | */ |
117 | | static xmlLinkPtr |
118 | | xmlListHigherSearch(xmlListPtr l, void *data) |
119 | 724 | { |
120 | 724 | xmlLinkPtr lk; |
121 | | |
122 | 724 | if (l == NULL) |
123 | 0 | return(NULL); |
124 | 724 | for(lk = l->sentinel->prev;lk != l->sentinel && l->linkCompare(lk->data, data) >0 ;lk = lk->prev); |
125 | 724 | return lk; |
126 | 724 | } |
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 | | */ |
137 | | static xmlLinkPtr |
138 | | xmlListLinkSearch(xmlListPtr l, void *data) |
139 | 0 | { |
140 | 0 | xmlLinkPtr lk; |
141 | 0 | if (l == NULL) |
142 | 0 | return(NULL); |
143 | 0 | lk = xmlListLowerSearch(l, data); |
144 | 0 | if (lk == l->sentinel) |
145 | 0 | return NULL; |
146 | 0 | else { |
147 | 0 | if (l->linkCompare(lk->data, data) ==0) |
148 | 0 | return lk; |
149 | 0 | return NULL; |
150 | 0 | } |
151 | 0 | } |
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 | | */ |
162 | | static xmlLinkPtr |
163 | | xmlListLinkReverseSearch(xmlListPtr l, void *data) |
164 | 0 | { |
165 | 0 | xmlLinkPtr lk; |
166 | 0 | if (l == NULL) |
167 | 0 | return(NULL); |
168 | 0 | lk = xmlListHigherSearch(l, data); |
169 | 0 | if (lk == l->sentinel) |
170 | 0 | return NULL; |
171 | 0 | else { |
172 | 0 | if (l->linkCompare(lk->data, data) ==0) |
173 | 0 | return lk; |
174 | 0 | return NULL; |
175 | 0 | } |
176 | 0 | } |
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 | 98 | { |
190 | 98 | xmlListPtr l; |
191 | 98 | l = (xmlListPtr)xmlMalloc(sizeof(xmlList)); |
192 | 98 | if (l == NULL) |
193 | 0 | return (NULL); |
194 | | /* Initialize the list to NULL */ |
195 | 98 | memset(l, 0, sizeof(xmlList)); |
196 | | |
197 | | /* Add the sentinel */ |
198 | 98 | l->sentinel = (xmlLinkPtr)xmlMalloc(sizeof(xmlLink)); |
199 | 98 | if (l->sentinel == NULL) { |
200 | 0 | xmlFree(l); |
201 | 0 | return (NULL); |
202 | 0 | } |
203 | 98 | l->sentinel->next = l->sentinel; |
204 | 98 | l->sentinel->prev = l->sentinel; |
205 | 98 | l->sentinel->data = NULL; |
206 | | |
207 | | /* If there is a link deallocator, use it */ |
208 | 98 | if (deallocator != NULL) |
209 | 98 | l->linkDeallocator = deallocator; |
210 | | /* If there is a link comparator, use it */ |
211 | 98 | if (compare != NULL) |
212 | 98 | l->linkCompare = compare; |
213 | 0 | else /* Use our own */ |
214 | 0 | l->linkCompare = xmlLinkCompare; |
215 | 98 | return l; |
216 | 98 | } |
217 | | |
218 | | /** |
219 | | * xmlListSearch: |
220 | | * @l: a list |
221 | | * @data: a search value |
222 | | * |
223 | | * Search the list for an existing value of @data |
224 | | * |
225 | | * Returns the value associated to @data or NULL in case of error |
226 | | */ |
227 | | void * |
228 | | xmlListSearch(xmlListPtr l, void *data) |
229 | 0 | { |
230 | 0 | xmlLinkPtr lk; |
231 | 0 | if (l == NULL) |
232 | 0 | return(NULL); |
233 | 0 | lk = xmlListLinkSearch(l, data); |
234 | 0 | if (lk) |
235 | 0 | return (lk->data); |
236 | 0 | return NULL; |
237 | 0 | } |
238 | | |
239 | | /** |
240 | | * xmlListReverseSearch: |
241 | | * @l: a list |
242 | | * @data: a search value |
243 | | * |
244 | | * Search the list in reverse order for an existing value of @data |
245 | | * |
246 | | * Returns the value associated to @data or NULL in case of error |
247 | | */ |
248 | | void * |
249 | | xmlListReverseSearch(xmlListPtr l, void *data) |
250 | 0 | { |
251 | 0 | xmlLinkPtr lk; |
252 | 0 | if (l == NULL) |
253 | 0 | return(NULL); |
254 | 0 | lk = xmlListLinkReverseSearch(l, data); |
255 | 0 | if (lk) |
256 | 0 | return (lk->data); |
257 | 0 | return NULL; |
258 | 0 | } |
259 | | |
260 | | /** |
261 | | * xmlListInsert: |
262 | | * @l: a list |
263 | | * @data: the data |
264 | | * |
265 | | * Insert data in the ordered list at the beginning for this value |
266 | | * |
267 | | * Returns 0 in case of success, 1 in case of failure |
268 | | */ |
269 | | int |
270 | | xmlListInsert(xmlListPtr l, void *data) |
271 | 0 | { |
272 | 0 | xmlLinkPtr lkPlace, lkNew; |
273 | |
|
274 | 0 | if (l == NULL) |
275 | 0 | return(1); |
276 | 0 | lkPlace = xmlListLowerSearch(l, data); |
277 | | /* Add the new link */ |
278 | 0 | lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink)); |
279 | 0 | if (lkNew == NULL) |
280 | 0 | return (1); |
281 | 0 | lkNew->data = data; |
282 | 0 | lkPlace = lkPlace->prev; |
283 | 0 | lkNew->next = lkPlace->next; |
284 | 0 | (lkPlace->next)->prev = lkNew; |
285 | 0 | lkPlace->next = lkNew; |
286 | 0 | lkNew->prev = lkPlace; |
287 | 0 | return 0; |
288 | 0 | } |
289 | | |
290 | | /** |
291 | | * xmlListAppend: |
292 | | * @l: a list |
293 | | * @data: the data |
294 | | * |
295 | | * Insert data in the ordered list at the end for this value |
296 | | * |
297 | | * Returns 0 in case of success, 1 in case of failure |
298 | | */ |
299 | | int xmlListAppend(xmlListPtr l, void *data) |
300 | 724 | { |
301 | 724 | xmlLinkPtr lkPlace, lkNew; |
302 | | |
303 | 724 | if (l == NULL) |
304 | 0 | return(1); |
305 | 724 | lkPlace = xmlListHigherSearch(l, data); |
306 | | /* Add the new link */ |
307 | 724 | lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink)); |
308 | 724 | if (lkNew == NULL) |
309 | 0 | return (1); |
310 | 724 | lkNew->data = data; |
311 | 724 | lkNew->next = lkPlace->next; |
312 | 724 | (lkPlace->next)->prev = lkNew; |
313 | 724 | lkPlace->next = lkNew; |
314 | 724 | lkNew->prev = lkPlace; |
315 | 724 | return 0; |
316 | 724 | } |
317 | | |
318 | | /** |
319 | | * xmlListDelete: |
320 | | * @l: a list |
321 | | * |
322 | | * Deletes the list and its associated data |
323 | | */ |
324 | | void xmlListDelete(xmlListPtr l) |
325 | 98 | { |
326 | 98 | if (l == NULL) |
327 | 0 | return; |
328 | | |
329 | 98 | xmlListClear(l); |
330 | 98 | xmlFree(l->sentinel); |
331 | 98 | xmlFree(l); |
332 | 98 | } |
333 | | |
334 | | /** |
335 | | * xmlListRemoveFirst: |
336 | | * @l: a list |
337 | | * @data: list data |
338 | | * |
339 | | * Remove the first instance associated to data in the list |
340 | | * |
341 | | * Returns 1 if a deallocation occurred, or 0 if not found |
342 | | */ |
343 | | int |
344 | | xmlListRemoveFirst(xmlListPtr l, void *data) |
345 | 0 | { |
346 | 0 | xmlLinkPtr lk; |
347 | |
|
348 | 0 | if (l == NULL) |
349 | 0 | return(0); |
350 | | /*Find the first instance of this data */ |
351 | 0 | lk = xmlListLinkSearch(l, data); |
352 | 0 | if (lk != NULL) { |
353 | 0 | xmlLinkDeallocator(l, lk); |
354 | 0 | return 1; |
355 | 0 | } |
356 | 0 | return 0; |
357 | 0 | } |
358 | | |
359 | | /** |
360 | | * xmlListRemoveLast: |
361 | | * @l: a list |
362 | | * @data: list data |
363 | | * |
364 | | * Remove the last instance associated to data in the list |
365 | | * |
366 | | * Returns 1 if a deallocation occurred, or 0 if not found |
367 | | */ |
368 | | int |
369 | | xmlListRemoveLast(xmlListPtr l, void *data) |
370 | 0 | { |
371 | 0 | xmlLinkPtr lk; |
372 | |
|
373 | 0 | if (l == NULL) |
374 | 0 | return(0); |
375 | | /*Find the last instance of this data */ |
376 | 0 | lk = xmlListLinkReverseSearch(l, data); |
377 | 0 | if (lk != NULL) { |
378 | 0 | xmlLinkDeallocator(l, lk); |
379 | 0 | return 1; |
380 | 0 | } |
381 | 0 | return 0; |
382 | 0 | } |
383 | | |
384 | | /** |
385 | | * xmlListRemoveAll: |
386 | | * @l: a list |
387 | | * @data: list data |
388 | | * |
389 | | * Remove the all instance associated to data in the list |
390 | | * |
391 | | * Returns the number of deallocation, or 0 if not found |
392 | | */ |
393 | | int |
394 | | xmlListRemoveAll(xmlListPtr l, void *data) |
395 | 0 | { |
396 | 0 | int count=0; |
397 | |
|
398 | 0 | if (l == NULL) |
399 | 0 | return(0); |
400 | | |
401 | 0 | while(xmlListRemoveFirst(l, data)) |
402 | 0 | count++; |
403 | 0 | return count; |
404 | 0 | } |
405 | | |
406 | | /** |
407 | | * xmlListClear: |
408 | | * @l: a list |
409 | | * |
410 | | * Remove the all data in the list |
411 | | */ |
412 | | void |
413 | | xmlListClear(xmlListPtr l) |
414 | 98 | { |
415 | 98 | xmlLinkPtr lk; |
416 | | |
417 | 98 | if (l == NULL) |
418 | 0 | return; |
419 | 98 | lk = l->sentinel->next; |
420 | 822 | while(lk != l->sentinel) { |
421 | 724 | xmlLinkPtr next = lk->next; |
422 | | |
423 | 724 | xmlLinkDeallocator(l, lk); |
424 | 724 | lk = next; |
425 | 724 | } |
426 | 98 | } |
427 | | |
428 | | /** |
429 | | * xmlListEmpty: |
430 | | * @l: a list |
431 | | * |
432 | | * Is the list empty ? |
433 | | * |
434 | | * Returns 1 if the list is empty, 0 if not empty and -1 in case of error |
435 | | */ |
436 | | int |
437 | | xmlListEmpty(xmlListPtr l) |
438 | 0 | { |
439 | 0 | if (l == NULL) |
440 | 0 | return(-1); |
441 | 0 | return (l->sentinel->next == l->sentinel); |
442 | 0 | } |
443 | | |
444 | | /** |
445 | | * xmlListFront: |
446 | | * @l: a list |
447 | | * |
448 | | * Get the first element in the list |
449 | | * |
450 | | * Returns the first element in the list, or NULL |
451 | | */ |
452 | | xmlLinkPtr |
453 | | xmlListFront(xmlListPtr l) |
454 | 0 | { |
455 | 0 | if (l == NULL) |
456 | 0 | return(NULL); |
457 | 0 | return (l->sentinel->next); |
458 | 0 | } |
459 | | |
460 | | /** |
461 | | * xmlListEnd: |
462 | | * @l: a list |
463 | | * |
464 | | * Get the last element in the list |
465 | | * |
466 | | * Returns the last element in the list, or NULL |
467 | | */ |
468 | | xmlLinkPtr |
469 | | xmlListEnd(xmlListPtr l) |
470 | 0 | { |
471 | 0 | if (l == NULL) |
472 | 0 | return(NULL); |
473 | 0 | return (l->sentinel->prev); |
474 | 0 | } |
475 | | |
476 | | /** |
477 | | * xmlListSize: |
478 | | * @l: a list |
479 | | * |
480 | | * Get the number of elements in the list |
481 | | * |
482 | | * Returns the number of elements in the list or -1 in case of error |
483 | | */ |
484 | | int |
485 | | xmlListSize(xmlListPtr l) |
486 | 0 | { |
487 | 0 | xmlLinkPtr lk; |
488 | 0 | int count=0; |
489 | |
|
490 | 0 | if (l == NULL) |
491 | 0 | return(-1); |
492 | | /* TODO: keep a counter in xmlList instead */ |
493 | 0 | for(lk = l->sentinel->next; lk != l->sentinel; lk = lk->next, count++); |
494 | 0 | return count; |
495 | 0 | } |
496 | | |
497 | | /** |
498 | | * xmlListPopFront: |
499 | | * @l: a list |
500 | | * |
501 | | * Removes the first element in the list |
502 | | */ |
503 | | void |
504 | | xmlListPopFront(xmlListPtr l) |
505 | 0 | { |
506 | 0 | if(!xmlListEmpty(l)) |
507 | 0 | xmlLinkDeallocator(l, l->sentinel->next); |
508 | 0 | } |
509 | | |
510 | | /** |
511 | | * xmlListPopBack: |
512 | | * @l: a list |
513 | | * |
514 | | * Removes the last element in the list |
515 | | */ |
516 | | void |
517 | | xmlListPopBack(xmlListPtr l) |
518 | 0 | { |
519 | 0 | if(!xmlListEmpty(l)) |
520 | 0 | xmlLinkDeallocator(l, l->sentinel->prev); |
521 | 0 | } |
522 | | |
523 | | /** |
524 | | * xmlListPushFront: |
525 | | * @l: a list |
526 | | * @data: new data |
527 | | * |
528 | | * add the new data at the beginning of the list |
529 | | * |
530 | | * Returns 1 if successful, 0 otherwise |
531 | | */ |
532 | | int |
533 | | xmlListPushFront(xmlListPtr l, void *data) |
534 | 0 | { |
535 | 0 | xmlLinkPtr lkPlace, lkNew; |
536 | |
|
537 | 0 | if (l == NULL) |
538 | 0 | return(0); |
539 | 0 | lkPlace = l->sentinel; |
540 | | /* Add the new link */ |
541 | 0 | lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink)); |
542 | 0 | if (lkNew == NULL) |
543 | 0 | return (0); |
544 | 0 | lkNew->data = data; |
545 | 0 | lkNew->next = lkPlace->next; |
546 | 0 | (lkPlace->next)->prev = lkNew; |
547 | 0 | lkPlace->next = lkNew; |
548 | 0 | lkNew->prev = lkPlace; |
549 | 0 | return 1; |
550 | 0 | } |
551 | | |
552 | | /** |
553 | | * xmlListPushBack: |
554 | | * @l: a list |
555 | | * @data: new data |
556 | | * |
557 | | * add the new data at the end of the list |
558 | | * |
559 | | * Returns 1 if successful, 0 otherwise |
560 | | */ |
561 | | int |
562 | | xmlListPushBack(xmlListPtr l, void *data) |
563 | 0 | { |
564 | 0 | xmlLinkPtr lkPlace, lkNew; |
565 | |
|
566 | 0 | if (l == NULL) |
567 | 0 | return(0); |
568 | 0 | lkPlace = l->sentinel->prev; |
569 | | /* Add the new link */ |
570 | 0 | lkNew = (xmlLinkPtr)xmlMalloc(sizeof(xmlLink)); |
571 | 0 | if (lkNew == NULL) |
572 | 0 | return (0); |
573 | 0 | lkNew->data = data; |
574 | 0 | lkNew->next = lkPlace->next; |
575 | 0 | (lkPlace->next)->prev = lkNew; |
576 | 0 | lkPlace->next = lkNew; |
577 | 0 | lkNew->prev = lkPlace; |
578 | 0 | return 1; |
579 | 0 | } |
580 | | |
581 | | /** |
582 | | * xmlLinkGetData: |
583 | | * @lk: a link |
584 | | * |
585 | | * See Returns. |
586 | | * |
587 | | * Returns a pointer to the data referenced from this link |
588 | | */ |
589 | | void * |
590 | | xmlLinkGetData(xmlLinkPtr lk) |
591 | 724 | { |
592 | 724 | if (lk == NULL) |
593 | 0 | return(NULL); |
594 | 724 | return lk->data; |
595 | 724 | } |
596 | | |
597 | | /** |
598 | | * xmlListReverse: |
599 | | * @l: a list |
600 | | * |
601 | | * Reverse the order of the elements in the list |
602 | | */ |
603 | | void |
604 | | xmlListReverse(xmlListPtr l) |
605 | 0 | { |
606 | 0 | xmlLinkPtr lk; |
607 | 0 | xmlLinkPtr lkPrev; |
608 | |
|
609 | 0 | if (l == NULL) |
610 | 0 | return; |
611 | 0 | lkPrev = l->sentinel; |
612 | 0 | for (lk = l->sentinel->next; lk != l->sentinel; lk = lk->next) { |
613 | 0 | lkPrev->next = lkPrev->prev; |
614 | 0 | lkPrev->prev = lk; |
615 | 0 | lkPrev = lk; |
616 | 0 | } |
617 | | /* Fix up the last node */ |
618 | 0 | lkPrev->next = lkPrev->prev; |
619 | 0 | lkPrev->prev = lk; |
620 | 0 | } |
621 | | |
622 | | /** |
623 | | * xmlListSort: |
624 | | * @l: a list |
625 | | * |
626 | | * Sort all the elements in the list |
627 | | */ |
628 | | void |
629 | | xmlListSort(xmlListPtr l) |
630 | 0 | { |
631 | 0 | xmlListPtr lTemp; |
632 | |
|
633 | 0 | if (l == NULL) |
634 | 0 | return; |
635 | 0 | if(xmlListEmpty(l)) |
636 | 0 | return; |
637 | | |
638 | | /* I think that the real answer is to implement quicksort, the |
639 | | * alternative is to implement some list copying procedure which |
640 | | * would be based on a list copy followed by a clear followed by |
641 | | * an insert. This is slow... |
642 | | */ |
643 | | |
644 | 0 | lTemp = xmlListDup(l); |
645 | 0 | if (lTemp == NULL) |
646 | 0 | return; |
647 | 0 | xmlListClear(l); |
648 | 0 | xmlListMerge(l, lTemp); |
649 | 0 | xmlListDelete(lTemp); |
650 | 0 | } |
651 | | |
652 | | /** |
653 | | * xmlListWalk: |
654 | | * @l: a list |
655 | | * @walker: a processing function |
656 | | * @user: a user parameter passed to the walker function |
657 | | * |
658 | | * Walk all the element of the first from first to last and |
659 | | * apply the walker function to it |
660 | | */ |
661 | | void |
662 | 0 | xmlListWalk(xmlListPtr l, xmlListWalker walker, void *user) { |
663 | 0 | xmlLinkPtr lk; |
664 | |
|
665 | 0 | if ((l == NULL) || (walker == NULL)) |
666 | 0 | return; |
667 | 0 | for(lk = l->sentinel->next; lk != l->sentinel; lk = lk->next) { |
668 | 0 | if((walker(lk->data, user)) == 0) |
669 | 0 | break; |
670 | 0 | } |
671 | 0 | } |
672 | | |
673 | | /** |
674 | | * xmlListReverseWalk: |
675 | | * @l: a list |
676 | | * @walker: a processing function |
677 | | * @user: a user parameter passed to the walker function |
678 | | * |
679 | | * Walk all the element of the list in reverse order and |
680 | | * apply the walker function to it |
681 | | */ |
682 | | void |
683 | 0 | xmlListReverseWalk(xmlListPtr l, xmlListWalker walker, void *user) { |
684 | 0 | xmlLinkPtr lk; |
685 | |
|
686 | 0 | if ((l == NULL) || (walker == NULL)) |
687 | 0 | return; |
688 | 0 | for(lk = l->sentinel->prev; lk != l->sentinel; lk = lk->prev) { |
689 | 0 | if((walker(lk->data, user)) == 0) |
690 | 0 | break; |
691 | 0 | } |
692 | 0 | } |
693 | | |
694 | | /** |
695 | | * xmlListMerge: |
696 | | * @l1: the original list |
697 | | * @l2: the new list |
698 | | * |
699 | | * include all the elements of the second list in the first one and |
700 | | * clear the second list |
701 | | */ |
702 | | void |
703 | | xmlListMerge(xmlListPtr l1, xmlListPtr l2) |
704 | 0 | { |
705 | 0 | xmlListCopy(l1, l2); |
706 | 0 | xmlListClear(l2); |
707 | 0 | } |
708 | | |
709 | | /** |
710 | | * xmlListDup: |
711 | | * @old: the list |
712 | | * |
713 | | * Duplicate the list |
714 | | * |
715 | | * Returns a new copy of the list or NULL in case of error |
716 | | */ |
717 | | xmlListPtr |
718 | | xmlListDup(xmlListPtr old) |
719 | 0 | { |
720 | 0 | xmlListPtr cur; |
721 | |
|
722 | 0 | if (old == NULL) |
723 | 0 | return(NULL); |
724 | | /* Hmmm, how to best deal with allocation issues when copying |
725 | | * lists. If there is a de-allocator, should responsibility lie with |
726 | | * the new list or the old list. Surely not both. I'll arbitrarily |
727 | | * set it to be the old list for the time being whilst I work out |
728 | | * the answer |
729 | | */ |
730 | 0 | cur = xmlListCreate(NULL, old->linkCompare); |
731 | 0 | if (cur == NULL) |
732 | 0 | return (NULL); |
733 | 0 | if (0 != xmlListCopy(cur, old)) |
734 | 0 | return NULL; |
735 | 0 | return cur; |
736 | 0 | } |
737 | | |
738 | | /** |
739 | | * xmlListCopy: |
740 | | * @cur: the new list |
741 | | * @old: the old list |
742 | | * |
743 | | * Move all the element from the old list in the new list |
744 | | * |
745 | | * Returns 0 in case of success 1 in case of error |
746 | | */ |
747 | | int |
748 | | xmlListCopy(xmlListPtr cur, xmlListPtr old) |
749 | 0 | { |
750 | | /* Walk the old tree and insert the data into the new one */ |
751 | 0 | xmlLinkPtr lk; |
752 | |
|
753 | 0 | if ((old == NULL) || (cur == NULL)) |
754 | 0 | return(1); |
755 | 0 | for(lk = old->sentinel->next; lk != old->sentinel; lk = lk->next) { |
756 | 0 | if (0 !=xmlListInsert(cur, lk->data)) { |
757 | 0 | xmlListDelete(cur); |
758 | 0 | return (1); |
759 | 0 | } |
760 | 0 | } |
761 | 0 | return (0); |
762 | 0 | } |
763 | | /* xmlListUnique() */ |
764 | | /* xmlListSwap */ |