Add a virStringReplace method to virstring.{h,c} to perform
substring matching and replacement

Signed-off-by: Daniel P. Berrange <berra...@redhat.com>
---
 src/libvirt_private.syms |  1 +
 src/util/virstring.c     | 44 +++++++++++++++++++++++++++++++++++-
 src/util/virstring.h     |  5 ++++
 tests/virstringtest.c    | 59 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 108 insertions(+), 1 deletion(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index f26190d..f7379a2 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1794,6 +1794,7 @@ virStringArrayHasString;
 virStringFreeList;
 virStringJoin;
 virStringListLength;
+virStringReplace;
 virStringSearch;
 virStringSortCompare;
 virStringSortRevCompare;
diff --git a/src/util/virstring.c b/src/util/virstring.c
index 67a87d3..3e42b06 100644
--- a/src/util/virstring.c
+++ b/src/util/virstring.c
@@ -619,7 +619,6 @@ size_t virStringListLength(char **strings)
     return i;
 }
 
-
 /**
  * virStringSortCompare:
  *
@@ -747,3 +746,46 @@ cleanup:
     }
     return ret;
 }
+
+/**
+ * virStringReplace:
+ * @haystack: the source string to process
+ * @oldneedle: the substring to locate
+ * @newneedle: the substring to insert
+ *
+ * Search @haystack and replace all occurences of @oldneedle with @newneedle.
+ *
+ * Returns: a new string with all the replacements, or NULL on error
+ */
+char *
+virStringReplace(const char *haystack,
+                 const char *oldneedle,
+                 const char *newneedle)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    const char *tmp1, *tmp2;
+    size_t oldneedlelen = strlen(oldneedle);
+    size_t newneedlelen = strlen(newneedle);
+
+    tmp1 = haystack;
+    tmp2 = NULL;
+
+    while (tmp1) {
+        tmp2 = strstr(tmp1, oldneedle);
+
+        if (tmp2) {
+            virBufferAdd(&buf, tmp1, (tmp2 - tmp1));
+            virBufferAdd(&buf, newneedle, newneedlelen);
+            tmp2 += oldneedlelen;
+        } else {
+            virBufferAdd(&buf, tmp1, -1);
+        }
+
+        tmp1 = tmp2;
+    }
+
+    if (virBufferError(&buf))
+        return NULL;
+
+    return virBufferContentAndReset(&buf);
+}
diff --git a/src/util/virstring.h b/src/util/virstring.h
index 8efc80c..5b77581 100644
--- a/src/util/virstring.h
+++ b/src/util/virstring.h
@@ -232,5 +232,10 @@ ssize_t virStringSearch(const char *str,
                         char ***matches)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4);
 
+char *virStringReplace(const char *haystack,
+                       const char *oldneedle,
+                       const char *newneedle)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+
 
 #endif /* __VIR_STRING_H__ */
diff --git a/tests/virstringtest.c b/tests/virstringtest.c
index b8c6115..43023d5 100644
--- a/tests/virstringtest.c
+++ b/tests/virstringtest.c
@@ -338,6 +338,38 @@ testStringSearch(const void *opaque ATTRIBUTE_UNUSED)
     return ret;
 }
 
+
+struct stringReplaceData {
+    const char *haystack;
+    const char *oldneedle;
+    const char *newneedle;
+    const char *result;
+};
+
+static int
+testStringReplace(const void *opaque ATTRIBUTE_UNUSED)
+{
+    const struct stringReplaceData *data = opaque;
+    char *result;
+    int ret = -1;
+
+    result = virStringReplace(data->haystack,
+                              data->oldneedle,
+                              data->newneedle);
+
+    if (STRNEQ_NULLABLE(data->result, result)) {
+        fprintf(stderr, "Expected '%s' but got '%s'\n",
+                data->result, NULLSTR(result));
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    return ret;
+}
+
+
 static int
 mymain(void)
 {
@@ -428,6 +460,33 @@ mymain(void)
     const char *matches3[] = { "foo", "bar" };
     TEST_SEARCH("1foo2bar3eek", "([a-z]+)", 2, 2, matches3, false);
 
+#define TEST_REPLACE(h, o, n, r)                                        \
+    do {                                                                \
+        struct stringReplaceData data = {                               \
+            .haystack = h,                                              \
+            .oldneedle = o,                                             \
+            .newneedle = n,                                             \
+            .result = r                                                 \
+        };                                                              \
+        if (virtTestRun("virStringReplace " h, testStringReplace, &data) < 0) \
+            ret = -1;                                                   \
+    } while (0)
+
+    /* no matches */
+    TEST_REPLACE("foo", "bar", "eek", "foo");
+
+    /* complete match */
+    TEST_REPLACE("foo", "foo", "bar", "bar");
+
+    /* middle match */
+    TEST_REPLACE("foobarwizz", "bar", "eek", "fooeekwizz");
+
+    /* many matches */
+    TEST_REPLACE("foofoofoofoo", "foo", "bar", "barbarbarbar");
+
+    /* many matches */
+    TEST_REPLACE("fooooofoooo", "foo", "bar", "barooobaroo");
+
     return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
-- 
1.8.5.3

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to