4 * Copyright (c) 2006-2012 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
,
210 alpm_list_t
*newlist
, *lp
, *tail_ptr
, *left_tail_ptr
, *right_tail_ptr
;
219 /* Save tail node pointers for future use */
220 left_tail_ptr
= left
->prev
;
221 right_tail_ptr
= right
->prev
;
223 if(fn(left
->data
, right
->data
) <= 0) {
231 newlist
->prev
= NULL
;
232 newlist
->next
= NULL
;
235 while((left
!= NULL
) && (right
!= NULL
)) {
236 if(fn(left
->data
, right
->data
) <= 0) {
252 tail_ptr
= left_tail_ptr
;
254 else if(right
!= NULL
) {
257 tail_ptr
= right_tail_ptr
;
263 newlist
->prev
= tail_ptr
;
269 * @brief Sort a list of size `n` using mergesort algorithm.
271 * @param list the list to sort
272 * @param n the size of the list
273 * @param fn the comparison function for determining order
275 * @return the resultant list
277 alpm_list_t SYMEXPORT
*alpm_list_msort(alpm_list_t
*list
, size_t n
,
283 alpm_list_t
*left
= list
, *lastleft
= list
, *right
;
286 lastleft
= lastleft
->next
;
288 right
= lastleft
->next
;
291 lastleft
->next
= NULL
;
292 right
->prev
= left
->prev
;
293 left
->prev
= lastleft
;
295 left
= alpm_list_msort(left
, half
, fn
);
296 right
= alpm_list_msort(right
, n
- half
, fn
);
297 list
= alpm_list_mmerge(left
, right
, fn
);
303 * @brief Remove an item from the list.
304 * item is not freed; this is the responsibility of the caller.
306 * @param haystack the list to remove the item from
307 * @param item the item to remove from the list
309 * @return the resultant list
311 alpm_list_t SYMEXPORT
*alpm_list_remove_item(alpm_list_t
*haystack
,
314 if(haystack
== NULL
|| item
== NULL
) {
318 if(item
== haystack
) {
319 /* Special case: removing the head node which has a back reference to
321 haystack
= item
->next
;
323 haystack
->prev
= item
->prev
;
326 } else if(item
== haystack
->prev
) {
327 /* Special case: removing the tail node, so we need to fix the back
328 * reference on the head node. We also know tail != head. */
330 /* i->next should always be null */
331 item
->prev
->next
= item
->next
;
332 haystack
->prev
= item
->prev
;
336 /* Normal case, non-head and non-tail node */
338 item
->next
->prev
= item
->prev
;
341 item
->prev
->next
= item
->next
;
350 * @brief Remove an item from the list.
352 * @param haystack the list to remove the item from
353 * @param needle the data member of the item we're removing
354 * @param fn the comparison function for searching
355 * @param data output parameter containing data of the removed item
357 * @return the resultant list
359 alpm_list_t SYMEXPORT
*alpm_list_remove(alpm_list_t
*haystack
,
360 const void *needle
, alpm_list_fn_cmp fn
, void **data
)
362 alpm_list_t
*i
= haystack
;
373 if(i
->data
== NULL
) {
377 if(fn(i
->data
, needle
) == 0) {
378 haystack
= alpm_list_remove_item(haystack
, i
);
394 * @brief Remove a string from a list.
396 * @param haystack the list to remove the item from
397 * @param needle the data member of the item we're removing
398 * @param data output parameter containing data of the removed item
400 * @return the resultant list
402 alpm_list_t SYMEXPORT
*alpm_list_remove_str(alpm_list_t
*haystack
,
403 const char *needle
, char **data
)
405 return alpm_list_remove(haystack
, (const void *)needle
,
406 (alpm_list_fn_cmp
)strcmp
, (void **)data
);
410 * @brief Create a new list without any duplicates.
412 * This does NOT copy data members.
414 * @param list the list to copy
416 * @return a new list containing non-duplicate items
418 alpm_list_t SYMEXPORT
*alpm_list_remove_dupes(const alpm_list_t
*list
)
420 const alpm_list_t
*lp
= list
;
421 alpm_list_t
*newlist
= NULL
;
423 if(!alpm_list_find_ptr(newlist
, lp
->data
)) {
424 newlist
= alpm_list_add(newlist
, lp
->data
);
432 * @brief Copy a string list, including data.
434 * @param list the list to copy
436 * @return a copy of the original list
438 alpm_list_t SYMEXPORT
*alpm_list_strdup(const alpm_list_t
*list
)
440 const alpm_list_t
*lp
= list
;
441 alpm_list_t
*newlist
= NULL
;
443 newlist
= alpm_list_add(newlist
, strdup(lp
->data
));
450 * @brief Copy a list, without copying data.
452 * @param list the list to copy
454 * @return a copy of the original list
456 alpm_list_t SYMEXPORT
*alpm_list_copy(const alpm_list_t
*list
)
458 const alpm_list_t
*lp
= list
;
459 alpm_list_t
*newlist
= NULL
;
461 newlist
= alpm_list_add(newlist
, lp
->data
);
468 * @brief Copy a list and copy the data.
469 * Note that the data elements to be copied should not contain pointers
470 * and should also be of constant size.
472 * @param list the list to copy
473 * @param size the size of each data element
475 * @return a copy of the original list, data copied as well
477 alpm_list_t SYMEXPORT
*alpm_list_copy_data(const alpm_list_t
*list
,
480 const alpm_list_t
*lp
= list
;
481 alpm_list_t
*newlist
= NULL
;
483 void *newdata
= malloc(size
);
485 memcpy(newdata
, lp
->data
, size
);
486 newlist
= alpm_list_add(newlist
, newdata
);
494 * @brief Create a new list in reverse order.
496 * @param list the list to copy
498 * @return a new list in reverse order
500 alpm_list_t SYMEXPORT
*alpm_list_reverse(alpm_list_t
*list
)
502 const alpm_list_t
*lp
;
503 alpm_list_t
*newlist
= NULL
, *backup
;
509 lp
= alpm_list_last(list
);
510 /* break our reverse circular list */
515 newlist
= alpm_list_add(newlist
, lp
->data
);
518 list
->prev
= backup
; /* restore tail pointer */
525 * @brief Return nth element from list (starting from 0).
527 * @param list the list
528 * @param n the index of the item to find (n < alpm_list_count(list) IS needed)
530 * @return an alpm_list_t node for index `n`
532 alpm_list_t SYMEXPORT
*alpm_list_nth(const alpm_list_t
*list
, size_t n
)
534 const alpm_list_t
*i
= list
;
538 return (alpm_list_t
*)i
;
542 * @brief Get the next element of a list.
544 * @param node the list node
546 * @return the next element, or NULL when no more elements exist
548 inline alpm_list_t SYMEXPORT
*alpm_list_next(const alpm_list_t
*node
)
558 * @brief Get the previous element of a list.
560 * @param list the list head
562 * @return the previous element, or NULL when no previous element exist
564 inline alpm_list_t SYMEXPORT
*alpm_list_previous(const alpm_list_t
*list
)
566 if(list
&& list
->prev
->next
) {
574 * @brief Get the last item in the list.
576 * @param list the list
578 * @return the last element in the list
580 alpm_list_t SYMEXPORT
*alpm_list_last(const alpm_list_t
*list
)
592 * @brief Get the number of items in a list.
594 * @param list the list
596 * @return the number of list items
598 size_t SYMEXPORT
alpm_list_count(const alpm_list_t
*list
)
601 const alpm_list_t
*lp
= list
;
610 * @brief Find an item in a list.
612 * @param needle the item to search
613 * @param haystack the list
614 * @param fn the comparison function for searching (!= NULL)
616 * @return `needle` if found, NULL otherwise
618 void SYMEXPORT
*alpm_list_find(const alpm_list_t
*haystack
, const void *needle
,
621 const alpm_list_t
*lp
= haystack
;
623 if(lp
->data
&& fn(lp
->data
, needle
) == 0) {
631 /* trivial helper function for alpm_list_find_ptr */
632 static int ptr_cmp(const void *p
, const void *q
)
638 * @brief Find an item in a list.
640 * Search for the item whose data matches that of the `needle`.
642 * @param needle the data to search for (== comparison)
643 * @param haystack the list
645 * @return `needle` if found, NULL otherwise
647 void SYMEXPORT
*alpm_list_find_ptr(const alpm_list_t
*haystack
,
650 return alpm_list_find(haystack
, needle
, ptr_cmp
);
654 * @brief Find a string in a list.
656 * @param needle the string to search for
657 * @param haystack the list
659 * @return `needle` if found, NULL otherwise
661 char SYMEXPORT
*alpm_list_find_str(const alpm_list_t
*haystack
,
664 return (char *)alpm_list_find(haystack
, (const void *)needle
,
665 (alpm_list_fn_cmp
)strcmp
);
669 * @brief Find the differences between list `left` and list `right`
671 * The two lists must be sorted. Items only in list `left` are added to the
672 * `onlyleft` list. Items only in list `right` are added to the `onlyright`
675 * @param left the first list
676 * @param right the second list
677 * @param fn the comparison function
678 * @param onlyleft pointer to the first result list
679 * @param onlyright pointer to the second result list
682 void SYMEXPORT
alpm_list_diff_sorted(const alpm_list_t
*left
,
683 const alpm_list_t
*right
, alpm_list_fn_cmp fn
,
684 alpm_list_t
**onlyleft
, alpm_list_t
**onlyright
)
686 const alpm_list_t
*l
= left
;
687 const alpm_list_t
*r
= right
;
689 if(!onlyleft
&& !onlyright
) {
693 while(l
!= NULL
&& r
!= NULL
) {
694 int cmp
= fn(l
->data
, r
->data
);
697 *onlyleft
= alpm_list_add(*onlyleft
, l
->data
);
703 *onlyright
= alpm_list_add(*onlyright
, r
->data
);
713 *onlyleft
= alpm_list_add(*onlyleft
, l
->data
);
719 *onlyright
= alpm_list_add(*onlyright
, r
->data
);
727 * @brief Find the items in list `lhs` that are not present in list `rhs`.
729 * @param lhs the first list
730 * @param rhs the second list
731 * @param fn the comparison function
733 * @return a list containing all items in `lhs` not present in `rhs`
735 alpm_list_t SYMEXPORT
*alpm_list_diff(const alpm_list_t
*lhs
,
736 const alpm_list_t
*rhs
, alpm_list_fn_cmp fn
)
738 alpm_list_t
*left
, *right
;
739 alpm_list_t
*ret
= NULL
;
741 left
= alpm_list_copy(lhs
);
742 left
= alpm_list_msort(left
, alpm_list_count(left
), fn
);
743 right
= alpm_list_copy(rhs
);
744 right
= alpm_list_msort(right
, alpm_list_count(right
), fn
);
746 alpm_list_diff_sorted(left
, right
, fn
, &ret
, NULL
);
748 alpm_list_free(left
);
749 alpm_list_free(right
);
754 * @brief Copy a list and data into a standard C array of fixed length.
755 * Note that the data elements are shallow copied so any contained pointers
756 * will point to the original data.
758 * @param list the list to copy
759 * @param n the size of the list
760 * @param size the size of each data element
762 * @return an array version of the original list, data copied as well
764 void SYMEXPORT
*alpm_list_to_array(const alpm_list_t
*list
, size_t n
,
768 const alpm_list_t
*item
;
775 array
= malloc(n
* size
);
779 for(i
= 0, item
= list
; i
< n
&& item
; i
++, item
= item
->next
) {
780 memcpy(array
+ i
* size
, item
->data
, size
);
787 /* vim: set ts=2 sw=2 noet: */