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