[glib/filechooserentry: 6/10] fileinfo: Add g_file_attribute_matcher_subtract()



commit 0fa3555cd8497d6ef4e49a84a4717b73297719b6
Author: Benjamin Otte <otte redhat com>
Date:   Tue Nov 1 20:11:47 2011 +0100

    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                     |   85 +++++++++++++++++++++++++++++++++-
 gio/gfileinfo.h                     |    2 +
 gio/gio.symbols                     |    1 +
 4 files changed, 86 insertions(+), 3 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 71cdf40..f6282ba 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 7b07e74..0ac44e5 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;
@@ -2147,7 +2147,13 @@ matcher_optimize (GFileAttributeMatcher *matcher)
     {
       g_array_free (matcher->sub_matchers, TRUE);
       matcher->sub_matchers = NULL;
-      return;
+      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
@@ -2172,6 +2178,8 @@ matcher_optimize (GFileAttributeMatcher *matcher)
     }
 
   g_array_set_size (matcher->sub_matchers, j + 1);
+
+  return matcher;
 }
 
 /**
@@ -2254,12 +2262,83 @@ 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 d209bb4..0c1e246 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 91138f3..3761153 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



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