diff options
author | Kay Sievers <kay.sievers@vrfy.org> | 2008-09-28 01:34:55 +0200 |
---|---|---|
committer | Kay Sievers <kay.sievers@vrfy.org> | 2008-09-28 01:34:55 +0200 |
commit | 0de33a61d741699f41f47ebdb505f518722159b2 (patch) | |
tree | c49789c423a93087a7034505284d5c68e113ee34 /udev/lib/libudev-list.c | |
parent | e345e2670a8c17f5e1145cc554b7a7646e271032 (diff) |
libudev: more list rework
Diffstat (limited to 'udev/lib/libudev-list.c')
-rw-r--r-- | udev/lib/libudev-list.c | 182 |
1 files changed, 98 insertions, 84 deletions
diff --git a/udev/lib/libudev-list.c b/udev/lib/libudev-list.c index 553edf69f8..895c665e40 100644 --- a/udev/lib/libudev-list.c +++ b/udev/lib/libudev-list.c @@ -27,7 +27,7 @@ #include "libudev.h" #include "libudev-private.h" -struct udev_list { +struct udev_list_entry { struct udev *udev; struct list_node node; struct list_node *list; @@ -35,157 +35,171 @@ struct udev_list { char *value; }; -static struct udev_list *node_to_entry(struct list_node *node) -{ - char *list; - - list = (char *)node; - list -= offsetof(struct udev_list, node); - return (struct udev_list *)list; -} - +/* list head point to itself if empty */ void list_init(struct list_node *list) { list->next = list; list->prev = list; } -static int list_empty(struct list_node *list) +static int list_is_empty(struct list_node *list) { return list->next == list; } -#if 0 -static void list_add(struct list_node *new, struct list_node *list) +static void list_node_insert_between(struct list_node *new, + struct list_node *prev, + struct list_node *next) { - struct list_node *next = list->next; - next->prev = new; new->next = next; - new->prev = list; - list->next = new; -} -#endif - -static void list_add_to_end(struct list_node *new, struct list_node *list) -{ - struct list_node *prev = list->prev; - - list->prev = new; - new->next = list; new->prev = prev; prev->next = new; } -static void list_del(struct list_node *entry) +static void list_node_remove(struct list_node *entry) { struct list_node *prev = entry->prev; struct list_node *next = entry->next; next->prev = prev; prev->next = next; + + entry->prev = NULL; + entry->next = NULL; } -#define list_for_each_entry(pos, list) \ - for (pos = node_to_entry((list)->next); \ - &pos->node != (list); \ - pos = node_to_entry(pos->node.next)) +/* return list entry which embeds this node */ +static struct udev_list_entry *list_node_to_entry(struct list_node *node) +{ + char *list; -#define list_for_each_entry_safe(pos, tmp, list) \ - for (pos = node_to_entry((list)->next), \ - tmp = node_to_entry(pos->node.next); \ - &pos->node != (list); \ - pos = tmp, tmp = node_to_entry(tmp->node.next)) + list = (char *)node; + list -= offsetof(struct udev_list_entry, node); + return (struct udev_list_entry *)list; +} + +/* insert entry into a list as the last element */ +static void list_entry_append(struct udev_list_entry *new, struct list_node *list) +{ + /* inserting before the list head make the node the last node in the list */ + list_node_insert_between(&new->node, list->prev, list); + new->list = list; +} + +/* insert entry into a list, before a given existing entry */ +static void list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry) +{ + list_node_insert_between(&new->node, entry->node.prev, &entry->node); + new->list = entry->list; +} -struct udev_list *list_insert_entry(struct udev *udev, struct list_node *list, - const char *name, const char *value, int sort) +void list_entry_remove(struct udev_list_entry *entry) { - struct udev_list *list_loop; - struct udev_list *list_new; - - /* avoid duplicate entries */ - list_for_each_entry(list_loop, list) { - if (strcmp(list_loop->name, name) == 0) { - dbg(udev, "'%s' is already in the list\n", name); - return list_loop; + list_node_remove(&entry->node); + entry->list = NULL; +} + +struct udev_list_entry *list_entry_add(struct udev *udev, struct list_node *list, + const char *name, const char *value, + int unique, int sort) +{ + struct udev_list_entry *entry_loop = NULL; + struct udev_list_entry *entry_new; + + if (unique) + udev_list_entry_foreach(entry_loop, list_get_entry(list)) { + if (strcmp(entry_loop->name, name) == 0) { + info(udev, "'%s' is already in the list\n", name); + if (value != NULL) { + free(entry_loop->value); + entry_loop->value = strdup(value); + if (entry_loop->value == NULL) + return NULL; + info(udev, "'%s' value replaced with '%s'\n", name, value); + } + return entry_loop; + } } - } - if (sort) { - list_for_each_entry(list_loop, list) { - if (strcmp(list_loop->name, name) > 0) + if (sort) + udev_list_entry_foreach(entry_loop, list_get_entry(list)) { + if (strcmp(entry_loop->name, name) > 0) break; } - } - list_new = malloc(sizeof(struct udev_list)); - if (list_new == NULL) + entry_new = malloc(sizeof(struct udev_list_entry)); + if (entry_new == NULL) return NULL; - memset(list_new, 0x00, sizeof(struct udev_list)); - list_new->udev = udev; - list_new->list = list; - list_new->name = strdup(name); - if (list_new->name == NULL) { - free(list_new); + memset(entry_new, 0x00, sizeof(struct udev_list_entry)); + entry_new->udev = udev; + entry_new->name = strdup(name); + if (entry_new->name == NULL) { + free(entry_new); return NULL; } if (value != NULL) { - list_new->value = strdup(value); - if (list_new->value == NULL) { - free(list_new); + entry_new->value = strdup(value); + if (entry_new->value == NULL) { + free(entry_new->name); + free(entry_new); return NULL; } } - dbg(udev, "adding '%s=%s'\n", list_new->name, list_new->value); - list_add_to_end(&list_new->node, &list_loop->node); - return list_new; + if (entry_loop != NULL) + list_entry_insert_before(entry_new, entry_loop); + else + list_entry_append(entry_new, list); + return entry_new; } -void list_move_entry_to_end(struct udev_list *list_entry, struct list_node *list) +void list_entry_move_to_end(struct udev_list_entry *list_entry) { - list_del(&list_entry->node); - list_add_to_end(&list_entry->node, list); + list_node_remove(&list_entry->node); + list_node_insert_between(&list_entry->node, list_entry->list->prev, list_entry->list); } void list_cleanup(struct udev *udev, struct list_node *list) { - struct udev_list *list_loop; - struct udev_list *list_tmp; - - list_for_each_entry_safe(list_loop, list_tmp, list) { - list_del(&list_loop->node); - free(list_loop->name); - free(list_loop->value); - free(list_loop); + struct udev_list_entry *entry_loop; + struct udev_list_entry *entry_tmp; + + list_entry_foreach_safe(entry_loop, entry_tmp, list_get_entry(list)) { + list_entry_remove(entry_loop); + free(entry_loop->name); + free(entry_loop->value); + free(entry_loop); } } -struct udev_list *list_get_entry(struct list_node *list) +struct udev_list_entry *list_get_entry(struct list_node *list) { - if (list_empty(list)) + if (list_is_empty(list)) return NULL; - return node_to_entry(list->next); + return list_node_to_entry(list->next); } -struct udev_list *udev_list_entry_get_next(struct udev_list *list_entry) +struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) { struct list_node *next; + if (list_entry == NULL) + return NULL; next = list_entry->node.next; - /* empty list or no more emtries */ + /* empty list or no more entries */ if (next == list_entry->list) return NULL; - return node_to_entry(next); + return list_node_to_entry(next); } -const char *udev_list_entry_get_name(struct udev_list *list_entry) +const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) { if (list_entry == NULL) return NULL; return list_entry->name; } -const char *udev_list_entry_get_value(struct udev_list *list_entry) +const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) { if (list_entry == NULL) return NULL; |