diff --git a/ChangeLog b/ChangeLog index 6e71f3abc..9233bff3d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2007-03-22 Chris Wilson + + * 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 * glib/pcre/Makefile.am: Make builddir != srcdir work. (#419900) diff --git a/glib/gkeyfile.c b/glib/gkeyfile.c index 01ab8da85..607085b56 100644 --- a/glib/gkeyfile.c +++ b/glib/gkeyfile.c @@ -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; } diff --git a/tests/keyfile-test.c b/tests/keyfile-test.c index 421ad0399..564420a80 100644 --- a/tests/keyfile-test.c +++ b/tests/keyfile-test.c @@ -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; }