Merge branch 'gstring_replace_guint' into 'main'

gstring: Support large strings in g_string_replace

See merge request GNOME/glib!4790
This commit is contained in:
Philip Withnall
2025-09-16 14:20:01 +00:00

View File

@@ -1055,7 +1055,12 @@ g_string_erase (GString *string,
* (beginning of string, end of string and between characters). This did * (beginning of string, end of string and between characters). This did
* not work correctly in earlier versions. * not work correctly in earlier versions.
* *
* Returns: the number of find and replace operations performed. * If @limit is zero and more than `G_MAXUINT` instances of @find are in
* the input string, they will all be replaced, but the return value will
* be capped at `G_MAXUINT`.
*
* Returns: the number of find and replace operations performed,
* up to `G_MAXUINT`
* *
* Since: 2.68 * Since: 2.68
*/ */
@@ -1087,36 +1092,38 @@ g_string_replace (GString *string,
* handle the case of an empty @find string separately. */ * handle the case of an empty @find string separately. */
if (G_UNLIKELY (f_len == 0)) if (G_UNLIKELY (f_len == 0))
{ {
if (limit == 0 || limit > string->len) size_t r_limit = limit;
if (r_limit == 0 || r_limit > string->len)
{ {
if (string->len > G_MAXSIZE - 1) if (string->len > G_MAXSIZE - 1)
g_error ("inserting in every position in string would overflow"); g_error ("inserting in every position in string would overflow");
limit = string->len + 1; r_limit = string->len + 1;
} }
if (r_len > 0 && if (r_len > 0 &&
(limit > G_MAXSIZE / r_len || (r_limit > G_MAXSIZE / r_len ||
limit * r_len > G_MAXSIZE - string->len)) r_limit * r_len > G_MAXSIZE - string->len))
g_error ("inserting in every position in string would overflow"); g_error ("inserting in every position in string would overflow");
new_len = string->len + limit * r_len; new_len = string->len + r_limit * r_len;
new_string = g_string_sized_new (new_len); new_string = g_string_sized_new (new_len);
for (size_t i = 0; i < limit; i++) for (size_t i = 0; i < r_limit; i++)
{ {
g_string_append_len (new_string, replace, r_len); g_string_append_len (new_string, replace, r_len);
if (i < string->len) if (i < string->len)
g_string_append_c (new_string, string->str[i]); g_string_append_c (new_string, string->str[i]);
} }
if (limit < string->len) if (r_limit < string->len)
g_string_append_len (new_string, string->str + limit, string->len - limit); g_string_append_len (new_string, string->str + r_limit, string->len - r_limit);
g_free (string->str); g_free (string->str);
string->allocated_len = new_string->allocated_len; string->allocated_len = new_string->allocated_len;
string->len = new_string->len; string->len = new_string->len;
string->str = g_string_free_and_steal (g_steal_pointer (&new_string)); string->str = g_string_free_and_steal (g_steal_pointer (&new_string));
return limit; return r_limit > G_MAXUINT ? G_MAXUINT : (guint) r_limit;
} }
/* Potentially do two passes: the first to calculate the length of the new string, /* Potentially do two passes: the first to calculate the length of the new string,
@@ -1137,7 +1144,8 @@ g_string_replace (GString *string,
n = 0; n = 0;
while ((next = strstr (cur, find)) != NULL) while ((next = strstr (cur, find)) != NULL)
{ {
n++; if (n < G_MAXUINT)
n++;
if (r_len <= f_len) if (r_len <= f_len)
{ {