• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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