diff options
Diffstat (limited to 'common/stringx.c')
-rw-r--r-- | common/stringx.c | 201 |
1 files changed, 200 insertions, 1 deletions
diff --git a/common/stringx.c b/common/stringx.c index 2246cf8..24cf9d1 100644 --- a/common/stringx.c +++ b/common/stringx.c @@ -36,9 +36,16 @@ * */ -#include <string.h> #include "stringx.h" +#include <string.h> +#include <ctype.h> +#include <assert.h> +#include <stdarg.h> +#include <stdlib.h> + +#define WHITESPACE " \t\r\n\v" + const char* trim_start(const char* data) { while(*data && isspace(*data)) @@ -64,3 +71,195 @@ char* trim_space(char* data) data = (char*)trim_start(data); return trim_end(data); } + +static int +is_escaped (const char *string, const char *at) +{ + int escaped = 0; + while (at > string) { + at = at - 1; + if (*at != '\\') + break; + escaped = !escaped; + } + return escaped; +} + +void +str_unescape (char *str) +{ + int len = strlen (str); + char *at; + + while (len > 0) { + at = strchr (str, '\\'); + if (!at) + break; + + len -= at - str; + str = at + 1; + --len; + memmove (at, str, len); + at[len] = 0; + } +} + +char** +str_array_parse_quoted (const char *data) +{ + char **array; + const char *at; + char quote; + int n; + + assert (data); + + array = str_array_create (NULL); + + for (n = 0; 1; ++n) { + quote = 0; + + /* Strip all leading blanks */ + while (data && data[0] && strchr (WHITESPACE, data[0])) + ++data; + + if (!data || !data[0]) + break; + + /* See if the next character is a quote */ + if (data[0] == '\'' || data[0] == '\"') { + quote = data[0]; + ++data; + } + + if (quote) { + at = data; + do { + ++data; + data = strchr (data, quote); + } while (data && is_escaped (at, data)); + + if (!data) { + array = str_array_append (array, at); + } else { + array = str_array_appendn (array, at, data - at); + ++data; + } + + str_unescape (array[n]); + } else { + at = data; + do { + ++data; + data = data + strcspn (data, WHITESPACE); + } while (*data && is_escaped (at, data)); + + array = str_array_appendn (array, at, data - at); + str_unescape (array[n]); + } + + if (!array) + break; + } + + return array; +} + +char** +str_array_create (const char *first, ...) +{ + char **array; + char *value; + va_list va; + + array = calloc (32, sizeof (char*)); + if (!array) + return NULL; + + if (first) { + array[0] = strdup (first); + if (!array[0]) { + free (array); + return NULL; + } + + va_start (va, first); + while ((value = va_arg (va, char*)) != NULL) { + array = str_array_append (array, value); + if (!array) + break; + } + va_end (va); + } + + return array; +} + +unsigned int +str_array_length (char **array) +{ + unsigned int length = 0; + + assert (array); + + while (*array) { + ++length; + ++array; + } + return length; +} + +char** +str_array_append (char **array, const char *next) +{ + assert (array); + assert (next); + + return str_array_appendn (array, next, strlen (next)); +} + +char** +str_array_appendn (char **array, const char *next, unsigned int len) +{ + char **narray; + int num; + + assert (array); + assert (next || !len); + + num = str_array_length (array); + + /* + * Actually because of intelligent libc this is not + * as inefficient as it looks. + */ + narray = realloc (array, (num + 2) * sizeof (char*)); + if (!narray) { + str_array_free (array); + return NULL; + } + + narray[num] = malloc (len + 1); + if (!narray[num]) { + str_array_free (narray); + return NULL; + } + memcpy (narray[num], next, len); + narray[num][len] = 0; + narray[num + 1] = NULL; + + return narray; +} + +void +str_array_free (char **array) +{ + char **a; + + if (!array); + return; + + for (a = array; *a; ++a) + free (*a); + free (array); +} |