]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
e345e267 | 2 | |
b5efdb8a | 3 | #include "alloc-util.h" |
c0113082 | 4 | #include "hashmap.h" |
5ea78a39 | 5 | #include "libudev-list-internal.h" |
c0113082 YW |
6 | #include "list.h" |
7 | #include "sort-util.h" | |
e345e267 | 8 | |
ce1d6d7f KS |
9 | /** |
10 | * SECTION:libudev-list | |
11 | * @short_description: list operation | |
12 | * | |
13 | * Libudev list operations. | |
14 | */ | |
15 | ||
1e511322 KS |
16 | /** |
17 | * udev_list_entry: | |
18 | * | |
ce1d6d7f KS |
19 | * Opaque object representing one entry in a list. An entry contains |
20 | * contains a name, and optionally a value. | |
1e511322 | 21 | */ |
0de33a61 | 22 | struct udev_list_entry { |
912541b0 KS |
23 | struct udev_list *list; |
24 | char *name; | |
25 | char *value; | |
c0113082 YW |
26 | |
27 | LIST_FIELDS(struct udev_list_entry, entries); | |
e345e267 KS |
28 | }; |
29 | ||
dcf557f7 | 30 | struct udev_list { |
c0113082 YW |
31 | Hashmap *unique_entries; |
32 | LIST_HEAD(struct udev_list_entry, entries); | |
33 | bool unique:1; | |
34 | bool uptodate:1; | |
dcf557f7 YW |
35 | }; |
36 | ||
c0113082 YW |
37 | static struct udev_list_entry *udev_list_entry_free(struct udev_list_entry *entry) { |
38 | if (!entry) | |
39 | return NULL; | |
e345e267 | 40 | |
c0113082 | 41 | if (entry->list) { |
8e5ce387 | 42 | if (entry->list->unique && entry->name) |
c0113082 | 43 | hashmap_remove(entry->list->unique_entries, entry->name); |
8e5ce387 YW |
44 | |
45 | if (!entry->list->unique || entry->list->uptodate) | |
c0113082 YW |
46 | LIST_REMOVE(entries, entry->list->entries, entry); |
47 | } | |
e345e267 | 48 | |
c0113082 YW |
49 | free(entry->name); |
50 | free(entry->value); | |
0de33a61 | 51 | |
c0113082 | 52 | return mfree(entry); |
e345e267 KS |
53 | } |
54 | ||
c0113082 | 55 | DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_list_entry *, udev_list_entry_free); |
0de33a61 | 56 | |
dcf557f7 YW |
57 | struct udev_list *udev_list_new(bool unique) { |
58 | struct udev_list *list; | |
59 | ||
60 | list = new(struct udev_list, 1); | |
61 | if (!list) | |
62 | return NULL; | |
63 | ||
64 | *list = (struct udev_list) { | |
65 | .unique = unique, | |
66 | }; | |
67 | ||
dcf557f7 | 68 | return list; |
0de33a61 KS |
69 | } |
70 | ||
c0113082 YW |
71 | struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *_name, const char *_value) { |
72 | _cleanup_(udev_list_entry_freep) struct udev_list_entry *entry = NULL; | |
73 | _cleanup_free_ char *name = NULL, *value = NULL; | |
912541b0 | 74 | |
c0113082 | 75 | assert(list); |
ecf83c24 | 76 | assert(_name); |
869c9031 | 77 | |
c0113082 YW |
78 | name = strdup(_name); |
79 | if (!name) | |
80 | return NULL; | |
912541b0 | 81 | |
c0113082 YW |
82 | if (_value) { |
83 | value = strdup(_value); | |
84 | if (!value) | |
85 | return NULL; | |
912541b0 KS |
86 | } |
87 | ||
c0113082 | 88 | entry = new(struct udev_list_entry, 1); |
62d74c78 | 89 | if (!entry) |
912541b0 | 90 | return NULL; |
6b430fdb | 91 | |
c0113082 | 92 | *entry = (struct udev_list_entry) { |
c0113082 YW |
93 | .name = TAKE_PTR(name), |
94 | .value = TAKE_PTR(value), | |
95 | }; | |
912541b0 KS |
96 | |
97 | if (list->unique) { | |
c0113082 | 98 | udev_list_entry_free(hashmap_get(list->unique_entries, entry->name)); |
912541b0 | 99 | |
eaef130d | 100 | if (hashmap_ensure_put(&list->unique_entries, &string_hash_ops, entry->name, entry) < 0) |
c0113082 | 101 | return NULL; |
912541b0 | 102 | |
c0113082 | 103 | list->uptodate = false; |
62d74c78 | 104 | } else |
c0113082 | 105 | LIST_APPEND(entries, list->entries, entry); |
912541b0 | 106 | |
140716a5 YW |
107 | entry->list = list; |
108 | ||
c0113082 | 109 | return TAKE_PTR(entry); |
e345e267 KS |
110 | } |
111 | ||
5ea78a39 | 112 | void udev_list_cleanup(struct udev_list *list) { |
c0113082 YW |
113 | if (!list) |
114 | return; | |
115 | ||
116 | if (list->unique) { | |
c0113082 | 117 | list->uptodate = false; |
65c637ad | 118 | hashmap_clear_with_destructor(list->unique_entries, udev_list_entry_free); |
c0113082 | 119 | } else |
80a226b2 | 120 | LIST_FOREACH(entries, i, list->entries) |
c0113082 | 121 | udev_list_entry_free(i); |
be7f7f57 | 122 | } |
dcf557f7 YW |
123 | |
124 | struct udev_list *udev_list_free(struct udev_list *list) { | |
125 | if (!list) | |
126 | return NULL; | |
127 | ||
128 | udev_list_cleanup(list); | |
c0113082 | 129 | hashmap_free(list->unique_entries); |
dcf557f7 YW |
130 | |
131 | return mfree(list); | |
132 | } | |
be7f7f57 | 133 | |
c0113082 YW |
134 | static int udev_list_entry_compare_func(struct udev_list_entry * const *a, struct udev_list_entry * const *b) { |
135 | return strcmp((*a)->name, (*b)->name); | |
136 | } | |
137 | ||
5ea78a39 | 138 | struct udev_list_entry *udev_list_get_entry(struct udev_list *list) { |
c0113082 | 139 | if (!list) |
912541b0 | 140 | return NULL; |
c0113082 YW |
141 | |
142 | if (list->unique && !list->uptodate) { | |
143 | size_t n; | |
144 | ||
145 | LIST_HEAD_INIT(list->entries); | |
146 | ||
147 | n = hashmap_size(list->unique_entries); | |
148 | if (n == 0) | |
149 | ; | |
150 | else if (n == 1) | |
151 | LIST_PREPEND(entries, list->entries, hashmap_first(list->unique_entries)); | |
152 | else { | |
153 | _cleanup_free_ struct udev_list_entry **buf = NULL; | |
154 | struct udev_list_entry *entry, **p; | |
c0113082 YW |
155 | size_t j; |
156 | ||
157 | buf = new(struct udev_list_entry *, n); | |
158 | if (!buf) | |
159 | return NULL; | |
160 | ||
161 | p = buf; | |
90e74a66 | 162 | HASHMAP_FOREACH(entry, list->unique_entries) |
c0113082 YW |
163 | *p++ = entry; |
164 | ||
165 | typesafe_qsort(buf, n, udev_list_entry_compare_func); | |
166 | ||
167 | for (j = n; j > 0; j--) | |
168 | LIST_PREPEND(entries, list->entries, buf[j-1]); | |
169 | } | |
170 | ||
171 | list->uptodate = true; | |
172 | } | |
173 | ||
174 | return list->entries; | |
e345e267 KS |
175 | } |
176 | ||
1e511322 KS |
177 | /** |
178 | * udev_list_entry_get_next: | |
179 | * @list_entry: current entry | |
180 | * | |
21dbe43a KS |
181 | * Get the next entry from the list. |
182 | * | |
183 | * Returns: udev_list_entry, #NULL if no more entries are available. | |
1e511322 | 184 | */ |
5ea78a39 | 185 | _public_ struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) { |
f921b457 | 186 | if (!list_entry) |
912541b0 | 187 | return NULL; |
c0113082 | 188 | if (list_entry->list->unique && !list_entry->list->uptodate) |
912541b0 | 189 | return NULL; |
c0113082 | 190 | return list_entry->entries_next; |
e345e267 KS |
191 | } |
192 | ||
1e511322 KS |
193 | /** |
194 | * udev_list_entry_get_by_name: | |
195 | * @list_entry: current entry | |
196 | * @name: name string to match | |
197 | * | |
21dbe43a KS |
198 | * Lookup an entry in the list with a certain name. |
199 | * | |
200 | * Returns: udev_list_entry, #NULL if no matching entry is found. | |
1e511322 | 201 | */ |
5ea78a39 | 202 | _public_ struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) { |
f921b457 | 203 | if (!list_entry) |
912541b0 | 204 | return NULL; |
c0113082 | 205 | if (!list_entry->list->unique || !list_entry->list->uptodate) |
912541b0 | 206 | return NULL; |
c0113082 | 207 | return hashmap_get(list_entry->list->unique_entries, name); |
bc8184ed KS |
208 | } |
209 | ||
1e511322 KS |
210 | /** |
211 | * udev_list_entry_get_name: | |
212 | * @list_entry: current entry | |
213 | * | |
21dbe43a KS |
214 | * Get the name of a list entry. |
215 | * | |
1e511322 KS |
216 | * Returns: the name string of this entry. |
217 | */ | |
5ea78a39 | 218 | _public_ const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) { |
f921b457 | 219 | if (!list_entry) |
912541b0 KS |
220 | return NULL; |
221 | return list_entry->name; | |
e345e267 KS |
222 | } |
223 | ||
1e511322 KS |
224 | /** |
225 | * udev_list_entry_get_value: | |
226 | * @list_entry: current entry | |
227 | * | |
21dbe43a KS |
228 | * Get the value of list entry. |
229 | * | |
1e511322 KS |
230 | * Returns: the value string of this entry. |
231 | */ | |
5ea78a39 | 232 | _public_ const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) { |
f921b457 | 233 | if (!list_entry) |
912541b0 KS |
234 | return NULL; |
235 | return list_entry->value; | |
e345e267 | 236 | } |