common: Add new helper function, strsplit.
authorNeal H. Walfield <neal@g10code.de>
Thu, 12 Mar 2015 12:03:50 +0000 (13:03 +0100)
committerNeal H. Walfield <neal@g10code.de>
Mon, 23 Mar 2015 18:58:25 +0000 (19:58 +0100)
* common/stringhelp.h (strsplit): New declaration.
* common/stringhelp.c (strsplit): New function.
* common/t-stringhelp.c (test_strsplit): New function.
(main): Call it here.

--
Signed-off-by: Neal H. Walfield <neal@g10code.de>
common/stringhelp.c
common/stringhelp.h
common/t-stringhelp.c

index 42e1bcb..61386cc 100644 (file)
@@ -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 <windows.h>
 #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;
+}
index ffef2d5..864a689 100644 (file)
@@ -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*/
index dcd5a45..f5b6cd9 100644 (file)
@@ -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;