From 1985d54bb2eee39e88e62d1b749bf85f43a55721 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 1 Nov 2011 20:11:47 +0100 Subject: [PATCH] fileinfo: Add g_file_attribute_matcher_subtract() Added as public API so I can write tests, the use case is local. --- docs/reference/gio/gio-sections.txt | 1 + gio/gfileinfo.c | 83 ++++++++++++++++++++++++++++- gio/gfileinfo.h | 2 + gio/gio.symbols | 1 + 4 files changed, 85 insertions(+), 2 deletions(-) diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index faa7f9809..71572bc13 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -365,6 +365,7 @@ g_file_info_set_symlink_target g_file_info_set_sort_order g_file_attribute_matcher_new g_file_attribute_matcher_ref +g_file_attribute_matcher_subtract g_file_attribute_matcher_unref g_file_attribute_matcher_matches g_file_attribute_matcher_matches_only diff --git a/gio/gfileinfo.c b/gio/gfileinfo.c index db4d7812c..87767bc0d 100644 --- a/gio/gfileinfo.c +++ b/gio/gfileinfo.c @@ -2136,7 +2136,7 @@ sub_matcher_matches (SubMatcher *matcher, /* Call this function after modifying a matcher. * It will ensure all the invariants other functions rely on. */ -static void +static GFileAttributeMatcher * matcher_optimize (GFileAttributeMatcher *matcher) { SubMatcher *submatcher, *compare; @@ -2153,6 +2153,12 @@ matcher_optimize (GFileAttributeMatcher *matcher) return matcher; } + if (matcher->sub_matchers->len == 0) + { + g_file_attribute_matcher_unref (matcher); + return NULL; + } + /* sort sub_matchers by id (and then mask), so we can bsearch * and compare matchers in O(N) instead of O(N²) */ g_array_sort (matcher->sub_matchers, compare_sub_matchers); @@ -2175,6 +2181,8 @@ matcher_optimize (GFileAttributeMatcher *matcher) } g_array_set_size (matcher->sub_matchers, j + 1); + + return matcher; } /** @@ -2257,11 +2265,82 @@ g_file_attribute_matcher_new (const char *attributes) g_strfreev (split); - matcher_optimize (matcher); + matcher = matcher_optimize (matcher); return matcher; } +/** + * g_file_attribute_matcher_subtract: + * @matcher: Matcher to subtract from + * @subtract: The matcher to subtract + * + * Subtracts all attributes of @subtract from @matcher and returns + * a matcher that supports those attributes. + * + * Note that currently it is not possible to remove a single + * attribute when the @matcher matches the whole namespace - or remove + * a namespace or attribute when the matcher matches everything. This + * is a limitation of the current implementation, but may be fixed + * in the future. + * + * Returns: A file attribute matcher matching all attributes of + * @matcher that are not matched by @subtract + **/ +GFileAttributeMatcher * +g_file_attribute_matcher_subtract (GFileAttributeMatcher *matcher, + GFileAttributeMatcher *subtract) +{ + GFileAttributeMatcher *result; + guint mi, si; + SubMatcher *msub, *ssub; + + if (matcher == NULL) + return NULL; + if (subtract == NULL) + return g_file_attribute_matcher_ref (matcher); + if (subtract->all) + return NULL; + if (matcher->all) + return g_file_attribute_matcher_ref (matcher); + + result = g_malloc0 (sizeof (GFileAttributeMatcher)); + result->ref = 1; + result->sub_matchers = g_array_new (FALSE, FALSE, sizeof (SubMatcher)); + + si = 0; + g_assert (subtract->sub_matchers->len > 0); + ssub = &g_array_index (subtract->sub_matchers, SubMatcher, si); + + for (mi = 0; mi < matcher->sub_matchers->len; mi++) + { + msub = &g_array_index (matcher->sub_matchers, SubMatcher, mi); + +retry: + if (sub_matcher_matches (ssub, msub)) + continue; + + si++; + if (si >= subtract->sub_matchers->len) + break; + + ssub = &g_array_index (subtract->sub_matchers, SubMatcher, si); + if (ssub->id <= msub->id) + goto retry; + + g_array_append_val (result->sub_matchers, *msub); + } + + if (mi < matcher->sub_matchers->len) + g_array_append_vals (result->sub_matchers, + &g_array_index (matcher->sub_matchers, SubMatcher, mi), + matcher->sub_matchers->len - mi); + + result = matcher_optimize (result); + + return result; +} + /** * g_file_attribute_matcher_ref: * @matcher: a #GFileAttributeMatcher. diff --git a/gio/gfileinfo.h b/gio/gfileinfo.h index e276518e2..952dade01 100644 --- a/gio/gfileinfo.h +++ b/gio/gfileinfo.h @@ -939,6 +939,8 @@ GType g_file_attribute_matcher_get_type (void) G_GNUC_CON GFileAttributeMatcher *g_file_attribute_matcher_new (const char *attributes); GFileAttributeMatcher *g_file_attribute_matcher_ref (GFileAttributeMatcher *matcher); void g_file_attribute_matcher_unref (GFileAttributeMatcher *matcher); +GFileAttributeMatcher *g_file_attribute_matcher_subtract (GFileAttributeMatcher *matcher, + GFileAttributeMatcher *subtract); gboolean g_file_attribute_matcher_matches (GFileAttributeMatcher *matcher, const char *attribute); gboolean g_file_attribute_matcher_matches_only (GFileAttributeMatcher *matcher, diff --git a/gio/gio.symbols b/gio/gio.symbols index 72eaa7d82..0cb45bf5d 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -431,6 +431,7 @@ g_file_info_set_symlink_target g_file_info_set_sort_order g_file_attribute_matcher_get_type g_file_attribute_matcher_new +g_file_attribute_matcher_subtract g_file_attribute_matcher_ref g_file_attribute_matcher_unref g_file_attribute_matcher_matches