[gtk/wip/compose-parser: 6/15] composetable: Handle includes




commit fb6c8cd466de50a7cc8b9e7642f7296a887a90a5
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Jul 7 10:47:17 2021 -0400

    composetable: Handle includes
    
    This adds the mechanics for parsing include lines in
    Compose files. We do detect and prevent cycles.
    
    Tests included.

 gtk/gtkcomposetable.c                  | 90 +++++++++++++++++++++++++++++++++-
 testsuite/gtk/compose/cycle            |  3 ++
 testsuite/gtk/compose/include          |  3 ++
 testsuite/gtk/compose/include.expected |  4 ++
 testsuite/gtk/compose/included         |  1 +
 testsuite/gtk/compose/nofile           |  3 ++
 testsuite/gtk/composetable.c           | 47 ++++++++++++++++++
 7 files changed, 149 insertions(+), 2 deletions(-)
---
diff --git a/gtk/gtkcomposetable.c b/gtk/gtkcomposetable.c
index 0c1f2d83f1..b8561aa161 100644
--- a/gtk/gtkcomposetable.c
+++ b/gtk/gtkcomposetable.c
@@ -49,6 +49,7 @@ gtk_compose_data_free (GtkComposeData *compose_data)
 
 typedef struct {
   GList *sequences;
+  GList *files;
   const char *compose_file;
 } GtkComposeParser;
 
@@ -60,6 +61,7 @@ parser_new (void)
   parser = g_new (GtkComposeParser, 1);
 
   parser->sequences = NULL;
+  parser->files = NULL;
   parser->compose_file = NULL;
 
   return parser;
@@ -69,6 +71,7 @@ static void
 parser_free (GtkComposeParser *parser)
 {
   g_list_free_full (parser->sequences, (GDestroyNotify) gtk_compose_data_free);
+  g_list_free_full (parser->files, g_free);
   g_free (parser);
 }
 
@@ -248,6 +251,57 @@ fail:
   return FALSE;
 }
 
+static void parser_parse_file (GtkComposeParser *parser,
+                               const char       *path);
+
+static void
+parser_handle_include (GtkComposeParser *parser,
+                       const char       *line)
+{
+  const char *p;
+  const char *start, *end;
+  char *path;
+
+  p = line + strlen ("include ");
+
+  while (g_ascii_isspace (*p))
+    p++;
+
+  if (*p != '"')
+    goto error;
+
+  p++;
+
+  start = p;
+
+  while (*p && *p != '"')
+    p++;
+
+  if (*p != '"')
+    goto error;
+
+  end = p;
+
+  p++;
+
+  while (g_ascii_isspace (*p))
+    p++;
+
+  if (*p && *p != '#')
+    goto error;
+
+  path = g_strndup (start, end - start);
+
+  parser_parse_file (parser, path);
+
+  g_free (path);
+
+  return;
+
+error:
+  g_warning ("Could not parse include: %s", line);
+}
+
 static void
 parser_parse_line (GtkComposeParser *parser,
                    const char       *line)
@@ -259,7 +313,10 @@ parser_parse_line (GtkComposeParser *parser,
     return;
 
   if (g_str_has_prefix (line, "include "))
-    return;
+    {
+      parser_handle_include (parser, line);
+      return;
+    }
 
   components = g_strsplit (line, ":", 2);
 
@@ -797,15 +854,44 @@ gtk_compose_table_new_with_list (GList   *compose_list,
   return retval;
 }
 
+static char *
+canonicalize_filename (const char *path)
+{
+  GFile *file;
+  char *retval;
+
+  file = g_file_new_for_path (path);
+  retval = g_file_get_path (file);
+
+  g_object_unref (file);
+
+  return retval;
+}
+
 static void
 parser_parse_file (GtkComposeParser *parser,
                    const char       *compose_file)
 {
+  char *path;
+
   // stash the name for the table hash
   if (parser->compose_file == NULL)
     parser->compose_file = compose_file;
 
-  parser_read_file (parser, compose_file);
+  path = canonicalize_filename (compose_file);
+
+  if (g_list_find_custom (parser->files, path, (GCompareFunc)strcmp))
+    {
+      g_warning ("include cycle detected: %s", compose_file);
+      g_free (path);
+      return;
+    }
+
+  parser->files = g_list_prepend (parser->files, path);
+
+  parser_read_file (parser, path);
+
+  parser->files = g_list_remove (parser->files, path);
 }
 
 static GtkComposeTable *
diff --git a/testsuite/gtk/compose/cycle b/testsuite/gtk/compose/cycle
new file mode 100644
index 0000000000..b65eca834f
--- /dev/null
+++ b/testsuite/gtk/compose/cycle
@@ -0,0 +1,3 @@
+include "testsuite/gtk/compose/cycle" # create an include cycle
+
+<Multi_key> <s> <e> <q> : "!"
diff --git a/testsuite/gtk/compose/include b/testsuite/gtk/compose/include
new file mode 100644
index 0000000000..a4769355a4
--- /dev/null
+++ b/testsuite/gtk/compose/include
@@ -0,0 +1,3 @@
+include "testsuite/gtk/compose/included"   # see if this works
+
+<Multi_key> <s> <e> <q> : "!"
diff --git a/testsuite/gtk/compose/include.expected b/testsuite/gtk/compose/include.expected
new file mode 100644
index 0000000000..10fbc4418c
--- /dev/null
+++ b/testsuite/gtk/compose/include.expected
@@ -0,0 +1,4 @@
+# n_seqs: 2
+# max_seq_len: 4
+<Uff20> <U73> <U61> <U73> : "\"\\"
+<Uff20> <U73> <U65> <U71> : "!" # U21
diff --git a/testsuite/gtk/compose/included b/testsuite/gtk/compose/included
new file mode 100644
index 0000000000..0d29359189
--- /dev/null
+++ b/testsuite/gtk/compose/included
@@ -0,0 +1 @@
+<Multi_key> <s> <a> <s> : "\"\\"
diff --git a/testsuite/gtk/compose/nofile b/testsuite/gtk/compose/nofile
new file mode 100644
index 0000000000..0b676e16d6
--- /dev/null
+++ b/testsuite/gtk/compose/nofile
@@ -0,0 +1,3 @@
+include "testsuite/gtk/compose/nosuchfile" # this file does not exist
+
+<Multi_key> <s> <e> <q> : "!"
diff --git a/testsuite/gtk/composetable.c b/testsuite/gtk/composetable.c
index 4348dfbea0..1414a7c99f 100644
--- a/testsuite/gtk/composetable.c
+++ b/testsuite/gtk/composetable.c
@@ -117,6 +117,50 @@ compose_table_compare (gconstpointer data)
   g_free (expected);
 }
 
+static void
+compose_table_cycle (void)
+{
+  if (g_test_subprocess ())
+    {
+      char *file;
+      GtkComposeTable *table;
+
+      file = g_build_filename (g_test_get_dir (G_TEST_DIST), "compose", "cycle", NULL);
+
+      table = gtk_compose_table_new_with_file (file);
+      g_assert_nonnull (table);
+      g_free (file);
+
+      return;
+    }
+
+  g_test_trap_subprocess (NULL, 0, 0);
+  g_test_trap_assert_stderr ("*include cycle detected*");
+  g_test_trap_assert_failed ();
+}
+
+static void
+compose_table_nofile (void)
+{
+  if (g_test_subprocess ())
+    {
+      char *file;
+      GtkComposeTable *table;
+
+      file = g_build_filename (g_test_get_dir (G_TEST_DIST), "compose", "nofile", NULL);
+
+      table = gtk_compose_table_new_with_file (file);
+      g_assert_nonnull (table);
+      g_free (file);
+
+      return;
+    }
+
+  g_test_trap_subprocess (NULL, 0, 0);
+  g_test_trap_assert_stderr ("*No such file or directory*");
+  g_test_trap_assert_failed ();
+}
+
 /* Check matching against a small table */
 static void
 compose_table_match (void)
@@ -360,6 +404,9 @@ main (int argc, char *argv[])
   g_test_add_data_func ("/compose-table/codepoint", "codepoint", compose_table_compare);
   g_test_add_data_func ("/compose-table/multi", "multi", compose_table_compare);
   g_test_add_data_func ("/compose-table/strings", "strings", compose_table_compare);
+  g_test_add_data_func ("/compose-table/include", "include", compose_table_compare);
+  g_test_add_func ("/compose-table/include-cycle", compose_table_cycle);
+  g_test_add_func ("/compose-table/include-nofile", compose_table_nofile);
   g_test_add_func ("/compose-table/match", compose_table_match);
   g_test_add_func ("/compose-table/match-compact", compose_table_match_compact);
   g_test_add_func ("/compose-table/match-algorithmic", match_algorithmic);


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