X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=lib%2Fllist.c;h=dbb5352a66f02b29951803b8daa374102c9fd130;hb=a126e5f9a29270523c108db20e0b1b64e961be58;hp=8d6fd265b473d6afd6250dfb72c2e25233c85905;hpb=0a04b3ef850cd3d6f06b3c8d0036993adc9ba7b2;p=android-x86%2Fexternal-toybox.git diff --git a/lib/llist.c b/lib/llist.c index 8d6fd265..dbb5352a 100644 --- a/lib/llist.c +++ b/lib/llist.c @@ -1,32 +1,130 @@ -/* vi: set sw=4 ts=4 : - * llist.c - Linked list functions +/* llist.c - Linked list functions * * Linked list structures have a next pointer as their first element. */ #include "toys.h" -// Free all the elements of a linked list -// if freeit!=NULL call freeit() on each element before freeing it. +// Callback function to free data pointer of double_list or arg_list -void llist_free(void *list, void (*freeit)(void *data)) +void llist_free_arg(void *node) { - while (list) { - void *pop = llist_pop(&list); - if (freeit) freeit(pop); - } + struct arg_list *d = node; + + free(d->arg); + free(d); +} + +void llist_free_double(void *node) +{ + struct double_list *d = node; + + free(d->data); + free(d); +} + +// Call a function (such as free()) on each element of a linked list. +void llist_traverse(void *list, void (*using)(void *node)) +{ + void *old = list; + + while (list) { + void *pop = llist_pop(&list); + using(pop); + + // End doubly linked list too. + if (old == list) break; + } } // Return the first item from the list, advancing the list (which must be called // as &list) void *llist_pop(void *list) { - // I'd use a void ** for the argument, and even accept the typecast in all - // callers as documentation you need the &, except the stupid compiler - // would then scream about type-punned pointers. Screw it. - void **llist = (void **)list; - void **next = (void **)*llist; - *llist = *next; + // I'd use a void ** for the argument, and even accept the typecast in all + // callers as documentation you need the &, except the stupid compiler + // would then scream about type-punned pointers. Screw it. + void **llist = (void **)list; + void **next = (void **)*llist; + *llist = *next; + + return (void *)next; +} + +void *dlist_pop(void *list) +{ + struct double_list **pdlist = (struct double_list **)list, *dlist = *pdlist; + + if (dlist->next == dlist) *pdlist = 0; + else { + dlist->next->prev = dlist->prev; + dlist->prev->next = *pdlist = dlist->next; + } + + return dlist; +} + +void dlist_add_nomalloc(struct double_list **list, struct double_list *new) +{ + if (*list) { + new->next = *list; + new->prev = (*list)->prev; + (*list)->prev->next = new; + (*list)->prev = new; + } else *list = new->next = new->prev = new; +} + + +// Add an entry to the end of a doubly linked list +struct double_list *dlist_add(struct double_list **list, char *data) +{ + struct double_list *new = xmalloc(sizeof(struct double_list)); + + new->data = data; + dlist_add_nomalloc(list, new); + + return new; +} + +// Terminate circular list for traversal in either direction. Returns end *. +void *dlist_terminate(void *list) +{ + struct double_list *end = list; + + if (!list) return 0; + + end = end->prev; + end->next->prev = 0; + end->next = 0; + + return end; +} + +// Find num in cache +struct num_cache *get_num_cache(struct num_cache *cache, long long num) +{ + while (cache) { + if (num==cache->num) return cache; + cache = cache->next; + } + + return 0; +} + +// Uniquely add num+data to cache. Updates *cache, returns pointer to existing +// entry if it was already there. +struct num_cache *add_num_cache(struct num_cache **cache, long long num, + void *data, int len) +{ + struct num_cache *old = get_num_cache(*cache, num); + + if (old) return old; + + old = xzalloc(sizeof(struct num_cache)+len); + old->next = *cache; + old->num = num; + memcpy(old->data, data, len); + *cache = old; - return (void *)next; + return 0; }