Add a helper to make case-insensitive globs

This will be used in GtkFileFilter in the future.

Tests included.
This commit is contained in:
Matthias Clasen 2021-06-03 23:50:09 -04:00
parent 8981ba4bd2
commit 47400e4bd8
3 changed files with 104 additions and 0 deletions

View File

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

View File

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

View File

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