---
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 6511044..09ad1c1 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1829,6 +1829,7 @@ virStringListLength;
virStringSplit;
virStrncpy;
virStrndup;
+virStrReplace;
virStrToDouble;
virStrToLong_i;
virStrToLong_l;
diff --git a/src/util/virstring.c b/src/util/virstring.c
index 1937f82..9526a7d 100644
--- a/src/util/virstring.c
+++ b/src/util/virstring.c
@@ -608,3 +608,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 34ffae1..6d44778 100644
--- a/src/util/virstring.h
+++ b/src/util/virstring.h
@@ -166,4 +166,10 @@ int virStrndup(char **dest, const char *src, ssize_t n, bool report,
int domcode
size_t virStringListLength(char **strings);
+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