[glib] fileinfo: Add g_file_attribute_matcher_subtract()



commit 1985d54bb2eee39e88e62d1b749bf85f43a55721
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                     |   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 faa7f98..71572bc 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 db4d781..87767bc 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,12 +2265,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 e276518..952dade 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 72eaa7d..0cb45bf 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]