Line data Source code
1 : /*********************************** LICENSE **********************************\
2 : * Copyright 2017 Morphux *
3 : * *
4 : * Licensed under the Apache License, Version 2.0 (the "License"); *
5 : * you may not use this file except in compliance with the License. *
6 : * You may obtain a copy of the License at *
7 : * *
8 : * http://www.apache.org/licenses/LICENSE-2.0 *
9 : * *
10 : * Unless required by applicable law or agreed to in writing, software *
11 : * distributed under the License is distributed on an "AS IS" BASIS, *
12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13 : * See the License for the specific language governing permissions and *
14 : * limitations under the License. *
15 : \******************************************************************************/
16 :
17 : #include <m_list.h>
18 :
19 : /*!
20 : * \brief Add a new member to a linked list
21 : * \param list Head of a linked list
22 : * \param member New member to add
23 : * \param size Size of the new member
24 : *
25 : * This function will add the member at the end of the list. If the list
26 : * pointer is null, a new list head is returned.
27 : * Member is copied with a memcpy, in a pre-allocated pointer of size.
28 : *
29 : * \note If member is NULL, NULL is returned
30 : * \note If size is equal to 0, NULL is returned
31 : * \note Member is _not freed_ by this function
32 : */
33 228 : mlist_t *list_add_member(mlist_t *list, void *member, u32_t size) {
34 : mlist_t *n_member, *tmp;
35 :
36 228 : if (member == NULL || size <= 0)
37 2 : return NULL;
38 :
39 : /* Allocate the list container and the new member */
40 226 : n_member = malloc(sizeof(mlist_t));
41 226 : n_member->member = malloc(size);
42 226 : assert(n_member && n_member->member);
43 :
44 : /* Copy the new member */
45 226 : memcpy(n_member->member, member, size);
46 226 : n_member->size = size;
47 226 : n_member->next = n_member->prev = NULL;
48 :
49 : /* If the list head is NULL, we return the new */
50 226 : if (list == NULL) {
51 46 : n_member->head = n_member;
52 46 : return n_member;
53 : }
54 :
55 : /* Else, we go the end of the list */
56 180 : for (tmp = list; tmp->next != NULL; tmp = tmp->next)
57 : ;
58 180 : tmp->next = n_member;
59 180 : n_member->prev = tmp;
60 180 : n_member->head = list;
61 180 : return list;
62 : }
63 :
64 : /*!
65 : * \brief Get list last member
66 : * \param list Head of the list
67 : * \return The last member of the list
68 : * \note If the list head is NULL, NULL is returned
69 : */
70 10 : mlist_t *list_get_last(mlist_t *list) {
71 : mlist_t *tmp;
72 :
73 10 : if (list == NULL)
74 2 : return NULL;
75 8 : for (tmp = list; tmp->next; tmp = tmp->next)
76 : ;
77 8 : return tmp;
78 : }
79 :
80 : /*!
81 : * \brief Insert a new member after a given existing member in a list
82 : * \param org List head
83 : * \param ptr Pointer used to add member after
84 : * \param member New member to add
85 : * \param size Size of the new member
86 : *
87 : * This function will try to add a new member after a given ptr.
88 : * If list head is NULL, a new list is returned
89 : * If the given pointer is not in the list, the new member is added at the end
90 : */
91 6 : mlist_t *list_insert_after(mlist_t *org, mlist_t *ptr, void *member, u32_t size) {
92 : mlist_t *n_member, *tmp, *tmp2;
93 :
94 : /* Allocate the new member */
95 6 : n_member = malloc(sizeof(mlist_t));
96 6 : n_member->member = malloc(size);
97 6 : assert(n_member && n_member->member);
98 :
99 : /* Copy the new member */
100 6 : memcpy(n_member->member, member, size);
101 6 : n_member->size = size;
102 6 : n_member->next = n_member->prev = NULL;
103 :
104 : /* If the list head is NULL, we return the new member */
105 6 : if (org == NULL) {
106 2 : n_member->head = n_member;
107 2 : return n_member;
108 : }
109 :
110 : /* Search for the given ptr */
111 4 : for (tmp = org; tmp->next && tmp != ptr; tmp = tmp->next)
112 : ;
113 :
114 : /* If the ptr is not in the list, add the new member at the end of head */
115 4 : if (tmp->next == NULL) {
116 2 : tmp->next = n_member;
117 2 : n_member->prev = tmp;
118 : } else {
119 2 : tmp2 = tmp->next;
120 2 : tmp->next = n_member;
121 2 : n_member->prev = tmp;
122 2 : n_member->next = tmp2;
123 2 : tmp2->prev = n_member;
124 : }
125 4 : n_member->head = org;
126 4 : return org;
127 : }
128 :
129 : /*!
130 : * \brief Insert a new member before a given existing member in a list
131 : * \param org List head
132 : * \param ptr Pointer used to add member after
133 : * \param member New member to add
134 : * \param size Size of the new member
135 : *
136 : * This function will try to add a new member before a given ptr
137 : * If list head is NULL, a new list is returned
138 : * If the given ptr is the current head, the head is updated with the new
139 : * member.
140 : * If the given ptr is not in the list, the member is added at the end
141 : */
142 8 : mlist_t *list_insert_before(mlist_t *org, mlist_t *ptr, void *member, u32_t size) {
143 : mlist_t *n_member, *tmp, *tmp2;
144 :
145 : /* Allocate the new member */
146 8 : n_member = malloc(sizeof(mlist_t));
147 8 : n_member->member = malloc(size);
148 8 : assert(n_member && n_member->member);
149 :
150 : /* Copy the new member */
151 8 : memcpy(n_member->member, member, size);
152 8 : n_member->size = size;
153 8 : n_member->next = n_member->prev = NULL;
154 :
155 : /* If the list is NULL, we return the new member */
156 8 : if (org == NULL) {
157 2 : n_member->head = n_member;
158 2 : return n_member;
159 : }
160 :
161 : /* Search for the given ptr */
162 6 : for (tmp = org; tmp->next != NULL && tmp != ptr; tmp = tmp->next)
163 : ;
164 :
165 : /* If the ptr is not in the list, add the new member at the end of head */
166 6 : if (tmp->next == NULL) {
167 2 : tmp->next = n_member;
168 2 : n_member->prev = tmp;
169 :
170 : /* If the given ptr is the head, replace the head by the new member */
171 4 : } else if (ptr == org) {
172 2 : n_member->next = org;
173 2 : n_member->prev = NULL;
174 2 : org->prev = n_member;
175 2 : org = n_member;
176 : } else {
177 2 : tmp2 = tmp->prev;
178 2 : n_member->next = tmp;
179 2 : tmp->prev = n_member;
180 2 : tmp2->next = n_member;
181 : }
182 6 : n_member->head = org;
183 6 : return org;
184 : }
185 :
186 : /*!
187 : * \brief Return the size of a list
188 : * \param list List head
189 : * \note If the list head is NULL, this function will return 0
190 : */
191 4 : u32_t list_size(mlist_t *list) {
192 : u32_t i;
193 : mlist_t *tmp;
194 :
195 4 : if (list == NULL)
196 2 : return 0;
197 :
198 2 : for (tmp = list, i = 0; tmp != NULL; tmp = tmp->next, i++)
199 : ;
200 2 : return i;
201 : }
202 :
203 : /*!
204 : * \brief Free a list
205 : * \param list List head
206 : * \param free_fn Function pointer to free the member
207 : *
208 : * This function will try to free a linked list.
209 : * free_fn function pointer is used to free the members.
210 : * This function must return something besides 0 in order to this function to
211 : * carry on.
212 : * If the free_fn function return 0, this function will stop, and return the
213 : * current not-freed pointer.
214 : *
215 : * \return If the list has been entirely freed, this function will return NULL
216 : */
217 42 : mlist_t *list_free(mlist_t *list, int (*free_fn)(void *member)) {
218 42 : mlist_t *tmp = list, *tmp2;
219 :
220 304 : while (tmp != NULL) {
221 222 : tmp2 = tmp->next;
222 222 : if (free_fn != NULL && free_fn(tmp->member) == 0) {
223 2 : return tmp;
224 : } else {
225 220 : free(tmp->member);
226 220 : free(tmp);
227 : }
228 220 : tmp = tmp2;
229 : }
230 40 : return NULL;
231 : }
232 :
233 : /*!
234 : * \brief Search a member in a list
235 : * \param list List head
236 : * \param member Member to search
237 : * \param size Size of the member
238 : *
239 : * Search member in list.
240 : * If member is found, return a pointer to it
241 : * If not, NULL is returned
242 : */
243 126 : void *list_get(mlist_t *list, void *member, size_t size) {
244 : mlist_t *tmp;
245 : void *ptr;
246 :
247 126 : if (list == NULL)
248 4 : return NULL;
249 262 : list_for_each(list, tmp, ptr) {
250 256 : if (memcmp(ptr, member, size) == 0 && (size == tmp->size))
251 116 : return ptr;
252 : }
253 6 : return NULL;
254 : }
255 :
256 : /*!
257 : * \brief Remove a member from the list
258 : * \param list List head
259 : * \param member Member to remove
260 : * \param size Size of the member (Used for memcmp)
261 : * \param free_fn Function use to free the member
262 : *
263 : * Remove a member in a list.
264 : */
265 8 : mlist_t *list_remove(mlist_t *list, void *member, size_t size,
266 : int (*free_fn)(void *member)) {
267 : mlist_t *tmp, *tmp2;
268 : void *ptr;
269 :
270 8 : if (list == NULL)
271 2 : return NULL;
272 :
273 : /* Search for the member */
274 12 : list_for_each(list, tmp2, ptr) {
275 10 : if (memcmp(member, ptr, size) == 0)
276 4 : break ;
277 : }
278 :
279 : /* We can't find the member */
280 6 : if (tmp2 == NULL) {
281 2 : return list;
282 : }
283 :
284 4 : if (tmp2 == list) {
285 : /* Replace the head */
286 2 : list = tmp2->next;
287 :
288 : /* Update the head in all other members */
289 6 : list_for_each(list, tmp, ptr) {
290 4 : tmp->head = list;
291 : }
292 : } else {
293 2 : tmp2->prev->next = tmp2->next;
294 : }
295 :
296 4 : if (free_fn != NULL) {
297 2 : free_fn(tmp2->member);
298 : } else {
299 2 : free(tmp2->member);
300 : }
301 4 : free(tmp2);
302 4 : return list;
303 : }
|