[PATCH v2 1/3] glibcompat: "Backport" 'g_string_replace'

Peter Krempa posted 3 patches 3 months, 2 weeks ago
[PATCH v2 1/3] glibcompat: "Backport" 'g_string_replace'
Posted by Peter Krempa 3 months, 2 weeks ago
Backport the implementation of 'g_string_replace' until we require at
least glib-2.68

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
---
 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