X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev%2Flib%2Flibudev-list.c;h=0c13b6d9277ae064a138e71305aa40e448ea56d4;hp=553edf69f87ab3083ff0b3bf455769a9bd0e3804;hb=19d7e87cc0ef364fb13a18411cb165b2427b3529;hpb=e345e2670a8c17f5e1145cc554b7a7646e271032 diff --git a/udev/lib/libudev-list.c b/udev/lib/libudev-list.c index 553edf69f..0c13b6d92 100644 --- a/udev/lib/libudev-list.c +++ b/udev/lib/libudev-list.c @@ -3,18 +3,10 @@ * * Copyright (C) 2008 Kay Sievers * - * 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 - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. */ #include @@ -27,167 +19,217 @@ #include "libudev.h" #include "libudev-private.h" -struct udev_list { +struct udev_list_entry { + struct udev_list_node node; struct udev *udev; - struct list_node node; - struct list_node *list; + struct udev_list_node *list; char *name; char *value; + int flag; }; -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; -} - -void list_init(struct list_node *list) +/* list head point to itself if empty */ +void udev_list_init(struct udev_list_node *list) { list->next = list; list->prev = list; } -static int list_empty(struct list_node *list) +int udev_list_is_empty(struct udev_list_node *list) { return list->next == list; } -#if 0 -static void list_add(struct list_node *new, struct list_node *list) +static void udev_list_node_insert_between(struct udev_list_node *new, + struct udev_list_node *prev, + struct udev_list_node *next) { - struct list_node *next = list->next; - next->prev = new; new->next = next; - new->prev = list; - list->next = new; + new->prev = prev; + prev->next = new; } -#endif -static void list_add_to_end(struct list_node *new, struct list_node *list) +void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list) { - struct list_node *prev = list->prev; - - list->prev = new; - new->next = list; - new->prev = prev; - prev->next = new; + udev_list_node_insert_between(new, list->prev, list); } -static void list_del(struct list_node *entry) +void udev_list_node_remove(struct udev_list_node *entry) { - struct list_node *prev = entry->prev; - struct list_node *next = entry->next; + struct udev_list_node *prev = entry->prev; + struct udev_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 udev_list_node *node) +{ + char *list; + + 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 */ +void udev_list_entry_append(struct udev_list_entry *new, struct udev_list_node *list) +{ + /* inserting before the list head make the node the last node in the list */ + udev_list_node_insert_between(&new->node, list->prev, list); + new->list = 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)) +/* remove entry from a list */ +void udev_list_entry_remove(struct udev_list_entry *entry) +{ + udev_list_node_remove(&entry->node); + entry->list = NULL; +} -struct udev_list *list_insert_entry(struct udev *udev, struct list_node *list, - const char *name, const char *value, int sort) +/* insert entry into a list, before a given existing entry */ +void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry) { - struct udev_list *list_loop; - struct udev_list *list_new; + udev_list_node_insert_between(&new->node, entry->node.prev, &entry->node); + new->list = entry->list; +} - /* 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; +struct udev_list_entry *udev_list_entry_add(struct udev *udev, struct udev_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, udev_list_get_entry(list)) { + if (strcmp(entry_loop->name, name) == 0) { + dbg(udev, "'%s' is already in the list\n", name); + free(entry_loop->value); + if (value == NULL) { + entry_loop->value = NULL; + dbg(udev, "'%s' value unset\n", name); + return entry_loop; + } + entry_loop->value = strdup(value); + if (entry_loop->value == NULL) + return NULL; + dbg(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, udev_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) + udev_list_entry_insert_before(entry_new, entry_loop); + else + udev_list_entry_append(entry_new, list); + dbg(udev, "'%s=%s' added\n", entry_new->name, entry_new->value); + return entry_new; } -void list_move_entry_to_end(struct udev_list *list_entry, struct list_node *list) +void udev_list_entry_delete(struct udev_list_entry *entry) { - list_del(&list_entry->node); - list_add_to_end(&list_entry->node, list); + udev_list_node_remove(&entry->node); + free(entry->name); + free(entry->value); + free(entry); } -void list_cleanup(struct udev *udev, struct list_node *list) +void udev_list_cleanup_entries(struct udev *udev, struct udev_list_node *list) { - struct udev_list *list_loop; - struct udev_list *list_tmp; + struct udev_list_entry *entry_loop; + struct udev_list_entry *entry_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); - } + udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(list)) + udev_list_entry_delete(entry_loop); } -struct udev_list *list_get_entry(struct list_node *list) +struct udev_list_entry *udev_list_get_entry(struct udev_list_node *list) { - if (list_empty(list)) + if (udev_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; + struct udev_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) +struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) +{ + struct udev_list_entry *entry; + + udev_list_entry_foreach(entry, list_entry) { + if (strcmp(udev_list_entry_get_name(entry), name) == 0) { + dbg(entry->udev, "found '%s=%s'\n", entry->name, entry->value); + return entry; + } + } + return NULL; +} + +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; return list_entry->value; } + +extern int udev_list_entry_get_flag(struct udev_list_entry *list_entry) +{ + if (list_entry == NULL) + return -EINVAL; + return list_entry->flag; +} + +extern void udev_list_entry_set_flag(struct udev_list_entry *list_entry, int flag) +{ + if (list_entry == NULL) + return; + list_entry->flag = flag; +}