From 66e3a3e91423995045ea872232d73639b8b23101 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 19 Feb 2014 20:30:46 +0000 Subject: [PATCH] Add virStringReplace method for substring replacement Add a virStringReplace method to virstring.{h,c} to perform substring matching and replacement Signed-off-by: Daniel P. Berrange --- src/libvirt_private.syms | 1 + src/util/virstring.c | 45 ++++++++++++++++++++++++++++ src/util/virstring.h | 5 ++++ tests/virstringtest.c | 64 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c7c8c6a3bf..7b0ca980cd 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1798,6 +1798,7 @@ virStringArrayHasString; virStringFreeList; virStringJoin; virStringListLength; +virStringReplace; virStringSearch; virStringSortCompare; virStringSortRevCompare; diff --git a/src/util/virstring.c b/src/util/virstring.c index 008293f5a9..b3912f3331 100644 --- a/src/util/virstring.c +++ b/src/util/virstring.c @@ -749,3 +749,48 @@ 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)) { + virReportOOMError(); + return NULL; + } + + return virBufferContentAndReset(&buf); +} diff --git a/src/util/virstring.h b/src/util/virstring.h index 8efc80cdc7..5b77581aaa 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 f6c44053cb..8d45e7134e 100644 --- a/tests/virstringtest.c +++ b/tests/virstringtest.c @@ -338,6 +338,39 @@ 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: + VIR_FREE(result); + return ret; +} + + static int mymain(void) { @@ -428,6 +461,37 @@ 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"); + + /* different length old/new needles */ + TEST_REPLACE("fooooofoooo", "foo", "barwizzeek", "barwizzeekooobarwizzeekoo"); + TEST_REPLACE("fooooofoooo", "foooo", "foo", "fooofoo"); + return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; }