You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pEpEngine/src/stringlist.c

412 lines
9.1 KiB
C

/**
* @file stringlist.c
* @brief File description for doxygen missing. FIXME
* @license This file is under GNU General Public License 3.0
* see LICENSE.txt
*/
8 years ago
#include "pEp_internal.h"
8 years ago
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "stringlist.h"
DYNAMIC_API stringlist_t *new_stringlist(const char *value)
{
8 years ago
stringlist_t *result = calloc(1, sizeof(stringlist_t));
8 years ago
assert(result);
8 years ago
if (result && value) {
result->value = strdup(value);
assert(result->value);
4 years ago
if (!result->value) {
8 years ago
free(result);
return NULL;
}
}
8 years ago
8 years ago
return result;
}
DYNAMIC_API stringlist_t *stringlist_dup(const stringlist_t *src)
{
assert(src);
if (src == NULL)
return NULL;
stringlist_t *dst = new_stringlist(src->value);
if (dst == NULL)
return NULL;
stringlist_t* src_curr = src->next;
stringlist_t** dst_curr_ptr = &dst->next;
while (src_curr) {
*dst_curr_ptr = new_stringlist(src_curr->value);
if (*dst_curr_ptr == NULL) {
free_stringlist(dst);
return NULL;
}
src_curr = src_curr->next;
dst_curr_ptr = &((*dst_curr_ptr)->next);
8 years ago
}
return dst;
}
/**
* @internal
*
* <!-- _stringlist_add_first() -->
*
* @brief TODO
*
* @param[in] *stringlist stringlist_t
* @param[in] **result stringlist_t
* @param[in] *value constchar
*
*/
static bool _stringlist_add_first(
8 years ago
stringlist_t *stringlist,
stringlist_t **result,
8 years ago
const char *value
)
{
// empty list (no nodes)
if (stringlist == NULL) {
*result = new_stringlist(value);
return true;
}
8 years ago
// empty list (one node, no value)
if (stringlist->value == NULL) {
if (stringlist->next) {
*result = NULL; // invalid list
return true;
}
stringlist->value = strdup(value);
assert(stringlist->value);
if (stringlist->value == NULL) {
*result = NULL;
return true;
}
*result = stringlist;
return true;
8 years ago
}
return false;
}
DYNAMIC_API stringlist_t *stringlist_add(
stringlist_t *stringlist,
const char *value
)
{
assert(value);
if (value == NULL)
return NULL;
stringlist_t *result = NULL;
if(_stringlist_add_first(stringlist, &result, value))
return result;
stringlist_t* list_curr = stringlist;
while (list_curr->next)
list_curr = list_curr->next;
list_curr->next = new_stringlist(value);
8 years ago
assert(list_curr->next);
if (list_curr->next == NULL)
8 years ago
return NULL;
return list_curr->next;
8 years ago
}
stringlist_t* stringlist_search(stringlist_t* head, const char* value) {
if (!head || !value || !head->value)
return NULL;
stringlist_t* retval = NULL;
stringlist_t* curr = head;
for (; curr ; curr = curr->next) {
if (strcmp(curr->value, value) == 0) {
retval = curr;
break;
}
}
return retval;
}
DYNAMIC_API stringlist_t *stringlist_add_unique(
stringlist_t *stringlist,
const char *value
)
{
assert(value);
if (value == NULL)
return NULL;
stringlist_t *result = NULL;
if(_stringlist_add_first(stringlist, &result, value))
return result;
if (!stringlist)
return NULL; // If the previous call fails somehow. this code is bizarre.
stringlist_t* list_curr = stringlist;
stringlist_t** next_ptr_addr = NULL;
while (list_curr) {
next_ptr_addr = &list_curr->next;
if (strcmp(list_curr->value, value) == 0)
return list_curr;
list_curr = list_curr->next;
}
if (!next_ptr_addr)
return NULL; // This is an error, because stringlist_add_first should
// have handled this case
*next_ptr_addr = new_stringlist(value);
if (!*next_ptr_addr)
return NULL;
return *next_ptr_addr;
}
8 years ago
DYNAMIC_API stringlist_t *stringlist_append(
stringlist_t *stringlist,
stringlist_t *second
)
8 years ago
{
assert(stringlist);
if (stringlist == NULL)
return NULL;
8 years ago
// Second list is empty
8 years ago
if (second == NULL || second->value == NULL)
return stringlist;
stringlist_t *_s = stringlist;
if (stringlist == second) {
// Passing in the same pointer twice is not cool.
// Since the semantics are to copy the second list,
// we'll just do that, presuming that the
// caller wants this.
second = stringlist_dup(stringlist);
stringlist_t** end_ptr = NULL;
while (_s) {
end_ptr = &_s->next;
_s = _s->next;
}
if (!end_ptr)
return NULL;
*end_ptr = second;
return stringlist;
}
8 years ago
stringlist_t *_s2;
for (_s2 = second; _s2 != NULL; _s2 = _s2->next) {
_s = stringlist_add(_s, _s2->value);
if (_s == NULL)
return NULL;
}
return _s;
}
DYNAMIC_API int stringlist_length(const stringlist_t *stringlist)
{
8 years ago
int len = 0;
8 years ago
8 years ago
const stringlist_t *_sl;
for (_sl = stringlist; _sl && _sl->value; _sl = _sl->next)
len++;
8 years ago
return len;
}
DYNAMIC_API stringlist_t *stringlist_delete(
stringlist_t *stringlist,
const char *value
)
{
assert(stringlist);
assert(value);
if (stringlist->value == NULL) {
free_stringlist(stringlist);
return NULL;
}
if (value == NULL)
return stringlist;
stringlist_t *_sl;
stringlist_t *last = NULL;
for (_sl = stringlist; _sl && _sl->value; _sl = _sl->next) {
if (strcmp(_sl->value, value) == 0) {
if (last == NULL)
stringlist = stringlist->next;
else
last->next = _sl->next;
_sl->next = NULL;
free_stringlist(_sl);
break;
}
last = _sl;
}
return stringlist;
}
/**
* @internal
*
* <!-- stringlist_multi_delete() -->
*
* @brief TODO
*
* @param[in] *stringlist stringlist_t
* @param[in] *value constchar
*
*/
static stringlist_t* stringlist_multi_delete(stringlist_t* stringlist, const char* value) {
if (stringlist == NULL || !stringlist->value)
return stringlist;
stringlist_t* list_curr = stringlist;
stringlist_t* prev_ptr = NULL;
while (list_curr) {
if (strcmp(list_curr->value, value) == 0) {
stringlist_t* victim = list_curr;
if (prev_ptr)
prev_ptr->next = list_curr->next;
else
stringlist = list_curr->next;
list_curr = list_curr->next;
victim->next = NULL;
free_stringlist(victim);
}
else {
prev_ptr = list_curr;
list_curr = list_curr->next;
}
}
return stringlist;
}
void dedup_stringlist(stringlist_t* stringlist) {
if (stringlist == NULL || !stringlist->value)
return;
stringlist_t* list_curr = stringlist;
while (list_curr && list_curr->next) {
stringlist_t* new_next = stringlist_multi_delete(list_curr->next, list_curr->value);
list_curr->next = new_next;
list_curr = list_curr->next;
}
}
8 years ago
DYNAMIC_API void free_stringlist(stringlist_t *stringlist)
{
stringlist_t *curr = stringlist;
while (curr) {
stringlist_t *next = curr->next;
free(curr->value);
curr->value = NULL;
free(curr);
curr = next;
8 years ago
}
}
char* stringlist_to_string(stringlist_t* list) {
if (!list)
return NULL;
unsigned int size = 0;
unsigned int count = 0;
stringlist_t* curr;
// calc size
for (curr = list; curr; curr = curr->next) {
if (!curr->value)
return NULL;
size += strlen(curr->value);
count++;
}
size += (count - 1) + 1;
char* retval = calloc(size, 1);
int i;
strlcpy(retval, list->value, size);
for (i = 1, curr = list->next; curr && (i < count); i++, curr = curr->next) {
strlcat(retval, ",", size);
strlcat(retval, curr->value, size);
}
return retval;
}
stringlist_t* string_to_stringlist(const char* str) {
if (!str || str[0] == '\0')
return NULL;
// Because of strtok, we do this
char* workstr = strdup(str);
if (!workstr)
return NULL;
char* token = strtok(workstr, ",");
stringlist_t* retval = new_stringlist(NULL);
while (token) {
if (token && token[0] != '\0')
stringlist_add(retval, token);
token = strtok(NULL, ",");
}
free(workstr);
if (!retval->value) {
free_stringlist(retval);
retval = NULL;
}
return retval;
}
stringlist_t* stringlist_get_tail(stringlist_t* sl) {
if (!sl || !sl->value) // empty string is a value, yes?
return NULL;
while (sl->next) {
sl = sl->next;
}
return sl;
}