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 <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange 2014-02-19 20:30:46 +00:00
parent 12aa71dfde
commit 66e3a3e914
4 changed files with 115 additions and 0 deletions

View File

@ -1798,6 +1798,7 @@ virStringArrayHasString;
virStringFreeList;
virStringJoin;
virStringListLength;
virStringReplace;
virStringSearch;
virStringSortCompare;
virStringSortRevCompare;

View File

@ -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);
}

View File

@ -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__ */

View File

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