]> git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-list.c
Implement circular double-linked list
[thirdparty/kmod.git] / libkmod / libkmod-list.c
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011 ProFUSION embedded systems
5 * Copyright (C) 2011 Lucas De Marchi <lucas.de.marchi@gmail.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation version 2.1.
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"
25 #include "libkmod-util.h"
26
27 static inline struct list_node *list_node_init(struct list_node *node)
28 {
29 node->next = node;
30 node->prev = node;
31
32 return node;
33 }
34
35 static inline struct list_node *list_node_next(struct list_node *node)
36 {
37 if (node == NULL)
38 return NULL;
39
40 return node->next;
41 }
42
43 static inline struct list_node *list_node_prev(struct list_node *node)
44 {
45 if (node == NULL)
46 return NULL;
47
48 return node->prev;
49 }
50
51 static inline void list_node_append(struct list_node *list,
52 struct list_node *node)
53 {
54 if (list == NULL) {
55 list_node_init(node);
56 return;
57 }
58
59 node->prev = list->prev;
60 list->prev->next = node;
61 list->prev = node;
62 node->next = list;
63 }
64
65 static inline struct list_node *list_node_remove(struct list_node *node)
66 {
67 if (node->prev == node || node->next == node)
68 return NULL;
69
70 node->prev->next = node->next;
71 node->next->prev = node->prev;
72
73 return node->prev;
74 }
75
76 struct kmod_list *kmod_list_append(struct kmod_list *list, void *data)
77 {
78 struct kmod_list *new;
79
80 new = malloc(sizeof(*new));
81 if (new == NULL)
82 return NULL;
83
84 new->data = data;
85 list_node_append(list ? &list->node : NULL, &new->node);
86
87 return list ? list : new;
88 }
89
90 struct kmod_list *kmod_list_prepend(struct kmod_list *list, void *data)
91 {
92 struct kmod_list *new;
93
94 new = malloc(sizeof(*new));
95 if (new == NULL)
96 return NULL;
97
98 new->data = data;
99 list_node_append(list ? &list->node : NULL, &new->node);
100
101 return new;
102 }
103
104 struct kmod_list *kmod_list_remove(struct kmod_list *list)
105 {
106 struct list_node *node;
107
108 if (list == NULL)
109 return NULL;
110
111 node = list_node_remove(&list->node);
112 free(list);
113
114 if (node == NULL)
115 return NULL;
116
117 return container_of(node, struct kmod_list, node);
118 }
119
120 struct kmod_list *kmod_list_remove_data(struct kmod_list *list,
121 const void *data)
122 {
123 struct kmod_list *itr;
124 struct list_node *node;
125
126 for (itr = list; itr != NULL; itr = kmod_list_next(list, itr)) {
127 if (itr->data == data)
128 break;
129 }
130
131 if (itr == NULL)
132 return list;
133
134 node = list_node_remove(&itr->node);
135 free(itr);
136
137 if (node == NULL)
138 return NULL;
139
140 return container_of(node, struct kmod_list, node);
141 }
142
143 KMOD_EXPORT struct kmod_list *kmod_list_next(struct kmod_list *list,
144 struct kmod_list *curr)
145 {
146 if (list == NULL || curr == NULL)
147 return NULL;
148
149 if (curr->node.next == &list->node)
150 return NULL;
151
152 return container_of(curr->node.next, struct kmod_list, node);
153 }