blob: cf6df37e5c209e02ba0d961e4a28501da23429e5 [file] [log] [blame]
Lucas De Marchi6924e472011-11-22 05:38:28 -02001/*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011 ProFUSION embedded systems
Lucas De Marchi6924e472011-11-22 05:38:28 -02005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
Lucas De Marchicb451f32011-12-12 18:24:35 -02008 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
Lucas De Marchi6924e472011-11-22 05:38:28 -020010 *
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"
Lucas De Marchi6924e472011-11-22 05:38:28 -020025
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
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -020034static inline struct list_node *list_node_next(const struct list_node *node)
Lucas De Marchi6924e472011-11-22 05:38:28 -020035{
36 if (node == NULL)
37 return NULL;
38
39 return node->next;
40}
41
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -020042static inline struct list_node *list_node_prev(const struct list_node *node)
Lucas De Marchi6924e472011-11-22 05:38:28 -020043{
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
Lucas De Marchie16e27f2011-12-06 02:20:46 -020072 return node->next;
Lucas De Marchi6924e472011-11-22 05:38:28 -020073}
74
Lucas De Marchi86e87882011-12-05 23:41:14 -020075static 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
Lucas De Marchib91a1c62011-12-05 23:53:56 -020089static 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
Lucas De Marchi19650292011-12-06 00:47:06 -0200103static 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
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200123struct kmod_list *kmod_list_append(struct kmod_list *list, const void *data)
Lucas De Marchi6924e472011-11-22 05:38:28 -0200124{
125 struct kmod_list *new;
126
127 new = malloc(sizeof(*new));
128 if (new == NULL)
129 return NULL;
130
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200131 new->data = (void *)data;
Lucas De Marchi6924e472011-11-22 05:38:28 -0200132 list_node_append(list ? &list->node : NULL, &new->node);
133
134 return list ? list : new;
135}
136
Lucas De Marchic35347f2011-12-12 10:48:02 -0200137struct kmod_list *kmod_list_insert_after(struct kmod_list *list,
138 const void *data)
Lucas De Marchi86e87882011-12-05 23:41:14 -0200139{
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
Lucas De Marchic35347f2011-12-12 10:48:02 -0200155struct kmod_list *kmod_list_insert_before(struct kmod_list *list,
156 const void *data)
Lucas De Marchib91a1c62011-12-05 23:53:56 -0200157{
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
Lucas De Marchi19650292011-12-06 00:47:06 -0200173struct 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
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200184struct kmod_list *kmod_list_prepend(struct kmod_list *list, const void *data)
Lucas De Marchi6924e472011-11-22 05:38:28 -0200185{
186 struct kmod_list *new;
187
188 new = malloc(sizeof(*new));
189 if (new == NULL)
190 return NULL;
191
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200192 new->data = (void *)data;
Lucas De Marchi6924e472011-11-22 05:38:28 -0200193 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
Lucas De Marchi62be7992011-12-01 15:27:42 -0200237/*
238 * n must be greater to or equal the number of elements (we don't check the
Lucas De Marchi7e1b3ae2011-12-08 12:25:36 -0200239 * condition)
Lucas De Marchi62be7992011-12-01 15:27:42 -0200240 */
241struct kmod_list *kmod_list_remove_n_latest(struct kmod_list *list,
242 unsigned int n)
243{
Lucas De Marchieb4ae532011-12-27 02:46:12 -0200244 struct kmod_list *l = list;
Lucas De Marchi62be7992011-12-01 15:27:42 -0200245 unsigned int i;
246
Lucas De Marchieb4ae532011-12-27 02:46:12 -0200247 for (i = 0; i < n; i++) {
248 l = kmod_list_last(l);
Lucas De Marchi62be7992011-12-01 15:27:42 -0200249 l = kmod_list_remove(l);
Lucas De Marchieb4ae532011-12-27 02:46:12 -0200250 }
Lucas De Marchi62be7992011-12-01 15:27:42 -0200251
Lucas De Marchieb4ae532011-12-27 02:46:12 -0200252 return l;
Lucas De Marchi62be7992011-12-01 15:27:42 -0200253}
Lucas De Marchieb4ae532011-12-27 02:46:12 -0200254
Lucas De Marchi7e1b3ae2011-12-08 12:25:36 -0200255/**
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 */
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200268KMOD_EXPORT struct kmod_list *kmod_list_prev(const struct kmod_list *list,
Lucas De Marchic35347f2011-12-12 10:48:02 -0200269 const struct kmod_list *curr)
Lucas De Marchi79d77112011-12-01 14:47:03 -0200270{
271 if (list == NULL || curr == NULL)
272 return NULL;
273
Gustavo Sverzut Barbieri2a70a5d2011-12-16 22:27:02 -0200274 if (list == curr)
Lucas De Marchi79d77112011-12-01 14:47:03 -0200275 return NULL;
276
277 return container_of(curr->node.prev, struct kmod_list, node);
278}
279
Lucas De Marchi7e1b3ae2011-12-08 12:25:36 -0200280/**
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 */
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200293KMOD_EXPORT struct kmod_list *kmod_list_next(const struct kmod_list *list,
Lucas De Marchic35347f2011-12-12 10:48:02 -0200294 const struct kmod_list *curr)
Lucas De Marchi6924e472011-11-22 05:38:28 -0200295{
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}
Gustavo Sverzut Barbierid5ec60b2011-12-16 22:32:33 -0200304
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}