]> git.ipfire.org Git - thirdparty/kmod.git/blame - libkmod/libkmod-list.c
kmod_list: add helper function to merge two lists
[thirdparty/kmod.git] / libkmod / libkmod-list.c
CommitLineData
6924e47a
LDM
1/*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011 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
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"
6924e47a
LDM
24
25static 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
1ce08a56 33static inline struct list_node *list_node_next(const struct list_node *node)
6924e47a
LDM
34{
35 if (node == NULL)
36 return NULL;
37
38 return node->next;
39}
40
1ce08a56 41static inline struct list_node *list_node_prev(const struct list_node *node)
6924e47a
LDM
42{
43 if (node == NULL)
44 return NULL;
45
46 return node->prev;
47}
48
49static 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
63static 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->prev;
72}
73
86e87885
LDM
74static 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
b91a1c6d
LDM
88static 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
1965029c
LDM
102static 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
1ce08a56 122struct kmod_list *kmod_list_append(struct kmod_list *list, const void *data)
6924e47a
LDM
123{
124 struct kmod_list *new;
125
126 new = malloc(sizeof(*new));
127 if (new == NULL)
128 return NULL;
129
1ce08a56 130 new->data = (void *)data;
6924e47a
LDM
131 list_node_append(list ? &list->node : NULL, &new->node);
132
133 return list ? list : new;
134}
135
86e87885
LDM
136struct kmod_list *kmod_list_insert_after(struct kmod_list *list, const void *data)
137{
138 struct kmod_list *new;
139
140 if (list == NULL)
141 return kmod_list_append(list, data);
142
143 new = malloc(sizeof(*new));
144 if (new == NULL)
145 return NULL;
146
147 new->data = (void *)data;
148 list_node_insert_after(&list->node, &new->node);
149
150 return list;
151}
152
b91a1c6d
LDM
153struct kmod_list *kmod_list_insert_before(struct kmod_list *list, const void *data)
154{
155 struct kmod_list *new;
156
157 if (list == NULL)
158 return kmod_list_append(list, data);
159
160 new = malloc(sizeof(*new));
161 if (new == NULL)
162 return NULL;
163
164 new->data = (void *)data;
165 list_node_insert_before(&list->node, &new->node);
166
167 return new;
168}
169
1965029c
LDM
170struct kmod_list *kmod_list_append_list(struct kmod_list *list1,
171 struct kmod_list *list2)
172{
173 if (list1 == NULL)
174 return list2;
175
176 list_node_append_list(&list1->node, &list2->node);
177
178 return list1;
179}
180
1ce08a56 181struct kmod_list *kmod_list_prepend(struct kmod_list *list, const void *data)
6924e47a
LDM
182{
183 struct kmod_list *new;
184
185 new = malloc(sizeof(*new));
186 if (new == NULL)
187 return NULL;
188
1ce08a56 189 new->data = (void *)data;
6924e47a
LDM
190 list_node_append(list ? &list->node : NULL, &new->node);
191
192 return new;
193}
194
195struct kmod_list *kmod_list_remove(struct kmod_list *list)
196{
197 struct list_node *node;
198
199 if (list == NULL)
200 return NULL;
201
202 node = list_node_remove(&list->node);
203 free(list);
204
205 if (node == NULL)
206 return NULL;
207
208 return container_of(node, struct kmod_list, node);
209}
210
211struct kmod_list *kmod_list_remove_data(struct kmod_list *list,
212 const void *data)
213{
214 struct kmod_list *itr;
215 struct list_node *node;
216
217 for (itr = list; itr != NULL; itr = kmod_list_next(list, itr)) {
218 if (itr->data == data)
219 break;
220 }
221
222 if (itr == NULL)
223 return list;
224
225 node = list_node_remove(&itr->node);
226 free(itr);
227
228 if (node == NULL)
229 return NULL;
230
231 return container_of(node, struct kmod_list, node);
232}
233
62be7995
LDM
234/*
235 * n must be greater to or equal the number of elements (we don't check the
236 * condition
237 */
238struct kmod_list *kmod_list_remove_n_latest(struct kmod_list *list,
239 unsigned int n)
240{
241 struct kmod_list *l;
242 unsigned int i;
243
244 /*
245 * Get last element, remove all appended elments and if list became
246 * empty, set return pointer to NULL
247 */
248 l = kmod_list_prev(list, list);
249 if (l == NULL)
250 l = list;
251
252 for (i = 0; i < n; i++)
253 l = kmod_list_remove(l);
254
255 /* If list became empty, save it*/
256 if (l == NULL)
257 list = NULL;
258
259 return list;
260}
261
1ce08a56
GSB
262KMOD_EXPORT struct kmod_list *kmod_list_prev(const struct kmod_list *list,
263 const struct kmod_list *curr)
79d77111
LDM
264{
265 if (list == NULL || curr == NULL)
266 return NULL;
267
268 if (curr->node.prev == &list->node)
269 return NULL;
270
271 return container_of(curr->node.prev, struct kmod_list, node);
272}
273
1ce08a56
GSB
274KMOD_EXPORT struct kmod_list *kmod_list_next(const struct kmod_list *list,
275 const struct kmod_list *curr)
6924e47a
LDM
276{
277 if (list == NULL || curr == NULL)
278 return NULL;
279
280 if (curr->node.next == &list->node)
281 return NULL;
282
283 return container_of(curr->node.next, struct kmod_list, node);
284}