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