Add a virStringReplace method to virstring.{h,c} to perform
substring matching and replacement
Signed-off-by: Daniel P. Berrange <berrange(a)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