---
src/libvirt_private.syms | 1 +
src/util/virstring.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++
src/util/virstring.h | 6 +++
3 files changed, 136 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 57a1b50..65e85d4 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1901,6 +1901,7 @@ virStringListLength;
virStringSplit;
virStrncpy;
virStrndup;
+virStrReplace;
virStrToDouble;
virStrToLong_i;
virStrToLong_l;
diff --git a/src/util/virstring.c b/src/util/virstring.c
index 1f4850e..81a3a4d 100644
--- a/src/util/virstring.c
+++ b/src/util/virstring.c
@@ -613,3 +613,132 @@ size_t virStringListLength(char **strings)
return i;
}
+
+/*
+ virStrReplace(haystack, haystacksize, oldneedle, newneedle) --
+ Search haystack and replace all occurences of oldneedle with newneedle.
+ Resulting haystack contains no more than haystacksize characters (including the
'\0').
+ If haystacksize is too small to make the replacements, do not modify haystack at all.
+
+ RETURN VALUES
+ virStrReplace() returns haystack on success and NULL on failure.
+ Failure means there was not enough room to replace all occurences of oldneedle.
+ Success is returned otherwise, even if no replacement is made.
+Methods found here:
http://stackoverflow.com/a/12546318, author: Brandin
+*/
+char *
+virStrReplace(char *haystack, size_t haystacksize,
+ const char *oldneedle, const char *newneedle)
+{
+ size_t oldneedle_len = strlen(oldneedle);
+ size_t newneedle_len = strlen(newneedle);
+ char *oldneedle_ptr; // locates occurences of oldneedle
+ char *read_ptr; // where to read in the haystack
+ char *write_ptr; // where to write in the haystack
+ const char *oldneedle_last = // the last character in oldneedle
+ oldneedle +
+ oldneedle_len - 1;
+
+ // Case 0: oldneedle is empty
+ if (oldneedle_len == 0)
+ return (char *)haystack; // nothing to do;
+
+ // Case 1: newneedle is not longer than oldneedle
+ if (newneedle_len <= oldneedle_len) {
+ // Pass 1: Perform copy/replace using read_ptr and write_ptr
+ for (oldneedle_ptr = (char *)oldneedle,
+ read_ptr = haystack, write_ptr = haystack;
+ *read_ptr != '\0';
+ read_ptr++, write_ptr++)
+ {
+ *write_ptr = *read_ptr;
+ bool found = virLocateForward(&oldneedle_ptr, read_ptr,
+ oldneedle, oldneedle_last);
+ if (found) {
+ // then perform update
+ write_ptr -= oldneedle_len;
+ memcpy(write_ptr+1, newneedle, newneedle_len);
+ write_ptr += newneedle_len;
+ }
+ }
+ *write_ptr = '\0';
+ return (char *)haystack;
+ }
+
+ // Case 2: newneedle is longer than oldneedle
+ else {
+ size_t diff_len = // the amount of extra space needed
+ newneedle_len - // to replace oldneedle with newneedle
+ oldneedle_len; // in the expanded haystack
+
+ // Pass 1: Perform forward scan, updating write_ptr along the way
+ for (oldneedle_ptr = (char *)oldneedle,
+ read_ptr = haystack, write_ptr = haystack;
+ *read_ptr != '\0';
+ read_ptr++, write_ptr++)
+ {
+ bool found = virLocateForward(&oldneedle_ptr, read_ptr,
+ oldneedle, oldneedle_last);
+ if (found) {
+ // then advance write_ptr
+ write_ptr += diff_len;
+ }
+ if (write_ptr >= haystack+haystacksize)
+ return NULL; // no more room in haystack
+ }
+
+ // Pass 2: Walk backwards through haystack, performing copy/replace
+ for (oldneedle_ptr = (char *)oldneedle_last;
+ write_ptr >= haystack;
+ write_ptr--, read_ptr--)
+ {
+ *write_ptr = *read_ptr;
+ bool found = virLocateBackward(&oldneedle_ptr, read_ptr,
+ oldneedle, oldneedle_last);
+ if (found) {
+ // then perform replacement
+ write_ptr -= diff_len;
+ memcpy(write_ptr, newneedle, newneedle_len);
+ }
+ }
+ return (char *)haystack;
+ }
+}
+
+// virLocateForward: compare needle_ptr and read_ptr to see if a match occured
+// needle_ptr is updated as appropriate for the next call
+// return true if match occured, false otherwise
+bool
+virLocateForward(char **needle_ptr, char *read_ptr,
+ const char *needle, const char *needle_last)
+{
+ if (**needle_ptr == *read_ptr) {
+ (*needle_ptr)++;
+ if (*needle_ptr > needle_last) {
+ *needle_ptr = (char *)needle;
+ return true;
+ }
+ }
+ else
+ *needle_ptr = (char *)needle;
+ return false;
+}
+
+// virLocateBackward: compare needle_ptr and read_ptr to see if a match occured
+// needle_ptr is updated as appropriate for the next call
+// return true if match occured, false otherwise
+bool
+virLocateBackward(char **needle_ptr, char *read_ptr,
+ const char *needle, const char *needle_last)
+{
+ if (**needle_ptr == *read_ptr) {
+ (*needle_ptr)--;
+ if (*needle_ptr < needle) {
+ *needle_ptr = (char *)needle_last;
+ return true;
+ }
+ }
+ else
+ *needle_ptr = (char *)needle_last;
+ return false;
+}
diff --git a/src/util/virstring.h b/src/util/virstring.h
index b390150..f69597f 100644
--- a/src/util/virstring.h
+++ b/src/util/virstring.h
@@ -223,4 +223,10 @@ size_t virStringListLength(char **strings);
virAsprintfInternal(false, 0, NULL, NULL, 0, \
strp, __VA_ARGS__)
+char * virStrReplace(char *haystack, size_t haystacksize, const char *oldneedle, const
char *newneedle);
+
+bool virLocateForward(char **needle_ptr, char *read_ptr, const char *needle, const char
*needle_last);
+
+bool virLocateBackward(char **needle_ptr, char *read_ptr,const char *needle, const char
*needle_last);
+
#endif /* __VIR_STRING_H__ */
--
1.7.10.4