Track whether the last key=value pair in a group is a blank line and
authorChris Wilson <chris@chris-wilson.co.uk>
Thu, 22 Mar 2007 08:58:59 +0000 (08:58 +0000)
committerChris Wilson <cpwilson@src.gnome.org>
Thu, 22 Mar 2007 08:58:59 +0000 (08:58 +0000)
2007-03-22  Chris Wilson  <chris@chris-wilson.co.uk>

* glib/gkeyfile.c: Track whether the last key=value pair in a group
is a blank line and during to_data() only insert a new blank line
betweens group in its absence. This allows the beautification of the
GKeyFile and prevents newlines being inserted indefinitely. (#420686)

* tests/keyfile-test.c (test_reload_idempotency): Test that after a
single beautification pass, g_key_file_to_data() does not alter its
input data.

svn path=/trunk/; revision=5431

ChangeLog
glib/gkeyfile.c
tests/keyfile-test.c

index 6e71f3a..9233bff 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2007-03-22  Chris Wilson  <chris@chris-wilson.co.uk>
+
+       * glib/gkeyfile.c: Track whether the last key=value pair in a group
+       is a blank line and during to_data() only insert a new blank line
+       betweens group in its absence. This allows the beautification of the
+       GKeyFile and prevents newlines being inserted indefinitely. (#420686)
+
+       * tests/keyfile-test.c (test_reload_idempotency): Test that after a 
+       single beautification pass, g_key_file_to_data() does not alter its
+       input data.
+
 2007-03-21  Matthias Clasen  <mclasen@redhat.com>
 
        * glib/pcre/Makefile.am: Make builddir != srcdir work.  (#419900)
index 01ab8da..607085b 100644 (file)
@@ -89,6 +89,7 @@ struct _GKeyFileGroup
   const gchar *name;  /* NULL for above first group (which will be comments) */
 
   GKeyFileKeyValuePair *comment; /* Special comment that is stuck to the top of a group */
+  gboolean has_trailing_blank_line;
 
   GList *key_value_pairs; 
 
@@ -729,6 +730,9 @@ g_key_file_parse_comment (GKeyFile     *key_file,
   
   key_file->current_group->key_value_pairs =
     g_list_prepend (key_file->current_group->key_value_pairs, pair);
+
+  if (length == 0 || line[0] != '#')
+    key_file->current_group->has_trailing_blank_line = TRUE;
 }
 
 static void
@@ -959,6 +963,7 @@ g_key_file_to_data (GKeyFile  *key_file,
 {
   GString *data_string;
   GList *group_node, *key_file_node;
+  gboolean has_blank_line = TRUE;
 
   g_return_val_if_fail (key_file != NULL, NULL);
 
@@ -972,10 +977,13 @@ g_key_file_to_data (GKeyFile  *key_file,
 
       group = (GKeyFileGroup *) group_node->data;
 
+      /* separate groups by at least an empty line */
+      if (!has_blank_line)
+       g_string_append_c (data_string, '\n');
+      has_blank_line = group->has_trailing_blank_line;
+
       if (group->comment != NULL)
         g_string_append_printf (data_string, "%s\n", group->comment->value);
-      else if (group_node->next) /* separate groups by at least an empty line */
-        g_string_append_c (data_string, '\n');
 
       if (group->name != NULL)
         g_string_append_printf (data_string, "[%s]\n", group->name);
@@ -3074,6 +3082,7 @@ g_key_file_add_key (GKeyFile      *key_file,
 
   g_hash_table_replace (group->lookup_map, pair->key, pair);
   group->key_value_pairs = g_list_prepend (group->key_value_pairs, pair);
+  group->has_trailing_blank_line = FALSE;
   key_file->approximate_size += strlen (key) + strlen (value) + 2;
 }
 
index 421ad03..564420a 100644 (file)
@@ -1250,6 +1250,86 @@ test_duplicate_groups2 (void)
   g_key_file_free (keyfile);  
 }
 
+
+/* http://bugzilla.gnome.org/show_bug.cgi?id=420686 */
+static void
+test_reload_idempotency (void)
+{
+  static const gchar *original_data=""
+    "# Top comment\n"
+    "\n"
+    "# First comment\n"
+    "[first]\n"
+    "key=value\n"
+    "# A random comment in the first group\n"
+    "anotherkey=anothervalue\n"
+    "# Second comment - one line\n"
+    "[second]\n"
+    "# Third comment - two lines\n"
+    "# Third comment - two lines\n"
+    "[third]\n"
+    "blank_line=1\n"
+    "\n"
+    "blank_lines=2\n"
+    "\n\n"
+    "[fourth]\n"
+    "[fifth]\n";
+  GKeyFile *keyfile;
+  GError *error = NULL;
+  gchar *data1, *data2;
+  gsize len1, len2;
+
+  /* check that we only insert a single new line between groups */
+  keyfile = g_key_file_new ();
+  if (!g_key_file_load_from_data (keyfile,
+                                 original_data, strlen(original_data),
+                                 G_KEY_FILE_KEEP_COMMENTS,
+                                 &error)) {
+    g_print ("Failed to parse keyfile[1]: %s", error->message);
+    g_error_free (error);
+    exit (1);
+  }
+
+  data1 = g_key_file_to_data (keyfile, &len1, &error);
+  if (data1 == NULL) {
+    g_print ("Failed to extract keyfile[1]: %s", error->message);
+    g_error_free (error);
+    exit (1);
+  }
+  g_key_file_free (keyfile);
+
+  keyfile = g_key_file_new ();
+  if (!g_key_file_load_from_data (keyfile,
+                                 data1, len1,
+                                 G_KEY_FILE_KEEP_COMMENTS,
+                                 &error)) {
+    g_print ("Failed to parse keyfile[2]: %s", error->message);
+    g_error_free (error);
+    exit (1);
+  }
+
+  data2 = g_key_file_to_data (keyfile, &len2, &error);
+  if (data2 == NULL) {
+    g_print ("Failed to extract keyfile[2]: %s", error->message);
+    g_error_free (error);
+    exit (1);
+  }
+  g_key_file_free (keyfile);
+
+
+  if (strcmp(data1, data2) != 0) {
+    g_print ("Reloading GKeyFile is not idempotent.");
+    g_print ("original:\n%s\n---\n", original_data);
+    g_print ("pass1:\n%s\n---\n", data1);
+    g_print ("pass2:\n%s\n---\n", data2);
+    exit (1);
+  }
+
+  g_free (data2);
+  g_free (data1);
+}
+
+
 static void 
 log_func (const gchar   *log_domain,
           GLogLevelFlags log_level,
@@ -1280,6 +1360,7 @@ main (int argc, char *argv[])
   test_duplicate_groups2 ();
   test_group_names ();
   test_key_names ();
+  test_reload_idempotency ();
   
   return 0;
 }