Backport the implementation of 'g_string_replace' until we require at least glib-2.68 Signed-off-by: Peter Krempa <pkrempa@xxxxxxxxxx> --- src/libvirt_private.syms | 1 + src/util/glibcompat.c | 65 ++++++++++++++++++++++++++++++++++++++++ src/util/glibcompat.h | 10 +++++++ 3 files changed, 76 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d15d6a6a9d..0accca442a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1864,6 +1864,7 @@ vir_g_fsync; vir_g_source_unref; vir_g_strdup_printf; vir_g_strdup_vprintf; +vir_g_string_replace; # util/viracpi.c diff --git a/src/util/glibcompat.c b/src/util/glibcompat.c index d8912b323b..98dcfab389 100644 --- a/src/util/glibcompat.c +++ b/src/util/glibcompat.c @@ -155,3 +155,68 @@ void vir_g_source_unref(GSource *src, GMainContext *ctx) } #endif + + +/** + * Adapted (to pass syntax check) from 'g_string_replace' from + * glib-2.81.1. Drop once minimum glib is bumped to 2.68. + * + * g_string_replace: + * @string: a #GString + * @find: the string to find in @string + * @replace: the string to insert in place of @find + * @limit: the maximum instances of @find to replace with @replace, or `0` for + * no limit + * + * Replaces the string @find with the string @replace in a #GString up to + * @limit times. If the number of instances of @find in the #GString is + * less than @limit, all instances are replaced. If @limit is `0`, + * all instances of @find are replaced. + * + * If @find is the empty string, since versions 2.69.1 and 2.68.4 the + * replacement will be inserted no more than once per possible position + * (beginning of string, end of string and between characters). This did + * not work correctly in earlier versions. + * + * Returns: the number of find and replace operations performed. + * + * Since: 2.68 + */ +guint +vir_g_string_replace(GString *string, + const gchar *find, + const gchar *replace, + guint limit) +{ + gsize f_len, r_len, pos; + gchar *cur, *next; + guint n = 0; + + g_return_val_if_fail(string != NULL, 0); + g_return_val_if_fail(find != NULL, 0); + g_return_val_if_fail(replace != NULL, 0); + + f_len = strlen(find); + r_len = strlen(replace); + cur = string->str; + + while ((next = strstr(cur, find)) != NULL) { + pos = next - string->str; + g_string_erase(string, pos, f_len); + g_string_insert(string, pos, replace); + cur = string->str + pos + r_len; + n++; + /* Only match the empty string once at any given position, to + * avoid infinite loops */ + if (f_len == 0) { + if (cur[0] == '\0') + break; + else + cur++; + } + if (n == limit) + break; + } + + return n; +} diff --git a/src/util/glibcompat.h b/src/util/glibcompat.h index 2542b4d5dc..3518023a41 100644 --- a/src/util/glibcompat.h +++ b/src/util/glibcompat.h @@ -85,6 +85,16 @@ char *vir_g_strdup_vprintf(const char *msg, va_list args) void vir_g_source_unref(GSource *src, GMainContext *ctx); + +/* Drop once we require glib-2.68 at minimum */ +guint +vir_g_string_replace(GString *string, + const gchar *find, + const gchar *replace, + guint limit); +#undef g_string_replace +#define g_string_replace vir_g_string_replace + #if !GLIB_CHECK_VERSION(2, 73, 2) # if (defined(__has_attribute) && __has_attribute(__noinline__)) || G_GNUC_CHECK_VERSION (2, 96) # if defined (__cplusplus) && __cplusplus >= 201103L -- 2.45.2