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