diff --git a/steam-runtime-tools/glib-backports-internal.h b/steam-runtime-tools/glib-backports-internal.h index 5b71d59eafbc85e2fcbf89b0592dfc4eeec62559..613beab70c59d7b336c0ced4a90d25e4ca72055d 100644 --- a/steam-runtime-tools/glib-backports-internal.h +++ b/steam-runtime-tools/glib-backports-internal.h @@ -157,3 +157,11 @@ gboolean my_g_ptr_array_find_with_equal_func (GPtrArray *haystack, #define g_warning_once g_warning #endif #endif + +#if !GLIB_CHECK_VERSION(2, 68, 0) +#define g_string_replace(s,f,r,l) my_g_string_replace (s, f, r, l) +guint my_g_string_replace (GString *string, + const gchar *find, + const gchar *replace, + guint limit); +#endif diff --git a/steam-runtime-tools/glib-backports.c b/steam-runtime-tools/glib-backports.c index c929274d37aeabe356a6a01503d2e13c60ec57be..59573a3bb9dcfa0bcbb42ea1db505e3332cae4ef 100644 --- a/steam-runtime-tools/glib-backports.c +++ b/steam-runtime-tools/glib-backports.c @@ -7,6 +7,7 @@ * Copyright 2013-2019 Collabora Ltd. * Copyright 2018 Georges Basile Stavracas Neto * Copyright 2018 Philip Withnall + * Copyright 2021 Joshua Lee * g_execvpe implementation based on GNU libc execvp: * Copyright 1991, 92, 95, 96, 97, 98, 99 Free Software Foundation, Inc. * SPDX-License-Identifier: LGPL-2.1-or-later @@ -586,3 +587,54 @@ my_g_ptr_array_find_with_equal_func (GPtrArray *haystack, return FALSE; } #endif + +#if !GLIB_CHECK_VERSION(2, 68, 0) +/** + * 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. + * + * Returns: the number of find and replace operations performed. + * + * Since: 2.68 + */ +guint +my_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++; + if (n == limit) + break; + } + + return n; +} +#endif diff --git a/tests/utils.c b/tests/utils.c index 1e9140bf1d9fa9d6e6968456bd52fdb269693eb2..b297c0745f1ce7ff3d7c10a1fd9f0e189ebc662f 100644 --- a/tests/utils.c +++ b/tests/utils.c @@ -29,6 +29,7 @@ #include <glib/gstdio.h> #include <glib-object.h> +#include "steam-runtime-tools/glib-backports-internal.h" #include "steam-runtime-tools/input-device-internal.h" #include "steam-runtime-tools/utils-internal.h" #include "test-utils.h" @@ -339,6 +340,38 @@ filter_gameoverlayrenderer (Fixture *f, g_free (filtered_preload); } +static void +test_gstring_replace (Fixture *f, + gconstpointer context) +{ + static const struct + { + const char *string; + const char *original; + const char *replacement; + const char *expected; + } + tests[] = + { + { "/usr/$LIB/libMangoHud.so", "$LIB", "lib32", "/usr/lib32/libMangoHud.so" }, + { "food for foals", "o", "", "fd fr fals" }, + { "aaa", "a", "aaa", "aaaaaaaaa" }, + { "aaa", "a", "", "" }, + { "aaa", "aa", "bb", "bba" }, + }; + gsize i; + + for (i = 0; i < G_N_ELEMENTS (tests); i++) + { + g_autoptr(GString) buffer = g_string_new (tests[i].string); + + g_string_replace (buffer, tests[i].original, tests[i].replacement, 0); + g_assert_cmpstr (buffer->str, ==, tests[i].expected); + g_assert_cmpuint (buffer->len, ==, strlen (tests[i].expected)); + g_assert_cmpuint (buffer->allocated_len, >=, strlen (tests[i].expected) + 1); + } +} + static void test_same_file (Fixture *f, gconstpointer context) @@ -472,6 +505,8 @@ main (int argc, filter_gameoverlayrenderer, teardown); g_test_add ("/utils/get-path-after", Fixture, NULL, setup, test_get_path_after, teardown); + g_test_add ("/utils/gstring-replace", Fixture, NULL, + setup, test_gstring_replace, teardown); g_test_add ("/utils/same-file", Fixture, NULL, setup, test_same_file, teardown); g_test_add ("/utils/str_is_integer", Fixture, NULL,