--- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list