src/stringlist.c
author Krista 'DarthMama' Bennett <krista@pep.foundation>
Tue, 25 Feb 2020 17:12:54 +0100
branchsync
changeset 4455 a44a569fa869
parent 3610 97033a138011
child 4071 68f242584e18
permissions -rw-r--r--
Fix for list_keys - : now means possible URI. We need to talk about whether or not we need some sort of address enforcement so this is less of a heuristic.
     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 = head;
   120     for (; retval ; retval = retval->next) {
   121         if (strcmp(retval->value, value) == 0)
   122             break;
   123     }
   124     return retval;
   125 }
   126 
   127 DYNAMIC_API stringlist_t *stringlist_add_unique(
   128         stringlist_t *stringlist,
   129         const char *value
   130     )
   131 {  
   132     assert(value);
   133     if (value == NULL)
   134         return NULL;
   135 
   136     stringlist_t *result = NULL;
   137     if(_stringlist_add_first(stringlist, &result, value))
   138         return result;
   139     
   140     stringlist_t* list_curr = stringlist;
   141 
   142     bool found = false;
   143     while (list_curr->next) {
   144         if(strcmp(list_curr->value,value)==0)
   145             found = true;
   146         list_curr = list_curr->next;
   147     }
   148     if(strcmp(list_curr->value,value)==0)
   149         found = true;
   150 
   151     if (!found) {
   152         list_curr->next = new_stringlist(value);
   153 
   154         assert(list_curr->next);
   155         if (list_curr->next == NULL)
   156             return NULL;
   157 
   158         return list_curr->next;
   159     } else {
   160         return list_curr;
   161     }
   162 }
   163 
   164 
   165 DYNAMIC_API stringlist_t *stringlist_append(
   166         stringlist_t *stringlist,
   167         stringlist_t *second
   168     )
   169 {
   170     assert(stringlist);
   171     if (stringlist == NULL)
   172         return NULL;
   173 
   174     // Second list is empty
   175     if (second == NULL || second->value == NULL)
   176         return stringlist;
   177 
   178     stringlist_t *_s = stringlist;
   179     stringlist_t *_s2;
   180     for (_s2 = second; _s2 != NULL; _s2 = _s2->next) {
   181         _s = stringlist_add(_s, _s2->value);
   182         if (_s == NULL)
   183             return NULL;
   184     }
   185     return _s;
   186 }
   187 
   188 DYNAMIC_API int stringlist_length(const stringlist_t *stringlist)
   189 {
   190     int len = 0;
   191 
   192     const stringlist_t *_sl;
   193     for (_sl = stringlist; _sl && _sl->value; _sl = _sl->next)
   194         len++;
   195 
   196     return len;
   197 }
   198 
   199 DYNAMIC_API stringlist_t *stringlist_delete(
   200         stringlist_t *stringlist,
   201         const char *value
   202     )
   203 {
   204     assert(stringlist);
   205     assert(value);
   206 
   207     if (stringlist->value == NULL) {
   208         free_stringlist(stringlist);
   209         return NULL;
   210     }
   211 
   212     if (value == NULL)
   213         return stringlist;
   214 
   215     stringlist_t *_sl;
   216     stringlist_t *last = NULL;
   217     for (_sl = stringlist; _sl && _sl->value; _sl = _sl->next) {
   218         if (strcmp(_sl->value, value) == 0) {
   219             if (last == NULL)
   220                 stringlist = stringlist->next;
   221             else
   222                 last->next = _sl->next;
   223             _sl->next = NULL;
   224             free_stringlist(_sl);
   225             break;
   226         }
   227         last = _sl;
   228     }
   229     return stringlist;
   230 }
   231 
   232 static stringlist_t* stringlist_multi_delete(stringlist_t* stringlist, const char* value) {
   233     if (stringlist == NULL || !stringlist->value)
   234         return stringlist;
   235     
   236     stringlist_t* list_curr = stringlist;
   237     stringlist_t* prev_ptr = NULL;
   238     
   239     while (list_curr) {
   240         if (strcmp(list_curr->value, value) == 0) {
   241             stringlist_t* victim = list_curr;
   242             if (prev_ptr)
   243                 prev_ptr->next = list_curr->next;    
   244             else
   245                 stringlist = list_curr->next;
   246             
   247             list_curr = list_curr->next;
   248 
   249             victim->next = NULL;
   250             
   251             free_stringlist(victim);
   252         }
   253         else {
   254             prev_ptr = list_curr;
   255             list_curr = list_curr->next;
   256         }
   257     }
   258     return stringlist;
   259 }
   260 
   261 
   262 
   263 void dedup_stringlist(stringlist_t* stringlist) {
   264     if (stringlist == NULL || !stringlist->value)
   265         return;
   266         
   267     stringlist_t* list_curr = stringlist;
   268 
   269     while (list_curr && list_curr->next) {
   270         stringlist_t* new_next = stringlist_multi_delete(list_curr->next, list_curr->value);
   271         list_curr->next = new_next;
   272         list_curr = list_curr->next;
   273     }    
   274 }
   275 
   276 DYNAMIC_API void free_stringlist(stringlist_t *stringlist)
   277 {
   278     stringlist_t *curr = stringlist;
   279     
   280     while (curr) {
   281         stringlist_t *next = curr->next;
   282         free(curr->value);
   283         curr->value = NULL;
   284         free(curr);
   285         curr = next;
   286     }
   287 }