utils: Add strreplace function
authorTobias Brunner <tobias@strongswan.org>
Fri, 22 Nov 2013 09:30:16 +0000 (10:30 +0100)
committerTobias Brunner <tobias@strongswan.org>
Thu, 23 Jan 2014 09:18:23 +0000 (10:18 +0100)
src/libstrongswan/tests/suites/test_utils.c
src/libstrongswan/utils/utils.c
src/libstrongswan/utils/utils.h

index 3ca0412..2d290f8 100644 (file)
@@ -385,6 +385,89 @@ START_TEST(test_translate)
 END_TEST
 
 /*******************************************************************************
+ * strreplace
+ */
+
+static struct {
+       char *in;
+       char *out;
+       char *search;
+       char *replace;
+       bool allocated;
+} strreplace_data[] = {
+       /* invalid arguments */
+       {NULL, NULL, NULL, NULL, FALSE},
+       {"", "", NULL, NULL, FALSE},
+       {"", "", "", NULL, FALSE},
+       {"", "", NULL, "", FALSE},
+       {"", "", "", "", FALSE},
+       {"", "", "", "asdf", FALSE},
+       {"", "", "asdf", "", FALSE},
+       {"asdf", "asdf", NULL, NULL, FALSE},
+       {"asdf", "asdf", "", NULL, FALSE},
+       {"asdf", "asdf", NULL, "", FALSE},
+       {"asdf", "asdf", "", "", FALSE},
+       {"asdf", "asdf", "", "asdf", FALSE},
+       {"asdf", "asdf", "asdf", NULL, FALSE},
+       {"qwer", "qwer", "", "asdf", FALSE},
+       /* replacement shorter */
+       {"asdf", "", "asdf", "", TRUE},
+       {"asdfasdf", "", "asdf", "", TRUE},
+       {"asasdfdf", "asdf", "asdf", "", TRUE},
+       {"asdf", "df", "as", "", TRUE},
+       {"asdf", "as", "df", "", TRUE},
+       {"qwer", "qwer", "asdf", "", FALSE},
+       /* replacement same length */
+       {"a", "b", "a", "b", TRUE},
+       {"aaa", "bbb", "a", "b", TRUE},
+       {"aaa", "bbb", "aaa", "bbb", TRUE},
+       {"asdf", "asdf", "asdf", "asdf", TRUE},
+       {"qwer", "qwer", "asdf", "asdf", FALSE},
+       /* replacement longer */
+       {"asdf", "asdf", "", "asdf", FALSE},
+       {"asdf", "asdfasdf", "asdf", "asdfasdf", TRUE},
+       {"asdf", "asdfsdf", "a", "asdf", TRUE},
+       {"asdf", "asdasdf", "f", "asdf", TRUE},
+       {"aaa", "asdfasdfasdf", "a", "asdf", TRUE},
+       {"qwer", "qwer", "asdf", "asdfasdf", FALSE},
+       /* real examples */
+       {"http://x.org/no/spaces", "http://x.org/no/spaces", " ", "%20", FALSE},
+       {"http://x.org/end ", "http://x.org/end%20", " ", "%20", TRUE},
+       {" http://x.org/start", "%20http://x.org/start", " ", "%20", TRUE},
+       {" http://x.org/both ", "%20http://x.org/both%20", " ", "%20", TRUE},
+       {"http://x.org/ /slash", "http://x.org/%20/slash", " ", "%20", TRUE},
+       {"http://x.org/   /three", "http://x.org/%20%20%20/three", " ", "%20", TRUE},
+       {"http://x.org/      ", "http://x.org/%20%20%20%20%20%20", " ", "%20", TRUE},
+       {"http://x.org/%20/encoded", "http://x.org/%20/encoded", " ", "%20", FALSE},
+};
+
+START_TEST(test_strreplace)
+{
+       char *ret;
+
+       ret = strreplace(strreplace_data[_i].in, strreplace_data[_i].search,
+                                        strreplace_data[_i].replace);
+       if (ret && strreplace_data[_i].out)
+       {
+               ck_assert_str_eq(ret, strreplace_data[_i].out);
+       }
+       else
+       {
+               ck_assert(ret == strreplace_data[_i].out);
+       }
+       if (strreplace_data[_i].allocated)
+       {
+               ck_assert(ret != strreplace_data[_i].in);
+               free(ret);
+       }
+       else
+       {
+               ck_assert(ret == strreplace_data[_i].in);
+       }
+}
+END_TEST
+
+/*******************************************************************************
  * time_printf_hook
  */
 
@@ -543,6 +626,10 @@ Suite *utils_suite_create()
        tcase_add_loop_test(tc, test_translate, 0, countof(translate_data));
        suite_add_tcase(s, tc);
 
+       tc = tcase_create("strreplace");
+       tcase_add_loop_test(tc, test_strreplace, 0, countof(strreplace_data));
+       suite_add_tcase(s, tc);
+
        tc = tcase_create("printf_hooks");
        tcase_add_loop_test(tc, test_time_printf_hook, 0, countof(time_data));
        tcase_add_loop_test(tc, test_time_delta_printf_hook, 0, countof(time_delta_data));
index 4bacb58..77d8754 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2012 Tobias Brunner
+ * Copyright (C) 2008-2013 Tobias Brunner
  * Copyright (C) 2005-2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -144,6 +144,58 @@ char* translate(char *str, const char *from, const char *to)
 /**
  * Described in header.
  */
+char* strreplace(const char *str, const char *search, const char *replace)
+{
+       size_t len, slen, rlen, count = 0;
+       char *res, *pos, *found, *dst;
+
+       if (!str || !*str || !search || !*search || !replace)
+       {
+               return (char*)str;
+       }
+       slen = strlen(search);
+       rlen = strlen(replace);
+       if (slen != rlen)
+       {
+               for (pos = (char*)str; (pos = strstr(pos, search)); pos += slen)
+               {
+                       found = pos;
+                       count++;
+               }
+               if (!count)
+               {
+                       return (char*)str;
+               }
+               len = (found - str) + strlen(found) + count * (rlen - slen);
+       }
+       else
+       {
+               len = strlen(str);
+       }
+       found = strstr(str, search);
+       if (!found)
+       {
+               return (char*)str;
+       }
+       dst = res = malloc(len + 1);
+       pos = (char*)str;
+       do
+       {
+               len = found - pos;
+               memcpy(dst, pos, len);
+               dst += len;
+               memcpy(dst, replace, rlen);
+               dst += rlen;
+               pos = found + slen;
+       }
+       while ((found = strstr(pos, search)));
+       strcpy(dst, pos);
+       return res;
+}
+
+/**
+ * Described in header.
+ */
 bool mkdir_p(const char *path, mode_t mode)
 {
        int len;
index cda7edf..7e4bfb2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2012 Tobias Brunner
+ * Copyright (C) 2008-2013 Tobias Brunner
  * Copyright (C) 2008 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -472,6 +472,20 @@ void *memstr(const void *haystack, const char *needle, size_t n);
 char *translate(char *str, const char *from, const char *to);
 
 /**
+ * Replaces all occurences of search in the given string with replace.
+ *
+ * Allocates memory only if anything is replaced in the string.  The original
+ * string is also returned if any of the arguments are invalid (e.g. if search
+ * is empty or any of them are NULL).
+ *
+ * @param str          original string
+ * @param search       string to search for and replace
+ * @param replace      string to replace found occurences with
+ * @return                     allocated string, if anything got replaced, str otherwise
+ */
+char *strreplace(const char *str, const char *search, const char *replace);
+
+/**
  * Creates a directory and all required parent directories.
  *
  * @param path         path to the new directory