[gtk/wip/compose-parser: 3/3] composetable: Rewrite Compose files if necessary




commit 87e2a02e0c69cec7c04a48265761da13b99c9a2b
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Jul 14 07:38:32 2021 -0400

    composetable: Rewrite Compose files if necessary
    
    Apply heuristics to avoid breaking users existing configurations
    with the change to not always add the default sequences.
    
    If we find a cache that was generated before 4.4, and the Compose
    file does not have an include, and doesn't contain so many sequences
    that it is probably a copy of the system one, we take steps to keep
    things working, and thell the user about it.

 gtk/compose/compose-parse.c  |   2 +-
 gtk/gtkcomposetable.c        | 122 +++++++++++++++++++++++++++++++++++++++----
 gtk/gtkcomposetable.h        |   3 +-
 testsuite/gtk/composetable.c |  10 ++--
 4 files changed, 119 insertions(+), 18 deletions(-)
---
diff --git a/gtk/compose/compose-parse.c b/gtk/compose/compose-parse.c
index 55e9331f3e..e80b270453 100644
--- a/gtk/compose/compose-parse.c
+++ b/gtk/compose/compose-parse.c
@@ -26,7 +26,7 @@ main (int argc, char *argv[])
       exit (1);
     }
 
-  table = gtk_compose_table_parse (argv[1]);
+  table = gtk_compose_table_parse (argv[1], NULL);
   if (!table)
     g_error ("Failed to parse %s", argv[1]);
 
diff --git a/gtk/gtkcomposetable.c b/gtk/gtkcomposetable.c
index 39ca2e3e92..c95b153e6f 100644
--- a/gtk/gtkcomposetable.c
+++ b/gtk/gtkcomposetable.c
@@ -83,6 +83,7 @@ typedef struct {
   GHashTable *sequences;
   GList *files;
   const char *compose_file;
+  gboolean found_include;
 } GtkComposeParser;
 
 static GtkComposeParser *
@@ -95,6 +96,7 @@ parser_new (void)
   parser->sequences = g_hash_table_new_full (sequence_hash, sequence_equal, g_free, g_free);
   parser->files = NULL;
   parser->compose_file = NULL;
+  parser->found_include = FALSE;
 
   return parser;
 }
@@ -357,6 +359,8 @@ parser_handle_include (GtkComposeParser *parser,
   const char *start, *end;
   char *path;
 
+  parser->found_include = TRUE;
+
   p = line + strlen ("include ");
 
   while (g_ascii_isspace (*p))
@@ -719,7 +723,8 @@ gtk_compose_table_serialize (GtkComposeTable *compose_table,
 }
 
 static GtkComposeTable *
-gtk_compose_table_load_cache (const char *compose_file)
+gtk_compose_table_load_cache (const char *compose_file,
+                              gboolean   *found_old_cache)
 {
   guint32 hash;
   char *path = NULL;
@@ -740,6 +745,8 @@ gtk_compose_table_load_cache (const char *compose_file)
   char *char_data = NULL;
   GtkComposeTable *retval;
 
+  *found_old_cache = FALSE;
+
   hash = g_str_hash (compose_file);
   if ((path = gtk_compose_hash_get_cache_path (hash)) == NULL)
     return NULL;
@@ -780,8 +787,8 @@ gtk_compose_table_load_cache (const char *compose_file)
   GET_GUINT16 (version);
   if (version != GTK_COMPOSE_TABLE_VERSION)
     {
-      g_warning ("cache version is different %u != %u",
-                 version, GTK_COMPOSE_TABLE_VERSION);
+      if (version < GTK_COMPOSE_TABLE_VERSION)
+        *found_old_cache = TRUE;
       goto out_load_cache;
     }
 
@@ -993,15 +1000,15 @@ parser_get_compose_table (GtkComposeParser *parser)
 }
 
 static char *
-canonicalize_filename (GtkComposeParser *parser,
-                       const char       *path)
+canonicalize_filename (const char *parent_path,
+                       const char *path)
 {
   GFile *file;
   char *retval;
 
-  if (path[0] != '/' && parser->compose_file)
+  if (path[0] != '/' && parent_path)
     {
-      GFile *orig = g_file_new_for_path (parser->compose_file);
+      GFile *orig = g_file_new_for_path (parent_path);
       GFile *parent = g_file_get_parent (orig);
       file = g_file_resolve_relative_path (parent, path);
       g_object_unref (parent);
@@ -1029,7 +1036,7 @@ parser_parse_file (GtkComposeParser *parser,
   if (parser->compose_file == NULL)
     parser->compose_file = compose_file;
 
-  path = canonicalize_filename (parser, compose_file);
+  path = canonicalize_filename (parser->compose_file, compose_file);
 
   if (g_list_find_custom (parser->files, path, (GCompareFunc)strcmp))
     {
@@ -1046,7 +1053,8 @@ parser_parse_file (GtkComposeParser *parser,
 }
 
 GtkComposeTable *
-gtk_compose_table_parse (const char *compose_file)
+gtk_compose_table_parse (const char *compose_file,
+                         gboolean   *found_include)
 {
   GtkComposeParser *parser;
   GtkComposeTable *compose_table;
@@ -1054,23 +1062,115 @@ gtk_compose_table_parse (const char *compose_file)
   parser = parser_new ();
   parser_parse_file (parser, compose_file);
   compose_table = parser_get_compose_table (parser);
+  if (found_include)
+    *found_include = parser->found_include;
   parser_free (parser);
 
   return compose_table;
 }
 
+static const char *prefix =
+  "# GTK has rewritten this file to add the line:\n"
+  "\n"
+  "include \"%L\"\n"
+  "\n"
+  "# This is necessary to add your own Compose sequences\n"
+  "# in addition to the builtin sequences of GTK. If this\n"
+  "# is not what you want, just remove that line.\n"
+  "#\n"
+  "# A backup of the previous file contents has been made.\n"
+  "\n"
+  "\n";
+
+static gboolean
+rewrite_compose_file (const char *compose_file)
+{
+  char *path = NULL;
+  char *content = NULL;
+  gsize content_len;
+  GFile *file = NULL;
+  GOutputStream *stream = NULL;
+  gboolean ret = FALSE;
+
+  path = canonicalize_filename (NULL, compose_file);
+
+  if (!g_file_get_contents (path, &content, &content_len, NULL))
+    goto out;
+
+  file = g_file_new_for_path (path);
+  stream = G_OUTPUT_STREAM (g_file_replace (file, NULL, TRUE, 0, NULL, NULL));
+
+  if (stream == NULL)
+    goto out;
+
+  if (!g_output_stream_write (stream, prefix, strlen (prefix), NULL, NULL))
+    goto out;
+
+  if (!g_output_stream_write (stream, content, content_len, NULL, NULL))
+    goto out;
+
+  if (!g_output_stream_close (stream, NULL, NULL))
+    goto out;
+
+  ret = TRUE;
+
+out:
+  g_clear_object (&stream);
+  g_clear_object (&file);
+  g_clear_pointer (&path, g_free);
+  g_clear_pointer (&content, g_free);
+
+  return ret;
+}
+
 GtkComposeTable *
 gtk_compose_table_new_with_file (const char *compose_file)
 {
   GtkComposeTable *compose_table;
+  gboolean found_old_cache = FALSE;
+  gboolean found_include = FALSE;
 
   g_assert (compose_file != NULL);
 
-  compose_table = gtk_compose_table_load_cache (compose_file);
+  compose_table = gtk_compose_table_load_cache (compose_file, &found_old_cache);
   if (compose_table != NULL)
     return compose_table;
 
-  compose_table = gtk_compose_table_parse (compose_file);
+parse:
+  compose_table = gtk_compose_table_parse (compose_file, &found_include);
+
+  /* This is where we apply heuristics to avoid breaking users existing configurations
+   * with the change to not always add the default sequences.
+   *
+   * If we find a cache that was generated before 4.4, and the Compose file
+   * does not have an include, and doesn't contain so many sequences that it
+   * is probably a copy of the system one, we take steps to keep things working,
+   * and thell the user about it.
+   */
+  if (found_old_cache && !found_include && compose_table->n_sequences < 100)
+    {
+      if (rewrite_compose_file (compose_file))
+        {
+          g_warning ("\nSince GTK 4.4, Compose files replace the builtin\n"
+                     "compose sequences. To keep them and add your own\n"
+                     "sequences on top, the line:\n"
+                     "\n"
+                     "  include \"%%L\"\n"
+                     "\n"
+                     "has been added to the Compose file\n%s.\n", compose_file);
+          goto parse;
+        }
+      else
+        {
+          g_warning ("\nSince GTK 4.4, Compose files replace the builtin\n"
+                     "compose sequences. To keep them and add your own\n"
+                     "sequences on top, you need to add the line:\n"
+                     "\n"
+                     "  include \"%%L\"\n"
+                     "\n"
+                     "to the Compose file\n%s.\n", compose_file);
+        }
+    }
 
   if (compose_table != NULL)
     gtk_compose_table_save_cache (compose_table);
diff --git a/gtk/gtkcomposetable.h b/gtk/gtkcomposetable.h
index 7a4c952f33..1398559a66 100644
--- a/gtk/gtkcomposetable.h
+++ b/gtk/gtkcomposetable.h
@@ -58,7 +58,8 @@ struct _GtkComposeTable
 };
 
 GtkComposeTable * gtk_compose_table_new_with_file (const char    *compose_file);
-GtkComposeTable * gtk_compose_table_parse         (const char    *compose_file);
+GtkComposeTable * gtk_compose_table_parse         (const char    *compose_file,
+                                                   gboolean      *found_include);
 GtkComposeTable * gtk_compose_table_new_with_data (const guint16 *data,
                                                    int            max_seq_len,
                                                    int            n_seqs);
diff --git a/testsuite/gtk/composetable.c b/testsuite/gtk/composetable.c
index 9c3a4a6142..1a77e5bc93 100644
--- a/testsuite/gtk/composetable.c
+++ b/testsuite/gtk/composetable.c
@@ -84,7 +84,7 @@ generate_output (const char *file)
   GtkComposeTable *table;
   char *output;
 
-  table = gtk_compose_table_parse (file);
+  table = gtk_compose_table_parse (file, NULL);
   output = gtk_compose_table_print (table);
 
   g_print ("%s", output);
@@ -104,7 +104,7 @@ compose_table_compare (gconstpointer data)
   file = g_test_build_filename (G_TEST_DIST, "compose", basename, NULL);
   expected = g_strconcat (file, ".expected", NULL);
 
-  table = gtk_compose_table_parse (file);
+  table = gtk_compose_table_parse (file, NULL);
   output = gtk_compose_table_print (table);
 
   diff = diff_with_file (expected, output, -1, &error);
@@ -131,7 +131,7 @@ compose_table_cycle (void)
 
       file = g_test_build_filename (G_TEST_DIST, "compose", "cycle", NULL);
 
-      table = gtk_compose_table_parse (file);
+      table = gtk_compose_table_parse (file, NULL);
       g_assert_nonnull (table);
       g_free (file);
 
@@ -153,7 +153,7 @@ compose_table_nofile (void)
 
       file = g_build_filename (g_test_get_dir (G_TEST_DIST), "compose", "nofile", NULL);
 
-      table = gtk_compose_table_parse (file);
+      table = gtk_compose_table_parse (file, NULL);
       g_assert_nonnull (table);
       g_free (file);
 
@@ -179,7 +179,7 @@ compose_table_match (void)
 
   file = g_build_filename (g_test_get_dir (G_TEST_DIST), "compose", "match", NULL);
 
-  table = gtk_compose_table_parse (file);
+  table = gtk_compose_table_parse (file, NULL);
 
   buffer[0] = GDK_KEY_Multi_key;
   buffer[1] = 0;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]