[gtk/ci-file-filters] GtkFileFilter: Allow case-insensitive patterns
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/ci-file-filters] GtkFileFilter: Allow case-insensitive patterns
- Date: Wed, 26 Sep 2018 19:58:18 +0000 (UTC)
commit 2bdbebef81d88be9b670cc028088324d584dd7da
Author: Matthias Clasen <mclasen redhat com>
Date: Wed Sep 26 15:55:47 2018 -0400
GtkFileFilter: Allow case-insensitive patterns
In the past, we've hardcoded case-insensitive matching
on Windows, and case-sensitive matching everywhere else.
With this change, we now have a way to explicitly add
case-insensitive patterns to a filter. We still interpret
all patterns case-insensitively on Windows.
gtk/fnmatch.c | 51 ++++++++++++++++++++------------------
gtk/gtkfilefilter.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++----
gtk/gtkfilefilter.h | 3 +++
gtk/gtkprivate.h | 3 ++-
4 files changed, 97 insertions(+), 30 deletions(-)
---
diff --git a/gtk/fnmatch.c b/gtk/fnmatch.c
index 87582cab69..c2a0c60586 100644
--- a/gtk/fnmatch.c
+++ b/gtk/fnmatch.c
@@ -36,14 +36,14 @@
#include <glib.h>
static gunichar
-get_char (const char **str)
+get_char (const char **str,
+ gboolean casefold)
{
gunichar c = g_utf8_get_char (*str);
*str = g_utf8_next_char (*str);
-#ifdef G_PLATFORM_WIN32
- c = g_unichar_tolower (c);
-#endif
+ if (casefold)
+ c = g_unichar_tolower (c);
return c;
}
@@ -56,13 +56,14 @@ get_char (const char **str)
static gunichar
get_unescaped_char (const char **str,
- gboolean *was_escaped)
+ gboolean *was_escaped,
+ gboolean casefold)
{
- gunichar c = get_char (str);
+ gunichar c = get_char (str, casefold);
*was_escaped = DO_ESCAPE && c == '\\';
if (*was_escaped)
- c = get_char (str);
+ c = get_char (str, casefold);
return c;
}
@@ -74,7 +75,8 @@ static gboolean
gtk_fnmatch_intern (const char *pattern,
const char *string,
gboolean component_start,
- gboolean no_leading_period)
+ gboolean no_leading_period,
+ gboolean casefold)
{
const char *p = pattern, *n = string;
@@ -82,8 +84,8 @@ gtk_fnmatch_intern (const char *pattern,
{
const char *last_n = n;
- gunichar c = get_char (&p);
- gunichar nc = get_char (&n);
+ gunichar c = get_char (&p, casefold);
+ gunichar nc = get_char (&n, casefold);
switch (c)
{
@@ -97,7 +99,7 @@ gtk_fnmatch_intern (const char *pattern,
break;
case '\\':
if (DO_ESCAPE)
- c = get_char (&p);
+ c = get_char (&p, casefold);
if (nc != c)
return FALSE;
break;
@@ -108,9 +110,9 @@ gtk_fnmatch_intern (const char *pattern,
{
const char *last_p = p;
- for (last_p = p, c = get_char (&p);
+ for (last_p = p, c = get_char (&p, casefold);
c == '?' || c == '*';
- last_p = p, c = get_char (&p))
+ last_p = p, c = get_char (&p, casefold))
{
if (c == '?')
{
@@ -120,7 +122,7 @@ gtk_fnmatch_intern (const char *pattern,
return FALSE;
else
{
- last_n = n; nc = get_char (&n);
+ last_n = n; nc = get_char (&n, casefold);
}
}
}
@@ -138,17 +140,17 @@ gtk_fnmatch_intern (const char *pattern,
}
if (DO_ESCAPE && c == '\\')
- c = get_char (&p);
+ c = get_char (&p, casefold);
for (p = last_p; nc != '\0';)
{
if ((c == '[' || nc == c) &&
- gtk_fnmatch_intern (p, last_n, component_start, no_leading_period))
+ gtk_fnmatch_intern (p, last_n, component_start, no_leading_period, casefold))
return TRUE;
component_start = (nc == G_DIR_SEPARATOR);
last_n = n;
- nc = get_char (&n);
+ nc = get_char (&n, casefold);
}
return FALSE;
@@ -170,7 +172,7 @@ gtk_fnmatch_intern (const char *pattern,
if (not)
++p;
- c = get_unescaped_char (&p, &was_escaped);
+ c = get_unescaped_char (&p, &was_escaped, casefold);
for (;;)
{
register gunichar cstart = c, cend = c;
@@ -178,15 +180,15 @@ gtk_fnmatch_intern (const char *pattern,
/* [ (unterminated) loses. */
return FALSE;
- c = get_unescaped_char (&p, &was_escaped);
+ c = get_unescaped_char (&p, &was_escaped, casefold);
if (!was_escaped && c == '-' && *p != ']')
{
- cend = get_unescaped_char (&p, &was_escaped);
+ cend = get_unescaped_char (&p, &was_escaped, casefold);
if (cend == '\0')
return FALSE;
- c = get_char (&p);
+ c = get_char (&p, casefold);
}
if (nc >= cstart && nc <= cend)
@@ -208,7 +210,7 @@ gtk_fnmatch_intern (const char *pattern,
/* [... (unterminated) loses. */
return FALSE;
- c = get_unescaped_char (&p, &was_escaped);
+ c = get_unescaped_char (&p, &was_escaped, casefold);
}
if (not)
return FALSE;
@@ -246,9 +248,10 @@ gtk_fnmatch_intern (const char *pattern,
gboolean
_gtk_fnmatch (const char *pattern,
const char *string,
- gboolean no_leading_period)
+ gboolean no_leading_period,
+ gboolean casefold)
{
- return gtk_fnmatch_intern (pattern, string, TRUE, no_leading_period);
+ return gtk_fnmatch_intern (pattern, string, TRUE, no_leading_period, casefold);
}
#undef FNMATCH_TEST_CASES
diff --git a/gtk/gtkfilefilter.c b/gtk/gtkfilefilter.c
index a63d2ecce3..5583632ca2 100644
--- a/gtk/gtkfilefilter.c
+++ b/gtk/gtkfilefilter.c
@@ -82,6 +82,7 @@ typedef struct _FilterRule FilterRule;
typedef enum {
FILTER_RULE_PATTERN,
+ FILTER_RULE_PATTERN_CI,
FILTER_RULE_MIME_TYPE,
FILTER_RULE_PIXBUF_FORMATS,
FILTER_RULE_CUSTOM
@@ -166,6 +167,7 @@ filter_rule_free (FilterRule *rule)
g_free (rule->u.mime_type);
break;
case FILTER_RULE_PATTERN:
+ case FILTER_RULE_PATTERN_CI:
g_free (rule->u.pattern);
break;
case FILTER_RULE_CUSTOM:
@@ -230,6 +232,7 @@ typedef struct {
ParserType type;
GString *string;
gboolean parsing;
+ gboolean ignore_case;
} SubParserData;
static void
@@ -242,9 +245,23 @@ parser_start_element (GMarkupParseContext *context,
{
SubParserData *data = (SubParserData*)user_data;
- if (!g_markup_collect_attributes (element_name, names, values, error,
- G_MARKUP_COLLECT_INVALID, NULL, NULL,
- G_MARKUP_COLLECT_INVALID))
+ if (strcmp (element_name, "patterns") == 0)
+ {
+ gboolean ignore_case = FALSE;
+
+ if (!g_markup_collect_attributes (element_name, names, values, error,
+ G_MARKUP_COLLECT_BOOLEAN|G_MARKUP_COLLECT_OPTIONAL, "ignore-case",
&ignore_case,
+ G_MARKUP_COLLECT_INVALID))
+ {
+ _gtk_builder_prefix_error (data->builder, context, error);
+ return;
+ }
+
+ data->ignore_case = ignore_case;
+ }
+ else if (!g_markup_collect_attributes (element_name, names, values, error,
+ G_MARKUP_COLLECT_INVALID, NULL, NULL,
+ G_MARKUP_COLLECT_INVALID))
{
_gtk_builder_prefix_error (data->builder, context, error);
return;
@@ -307,7 +324,10 @@ parser_end_element (GMarkupParseContext *context,
gtk_file_filter_add_mime_type (data->filter, data->string->str);
break;
case PARSE_PATTERNS:
- gtk_file_filter_add_pattern (data->filter, data->string->str);
+ if (data->ignore_case)
+ gtk_file_filter_add_case_insensitive_pattern (data->filter, data->string->str);
+ else
+ gtk_file_filter_add_pattern (data->filter, data->string->str);
break;
default:
break;
@@ -496,6 +516,31 @@ gtk_file_filter_add_pattern (GtkFileFilter *filter,
file_filter_add_rule (filter, rule);
}
+/**
+ * gtk_file_filter_add_case_insensitive_pattern:
+ * @filter: a #GtkFileFilter
+ * @pattern: a shell style glob
+ *
+ * Adds a rule allowing a shell style glob to a filter,
+ * ignoring case.
+ **/
+void
+gtk_file_filter_add_case_insensitive_pattern (GtkFileFilter *filter,
+ const gchar *pattern)
+{
+ FilterRule *rule;
+
+ g_return_if_fail (GTK_IS_FILE_FILTER (filter));
+ g_return_if_fail (pattern != NULL);
+
+ rule = g_slice_new (FilterRule);
+ rule->type = FILTER_RULE_PATTERN_CI;
+ rule->needed = GTK_FILE_FILTER_DISPLAY_NAME;
+ rule->u.pattern = g_strdup (pattern);
+
+ file_filter_add_rule (filter, rule);
+}
+
/**
* gtk_file_filter_add_pixbuf_formats:
* @filter: a #GtkFileFilter
@@ -609,6 +654,7 @@ NSArray * _gtk_file_filter_get_as_pattern_nsstrings (GtkFileFilter *filter)
}
break;
case FILTER_RULE_PATTERN:
+ case FILTER_RULE_PATTERN_CI:
{
// patterns will need to be stripped of their leading *.
GString *pattern = g_string_new (rule->u.pattern);
@@ -674,6 +720,7 @@ _gtk_file_filter_get_as_patterns (GtkFileFilter *filter)
return NULL;
break;
case FILTER_RULE_PATTERN:
+ case FILTER_RULE_PATTERN_CI:
g_ptr_array_add (array, g_strdup (rule->u.pattern));
break;
case FILTER_RULE_PIXBUF_FORMATS:
@@ -728,6 +775,7 @@ gtk_file_filter_filter (GtkFileFilter *filter,
for (tmp_list = filter->rules; tmp_list; tmp_list = tmp_list->next)
{
FilterRule *rule = tmp_list->data;
+ gboolean casefold = FALSE;
if ((filter_info->contains & rule->needed) != rule->needed)
continue;
@@ -752,9 +800,15 @@ gtk_file_filter_filter (GtkFileFilter *filter,
return TRUE;
}
break;
+ case FILTER_RULE_PATTERN_CI:
+ casefold = TRUE;
+ /* Fall thru */
case FILTER_RULE_PATTERN:
+#ifdef G_PLATFORM_WIN32
+ casefold = TRUE;
+#endif
if (filter_info->display_name != NULL &&
- _gtk_fnmatch (rule->u.pattern, filter_info->display_name, FALSE))
+ _gtk_fnmatch (rule->u.pattern, filter_info->display_name, FALSE, casefold))
return TRUE;
break;
case FILTER_RULE_PIXBUF_FORMATS:
@@ -821,6 +875,9 @@ gtk_file_filter_to_gvariant (GtkFileFilter *filter)
case FILTER_RULE_PATTERN:
g_variant_builder_add (&builder, "(us)", 0, rule->u.pattern);
break;
+ case FILTER_RULE_PATTERN_CI:
+ g_variant_builder_add (&builder, "(us)", 2, rule->u.pattern);
+ break;
case FILTER_RULE_MIME_TYPE:
g_variant_builder_add (&builder, "(us)", 1, rule->u.mime_type);
break;
@@ -881,6 +938,9 @@ gtk_file_filter_new_from_gvariant (GVariant *variant)
case 0:
gtk_file_filter_add_pattern (filter, tmp);
break;
+ case 2:
+ gtk_file_filter_add_case_insensitive_pattern (filter, tmp);
+ break;
case 1:
gtk_file_filter_add_mime_type (filter, tmp);
break;
diff --git a/gtk/gtkfilefilter.h b/gtk/gtkfilefilter.h
index 715556546a..7e3c470527 100644
--- a/gtk/gtkfilefilter.h
+++ b/gtk/gtkfilefilter.h
@@ -108,6 +108,9 @@ GDK_AVAILABLE_IN_ALL
void gtk_file_filter_add_pattern (GtkFileFilter *filter,
const gchar *pattern);
GDK_AVAILABLE_IN_ALL
+void gtk_file_filter_add_case_insensitive_pattern (GtkFileFilter *filter,
+ const gchar *pattern);
+GDK_AVAILABLE_IN_ALL
void gtk_file_filter_add_pixbuf_formats (GtkFileFilter *filter);
GDK_AVAILABLE_IN_ALL
void gtk_file_filter_add_custom (GtkFileFilter *filter,
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index 58b2453930..6d1bf2c71d 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -57,7 +57,8 @@ const gchar * _gtk_get_data_prefix (void);
gboolean _gtk_fnmatch (const char *pattern,
const char *string,
- gboolean no_leading_period);
+ gboolean no_leading_period,
+ gboolean casefold);
gchar * _gtk_get_lc_ctype (void);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]