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