]>
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
) {
144 struct udev_list_entry
*entry
;
148 /* lookup existing name or insertion-index */
149 i
= list_search(list
, name
);
151 entry
= list
->entries
[i
];
158 entry
->value
= strdup(value
);
166 entry
= new0(struct udev_list_entry
, 1);
170 entry
->name
= strdup(name
);
175 entry
->value
= strdup(value
);
183 /* allocate or enlarge sorted array if needed */
184 if (list
->entries_cur
>= list
->entries_max
) {
185 struct udev_list_entry
**entries
;
188 add
= list
->entries_max
;
191 entries
= reallocarray(list
->entries
, list
->entries_max
+ add
, sizeof(struct udev_list_entry
*));
197 list
->entries
= entries
;
198 list
->entries_max
+= add
;
201 /* the negative i returned the insertion index */
204 /* insert into sorted list */
205 if ((unsigned int)i
< list
->entries_cur
)
206 udev_list_entry_insert_before(entry
, list
->entries
[i
]);
208 udev_list_entry_append(entry
, list
);
210 /* insert into sorted array */
211 memmove(&list
->entries
[i
+1], &list
->entries
[i
],
212 (list
->entries_cur
- i
) * sizeof(struct udev_list_entry
*));
213 list
->entries
[i
] = entry
;
216 udev_list_entry_append(entry
, list
);
221 void udev_list_entry_delete(struct udev_list_entry
*entry
)
223 if (entry
->list
->entries
!= NULL
) {
225 struct udev_list
*list
= entry
->list
;
227 /* remove entry from sorted array */
228 i
= list_search(list
, entry
->name
);
230 memmove(&list
->entries
[i
], &list
->entries
[i
+1],
231 ((list
->entries_cur
-1) - i
) * sizeof(struct udev_list_entry
*));
236 udev_list_node_remove(&entry
->node
);
242 void udev_list_cleanup(struct udev_list
*list
)
244 struct udev_list_entry
*entry_loop
;
245 struct udev_list_entry
*entry_tmp
;
247 list
->entries
= mfree(list
->entries
);
248 list
->entries_cur
= 0;
249 list
->entries_max
= 0;
250 udev_list_entry_foreach_safe(entry_loop
, entry_tmp
, udev_list_get_entry(list
))
251 udev_list_entry_delete(entry_loop
);
254 struct udev_list_entry
*udev_list_get_entry(struct udev_list
*list
)
256 if (udev_list_node_is_empty(&list
->node
))
258 return list_node_to_entry(list
->node
.next
);
262 * udev_list_entry_get_next:
263 * @list_entry: current entry
265 * Get the next entry from the list.
267 * Returns: udev_list_entry, #NULL if no more entries are available.
269 _public_
struct udev_list_entry
*udev_list_entry_get_next(struct udev_list_entry
*list_entry
)
271 struct udev_list_node
*next
;
273 if (list_entry
== NULL
)
275 next
= list_entry
->node
.next
;
276 /* empty list or no more entries */
277 if (next
== &list_entry
->list
->node
)
279 return list_node_to_entry(next
);
283 * udev_list_entry_get_by_name:
284 * @list_entry: current entry
285 * @name: name string to match
287 * Lookup an entry in the list with a certain name.
289 * Returns: udev_list_entry, #NULL if no matching entry is found.
291 _public_
struct udev_list_entry
*udev_list_entry_get_by_name(struct udev_list_entry
*list_entry
, const char *name
)
295 if (list_entry
== NULL
)
298 if (!list_entry
->list
->unique
)
301 i
= list_search(list_entry
->list
, name
);
304 return list_entry
->list
->entries
[i
];
308 * udev_list_entry_get_name:
309 * @list_entry: current entry
311 * Get the name of a list entry.
313 * Returns: the name string of this entry.
315 _public_
const char *udev_list_entry_get_name(struct udev_list_entry
*list_entry
)
317 if (list_entry
== NULL
)
319 return list_entry
->name
;
323 * udev_list_entry_get_value:
324 * @list_entry: current entry
326 * Get the value of list entry.
328 * Returns: the value string of this entry.
330 _public_
const char *udev_list_entry_get_value(struct udev_list_entry
*list_entry
)
332 if (list_entry
== NULL
)
334 return list_entry
->value
;
337 int udev_list_entry_get_num(struct udev_list_entry
*list_entry
)
339 if (list_entry
== NULL
)
341 return list_entry
->num
;
344 void udev_list_entry_set_num(struct udev_list_entry
*list_entry
, int num
)
346 if (list_entry
== NULL
)
348 list_entry
->num
= num
;