]>
Commit | Line | Data |
---|---|---|
6924e47a LDM |
1 | /* |
2 | * libkmod - interface to kernel module operations | |
3 | * | |
e6b0e49b | 4 | * Copyright (C) 2011-2013 ProFUSION embedded systems |
6924e47a LDM |
5 | * |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
cb451f35 LDM |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2.1 of the License, or (at your option) any later version. | |
6924e47a LDM |
10 | * |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
19 | */ | |
20 | ||
21 | #include <stdlib.h> | |
22 | ||
23 | #include "libkmod.h" | |
24 | #include "libkmod-private.h" | |
6924e47a | 25 | |
6681951b LDM |
26 | /** |
27 | * SECTION:libkmod-list | |
28 | * @short_description: general purpose list | |
29 | */ | |
30 | ||
6924e47a LDM |
31 | static inline struct list_node *list_node_init(struct list_node *node) |
32 | { | |
33 | node->next = node; | |
34 | node->prev = node; | |
35 | ||
36 | return node; | |
37 | } | |
38 | ||
1ce08a56 | 39 | static inline struct list_node *list_node_next(const struct list_node *node) |
6924e47a LDM |
40 | { |
41 | if (node == NULL) | |
42 | return NULL; | |
43 | ||
44 | return node->next; | |
45 | } | |
46 | ||
1ce08a56 | 47 | static inline struct list_node *list_node_prev(const struct list_node *node) |
6924e47a LDM |
48 | { |
49 | if (node == NULL) | |
50 | return NULL; | |
51 | ||
52 | return node->prev; | |
53 | } | |
54 | ||
55 | static inline void list_node_append(struct list_node *list, | |
56 | struct list_node *node) | |
57 | { | |
58 | if (list == NULL) { | |
59 | list_node_init(node); | |
60 | return; | |
61 | } | |
62 | ||
63 | node->prev = list->prev; | |
64 | list->prev->next = node; | |
65 | list->prev = node; | |
66 | node->next = list; | |
67 | } | |
68 | ||
69 | static inline struct list_node *list_node_remove(struct list_node *node) | |
70 | { | |
71 | if (node->prev == node || node->next == node) | |
72 | return NULL; | |
73 | ||
74 | node->prev->next = node->next; | |
75 | node->next->prev = node->prev; | |
76 | ||
e16e27f4 | 77 | return node->next; |
6924e47a LDM |
78 | } |
79 | ||
86e87885 LDM |
80 | static inline void list_node_insert_after(struct list_node *list, |
81 | struct list_node *node) | |
82 | { | |
83 | if (list == NULL) { | |
84 | list_node_init(node); | |
85 | return; | |
86 | } | |
87 | ||
88 | node->prev = list; | |
89 | node->next = list->next; | |
90 | list->next->prev = node; | |
91 | list->next = node; | |
92 | } | |
93 | ||
b91a1c6d LDM |
94 | static inline void list_node_insert_before(struct list_node *list, |
95 | struct list_node *node) | |
96 | { | |
97 | if (list == NULL) { | |
98 | list_node_init(node); | |
99 | return; | |
100 | } | |
101 | ||
102 | node->next = list; | |
103 | node->prev = list->prev; | |
104 | list->prev->next = node; | |
105 | list->prev = node; | |
106 | } | |
107 | ||
1965029c LDM |
108 | static inline void list_node_append_list(struct list_node *list1, |
109 | struct list_node *list2) | |
110 | { | |
111 | struct list_node *list1_last; | |
112 | ||
113 | if (list1 == NULL) { | |
114 | list_node_init(list2); | |
115 | return; | |
116 | } | |
117 | ||
118 | list1->prev->next = list2; | |
119 | list2->prev->next = list1; | |
120 | ||
121 | /* cache the last, because we will lose the pointer */ | |
122 | list1_last = list1->prev; | |
123 | ||
124 | list1->prev = list2->prev; | |
125 | list2->prev = list1_last; | |
126 | } | |
127 | ||
1ce08a56 | 128 | struct kmod_list *kmod_list_append(struct kmod_list *list, const void *data) |
6924e47a LDM |
129 | { |
130 | struct kmod_list *new; | |
131 | ||
132 | new = malloc(sizeof(*new)); | |
133 | if (new == NULL) | |
134 | return NULL; | |
135 | ||
1ce08a56 | 136 | new->data = (void *)data; |
6924e47a LDM |
137 | list_node_append(list ? &list->node : NULL, &new->node); |
138 | ||
139 | return list ? list : new; | |
140 | } | |
141 | ||
c35347f1 LDM |
142 | struct kmod_list *kmod_list_insert_after(struct kmod_list *list, |
143 | const void *data) | |
86e87885 LDM |
144 | { |
145 | struct kmod_list *new; | |
146 | ||
147 | if (list == NULL) | |
148 | return kmod_list_append(list, data); | |
149 | ||
150 | new = malloc(sizeof(*new)); | |
151 | if (new == NULL) | |
152 | return NULL; | |
153 | ||
154 | new->data = (void *)data; | |
155 | list_node_insert_after(&list->node, &new->node); | |
156 | ||
157 | return list; | |
158 | } | |
159 | ||
c35347f1 LDM |
160 | struct kmod_list *kmod_list_insert_before(struct kmod_list *list, |
161 | const void *data) | |
b91a1c6d LDM |
162 | { |
163 | struct kmod_list *new; | |
164 | ||
165 | if (list == NULL) | |
166 | return kmod_list_append(list, data); | |
167 | ||
168 | new = malloc(sizeof(*new)); | |
169 | if (new == NULL) | |
170 | return NULL; | |
171 | ||
172 | new->data = (void *)data; | |
173 | list_node_insert_before(&list->node, &new->node); | |
174 | ||
175 | return new; | |
176 | } | |
177 | ||
1965029c LDM |
178 | struct kmod_list *kmod_list_append_list(struct kmod_list *list1, |
179 | struct kmod_list *list2) | |
180 | { | |
181 | if (list1 == NULL) | |
182 | return list2; | |
183 | ||
434f32ca LDM |
184 | if (list2 == NULL) |
185 | return list1; | |
186 | ||
1965029c LDM |
187 | list_node_append_list(&list1->node, &list2->node); |
188 | ||
189 | return list1; | |
190 | } | |
191 | ||
1ce08a56 | 192 | struct kmod_list *kmod_list_prepend(struct kmod_list *list, const void *data) |
6924e47a LDM |
193 | { |
194 | struct kmod_list *new; | |
195 | ||
196 | new = malloc(sizeof(*new)); | |
197 | if (new == NULL) | |
198 | return NULL; | |
199 | ||
1ce08a56 | 200 | new->data = (void *)data; |
6924e47a LDM |
201 | list_node_append(list ? &list->node : NULL, &new->node); |
202 | ||
203 | return new; | |
204 | } | |
205 | ||
206 | struct kmod_list *kmod_list_remove(struct kmod_list *list) | |
207 | { | |
208 | struct list_node *node; | |
209 | ||
210 | if (list == NULL) | |
211 | return NULL; | |
212 | ||
213 | node = list_node_remove(&list->node); | |
214 | free(list); | |
215 | ||
216 | if (node == NULL) | |
217 | return NULL; | |
218 | ||
219 | return container_of(node, struct kmod_list, node); | |
220 | } | |
221 | ||
222 | struct kmod_list *kmod_list_remove_data(struct kmod_list *list, | |
223 | const void *data) | |
224 | { | |
225 | struct kmod_list *itr; | |
226 | struct list_node *node; | |
227 | ||
228 | for (itr = list; itr != NULL; itr = kmod_list_next(list, itr)) { | |
229 | if (itr->data == data) | |
230 | break; | |
231 | } | |
232 | ||
233 | if (itr == NULL) | |
234 | return list; | |
235 | ||
236 | node = list_node_remove(&itr->node); | |
237 | free(itr); | |
238 | ||
239 | if (node == NULL) | |
240 | return NULL; | |
241 | ||
242 | return container_of(node, struct kmod_list, node); | |
243 | } | |
244 | ||
62be7995 LDM |
245 | /* |
246 | * n must be greater to or equal the number of elements (we don't check the | |
7e1b3ae2 | 247 | * condition) |
62be7995 LDM |
248 | */ |
249 | struct kmod_list *kmod_list_remove_n_latest(struct kmod_list *list, | |
250 | unsigned int n) | |
251 | { | |
eb4ae531 | 252 | struct kmod_list *l = list; |
62be7995 LDM |
253 | unsigned int i; |
254 | ||
eb4ae531 LDM |
255 | for (i = 0; i < n; i++) { |
256 | l = kmod_list_last(l); | |
62be7995 | 257 | l = kmod_list_remove(l); |
eb4ae531 | 258 | } |
62be7995 | 259 | |
eb4ae531 | 260 | return l; |
62be7995 | 261 | } |
eb4ae531 | 262 | |
7e1b3ae2 LDM |
263 | /** |
264 | * kmod_list_prev: | |
265 | * @list: the head of the list | |
266 | * @curr: the current node in the list | |
267 | * | |
268 | * Get the previous node in @list relative to @curr as if @list was not a | |
269 | * circular list. I.e.: the previous of the head is NULL. It can be used to | |
270 | * iterate a list by checking for NULL return to know when all elements were | |
271 | * iterated. | |
272 | * | |
273 | * Returns: node previous to @curr or NULL if either this node is the head of | |
274 | * the list or the list is empty. | |
275 | */ | |
1ce08a56 | 276 | KMOD_EXPORT struct kmod_list *kmod_list_prev(const struct kmod_list *list, |
c35347f1 | 277 | const struct kmod_list *curr) |
79d77111 LDM |
278 | { |
279 | if (list == NULL || curr == NULL) | |
280 | return NULL; | |
281 | ||
2a70a5d4 | 282 | if (list == curr) |
79d77111 LDM |
283 | return NULL; |
284 | ||
285 | return container_of(curr->node.prev, struct kmod_list, node); | |
286 | } | |
287 | ||
7e1b3ae2 LDM |
288 | /** |
289 | * kmod_list_next: | |
290 | * @list: the head of the list | |
291 | * @curr: the current node in the list | |
292 | * | |
293 | * Get the next node in @list relative to @curr as if @list was not a circular | |
294 | * list. I.e. calling this function in the last node of the list returns | |
295 | * NULL.. It can be used to iterate a list by checking for NULL return to know | |
296 | * when all elements were iterated. | |
297 | * | |
298 | * Returns: node next to @curr or NULL if either this node is the last of or | |
299 | * list is empty. | |
300 | */ | |
1ce08a56 | 301 | KMOD_EXPORT struct kmod_list *kmod_list_next(const struct kmod_list *list, |
c35347f1 | 302 | const struct kmod_list *curr) |
6924e47a LDM |
303 | { |
304 | if (list == NULL || curr == NULL) | |
305 | return NULL; | |
306 | ||
307 | if (curr->node.next == &list->node) | |
308 | return NULL; | |
309 | ||
310 | return container_of(curr->node.next, struct kmod_list, node); | |
311 | } | |
d5ec60bc GSB |
312 | |
313 | /** | |
314 | * kmod_list_last: | |
315 | * @list: the head of the list | |
316 | * | |
317 | * Get the last element of the @list. As @list is a circular list, | |
318 | * this is a cheap operation O(1) with the last element being the | |
319 | * previous element. | |
320 | * | |
321 | * If the list has a single element it will return the list itself (as | |
322 | * expected, and this is what differentiates from kmod_list_prev()). | |
323 | * | |
324 | * Returns: last node at @list or NULL if the list is empty. | |
325 | */ | |
326 | KMOD_EXPORT struct kmod_list *kmod_list_last(const struct kmod_list *list) | |
327 | { | |
328 | if (list == NULL) | |
329 | return NULL; | |
330 | return container_of(list->node.prev, struct kmod_list, node); | |
331 | } |