diff options
Diffstat (limited to 'libudev/libudev-list.c')
-rw-r--r-- | libudev/libudev-list.c | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/libudev/libudev-list.c b/libudev/libudev-list.c new file mode 100644 index 0000000000..182d75aa8a --- /dev/null +++ b/libudev/libudev-list.c @@ -0,0 +1,235 @@ +/* + * libudev - interface to udev device information + * + * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org> + * + * 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 <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +#include "libudev.h" +#include "libudev-private.h" + +struct udev_list_entry { + struct udev_list_node node; + struct udev *udev; + struct udev_list_node *list; + char *name; + char *value; + int flag; +}; + +/* list head point to itself if empty */ +void udev_list_init(struct udev_list_node *list) +{ + list->next = list; + list->prev = list; +} + +int udev_list_is_empty(struct udev_list_node *list) +{ + return list->next == list; +} + +static void udev_list_node_insert_between(struct udev_list_node *new, + struct udev_list_node *prev, + struct udev_list_node *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list) +{ + udev_list_node_insert_between(new, list->prev, list); +} + +void udev_list_node_remove(struct udev_list_node *entry) +{ + 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; +} + +/* 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; +} + +/* remove entry from a list */ +void udev_list_entry_remove(struct udev_list_entry *entry) +{ + udev_list_node_remove(&entry->node); + entry->list = NULL; +} + +/* 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) +{ + udev_list_node_insert_between(&new->node, entry->node.prev, &entry->node); + new->list = entry->list; +} + +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) + udev_list_entry_foreach(entry_loop, udev_list_get_entry(list)) { + if (strcmp(entry_loop->name, name) > 0) + break; + } + + entry_new = malloc(sizeof(struct udev_list_entry)); + if (entry_new == NULL) + return NULL; + 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) { + entry_new->value = strdup(value); + if (entry_new->value == NULL) { + free(entry_new->name); + free(entry_new); + return NULL; + } + } + 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 udev_list_entry_delete(struct udev_list_entry *entry) +{ + udev_list_node_remove(&entry->node); + free(entry->name); + free(entry->value); + free(entry); +} + +void udev_list_cleanup_entries(struct udev *udev, struct udev_list_node *list) +{ + struct udev_list_entry *entry_loop; + struct udev_list_entry *entry_tmp; + + udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(list)) + udev_list_entry_delete(entry_loop); +} + +struct udev_list_entry *udev_list_get_entry(struct udev_list_node *list) +{ + if (udev_list_is_empty(list)) + return NULL; + return list_node_to_entry(list->next); +} + +struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) +{ + struct udev_list_node *next; + + if (list_entry == NULL) + return NULL; + next = list_entry->node.next; + /* empty list or no more entries */ + if (next == list_entry->list) + return NULL; + return list_node_to_entry(next); +} + +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_entry *list_entry) +{ + if (list_entry == NULL) + return NULL; + return list_entry->value; +} + +int udev_list_entry_get_flag(struct udev_list_entry *list_entry) +{ + if (list_entry == NULL) + return -EINVAL; + return list_entry->flag; +} + +void udev_list_entry_set_flag(struct udev_list_entry *list_entry, int flag) +{ + if (list_entry == NULL) + return; + list_entry->flag = flag; +} |