1From f74589f53041abff29d538a5d9884c3202f2c00a Mon Sep 17 00:00:00 2001 2From: =?UTF-8?q?Ga=C3=ABl=20Bonithon?= <gael@xfce.org> 3Date: Thu, 20 Apr 2023 16:52:19 +0200 4Subject: [PATCH 1/2] gkeyfile: Replace g_slice_*() with 5 g_new*()/g_free_sized() 6 7Conflict:NA 8Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/f74589f53041abff29d538a5d9884c3202f2c00a 9 10--- 11 glib/gkeyfile.c | 26 +++++++++++++------------- 12 1 file changed, 13 insertions(+), 13 deletions(-) 13 14diff --git a/glib/gkeyfile.c b/glib/gkeyfile.c 15index 9a4821bc5a..d76335653f 100644 16--- a/glib/gkeyfile.c 17+++ b/glib/gkeyfile.c 18@@ -638,7 +638,7 @@ G_DEFINE_QUARK (g-key-file-error-quark, g_key_file_error) 19 static void 20 g_key_file_init (GKeyFile *key_file) 21 { 22- key_file->current_group = g_slice_new0 (GKeyFileGroup); 23+ key_file->current_group = g_new0 (GKeyFileGroup, 1); 24 key_file->groups = g_list_prepend (NULL, key_file->current_group); 25 key_file->group_hash = NULL; 26 key_file->start_group = NULL; 27@@ -700,7 +700,7 @@ g_key_file_new (void) 28 { 29 GKeyFile *key_file; 30 31- key_file = g_slice_new0 (GKeyFile); 32+ key_file = g_new0 (GKeyFile, 1); 33 key_file->ref_count = 1; 34 g_key_file_init (key_file); 35 36@@ -1205,7 +1205,7 @@ g_key_file_free (GKeyFile *key_file) 37 g_key_file_clear (key_file); 38 39 if (g_atomic_int_dec_and_test (&key_file->ref_count)) 40- g_slice_free (GKeyFile, key_file); 41+ g_free_sized (key_file, sizeof (GKeyFile)); 42 else 43 g_key_file_init (key_file); 44 } 45@@ -1227,7 +1227,7 @@ g_key_file_unref (GKeyFile *key_file) 46 if (g_atomic_int_dec_and_test (&key_file->ref_count)) 47 { 48 g_key_file_clear (key_file); 49- g_slice_free (GKeyFile, key_file); 50+ g_free_sized (key_file, sizeof (GKeyFile)); 51 } 52 } 53 54@@ -1317,7 +1317,7 @@ g_key_file_parse_comment (GKeyFile *key_file, 55 56 g_warn_if_fail (key_file->current_group != NULL); 57 58- pair = g_slice_new (GKeyFileKeyValuePair); 59+ pair = g_new (GKeyFileKeyValuePair, 1); 60 pair->key = NULL; 61 pair->value = g_strndup (line, length); 62 63@@ -1442,7 +1442,7 @@ g_key_file_parse_key_value_pair (GKeyFile *key_file, 64 { 65 GKeyFileKeyValuePair *pair; 66 67- pair = g_slice_new (GKeyFileKeyValuePair); 68+ pair = g_new (GKeyFileKeyValuePair, 1); 69 pair->key = g_steal_pointer (&key); 70 pair->value = g_strndup (value_start, value_len); 71 72@@ -3339,7 +3339,7 @@ g_key_file_set_key_comment (GKeyFile *key_file, 73 74 /* Now we can add our new comment 75 */ 76- pair = g_slice_new (GKeyFileKeyValuePair); 77+ pair = g_new (GKeyFileKeyValuePair, 1); 78 pair->key = NULL; 79 pair->value = g_key_file_parse_comment_as_value (key_file, comment); 80 81@@ -3383,7 +3383,7 @@ g_key_file_set_group_comment (GKeyFile *key_file, 82 83 /* Now we can add our new comment 84 */ 85- group->comment = g_slice_new (GKeyFileKeyValuePair); 86+ group->comment = g_new (GKeyFileKeyValuePair, 1); 87 group->comment->key = NULL; 88 group->comment->value = g_key_file_parse_comment_as_value (key_file, comment); 89 90@@ -3416,7 +3416,7 @@ g_key_file_set_top_comment (GKeyFile *key_file, 91 if (comment == NULL) 92 return TRUE; 93 94- pair = g_slice_new (GKeyFileKeyValuePair); 95+ pair = g_new (GKeyFileKeyValuePair, 1); 96 pair->key = NULL; 97 pair->value = g_key_file_parse_comment_as_value (key_file, comment); 98 99@@ -3840,7 +3840,7 @@ g_key_file_add_group (GKeyFile *key_file, 100 return; 101 } 102 103- group = g_slice_new0 (GKeyFileGroup); 104+ group = g_new0 (GKeyFileGroup, 1); 105 group->name = g_strdup (group_name); 106 group->lookup_map = g_hash_table_new (g_str_hash, g_str_equal); 107 key_file->groups = g_list_prepend (key_file->groups, group); 108@@ -3862,7 +3862,7 @@ g_key_file_key_value_pair_free (GKeyFileKeyValuePair *pair) 109 { 110 g_free (pair->key); 111 g_free (pair->value); 112- g_slice_free (GKeyFileKeyValuePair, pair); 113+ g_free_sized (pair, sizeof (GKeyFileKeyValuePair)); 114 } 115 } 116 117@@ -3971,7 +3971,7 @@ g_key_file_remove_group_node (GKeyFile *key_file, 118 } 119 120 g_free ((gchar *) group->name); 121- g_slice_free (GKeyFileGroup, group); 122+ g_free_sized (group, sizeof (GKeyFileGroup)); 123 g_list_free_1 (group_node); 124 } 125 126@@ -4031,7 +4031,7 @@ g_key_file_add_key (GKeyFile *key_file, 127 { 128 GKeyFileKeyValuePair *pair; 129 130- pair = g_slice_new (GKeyFileKeyValuePair); 131+ pair = g_new (GKeyFileKeyValuePair, 1); 132 pair->key = g_strdup (key); 133 pair->value = g_strdup (value); 134 135-- 136GitLab 137 138 139From 86b4b0453ea3a814167d4a5f7a4031d467543716 Mon Sep 17 00:00:00 2001 140From: =?UTF-8?q?Ga=C3=ABl=20Bonithon?= <gael@xfce.org> 141Date: Fri, 14 Apr 2023 19:40:30 +0200 142Subject: [PATCH 2/2] gkeyfile: Fix group comment management 143 144This removes the `comment` member of the GKeyFileGroup structure, which 145seemed intended to distinguish comments just above a group from comments 146above them, separated by one or more blank lines. Indeed: 147* This does not seem to match any specification in the documentation, 148 where blank lines and lines starting with `#` are indiscriminately 149 considered comments. In particular, no distinction is made between the 150 comment above the first group and the comment at the beginning of the 151 file. 152* This distinction was only half implemented, resulting in confusion 153 between comment above a group and comment at the end of the preceding 154 group. 155 156Instead, the same logic is used for groups as for keys: the comment 157above a group is simply the sequence of key-value pairs of the preceding 158group where the key is null, starting from the bottom. 159 160The addition of a blank line above groups when writing, involved in 161bugs #104 and #2927, is kept, but: 162* It is now added as a comment as soon as the group is added (since a 163 blank line is considered a comment), so that 164 `g_key_file_get_comment()` returns the correct result right away. 165* It is always added if comments are not kept. 166* Otherwise it is only added if the group is newly created (not present 167 in the original data), in order to really keep comments (existing and 168 not existing). 169 170Closes: #104, #2927 171 172Conflict:NA 173Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/86b4b0453ea3a814167d4a5f7a4031d467543716 174 175--- 176 glib/gkeyfile.c | 137 +++++++++++++++++++++++-------------------- 177 glib/tests/keyfile.c | 75 ++++++++++++++++++++++- 178 2 files changed, 147 insertions(+), 65 deletions(-) 179 180diff --git a/glib/gkeyfile.c b/glib/gkeyfile.c 181index d76335653f..1fcef9fc91 100644 182--- a/glib/gkeyfile.c 183+++ b/glib/gkeyfile.c 184@@ -529,8 +529,6 @@ struct _GKeyFileGroup 185 { 186 const gchar *name; /* NULL for above first group (which will be comments) */ 187 188- GKeyFileKeyValuePair *comment; /* Special comment that is stuck to the top of a group */ 189- 190 GList *key_value_pairs; 191 192 /* Used in parallel with key_value_pairs for 193@@ -579,7 +577,8 @@ static void g_key_file_add_key (GKeyFile 194 const gchar *key, 195 const gchar *value); 196 static void g_key_file_add_group (GKeyFile *key_file, 197- const gchar *group_name); 198+ const gchar *group_name, 199+ gboolean created); 200 static gboolean g_key_file_is_group_name (const gchar *name); 201 static gboolean g_key_file_is_key_name (const gchar *name, 202 gsize len); 203@@ -1354,7 +1353,7 @@ g_key_file_parse_group (GKeyFile *key_file, 204 return; 205 } 206 207- g_key_file_add_group (key_file, group_name); 208+ g_key_file_add_group (key_file, group_name, FALSE); 209 g_free (group_name); 210 } 211 212@@ -1610,14 +1609,6 @@ g_key_file_to_data (GKeyFile *key_file, 213 214 group = (GKeyFileGroup *) group_node->data; 215 216- /* separate groups by at least an empty line */ 217- if (data_string->len >= 2 && 218- data_string->str[data_string->len - 2] != '\n') 219- g_string_append_c (data_string, '\n'); 220- 221- if (group->comment != NULL) 222- g_string_append_printf (data_string, "%s\n", group->comment->value); 223- 224 if (group->name != NULL) 225 g_string_append_printf (data_string, "[%s]\n", group->name); 226 227@@ -1902,7 +1893,7 @@ g_key_file_set_value (GKeyFile *key_file, 228 229 if (!group) 230 { 231- g_key_file_add_group (key_file, group_name); 232+ g_key_file_add_group (key_file, group_name, TRUE); 233 group = (GKeyFileGroup *) key_file->groups->data; 234 235 g_key_file_add_key (key_file, group, key, value); 236@@ -3349,6 +3340,42 @@ g_key_file_set_key_comment (GKeyFile *key_file, 237 return TRUE; 238 } 239 240+static gboolean 241+g_key_file_set_top_comment (GKeyFile *key_file, 242+ const gchar *comment, 243+ GError **error) 244+{ 245+ GList *group_node; 246+ GKeyFileGroup *group; 247+ GKeyFileKeyValuePair *pair; 248+ 249+ /* The last group in the list should be the top (comments only) 250+ * group in the file 251+ */ 252+ g_warn_if_fail (key_file->groups != NULL); 253+ group_node = g_list_last (key_file->groups); 254+ group = (GKeyFileGroup *) group_node->data; 255+ g_warn_if_fail (group->name == NULL); 256+ 257+ /* Note all keys must be comments at the top of 258+ * the file, so we can just free it all. 259+ */ 260+ g_list_free_full (group->key_value_pairs, (GDestroyNotify) g_key_file_key_value_pair_free); 261+ group->key_value_pairs = NULL; 262+ 263+ if (comment == NULL) 264+ return TRUE; 265+ 266+ pair = g_new (GKeyFileKeyValuePair, 1); 267+ pair->key = NULL; 268+ pair->value = g_key_file_parse_comment_as_value (key_file, comment); 269+ 270+ group->key_value_pairs = 271+ g_list_prepend (group->key_value_pairs, pair); 272+ 273+ return TRUE; 274+} 275+ 276 static gboolean 277 g_key_file_set_group_comment (GKeyFile *key_file, 278 const gchar *group_name, 279@@ -3356,6 +3383,8 @@ g_key_file_set_group_comment (GKeyFile *key_file, 280 GError **error) 281 { 282 GKeyFileGroup *group; 283+ GList *group_node; 284+ GKeyFileKeyValuePair *pair; 285 286 g_return_val_if_fail (group_name != NULL && g_key_file_is_group_name (group_name), FALSE); 287 288@@ -3370,12 +3399,22 @@ g_key_file_set_group_comment (GKeyFile *key_file, 289 return FALSE; 290 } 291 292+ if (group == key_file->start_group) 293+ return g_key_file_set_top_comment (key_file, comment, error); 294+ 295 /* First remove any existing comment 296 */ 297- if (group->comment) 298+ group_node = g_key_file_lookup_group_node (key_file, group_name); 299+ group = group_node->next->data; 300+ for (GList *lp = group->key_value_pairs; lp != NULL; ) 301 { 302- g_key_file_key_value_pair_free (group->comment); 303- group->comment = NULL; 304+ GList *lnext = lp->next; 305+ pair = lp->data; 306+ if (pair->key != NULL) 307+ break; 308+ 309+ g_key_file_remove_key_value_pair_node (key_file, group, lp); 310+ lp = lnext; 311 } 312 313 if (comment == NULL) 314@@ -3383,45 +3422,10 @@ g_key_file_set_group_comment (GKeyFile *key_file, 315 316 /* Now we can add our new comment 317 */ 318- group->comment = g_new (GKeyFileKeyValuePair, 1); 319- group->comment->key = NULL; 320- group->comment->value = g_key_file_parse_comment_as_value (key_file, comment); 321- 322- return TRUE; 323-} 324- 325-static gboolean 326-g_key_file_set_top_comment (GKeyFile *key_file, 327- const gchar *comment, 328- GError **error) 329-{ 330- GList *group_node; 331- GKeyFileGroup *group; 332- GKeyFileKeyValuePair *pair; 333- 334- /* The last group in the list should be the top (comments only) 335- * group in the file 336- */ 337- g_warn_if_fail (key_file->groups != NULL); 338- group_node = g_list_last (key_file->groups); 339- group = (GKeyFileGroup *) group_node->data; 340- g_warn_if_fail (group->name == NULL); 341- 342- /* Note all keys must be comments at the top of 343- * the file, so we can just free it all. 344- */ 345- g_list_free_full (group->key_value_pairs, (GDestroyNotify) g_key_file_key_value_pair_free); 346- group->key_value_pairs = NULL; 347- 348- if (comment == NULL) 349- return TRUE; 350- 351 pair = g_new (GKeyFileKeyValuePair, 1); 352 pair->key = NULL; 353 pair->value = g_key_file_parse_comment_as_value (key_file, comment); 354- 355- group->key_value_pairs = 356- g_list_prepend (group->key_value_pairs, pair); 357+ group->key_value_pairs = g_list_prepend (group->key_value_pairs, pair); 358 359 return TRUE; 360 } 361@@ -3629,9 +3633,6 @@ g_key_file_get_group_comment (GKeyFile *key_file, 362 return NULL; 363 } 364 365- if (group->comment) 366- return g_strdup (group->comment->value); 367- 368 group_node = g_key_file_lookup_group_node (key_file, group_name); 369 group_node = group_node->next; 370 group = (GKeyFileGroup *)group_node->data; 371@@ -3826,7 +3827,8 @@ g_key_file_has_key (GKeyFile *key_file, 372 373 static void 374 g_key_file_add_group (GKeyFile *key_file, 375- const gchar *group_name) 376+ const gchar *group_name, 377+ gboolean created) 378 { 379 GKeyFileGroup *group; 380 381@@ -3847,7 +3849,22 @@ g_key_file_add_group (GKeyFile *key_file, 382 key_file->current_group = group; 383 384 if (key_file->start_group == NULL) 385- key_file->start_group = group; 386+ { 387+ key_file->start_group = group; 388+ } 389+ else if (!(key_file->flags & G_KEY_FILE_KEEP_COMMENTS) || created) 390+ { 391+ /* separate groups by a blank line if we don't keep comments or group is created */ 392+ GKeyFileGroup *next_group = key_file->groups->next->data; 393+ if (next_group->key_value_pairs == NULL || 394+ ((GKeyFileKeyValuePair *) next_group->key_value_pairs->data)->key != NULL) 395+ { 396+ GKeyFileKeyValuePair *pair = g_new (GKeyFileKeyValuePair, 1); 397+ pair->key = NULL; 398+ pair->value = g_strdup (""); 399+ next_group->key_value_pairs = g_list_prepend (next_group->key_value_pairs, pair); 400+ } 401+ } 402 403 if (!key_file->group_hash) 404 key_file->group_hash = g_hash_table_new (g_str_hash, g_str_equal); 405@@ -3958,12 +3975,6 @@ g_key_file_remove_group_node (GKeyFile *key_file, 406 407 g_warn_if_fail (group->key_value_pairs == NULL); 408 409- if (group->comment) 410- { 411- g_key_file_key_value_pair_free (group->comment); 412- group->comment = NULL; 413- } 414- 415 if (group->lookup_map) 416 { 417 g_hash_table_destroy (group->lookup_map); 418diff --git a/glib/tests/keyfile.c b/glib/tests/keyfile.c 419index 3d72d9670e..d3eed29841 100644 420--- a/glib/tests/keyfile.c 421+++ b/glib/tests/keyfile.c 422@@ -382,7 +382,9 @@ test_comments (void) 423 "key4 = value4\n" 424 "# group comment\n" 425 "# group comment, continued\n" 426- "[group2]\n"; 427+ "[group2]\n\n" 428+ "[group3]\n" 429+ "[group4]\n"; 430 431 const gchar *top_comment = " top comment\n top comment, continued"; 432 const gchar *group_comment = " group comment\n group comment, continued"; 433@@ -427,6 +429,12 @@ test_comments (void) 434 check_name ("top comment", comment, top_comment, 0); 435 g_free (comment); 436 437+ g_key_file_remove_comment (keyfile, NULL, NULL, &error); 438+ check_no_error (&error); 439+ comment = g_key_file_get_comment (keyfile, NULL, NULL, &error); 440+ check_no_error (&error); 441+ g_assert_null (comment); 442+ 443 comment = g_key_file_get_comment (keyfile, "group1", "key2", &error); 444 check_no_error (&error); 445 check_name ("key comment", comment, key_comment, 0); 446@@ -448,7 +456,25 @@ test_comments (void) 447 check_name ("group comment", comment, group_comment, 0); 448 g_free (comment); 449 450+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/104"); 451+ 452+ /* check if comments above another group than the first one are properly removed */ 453+ g_key_file_remove_comment (keyfile, "group2", NULL, &error); 454+ check_no_error (&error); 455+ comment = g_key_file_get_comment (keyfile, "group2", NULL, &error); 456+ check_no_error (&error); 457+ g_assert_null (comment); 458+ 459 comment = g_key_file_get_comment (keyfile, "group3", NULL, &error); 460+ check_no_error (&error); 461+ check_name ("group comment", comment, "", 0); 462+ g_free (comment); 463+ 464+ comment = g_key_file_get_comment (keyfile, "group4", NULL, &error); 465+ check_no_error (&error); 466+ g_assert_null (comment); 467+ 468+ comment = g_key_file_get_comment (keyfile, "group5", NULL, &error); 469 check_error (&error, 470 G_KEY_FILE_ERROR, 471 G_KEY_FILE_ERROR_GROUP_NOT_FOUND); 472@@ -1321,9 +1347,16 @@ test_reload_idempotency (void) 473 "[fifth]\n"; 474 GKeyFile *keyfile; 475 GError *error = NULL; 476- gchar *data1, *data2; 477+ gchar *data1, *data2, *comment; 478 gsize len1, len2; 479 480+ const gchar *key_comment = " A random comment in the first group"; 481+ const gchar *top_comment = " Top comment\n\n First comment"; 482+ const gchar *group_comment_1 = top_comment; 483+ const gchar *group_comment_2 = " Second comment - one line"; 484+ const gchar *group_comment_3 = " Third comment - two lines\n Third comment - two lines"; 485+ const gchar *group_comment_4 = "\n"; 486+ 487 g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=420686"); 488 489 /* check that we only insert a single new line between groups */ 490@@ -1347,6 +1380,44 @@ test_reload_idempotency (void) 491 492 data2 = g_key_file_to_data (keyfile, &len2, &error); 493 g_assert_nonnull (data2); 494+ 495+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2927"); 496+ 497+ /* check if comments are preserved on reload */ 498+ comment = g_key_file_get_comment (keyfile, "first", "anotherkey", &error); 499+ check_no_error (&error); 500+ g_assert_cmpstr (comment, ==, key_comment); 501+ g_free (comment); 502+ 503+ comment = g_key_file_get_comment (keyfile, NULL, NULL, &error); 504+ check_no_error (&error); 505+ g_assert_cmpstr (comment, ==, top_comment); 506+ g_free (comment); 507+ 508+ comment = g_key_file_get_comment (keyfile, "first", NULL, &error); 509+ check_no_error (&error); 510+ g_assert_cmpstr (comment, ==, group_comment_1); 511+ g_free (comment); 512+ 513+ comment = g_key_file_get_comment (keyfile, "second", NULL, &error); 514+ check_no_error (&error); 515+ g_assert_cmpstr (comment, ==, group_comment_2); 516+ g_free (comment); 517+ 518+ comment = g_key_file_get_comment (keyfile, "third", NULL, &error); 519+ check_no_error (&error); 520+ g_assert_cmpstr (comment, ==, group_comment_3); 521+ g_free (comment); 522+ 523+ comment = g_key_file_get_comment (keyfile, "fourth", NULL, &error); 524+ check_no_error (&error); 525+ g_assert_cmpstr (comment, ==, group_comment_4); 526+ g_free (comment); 527+ 528+ comment = g_key_file_get_comment (keyfile, "fifth", NULL, &error); 529+ check_no_error (&error); 530+ g_assert_null (comment); 531+ 532 g_key_file_free (keyfile); 533 534 g_assert_cmpstr (data1, ==, data2); 535-- 536GitLab