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.
This commit is contained in:
Matthias Clasen 2021-07-14 07:38:32 -04:00
parent 264d592012
commit 87e2a02e0c
4 changed files with 119 additions and 18 deletions

View File

@ -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]);

View File

@ -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);

View File

@ -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);

View File

@ -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;