Coverage Report

Created: 2025-07-18 06:10

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