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 104 : mlist_t *list_add_member(mlist_t *list, void *member, u32_t size) {
34 : mlist_t *n_member, *tmp;
35 :
36 104 : if (member == NULL || size <= 0)
37 1 : return NULL;
38 :
39 : /* Allocate the list container and the new member */
40 103 : n_member = malloc(sizeof(mlist_t));
41 103 : n_member->member = malloc(size);
42 103 : assert(n_member && n_member->member);
43 :
44 : /* Copy the new member */
45 103 : memcpy(n_member->member, member, size);
46 103 : n_member->size = size;
47 103 : n_member->next = n_member->prev = NULL;
48 :
49 : /* If the list head is NULL, we return the new */
50 103 : if (list == NULL) {
51 17 : n_member->head = n_member;
52 17 : return n_member;
53 : }
54 :
55 : /* Else, we go the end of the list */
56 86 : for (tmp = list; tmp->next != NULL; tmp = tmp->next)
57 : ;
58 86 : tmp->next = n_member;
59 86 : n_member->prev = tmp;
60 86 : n_member->head = list;
61 86 : 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 5 : mlist_t *list_get_last(mlist_t *list) {
71 : mlist_t *tmp;
72 :
73 5 : if (list == NULL)
74 1 : return NULL;
75 4 : for (tmp = list; tmp->next; tmp = tmp->next)
76 : ;
77 4 : 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 3 : 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 3 : n_member = malloc(sizeof(mlist_t));
96 3 : n_member->member = malloc(size);
97 3 : assert(n_member && n_member->member);
98 :
99 : /* Copy the new member */
100 3 : memcpy(n_member->member, member, size);
101 3 : n_member->size = size;
102 3 : n_member->next = n_member->prev = NULL;
103 :
104 : /* If the list head is NULL, we return the new member */
105 3 : if (org == NULL) {
106 1 : n_member->head = n_member;
107 1 : return n_member;
108 : }
109 :
110 : /* Search for the given ptr */
111 2 : 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 2 : if (tmp->next == NULL) {
116 1 : tmp->next = n_member;
117 1 : n_member->prev = tmp;
118 : } else {
119 1 : tmp2 = tmp->next;
120 1 : tmp->next = n_member;
121 1 : n_member->prev = tmp;
122 1 : n_member->next = tmp2;
123 1 : tmp2->prev = n_member;
124 : }
125 2 : n_member->head = org;
126 2 : 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 4 : 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 4 : n_member = malloc(sizeof(mlist_t));
147 4 : n_member->member = malloc(size);
148 4 : assert(n_member && n_member->member);
149 :
150 : /* Copy the new member */
151 4 : memcpy(n_member->member, member, size);
152 4 : n_member->size = size;
153 4 : n_member->next = n_member->prev = NULL;
154 :
155 : /* If the list is NULL, we return the new member */
156 4 : if (org == NULL) {
157 1 : n_member->head = n_member;
158 1 : return n_member;
159 : }
160 :
161 : /* Search for the given ptr */
162 3 : 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 3 : if (tmp->next == NULL) {
167 1 : tmp->next = n_member;
168 1 : n_member->prev = tmp;
169 :
170 : /* If the given ptr is the head, replace the head by the new member */
171 2 : } else if (ptr == org) {
172 1 : n_member->next = org;
173 1 : n_member->prev = NULL;
174 1 : org->prev = n_member;
175 1 : org = n_member;
176 : } else {
177 1 : tmp2 = tmp->prev;
178 1 : n_member->next = tmp;
179 1 : tmp->prev = n_member;
180 1 : tmp2->next = n_member;
181 : }
182 3 : n_member->head = org;
183 3 : 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 2 : u32_t list_size(mlist_t *list) {
192 : u32_t i;
193 : mlist_t *tmp;
194 :
195 2 : if (list == NULL)
196 1 : return 0;
197 :
198 1 : for (tmp = list, i = 0; tmp != NULL; tmp = tmp->next, i++)
199 : ;
200 1 : 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 21 : mlist_t *list_free(mlist_t *list, int (*free_fn)(void *member)) {
218 21 : mlist_t *tmp = list, *tmp2;
219 :
220 150 : while (tmp != NULL) {
221 109 : tmp2 = tmp->next;
222 109 : if (free_fn != NULL && free_fn(tmp->member) == 0) {
223 1 : return tmp;
224 : } else {
225 108 : free(tmp->member);
226 108 : free(tmp);
227 : }
228 108 : tmp = tmp2;
229 : }
230 20 : 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 61 : void *list_get(mlist_t *list, void *member, size_t size) {
244 : mlist_t *tmp;
245 : void *ptr;
246 :
247 61 : if (list == NULL)
248 2 : return NULL;
249 127 : list_for_each(list, tmp, ptr) {
250 124 : if (memcmp(ptr, member, size) == 0 && (size == tmp->size))
251 56 : return ptr;
252 : }
253 3 : 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 4 : 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 4 : if (list == NULL)
271 1 : return NULL;
272 :
273 : /* Search for the member */
274 6 : list_for_each(list, tmp2, ptr) {
275 5 : if (memcmp(member, ptr, size) == 0)
276 2 : break ;
277 : }
278 :
279 : /* We can't find the member */
280 3 : if (tmp2 == NULL) {
281 1 : return list;
282 : }
283 :
284 2 : if (tmp2 == list) {
285 : /* Replace the head */
286 1 : list = tmp2->next;
287 :
288 : /* Update the head in all other members */
289 3 : list_for_each(list, tmp, ptr) {
290 2 : tmp->head = list;
291 : }
292 : } else {
293 1 : tmp2->prev->next = tmp2->next;
294 : }
295 :
296 2 : if (free_fn != NULL) {
297 1 : free_fn(tmp2->member);
298 : } else {
299 1 : free(tmp2->member);
300 : }
301 2 : free(tmp2);
302 2 : return list;
303 : }
|