]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/libudev/libudev-list.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "alloc-util.h"
27 #include "libudev-private.h"
30 * SECTION:libudev-list
31 * @short_description: list operation
33 * Libudev list operations.
39 * Opaque object representing one entry in a list. An entry contains
40 * contains a name, and optionally a value.
42 struct udev_list_entry
{
43 struct udev_list_node node
;
44 struct udev_list
*list
;
50 /* the list's head points to itself if empty */
51 void udev_list_node_init(struct udev_list_node
*list
)
57 int udev_list_node_is_empty(struct udev_list_node
*list
)
59 return list
->next
== list
;
62 static void udev_list_node_insert_between(struct udev_list_node
*new,
63 struct udev_list_node
*prev
,
64 struct udev_list_node
*next
)
72 void udev_list_node_append(struct udev_list_node
*new, struct udev_list_node
*list
)
74 udev_list_node_insert_between(new, list
->prev
, list
);
77 void udev_list_node_remove(struct udev_list_node
*entry
)
79 struct udev_list_node
*prev
= entry
->prev
;
80 struct udev_list_node
*next
= entry
->next
;
89 /* return list entry which embeds this node */
90 static inline struct udev_list_entry
*list_node_to_entry(struct udev_list_node
*node
)
92 return container_of(node
, struct udev_list_entry
, node
);
95 void udev_list_init(struct udev
*udev
, struct udev_list
*list
, bool unique
)
97 memzero(list
, sizeof(struct udev_list
));
99 list
->unique
= unique
;
100 udev_list_node_init(&list
->node
);
103 /* insert entry into a list as the last element */
104 static void udev_list_entry_append(struct udev_list_entry
*new, struct udev_list
*list
)
106 /* inserting before the list head make the node the last node in the list */
107 udev_list_node_insert_between(&new->node
, list
->node
.prev
, &list
->node
);
111 /* insert entry into a list, before a given existing entry */
112 static void udev_list_entry_insert_before(struct udev_list_entry
*new, struct udev_list_entry
*entry
)
114 udev_list_node_insert_between(&new->node
, entry
->node
.prev
, &entry
->node
);
115 new->list
= entry
->list
;
118 /* binary search in sorted array */
119 static int list_search(struct udev_list
*list
, const char *name
)
121 unsigned int first
, last
;
124 last
= list
->entries_cur
;
125 while (first
< last
) {
129 i
= (first
+ last
)/2;
130 cmp
= strcmp(name
, list
->entries
[i
]->name
);
139 /* not found, return negative insertion-index+1 */
143 struct udev_list_entry
*udev_list_entry_add(struct udev_list
*list
, const char *name
, const char *value
)
145 struct udev_list_entry
*entry
;
149 /* lookup existing name or insertion-index */
150 i
= list_search(list
, name
);
152 entry
= list
->entries
[i
];
159 entry
->value
= strdup(value
);
160 if (entry
->value
== NULL
)
167 entry
= new0(struct udev_list_entry
, 1);
171 entry
->name
= strdup(name
);
172 if (entry
->name
== NULL
)
176 entry
->value
= strdup(value
);
177 if (entry
->value
== NULL
) {
184 /* allocate or enlarge sorted array if needed */
185 if (list
->entries_cur
>= list
->entries_max
) {
186 struct udev_list_entry
**entries
;
189 add
= list
->entries_max
;
192 entries
= realloc(list
->entries
, (list
->entries_max
+ add
) * sizeof(struct udev_list_entry
*));
193 if (entries
== NULL
) {
198 list
->entries
= entries
;
199 list
->entries_max
+= add
;
202 /* the negative i returned the insertion index */
205 /* insert into sorted list */
206 if ((unsigned int)i
< list
->entries_cur
)
207 udev_list_entry_insert_before(entry
, list
->entries
[i
]);
209 udev_list_entry_append(entry
, list
);
211 /* insert into sorted array */
212 memmove(&list
->entries
[i
+1], &list
->entries
[i
],
213 (list
->entries_cur
- i
) * sizeof(struct udev_list_entry
*));
214 list
->entries
[i
] = entry
;
217 udev_list_entry_append(entry
, list
);
223 void udev_list_entry_delete(struct udev_list_entry
*entry
)
225 if (entry
->list
->entries
!= NULL
) {
227 struct udev_list
*list
= entry
->list
;
229 /* remove entry from sorted array */
230 i
= list_search(list
, entry
->name
);
232 memmove(&list
->entries
[i
], &list
->entries
[i
+1],
233 ((list
->entries_cur
-1) - i
) * sizeof(struct udev_list_entry
*));
238 udev_list_node_remove(&entry
->node
);
244 void udev_list_cleanup(struct udev_list
*list
)
246 struct udev_list_entry
*entry_loop
;
247 struct udev_list_entry
*entry_tmp
;
249 list
->entries
= mfree(list
->entries
);
250 list
->entries_cur
= 0;
251 list
->entries_max
= 0;
252 udev_list_entry_foreach_safe(entry_loop
, entry_tmp
, udev_list_get_entry(list
))
253 udev_list_entry_delete(entry_loop
);
256 struct udev_list_entry
*udev_list_get_entry(struct udev_list
*list
)
258 if (udev_list_node_is_empty(&list
->node
))
260 return list_node_to_entry(list
->node
.next
);
264 * udev_list_entry_get_next:
265 * @list_entry: current entry
267 * Get the next entry from the list.
269 * Returns: udev_list_entry, #NULL if no more entries are available.
271 _public_
struct udev_list_entry
*udev_list_entry_get_next(struct udev_list_entry
*list_entry
)
273 struct udev_list_node
*next
;
275 if (list_entry
== NULL
)
277 next
= list_entry
->node
.next
;
278 /* empty list or no more entries */
279 if (next
== &list_entry
->list
->node
)
281 return list_node_to_entry(next
);
285 * udev_list_entry_get_by_name:
286 * @list_entry: current entry
287 * @name: name string to match
289 * Lookup an entry in the list with a certain name.
291 * Returns: udev_list_entry, #NULL if no matching entry is found.
293 _public_
struct udev_list_entry
*udev_list_entry_get_by_name(struct udev_list_entry
*list_entry
, const char *name
)
297 if (list_entry
== NULL
)
300 if (!list_entry
->list
->unique
)
303 i
= list_search(list_entry
->list
, name
);
306 return list_entry
->list
->entries
[i
];
310 * udev_list_entry_get_name:
311 * @list_entry: current entry
313 * Get the name of a list entry.
315 * Returns: the name string of this entry.
317 _public_
const char *udev_list_entry_get_name(struct udev_list_entry
*list_entry
)
319 if (list_entry
== NULL
)
321 return list_entry
->name
;
325 * udev_list_entry_get_value:
326 * @list_entry: current entry
328 * Get the value of list entry.
330 * Returns: the value string of this entry.
332 _public_
const char *udev_list_entry_get_value(struct udev_list_entry
*list_entry
)
334 if (list_entry
== NULL
)
336 return list_entry
->value
;
339 int udev_list_entry_get_num(struct udev_list_entry
*list_entry
)
341 if (list_entry
== NULL
)
343 return list_entry
->num
;
346 void udev_list_entry_set_num(struct udev_list_entry
*list_entry
, int num
)
348 if (list_entry
== NULL
)
350 list_entry
->num
= num
;