]> git.ipfire.org Git - thirdparty/kmod.git/blame - libkmod/libkmod-list.c
libkmod-module: Add helper for building the module info list
[thirdparty/kmod.git] / libkmod / libkmod-list.c
CommitLineData
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 25
6681951b
LDM
26/**
27 * SECTION:libkmod-list
28 * @short_description: general purpose list
29 */
30
6924e47a
LDM
31static 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 39static 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 47static 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
55static 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
69static 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
80static 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
94static 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
108static 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 128struct 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
142struct 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
160struct 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
178struct 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 192struct 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
206struct 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
222struct 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 */
249struct 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 276KMOD_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 301KMOD_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 */
326KMOD_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}