]> git.ipfire.org Git - thirdparty/kmod.git/blame - libkmod/libkmod-list.c
doc: add gtk-doc to generate documentation
[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
LDM
25
26static 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 34static 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 42static 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
50static 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
64static 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
75static 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
89static 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
103static 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 123struct 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
137struct 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
155struct 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
173struct 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 184struct 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
198struct 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
214struct 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 */
241struct 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 268KMOD_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 293KMOD_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 */
318KMOD_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}