src/stringlist.c
author buff <andreas@pep-project.org>
Fri, 22 Jan 2021 12:26:53 +0100
branchIOSAD-186
changeset 5279 eef5d0a66d7d
parent 5190 1584ad11438f
child 5193 74e24f603e30
permissions -rw-r--r--
merge Release_2.1.11
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 #include "pEp_internal.h"
     5 
     6 #include <stdlib.h>
     7 #include <string.h>
     8 #include <assert.h>
     9 
    10 #include "stringlist.h"
    11 
    12 
    13 DYNAMIC_API stringlist_t *new_stringlist(const char *value)
    14 {
    15     stringlist_t *result = calloc(1, sizeof(stringlist_t));
    16     assert(result);
    17 
    18     if (result && value) {
    19         result->value = strdup(value);
    20         assert(result->value);
    21         if (!result->value) {
    22             free(result);
    23             return NULL;
    24         }
    25     }
    26 
    27     return result;
    28 }
    29 
    30 DYNAMIC_API stringlist_t *stringlist_dup(const stringlist_t *src)
    31 {
    32     assert(src);
    33     if (src == NULL)
    34         return NULL;
    35 
    36     stringlist_t *dst = new_stringlist(src->value);
    37     if (dst == NULL)
    38         return NULL;
    39 
    40     stringlist_t* src_curr = src->next;
    41     stringlist_t** dst_curr_ptr = &dst->next;
    42     
    43     while (src_curr) {
    44         *dst_curr_ptr = new_stringlist(src_curr->value);
    45         if (*dst_curr_ptr == NULL) {
    46             free_stringlist(dst);
    47             return NULL;
    48         }
    49         src_curr = src_curr->next;
    50         dst_curr_ptr = &((*dst_curr_ptr)->next);
    51     }
    52 
    53     return dst;
    54 }
    55 
    56 static bool _stringlist_add_first(
    57         stringlist_t *stringlist,
    58         stringlist_t **result,
    59         const char *value
    60     )
    61 {  
    62     // empty list (no nodes)
    63     if (stringlist == NULL) {
    64         *result = new_stringlist(value);
    65         return true;
    66     }
    67 
    68     // empty list (one node, no value)
    69     if (stringlist->value == NULL) {
    70         if (stringlist->next) {
    71             *result = NULL; // invalid list
    72             return true;
    73         } 
    74             
    75         stringlist->value = strdup(value);
    76         assert(stringlist->value);
    77         
    78         if (stringlist->value == NULL) {
    79             *result = NULL;
    80             return true;
    81         }
    82         
    83         *result = stringlist;
    84         return true;
    85     }
    86     return false;
    87 }
    88 
    89 DYNAMIC_API stringlist_t *stringlist_add(
    90         stringlist_t *stringlist,
    91         const char *value
    92     )
    93 {  
    94     assert(value);
    95     if (value == NULL)
    96         return NULL;
    97 
    98     stringlist_t *result = NULL;
    99     if(_stringlist_add_first(stringlist, &result, value))
   100         return result;
   101     
   102     stringlist_t* list_curr = stringlist;
   103 
   104     while (list_curr->next)
   105         list_curr = list_curr->next;
   106      
   107     list_curr->next = new_stringlist(value);
   108 
   109     assert(list_curr->next);
   110     if (list_curr->next == NULL)
   111         return NULL;
   112 
   113     return list_curr->next;
   114 }
   115 
   116 stringlist_t* stringlist_search(stringlist_t* head, const char* value) {
   117     if (!head || !value || !head->value)
   118         return NULL;
   119     stringlist_t* retval = NULL;
   120     
   121     stringlist_t* curr = head;
   122     for (; curr ; curr = curr->next) {
   123         if (strcmp(curr->value, value) == 0) {
   124             retval = curr;
   125             break;
   126         }    
   127     }
   128     return retval;
   129 }
   130 
   131 
   132 DYNAMIC_API stringlist_t *stringlist_add_unique(
   133         stringlist_t *stringlist,
   134         const char *value
   135     )
   136 {  
   137     assert(value);
   138     if (value == NULL)
   139         return NULL;
   140 
   141     stringlist_t *result = NULL;
   142 
   143     if(_stringlist_add_first(stringlist, &result, value))
   144         return result;
   145 
   146     if (!stringlist)
   147         return NULL; // If the previous call fails somehow. this code is bizarre.
   148 
   149     stringlist_t* list_curr = stringlist;
   150 
   151     stringlist_t** next_ptr_addr = NULL;
   152 
   153     while (list_curr) {
   154         next_ptr_addr = &list_curr->next;
   155         if (strcmp(list_curr->value, value) == 0)
   156             return list_curr;
   157         list_curr = list_curr->next;
   158     }
   159 
   160     if (!next_ptr_addr)
   161         return NULL; // This is an error, because stringlist_add_first should
   162                      // have handled this case
   163 
   164     *next_ptr_addr = new_stringlist(value);
   165 
   166     if (!*next_ptr_addr)
   167         return NULL;
   168 
   169     return *next_ptr_addr;
   170 
   171 }
   172 
   173 
   174 DYNAMIC_API stringlist_t *stringlist_append(
   175         stringlist_t *stringlist,
   176         stringlist_t *second
   177     )
   178 {
   179     assert(stringlist);
   180     if (stringlist == NULL)
   181         return NULL;
   182 
   183     // Second list is empty
   184     if (second == NULL || second->value == NULL)
   185         return stringlist;
   186 
   187     stringlist_t *_s = stringlist;
   188 
   189     if (stringlist == second) {
   190         // Passing in the same pointer twice is not cool.
   191         // Since the semantics are to copy the second list,
   192         // we'll just do that, presuming that the
   193         // caller wants this.
   194         second = stringlist_dup(stringlist);
   195 
   196         stringlist_t** end_ptr = NULL;
   197 
   198         while (_s) {
   199             end_ptr = &_s->next;
   200             _s = _s->next;
   201         }
   202         if (!end_ptr)
   203             return NULL;
   204         *end_ptr = second;
   205 
   206         return stringlist;
   207     }
   208 
   209     stringlist_t *_s2;
   210     for (_s2 = second; _s2 != NULL; _s2 = _s2->next) {
   211         _s = stringlist_add(_s, _s2->value);
   212         if (_s == NULL)
   213             return NULL;
   214     }
   215     return _s;
   216 }
   217 
   218 DYNAMIC_API int stringlist_length(const stringlist_t *stringlist)
   219 {
   220     int len = 0;
   221 
   222     const stringlist_t *_sl;
   223     for (_sl = stringlist; _sl && _sl->value; _sl = _sl->next)
   224         len++;
   225 
   226     return len;
   227 }
   228 
   229 DYNAMIC_API stringlist_t *stringlist_delete(
   230         stringlist_t *stringlist,
   231         const char *value
   232     )
   233 {
   234     assert(stringlist);
   235     assert(value);
   236 
   237     if (stringlist->value == NULL) {
   238         free_stringlist(stringlist);
   239         return NULL;
   240     }
   241 
   242     if (value == NULL)
   243         return stringlist;
   244 
   245     stringlist_t *_sl;
   246     stringlist_t *last = NULL;
   247     for (_sl = stringlist; _sl && _sl->value; _sl = _sl->next) {
   248         if (strcmp(_sl->value, value) == 0) {
   249             if (last == NULL)
   250                 stringlist = stringlist->next;
   251             else
   252                 last->next = _sl->next;
   253             _sl->next = NULL;
   254             free_stringlist(_sl);
   255             break;
   256         }
   257         last = _sl;
   258     }
   259     return stringlist;
   260 }
   261 
   262 static stringlist_t* stringlist_multi_delete(stringlist_t* stringlist, const char* value) {
   263     if (stringlist == NULL || !stringlist->value)
   264         return stringlist;
   265     
   266     stringlist_t* list_curr = stringlist;
   267     stringlist_t* prev_ptr = NULL;
   268     
   269     while (list_curr) {
   270         if (strcmp(list_curr->value, value) == 0) {
   271             stringlist_t* victim = list_curr;
   272             if (prev_ptr)
   273                 prev_ptr->next = list_curr->next;    
   274             else
   275                 stringlist = list_curr->next;
   276             
   277             list_curr = list_curr->next;
   278 
   279             victim->next = NULL;
   280             
   281             free_stringlist(victim);
   282         }
   283         else {
   284             prev_ptr = list_curr;
   285             list_curr = list_curr->next;
   286         }
   287     }
   288     return stringlist;
   289 }
   290 
   291 
   292 
   293 void dedup_stringlist(stringlist_t* stringlist) {
   294     if (stringlist == NULL || !stringlist->value)
   295         return;
   296         
   297     stringlist_t* list_curr = stringlist;
   298 
   299     while (list_curr && list_curr->next) {
   300         stringlist_t* new_next = stringlist_multi_delete(list_curr->next, list_curr->value);
   301         list_curr->next = new_next;
   302         list_curr = list_curr->next;
   303     }    
   304 }
   305 
   306 DYNAMIC_API void free_stringlist(stringlist_t *stringlist)
   307 {
   308     stringlist_t *curr = stringlist;
   309     
   310     while (curr) {
   311         stringlist_t *next = curr->next;
   312         free(curr->value);
   313         curr->value = NULL;
   314         free(curr);
   315         curr = next;
   316     }
   317 }
   318 
   319 char* stringlist_to_string(stringlist_t* list) {
   320     if (!list)
   321         return NULL;
   322     
   323     unsigned int size = 0;
   324     unsigned int count = 0;
   325     stringlist_t* curr;
   326 
   327     // calc size
   328     for (curr = list; curr; curr = curr->next) {
   329         if (!curr->value)
   330             return NULL;
   331         size += strlen(curr->value);
   332         count++;
   333     }    
   334     
   335     size += (count - 1) + 1;
   336     
   337     char* retval = calloc(size, 1);
   338     
   339     int i;
   340     strlcpy(retval, list->value, size);
   341     
   342     for (i = 1, curr = list->next; curr && (i < count); i++, curr = curr->next) {
   343         strlcat(retval, ",", size);
   344         strlcat(retval, curr->value, size);
   345     }
   346     
   347     return retval;
   348 }
   349 
   350 stringlist_t* string_to_stringlist(const char* str) {
   351     if (!str || str[0] == '\0')
   352         return NULL;
   353         
   354     // Because of strtok, we do this
   355     char* workstr = strdup(str);
   356     if (!workstr)
   357         return NULL;
   358         
   359     char* token = strtok(workstr, ",");
   360     stringlist_t* retval = new_stringlist(NULL);
   361     
   362     while (token) {
   363         if (token && token[0] != '\0')
   364             stringlist_add(retval, token);
   365         token = strtok(NULL, ",");
   366     }    
   367     free(workstr);
   368     
   369     if (!retval->value) {
   370         free_stringlist(retval);
   371         retval = NULL;
   372     }
   373     return retval;
   374 }