diff --git a/ChangeLog b/ChangeLog index 3d5b55cdb..d229e38bc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2003-11-05 Morten Welinder + + * glib/gstring.c (g_string_insert_len): Handle the case where the + to-be-inserted string is a substring of the target string. + (g_string_assign): Handle "s = s;". + (#114260, self.) + Sun Nov 2 01:47:31 2003 Matthias Clasen Fix 64bit printing for MSVC builds (#119292, Hans Breuer): diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 3d5b55cdb..d229e38bc 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,10 @@ +2003-11-05 Morten Welinder + + * glib/gstring.c (g_string_insert_len): Handle the case where the + to-be-inserted string is a substring of the target string. + (g_string_assign): Handle "s = s;". + (#114260, self.) + Sun Nov 2 01:47:31 2003 Matthias Clasen Fix 64bit printing for MSVC builds (#119292, Hans Breuer): diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 3d5b55cdb..d229e38bc 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,10 @@ +2003-11-05 Morten Welinder + + * glib/gstring.c (g_string_insert_len): Handle the case where the + to-be-inserted string is a substring of the target string. + (g_string_assign): Handle "s = s;". + (#114260, self.) + Sun Nov 2 01:47:31 2003 Matthias Clasen Fix 64bit printing for MSVC builds (#119292, Hans Breuer): diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 3d5b55cdb..d229e38bc 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,10 @@ +2003-11-05 Morten Welinder + + * glib/gstring.c (g_string_insert_len): Handle the case where the + to-be-inserted string is a substring of the target string. + (g_string_assign): Handle "s = s;". + (#114260, self.) + Sun Nov 2 01:47:31 2003 Matthias Clasen Fix 64bit printing for MSVC builds (#119292, Hans Breuer): diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 3d5b55cdb..d229e38bc 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,10 @@ +2003-11-05 Morten Welinder + + * glib/gstring.c (g_string_insert_len): Handle the case where the + to-be-inserted string is a substring of the target string. + (g_string_assign): Handle "s = s;". + (#114260, self.) + Sun Nov 2 01:47:31 2003 Matthias Clasen Fix 64bit printing for MSVC builds (#119292, Hans Breuer): diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 3d5b55cdb..d229e38bc 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,10 @@ +2003-11-05 Morten Welinder + + * glib/gstring.c (g_string_insert_len): Handle the case where the + to-be-inserted string is a substring of the target string. + (g_string_assign): Handle "s = s;". + (#114260, self.) + Sun Nov 2 01:47:31 2003 Matthias Clasen Fix 64bit printing for MSVC builds (#119292, Hans Breuer): diff --git a/glib/gstring.c b/glib/gstring.c index 24d8b8592..4f212a6de 100644 --- a/glib/gstring.c +++ b/glib/gstring.c @@ -373,9 +373,15 @@ g_string_assign (GString *string, { g_return_val_if_fail (string != NULL, NULL); g_return_val_if_fail (rval != NULL, string); - - g_string_truncate (string, 0); - g_string_append (string, rval); + + /* Make sure assigning to itself doesn't corrupt the string. */ + if (string->str != rval) + { + /* Assigning from substring should be ok since g_string_truncate + does not realloc. */ + g_string_truncate (string, 0); + g_string_append (string, rval); + } return string; } @@ -436,17 +442,50 @@ g_string_insert_len (GString *string, pos = string->len; else g_return_val_if_fail (pos <= string->len, string); - - g_string_maybe_expand (string, len); - /* If we aren't appending at the end, move a hunk - * of the old string to the end, opening up space - */ - if (pos < string->len) - g_memmove (string->str + pos + len, string->str + pos, string->len - pos); - - /* insert the new string */ - g_memmove (string->str + pos, val, len); + /* Check whether val represents a substring of string. This test + probably violates chapter and verse of the C standards, since + ">=" and "<=" are only valid when val really is a substring. + In practice, it will work on modern archs. */ + if (val >= string->str && val <= string->str + string->len) + { + gsize offset = val - string->str; + gsize precount = 0; + + g_string_maybe_expand (string, len); + val = string->str + offset; + /* At this point, val is valid again. */ + + /* Open up space where we are going to insert. */ + if (pos < string->len) + g_memmove (string->str + pos + len, string->str + pos, string->len - pos); + + /* Move the source part before the gap, if any. */ + if (offset < pos) + { + precount = MIN (len, pos - offset); + memcpy (string->str + pos, val, precount); + } + + /* Move the source part after the gap, if any. */ + if (len > precount) + memcpy (string->str + pos + precount, + val + /* Already moved: */ precount + /* Space opened up: */ len, + len - precount); + } + else + { + g_string_maybe_expand (string, len); + + /* If we aren't appending at the end, move a hunk + * of the old string to the end, opening up space + */ + if (pos < string->len) + g_memmove (string->str + pos + len, string->str + pos, string->len - pos); + + /* insert the new string */ + memcpy (string->str + pos, val, len); + } string->len += len; diff --git a/tests/string-test.c b/tests/string-test.c index b328e9cc8..d129b53f6 100644 --- a/tests/string-test.c +++ b/tests/string-test.c @@ -89,7 +89,7 @@ main (int argc, g_string_chunk_free (string_chunk); string1 = g_string_new ("hi pete!"); - string2 = g_string_new (""); + string2 = g_string_new (NULL); g_assert (string1 != NULL); g_assert (string2 != NULL); @@ -182,6 +182,33 @@ main (int argc, g_assert (strcmp (string1->str, "firstlast") == 0); g_string_free (string1, TRUE); + /* insert_len with string overlap */ + string1 = g_string_new ("textbeforetextafter"); + g_string_insert_len (string1, 10, string1->str + 8, 5); + g_assert (strcmp (string1->str, "textbeforeretextextafter") == 0); + g_string_free (string1, TRUE); + + string1 = g_string_new ("boring text"); + g_string_insert_len (string1, 7, string1->str + 2, 4); + g_assert (strcmp (string1->str, "boring ringtext") == 0); + g_string_free (string1, TRUE); + + string1 = g_string_new ("boring text"); + g_string_insert_len (string1, 6, string1->str + 7, 4); + g_assert (strcmp (string1->str, "boringtext text") == 0); + g_string_free (string1, TRUE); + + /* assign_len with string overlap */ + string1 = g_string_new ("textbeforetextafter"); + g_string_assign (string1, string1->str + 10); + g_assert (strcmp (string1->str, "textafter") == 0); + g_string_free (string1, TRUE); + + string1 = g_string_new ("boring text"); + g_string_assign (string1, string1->str); + g_assert (strcmp (string1->str, "boring text") == 0); + g_string_free (string1, TRUE); + /* g_string_equal */ string1 = g_string_new ("test"); string2 = g_string_new ("te");