1 /*
2 * Copyright (C) 2003-2009 the oxine project
3 *
4 * xine is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * xine is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17 *
18 * doubly linked lists with builtin iterator,
19 * based upon xine_list functions of the xine project
20 */
21
22 #include "config.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/types.h>
27 #include <inttypes.h>
28
29 #ifdef DEBUG
30 #include <string.h>
31 #endif
32
33 #include "list.h"
34 #include "utils.h"
35
36 /*
37 * private data structures
38 */
39
40 typedef struct node_s {
41
42 struct node_s *next, *prev;
43 void *content;
44 int priority;
45
46 } node_t;
47
48
49 struct list_s {
50
51 node_t *first, *last, *cur;
52
53 #ifdef DEBUG
54 #define TAG_SIZE 256
55 char tag[TAG_SIZE];
56 #endif
57 };
58
59
60 /*
61 * create a new, empty list
62 */
63
64 #ifdef DEBUG
_list_new_tagged(const char * file,int line)65 list_t *_list_new_tagged(const char *file, int line) {
66
67 char tag[TAG_SIZE];
68 list_t *list;
69
70 snprintf(tag, TAG_SIZE, "list @ %s:%i", file, line);
71 list = ho_new_tagged(list_t, tag);
72 strcpy(list->tag, tag);
73
74 list->first=NULL;
75 list->last =NULL;
76 list->cur =NULL;
77
78 return list;
79 }
80 #else
list_new(void)81 list_t *list_new (void) {
82 list_t *list;
83
84 list = ho_new(list_t);
85
86 list->first=NULL;
87 list->last =NULL;
88 list->cur =NULL;
89
90 return list;
91 }
92 #endif
93
94 /*
95 * dispose a list (and only the list, contents have to be managed separately)
96 */
97
list_free(list_t * l)98 void list_free(list_t *l) {
99 node_t *node;
100
101 if (!l) {
102 printf ("list: tried to free empty list\n");
103 abort();
104 }
105
106 if (!l->first) {
107
108 ho_free(l);
109
110 return;
111 }
112
113 node = l->first;
114
115 while(node) {
116 node_t *n = node;
117
118 node = n->next;
119 ho_free(n);
120 }
121
122 ho_free(l);
123 }
124
list_first_content(list_t * l)125 void *list_first_content (list_t *l) {
126
127 l->cur = l->first;
128
129 if (l->first)
130 return l->first->content;
131 else
132 return NULL;
133 }
134
list_next_content(list_t * l)135 void *list_next_content (list_t *l) {
136 if (l->cur) {
137
138 if (l->cur->next) {
139 l->cur = l->cur->next;
140 return l->cur->content;
141 }
142 else
143 return NULL;
144
145 } else {
146 printf ("list: next_content - passed end of list\n");
147 abort ();
148 }
149 }
150
list_current_content(list_t * l)151 void *list_current_content (list_t *l) {
152 if (l->cur) {
153
154 return l->cur->content;
155
156 } else {
157 printf ("list: next_content - passed end of list\n");
158 abort ();
159 }
160 }
161
list_is_empty(list_t * l)162 int list_is_empty (list_t *l) {
163
164 if (l == NULL){
165 printf ("list: list_is_empty : list is NULL\n");
166 abort();
167 }
168 return (l->first != NULL);
169 }
170
list_last_content(list_t * l)171 void *list_last_content (list_t *l) {
172
173 if (l->last) {
174 l->cur = l->last;
175 return l->last->content;
176 } else
177 return NULL;
178 }
179
list_prev_content(list_t * l)180 void *list_prev_content (list_t *l) {
181
182 if (l->cur) {
183 if (l->cur->prev) {
184 l->cur = l->cur->prev;
185 return l->cur->content;
186 }
187 else
188 return NULL;
189 } else {
190 printf ("list: passed begin of list\n");
191 abort ();
192 }
193 }
194
list_append_priority_content(list_t * l,void * content,int priority)195 void list_append_priority_content (list_t *l, void *content, int priority) {
196 node_t *node;
197
198 #ifdef DEBUG
199 char tag[TAG_SIZE];
200
201 snprintf(tag, TAG_SIZE, "pri node in %s", l->tag);
202 node = ho_new_tagged(node_t, tag);
203 #else
204 node = ho_new(node_t);
205 #endif
206
207 node->content = content;
208 node->priority = priority;
209
210 if (l->first) {
211 node_t *cur;
212
213 cur = l->first;
214
215 while(1) {
216 if( priority >= cur->priority ) {
217 node->next = cur;
218 node->prev = cur->prev;
219
220 if( node->prev )
221 node->prev->next = node;
222 else
223 l->first = node;
224 cur->prev = node;
225
226 l->cur = node;
227 break;
228 }
229
230 if( !cur->next ) {
231 node->next = NULL;
232 node->prev = cur;
233 cur->next = node;
234
235 l->cur = node;
236 l->last = node;
237 break;
238 }
239
240 cur = cur->next;
241 }
242 }
243 else {
244 l->first = l->last = l->cur = node;
245 node->prev = node->next = NULL;
246 }
247 }
248
249 #ifdef DEBUG
_list_append_content(list_t * l,void * content,const char * file,int line)250 void _list_append_content(list_t *l, void *content, const char *file, int line) {
251 node_t *node;
252 char tag[TAG_SIZE];
253
254 snprintf(tag, TAG_SIZE, "app node @ %s:%i", file, line);
255 node = ho_new_tagged(node_t, tag);
256
257 #else
258 void list_append_content (list_t *l, void *content) {
259 node_t *node;
260
261 node = ho_new(node_t);
262 #endif
263 node->content = content;
264
265 if (l->last) {
266 node->next = NULL;
267 node->prev = l->last;
268 l->last->next = node;
269 l->last = node;
270 l->cur = node;
271 }
272 else {
273 l->first = l->last = l->cur = node;
274 node->prev = node->next = NULL;
275 }
276 }
277
278 void list_insert_content (list_t *l, void *content) {
279 node_t *nodecur, *nodenew, *nodeprev;
280
281 #ifdef DEBUG
282 char tag[TAG_SIZE];
283
284 snprintf(tag, TAG_SIZE, "ins node in %s", l->tag);
285 nodenew = ho_new_tagged(node_t, tag);
286 #else
287 nodenew = ho_new(node_t);
288 #endif
289 nodenew->content = content;
290 nodecur = l->cur;
291
292 if(!nodecur) {
293 list_append_content(l, content);
294 return;
295 }
296
297 nodeprev = nodecur->prev;
298 nodecur->prev = nodenew;
299 nodenew->next = nodecur;
300 nodenew->prev = nodeprev;
301 if(nodecur != l->first) {
302 nodeprev->next = nodenew;
303 } else {
304 l->first = nodenew;
305 }
306 l->cur = nodenew;
307 }
308
309 void list_delete_current (list_t *l) {
310 node_t *node_cur;
311
312 node_cur = l->cur;
313
314 if(node_cur->prev) {
315 node_cur->prev->next = node_cur->next;
316 }
317 else { /* First entry */
318 l->first = node_cur->next;
319 }
320
321 if(node_cur->next) {
322 node_cur->next->prev = node_cur->prev;
323 l->cur = node_cur->next;
324 }
325 else { /* last entry in the list */
326 l->last = node_cur->prev;
327 l->cur = node_cur->prev;
328 }
329 ho_free(node_cur);
330 }
331
332 /*
333 * glib's implementation of lists
334 */
335
336 #define _g_list_new g_list_new
337 g_list_t* g_list_new (void) {
338 g_list_t *list;
339
340 list = ho_new(g_list_t);
341
342 return list;
343 }
344
345 void g_list_free (g_list_t *list) {
346 g_list_t *last;
347
348 while (list)
349 {
350 last = list;
351 list = list->next;
352 ho_free (last);
353 }
354 }
355
356 #define _g_list_free_1 g_list_free_1
357 void g_list_free_1 (g_list_t *list) {
358 ho_free (list);
359 }
360
361 g_list_t* g_list_append (g_list_t *list, void* data) {
362 g_list_t *new_list;
363 g_list_t *last;
364
365 new_list = _g_list_new ();
366 new_list->data = data;
367
368 if (list)
369 {
370 last = g_list_last (list);
371 last->next = new_list;
372 new_list->prev = last;
373
374 return list;
375 }
376 else
377 return new_list;
378 }
379
380 g_list_t* g_list_prepend (g_list_t *list, void* data) {
381 g_list_t *new_list;
382
383 new_list = _g_list_new ();
384 new_list->data = data;
385
386 if (list)
387 {
388 if (list->prev)
389 {
390 list->prev->next = new_list;
391 new_list->prev = list->prev;
392 }
393 list->prev = new_list;
394 new_list->next = list;
395 }
396
397 return new_list;
398 }
399
400 g_list_t* g_list_insert (g_list_t *list, void* data, int position) {
401 g_list_t *new_list;
402 g_list_t *tmp_list;
403
404 if (position < 0)
405 return g_list_append (list, data);
406 else if (position == 0)
407 return g_list_prepend (list, data);
408
409 tmp_list = g_list_nth (list, position);
410 if (!tmp_list)
411 return g_list_append (list, data);
412
413 new_list = _g_list_new ();
414 new_list->data = data;
415
416 if (tmp_list->prev)
417 {
418 tmp_list->prev->next = new_list;
419 new_list->prev = tmp_list->prev;
420 }
421 new_list->next = tmp_list;
422 tmp_list->prev = new_list;
423
424 if (tmp_list == list)
425 return new_list;
426 else
427 return list;
428 }
429
430 g_list_t* g_list_insert_before (g_list_t *list, g_list_t *sibling, void* data) {
431 if (!list)
432 {
433 list = g_list_new ();
434 list->data = data;
435 return list;
436 }
437 else if (sibling)
438 {
439 g_list_t *node;
440
441 node = g_list_new ();
442 node->data = data;
443 if (sibling->prev)
444 {
445 node->prev = sibling->prev;
446 node->prev->next = node;
447 node->next = sibling;
448 sibling->prev = node;
449 return list;
450 }
451 else
452 {
453 node->next = sibling;
454 sibling->prev = node;
455 return node;
456 }
457 }
458 else
459 {
460 g_list_t *last;
461
462 last = list;
463 while (last->next)
464 last = last->next;
465
466 last->next = g_list_new ();
467 last->next->data = data;
468 last->next->prev = last;
469
470 return list;
471 }
472 }
473
474 g_list_t * g_list_concat (g_list_t *list1, g_list_t *list2) {
475 g_list_t *tmp_list;
476
477 if (list2)
478 {
479 tmp_list = g_list_last (list1);
480 if (tmp_list)
481 tmp_list->next = list2;
482 else
483 list1 = list2;
484 list2->prev = tmp_list;
485 }
486
487 return list1;
488 }
489
490 g_list_t* g_list_remove (g_list_t *list, const void *data) {
491 g_list_t *tmp;
492
493 tmp = list;
494 while (tmp)
495 {
496 if (tmp->data != data)
497 tmp = tmp->next;
498 else
499 {
500 if (tmp->prev)
501 tmp->prev->next = tmp->next;
502 if (tmp->next)
503 tmp->next->prev = tmp->prev;
504
505 if (list == tmp)
506 list = list->next;
507
508 _g_list_free_1 (tmp);
509
510 break;
511 }
512 }
513 return list;
514 }
515
516 g_list_t* g_list_remove_all (g_list_t *list, const void *data) {
517 g_list_t *tmp = list;
518
519 while (tmp)
520 {
521 if (tmp->data != data)
522 tmp = tmp->next;
523 else
524 {
525 g_list_t *next = tmp->next;
526
527 if (tmp->prev)
528 tmp->prev->next = next;
529 else
530 list = next;
531 if (next)
532 next->prev = tmp->prev;
533
534 _g_list_free_1 (tmp);
535 tmp = next;
536 }
537 }
538 return list;
539 }
540
541 static inline g_list_t* _g_list_remove_link (g_list_t *list, g_list_t *link) {
542 if (link)
543 {
544 if (link->prev)
545 link->prev->next = link->next;
546 if (link->next)
547 link->next->prev = link->prev;
548
549 if (link == list)
550 list = list->next;
551
552 link->next = NULL;
553 link->prev = NULL;
554 }
555
556 return list;
557 }
558
559 g_list_t* g_list_remove_link (g_list_t *list, g_list_t *link) {
560 return _g_list_remove_link (list, link);
561 }
562
563 g_list_t* g_list_delete_link (g_list_t *list, g_list_t *link) {
564 list = _g_list_remove_link (list, link);
565 _g_list_free_1 (link);
566
567 return list;
568 }
569
570 g_list_t* g_list_copy (g_list_t *list) {
571 g_list_t *new_list = NULL;
572
573 if (list)
574 {
575 g_list_t *last;
576
577 new_list = _g_list_new ();
578 new_list->data = list->data;
579 last = new_list;
580 list = list->next;
581 while (list)
582 {
583 last->next = _g_list_new ();
584 last->next->prev = last;
585 last = last->next;
586 last->data = list->data;
587 list = list->next;
588 }
589 }
590
591 return new_list;
592 }
593
594 g_list_t* g_list_reverse (g_list_t *list) {
595 g_list_t *last;
596
597 last = NULL;
598 while (list)
599 {
600 last = list;
601 list = last->next;
602 last->next = last->prev;
603 last->prev = list;
604 }
605
606 return last;
607 }
608
609 g_list_t* g_list_nth (g_list_t *list, unsigned int n) {
610 while ((n-- > 0) && list)
611 list = list->next;
612
613 return list;
614 }
615
616 g_list_t* g_list_nth_prev (g_list_t *list, unsigned int n) {
617 while ((n-- > 0) && list)
618 list = list->prev;
619
620 return list;
621 }
622
623 void* g_list_nth_data (g_list_t *list, unsigned int n) {
624 while ((n-- > 0) && list)
625 list = list->next;
626
627 return list ? list->data : NULL;
628 }
629
630 g_list_t* g_list_find (g_list_t *list, const void *data) {
631 while (list)
632 {
633 if (list->data == data)
634 break;
635 list = list->next;
636 }
637
638 return list;
639 }
640
641 g_list_t* g_list_find_custom (g_list_t *list, const void *data, list_compare func) {
642
643 while (list)
644 {
645 if (! func (list->data, data))
646 return list;
647 list = list->next;
648 }
649
650 return NULL;
651 }
652
653
654 int g_list_position (g_list_t *list, g_list_t *link) {
655 int i;
656
657 i = 0;
658 while (list)
659 {
660 if (list == link)
661 return i;
662 i++;
663 list = list->next;
664 }
665
666 return -1;
667 }
668
669 int g_list_index (g_list_t *list, const void *data) {
670 int i;
671
672 i = 0;
673 while (list)
674 {
675 if (list->data == data)
676 return i;
677 i++;
678 list = list->next;
679 }
680
681 return -1;
682 }
683
684 g_list_t* g_list_last (g_list_t *list) {
685 if (list)
686 {
687 while (list->next)
688 list = list->next;
689 }
690
691 return list;
692 }
693
694 g_list_t* g_list_first (g_list_t *list) {
695 if (list)
696 {
697 while (list->prev)
698 list = list->prev;
699 }
700
701 return list;
702 }
703
704 unsigned int g_list_length (g_list_t *list) {
705 unsigned int length;
706
707 length = 0;
708 while (list)
709 {
710 length++;
711 list = list->next;
712 }
713
714 return length;
715 }
716
717 void g_list_foreach (g_list_t *list, list_func func, void *user_data) {
718 while (list)
719 {
720 g_list_t *next = list->next;
721 (*func) (list->data, user_data);
722 list = next;
723 }
724 }
725
726
727 g_list_t* g_list_insert_sorted (g_list_t *list, void *data, list_compare func) {
728 g_list_t *tmp_list = list;
729 g_list_t *new_list;
730 int cmp;
731
732 if (!func) return list;
733
734 if (!list)
735 {
736 new_list = _g_list_new ();
737 new_list->data = data;
738 return new_list;
739 }
740
741 cmp = (*func) (data, tmp_list->data);
742
743 while ((tmp_list->next) && (cmp > 0))
744 {
745 tmp_list = tmp_list->next;
746 cmp = (*func) (data, tmp_list->data);
747 }
748
749 new_list = _g_list_new ();
750 new_list->data = data;
751
752 if ((!tmp_list->next) && (cmp > 0))
753 {
754 tmp_list->next = new_list;
755 new_list->prev = tmp_list;
756 return list;
757 }
758
759 if (tmp_list->prev)
760 {
761 tmp_list->prev->next = new_list;
762 new_list->prev = tmp_list->prev;
763 }
764 new_list->next = tmp_list;
765 tmp_list->prev = new_list;
766
767 if (tmp_list == list)
768 return new_list;
769 else
770 return list;
771 }
772
773 static g_list_t *g_list_sort_merge (g_list_t *l1, g_list_t *l2, list_func compare_func,
774 int use_data, void *user_data) {
775
776 g_list_t list, *l, *lprev;
777 int cmp;
778
779 l = &list;
780 lprev = NULL;
781
782 while (l1 && l2)
783 {
784 if (use_data)
785 cmp = ((list_compare_data) compare_func) (l1->data, l2->data, user_data);
786 else
787 cmp = ((list_compare) compare_func) (l1->data, l2->data);
788
789 if (cmp <= 0)
790 {
791 l->next = l1;
792 l = l->next;
793 l->prev = lprev;
794 lprev = l;
795 l1 = l1->next;
796 }
797 else
798 {
799 l->next = l2;
800 l = l->next;
801 l->prev = lprev;
802 lprev = l;
803 l2 = l2->next;
804 }
805 }
806 l->next = l1 ? l1 : l2;
807 l->next->prev = l;
808
809 return list.next;
810 }
811
812 static g_list_t* g_list_sort_real (g_list_t *list, list_func compare_func,
813 int use_data, void *user_data) {
814
815 g_list_t *l1, *l2;
816
817 if (!list)
818 return NULL;
819 if (!list->next)
820 return list;
821
822 l1 = list;
823 l2 = list->next;
824
825 while ((l2 = l2->next) != NULL)
826 {
827 if ((l2 = l2->next) == NULL)
828 break;
829 l1 = l1->next;
830 }
831 l2 = l1->next;
832 l1->next = NULL;
833
834 return g_list_sort_merge (g_list_sort_real (list, compare_func, use_data, user_data),
835 g_list_sort_real (l2, compare_func, use_data, user_data),
836 compare_func,
837 use_data,
838 user_data);
839 }
840
841 g_list_t *g_list_sort (g_list_t *list, list_compare compare_func) {
842 return g_list_sort_real (list, (list_func) compare_func, 0, NULL);
843 }
844
845 g_list_t * g_list_sort_with_data (g_list_t *list, list_compare compare_func, void *user_data) {
846 return g_list_sort_real (list, (list_func) compare_func, 1, user_data);
847 }
848
849 #if 0
850 static g_list_t* g_list_sort2 (g_list_t *list, list_compare compare_func) {
851 g_list_t *runs = NULL;
852 g_list_t *tmp;
853
854 /* Degenerate case. */
855 if (!list) return NULL;
856
857 /* Assume: list = [12,2,4,11,2,4,6,1,1,12]. */
858 for (tmp = list; tmp; )
859 {
860 g_list_t *tmp2;
861 for (tmp2 = tmp;
862 tmp2->next && compare_func (tmp2->data, tmp2->next->data) <= 0;
863 tmp2 = tmp2->next)
864 /* Nothing */;
865 runs = g_list_append (runs, tmp);
866 tmp = tmp2->next;
867 tmp2->next = NULL;
868 }
869 /* Now: runs = [[12],[2,4,11],[2,4,6],[1,1,12]]. */
870
871 while (runs->next)
872 {
873 /* We have more than one run. Merge pairwise. */
874 g_list_t *dst, *src, *dstprev = NULL;
875 dst = src = runs;
876 while (src && src->next)
877 {
878 dst->data = g_list_sort_merge (src->data,
879 src->next->data,
880 (list_func) compare_func,
881 0, NULL);
882 dstprev = dst;
883 dst = dst->next;
884 src = src->next->next;
885 }
886
887 /* If number of runs was odd, just keep the last. */
888 if (src)
889 {
890 dst->data = src->data;
891 dstprev = dst;
892 dst = dst->next;
893 }
894
895 dstprev->next = NULL;
896 g_list_free (dst);
897 }
898
899 /* After 1st loop: runs = [[2,4,11,12],[1,1,2,4,6,12]]. */
900 /* After 2nd loop: runs = [[1,1,2,2,4,4,6,11,12,12]]. */
901
902 list = runs->data;
903 g_list_free (runs);
904 return list;
905 }
906 #endif
907