[gtk/ci-file-filters: 20/21] Add a helper to make case-insensitive globs




commit 980150c7f79995a3ff0dce8190a6b40cf41e3eb7
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Jun 3 23:50:09 2021 -0400

    Add a helper to make case-insensitive globs
    
    This will be used in GtkFileFilter in the future.
    
    Tests included.

 gtk/fnmatch.c           | 64 +++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkprivate.h        |  3 +++
 testsuite/gtk/fnmatch.c | 37 ++++++++++++++++++++++++++++
 3 files changed, 104 insertions(+)
---
diff --git a/gtk/fnmatch.c b/gtk/fnmatch.c
index 0ad1cd8992..9b51df208d 100644
--- a/gtk/fnmatch.c
+++ b/gtk/fnmatch.c
@@ -253,3 +253,67 @@ _gtk_fnmatch (const char *pattern,
 {
   return gtk_fnmatch_intern (pattern, string, TRUE, no_leading_period, casefold);
 }
+
+/* Turn a glob pattern into a case-insensitive one, by replacing
+ * alphabetic characters by [xX] ranges.
+ */
+char *
+_gtk_make_ci_glob_pattern (const char *pattern)
+{
+  GString *s;
+  gboolean in_range = FALSE;
+
+  s = g_string_new ("");
+  for (const char *p = pattern; *p; p = g_utf8_next_char (p))
+    {
+      gunichar c = g_utf8_get_char (p);
+      if (in_range)
+        {
+          g_string_append_unichar (s, c);
+          if (c == ']')
+            in_range = FALSE;
+          continue;
+        }
+
+#if DO_ESCAPE
+      if (c == '\\')
+        {
+          g_string_append (s, "\\");
+          p = g_utf8_next_char (p);
+          if (*p == '\0')
+            break;
+
+          c = g_utf8_get_char (p);
+          g_string_append_unichar (s, c);
+          continue;
+        }
+#endif
+
+      if (c == '[')
+        {
+          g_string_append (s, "[");
+          p = g_utf8_next_char (p);
+          if (*p == '\0')
+            break;
+
+          c = g_utf8_get_char (p);
+          g_string_append_unichar (s, c);
+
+          in_range = TRUE;
+          continue;
+        }
+      else if (g_unichar_isalpha (c))
+        {
+          g_string_append (s, "[");
+          g_string_append_unichar (s, g_unichar_tolower (c));
+          g_string_append_unichar (s, g_unichar_toupper (c));
+          g_string_append (s, "]");
+        }
+      else
+        {
+          g_string_append_unichar (s, c);
+        }
+    }
+
+  return g_string_free (s, FALSE);
+}
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index d24c272065..8cb11c761c 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -64,6 +64,9 @@ gboolean      _gtk_fnmatch                (const char *pattern,
                                            gboolean    no_leading_period,
                                            gboolean    casefold);
 
+char *        _gtk_make_ci_glob_pattern   (const char *pattern);
+
+
 char        * _gtk_get_lc_ctype           (void);
 
 void          _gtk_ensure_resources       (void);
diff --git a/testsuite/gtk/fnmatch.c b/testsuite/gtk/fnmatch.c
index a614c1f99b..e16bdae016 100644
--- a/testsuite/gtk/fnmatch.c
+++ b/testsuite/gtk/fnmatch.c
@@ -125,6 +125,37 @@ test_fnmatch (gconstpointer data)
   g_assert_true (_gtk_fnmatch (test->pat, test->str, test->no_leading_period, test->ci) == test->result);
 }
 
+typedef struct {
+  const char *glob;
+  const char *ci;
+} CITest;
+
+static CITest citests[] = {
+  { "*.txt", "*.[tT][xX][tT]" },
+  { "*.TXT", "*.[tT][xX][tT]" },
+  { "*?[]-abc]t", "*?[]-abc][tT]" },
+#ifdef DO_ESCAPE
+  /* Tests of escaping */
+  { "\\\\", "\\\\" },
+  { "\\??", "\\??" },
+  { "\\**", "\\**" },
+  { "\\[", "\\[" },
+  { "\\[a-", "\\[[aA]-" },
+  { "\\[]", "\\[]" },
+#endif
+};
+
+static void
+test_ci_glob (gconstpointer data)
+{
+  const CITest *test = data;
+  char *ci;
+
+  ci = _gtk_make_ci_glob_pattern (test->glob);
+  g_assert_cmpstr (ci, ==, test->ci);
+  g_free (ci);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -136,5 +167,11 @@ main (int argc, char *argv[])
       g_test_add_data_func (path, &tests[i], test_fnmatch);
     }
 
+  for (int i = 0; i < G_N_ELEMENTS (citests); i++)
+    {
+      char *path = g_strdup_printf ("/ci-glob/test%d", i);
+      g_test_add_data_func (path, &citests[i], test_ci_glob);
+    }
+
   return g_test_run ();
 }


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