chiark / gitweb /
0c13b6d9277ae064a138e71305aa40e448ea56d4
[elogind.git] / udev / lib / libudev-list.c
1 /*
2  * libudev - interface to udev device information
3  *
4  * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stddef.h>
15 #include <unistd.h>
16 #include <errno.h>
17 #include <string.h>
18
19 #include "libudev.h"
20 #include "libudev-private.h"
21
22 struct udev_list_entry {
23         struct udev_list_node node;
24         struct udev *udev;
25         struct udev_list_node *list;
26         char *name;
27         char *value;
28         int flag;
29 };
30
31 /* list head point to itself if empty */
32 void udev_list_init(struct udev_list_node *list)
33 {
34         list->next = list;
35         list->prev = list;
36 }
37
38 int udev_list_is_empty(struct udev_list_node *list)
39 {
40         return list->next == list;
41 }
42
43 static void udev_list_node_insert_between(struct udev_list_node *new,
44                                           struct udev_list_node *prev,
45                                           struct udev_list_node *next)
46 {
47         next->prev = new;
48         new->next = next;
49         new->prev = prev;
50         prev->next = new;
51 }
52
53 void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list)
54 {
55         udev_list_node_insert_between(new, list->prev, list);
56 }
57
58 void udev_list_node_remove(struct udev_list_node *entry)
59 {
60         struct udev_list_node *prev = entry->prev;
61         struct udev_list_node *next = entry->next;
62
63         next->prev = prev;
64         prev->next = next;
65
66         entry->prev = NULL;
67         entry->next = NULL;
68 }
69
70 /* return list entry which embeds this node */
71 static struct udev_list_entry *list_node_to_entry(struct udev_list_node *node)
72 {
73         char *list;
74
75         list = (char *)node;
76         list -= offsetof(struct udev_list_entry, node);
77         return (struct udev_list_entry *)list;
78 }
79
80 /* insert entry into a list as the last element  */
81 void udev_list_entry_append(struct udev_list_entry *new, struct udev_list_node *list)
82 {
83         /* inserting before the list head make the node the last node in the list */
84         udev_list_node_insert_between(&new->node, list->prev, list);
85         new->list = list;
86 }
87
88 /* remove entry from a list */
89 void udev_list_entry_remove(struct udev_list_entry *entry)
90 {
91         udev_list_node_remove(&entry->node);
92         entry->list = NULL;
93 }
94
95 /* insert entry into a list, before a given existing entry */
96 void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry)
97 {
98         udev_list_node_insert_between(&new->node, entry->node.prev, &entry->node);
99         new->list = entry->list;
100 }
101
102 struct udev_list_entry *udev_list_entry_add(struct udev *udev, struct udev_list_node *list,
103                                             const char *name, const char *value,
104                                             int unique, int sort)
105 {
106         struct udev_list_entry *entry_loop = NULL;
107         struct udev_list_entry *entry_new;
108
109         if (unique)
110                 udev_list_entry_foreach(entry_loop, udev_list_get_entry(list)) {
111                         if (strcmp(entry_loop->name, name) == 0) {
112                                 dbg(udev, "'%s' is already in the list\n", name);
113                                 free(entry_loop->value);
114                                 if (value == NULL) {
115                                         entry_loop->value = NULL;
116                                         dbg(udev, "'%s' value unset\n", name);
117                                         return entry_loop;
118                                 }
119                                 entry_loop->value = strdup(value);
120                                 if (entry_loop->value == NULL)
121                                         return NULL;
122                                 dbg(udev, "'%s' value replaced with '%s'\n", name, value);
123                                 return entry_loop;
124                         }
125                 }
126
127         if (sort)
128                 udev_list_entry_foreach(entry_loop, udev_list_get_entry(list)) {
129                         if (strcmp(entry_loop->name, name) > 0)
130                                 break;
131                 }
132
133         entry_new = malloc(sizeof(struct udev_list_entry));
134         if (entry_new == NULL)
135                 return NULL;
136         memset(entry_new, 0x00, sizeof(struct udev_list_entry));
137         entry_new->udev = udev;
138         entry_new->name = strdup(name);
139         if (entry_new->name == NULL) {
140                 free(entry_new);
141                 return NULL;
142         }
143         if (value != NULL) {
144                 entry_new->value = strdup(value);
145                 if (entry_new->value == NULL) {
146                         free(entry_new->name);
147                         free(entry_new);
148                         return NULL;
149                 }
150         }
151         if (entry_loop != NULL)
152                 udev_list_entry_insert_before(entry_new, entry_loop);
153         else
154                 udev_list_entry_append(entry_new, list);
155         dbg(udev, "'%s=%s' added\n", entry_new->name, entry_new->value);
156         return entry_new;
157 }
158
159 void udev_list_entry_delete(struct udev_list_entry *entry)
160 {
161         udev_list_node_remove(&entry->node);
162         free(entry->name);
163         free(entry->value);
164         free(entry);
165 }
166
167 void udev_list_cleanup_entries(struct udev *udev, struct udev_list_node *list)
168 {
169         struct udev_list_entry *entry_loop;
170         struct udev_list_entry *entry_tmp;
171
172         udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(list))
173                 udev_list_entry_delete(entry_loop);
174 }
175
176 struct udev_list_entry *udev_list_get_entry(struct udev_list_node *list)
177 {
178         if (udev_list_is_empty(list))
179                 return NULL;
180         return list_node_to_entry(list->next);
181 }
182
183 struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry)
184 {
185         struct udev_list_node *next;
186
187         if (list_entry == NULL)
188                 return NULL;
189         next = list_entry->node.next;
190         /* empty list or no more entries */
191         if (next == list_entry->list)
192                 return NULL;
193         return list_node_to_entry(next);
194 }
195
196 struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name)
197 {
198         struct udev_list_entry *entry;
199
200         udev_list_entry_foreach(entry, list_entry) {
201                 if (strcmp(udev_list_entry_get_name(entry), name) == 0) {
202                         dbg(entry->udev, "found '%s=%s'\n", entry->name, entry->value);
203                         return entry;
204                 }
205         }
206         return NULL;
207 }
208
209 const char *udev_list_entry_get_name(struct udev_list_entry *list_entry)
210 {
211         if (list_entry == NULL)
212                 return NULL;
213         return list_entry->name;
214 }
215
216 const char *udev_list_entry_get_value(struct udev_list_entry *list_entry)
217 {
218         if (list_entry == NULL)
219                 return NULL;
220         return list_entry->value;
221 }
222
223 extern int udev_list_entry_get_flag(struct udev_list_entry *list_entry)
224 {
225         if (list_entry == NULL)
226                 return -EINVAL;
227         return list_entry->flag;
228 }
229
230 extern void udev_list_entry_set_flag(struct udev_list_entry *list_entry, int flag)
231 {
232         if (list_entry == NULL)
233                 return;
234         list_entry->flag = flag;
235 }