]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
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 YW |
41 | if (entry->list) { |
42 | if (entry->list->unique) | |
43 | hashmap_remove(entry->list->unique_entries, entry->name); | |
44 | else | |
45 | LIST_REMOVE(entries, entry->list->entries, entry); | |
46 | } | |
e345e267 | 47 | |
c0113082 YW |
48 | free(entry->name); |
49 | free(entry->value); | |
0de33a61 | 50 | |
c0113082 | 51 | return mfree(entry); |
e345e267 KS |
52 | } |
53 | ||
c0113082 | 54 | DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_list_entry *, udev_list_entry_free); |
0de33a61 | 55 | |
dcf557f7 YW |
56 | struct udev_list *udev_list_new(bool unique) { |
57 | struct udev_list *list; | |
58 | ||
59 | list = new(struct udev_list, 1); | |
60 | if (!list) | |
61 | return NULL; | |
62 | ||
63 | *list = (struct udev_list) { | |
64 | .unique = unique, | |
65 | }; | |
66 | ||
dcf557f7 | 67 | return list; |
0de33a61 KS |
68 | } |
69 | ||
c0113082 YW |
70 | struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *_name, const char *_value) { |
71 | _cleanup_(udev_list_entry_freep) struct udev_list_entry *entry = NULL; | |
72 | _cleanup_free_ char *name = NULL, *value = NULL; | |
73 | int r; | |
912541b0 | 74 | |
c0113082 | 75 | assert(list); |
869c9031 | 76 | |
c0113082 YW |
77 | name = strdup(_name); |
78 | if (!name) | |
79 | return NULL; | |
912541b0 | 80 | |
c0113082 YW |
81 | if (_value) { |
82 | value = strdup(_value); | |
83 | if (!value) | |
84 | return NULL; | |
912541b0 KS |
85 | } |
86 | ||
c0113082 | 87 | entry = new(struct udev_list_entry, 1); |
62d74c78 | 88 | if (!entry) |
912541b0 | 89 | return NULL; |
6b430fdb | 90 | |
c0113082 YW |
91 | *entry = (struct udev_list_entry) { |
92 | .list = list, | |
93 | .name = TAKE_PTR(name), | |
94 | .value = TAKE_PTR(value), | |
95 | }; | |
912541b0 KS |
96 | |
97 | if (list->unique) { | |
c0113082 YW |
98 | r = hashmap_ensure_allocated(&list->unique_entries, &string_hash_ops); |
99 | if (r < 0) | |
100 | return NULL; | |
912541b0 | 101 | |
c0113082 | 102 | udev_list_entry_free(hashmap_get(list->unique_entries, entry->name)); |
912541b0 | 103 | |
c0113082 YW |
104 | r = hashmap_put(list->unique_entries, entry->name, entry); |
105 | if (r < 0) | |
106 | return NULL; | |
912541b0 | 107 | |
c0113082 | 108 | list->uptodate = false; |
62d74c78 | 109 | } else |
c0113082 | 110 | LIST_APPEND(entries, list->entries, entry); |
912541b0 | 111 | |
c0113082 | 112 | return TAKE_PTR(entry); |
e345e267 KS |
113 | } |
114 | ||
5ea78a39 | 115 | void udev_list_cleanup(struct udev_list *list) { |
c0113082 | 116 | struct udev_list_entry *i, *n; |
912541b0 | 117 | |
c0113082 YW |
118 | if (!list) |
119 | return; | |
120 | ||
121 | if (list->unique) { | |
122 | hashmap_clear_with_destructor(list->unique_entries, udev_list_entry_free); | |
123 | list->uptodate = false; | |
124 | } else | |
125 | LIST_FOREACH_SAFE(entries, i, n, list->entries) | |
126 | udev_list_entry_free(i); | |
be7f7f57 | 127 | } |
dcf557f7 YW |
128 | |
129 | struct udev_list *udev_list_free(struct udev_list *list) { | |
130 | if (!list) | |
131 | return NULL; | |
132 | ||
133 | udev_list_cleanup(list); | |
c0113082 | 134 | hashmap_free(list->unique_entries); |
dcf557f7 YW |
135 | |
136 | return mfree(list); | |
137 | } | |
be7f7f57 | 138 | |
c0113082 YW |
139 | static int udev_list_entry_compare_func(struct udev_list_entry * const *a, struct udev_list_entry * const *b) { |
140 | return strcmp((*a)->name, (*b)->name); | |
141 | } | |
142 | ||
5ea78a39 | 143 | struct udev_list_entry *udev_list_get_entry(struct udev_list *list) { |
c0113082 | 144 | if (!list) |
912541b0 | 145 | return NULL; |
c0113082 YW |
146 | |
147 | if (list->unique && !list->uptodate) { | |
148 | size_t n; | |
149 | ||
150 | LIST_HEAD_INIT(list->entries); | |
151 | ||
152 | n = hashmap_size(list->unique_entries); | |
153 | if (n == 0) | |
154 | ; | |
155 | else if (n == 1) | |
156 | LIST_PREPEND(entries, list->entries, hashmap_first(list->unique_entries)); | |
157 | else { | |
158 | _cleanup_free_ struct udev_list_entry **buf = NULL; | |
159 | struct udev_list_entry *entry, **p; | |
160 | Iterator i; | |
161 | size_t j; | |
162 | ||
163 | buf = new(struct udev_list_entry *, n); | |
164 | if (!buf) | |
165 | return NULL; | |
166 | ||
167 | p = buf; | |
168 | HASHMAP_FOREACH(entry, list->unique_entries, i) | |
169 | *p++ = entry; | |
170 | ||
171 | typesafe_qsort(buf, n, udev_list_entry_compare_func); | |
172 | ||
173 | for (j = n; j > 0; j--) | |
174 | LIST_PREPEND(entries, list->entries, buf[j-1]); | |
175 | } | |
176 | ||
177 | list->uptodate = true; | |
178 | } | |
179 | ||
180 | return list->entries; | |
e345e267 KS |
181 | } |
182 | ||
1e511322 KS |
183 | /** |
184 | * udev_list_entry_get_next: | |
185 | * @list_entry: current entry | |
186 | * | |
21dbe43a KS |
187 | * Get the next entry from the list. |
188 | * | |
189 | * Returns: udev_list_entry, #NULL if no more entries are available. | |
1e511322 | 190 | */ |
5ea78a39 | 191 | _public_ struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) { |
f921b457 | 192 | if (!list_entry) |
912541b0 | 193 | return NULL; |
c0113082 | 194 | if (list_entry->list->unique && !list_entry->list->uptodate) |
912541b0 | 195 | return NULL; |
c0113082 | 196 | return list_entry->entries_next; |
e345e267 KS |
197 | } |
198 | ||
1e511322 KS |
199 | /** |
200 | * udev_list_entry_get_by_name: | |
201 | * @list_entry: current entry | |
202 | * @name: name string to match | |
203 | * | |
21dbe43a KS |
204 | * Lookup an entry in the list with a certain name. |
205 | * | |
206 | * Returns: udev_list_entry, #NULL if no matching entry is found. | |
1e511322 | 207 | */ |
5ea78a39 | 208 | _public_ struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) { |
f921b457 | 209 | if (!list_entry) |
912541b0 | 210 | return NULL; |
c0113082 | 211 | if (!list_entry->list->unique || !list_entry->list->uptodate) |
912541b0 | 212 | return NULL; |
c0113082 | 213 | return hashmap_get(list_entry->list->unique_entries, name); |
bc8184ed KS |
214 | } |
215 | ||
1e511322 KS |
216 | /** |
217 | * udev_list_entry_get_name: | |
218 | * @list_entry: current entry | |
219 | * | |
21dbe43a KS |
220 | * Get the name of a list entry. |
221 | * | |
1e511322 KS |
222 | * Returns: the name string of this entry. |
223 | */ | |
5ea78a39 | 224 | _public_ const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) { |
f921b457 | 225 | if (!list_entry) |
912541b0 KS |
226 | return NULL; |
227 | return list_entry->name; | |
e345e267 KS |
228 | } |
229 | ||
1e511322 KS |
230 | /** |
231 | * udev_list_entry_get_value: | |
232 | * @list_entry: current entry | |
233 | * | |
21dbe43a KS |
234 | * Get the value of list entry. |
235 | * | |
1e511322 KS |
236 | * Returns: the value string of this entry. |
237 | */ | |
5ea78a39 | 238 | _public_ const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) { |
f921b457 | 239 | if (!list_entry) |
912541b0 KS |
240 | return NULL; |
241 | return list_entry->value; | |
e345e267 | 242 | } |