]>
Commit | Line | Data |
---|---|---|
1 | // SPDX-License-Identifier: LGPL-2.1-or-later | |
2 | /* | |
3 | * Copyright (C) 2011-2013 ProFUSION embedded systems | |
4 | */ | |
5 | ||
6 | #include <stdlib.h> | |
7 | ||
8 | #include "libkmod.h" | |
9 | #include "libkmod-internal.h" | |
10 | ||
11 | static inline struct list_node *list_node_init(struct list_node *node) | |
12 | { | |
13 | node->next = node; | |
14 | node->prev = node; | |
15 | ||
16 | return node; | |
17 | } | |
18 | ||
19 | static inline void list_node_append(struct list_node *list, struct list_node *node) | |
20 | { | |
21 | if (list == NULL) { | |
22 | list_node_init(node); | |
23 | return; | |
24 | } | |
25 | ||
26 | node->prev = list->prev; | |
27 | list->prev->next = node; | |
28 | list->prev = node; | |
29 | node->next = list; | |
30 | } | |
31 | ||
32 | static inline struct list_node *list_node_remove(struct list_node *node) | |
33 | { | |
34 | if (node->prev == node || node->next == node) | |
35 | return NULL; | |
36 | ||
37 | node->prev->next = node->next; | |
38 | node->next->prev = node->prev; | |
39 | ||
40 | return node->next; | |
41 | } | |
42 | ||
43 | static inline void list_node_insert_after(struct list_node *list, struct list_node *node) | |
44 | { | |
45 | if (list == NULL) { | |
46 | list_node_init(node); | |
47 | return; | |
48 | } | |
49 | ||
50 | node->prev = list; | |
51 | node->next = list->next; | |
52 | list->next->prev = node; | |
53 | list->next = node; | |
54 | } | |
55 | ||
56 | static inline void list_node_insert_before(struct list_node *list, struct list_node *node) | |
57 | { | |
58 | if (list == NULL) { | |
59 | list_node_init(node); | |
60 | return; | |
61 | } | |
62 | ||
63 | node->next = list; | |
64 | node->prev = list->prev; | |
65 | list->prev->next = node; | |
66 | list->prev = node; | |
67 | } | |
68 | ||
69 | static inline void list_node_append_list(struct list_node *list1, struct list_node *list2) | |
70 | { | |
71 | struct list_node *list1_last; | |
72 | ||
73 | if (list1 == NULL) { | |
74 | list_node_init(list2); | |
75 | return; | |
76 | } | |
77 | ||
78 | list1->prev->next = list2; | |
79 | list2->prev->next = list1; | |
80 | ||
81 | /* cache the last, because we will lose the pointer */ | |
82 | list1_last = list1->prev; | |
83 | ||
84 | list1->prev = list2->prev; | |
85 | list2->prev = list1_last; | |
86 | } | |
87 | ||
88 | struct kmod_list *kmod_list_append(struct kmod_list *list, const void *data) | |
89 | { | |
90 | struct kmod_list *new; | |
91 | ||
92 | new = malloc(sizeof(*new)); | |
93 | if (new == NULL) | |
94 | return NULL; | |
95 | ||
96 | new->data = (void *)data; | |
97 | list_node_append(list ? &list->node : NULL, &new->node); | |
98 | ||
99 | return list ? list : new; | |
100 | } | |
101 | ||
102 | struct kmod_list *kmod_list_insert_after(struct kmod_list *list, const void *data) | |
103 | { | |
104 | struct kmod_list *new; | |
105 | ||
106 | if (list == NULL) | |
107 | return kmod_list_append(list, data); | |
108 | ||
109 | new = malloc(sizeof(*new)); | |
110 | if (new == NULL) | |
111 | return NULL; | |
112 | ||
113 | new->data = (void *)data; | |
114 | list_node_insert_after(&list->node, &new->node); | |
115 | ||
116 | return list; | |
117 | } | |
118 | ||
119 | struct kmod_list *kmod_list_insert_before(struct kmod_list *list, const void *data) | |
120 | { | |
121 | struct kmod_list *new; | |
122 | ||
123 | if (list == NULL) | |
124 | return kmod_list_append(list, data); | |
125 | ||
126 | new = malloc(sizeof(*new)); | |
127 | if (new == NULL) | |
128 | return NULL; | |
129 | ||
130 | new->data = (void *)data; | |
131 | list_node_insert_before(&list->node, &new->node); | |
132 | ||
133 | return new; | |
134 | } | |
135 | ||
136 | struct kmod_list *kmod_list_append_list(struct kmod_list *list1, struct kmod_list *list2) | |
137 | { | |
138 | if (list1 == NULL) | |
139 | return list2; | |
140 | ||
141 | if (list2 == NULL) | |
142 | return list1; | |
143 | ||
144 | list_node_append_list(&list1->node, &list2->node); | |
145 | ||
146 | return list1; | |
147 | } | |
148 | ||
149 | struct kmod_list *kmod_list_prepend(struct kmod_list *list, const void *data) | |
150 | { | |
151 | struct kmod_list *new; | |
152 | ||
153 | new = malloc(sizeof(*new)); | |
154 | if (new == NULL) | |
155 | return NULL; | |
156 | ||
157 | new->data = (void *)data; | |
158 | list_node_append(list ? &list->node : NULL, &new->node); | |
159 | ||
160 | return new; | |
161 | } | |
162 | ||
163 | struct kmod_list *kmod_list_remove(struct kmod_list *list) | |
164 | { | |
165 | struct list_node *node; | |
166 | ||
167 | if (list == NULL) | |
168 | return NULL; | |
169 | ||
170 | node = list_node_remove(&list->node); | |
171 | free(list); | |
172 | ||
173 | if (node == NULL) | |
174 | return NULL; | |
175 | ||
176 | return container_of(node, struct kmod_list, node); | |
177 | } | |
178 | ||
179 | struct kmod_list *kmod_list_remove_data(struct kmod_list *list, const void *data) | |
180 | { | |
181 | struct kmod_list *itr; | |
182 | struct list_node *node; | |
183 | ||
184 | for (itr = list; itr != NULL; itr = kmod_list_next(list, itr)) { | |
185 | if (itr->data == data) | |
186 | break; | |
187 | } | |
188 | ||
189 | if (itr == NULL) | |
190 | return list; | |
191 | ||
192 | node = list_node_remove(&itr->node); | |
193 | free(itr); | |
194 | ||
195 | if (node == NULL) | |
196 | return NULL; | |
197 | ||
198 | return container_of(node, struct kmod_list, node); | |
199 | } | |
200 | ||
201 | KMOD_EXPORT struct kmod_list *kmod_list_prev(const struct kmod_list *list, | |
202 | const struct kmod_list *curr) | |
203 | { | |
204 | if (list == NULL || curr == NULL) | |
205 | return NULL; | |
206 | ||
207 | if (list == curr) | |
208 | return NULL; | |
209 | ||
210 | return container_of(curr->node.prev, struct kmod_list, node); | |
211 | } | |
212 | ||
213 | KMOD_EXPORT struct kmod_list *kmod_list_next(const struct kmod_list *list, | |
214 | const struct kmod_list *curr) | |
215 | { | |
216 | if (list == NULL || curr == NULL) | |
217 | return NULL; | |
218 | ||
219 | if (curr->node.next == &list->node) | |
220 | return NULL; | |
221 | ||
222 | return container_of(curr->node.next, struct kmod_list, node); | |
223 | } | |
224 | ||
225 | KMOD_EXPORT struct kmod_list *kmod_list_last(const struct kmod_list *list) | |
226 | { | |
227 | if (list == NULL) | |
228 | return NULL; | |
229 | return container_of(list->node.prev, struct kmod_list, node); | |
230 | } |