index : pacman | |
Archlinux32 fork of pacman | gitolite user |
summaryrefslogtreecommitdiff |
-rw-r--r-- | lib/libalpm/alpm_list.c | 498 |
diff --git a/lib/libalpm/alpm_list.c b/lib/libalpm/alpm_list.c index 54027455..a1e8861b 100644 --- a/lib/libalpm/alpm_list.c +++ b/lib/libalpm/alpm_list.c @@ -1,8 +1,8 @@ /* * alpm_list.c - * + * * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ @@ -29,29 +29,41 @@ #include "alpm_list.h" #include "util.h" -/** \defgroup alpm_list functions */ -/*\@{*/ +/** + * @addtogroup alpm_list List Functions + * @brief Functions to manipulate alpm_list_t lists. + * + * These functions are designed to create, destroy, and modify lists of + * type alpm_list_t. This is an internal list type used by libalpm that is + * publicly exposed for use by frontends if desired. + * + * @{ */ /* Allocation */ -/** Allocate a new alpm_list_t - * @return a new alpm_list_t item, or NULL on failure +/** + * @brief Allocate a new alpm_list_t. + * + * @return a new alpm_list_t item, or NULL on failure */ -alpm_list_t *alpm_list_new() +alpm_list_t SYMEXPORT *alpm_list_new() { alpm_list_t *list = NULL; - list = (alpm_list_t *)malloc(sizeof(alpm_list_t)); + list = malloc(sizeof(alpm_list_t)); if(list) { list->data = NULL; - list->prev = NULL; + list->prev = list; /* maintain a back reference to the tail pointer */ list->next = NULL; } + return(list); } -/** Free a list, but not the contained data - * @param list the list to free +/** + * @brief Free a list, but not the contained data. + * + * @param list the list to free */ void SYMEXPORT alpm_list_free(alpm_list_t *list) { @@ -64,9 +76,11 @@ void SYMEXPORT alpm_list_free(alpm_list_t *list) } } -/** Free the internal data of a list structure - * @param list the list to free - * @param fn a free function for the internal data +/** + * @brief Free the internal data of a list structure. + * + * @param list the list to free + * @param fn a free function for the internal data */ void SYMEXPORT alpm_list_free_inner(alpm_list_t *list, alpm_list_fn_free fn) { @@ -83,10 +97,13 @@ void SYMEXPORT alpm_list_free_inner(alpm_list_t *list, alpm_list_fn_free fn) /* Mutators */ -/** Add a new item to the list - * @param list the list to add to - * @param data the new item to be added to the list - * @return the resultant list, or NULL on failure +/** + * @brief Add a new item to the end of the list. + * + * @param list the list to add to + * @param data the new item to be added to the list + * + * @return the resultant list */ alpm_list_t SYMEXPORT *alpm_list_add(alpm_list_t *list, void *data) { @@ -110,6 +127,7 @@ alpm_list_t SYMEXPORT *alpm_list_add(alpm_list_t *list, void *data) } lp->next->prev = lp; lp = lp->next; + list->prev = lp; } lp->data = data; @@ -117,13 +135,16 @@ alpm_list_t SYMEXPORT *alpm_list_add(alpm_list_t *list, void *data) return(ptr); } -/** Add items to a list in sorted order. - * @param list the list to add to - * @param data the new item to be added to the list - * @param fn the comparison function to use to determine order - * @return the resultant list, or NULL on failure +/** + * @brief Add items to a list in sorted order. + * + * @param list the list to add to + * @param data the new item to be added to the list + * @param fn the comparison function to use to determine order + * + * @return the resultant list */ -alpm_list_t *alpm_list_add_sorted(alpm_list_t *list, void *data, alpm_list_fn_cmp fn) +alpm_list_t SYMEXPORT *alpm_list_add_sorted(alpm_list_t *list, void *data, alpm_list_fn_cmp fn) { if(!fn) { return alpm_list_add(list, data); @@ -153,21 +174,63 @@ alpm_list_t *alpm_list_add_sorted(alpm_list_t *list, void *data, alpm_list_fn_cm } else { list = add; /* At beginning, or new list */ } - + + if(next == NULL) { + /* At end, adjust tail pointer on head node */ + list->prev = add; + } + return(list); } } -/** Merge the two sorted sublists into one sorted list - * @param left the first list +/** + * @brief Join two lists. + * The two lists must be independent. Do not free the original lists after + * calling this function, as this is not a copy operation. The list pointers + * passed in should be considered invalid after calling this function. + * + * @param first the first list + * @param second the second list + * + * @return the resultant joined list + */ +alpm_list_t SYMEXPORT *alpm_list_join(alpm_list_t *first, alpm_list_t *second) +{ + alpm_list_t *tmp; + + if (first == NULL) { + return second; + } + if (second == NULL) { + return first; + } + /* tmp is the last element of the first list */ + tmp = first->prev; + /* link the first list to the second */ + tmp->next = second; + /* link the second list to the first */ + first->prev = second->prev; + /* set the back reference to the tail */ + second->prev = tmp; + + return(first); +} + +/** + * @brief Merge the two sorted sublists into one sorted list. + * + * @param left the first list * @param right the second list - * @param fn comparison function for determining merge order + * @param fn comparison function for determining merge order + * + * @return the resultant list */ -alpm_list_t *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right, alpm_list_fn_cmp fn) +alpm_list_t SYMEXPORT *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right, alpm_list_fn_cmp fn) { alpm_list_t *newlist, *lp; - if (left == NULL) + if (left == NULL) return right; if (right == NULL) return left; @@ -189,7 +252,7 @@ alpm_list_t *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right, alpm_list_f lp->next = left; left->prev = lp; left = left->next; - } + } else { lp->next = right; right->prev = lp; @@ -206,22 +269,35 @@ alpm_list_t *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right, alpm_list_f lp->next = right; right->prev = lp; } + + /* Find our tail pointer + * TODO maintain this in the algorithm itself */ + lp = newlist; + while(lp && lp->next) { + lp = lp->next; + } + newlist->prev = lp; + return(newlist); } -/** Sort a list of size `n` using mergesort algorithm - * @param list the list to sort - * @param n the size of the list - * @param fn the comparison function for determining order +/** + * @brief Sort a list of size `n` using mergesort algorithm. + * + * @param list the list to sort + * @param n the size of the list + * @param fn the comparison function for determining order + * + * @return the resultant list */ -alpm_list_t* alpm_list_msort(alpm_list_t *list, int n, alpm_list_fn_cmp fn) +alpm_list_t SYMEXPORT *alpm_list_msort(alpm_list_t *list, int n, alpm_list_fn_cmp fn) { if (n > 1) { alpm_list_t *left = list; alpm_list_t *lastleft = alpm_list_nth(list, n/2 - 1); alpm_list_t *right = lastleft->next; /* terminate first list */ - lastleft->next = NULL; + lastleft->next = NULL; left = alpm_list_msort(left, n/2, fn); right = alpm_list_msort(right, n - (n/2), fn); @@ -230,15 +306,18 @@ alpm_list_t* alpm_list_msort(alpm_list_t *list, int n, alpm_list_fn_cmp fn) return(list); } -/** Remove an item from the list - * @param haystack the list to remove the item from - * @param needle the data member of the item we're removing - * @param fn the comparison function for searching - * @param data output parameter containing the data member of the item removed - * @return the resultant list, or NULL on failure +/** + * @brief Remove an item from the list. + * + * @param haystack the list to remove the item from + * @param needle the data member of the item we're removing + * @param fn the comparison function for searching + * @param data output parameter containing data of the removed item + * + * @return the resultant list */ -alpm_list_t *alpm_list_remove(alpm_list_t *haystack, const void *needle, alpm_list_fn_cmp fn, void **data) -{ /* TODO I modified this to remove ALL matching items. Do we need a remove_first? */ +alpm_list_t SYMEXPORT *alpm_list_remove(alpm_list_t *haystack, const void *needle, alpm_list_fn_cmp fn, void **data) +{ alpm_list_t *i = haystack, *tmp = NULL; if(data) { @@ -252,16 +331,31 @@ alpm_list_t *alpm_list_remove(alpm_list_t *haystack, const void *needle, alpm_li tmp = i->next; if(fn(needle, i->data) == 0) { /* we found a matching item */ - if(i->next) { - i->next->prev = i->prev; - } - if(i->prev) { - i->prev->next = i->next; - } - if(i == haystack) { - /* The item found is the first in the chain */ - haystack = haystack->next; + /* Special case: removing the head node which has a back reference to + * the tail node */ + haystack = i->next; + if(haystack) { + haystack->prev = i->prev; + } + i->prev = NULL; + } else if(i == haystack->prev) { + /* Special case: removing the tail node, so we need to fix the back + * reference on the head node. We also know tail != head. */ + if(i->prev) { + /* i->next should always be null */ + i->prev->next = i->next; + haystack->prev = i->prev; + i->prev = NULL; + } + } else { + /* Normal case, non-head and non-tail node */ + if(i->next) { + i->next->prev = i->prev; + } + if(i->prev) { + i->prev->next = i->next; + } } if(data) { @@ -269,79 +363,117 @@ alpm_list_t *alpm_list_remove(alpm_list_t *haystack, const void *needle, alpm_li } i->data = NULL; free(i); + i = NULL; + } else { + i = tmp; } - i = tmp; } return(haystack); } -/** Remove the passed in node from the list that it is a part of - * @note this DOES NOT free the node - * @param node the list node we're removing - * @return the node which took the place of this one +/** + * @brief Create a new list without any duplicates. + * + * This does NOT copy data members. + * + * @param list the list to copy + * + * @return a new list containing non-duplicate items */ -alpm_list_t *alpm_list_remove_node(alpm_list_t *node) +alpm_list_t SYMEXPORT *alpm_list_remove_dupes(const alpm_list_t *list) { - if(!node) return(NULL); - - alpm_list_t *ret = NULL; - - if(node->prev) { - node->prev->next = node->next; - ret = node->prev; - node->prev = NULL; - } - if(node->next) { - node->next->prev = node->prev; - ret = node->next; - node->next = NULL; + const alpm_list_t *lp = list; + alpm_list_t *newlist = NULL; + while(lp) { + if(!alpm_list_find_ptr(newlist, lp->data)) { + newlist = alpm_list_add(newlist, lp->data); + } + lp = lp->next; } - - return(ret); + return(newlist); } -/** Create a new list without any duplicates - * @note DOES NOT copy data members - * @param list the list to copy - * @return a NEW list containing non-duplicated items +/** + * @brief Copy a string list, including data. + * + * @param list the list to copy + * + * @return a copy of the original list */ -alpm_list_t SYMEXPORT *alpm_list_remove_dupes(alpm_list_t *list) -{ /* TODO does removing the strdup here cause invalid free's anywhere? */ - alpm_list_t *lp = list, *newlist = NULL; +alpm_list_t SYMEXPORT *alpm_list_strdup(const alpm_list_t *list) +{ + const alpm_list_t *lp = list; + alpm_list_t *newlist = NULL; while(lp) { - if(!alpm_list_find(newlist, lp->data)) { - newlist = alpm_list_add(newlist, lp->data); - } + newlist = alpm_list_add(newlist, strdup(lp->data)); lp = lp->next; } return(newlist); } -/** Copy a string list, including data - * @note this is gross, assumes string data members - * @param list the list to copy - * @return a copy of the original list +/** + * @brief Copy a list, without copying data. + * + * @param list the list to copy + * + * @return a copy of the original list */ -alpm_list_t *alpm_list_strdup(alpm_list_t *list) +alpm_list_t SYMEXPORT *alpm_list_copy(const alpm_list_t *list) { - alpm_list_t *lp = list, *newlist = NULL; + const alpm_list_t *lp = list; + alpm_list_t *newlist = NULL; while(lp) { - newlist = alpm_list_add(newlist, strdup(lp->data)); + newlist = alpm_list_add(newlist, lp->data); lp = lp->next; } return(newlist); } -/** Create a new list in reverse order - * @param list the list to copy - * @return a NEW list in reverse order of the first +/** + * @brief Copy a list and copy the data. + * Note that the data elements to be copied should not contain pointers + * and should also be of constant size. + * + * @param list the list to copy + * @param size the size of each data element + * + * @return a copy of the original list, data copied as well */ -alpm_list_t *alpm_list_reverse(alpm_list_t *list) -{ /* TODO any invalid free's from NOT duplicating data here? */ - alpm_list_t *lp, *newlist = NULL; +alpm_list_t SYMEXPORT *alpm_list_copy_data(const alpm_list_t *list, + size_t size) +{ + const alpm_list_t *lp = list; + alpm_list_t *newlist = NULL; + while(lp) { + void *newdata = calloc(1, size); + if(newdata) { + memcpy(newdata, lp->data, size); + newlist = alpm_list_add(newlist, newdata); + lp = lp->next; + } + } + return(newlist); +} + +/** + * @brief Create a new list in reverse order. + * + * @param list the list to copy + * + * @return a new list in reverse order + */ +alpm_list_t SYMEXPORT *alpm_list_reverse(alpm_list_t *list) +{ + const alpm_list_t *lp; + alpm_list_t *newlist = NULL; lp = alpm_list_last(list); + if(list) { + /* break our reverse circular list */ + list->prev = NULL; + } + while(lp) { newlist = alpm_list_add(newlist, lp->data); lp = lp->prev; @@ -351,65 +483,84 @@ alpm_list_t *alpm_list_reverse(alpm_list_t *list) /* Accessors */ -/** Get the first element of a list. +/** + * @brief Get the first element of a list. + * * @param list the list + * * @return the first element in the list */ -alpm_list_t SYMEXPORT *alpm_list_first(alpm_list_t *list) +inline alpm_list_t SYMEXPORT *alpm_list_first(const alpm_list_t *list) { - return(list); + return((alpm_list_t*)list); } -/** Return nth element from list (starting with 0) - * @param list the list to access - * @param n the index of the item to find - * @return an alpm_list_t node for index `n` +/** + * @brief Return nth element from list (starting from 0). + * + * @param list the list + * @param n the index of the item to find + * + * @return an alpm_list_t node for index `n` */ -alpm_list_t *alpm_list_nth(alpm_list_t *list, int n) +alpm_list_t SYMEXPORT *alpm_list_nth(const alpm_list_t *list, int n) { - alpm_list_t *i = list; + const alpm_list_t *i = list; while(n--) { i = i->next; } - return(i); + return((alpm_list_t*)i); } -/** Get the next element of a list. - * @param entry the list entry +/** + * @brief Get the next element of a list. + * + * @param node the list node + * * @return the next element, or NULL when no more elements exist */ -alpm_list_t SYMEXPORT *alpm_list_next(alpm_list_t *entry) +inline alpm_list_t SYMEXPORT *alpm_list_next(const alpm_list_t *node) { - return(entry->next); + return(node->next); } -/** Get the last item in the list. - * @param list the list to operate on - * @return the last element in the list + +/** + * @brief Get the last item in the list. + * + * @param list the list + * + * @return the last element in the list */ -alpm_list_t *alpm_list_last(alpm_list_t *list) +alpm_list_t SYMEXPORT *alpm_list_last(const alpm_list_t *list) { - alpm_list_t *i = list; - while(i && i->next) { - i = i->next; + if(list) { + return(list->prev); + } else { + return(NULL); } - return(i); } -/** Get the data member of a list entry. - * @param entry the list entry +/** + * @brief Get the data member of a list node. + * + * @param node the list node + * * @return the contained data, or NULL if none */ -void SYMEXPORT *alpm_list_getdata(const alpm_list_t *entry) +void SYMEXPORT *alpm_list_getdata(const alpm_list_t *node) { - if(entry == NULL) return(NULL); - return(entry->data); + if(node == NULL) return(NULL); + return(node->data); } /* Misc */ -/** Count the list items - * @param list the list to operate on - * @return the number of list items +/** + * @brief Get the number of items in a list. + * + * @param list the list + * + * @return the number of list items */ int SYMEXPORT alpm_list_count(const alpm_list_t *list) { @@ -422,53 +573,80 @@ int SYMEXPORT alpm_list_count(const alpm_list_t *list) return(i); } -/** Is an item in the list - * @param needle the data to compare to (== comparison) - * @param haystack the list to search - * @return 1 if `needle` is found, 0 otherwise +/** + * @brief Find an item in a list. + * + * @param needle the item to search + * @param haystack the list + * @param fn the comparison function for searching (!= NULL) + * + * @return `needle` if found, NULL otherwise */ -int SYMEXPORT alpm_list_find(alpm_list_t *haystack, const void *needle) +void SYMEXPORT *alpm_list_find(const alpm_list_t *haystack, const void *needle, + alpm_list_fn_cmp fn) { - alpm_list_t *lp = haystack; + const alpm_list_t *lp = haystack; while(lp) { - if(lp->data == needle) { - return(1); + if(lp->data && fn(lp->data, needle) == 0) { + return(lp->data); } lp = lp->next; } - return(0); + return(NULL); +} + +/* trivial helper function for alpm_list_find_ptr */ +static int ptrcmp(const void *p, const void *q) +{ + return(p != q); +} + +/** + * @brief Find an item in a list. + * + * Search for the item whos data matches that of the `needle`. + * + * @param needle the data to search for (== comparison) + * @param haystack the list + * + * @return `needle` if found, NULL otherwise + */ +void SYMEXPORT *alpm_list_find_ptr(const alpm_list_t *haystack, const void *needle) +{ + return(alpm_list_find(haystack, needle, ptrcmp)); } -/* Test for existence of a string in a alpm_list_t -*/ -/** Is a _string_ in the list (optimization of alpm_list_find for strings) - * @param needle the string to compare - * @param haystack the list to search - * @return 1 if `needle` is found, 0 otherwise +/** + * @brief Find a string in a list. + * + * @param needle the string to search for + * @param haystack the list + * + * @return `needle` if found, NULL otherwise */ -int SYMEXPORT alpm_list_find_str(alpm_list_t *haystack, const char *needle) +char SYMEXPORT *alpm_list_find_str(const alpm_list_t *haystack, const char *needle) { - alpm_list_t *lp = haystack; - while(lp) { - if(lp->data && strcmp((const char *)lp->data, needle) == 0) { - return(1); - } - lp = lp->next; - } - return(0); + return((char *)alpm_list_find(haystack, (const void*)needle, (alpm_list_fn_cmp)strcmp)); } -/** - * Calculate the items in list `lhs` that are not present in list `rhs` - * @note Entries are not duplicated +/** + * @brief Find the items in list `lhs` that are not present in list `rhs`. + * + * Entries are not duplicated. Operation is O(m*n). The first list is stepped + * through one node at a time, and for each node in the first list, each node + * in the second list is compared to it. + * * @param lhs the first list * @param rhs the second list - * @param fn the comparison function - * @return a list containing all items in lhs not present in rhs + * @param fn the comparison function + * + * @return a list containing all items in `lhs` not present in `rhs` */ -alpm_list_t *alpm_list_diff(alpm_list_t *lhs, alpm_list_t *rhs, alpm_list_fn_cmp fn) +alpm_list_t SYMEXPORT *alpm_list_diff(const alpm_list_t *lhs, + const alpm_list_t *rhs, alpm_list_fn_cmp fn) { - alpm_list_t *i, *j, *ret = NULL; + const alpm_list_t *i, *j; + alpm_list_t *ret = NULL; for(i = lhs; i; i = i->next) { int found = 0; for(j = rhs; j; j = j->next) { |