]> git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-list.c
Rename kmod_loaded_get_list() to kmod_module_new_from_loaded()
[thirdparty/kmod.git] / libkmod / libkmod-list.c
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011 ProFUSION embedded systems
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
8 * License as published by the Free Software Foundation version 2.1.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <stdlib.h>
21
22 #include "libkmod.h"
23 #include "libkmod-private.h"
24
25 static inline struct list_node *list_node_init(struct list_node *node)
26 {
27 node->next = node;
28 node->prev = node;
29
30 return node;
31 }
32
33 static inline struct list_node *list_node_next(const struct list_node *node)
34 {
35 if (node == NULL)
36 return NULL;
37
38 return node->next;
39 }
40
41 static inline struct list_node *list_node_prev(const struct list_node *node)
42 {
43 if (node == NULL)
44 return NULL;
45
46 return node->prev;
47 }
48
49 static inline void list_node_append(struct list_node *list,
50 struct list_node *node)
51 {
52 if (list == NULL) {
53 list_node_init(node);
54 return;
55 }
56
57 node->prev = list->prev;
58 list->prev->next = node;
59 list->prev = node;
60 node->next = list;
61 }
62
63 static inline struct list_node *list_node_remove(struct list_node *node)
64 {
65 if (node->prev == node || node->next == node)
66 return NULL;
67
68 node->prev->next = node->next;
69 node->next->prev = node->prev;
70
71 return node->next;
72 }
73
74 static inline void list_node_insert_after(struct list_node *list,
75 struct list_node *node)
76 {
77 if (list == NULL) {
78 list_node_init(node);
79 return;
80 }
81
82 node->prev = list;
83 node->next = list->next;
84 list->next->prev = node;
85 list->next = node;
86 }
87
88 static inline void list_node_insert_before(struct list_node *list,
89 struct list_node *node)
90 {
91 if (list == NULL) {
92 list_node_init(node);
93 return;
94 }
95
96 node->next = list;
97 node->prev = list->prev;
98 list->prev->next = node;
99 list->prev = node;
100 }
101
102 static inline void list_node_append_list(struct list_node *list1,
103 struct list_node *list2)
104 {
105 struct list_node *list1_last;
106
107 if (list1 == NULL) {
108 list_node_init(list2);
109 return;
110 }
111
112 list1->prev->next = list2;
113 list2->prev->next = list1;
114
115 /* cache the last, because we will lose the pointer */
116 list1_last = list1->prev;
117
118 list1->prev = list2->prev;
119 list2->prev = list1_last;
120 }
121
122 struct kmod_list *kmod_list_append(struct kmod_list *list, const void *data)
123 {
124 struct kmod_list *new;
125
126 new = malloc(sizeof(*new));
127 if (new == NULL)
128 return NULL;
129
130 new->data = (void *)data;
131 list_node_append(list ? &list->node : NULL, &new->node);
132
133 return list ? list : new;
134 }
135
136 struct kmod_list *kmod_list_insert_after(struct kmod_list *list,
137 const void *data)
138 {
139 struct kmod_list *new;
140
141 if (list == NULL)
142 return kmod_list_append(list, data);
143
144 new = malloc(sizeof(*new));
145 if (new == NULL)
146 return NULL;
147
148 new->data = (void *)data;
149 list_node_insert_after(&list->node, &new->node);
150
151 return list;
152 }
153
154 struct kmod_list *kmod_list_insert_before(struct kmod_list *list,
155 const void *data)
156 {
157 struct kmod_list *new;
158
159 if (list == NULL)
160 return kmod_list_append(list, data);
161
162 new = malloc(sizeof(*new));
163 if (new == NULL)
164 return NULL;
165
166 new->data = (void *)data;
167 list_node_insert_before(&list->node, &new->node);
168
169 return new;
170 }
171
172 struct kmod_list *kmod_list_append_list(struct kmod_list *list1,
173 struct kmod_list *list2)
174 {
175 if (list1 == NULL)
176 return list2;
177
178 list_node_append_list(&list1->node, &list2->node);
179
180 return list1;
181 }
182
183 struct kmod_list *kmod_list_prepend(struct kmod_list *list, const void *data)
184 {
185 struct kmod_list *new;
186
187 new = malloc(sizeof(*new));
188 if (new == NULL)
189 return NULL;
190
191 new->data = (void *)data;
192 list_node_append(list ? &list->node : NULL, &new->node);
193
194 return new;
195 }
196
197 struct kmod_list *kmod_list_remove(struct kmod_list *list)
198 {
199 struct list_node *node;
200
201 if (list == NULL)
202 return NULL;
203
204 node = list_node_remove(&list->node);
205 free(list);
206
207 if (node == NULL)
208 return NULL;
209
210 return container_of(node, struct kmod_list, node);
211 }
212
213 struct kmod_list *kmod_list_remove_data(struct kmod_list *list,
214 const void *data)
215 {
216 struct kmod_list *itr;
217 struct list_node *node;
218
219 for (itr = list; itr != NULL; itr = kmod_list_next(list, itr)) {
220 if (itr->data == data)
221 break;
222 }
223
224 if (itr == NULL)
225 return list;
226
227 node = list_node_remove(&itr->node);
228 free(itr);
229
230 if (node == NULL)
231 return NULL;
232
233 return container_of(node, struct kmod_list, node);
234 }
235
236 /*
237 * n must be greater to or equal the number of elements (we don't check the
238 * condition)
239 */
240 struct kmod_list *kmod_list_remove_n_latest(struct kmod_list *list,
241 unsigned int n)
242 {
243 struct kmod_list *l;
244 unsigned int i;
245
246 /*
247 * Get last element, remove all appended elments and if list became
248 * empty, set return pointer to NULL
249 */
250 l = kmod_list_prev(list, list);
251 if (l == NULL)
252 l = list;
253
254 for (i = 0; i < n; i++)
255 l = kmod_list_remove(l);
256
257 /* If list became empty, save it*/
258 if (l == NULL)
259 list = NULL;
260
261 return list;
262 }
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 */
276 KMOD_EXPORT struct kmod_list *kmod_list_prev(const struct kmod_list *list,
277 const struct kmod_list *curr)
278 {
279 if (list == NULL || curr == NULL)
280 return NULL;
281
282 if (curr->node.prev == &list->node)
283 return NULL;
284
285 return container_of(curr->node.prev, struct kmod_list, node);
286 }
287
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 */
301 KMOD_EXPORT struct kmod_list *kmod_list_next(const struct kmod_list *list,
302 const struct kmod_list *curr)
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 }