fileinfo: Add g_file_attribute_matcher_subtract()
authorBenjamin Otte <otte@redhat.com>
Tue, 1 Nov 2011 19:11:47 +0000 (20:11 +0100)
committerBenjamin Otte <otte@redhat.com>
Wed, 16 Nov 2011 16:19:02 +0000 (17:19 +0100)
Added as public API so I can write tests, the use case is local.

docs/reference/gio/gio-sections.txt
gio/gfileinfo.c
gio/gfileinfo.h
gio/gio.symbols

index faa7f98..71572bc 100644 (file)
@@ -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
index db4d781..87767bc 100644 (file)
@@ -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.
  *
index e276518..952dade 100644 (file)
@@ -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,
index 72eaa7d..0cb45bf 100644 (file)
@@ -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