1 /**
2 *
3 * Orcania library
4 *
5 * Different functions for different purposes but that can be shared between
6 * other projects
7 *
8 * orcania.c: main functions definitions
9 *
10 * Copyright 2015-2020 Nicolas Mora <mail@babelouest.org>
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation;
15 * version 2.1 of the License.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU GENERAL PUBLIC LICENSE for more details.
21 *
22 * You should have received a copy of the GNU General Public
23 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
24 *
25 */
26
27 #ifndef _GNU_SOURCE
28 #define _GNU_SOURCE
29 #endif
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stdarg.h>
34 #include "orcania.h"
35
36 #ifdef _MSC_VER
37 #define strncasecmp _strnicmp
38 #define strcasecmp _stricmp
39 #endif
40
41 /**
42 *
43 * Orcania library
44 *
45 * Different functions for different purposes but that can be shared between
46 * other projects
47 *
48 */
49
50 /**
51 * char * str_replace(const char * source, char * str_old, char * str_new)
52 * replace all occurences of str_old by str_new in the string source
53 * return a char * with the str_new value
54 * return NULL on error
55 * returned value must be free'd after use
56 */
str_replace(const char * source,const char * str_old,const char * str_new)57 char * str_replace(const char * source, const char * str_old, const char * str_new) {
58 char * to_return, * ptr, * pre, * next;
59 size_t len, pre_len;
60
61 if (source == NULL || str_old == NULL || str_new == NULL) {
62 return NULL;
63 }
64
65 ptr = strstr(source, str_old);
66 if (ptr == NULL) {
67 return o_strdup(source);
68 } else {
69 pre_len = ptr-source;
70 pre = o_malloc((pre_len+1)*sizeof(char));
71 if (pre == NULL) {
72 return NULL;
73 }
74 memcpy(pre, source, pre_len);
75 pre[pre_len] = '\0';
76
77 next = str_replace(source+strlen(pre)+strlen(str_old), str_old, str_new);
78 if (next == NULL) {
79 o_free(pre);
80 return NULL;
81 }
82 len = ((ptr-source)+strlen(str_new)+strlen(next));
83 to_return = o_malloc((len+1)*sizeof(char));
84 if (to_return == NULL) {
85 o_free(pre);
86 o_free(next);
87 return NULL;
88 }
89 if (snprintf(to_return, (len+1), "%s%s%s", pre, str_new, next) < 0) {
90 o_free(pre);
91 o_free(next);
92 o_free(to_return);
93 return NULL;
94 }
95 o_free(pre);
96 o_free(next);
97 return to_return;
98 }
99 }
100
101 /**
102 * char * msprintf(const char * message, ...)
103 * Implementation of sprintf that return a malloc'd char * with the string construction
104 * because life is too short to use 3 lines instead of 1
105 * but don't forget to free the returned value after use!
106 */
msprintf(const char * message,...)107 char * msprintf(const char * message, ...) {
108 va_list argp, argp_cpy;
109 size_t out_len = 0;
110 char * out = NULL;
111 if (message != NULL) {
112 va_start(argp, message);
113 va_copy(argp_cpy, argp); // We make a copy because in some architectures, vsnprintf can modify argp
114 out_len = vsnprintf(NULL, 0, message, argp);
115 out = o_malloc(out_len+sizeof(char));
116 if (out == NULL) {
117 va_end(argp);
118 va_end(argp_cpy);
119 return NULL;
120 }
121 vsnprintf(out, (out_len+sizeof(char)), message, argp_cpy);
122 va_end(argp);
123 va_end(argp_cpy);
124 }
125 return out;
126 }
127
128 /**
129 * char * mstrcatf((char * source, const char * message, ...)
130 * A combination of strcat and msprintf that will concat source and message formatted
131 * and return the combination as a new allocated char *
132 * and will o_free source
133 * but don't forget to free the returned value after use!
134 */
mstrcatf(char * source,const char * message,...)135 char * mstrcatf(char * source, const char * message, ...) {
136 va_list argp, argp_cpy;
137 char * out = NULL, * message_formatted = NULL;
138 size_t message_formatted_len = 0, out_len = 0, source_len = 0;
139
140 if (message != NULL) {
141 va_start(argp, message);
142 va_copy(argp_cpy, argp); // We make a copy because in some architectures, vsnprintf can modify argp
143 if (source != NULL) {
144 source_len = o_strlen(source);
145 message_formatted_len = vsnprintf(NULL, 0, message, argp);
146 message_formatted = o_malloc(message_formatted_len+sizeof(char));
147 if (message_formatted != NULL) {
148 out = o_malloc(source_len+message_formatted_len+sizeof(char));
149 vsnprintf(message_formatted, (message_formatted_len+sizeof(char)), message, argp_cpy);
150 if (out != NULL) {
151 o_strncpy(out, source, source_len);
152 o_strncpy(out+source_len, message_formatted, message_formatted_len);
153 out[source_len+message_formatted_len] = '\0';
154 }
155 o_free(message_formatted);
156 o_free(source);
157 }
158 } else {
159 out_len = vsnprintf(NULL, 0, message, argp);
160 out = o_malloc(out_len+sizeof(char));
161 if (out != NULL) {
162 vsnprintf(out, (out_len+sizeof(char)), message, argp_cpy);
163 }
164 }
165 va_end(argp);
166 va_end(argp_cpy);
167 }
168 return out;
169 }
170
171 /**
172 * o_strdup
173 * a modified strdup function that don't crash when source is NULL, instead return NULL
174 * Returned value must be free'd after use
175 */
o_strdup(const char * source)176 char * o_strdup(const char * source) {
177 return (source==NULL?NULL:o_strndup(source, strlen(source)));
178 }
179
180 /**
181 * o_strndup
182 * a modified strndup function that don't crash when source is NULL, instead return NULL
183 * Returned value must be free'd after use
184 */
o_strndup(const char * source,size_t len)185 char * o_strndup(const char * source, size_t len) {
186 char *new_str;
187
188 if (source == NULL) {
189 return NULL;
190 } else {
191 new_str = o_malloc(len + 1);
192 if(!new_str) {
193 return NULL;
194 }
195
196 memcpy(new_str, source, len);
197 new_str[len] = '\0';
198 return new_str;
199 }
200 }
201
202 /**
203 * o_strcmp
204 * a modified strcmp function that don't crash when p1 is NULL or p2 us NULL
205 */
o_strcmp(const char * p1,const char * p2)206 int o_strcmp(const char * p1, const char * p2) {
207 if (p1 == NULL && p2 == NULL) {
208 return 0;
209 } else if (p1 != NULL && p2 == NULL) {
210 return -1;
211 } else if (p1 == NULL) {
212 return 1;
213 } else {
214 return strcmp(p1, p2);
215 }
216 }
217
218 /**
219 * o_strncmp
220 * a modified strncmp function that don't crash when p1 is NULL or p2 us NULL
221 */
o_strncmp(const char * p1,const char * p2,size_t n)222 int o_strncmp(const char * p1, const char * p2, size_t n) {
223 if ((p1 == NULL && p2 == NULL) || n <= 0) {
224 return 0;
225 } else if (p1 != NULL && p2 == NULL) {
226 return -1;
227 } else if (p1 == NULL) {
228 return 1;
229 } else {
230 return strncmp(p1, p2, n);
231 }
232 }
233
234 /**
235 * o_strcpy
236 * a modified strcpy function that don't crash when p1 is NULL or p2 us NULL
237 */
o_strcpy(char * p1,const char * p2)238 char * o_strcpy(char * p1, const char * p2) {
239 if (p1 == NULL || p2 == NULL) {
240 return NULL;
241 } else {
242 return strcpy(p1, p2);
243 }
244 }
245
246 /**
247 * o_strncpy
248 * a modified strncpy function that don't crash when p1 is NULL or p2 us NULL
249 */
o_strncpy(char * p1,const char * p2,size_t n)250 char * o_strncpy(char * p1, const char * p2, size_t n) {
251 if (p1 == NULL || p2 == NULL) {
252 return NULL;
253 } else {
254 return strncpy(p1, p2, n);
255 }
256 }
257
258 /**
259 * o_strcasecmp
260 * a modified strcasecmp function that don't crash when p1 is NULL or p2 us NULL
261 */
o_strcasecmp(const char * p1,const char * p2)262 int o_strcasecmp(const char * p1, const char * p2) {
263 if (p1 == NULL && p2 == NULL) {
264 return 0;
265 } else if (p1 != NULL && p2 == NULL) {
266 return -1;
267 } else if (p1 == NULL && p2 != NULL) {
268 return 1;
269 } else {
270 return strcasecmp(p1, p2);
271 }
272 }
273
274 /**
275 * o_strncasecmp
276 * a modified strncasecmp function that don't crash when p1 is NULL or p2 us NULL
277 */
o_strncasecmp(const char * p1,const char * p2,size_t n)278 int o_strncasecmp(const char * p1, const char * p2, size_t n) {
279 if ((p1 == NULL && p2 == NULL) || n <= 0) {
280 return 0;
281 } else if (p1 != NULL && p2 == NULL) {
282 return -1;
283 } else if (p1 == NULL && p2 != NULL) {
284 return 1;
285 } else {
286 return strncasecmp(p1, p2, n);
287 }
288 }
289
290 /**
291 * o_strstr
292 * a modified strstr function that don't crash when haystack is NULL or needle us NULL
293 */
o_strstr(const char * haystack,const char * needle)294 char * o_strstr(const char * haystack, const char * needle) {
295 if (haystack == NULL || needle == NULL) {
296 return NULL;
297 } else {
298 return strstr(haystack, needle);
299 }
300 }
301
302 /**
303 * o_strchr
304 * a modified strchr function that don't crash when haystack is NULL
305 */
o_strchr(const char * haystack,int c)306 char * o_strchr(const char * haystack, int c) {
307 if (haystack == NULL) {
308 return NULL;
309 } else {
310 return strchr(haystack, c);
311 }
312 }
313
314 /**
315 * o_strnchr
316 * a modified strnchr function that don't crash when haystack is NULL
317 */
o_strnchr(const char * haystack,size_t len,char c)318 const char * o_strnchr(const char * haystack, size_t len, char c) {
319 size_t offset;
320 if (haystack != NULL && len > 0) {
321 for (offset = 0; offset < len && offset < o_strlen(haystack); offset++) {
322 if (haystack[offset] == c) {
323 return (haystack+offset);
324 }
325 }
326 }
327 return NULL;
328 }
329
330 /**
331 * o_strrchr
332 * a modified strrchr function that don't crash when haystack is NULL
333 */
o_strrchr(const char * haystack,int c)334 char * o_strrchr(const char * haystack, int c) {
335 if (haystack == NULL) {
336 return NULL;
337 } else {
338 return strrchr(haystack, c);
339 }
340 }
341
342 /**
343 * o_strrnchr
344 * a modified strrnchr function that don't crash when haystack is NULL
345 */
o_strrnchr(const char * haystack,size_t len,char c)346 const char * o_strrnchr(const char * haystack, size_t len, char c) {
347 ssize_t offset;
348 if (haystack != NULL && len > 0) {
349 for (offset = o_strlen(haystack)-1; offset>=0 && (o_strlen(haystack) - 1 - offset < len); offset--) {
350 if (haystack[offset] == c) {
351 return (haystack+offset);
352 }
353 }
354 }
355 return NULL;
356 }
357
358 #if defined(__linux__) || defined(__GLIBC__) || defined(_WIN32) || defined(O_STRSTR)
strnstr(const char * haystack,const char * needle,size_t len)359 static char *strnstr(const char *haystack, const char *needle, size_t len) {
360 int i;
361 size_t needle_len;
362
363 /* segfault here if needle is not NULL terminated */
364 if (0 == (needle_len = strlen(needle)))
365 return (char *)haystack;
366
367 for (i=0; i<=(int)(len - needle_len); i++) {
368 if ((haystack[0] == needle[0]) && (0 == strncmp(haystack, needle, needle_len)))
369 return (char *)haystack;
370
371 haystack++;
372 }
373 return NULL;
374 }
375 #endif
376
377 #ifdef _WIN32
strcasestr(const char * haystack,const char * needle)378 static char *strcasestr(const char *haystack, const char *needle) {
379 size_t n;
380 if (haystack == NULL || needle == NULL) {
381 return NULL;
382 }
383 n = o_strlen(needle);
384 while (*haystack) {
385 if (!strnicmp(haystack++, needle, n)) {
386 return (char *)(haystack-sizeof(char));
387 }
388 }
389 return NULL;
390 }
391 #endif
392
393 /**
394 * o_strnstr
395 * a modified strnstr function that don't crash when haystack is NULL or needle us NULL
396 */
o_strnstr(const char * haystack,const char * needle,size_t len)397 char * o_strnstr(const char * haystack, const char * needle, size_t len) {
398 if (haystack == NULL || needle == NULL) {
399 return NULL;
400 } else {
401 return strnstr(haystack, needle, len);
402 }
403 }
404
405 /**
406 * o_strcasestr
407 * a modified strcasestr function that don't crash when haystack is NULL or needle us NULL
408 */
o_strcasestr(const char * haystack,const char * needle)409 char * o_strcasestr(const char * haystack, const char * needle) {
410 if (haystack == NULL || needle == NULL) {
411 return NULL;
412 } else {
413 return strcasestr(haystack, needle);
414 }
415 }
416
417 /**
418 * o_strlen
419 * a modified version of strlen that don't crash when s is NULL
420 */
o_strlen(const char * s)421 size_t o_strlen(const char * s) {
422 if (s == NULL) {
423 return 0;
424 } else {
425 return strlen(s);
426 }
427 }
428
429 /**
430 * Split a string into an array of strings using separator string
431 * return the number of elements to be returned, 0 on error
432 * if return_array is not NULL, set the returned array in it
433 * return_array is an array of char * ending with a NULL value
434 * return_array must be free'd after use
435 * you can use free_string_array to free return_array
436 */
split_string(const char * string,const char * separator,char *** return_array)437 size_t split_string(const char * string, const char * separator, char *** return_array) {
438 size_t result = 0;
439 char * token;
440 const char * begin = string;
441
442 if (string != NULL && separator != NULL) {
443 if (return_array != NULL) {
444 *return_array = NULL;
445 }
446 result = 1;
447 token = strstr(begin, separator);
448 while (token != NULL) {
449 if (return_array != NULL) {
450 (*return_array) = o_realloc((*return_array), (result + 1)*sizeof(char*));
451 if ((*return_array) != NULL) {
452 (*return_array)[result-1] = o_strndup(begin, (token-begin));
453 (*return_array)[result] = NULL;
454 }
455 }
456 result++;
457 begin = token+strlen(separator);
458 token = strstr(begin, separator);
459 }
460 if (return_array != NULL) {
461 (*return_array) = o_realloc((*return_array), (result + 1)*sizeof(char*));
462 if ((*return_array) != NULL) {
463 (*return_array)[result-1] = o_strdup(begin);
464 (*return_array)[result] = NULL;
465 }
466 }
467 }
468 return result;
469 }
470
471 /**
472 * Clean an array of strings
473 */
free_string_array(char ** array)474 void free_string_array(char ** array) {
475 int i;
476 if (array != NULL) {
477 for (i=0; array[i] != NULL; i++) {
478 o_free(array[i]);
479 array[i] = NULL;
480 }
481 o_free(array);
482 }
483 }
484
485 /**
486 * Count the number of elements in an array of strings
487 */
string_array_size(char ** array)488 size_t string_array_size(char ** array) {
489 size_t ret = 0;
490 if (array != NULL) {
491 for (;array[ret] != NULL; ret++);
492 }
493 return ret;
494 }
495
496 /**
497 * Join a string array into a single string
498 */
string_array_join(const char ** array,const char * separator)499 char * string_array_join(const char ** array, const char * separator) {
500 char * to_return = NULL, * tmp;
501 int i;
502
503 if (array != NULL && separator != NULL) {
504 for (i=0; array[i] != NULL; i++) {
505 if (to_return == NULL) {
506 to_return = o_strdup(array[i]);
507 } else {
508 tmp = msprintf("%s%s%s", to_return, separator, array[i]);
509 o_free(to_return);
510 to_return = tmp;
511 }
512 }
513 }
514 return to_return;
515 }
516
517 /**
518 * Remove string of beginning and ending whitespaces
519 */
trimwhitespace(char * str)520 char * trimwhitespace(char * str) {
521 char * end;
522
523 if (str == NULL) {
524 return NULL;
525 } else if(*str == 0) {
526 return str;
527 }
528
529 while(isspace((unsigned char)*str)) str++;
530
531 end = str + o_strlen(str) - 1;
532 while(end > str && isspace((unsigned char)*end)) {
533 end--;
534 }
535
536 *(end+1) = 0;
537
538 return str;
539 }
540
541 /**
542 * Remove string of beginning and ending given character
543 */
trimcharacter(char * str,char to_remove)544 char * trimcharacter(char * str, char to_remove) {
545 char * end;
546
547 if (str == NULL) {
548 return NULL;
549 } else if(*str == 0) {
550 return str;
551 }
552
553 while(*str == to_remove) str++;
554
555 end = str + o_strlen(str) - 1;
556 while(end > str && (*end == to_remove)) {
557 end--;
558 }
559
560 *(end+1) = 0;
561
562 return str;
563 }
564
565 /**
566 * Check if an array of string has a specified value, case sensitive
567 */
string_array_has_value(const char ** array,const char * needle)568 int string_array_has_value(const char ** array, const char * needle) {
569 int i;
570 if (array != NULL && needle != NULL) {
571 for (i=0; array[i] != NULL; i++) {
572 if (o_strcmp(array[i], needle) == 0) {
573 return 1;
574 }
575 }
576 return 0;
577 } else {
578 return 0;
579 }
580 }
581
582 /**
583 * Check if an array of string has a specified value, case insensitive
584 */
string_array_has_value_case(const char ** array,const char * needle)585 int string_array_has_value_case(const char ** array, const char * needle) {
586 int i;
587 if (array != NULL && needle != NULL) {
588 for (i=0; array[i] != NULL; i++) {
589 if (o_strcasecmp(array[i], needle) == 0) {
590 return 1;
591 }
592 }
593 return 0;
594 } else {
595 return 0;
596 }
597 }
598
599 /**
600 * Check if an array of string has a specified value, case sensitive, limit to len characters
601 */
string_array_has_value_n(const char ** array,const char * needle,size_t len)602 int string_array_has_value_n(const char ** array, const char * needle, size_t len) {
603 int i;
604 if (array != NULL && needle != NULL) {
605 for (i=0; array[i] != NULL; i++) {
606 if (o_strncmp(array[i], needle, len) == 0) {
607 return 1;
608 }
609 }
610 return 0;
611 } else {
612 return 0;
613 }
614 }
615
616 /**
617 * Check if an array of string has a specified value, case insensitive, limit to len characters
618 */
string_array_has_value_ncase(const char ** array,const char * needle,size_t len)619 int string_array_has_value_ncase(const char ** array, const char * needle, size_t len) {
620 int i;
621 if (array != NULL && needle != NULL) {
622 for (i=0; array[i] != NULL; i++) {
623 if (o_strncasecmp(array[i], needle, len) == 0) {
624 return 1;
625 }
626 }
627 return 0;
628 } else {
629 return 0;
630 }
631 }
632
633 /**
634 * Check if an array of string has a specified trimmed value
635 */
string_array_has_trimmed_value(const char ** array,const char * needle)636 int string_array_has_trimmed_value(const char ** array, const char * needle) {
637 int i, to_return = 0;
638 char * duplicate_needle, * trimmed_needle, * duplicate_value, * trimmed_value;
639 if (array != NULL && needle != NULL) {
640 duplicate_needle = o_strdup(needle);
641 if (duplicate_needle != NULL) {
642 trimmed_needle = trimwhitespace(duplicate_needle);
643 for (i=0; array[i] != NULL && !to_return; i++) {
644 duplicate_value = o_strdup(array[i]);
645 if (duplicate_value == NULL) {
646 break;
647 } else {
648 trimmed_value = trimwhitespace(duplicate_value);
649 if (o_strcmp(trimmed_value, trimmed_needle) == 0) {
650 to_return = 1;
651 }
652 }
653 o_free(duplicate_value);
654 }
655 }
656 o_free(duplicate_needle);
657 }
658 return to_return;
659 }
660
661 /**
662 * pointer_list_init
663 * Initialize a pointer list structure
664 */
pointer_list_init(struct _pointer_list * pointer_list)665 void pointer_list_init(struct _pointer_list * pointer_list) {
666 if (pointer_list != NULL) {
667 pointer_list->size = 0;
668 pointer_list->list = NULL;
669 }
670 }
671
672 /**
673 * pointer_list_clean
674 * Clean a pointer list structure
675 */
pointer_list_clean(struct _pointer_list * pointer_list)676 void pointer_list_clean(struct _pointer_list * pointer_list) {
677 size_t i;
678 if (pointer_list != NULL) {
679 for (i=pointer_list_size(pointer_list); i; i--) {
680 pointer_list_remove_at(pointer_list, (i-1));
681 }
682 }
683 }
684
685 /**
686 * pointer_list_clean_free
687 * Clean a pointer list structure
688 * Free all elements using the free_function given in parameters
689 */
pointer_list_clean_free(struct _pointer_list * pointer_list,void (* free_function)(void * elt))690 void pointer_list_clean_free(struct _pointer_list * pointer_list, void (* free_function)(void * elt)) {
691 size_t i;
692 if (pointer_list != NULL) {
693 for (i=pointer_list_size(pointer_list); i; i--) {
694 free_function(pointer_list_get_at(pointer_list, i-1));
695 pointer_list_remove_at(pointer_list, (i-1));
696 }
697 }
698 }
699
700 /**
701 * pointer_list_size
702 * Return the size of a pointer list
703 */
pointer_list_size(struct _pointer_list * pointer_list)704 size_t pointer_list_size(struct _pointer_list * pointer_list) {
705 if (pointer_list != NULL) {
706 return pointer_list->size;
707 } else {
708 return 0;
709 }
710 }
711
712 /**
713 * pointer_list_append
714 * Appends an element at the end of a pointer list
715 * Return 1 on success, 0 on error
716 */
pointer_list_append(struct _pointer_list * pointer_list,void * element)717 int pointer_list_append(struct _pointer_list * pointer_list, void * element) {
718 if (pointer_list) {
719 pointer_list->list = o_realloc(pointer_list->list, (pointer_list->size+1)*sizeof(void *));
720 if (pointer_list->list != NULL) {
721 pointer_list->list[pointer_list->size] = element;
722 pointer_list->size++;
723 return 1;
724 } else {
725 o_free(pointer_list->list);
726 pointer_list->list = NULL;
727 return 0;
728 }
729 } else {
730 return 0;
731 }
732 }
733
734 /**
735 * pointer_list_get_at
736 * Returns an element of a pointer list at the specified index or NULL if non valid index
737 */
pointer_list_get_at(struct _pointer_list * pointer_list,size_t index)738 void * pointer_list_get_at(struct _pointer_list * pointer_list, size_t index) {
739 if (pointer_list != NULL && index < pointer_list->size) {
740 return pointer_list->list[index];
741 } else {
742 return NULL;
743 }
744 }
745
746 /**
747 * pointer_list_remove_at
748 * Removes an element of a pointer list at the specified index
749 * Return 1 on success, 0 on error or non valid index
750 */
pointer_list_remove_at(struct _pointer_list * pointer_list,size_t index)751 int pointer_list_remove_at(struct _pointer_list * pointer_list, size_t index) {
752 size_t i;
753 if (pointer_list != NULL && index < pointer_list->size) {
754 for (i=index; i<pointer_list->size-1; i++) {
755 pointer_list->list[i] = pointer_list->list[i+1];
756 }
757 if (pointer_list->size > 1) {
758 pointer_list->list = o_realloc(pointer_list->list, (pointer_list->size-1)*sizeof(void *));
759 } else {
760 o_free(pointer_list->list);
761 pointer_list->list = NULL;
762 }
763 pointer_list->size--;
764 return 1;
765 } else {
766 return 0;
767 }
768 }
769
770 /**
771 * pointer_list_remove_at_free
772 * Removes an element of a pointer list at the specified index
773 * Return 1 on success, 0 on error or non valid index
774 * Free the element using the free_function given in parameters
775 */
pointer_list_remove_at_free(struct _pointer_list * pointer_list,size_t index,void (* free_function)(void * elt))776 int pointer_list_remove_at_free(struct _pointer_list * pointer_list, size_t index, void (* free_function)(void * elt)) {
777 if (pointer_list != NULL && index < pointer_list->size) {
778 free_function(pointer_list_get_at(pointer_list, index));
779 return pointer_list_remove_at(pointer_list, index);
780 } else {
781 return 0;
782 }
783 }
784
785 /**
786 * pointer_list_insert_at
787 * Inserts an element at the specified index of a pointer list
788 * Return 1 on success, 0 on error or non valid index
789 */
pointer_list_insert_at(struct _pointer_list * pointer_list,void * element,size_t index)790 int pointer_list_insert_at(struct _pointer_list * pointer_list, void * element, size_t index) {
791 size_t i;
792 if (pointer_list != NULL && index <= pointer_list->size) {
793 pointer_list->list = o_realloc(pointer_list->list, (pointer_list->size + 1)*sizeof(void *));
794 if (pointer_list->list != NULL) {
795 for (i=pointer_list->size; i>index; i--) {
796 pointer_list->list[i] = pointer_list->list[i-1];
797 }
798 pointer_list->list[index] = element;
799 pointer_list->size++;
800 return 1;
801 } else {
802 return 0;
803 }
804 } else {
805 return 0;
806 }
807 }
808
809 /**
810 * pointer_list_remove_at
811 * Removes an element of a pointer list corresponding to the specified element
812 * Return 1 on success, 0 on error or non valid element
813 */
pointer_list_remove_pointer(struct _pointer_list * pointer_list,void * element)814 int pointer_list_remove_pointer(struct _pointer_list * pointer_list, void * element) {
815 size_t index;
816 if (pointer_list != NULL) {
817 for (index=0; index<pointer_list->size; index++) {
818 if (pointer_list->list[index] == element) {
819 return pointer_list_remove_at(pointer_list, index);
820 }
821 }
822 return 0;
823 } else {
824 return 0;
825 }
826 }
827
828 /**
829 * pointer_list_remove_pointer_free
830 * Removes an element of a pointer list corresponding to the specified element
831 * Free the element using the free_function given in parameters
832 * Return 1 on success, 0 on error or non valid element
833 */
pointer_list_remove_pointer_free(struct _pointer_list * pointer_list,void * element,void (* free_function)(void * elt))834 int pointer_list_remove_pointer_free(struct _pointer_list * pointer_list, void * element, void (* free_function)(void * elt)) {
835 size_t index;
836 if (pointer_list != NULL) {
837 for (index=0; index<pointer_list->size; index++) {
838 if (pointer_list->list[index] == element) {
839 free_function(element);
840 return pointer_list_remove_at(pointer_list, index);
841 }
842 }
843 return 0;
844 } else {
845 return 0;
846 }
847 }
848