diff --git a/common/stringhelp.c b/common/stringhelp.c index 42e1bcbbb..61386cc38 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -2,6 +2,7 @@ * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, * 2008, 2009, 2010 Free Software Foundation, Inc. * Copyright (C) 2014 Werner Koch + * Copyright (C) 2015 g10 Code GmbH * * This file is part of JNLIB, which is a subsystem of GnuPG. * @@ -48,6 +49,7 @@ # include #endif +#include "util.h" #include "libjnlib-config.h" #include "utf8conv.h" #include "sysutils.h" @@ -1196,3 +1198,39 @@ xstrconcat (const char *s1, ...) } return result; } + +/* Split a string into fields at DELIM. REPLACEMENT is the character + to replace the delimiter with (normally: '\0' so that each field is + NUL terminated). The caller is responsible for freeing the result. + Note: this function modifies STRING! If you need the original + value, then you should pass a copy to this function. + + If malloc fails, this function returns NULL. */ +char ** +strsplit (char *string, char delim, char replacement, int *count) +{ + int fields = 1; + char *t; + char **result; + + /* First, count the number of fields. */ + for (t = strchr (string, delim); t; t = strchr (t + 1, delim)) + fields ++; + + result = xtrycalloc (sizeof (*result), (fields + 1)); + if (! result) + return NULL; + + result[0] = string; + fields = 1; + for (t = strchr (string, delim); t; t = strchr (t + 1, delim)) + { + result[fields ++] = t + 1; + *t = replacement; + } + + if (count) + *count = fields; + + return result; +} diff --git a/common/stringhelp.h b/common/stringhelp.h index ffef2d52f..864a6893b 100644 --- a/common/stringhelp.h +++ b/common/stringhelp.h @@ -1,6 +1,7 @@ /* stringhelp.h * Copyright (C) 1998, 1999, 2000, 2001, 2003, * 2006, 2007, 2009 Free Software Foundation, Inc. + * 2015 g10 Code GmbH * * This file is part of JNLIB, which is a subsystem of GnuPG. * @@ -142,9 +143,9 @@ char *strconcat (const char *s1, ...) GNUPG_GCC_A_SENTINEL(0); /* Ditto, but die on error. */ char *xstrconcat (const char *s1, ...) GNUPG_GCC_A_SENTINEL(0); +char **strsplit (char *string, char delim, char replacement, int *count); /*-- mapstrings.c --*/ const char *map_static_macro_string (const char *string); - #endif /*LIBJNLIB_STRINGHELP_H*/ diff --git a/common/t-stringhelp.c b/common/t-stringhelp.c index dcd5a453f..f5b6cd99e 100644 --- a/common/t-stringhelp.c +++ b/common/t-stringhelp.c @@ -1,5 +1,6 @@ /* t-stringhelp.c - Regression tests for stringhelp.c * Copyright (C) 2007 Free Software Foundation, Inc. + * 2015 g10 Code GmbH * * This file is part of JNLIB, which is a subsystem of GnuPG. * @@ -478,6 +479,62 @@ test_make_absfilename_try (void) xfree (cwd); } +static void +test_strsplit (void) +{ + int test_count = 0; + void test (const char *s, char delim, char replacement, + const char *fields_expected[]) + { + char *s2; + int field_count; + char **fields; + int field_count_expected; + int i; + + /* Count the fields. */ + for (field_count_expected = 0; + fields_expected[field_count_expected]; + field_count_expected ++) + ; + + test_count ++; + + /* We need to copy s since strsplit modifies it in place. */ + s2 = xstrdup (s); + fields = strsplit (s2, delim, replacement, &field_count); + + if (field_count != field_count_expected) + fail (test_count * 1000); + + for (i = 0; i < field_count_expected; i ++) + if (strcmp (fields_expected[i], fields[i]) != 0) + { + printf ("For field %d, expected '%s', but got '%s'\n", + i, fields_expected[i], fields[i]); + fail (test_count * 1000 + i + 1); + } + + xfree (s2); + } + + { + const char *expected_result[] = + { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL }; + test ("a:bc:cde:fghi:jklmn::foo:", ':', '\0', expected_result); + } + + { + const char *expected_result[] = + { "!a!bc!!def!", "a!bc!!def!", "bc!!def!", "!def!", "def!", "", NULL }; + test (",a,bc,,def,", ',', '!', expected_result); + } + + { + const char *expected_result[] = { "", NULL }; + test ("", ':', ',', expected_result); + } +} int main (int argc, char **argv) @@ -491,6 +548,7 @@ main (int argc, char **argv) test_xstrconcat (); test_make_filename_try (); test_make_absfilename_try (); + test_strsplit (); xfree (home_buffer); return 0;