On 02/19/2014 09:36 PM, Daniel P. Berrange wrote:
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:
*
Unrelated whitespace change.
@@ -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))
virBufferError doesn't report an error, but I think this function should.
+ return NULL;
+
+ return virBufferContentAndReset(&buf);
+}
diff --git a/tests/virstringtest.c b/tests/virstringtest.c
index b8c6115..43023d5 100644
--- a/tests/virstringtest.c
+++ b/tests/virstringtest.c
@@ -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;
}
A test with different length of old and new needles would be nice.
ACK with error reporting.
Jan