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(fof, foo, bar, barooobaroo);
+
return