File: | build-analysis/../src/lib/xmmstypes/xmmsv_list.c |
Warning: | line 87, column 3 Use of memory after it is freed |
1 | /* XMMS2 - X Music Multiplexer System | |||
2 | * Copyright (C) 2003-2017 XMMS2 Team | |||
3 | * | |||
4 | * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!! | |||
5 | * | |||
6 | * This library is free software; you can redistribute it and/or | |||
7 | * modify it under the terms of the GNU Lesser General Public | |||
8 | * License as published by the Free Software Foundation; either | |||
9 | * version 2.1 of the License, or (at your option) any later version. | |||
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 | ||||
17 | #include <stdlib.h> | |||
18 | #include <string.h> | |||
19 | ||||
20 | #include <xmmscpriv/xmmsv.h> | |||
21 | #include <xmmscpriv/xmms_list.h> | |||
22 | ||||
23 | #include <xmmsc/xmmsv.h> | |||
24 | ||||
25 | struct xmmsv_list_iter_St { | |||
26 | xmmsv_list_internal_t *parent; | |||
27 | int position; | |||
28 | }; | |||
29 | ||||
30 | struct xmmsv_list_internal_St { | |||
31 | xmmsv_t **list; | |||
32 | xmmsv_t *parent_value; | |||
33 | int size; | |||
34 | int allocated; | |||
35 | bool_Bool restricted; | |||
36 | xmmsv_type_t restricttype; | |||
37 | x_list_t *iterators; | |||
38 | }; | |||
39 | ||||
40 | static void _xmmsv_list_iter_free (xmmsv_list_iter_t *it); | |||
41 | ||||
42 | static int | |||
43 | _xmmsv_list_position_normalize (int *pos, int size, int allow_append) | |||
44 | { | |||
45 | x_return_val_if_fail (size >= 0, 0)if (!(size >= 0)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "size >= 0", __FUNCTION__ , "../src/lib/xmmstypes/xmmsv_list.c", 45); return (0); }; | |||
46 | ||||
47 | if (*pos < 0) { | |||
48 | if (-*pos > size) | |||
49 | return 0; | |||
50 | *pos = size + *pos; | |||
51 | } | |||
52 | ||||
53 | if (*pos > size) | |||
54 | return 0; | |||
55 | ||||
56 | if (!allow_append && *pos == size) | |||
57 | return 0; | |||
58 | ||||
59 | return 1; | |||
60 | } | |||
61 | ||||
62 | static xmmsv_list_internal_t * | |||
63 | _xmmsv_list_new (void) | |||
64 | { | |||
65 | xmmsv_list_internal_t *list; | |||
66 | ||||
67 | list = x_new0 (xmmsv_list_internal_t, 1)calloc (1, sizeof (xmmsv_list_internal_t) * (1)); | |||
68 | if (!list) { | |||
69 | x_oom ()xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 69); | |||
70 | return NULL((void*)0); | |||
71 | } | |||
72 | ||||
73 | /* list is all empty for now! */ | |||
74 | ||||
75 | return list; | |||
76 | } | |||
77 | ||||
78 | void | |||
79 | _xmmsv_list_free (xmmsv_list_internal_t *l) | |||
80 | { | |||
81 | xmmsv_list_iter_t *it; | |||
82 | int i; | |||
83 | ||||
84 | /* free iterators */ | |||
85 | while (l->iterators) { | |||
| ||||
86 | it = (xmmsv_list_iter_t *) l->iterators->data; | |||
87 | _xmmsv_list_iter_free (it); | |||
| ||||
88 | } | |||
89 | ||||
90 | /* unref contents */ | |||
91 | for (i = 0; i < l->size; i++) { | |||
92 | xmmsv_unref (l->list[i]); | |||
93 | } | |||
94 | ||||
95 | free (l->list); | |||
96 | free (l); | |||
97 | } | |||
98 | ||||
99 | static int | |||
100 | _xmmsv_list_resize (xmmsv_list_internal_t *l, int newsize) | |||
101 | { | |||
102 | xmmsv_t **newmem; | |||
103 | ||||
104 | newmem = realloc (l->list, newsize * sizeof (xmmsv_t *)); | |||
105 | ||||
106 | if (newsize != 0 && newmem == NULL((void*)0)) { | |||
107 | x_oom ()xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 107); | |||
108 | return 0; | |||
109 | } | |||
110 | ||||
111 | l->list = newmem; | |||
112 | l->allocated = newsize; | |||
113 | ||||
114 | return 1; | |||
115 | } | |||
116 | ||||
117 | static int | |||
118 | _xmmsv_list_insert (xmmsv_list_internal_t *l, int pos, xmmsv_t *val) | |||
119 | { | |||
120 | xmmsv_list_iter_t *it; | |||
121 | x_list_t *n; | |||
122 | ||||
123 | if (!_xmmsv_list_position_normalize (&pos, l->size, 1)) { | |||
124 | return 0; | |||
125 | } | |||
126 | ||||
127 | if (l->restricted) { | |||
128 | x_return_val_if_fail (xmmsv_is_type (val, l->restricttype), 0)if (!(xmmsv_is_type (val, l->restricttype))) { xmmsc_log ( "xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d" , "xmmsv_is_type (val, l->restricttype)", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 128); return (0); }; | |||
129 | } | |||
130 | ||||
131 | /* We need more memory, reallocate */ | |||
132 | if (l->size == l->allocated) { | |||
133 | int success; | |||
134 | size_t double_size; | |||
135 | if (l->allocated > 0) { | |||
136 | double_size = l->allocated << 1; | |||
137 | } else { | |||
138 | double_size = 1; | |||
139 | } | |||
140 | success = _xmmsv_list_resize (l, double_size); | |||
141 | x_return_val_if_fail (success, 0)if (!(success)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "success", __FUNCTION__ , "../src/lib/xmmstypes/xmmsv_list.c", 141); return (0); }; | |||
142 | } | |||
143 | ||||
144 | /* move existing items out of the way */ | |||
145 | if (l->size > pos) { | |||
146 | memmove (l->list + pos + 1, l->list + pos, | |||
147 | (l->size - pos) * sizeof (xmmsv_t *)); | |||
148 | } | |||
149 | ||||
150 | l->list[pos] = xmmsv_ref (val); | |||
151 | l->size++; | |||
152 | ||||
153 | /* update iterators pos */ | |||
154 | for (n = l->iterators; n; n = n->next) { | |||
155 | it = (xmmsv_list_iter_t *) n->data; | |||
156 | if (it->position > pos) { | |||
157 | it->position++; | |||
158 | } | |||
159 | } | |||
160 | ||||
161 | return 1; | |||
162 | } | |||
163 | ||||
164 | static int | |||
165 | _xmmsv_list_append (xmmsv_list_internal_t *l, xmmsv_t *val) | |||
166 | { | |||
167 | return _xmmsv_list_insert (l, l->size, val); | |||
168 | } | |||
169 | ||||
170 | static int | |||
171 | _xmmsv_list_remove (xmmsv_list_internal_t *l, int pos) | |||
172 | { | |||
173 | xmmsv_list_iter_t *it; | |||
174 | int half_size; | |||
175 | x_list_t *n; | |||
176 | ||||
177 | /* prevent removing after the last element */ | |||
178 | if (!_xmmsv_list_position_normalize (&pos, l->size, 0)) { | |||
179 | return 0; | |||
180 | } | |||
181 | ||||
182 | xmmsv_unref (l->list[pos]); | |||
183 | ||||
184 | l->size--; | |||
185 | ||||
186 | /* fill the gap */ | |||
187 | if (pos < l->size) { | |||
188 | memmove (l->list + pos, l->list + pos + 1, | |||
189 | (l->size - pos) * sizeof (xmmsv_t *)); | |||
190 | } | |||
191 | ||||
192 | /* Reduce memory usage by two if possible */ | |||
193 | half_size = l->allocated >> 1; | |||
194 | if (l->size <= half_size) { | |||
195 | int success; | |||
196 | success = _xmmsv_list_resize (l, half_size); | |||
197 | x_return_val_if_fail (success, 0)if (!(success)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "success", __FUNCTION__ , "../src/lib/xmmstypes/xmmsv_list.c", 197); return (0); }; | |||
198 | } | |||
199 | ||||
200 | /* update iterator pos */ | |||
201 | for (n = l->iterators; n; n = n->next) { | |||
202 | it = (xmmsv_list_iter_t *) n->data; | |||
203 | if (it->position > pos) { | |||
204 | it->position--; | |||
205 | } | |||
206 | } | |||
207 | ||||
208 | return 1; | |||
209 | } | |||
210 | ||||
211 | static int | |||
212 | _xmmsv_list_move (xmmsv_list_internal_t *l, int old_pos, int new_pos) | |||
213 | { | |||
214 | xmmsv_t *v; | |||
215 | xmmsv_list_iter_t *it; | |||
216 | x_list_t *n; | |||
217 | ||||
218 | if (!_xmmsv_list_position_normalize (&old_pos, l->size, 0)) { | |||
219 | return 0; | |||
220 | } | |||
221 | if (!_xmmsv_list_position_normalize (&new_pos, l->size, 0)) { | |||
222 | return 0; | |||
223 | } | |||
224 | ||||
225 | v = l->list[old_pos]; | |||
226 | if (old_pos < new_pos) { | |||
227 | memmove (l->list + old_pos, l->list + old_pos + 1, | |||
228 | (new_pos - old_pos) * sizeof (xmmsv_t *)); | |||
229 | l->list[new_pos] = v; | |||
230 | ||||
231 | /* update iterator pos */ | |||
232 | for (n = l->iterators; n; n = n->next) { | |||
233 | it = (xmmsv_list_iter_t *) n->data; | |||
234 | if (it->position >= old_pos && it->position <= new_pos) { | |||
235 | if (it->position == old_pos) { | |||
236 | it->position = new_pos; | |||
237 | } else { | |||
238 | it->position--; | |||
239 | } | |||
240 | } | |||
241 | } | |||
242 | } else { | |||
243 | memmove (l->list + new_pos + 1, l->list + new_pos, | |||
244 | (old_pos - new_pos) * sizeof (xmmsv_t *)); | |||
245 | l->list[new_pos] = v; | |||
246 | ||||
247 | /* update iterator pos */ | |||
248 | for (n = l->iterators; n; n = n->next) { | |||
249 | it = (xmmsv_list_iter_t *) n->data; | |||
250 | if (it->position >= new_pos && it->position <= old_pos) { | |||
251 | if (it->position == old_pos) { | |||
252 | it->position = new_pos; | |||
253 | } else { | |||
254 | it->position++; | |||
255 | } | |||
256 | } | |||
257 | } | |||
258 | } | |||
259 | ||||
260 | return 1; | |||
261 | } | |||
262 | ||||
263 | static void | |||
264 | _xmmsv_list_clear (xmmsv_list_internal_t *l) | |||
265 | { | |||
266 | xmmsv_list_iter_t *it; | |||
267 | x_list_t *n; | |||
268 | int i; | |||
269 | ||||
270 | /* unref all stored values */ | |||
271 | for (i = 0; i < l->size; i++) { | |||
272 | xmmsv_unref (l->list[i]); | |||
273 | } | |||
274 | ||||
275 | /* free list, declare empty */ | |||
276 | free (l->list); | |||
277 | l->list = NULL((void*)0); | |||
278 | ||||
279 | l->size = 0; | |||
280 | l->allocated = 0; | |||
281 | ||||
282 | /* reset iterator pos */ | |||
283 | for (n = l->iterators; n; n = n->next) { | |||
284 | it = (xmmsv_list_iter_t *) n->data; | |||
285 | it->position = 0; | |||
286 | } | |||
287 | } | |||
288 | ||||
289 | static void | |||
290 | _xmmsv_list_sort (xmmsv_list_internal_t *l, xmmsv_list_compare_func_t comparator) | |||
291 | { | |||
292 | qsort (l->list, l->size, sizeof (xmmsv_t *), | |||
293 | (int (*)(const void *, const void *)) comparator); | |||
294 | } | |||
295 | ||||
296 | /** | |||
297 | * Allocates a new list #xmmsv_t. | |||
298 | * @return The new #xmmsv_t. Must be unreferenced with | |||
299 | * #xmmsv_unref. | |||
300 | */ | |||
301 | xmmsv_t * | |||
302 | xmmsv_new_list (void) | |||
303 | { | |||
304 | xmmsv_t *val = _xmmsv_new (XMMSV_TYPE_LIST); | |||
305 | ||||
306 | if (val) { | |||
307 | val->value.list = _xmmsv_list_new (); | |||
308 | val->value.list->parent_value = val; | |||
309 | } | |||
310 | ||||
311 | return val; | |||
312 | } | |||
313 | ||||
314 | /** | |||
315 | * Get the element at the given position in the list #xmmsv_t. This | |||
316 | * function does not increase the refcount of the element, the | |||
317 | * reference is still owned by the list. | |||
318 | * | |||
319 | * @param listv A #xmmsv_t containing a list. | |||
320 | * @param pos The position in the list. If negative, start counting | |||
321 | * from the end (-1 is the last element, etc). | |||
322 | * @param val Pointer set to a borrowed reference to the element at | |||
323 | * the given position in the list. | |||
324 | * @return 1 upon success otherwise 0 | |||
325 | */ | |||
326 | int | |||
327 | xmmsv_list_get (xmmsv_t *listv, int pos, xmmsv_t **val) | |||
328 | { | |||
329 | xmmsv_list_internal_t *l; | |||
330 | ||||
331 | x_return_val_if_fail (listv, 0)if (!(listv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "listv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 331); return (0); }; | |||
332 | x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0)if (!(xmmsv_is_type (listv, XMMSV_TYPE_LIST))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (listv, XMMSV_TYPE_LIST)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 332); return (0); }; | |||
333 | ||||
334 | l = listv->value.list; | |||
335 | ||||
336 | /* prevent accessing after the last element */ | |||
337 | if (!_xmmsv_list_position_normalize (&pos, l->size, 0)) { | |||
338 | return 0; | |||
339 | } | |||
340 | ||||
341 | if (val) { | |||
342 | *val = l->list[pos]; | |||
343 | } | |||
344 | ||||
345 | return 1; | |||
346 | } | |||
347 | ||||
348 | /** | |||
349 | * Set the element at the given position in the list #xmmsv_t. | |||
350 | * | |||
351 | * @param listv A #xmmsv_t containing a list. | |||
352 | * @param pos The position in the list. If negative, start counting | |||
353 | * from the end (-1 is the last element, etc). | |||
354 | * @param val The element to put at the given position in the list. | |||
355 | * @return 1 upon success otherwise 0 | |||
356 | */ | |||
357 | int | |||
358 | xmmsv_list_set (xmmsv_t *listv, int pos, xmmsv_t *val) | |||
359 | { | |||
360 | xmmsv_t *old_val; | |||
361 | xmmsv_list_internal_t *l; | |||
362 | ||||
363 | x_return_val_if_fail (listv, 0)if (!(listv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "listv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 363); return (0); }; | |||
364 | x_return_val_if_fail (val, 0)if (!(val)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "val", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 364); return (0); }; | |||
365 | x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0)if (!(xmmsv_is_type (listv, XMMSV_TYPE_LIST))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (listv, XMMSV_TYPE_LIST)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 365); return (0); }; | |||
366 | ||||
367 | l = listv->value.list; | |||
368 | ||||
369 | if (!_xmmsv_list_position_normalize (&pos, l->size, 0)) { | |||
370 | return 0; | |||
371 | } | |||
372 | ||||
373 | old_val = l->list[pos]; | |||
374 | l->list[pos] = xmmsv_ref (val); | |||
375 | xmmsv_unref (old_val); | |||
376 | ||||
377 | return 1; | |||
378 | } | |||
379 | ||||
380 | /** | |||
381 | * Insert an element at the given position in the list #xmmsv_t. | |||
382 | * The list will hold a reference to the element until it's removed. | |||
383 | * | |||
384 | * @param listv A #xmmsv_t containing a list. | |||
385 | * @param pos The position in the list. If negative, start counting | |||
386 | * from the end (-1 is the last element, etc). | |||
387 | * @param val The element to insert. | |||
388 | * @return 1 upon success otherwise 0 | |||
389 | */ | |||
390 | int | |||
391 | xmmsv_list_insert (xmmsv_t *listv, int pos, xmmsv_t *val) | |||
392 | { | |||
393 | x_return_val_if_fail (listv, 0)if (!(listv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "listv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 393); return (0); }; | |||
394 | x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0)if (!(xmmsv_is_type (listv, XMMSV_TYPE_LIST))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (listv, XMMSV_TYPE_LIST)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 394); return (0); }; | |||
395 | x_return_val_if_fail (val, 0)if (!(val)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "val", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 395); return (0); }; | |||
396 | ||||
397 | return _xmmsv_list_insert (listv->value.list, pos, val); | |||
398 | } | |||
399 | ||||
400 | /** | |||
401 | * Remove the element at the given position from the list #xmmsv_t. | |||
402 | * | |||
403 | * @param listv A #xmmsv_t containing a list. | |||
404 | * @param pos The position in the list. If negative, start counting | |||
405 | * from the end (-1 is the last element, etc). | |||
406 | * @return 1 upon success otherwise 0 | |||
407 | */ | |||
408 | int | |||
409 | xmmsv_list_remove (xmmsv_t *listv, int pos) | |||
410 | { | |||
411 | x_return_val_if_fail (listv, 0)if (!(listv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "listv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 411); return (0); }; | |||
412 | x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0)if (!(xmmsv_is_type (listv, XMMSV_TYPE_LIST))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (listv, XMMSV_TYPE_LIST)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 412); return (0); }; | |||
413 | ||||
414 | return _xmmsv_list_remove (listv->value.list, pos); | |||
415 | } | |||
416 | ||||
417 | /** | |||
418 | * Move the element from position #old to position #new. | |||
419 | * | |||
420 | * #xmmsv_list_iter_t's remain pointing at their element (which might or might | |||
421 | * not be at a different position). | |||
422 | * | |||
423 | * @param listv A #xmmsv_t containing a list | |||
424 | * @param old The original position in the list. If negative, start counting | |||
425 | * from the end (-1 is the last element, etc.) | |||
426 | * @param new The new position in the list. If negative start counting from the | |||
427 | * end (-1 is the last element, etc.) For the sake of counting the | |||
428 | * element to be moved is still at its old position. | |||
429 | * @return 1 upon success otherwise 0 | |||
430 | */ | |||
431 | int | |||
432 | xmmsv_list_move (xmmsv_t *listv, int old_pos, int new_pos) | |||
433 | { | |||
434 | x_return_val_if_fail (listv, 0)if (!(listv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "listv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 434); return (0); }; | |||
435 | x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0)if (!(xmmsv_is_type (listv, XMMSV_TYPE_LIST))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (listv, XMMSV_TYPE_LIST)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 435); return (0); }; | |||
436 | ||||
437 | return _xmmsv_list_move (listv->value.list, old_pos, new_pos); | |||
438 | } | |||
439 | ||||
440 | /** | |||
441 | * Append an element to the end of the list #xmmsv_t. | |||
442 | * The list will hold a reference to the element until it's removed. | |||
443 | * | |||
444 | * @param listv A #xmmsv_t containing a list. | |||
445 | * @param val The element to append. | |||
446 | * @return 1 upon success otherwise 0 | |||
447 | */ | |||
448 | int | |||
449 | xmmsv_list_append (xmmsv_t *listv, xmmsv_t *val) | |||
450 | { | |||
451 | x_return_val_if_fail (listv, 0)if (!(listv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "listv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 451); return (0); }; | |||
452 | x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0)if (!(xmmsv_is_type (listv, XMMSV_TYPE_LIST))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (listv, XMMSV_TYPE_LIST)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 452); return (0); }; | |||
453 | x_return_val_if_fail (val, 0)if (!(val)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "val", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 453); return (0); }; | |||
454 | ||||
455 | return _xmmsv_list_append (listv->value.list, val); | |||
456 | } | |||
457 | ||||
458 | /** | |||
459 | * Empty the list from all its elements. | |||
460 | * | |||
461 | * @param listv A #xmmsv_t containing a list. | |||
462 | * @return 1 upon success otherwise 0 | |||
463 | */ | |||
464 | int | |||
465 | xmmsv_list_clear (xmmsv_t *listv) | |||
466 | { | |||
467 | x_return_val_if_fail (listv, 0)if (!(listv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "listv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 467); return (0); }; | |||
468 | x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0)if (!(xmmsv_is_type (listv, XMMSV_TYPE_LIST))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (listv, XMMSV_TYPE_LIST)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 468); return (0); }; | |||
469 | ||||
470 | _xmmsv_list_clear (listv->value.list); | |||
471 | ||||
472 | return 1; | |||
473 | } | |||
474 | ||||
475 | /** | |||
476 | * Sort the list using the supplied comparator. | |||
477 | * | |||
478 | * @param listv A #xmmsv_t containing a list. | |||
479 | * @return 1 upon success otherwise 0 | |||
480 | */ | |||
481 | int | |||
482 | xmmsv_list_sort (xmmsv_t *listv, xmmsv_list_compare_func_t comparator) | |||
483 | { | |||
484 | x_return_val_if_fail (comparator, 0)if (!(comparator)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "comparator", __FUNCTION__ , "../src/lib/xmmstypes/xmmsv_list.c", 484); return (0); }; | |||
485 | x_return_val_if_fail (listv, 0)if (!(listv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "listv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 485); return (0); }; | |||
486 | x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0)if (!(xmmsv_is_type (listv, XMMSV_TYPE_LIST))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (listv, XMMSV_TYPE_LIST)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 486); return (0); }; | |||
487 | ||||
488 | _xmmsv_list_sort (listv->value.list, comparator); | |||
489 | ||||
490 | return 1; | |||
491 | } | |||
492 | ||||
493 | /** | |||
494 | * Apply a function to each element in the list, in sequential order. | |||
495 | * | |||
496 | * @param listv A #xmmsv_t containing a list. | |||
497 | * @param function The function to apply to each element. | |||
498 | * @param user_data User data passed to the foreach function. | |||
499 | * @return 1 upon success otherwise 0 | |||
500 | */ | |||
501 | int | |||
502 | xmmsv_list_foreach (xmmsv_t *listv, xmmsv_list_foreach_func func, | |||
503 | void* user_data) | |||
504 | { | |||
505 | xmmsv_list_iter_t *it; | |||
506 | xmmsv_t *v; | |||
507 | ||||
508 | x_return_val_if_fail (listv, 0)if (!(listv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "listv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 508); return (0); }; | |||
509 | x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0)if (!(xmmsv_is_type (listv, XMMSV_TYPE_LIST))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (listv, XMMSV_TYPE_LIST)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 509); return (0); }; | |||
510 | x_return_val_if_fail (xmmsv_get_list_iter (listv, &it), 0)if (!(xmmsv_get_list_iter (listv, &it))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_get_list_iter (listv, &it)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 510); return (0); }; | |||
511 | ||||
512 | while (xmmsv_list_iter_entry (it, &v)) { | |||
513 | func (v, user_data); | |||
514 | xmmsv_list_iter_next (it); | |||
515 | } | |||
516 | ||||
517 | _xmmsv_list_iter_free (it); | |||
518 | ||||
519 | return 1; | |||
520 | } | |||
521 | ||||
522 | /** | |||
523 | * Return the size of the list. | |||
524 | * | |||
525 | * @param listv The #xmmsv_t containing the list. | |||
526 | * @return The size of the list, or -1 if listv is invalid. | |||
527 | */ | |||
528 | int | |||
529 | xmmsv_list_get_size (xmmsv_t *listv) | |||
530 | { | |||
531 | x_return_val_if_fail (listv, -1)if (!(listv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "listv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 531); return (-1); }; | |||
532 | x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), -1)if (!(xmmsv_is_type (listv, XMMSV_TYPE_LIST))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (listv, XMMSV_TYPE_LIST)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 532); return (-1); }; | |||
533 | ||||
534 | return listv->value.list->size; | |||
535 | } | |||
536 | ||||
537 | ||||
538 | int | |||
539 | xmmsv_list_restrict_type (xmmsv_t *listv, xmmsv_type_t type) | |||
540 | { | |||
541 | x_return_val_if_fail (xmmsv_list_has_type (listv, type), 0)if (!(xmmsv_list_has_type (listv, type))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_list_has_type (listv, type)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 541); return (0); }; | |||
542 | x_return_val_if_fail (!listv->value.list->restricted ||if (!(!listv->value.list->restricted || listv->value .list->restricttype == type)) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "!listv->value.list->restricted || listv->value.list->restricttype == type" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 543); return (0); } | |||
543 | listv->value.list->restricttype == type, 0)if (!(!listv->value.list->restricted || listv->value .list->restricttype == type)) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "!listv->value.list->restricted || listv->value.list->restricttype == type" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 543); return (0); }; | |||
544 | ||||
545 | listv->value.list->restricted = true1; | |||
546 | listv->value.list->restricttype = type; | |||
547 | ||||
548 | return 1; | |||
549 | } | |||
550 | ||||
551 | /** | |||
552 | * Gets the current type restriction of a list. | |||
553 | * | |||
554 | * @param listv The list to Check | |||
555 | * @return the xmmsv_type_t of the restricted type, or XMMSV_TYPE_NONE if no restriction. | |||
556 | */ | |||
557 | int | |||
558 | xmmsv_list_get_type (xmmsv_t *listv, xmmsv_type_t *type) | |||
559 | { | |||
560 | x_return_val_if_fail (listv, false)if (!(listv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "listv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 560); return (0); }; | |||
561 | x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), false)if (!(xmmsv_is_type (listv, XMMSV_TYPE_LIST))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (listv, XMMSV_TYPE_LIST)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 561); return (0); }; | |||
562 | if (listv->value.list->restricted) { | |||
563 | *type = listv->value.list->restricttype; | |||
564 | } else { | |||
565 | *type = XMMSV_TYPE_NONE; | |||
566 | } | |||
567 | return true1; | |||
568 | } | |||
569 | ||||
570 | /** | |||
571 | * Checks if all elements in the list has the given type | |||
572 | * | |||
573 | * @param listv The list to check | |||
574 | * @param type The type to check for | |||
575 | * @return non-zero if all elements in the list has the type, 0 otherwise | |||
576 | */ | |||
577 | int | |||
578 | xmmsv_list_has_type (xmmsv_t *listv, xmmsv_type_t type) | |||
579 | { | |||
580 | xmmsv_list_iter_t *it; | |||
581 | xmmsv_t *v; | |||
582 | ||||
583 | x_return_val_if_fail (listv, 0)if (!(listv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "listv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 583); return (0); }; | |||
584 | x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), 0)if (!(xmmsv_is_type (listv, XMMSV_TYPE_LIST))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (listv, XMMSV_TYPE_LIST)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 584); return (0); }; | |||
585 | ||||
586 | if (listv->value.list->restricted) | |||
587 | return listv->value.list->restricttype == type; | |||
588 | ||||
589 | x_return_val_if_fail (xmmsv_get_list_iter (listv, &it), 0)if (!(xmmsv_get_list_iter (listv, &it))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_get_list_iter (listv, &it)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 589); return (0); }; | |||
590 | while (xmmsv_list_iter_entry (it, &v)) { | |||
591 | if (!xmmsv_is_type (v, type)) { | |||
592 | _xmmsv_list_iter_free (it); | |||
593 | return 0; | |||
594 | } | |||
595 | xmmsv_list_iter_next (it); | |||
596 | } | |||
597 | ||||
598 | _xmmsv_list_iter_free (it); | |||
599 | ||||
600 | return 1; | |||
601 | } | |||
602 | ||||
603 | /** | |||
604 | * Get the index of an element in the list. This function compares the | |||
605 | * pointers and not the actual values contained in the elements. | |||
606 | * | |||
607 | * @param listv The #xmmsv_t containing the list | |||
608 | * @param val The element to find | |||
609 | * @return The index of the element if found, -1 otherwise | |||
610 | */ | |||
611 | int | |||
612 | xmmsv_list_index_of (xmmsv_t *listv, xmmsv_t *val) | |||
613 | { | |||
614 | xmmsv_list_iter_t *it; | |||
615 | xmmsv_t *v; | |||
616 | int i = 0, ret = -1; | |||
617 | ||||
618 | x_return_val_if_fail (listv, -1)if (!(listv)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "listv", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 618); return (-1); }; | |||
619 | x_return_val_if_fail (xmmsv_is_type (listv, XMMSV_TYPE_LIST), -1)if (!(xmmsv_is_type (listv, XMMSV_TYPE_LIST))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (listv, XMMSV_TYPE_LIST)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 619); return (-1); }; | |||
620 | ||||
621 | if (!xmmsv_get_list_iter (listv, &it)) | |||
622 | return -1; | |||
623 | ||||
624 | while (xmmsv_list_iter_entry (it, &v)) { | |||
625 | if (v == val) { | |||
626 | ret = i; | |||
627 | break; | |||
628 | } | |||
629 | xmmsv_list_iter_next (it); | |||
630 | i++; | |||
631 | } | |||
632 | ||||
633 | xmmsv_list_iter_explicit_destroy (it); | |||
634 | ||||
635 | return ret; | |||
636 | } | |||
637 | ||||
638 | static xmmsv_list_iter_t * | |||
639 | _xmmsv_list_iter_new (xmmsv_list_internal_t *l) | |||
640 | { | |||
641 | xmmsv_list_iter_t *it; | |||
642 | ||||
643 | it = x_new0 (xmmsv_list_iter_t, 1)calloc (1, sizeof (xmmsv_list_iter_t) * (1)); | |||
644 | if (!it) { | |||
645 | x_oom ()xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL, "Out of memory in %s at %s:%d" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 645); | |||
646 | return NULL((void*)0); | |||
647 | } | |||
648 | ||||
649 | it->parent = l; | |||
650 | it->position = 0; | |||
651 | ||||
652 | /* register iterator into parent */ | |||
653 | l->iterators = x_list_prepend (l->iterators, it); | |||
654 | ||||
655 | return it; | |||
656 | } | |||
657 | ||||
658 | /** | |||
659 | * Retrieves a list iterator from a list #xmmsv_t. | |||
660 | * | |||
661 | * @param val a #xmmsv_t containing a list. | |||
662 | * @param it An #xmmsv_list_iter_t that can be used to access the list | |||
663 | * data. The iterator will be freed when the value is freed. | |||
664 | * @return 1 upon success otherwise 0 | |||
665 | */ | |||
666 | int | |||
667 | xmmsv_get_list_iter (const xmmsv_t *val, xmmsv_list_iter_t **it) | |||
668 | { | |||
669 | xmmsv_list_iter_t *new_it; | |||
670 | ||||
671 | if (!val || val->type != XMMSV_TYPE_LIST) { | |||
672 | *it = NULL((void*)0); | |||
673 | return 0; | |||
674 | } | |||
675 | ||||
676 | new_it = _xmmsv_list_iter_new (val->value.list); | |||
677 | if (!new_it) { | |||
678 | *it = NULL((void*)0); | |||
679 | return 0; | |||
680 | } | |||
681 | ||||
682 | *it = new_it; | |||
683 | ||||
684 | return 1; | |||
685 | } | |||
686 | ||||
687 | static void | |||
688 | _xmmsv_list_iter_free (xmmsv_list_iter_t *it) | |||
689 | { | |||
690 | /* unref iterator from list and free it */ | |||
691 | it->parent->iterators = x_list_remove (it->parent->iterators, it); | |||
692 | free (it); | |||
693 | } | |||
694 | ||||
695 | /** | |||
696 | * Explicitly free list iterator. | |||
697 | * | |||
698 | * Immediately frees any resources used by this iterator. The iterator | |||
699 | * is freed automatically when the list is freed, but this function is | |||
700 | * useful when the list can be long lived. | |||
701 | * | |||
702 | * @param it iterator to free | |||
703 | * | |||
704 | */ | |||
705 | void | |||
706 | xmmsv_list_iter_explicit_destroy (xmmsv_list_iter_t *it) | |||
707 | { | |||
708 | _xmmsv_list_iter_free (it); | |||
709 | } | |||
710 | ||||
711 | /** | |||
712 | * Get the element currently pointed at by the iterator. This function | |||
713 | * does not increase the refcount of the element, the reference is | |||
714 | * still owned by the list. If iterator does not point on a valid | |||
715 | * element xmmsv_list_iter_entry returns 0 and leaves val untouched. | |||
716 | * | |||
717 | * @param it A #xmmsv_list_iter_t. | |||
718 | * @param val Pointer set to a borrowed reference to the element | |||
719 | * pointed at by the iterator. | |||
720 | * @return 1 upon success otherwise 0 | |||
721 | */ | |||
722 | int | |||
723 | xmmsv_list_iter_entry (xmmsv_list_iter_t *it, xmmsv_t **val) | |||
724 | { | |||
725 | if (!xmmsv_list_iter_valid (it)) | |||
726 | return 0; | |||
727 | ||||
728 | *val = it->parent->list[it->position]; | |||
729 | ||||
730 | return 1; | |||
731 | } | |||
732 | ||||
733 | /** | |||
734 | * Check whether the iterator is valid and points to a valid element. | |||
735 | * | |||
736 | * @param it A #xmmsv_list_iter_t. | |||
737 | * @return 1 if the iterator is valid, 0 otherwise | |||
738 | */ | |||
739 | int | |||
740 | xmmsv_list_iter_valid (xmmsv_list_iter_t *it) | |||
741 | { | |||
742 | return it && (it->position < it->parent->size) && (it->position >= 0); | |||
743 | } | |||
744 | ||||
745 | /** | |||
746 | * Rewind the iterator to the start of the list. | |||
747 | * | |||
748 | * @param it A #xmmsv_list_iter_t. | |||
749 | */ | |||
750 | void | |||
751 | xmmsv_list_iter_first (xmmsv_list_iter_t *it) | |||
752 | { | |||
753 | x_return_if_fail (it)if (!(it)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "it", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 753); return; }; | |||
754 | ||||
755 | it->position = 0; | |||
756 | } | |||
757 | ||||
758 | /** | |||
759 | * Move the iterator to end of the list. | |||
760 | * | |||
761 | * @param listv A #xmmsv_list_iter_t. | |||
762 | */ | |||
763 | void | |||
764 | xmmsv_list_iter_last (xmmsv_list_iter_t *it) | |||
765 | { | |||
766 | x_return_if_fail (it)if (!(it)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "it", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 766); return; }; | |||
767 | ||||
768 | if (it->parent->size > 0) { | |||
769 | it->position = it->parent->size - 1; | |||
770 | } else { | |||
771 | it->position = it->parent->size; | |||
772 | } | |||
773 | } | |||
774 | ||||
775 | /** | |||
776 | * Advance the iterator to the next element in the list. | |||
777 | * | |||
778 | * @param it A #xmmsv_list_iter_t. | |||
779 | */ | |||
780 | void | |||
781 | xmmsv_list_iter_next (xmmsv_list_iter_t *it) | |||
782 | { | |||
783 | x_return_if_fail (it)if (!(it)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "it", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 783); return; }; | |||
784 | ||||
785 | if (it->position < it->parent->size) { | |||
786 | it->position++; | |||
787 | } | |||
788 | } | |||
789 | ||||
790 | /** | |||
791 | * Move the iterator to the previous element in the list. | |||
792 | * | |||
793 | * @param listv A #xmmsv_list_iter_t. | |||
794 | */ | |||
795 | void | |||
796 | xmmsv_list_iter_prev (xmmsv_list_iter_t *it) | |||
797 | { | |||
798 | x_return_if_fail (it)if (!(it)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "it", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 798); return; }; | |||
799 | ||||
800 | if (it->position >= 0) { | |||
801 | it->position--; | |||
802 | } | |||
803 | } | |||
804 | ||||
805 | ||||
806 | /** | |||
807 | * Move the iterator to the n-th element in the list. | |||
808 | * | |||
809 | * @param it A #xmmsv_list_iter_t. | |||
810 | * @param pos The position in the list. If negative, start counting | |||
811 | * from the end (-1 is the last element, etc). | |||
812 | * @return 1 upon success otherwise 0 | |||
813 | */ | |||
814 | int | |||
815 | xmmsv_list_iter_seek (xmmsv_list_iter_t *it, int pos) | |||
816 | { | |||
817 | x_return_val_if_fail (it, 0)if (!(it)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "it", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 817); return (0); }; | |||
818 | ||||
819 | if (!_xmmsv_list_position_normalize (&pos, it->parent->size, 1)) { | |||
820 | return 0; | |||
821 | } | |||
822 | it->position = pos; | |||
823 | ||||
824 | return 1; | |||
825 | } | |||
826 | ||||
827 | /** | |||
828 | * Tell the position of the iterator. | |||
829 | * | |||
830 | * @param it A #xmmsv_list_iter_t. | |||
831 | * @return The position of the iterator, or -1 if invalid. | |||
832 | */ | |||
833 | int | |||
834 | xmmsv_list_iter_tell (const xmmsv_list_iter_t *it) | |||
835 | { | |||
836 | x_return_val_if_fail (it, -1)if (!(it)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "it", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 836); return (-1); }; | |||
837 | ||||
838 | return it->position; | |||
839 | } | |||
840 | ||||
841 | /** | |||
842 | * Return the parent #xmmsv_t of an iterator. | |||
843 | * | |||
844 | * @param it A #xmmsv_list_iter_t. | |||
845 | * @return The parent #xmmsv_t of the iterator, or NULL if invalid. | |||
846 | */ | |||
847 | xmmsv_t* | |||
848 | xmmsv_list_iter_get_parent (const xmmsv_list_iter_t *it) | |||
849 | { | |||
850 | x_return_val_if_fail (it, NULL)if (!(it)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "it", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 850); return (((void*)0)); }; | |||
851 | ||||
852 | return it->parent->parent_value; | |||
853 | } | |||
854 | ||||
855 | /** | |||
856 | * Replace an element in the list at the position pointed at by the | |||
857 | * iterator. | |||
858 | * | |||
859 | * @param it A #xmmsv_list_iter_t. | |||
860 | * @param val The element to insert. | |||
861 | * @return 1 upon success otherwise 0 | |||
862 | */ | |||
863 | int | |||
864 | xmmsv_list_iter_set (xmmsv_list_iter_t *it, xmmsv_t *val) | |||
865 | { | |||
866 | x_return_val_if_fail (it, 0)if (!(it)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "it", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 866); return (0); }; | |||
867 | x_return_val_if_fail (val, 0)if (!(val)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "val", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 867); return (0); }; | |||
868 | ||||
869 | return xmmsv_list_set (it->parent->parent_value, it->position, val); | |||
870 | } | |||
871 | ||||
872 | /** | |||
873 | * Insert an element in the list at the position pointed at by the | |||
874 | * iterator. | |||
875 | * | |||
876 | * @param it A #xmmsv_list_iter_t. | |||
877 | * @param val The element to insert. | |||
878 | * @return 1 upon success otherwise 0 | |||
879 | */ | |||
880 | int | |||
881 | xmmsv_list_iter_insert (xmmsv_list_iter_t *it, xmmsv_t *val) | |||
882 | { | |||
883 | x_return_val_if_fail (it, 0)if (!(it)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "it", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 883); return (0); }; | |||
884 | x_return_val_if_fail (val, 0)if (!(val)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "val", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 884); return (0); }; | |||
885 | ||||
886 | return _xmmsv_list_insert (it->parent, it->position, val); | |||
887 | } | |||
888 | ||||
889 | /** | |||
890 | * Remove the element in the list at the position pointed at by the | |||
891 | * iterator. | |||
892 | * | |||
893 | * @param it A #xmmsv_list_iter_t. | |||
894 | * @return 1 upon success otherwise 0 | |||
895 | */ | |||
896 | int | |||
897 | xmmsv_list_iter_remove (xmmsv_list_iter_t *it) | |||
898 | { | |||
899 | x_return_val_if_fail (it, 0)if (!(it)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "it", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 899); return (0); }; | |||
900 | ||||
901 | return _xmmsv_list_remove (it->parent, it->position); | |||
902 | } | |||
903 | ||||
904 | static int | |||
905 | _xmmsv_list_flatten (xmmsv_t *list, xmmsv_t *result, int depth) | |||
906 | { | |||
907 | xmmsv_list_iter_t *it; | |||
908 | xmmsv_t *val; | |||
909 | int ret = 1; | |||
910 | ||||
911 | x_return_val_if_fail (xmmsv_is_type (list, XMMSV_TYPE_LIST), 0)if (!(xmmsv_is_type (list, XMMSV_TYPE_LIST))) { xmmsc_log ("xmmsc/xmmstypes" , XMMS_LOG_LEVEL_FAIL, "Check '%s' failed in %s at %s:%d", "xmmsv_is_type (list, XMMSV_TYPE_LIST)" , __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c", 911); return (0); }; | |||
912 | ||||
913 | for (xmmsv_get_list_iter (list, &it); | |||
914 | xmmsv_list_iter_entry (it, &val) && ret; | |||
915 | xmmsv_list_iter_next (it)) { | |||
916 | if (depth == 0) { | |||
917 | xmmsv_list_append (result, val); | |||
918 | } else { | |||
919 | ret = _xmmsv_list_flatten (val, result, depth - 1); | |||
920 | } | |||
921 | } | |||
922 | ||||
923 | return ret; | |||
924 | } | |||
925 | ||||
926 | /** | |||
927 | * Flattens a list of lists. | |||
928 | * | |||
929 | * @param list The list to flatten | |||
930 | * @param depth The level of lists to flatten. | |||
931 | * @return A new flattened list, or NULL on error. | |||
932 | */ | |||
933 | xmmsv_t * | |||
934 | xmmsv_list_flatten (xmmsv_t *list, int depth) | |||
935 | { | |||
936 | x_return_val_if_fail (list, NULL)if (!(list)) { xmmsc_log ("xmmsc/xmmstypes", XMMS_LOG_LEVEL_FAIL , "Check '%s' failed in %s at %s:%d", "list", __FUNCTION__, "../src/lib/xmmstypes/xmmsv_list.c" , 936); return (((void*)0)); }; | |||
937 | xmmsv_t *result = xmmsv_new_list (); | |||
938 | ||||
939 | if (!_xmmsv_list_flatten (list, result, depth)) { | |||
940 | xmmsv_unref (result); | |||
941 | return NULL((void*)0); | |||
942 | } | |||
943 | ||||
944 | return result; | |||
945 | } | |||
946 | ||||
947 | /* macro-magically define list extractors */ | |||
948 | #define GEN_LIST_EXTRACTOR_FUNC(typename, type)int xmmsv_list_get_typename (xmmsv_t *val, int pos, type *r) { xmmsv_t *v; if (!xmmsv_list_get (val, pos, &v)) { return 0; } return xmmsv_get_typename (v, r); } \ | |||
949 | int \ | |||
950 | xmmsv_list_get_##typename (xmmsv_t *val, int pos, type *r) \ | |||
951 | { \ | |||
952 | xmmsv_t *v; \ | |||
953 | if (!xmmsv_list_get (val, pos, &v)) { \ | |||
954 | return 0; \ | |||
955 | } \ | |||
956 | return xmmsv_get_##typename (v, r); \ | |||
957 | } | |||
958 | ||||
959 | GEN_LIST_EXTRACTOR_FUNC (string, const char *)int xmmsv_list_get_string (xmmsv_t *val, int pos, const char * *r) { xmmsv_t *v; if (!xmmsv_list_get (val, pos, &v)) { return 0; } return xmmsv_get_string (v, r); } | |||
960 | GEN_LIST_EXTRACTOR_FUNC (int32, int32_t)int xmmsv_list_get_int32 (xmmsv_t *val, int pos, int32_t *r) { xmmsv_t *v; if (!xmmsv_list_get (val, pos, &v)) { return 0; } return xmmsv_get_int32 (v, r); } | |||
961 | GEN_LIST_EXTRACTOR_FUNC (int64, int64_t)int xmmsv_list_get_int64 (xmmsv_t *val, int pos, int64_t *r) { xmmsv_t *v; if (!xmmsv_list_get (val, pos, &v)) { return 0; } return xmmsv_get_int64 (v, r); } | |||
962 | GEN_LIST_EXTRACTOR_FUNC (float, float)int xmmsv_list_get_float (xmmsv_t *val, int pos, float *r) { xmmsv_t *v; if (!xmmsv_list_get (val, pos, &v)) { return 0; } return xmmsv_get_float (v, r); } | |||
963 | ||||
964 | int | |||
965 | xmmsv_list_get_coll (xmmsv_t *val, int pos, xmmsv_t **r) | |||
966 | { | |||
967 | return xmmsv_list_get (val, pos, r); | |||
968 | } | |||
969 | ||||
970 | /* macro-magically define list set functions */ | |||
971 | #define GEN_LIST_SET_FUNC(typename, type)int xmmsv_list_set_typename (xmmsv_t *list, int pos, type elem ) { int ret; xmmsv_t *v; v = xmmsv_new_typename (elem); ret = xmmsv_list_set (list, pos, v); xmmsv_unref (v); return ret; } \ | |||
972 | int \ | |||
973 | xmmsv_list_set_##typename (xmmsv_t *list, int pos, type elem) \ | |||
974 | { \ | |||
975 | int ret; \ | |||
976 | xmmsv_t *v; \ | |||
977 | \ | |||
978 | v = xmmsv_new_##typename (elem); \ | |||
979 | ret = xmmsv_list_set (list, pos, v); \ | |||
980 | xmmsv_unref (v); \ | |||
981 | \ | |||
982 | return ret; \ | |||
983 | } | |||
984 | ||||
985 | GEN_LIST_SET_FUNC (string, const char *)int xmmsv_list_set_string (xmmsv_t *list, int pos, const char * elem) { int ret; xmmsv_t *v; v = xmmsv_new_string (elem); ret = xmmsv_list_set (list, pos, v); xmmsv_unref (v); return ret ; } | |||
986 | GEN_LIST_SET_FUNC (int, int64_t)int xmmsv_list_set_int (xmmsv_t *list, int pos, int64_t elem) { int ret; xmmsv_t *v; v = xmmsv_new_int (elem); ret = xmmsv_list_set (list, pos, v); xmmsv_unref (v); return ret; } | |||
987 | GEN_LIST_SET_FUNC (float, float)int xmmsv_list_set_float (xmmsv_t *list, int pos, float elem) { int ret; xmmsv_t *v; v = xmmsv_new_float (elem); ret = xmmsv_list_set (list, pos, v); xmmsv_unref (v); return ret; } | |||
988 | ||||
989 | int | |||
990 | xmmsv_list_set_coll (xmmsv_t *list, int pos, xmmsv_t *elem) | |||
991 | { | |||
992 | return xmmsv_list_set (list, pos, elem); | |||
993 | } | |||
994 | ||||
995 | /* macro-magically define list insert functions */ | |||
996 | #define GEN_LIST_INSERT_FUNC(typename, type)int xmmsv_list_insert_typename (xmmsv_t *list, int pos, type elem ) { int ret; xmmsv_t *v; v = xmmsv_new_typename (elem); ret = xmmsv_list_insert (list, pos, v); xmmsv_unref (v); return ret ; } \ | |||
997 | int \ | |||
998 | xmmsv_list_insert_##typename (xmmsv_t *list, int pos, type elem) \ | |||
999 | { \ | |||
1000 | int ret; \ | |||
1001 | xmmsv_t *v; \ | |||
1002 | \ | |||
1003 | v = xmmsv_new_##typename (elem); \ | |||
1004 | ret = xmmsv_list_insert (list, pos, v); \ | |||
1005 | xmmsv_unref (v); \ | |||
1006 | \ | |||
1007 | return ret; \ | |||
1008 | } | |||
1009 | ||||
1010 | GEN_LIST_INSERT_FUNC (string, const char *)int xmmsv_list_insert_string (xmmsv_t *list, int pos, const char * elem) { int ret; xmmsv_t *v; v = xmmsv_new_string (elem); ret = xmmsv_list_insert (list, pos, v); xmmsv_unref (v); return ret ; } | |||
1011 | GEN_LIST_INSERT_FUNC (int, int64_t)int xmmsv_list_insert_int (xmmsv_t *list, int pos, int64_t elem ) { int ret; xmmsv_t *v; v = xmmsv_new_int (elem); ret = xmmsv_list_insert (list, pos, v); xmmsv_unref (v); return ret; } | |||
1012 | GEN_LIST_INSERT_FUNC (float, float)int xmmsv_list_insert_float (xmmsv_t *list, int pos, float elem ) { int ret; xmmsv_t *v; v = xmmsv_new_float (elem); ret = xmmsv_list_insert (list, pos, v); xmmsv_unref (v); return ret; } | |||
1013 | ||||
1014 | int | |||
1015 | xmmsv_list_insert_coll (xmmsv_t *list, int pos, xmmsv_t *elem) | |||
1016 | { | |||
1017 | return xmmsv_list_insert (list, pos, elem); | |||
1018 | } | |||
1019 | ||||
1020 | /* macro-magically define list append functions */ | |||
1021 | #define GEN_LIST_APPEND_FUNC(typename, type)int xmmsv_list_append_typename (xmmsv_t *list, type elem) { int ret; xmmsv_t *v; v = xmmsv_new_typename (elem); ret = xmmsv_list_append (list, v); xmmsv_unref (v); return ret; } \ | |||
1022 | int \ | |||
1023 | xmmsv_list_append_##typename (xmmsv_t *list, type elem) \ | |||
1024 | { \ | |||
1025 | int ret; \ | |||
1026 | xmmsv_t *v; \ | |||
1027 | \ | |||
1028 | v = xmmsv_new_##typename (elem); \ | |||
1029 | ret = xmmsv_list_append (list, v); \ | |||
1030 | xmmsv_unref (v); \ | |||
1031 | \ | |||
1032 | return ret; \ | |||
1033 | } | |||
1034 | ||||
1035 | GEN_LIST_APPEND_FUNC (string, const char *)int xmmsv_list_append_string (xmmsv_t *list, const char * elem ) { int ret; xmmsv_t *v; v = xmmsv_new_string (elem); ret = xmmsv_list_append (list, v); xmmsv_unref (v); return ret; } | |||
1036 | GEN_LIST_APPEND_FUNC (int, int64_t)int xmmsv_list_append_int (xmmsv_t *list, int64_t elem) { int ret; xmmsv_t *v; v = xmmsv_new_int (elem); ret = xmmsv_list_append (list, v); xmmsv_unref (v); return ret; } | |||
1037 | GEN_LIST_APPEND_FUNC (float, float)int xmmsv_list_append_float (xmmsv_t *list, float elem) { int ret; xmmsv_t *v; v = xmmsv_new_float (elem); ret = xmmsv_list_append (list, v); xmmsv_unref (v); return ret; } | |||
1038 | ||||
1039 | int | |||
1040 | xmmsv_list_append_coll (xmmsv_t *list, xmmsv_t *elem) | |||
1041 | { | |||
1042 | return xmmsv_list_append (list, elem); | |||
1043 | } | |||
1044 | ||||
1045 | /* macro-magically define list_iter extractors */ | |||
1046 | #define GEN_LIST_ITER_EXTRACTOR_FUNC(typename, type)int xmmsv_list_iter_entry_typename (xmmsv_list_iter_t *it, type *r) { xmmsv_t *v; if (!xmmsv_list_iter_entry (it, &v)) { return 0; } return xmmsv_get_typename (v, r); } \ | |||
1047 | int \ | |||
1048 | xmmsv_list_iter_entry_##typename (xmmsv_list_iter_t *it, type *r) \ | |||
1049 | { \ | |||
1050 | xmmsv_t *v; \ | |||
1051 | if (!xmmsv_list_iter_entry (it, &v)) { \ | |||
1052 | return 0; \ | |||
1053 | } \ | |||
1054 | return xmmsv_get_##typename (v, r); \ | |||
1055 | } | |||
1056 | ||||
1057 | GEN_LIST_ITER_EXTRACTOR_FUNC (string, const char *)int xmmsv_list_iter_entry_string (xmmsv_list_iter_t *it, const char * *r) { xmmsv_t *v; if (!xmmsv_list_iter_entry (it, & v)) { return 0; } return xmmsv_get_string (v, r); } | |||
1058 | GEN_LIST_ITER_EXTRACTOR_FUNC (int32, int32_t)int xmmsv_list_iter_entry_int32 (xmmsv_list_iter_t *it, int32_t *r) { xmmsv_t *v; if (!xmmsv_list_iter_entry (it, &v)) { return 0; } return xmmsv_get_int32 (v, r); } | |||
1059 | GEN_LIST_ITER_EXTRACTOR_FUNC (int64, int64_t)int xmmsv_list_iter_entry_int64 (xmmsv_list_iter_t *it, int64_t *r) { xmmsv_t *v; if (!xmmsv_list_iter_entry (it, &v)) { return 0; } return xmmsv_get_int64 (v, r); } | |||
1060 | GEN_LIST_ITER_EXTRACTOR_FUNC (float, float)int xmmsv_list_iter_entry_float (xmmsv_list_iter_t *it, float *r) { xmmsv_t *v; if (!xmmsv_list_iter_entry (it, &v)) { return 0; } return xmmsv_get_float (v, r); } | |||
1061 | ||||
1062 | int | |||
1063 | xmmsv_list_iter_entry_coll (xmmsv_list_iter_t *it, xmmsv_t **r) | |||
1064 | { | |||
1065 | return xmmsv_list_iter_entry (it, r); | |||
1066 | } | |||
1067 | ||||
1068 | /* macro-magically define list_iter insert functions */ | |||
1069 | #define GEN_LIST_ITER_INSERT_FUNC(typename, type)int xmmsv_list_iter_insert_typename (xmmsv_list_iter_t *it, type elem) { int ret; xmmsv_t *v; v = xmmsv_new_typename (elem); ret = xmmsv_list_iter_insert (it, v); xmmsv_unref (v); return ret ; } \ | |||
1070 | int \ | |||
1071 | xmmsv_list_iter_insert_##typename (xmmsv_list_iter_t *it, type elem) \ | |||
1072 | { \ | |||
1073 | int ret; \ | |||
1074 | xmmsv_t *v; \ | |||
1075 | \ | |||
1076 | v = xmmsv_new_##typename (elem); \ | |||
1077 | ret = xmmsv_list_iter_insert (it, v); \ | |||
1078 | xmmsv_unref (v); \ | |||
1079 | \ | |||
1080 | return ret; \ | |||
1081 | } | |||
1082 | ||||
1083 | GEN_LIST_ITER_INSERT_FUNC (string, const char *)int xmmsv_list_iter_insert_string (xmmsv_list_iter_t *it, const char * elem) { int ret; xmmsv_t *v; v = xmmsv_new_string (elem ); ret = xmmsv_list_iter_insert (it, v); xmmsv_unref (v); return ret; } | |||
1084 | GEN_LIST_ITER_INSERT_FUNC (int, int64_t)int xmmsv_list_iter_insert_int (xmmsv_list_iter_t *it, int64_t elem) { int ret; xmmsv_t *v; v = xmmsv_new_int (elem); ret = xmmsv_list_iter_insert (it, v); xmmsv_unref (v); return ret; } | |||
1085 | GEN_LIST_ITER_INSERT_FUNC (float, float)int xmmsv_list_iter_insert_float (xmmsv_list_iter_t *it, float elem) { int ret; xmmsv_t *v; v = xmmsv_new_float (elem); ret = xmmsv_list_iter_insert (it, v); xmmsv_unref (v); return ret ; } | |||
1086 | ||||
1087 | int | |||
1088 | xmmsv_list_iter_insert_coll (xmmsv_list_iter_t *it, xmmsv_t *elem) | |||
1089 | { | |||
1090 | return xmmsv_list_iter_insert (it, elem); | |||
1091 | } |