
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@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