diff options
-rw-r--r-- | common/stringhelp.c | 67 | ||||
-rw-r--r-- | common/stringhelp.h | 4 | ||||
-rw-r--r-- | common/t-stringhelp.c | 141 |
3 files changed, 212 insertions, 0 deletions
diff --git a/common/stringhelp.c b/common/stringhelp.c index ca8ae0bbc..6714eb8b9 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -48,6 +48,7 @@ # endif # include <windows.h> #endif +#include <assert.h> #include "util.h" #include "common-defs.h" @@ -1234,3 +1235,69 @@ strsplit (char *string, char delim, char replacement, int *count) return result; } + + +/* Tokenize STRING using the set of delimiters in DELIM. Leading + * spaces and tabs are removed from all tokens. The caller must xfree + * the result. + * + * Returns: A malloced and NULL delimited array with the tokens. On + * memory error NULL is returned and ERRNO is set. + */ +char ** +strtokenize (const char *string, const char *delim) +{ + const char *s; + size_t fields; + size_t bytes, n; + char *buffer; + char *p, *px, *pend; + char **result; + + /* Count the number of fields. */ + for (fields = 1, s = strpbrk (string, delim); s; s = strpbrk (s + 1, delim)) + fields++; + fields++; /* Add one for the terminating NULL. */ + + /* Allocate an array for all fields, a terminating NULL, and space + for a copy of the string. */ + bytes = fields * sizeof *result; + if (bytes / sizeof *result != fields) + { + gpg_err_set_errno (ENOMEM); + return NULL; + } + n = strlen (string) + 1; + bytes += n; + if (bytes < n) + { + gpg_err_set_errno (ENOMEM); + return NULL; + } + result = xtrymalloc (bytes); + if (!result) + return NULL; + buffer = (char*)(result + fields); + + /* Copy and parse the string. */ + strcpy (buffer, string); + for (n = 0, p = buffer; (pend = strpbrk (p, delim)); p = pend + 1) + { + *pend = 0; + while (spacep (p)) + p++; + for (px = pend - 1; px >= p && spacep (px); px--) + *px = 0; + result[n++] = p; + } + while (spacep (p)) + p++; + for (px = p + strlen (p) - 1; px >= p && spacep (px); px--) + *px = 0; + result[n++] = p; + result[n] = NULL; + + assert ((char*)(result + n + 1) == buffer); + + return result; +} diff --git a/common/stringhelp.h b/common/stringhelp.h index b9b51fd9c..ab16d169c 100644 --- a/common/stringhelp.h +++ b/common/stringhelp.h @@ -145,6 +145,10 @@ char *xstrconcat (const char *s1, ...) GNUPG_GCC_A_SENTINEL(0); char **strsplit (char *string, char delim, char replacement, int *count); +/* Tokenize STRING using the set of delimiters in DELIM. */ +char **strtokenize (const char *string, const char *delim); + + /*-- mapstrings.c --*/ const char *map_static_macro_string (const char *string); diff --git a/common/t-stringhelp.c b/common/t-stringhelp.c index 6c4723754..13f3afa74 100644 --- a/common/t-stringhelp.c +++ b/common/t-stringhelp.c @@ -538,6 +538,146 @@ test_strsplit (void) } } + + +static void +test_strtokenize (void) +{ + struct { + const char *s; + const char *delim; + const char *fields_expected[10]; + } tv[] = { + { + "", ":", + { "", NULL } + }, + { + "a", ":", + { "a", NULL } + }, + { + ":", ":", + { "", "", NULL } + }, + { + "::", ":", + { "", "", "", NULL } + }, + { + "a:b:c", ":", + { "a", "b", "c", NULL } + }, + { + "a:b:", ":", + { "a", "b", "", NULL } + }, + { + "a:b", ":", + { "a", "b", NULL } + }, + { + "aa:b:cd", ":", + { "aa", "b", "cd", NULL } + }, + { + "aa::b:cd", ":", + { "aa", "", "b", "cd", NULL } + }, + { + "::b:cd", ":", + { "", "", "b", "cd", NULL } + }, + { + "aa: : b:cd ", ":", + { "aa", "", "b", "cd", NULL } + }, + { + " aa: : b: cd ", ":", + { "aa", "", "b", "cd", NULL } + }, + { + " ", ":", + { "", NULL } + }, + { + " :", ":", + { "", "", NULL } + }, + { + " : ", ":", + { "", "", NULL } + }, + { + ": ", ":", + { "", "", NULL } + }, + { + ": x ", ":", + { "", "x", NULL } + }, + { + "a:bc:cde:fghi:jklmn::foo:", ":", + { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL } + }, + { + ",a,bc,,def,", ",", + { "", "a", "bc", "", "def", "", NULL } + }, + { + " a ", " ", + { "", "a", "", NULL } + }, + { + " ", " ", + { "", "", NULL } + }, + { + "", " ", + { "", NULL } + } + }; + + int tidx; + + for (tidx = 0; tidx < DIM(tv); tidx++) + { + char **fields; + int field_count; + int field_count_expected; + int i; + + for (field_count_expected = 0; + tv[tidx].fields_expected[field_count_expected]; + field_count_expected ++) + ; + + fields = strtokenize (tv[tidx].s, tv[tidx].delim); + if (!fields) + fail (tidx * 1000); + else + { + for (field_count = 0; fields[field_count]; field_count++) + ; + if (field_count != field_count_expected) + fail (tidx * 1000); + else + { + for (i = 0; i < field_count_expected; i++) + if (strcmp (tv[tidx].fields_expected[i], fields[i])) + { + printf ("For field %d, expected '%s', but got '%s'\n", + i, tv[tidx].fields_expected[i], fields[i]); + fail (tidx * 1000 + i + 1); + } + } + } + + xfree (fields); + } +} + + int main (int argc, char **argv) { @@ -551,6 +691,7 @@ main (int argc, char **argv) test_make_filename_try (); test_make_absfilename_try (); test_strsplit (); + test_strtokenize (); xfree (home_buffer); return 0; |