]>
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); |
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 | 91 | *entry = (struct udev_list_entry) { |
c0113082 YW |
92 | .name = TAKE_PTR(name), |
93 | .value = TAKE_PTR(value), | |
94 | }; | |
912541b0 KS |
95 | |
96 | if (list->unique) { | |
c0113082 | 97 | udev_list_entry_free(hashmap_get(list->unique_entries, entry->name)); |
912541b0 | 98 | |
eaef130d | 99 | if (hashmap_ensure_put(&list->unique_entries, &string_hash_ops, entry->name, entry) < 0) |
c0113082 | 100 | return NULL; |
912541b0 | 101 | |
c0113082 | 102 | list->uptodate = false; |
62d74c78 | 103 | } else |
c0113082 | 104 | LIST_APPEND(entries, list->entries, entry); |
912541b0 | 105 | |
140716a5 YW |
106 | entry->list = list; |
107 | ||
c0113082 | 108 | return TAKE_PTR(entry); |
e345e267 KS |
109 | } |
110 | ||
5ea78a39 | 111 | void udev_list_cleanup(struct udev_list *list) { |
c0113082 | 112 | struct udev_list_entry *i, *n; |
912541b0 | 113 | |
c0113082 YW |
114 | if (!list) |
115 | return; | |
116 | ||
117 | if (list->unique) { | |
c0113082 | 118 | list->uptodate = false; |
65c637ad | 119 | hashmap_clear_with_destructor(list->unique_entries, udev_list_entry_free); |
c0113082 YW |
120 | } else |
121 | LIST_FOREACH_SAFE(entries, i, n, list->entries) | |
122 | udev_list_entry_free(i); | |
be7f7f57 | 123 | } |
dcf557f7 YW |
124 | |
125 | struct udev_list *udev_list_free(struct udev_list *list) { | |
126 | if (!list) | |
127 | return NULL; | |
128 | ||
129 | udev_list_cleanup(list); | |
c0113082 | 130 | hashmap_free(list->unique_entries); |
dcf557f7 YW |
131 | |
132 | return mfree(list); | |
133 | } | |
be7f7f57 | 134 | |
c0113082 YW |
135 | static int udev_list_entry_compare_func(struct udev_list_entry * const *a, struct udev_list_entry * const *b) { |
136 | return strcmp((*a)->name, (*b)->name); | |
137 | } | |
138 | ||
5ea78a39 | 139 | struct udev_list_entry *udev_list_get_entry(struct udev_list *list) { |
c0113082 | 140 | if (!list) |
912541b0 | 141 | return NULL; |
c0113082 YW |
142 | |
143 | if (list->unique && !list->uptodate) { | |
144 | size_t n; | |
145 | ||
146 | LIST_HEAD_INIT(list->entries); | |
147 | ||
148 | n = hashmap_size(list->unique_entries); | |
149 | if (n == 0) | |
150 | ; | |
151 | else if (n == 1) | |
152 | LIST_PREPEND(entries, list->entries, hashmap_first(list->unique_entries)); | |
153 | else { | |
154 | _cleanup_free_ struct udev_list_entry **buf = NULL; | |
155 | struct udev_list_entry *entry, **p; | |
c0113082 YW |
156 | size_t j; |
157 | ||
158 | buf = new(struct udev_list_entry *, n); | |
159 | if (!buf) | |
160 | return NULL; | |
161 | ||
162 | p = buf; | |
90e74a66 | 163 | HASHMAP_FOREACH(entry, list->unique_entries) |
c0113082 YW |
164 | *p++ = entry; |
165 | ||
166 | typesafe_qsort(buf, n, udev_list_entry_compare_func); | |
167 | ||
168 | for (j = n; j > 0; j--) | |
169 | LIST_PREPEND(entries, list->entries, buf[j-1]); | |
170 | } | |
171 | ||
172 | list->uptodate = true; | |
173 | } | |
174 | ||
175 | return list->entries; | |
e345e267 KS |
176 | } |
177 | ||
1e511322 KS |
178 | /** |
179 | * udev_list_entry_get_next: | |
180 | * @list_entry: current entry | |
181 | * | |
21dbe43a KS |
182 | * Get the next entry from the list. |
183 | * | |
184 | * Returns: udev_list_entry, #NULL if no more entries are available. | |
1e511322 | 185 | */ |
5ea78a39 | 186 | _public_ struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) { |
f921b457 | 187 | if (!list_entry) |
912541b0 | 188 | return NULL; |
c0113082 | 189 | if (list_entry->list->unique && !list_entry->list->uptodate) |
912541b0 | 190 | return NULL; |
c0113082 | 191 | return list_entry->entries_next; |
e345e267 KS |
192 | } |
193 | ||
1e511322 KS |
194 | /** |
195 | * udev_list_entry_get_by_name: | |
196 | * @list_entry: current entry | |
197 | * @name: name string to match | |
198 | * | |
21dbe43a KS |
199 | * Lookup an entry in the list with a certain name. |
200 | * | |
201 | * Returns: udev_list_entry, #NULL if no matching entry is found. | |
1e511322 | 202 | */ |
5ea78a39 | 203 | _public_ struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) { |
f921b457 | 204 | if (!list_entry) |
912541b0 | 205 | return NULL; |
c0113082 | 206 | if (!list_entry->list->unique || !list_entry->list->uptodate) |
912541b0 | 207 | return NULL; |
c0113082 | 208 | return hashmap_get(list_entry->list->unique_entries, name); |
bc8184ed KS |
209 | } |
210 | ||
1e511322 KS |
211 | /** |
212 | * udev_list_entry_get_name: | |
213 | * @list_entry: current entry | |
214 | * | |
21dbe43a KS |
215 | * Get the name of a list entry. |
216 | * | |
1e511322 KS |
217 | * Returns: the name string of this entry. |
218 | */ | |
5ea78a39 | 219 | _public_ const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) { |
f921b457 | 220 | if (!list_entry) |
912541b0 KS |
221 | return NULL; |
222 | return list_entry->name; | |
e345e267 KS |
223 | } |
224 | ||
1e511322 KS |
225 | /** |
226 | * udev_list_entry_get_value: | |
227 | * @list_entry: current entry | |
228 | * | |
21dbe43a KS |
229 | * Get the value of list entry. |
230 | * | |
1e511322 KS |
231 | * Returns: the value string of this entry. |
232 | */ | |
5ea78a39 | 233 | _public_ const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) { |
f921b457 | 234 | if (!list_entry) |
912541b0 KS |
235 | return NULL; |
236 | return list_entry->value; | |
e345e267 | 237 | } |