4 * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
5 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "alpm_list.h"
27 /* check exported library symbols with: nm -C -D <lib> */
28 #define SYMEXPORT __attribute__((visibility("default")))
29 #define SYMHIDDEN __attribute__((visibility("internal")))
32 * @addtogroup alpm_list List Functions
33 * @brief Functions to manipulate alpm_list_t lists.
35 * These functions are designed to create, destroy, and modify lists of
36 * type alpm_list_t. This is an internal list type used by libalpm that is
37 * publicly exposed for use by frontends if desired.
44 * @brief Free a list, but not the contained data.
46 * @param list the list to free
48 void SYMEXPORT
alpm_list_free(alpm_list_t
*list
)
50 alpm_list_t
*it
= list
;
53 alpm_list_t
*tmp
= it
->next
;
60 * @brief Free the internal data of a list structure.
62 * @param list the list to free
63 * @param fn a free function for the internal data
65 void SYMEXPORT
alpm_list_free_inner(alpm_list_t
*list
, alpm_list_fn_free fn
)
67 alpm_list_t
*it
= list
;
81 * @brief Add a new item to the end of the list.
83 * @param list the list to add to
84 * @param data the new item to be added to the list
86 * @return the resultant list
88 alpm_list_t SYMEXPORT
*alpm_list_add(alpm_list_t
*list
, void *data
)
90 alpm_list_t
*ptr
, *lp
;
92 ptr
= malloc(sizeof(alpm_list_t
));
100 /* Special case: the input list is empty */
106 lp
= alpm_list_last(list
);
115 * @brief Add items to a list in sorted order.
117 * @param list the list to add to
118 * @param data the new item to be added to the list
119 * @param fn the comparison function to use to determine order
121 * @return the resultant list
123 alpm_list_t SYMEXPORT
*alpm_list_add_sorted(alpm_list_t
*list
, void *data
, alpm_list_fn_cmp fn
)
126 return alpm_list_add(list
, data
);
128 alpm_list_t
*add
= NULL
, *prev
= NULL
, *next
= list
;
130 add
= malloc(sizeof(alpm_list_t
));
136 /* Find insertion point. */
138 if(fn(add
->data
, next
->data
) <= 0) break;
143 /* Insert the add node to the list */
144 if(prev
== NULL
) { /* special case: we insert add as the first element */
145 add
->prev
= list
->prev
; /* list != NULL */
149 } else if(next
== NULL
) { /* another special case: add last element */
166 * @brief Join two lists.
167 * The two lists must be independent. Do not free the original lists after
168 * calling this function, as this is not a copy operation. The list pointers
169 * passed in should be considered invalid after calling this function.
171 * @param first the first list
172 * @param second the second list
174 * @return the resultant joined list
176 alpm_list_t SYMEXPORT
*alpm_list_join(alpm_list_t
*first
, alpm_list_t
*second
)
186 /* tmp is the last element of the first list */
188 /* link the first list to the second */
190 /* link the second list to the first */
191 first
->prev
= second
->prev
;
192 /* set the back reference to the tail */
199 * @brief Merge the two sorted sublists into one sorted list.
201 * @param left the first list
202 * @param right the second list
203 * @param fn comparison function for determining merge order
205 * @return the resultant list
207 alpm_list_t SYMEXPORT
*alpm_list_mmerge(alpm_list_t
*left
, alpm_list_t
*right
, alpm_list_fn_cmp fn
)
209 alpm_list_t
*newlist
, *lp
, *tail_ptr
, *left_tail_ptr
, *right_tail_ptr
;
218 /* Save tail node pointers for future use */
219 left_tail_ptr
= left
->prev
;
220 right_tail_ptr
= right
->prev
;
222 if(fn(left
->data
, right
->data
) <= 0) {
230 newlist
->prev
= NULL
;
231 newlist
->next
= NULL
;
234 while((left
!= NULL
) && (right
!= NULL
)) {
235 if(fn(left
->data
, right
->data
) <= 0) {
251 tail_ptr
= left_tail_ptr
;
253 else if(right
!= NULL
) {
256 tail_ptr
= right_tail_ptr
;
262 newlist
->prev
= tail_ptr
;
268 * @brief Sort a list of size `n` using mergesort algorithm.
270 * @param list the list to sort
271 * @param n the size of the list
272 * @param fn the comparison function for determining order
274 * @return the resultant list
276 alpm_list_t SYMEXPORT
*alpm_list_msort(alpm_list_t
*list
, size_t n
, alpm_list_fn_cmp fn
)
279 alpm_list_t
*left
= list
;
280 alpm_list_t
*lastleft
= alpm_list_nth(list
, n
/2 - 1);
281 alpm_list_t
*right
= lastleft
->next
;
282 /* terminate first list */
283 lastleft
->next
= NULL
;
285 left
= alpm_list_msort(left
, n
/2, fn
);
286 right
= alpm_list_msort(right
, n
- (n
/2), fn
);
287 list
= alpm_list_mmerge(left
, right
, fn
);
293 * @brief Remove an item from the list.
294 * item is not freed; this is the responsibility of the caller.
296 * @param haystack the list to remove the item from
297 * @param item the item to remove from the list
299 * @return the resultant list
301 alpm_list_t SYMEXPORT
*alpm_list_remove_item(alpm_list_t
*haystack
,
304 if(haystack
== NULL
|| item
== NULL
) {
308 if(item
== haystack
) {
309 /* Special case: removing the head node which has a back reference to
311 haystack
= item
->next
;
313 haystack
->prev
= item
->prev
;
316 } else if(item
== haystack
->prev
) {
317 /* Special case: removing the tail node, so we need to fix the back
318 * reference on the head node. We also know tail != head. */
320 /* i->next should always be null */
321 item
->prev
->next
= item
->next
;
322 haystack
->prev
= item
->prev
;
326 /* Normal case, non-head and non-tail node */
328 item
->next
->prev
= item
->prev
;
331 item
->prev
->next
= item
->next
;
340 * @brief Remove an item from the list.
342 * @param haystack the list to remove the item from
343 * @param needle the data member of the item we're removing
344 * @param fn the comparison function for searching
345 * @param data output parameter containing data of the removed item
347 * @return the resultant list
349 alpm_list_t SYMEXPORT
*alpm_list_remove(alpm_list_t
*haystack
,
350 const void *needle
, alpm_list_fn_cmp fn
, void **data
)
352 alpm_list_t
*i
= haystack
;
363 if(i
->data
== NULL
) {
367 if(fn(i
->data
, needle
) == 0) {
368 haystack
= alpm_list_remove_item(haystack
, i
);
384 * @brief Remove a string from a list.
386 * @param haystack the list to remove the item from
387 * @param needle the data member of the item we're removing
388 * @param data output parameter containing data of the removed item
390 * @return the resultant list
392 alpm_list_t SYMEXPORT
*alpm_list_remove_str(alpm_list_t
*haystack
,
393 const char *needle
, char **data
)
395 return alpm_list_remove(haystack
, (const void *)needle
,
396 (alpm_list_fn_cmp
)strcmp
, (void **)data
);
400 * @brief Create a new list without any duplicates.
402 * This does NOT copy data members.
404 * @param list the list to copy
406 * @return a new list containing non-duplicate items
408 alpm_list_t SYMEXPORT
*alpm_list_remove_dupes(const alpm_list_t
*list
)
410 const alpm_list_t
*lp
= list
;
411 alpm_list_t
*newlist
= NULL
;
413 if(!alpm_list_find_ptr(newlist
, lp
->data
)) {
414 newlist
= alpm_list_add(newlist
, lp
->data
);
422 * @brief Copy a string list, including data.
424 * @param list the list to copy
426 * @return a copy of the original list
428 alpm_list_t SYMEXPORT
*alpm_list_strdup(const alpm_list_t
*list
)
430 const alpm_list_t
*lp
= list
;
431 alpm_list_t
*newlist
= NULL
;
433 newlist
= alpm_list_add(newlist
, strdup(lp
->data
));
440 * @brief Copy a list, without copying data.
442 * @param list the list to copy
444 * @return a copy of the original list
446 alpm_list_t SYMEXPORT
*alpm_list_copy(const alpm_list_t
*list
)
448 const alpm_list_t
*lp
= list
;
449 alpm_list_t
*newlist
= NULL
;
451 newlist
= alpm_list_add(newlist
, lp
->data
);
458 * @brief Copy a list and copy the data.
459 * Note that the data elements to be copied should not contain pointers
460 * and should also be of constant size.
462 * @param list the list to copy
463 * @param size the size of each data element
465 * @return a copy of the original list, data copied as well
467 alpm_list_t SYMEXPORT
*alpm_list_copy_data(const alpm_list_t
*list
,
470 const alpm_list_t
*lp
= list
;
471 alpm_list_t
*newlist
= NULL
;
473 void *newdata
= malloc(size
);
475 memcpy(newdata
, lp
->data
, size
);
476 newlist
= alpm_list_add(newlist
, newdata
);
484 * @brief Create a new list in reverse order.
486 * @param list the list to copy
488 * @return a new list in reverse order
490 alpm_list_t SYMEXPORT
*alpm_list_reverse(alpm_list_t
*list
)
492 const alpm_list_t
*lp
;
493 alpm_list_t
*newlist
= NULL
, *backup
;
499 lp
= alpm_list_last(list
);
500 /* break our reverse circular list */
505 newlist
= alpm_list_add(newlist
, lp
->data
);
508 list
->prev
= backup
; /* restore tail pointer */
515 * @brief Return nth element from list (starting from 0).
517 * @param list the list
518 * @param n the index of the item to find (n < alpm_list_count(list) IS needed)
520 * @return an alpm_list_t node for index `n`
522 alpm_list_t SYMEXPORT
*alpm_list_nth(const alpm_list_t
*list
, size_t n
)
524 const alpm_list_t
*i
= list
;
528 return (alpm_list_t
*)i
;
532 * @brief Get the next element of a list.
534 * @param node the list node
536 * @return the next element, or NULL when no more elements exist
538 inline alpm_list_t SYMEXPORT
*alpm_list_next(const alpm_list_t
*node
)
548 * @brief Get the previous element of a list.
550 * @param list the list head
552 * @return the previous element, or NULL when no previous element exist
554 inline alpm_list_t SYMEXPORT
*alpm_list_previous(const alpm_list_t
*list
)
556 if(list
&& list
->prev
->next
) {
564 * @brief Get the last item in the list.
566 * @param list the list
568 * @return the last element in the list
570 alpm_list_t SYMEXPORT
*alpm_list_last(const alpm_list_t
*list
)
582 * @brief Get the number of items in a list.
584 * @param list the list
586 * @return the number of list items
588 size_t SYMEXPORT
alpm_list_count(const alpm_list_t
*list
)
591 const alpm_list_t
*lp
= list
;
600 * @brief Find an item in a list.
602 * @param needle the item to search
603 * @param haystack the list
604 * @param fn the comparison function for searching (!= NULL)
606 * @return `needle` if found, NULL otherwise
608 void SYMEXPORT
*alpm_list_find(const alpm_list_t
*haystack
, const void *needle
,
611 const alpm_list_t
*lp
= haystack
;
613 if(lp
->data
&& fn(lp
->data
, needle
) == 0) {
621 /* trivial helper function for alpm_list_find_ptr */
622 static int ptr_cmp(const void *p
, const void *q
)
628 * @brief Find an item in a list.
630 * Search for the item whose data matches that of the `needle`.
632 * @param needle the data to search for (== comparison)
633 * @param haystack the list
635 * @return `needle` if found, NULL otherwise
637 void SYMEXPORT
*alpm_list_find_ptr(const alpm_list_t
*haystack
,
640 return alpm_list_find(haystack
, needle
, ptr_cmp
);
644 * @brief Find a string in a list.
646 * @param needle the string to search for
647 * @param haystack the list
649 * @return `needle` if found, NULL otherwise
651 char SYMEXPORT
*alpm_list_find_str(const alpm_list_t
*haystack
,
654 return (char *)alpm_list_find(haystack
, (const void *)needle
,
655 (alpm_list_fn_cmp
)strcmp
);
659 * @brief Find the differences between list `left` and list `right`
661 * The two lists must be sorted. Items only in list `left` are added to the
662 * `onlyleft` list. Items only in list `right` are added to the `onlyright`
665 * @param left the first list
666 * @param right the second list
667 * @param fn the comparison function
668 * @param onlyleft pointer to the first result list
669 * @param onlyright pointer to the second result list
672 void SYMEXPORT
alpm_list_diff_sorted(const alpm_list_t
*left
,
673 const alpm_list_t
*right
, alpm_list_fn_cmp fn
,
674 alpm_list_t
**onlyleft
, alpm_list_t
**onlyright
)
676 const alpm_list_t
*l
= left
;
677 const alpm_list_t
*r
= right
;
679 if(!onlyleft
&& !onlyright
) {
683 while(l
!= NULL
&& r
!= NULL
) {
684 int cmp
= fn(l
->data
, r
->data
);
687 *onlyleft
= alpm_list_add(*onlyleft
, l
->data
);
693 *onlyright
= alpm_list_add(*onlyright
, r
->data
);
703 *onlyleft
= alpm_list_add(*onlyleft
, l
->data
);
709 *onlyright
= alpm_list_add(*onlyright
, r
->data
);
717 * @brief Find the items in list `lhs` that are not present in list `rhs`.
719 * @param lhs the first list
720 * @param rhs the second list
721 * @param fn the comparison function
723 * @return a list containing all items in `lhs` not present in `rhs`
725 alpm_list_t SYMEXPORT
*alpm_list_diff(const alpm_list_t
*lhs
,
726 const alpm_list_t
*rhs
, alpm_list_fn_cmp fn
)
728 alpm_list_t
*left
, *right
;
729 alpm_list_t
*ret
= NULL
;
731 left
= alpm_list_copy(lhs
);
732 left
= alpm_list_msort(left
, alpm_list_count(left
), fn
);
733 right
= alpm_list_copy(rhs
);
734 right
= alpm_list_msort(right
, alpm_list_count(right
), fn
);
736 alpm_list_diff_sorted(left
, right
, fn
, &ret
, NULL
);
738 alpm_list_free(left
);
739 alpm_list_free(right
);
744 * @brief Copy a list and data into a standard C array of fixed length.
745 * Note that the data elements are shallow copied so any contained pointers
746 * will point to the original data.
748 * @param list the list to copy
749 * @param n the size of the list
750 * @param size the size of each data element
752 * @return an array version of the original list, data copied as well
754 void SYMEXPORT
*alpm_list_to_array(const alpm_list_t
*list
, size_t n
,
758 const alpm_list_t
*item
;
765 array
= malloc(n
* size
);
769 for(i
= 0, item
= list
; i
< n
&& item
; i
++, item
= item
->next
) {
770 memcpy(array
+ i
* size
, item
->data
, size
);
777 /* vim: set ts=2 sw=2 noet: */