adds tag filter evaluation functions

Wed, 30 May 2018 16:06:03 +0200

author
Mike Becker <universe@uap-core.de>
date
Wed, 30 May 2018 16:06:03 +0200
changeset 390
26998dc980f9
parent 389
fe855ce911f9
child 391
10305c5b0a16

adds tag filter evaluation functions

dav/sync.c file | annotate | diff | comparison | revisions
dav/sync.h file | annotate | diff | comparison | revisions
dav/tags.c file | annotate | diff | comparison | revisions
dav/tags.h file | annotate | diff | comparison | revisions
--- a/dav/sync.c	Wed May 30 12:10:58 2018 +0200
+++ b/dav/sync.c	Wed May 30 16:06:03 2018 +0200
@@ -255,31 +255,74 @@
     return 1;
 }
 
-static int matches_tags(UcxList *resource_tags, SyncTagFilter *tagfilter) {
-    if(!resource_tags) {
-        return 0;
+static int matches_tags_and(UcxList *dav_tags, UcxList *tags, int ignorecase) {
+    UCX_FOREACH(e, tags) {
+        if (!ucx_list_contains(dav_tags, e->data,
+                (cmp_func) compare_tagname, &ignorecase)) {
+            return 0;
+        }
     }
-    
-    UcxMap *res_tagmap = ucx_map_new(32);
-    UCX_FOREACH(elm, resource_tags) {
-        DavTag *t = elm->data;
-        // the value actually doesn't matter
-        ucx_map_cstr_put(res_tagmap, t->name, t);
+    return 1;
+}
+
+static int matches_tags_or(UcxList *dav_tags, UcxList *tags, int ignorecase) {
+    UCX_FOREACH(e, tags) {
+        if (ucx_list_contains(dav_tags, e->data,
+                (cmp_func) compare_tagname, &ignorecase)) {
+            return 1;
+        }
     }
-    
-    int ret = 1;
-    
-    // TODO: replace FOREACH with new tag expression evaluation
-    UCX_FOREACH(elm, tagfilter->tags) {
-        DavTag *matches_tag = elm->data;
-        if(!ucx_map_cstr_get(res_tagmap, matches_tag->name)) {
-            ret = 0;
-            break;
+    return 0;
+}
+
+static int matches_tags_one(UcxList *dav_tags, UcxList *tags, int ignorecase) {
+    int matches_exactly_one = 0;
+    UCX_FOREACH(e, tags) {
+        if (ucx_list_contains(dav_tags, e->data,
+                (cmp_func) compare_tagname, &ignorecase)) {
+            if (matches_exactly_one) {
+                return 0;
+            } else {
+                matches_exactly_one = 1;
+            }
         }
     }
-    
-    ucx_map_free(res_tagmap);
-    return ret;
+    return matches_exactly_one;
+}
+
+static int matches_tags_none(UcxList *dav_tags, UcxList *tags, int ignorecase) {
+    UCX_FOREACH(e, tags) {
+        if (ucx_list_contains(dav_tags, e->data,
+                (cmp_func) compare_tagname, &ignorecase)) {
+            return 0;
+        }
+    }
+    return 1;
+}
+
+static int matches_tags(UcxList *dav_tags, SyncTagFilter *tagfilter) {
+
+    if (tagfilter->subfilter_count > 0) {
+        int ret = 1;
+        for (size_t i = 0 ; i < tagfilter->subfilter_count ; i++) {
+            ret &= matches_tags(dav_tags, &(tagfilter->subfilters[i]));
+        }
+        return ret;
+    } else {
+        int ignorecase = 0; // TODO: maybe add support later
+        switch (tagfilter->mode) {
+        case DAV_SYNC_TAGFILTER_OR:
+            return matches_tags_or(dav_tags, tagfilter->tags, ignorecase);
+        case DAV_SYNC_TAGFILTER_AND:
+            return matches_tags_and(dav_tags, tagfilter->tags, ignorecase);
+        case DAV_SYNC_TAGFILTER_NONE:
+            return matches_tags_none(dav_tags, tagfilter->tags, ignorecase);
+        case DAV_SYNC_TAGFILTER_ONE:
+            return matches_tags_one(dav_tags, tagfilter->tags, ignorecase);
+        default:
+            abort();
+        }
+    }
 }
 
 static int res_matches_tags(DavResource *res, SyncTagFilter *tagfilter) {
@@ -291,8 +334,10 @@
     UcxList *res_tags = parse_dav_xml_taglist(tagsprop);
     
     int ret = matches_tags(res_tags, tagfilter);
-    // TODO: free list content
+    
+    ucx_list_free_content(res_tags, (ucx_destructor) free_dav_tag);
     ucx_list_free(res_tags);
+    
     return ret;
 }
 
@@ -474,8 +519,10 @@
                 continue;
             }
             
-            
+            // TODO: remove this fake and let the cmd parser store the filter
             SyncTagFilter tagfilter;
+            tagfilter.mode = DAV_SYNC_TAGFILTER_AND;
+            tagfilter.subfilter_count = 0;
             tagfilter.tags = NULL;
             char *tags_str = cmd_getoption(a, "tags");
             if(tags_str) {
--- a/dav/sync.h	Wed May 30 12:10:58 2018 +0200
+++ b/dav/sync.h	Wed May 30 16:06:03 2018 +0200
@@ -111,9 +111,24 @@
 int cmd_trash_info(CmdArgs *args);
 int cmd_empty_trash(CmdArgs *args);
 
-typedef struct {
+/**
+ * filter ::= tag_list | (operator , ("(" , filter , ")")*)
+ * tag_list ::= tag , ("," tag)*
+ * operator ::= "&" | "|" | "1" | "0"
+ */
+typedef struct SyncTagFilter SyncTagFilter;
+
+#define DAV_SYNC_TAGFILTER_AND     1
+#define DAV_SYNC_TAGFILTER_OR      2
+#define DAV_SYNC_TAGFILTER_ONE     3
+#define DAV_SYNC_TAGFILTER_NONE    4
+
+struct SyncTagFilter {
+    int mode;
     UcxList* tags;
-} SyncTagFilter;
+    size_t subfilter_count;
+    SyncTagFilter* subfilters;
+};
 
 int cmd_add_tag(CmdArgs *args);
 int cmd_remove_tag(CmdArgs *args);
--- a/dav/tags.c	Wed May 30 12:10:58 2018 +0200
+++ b/dav/tags.c	Wed May 30 16:06:03 2018 +0200
@@ -40,6 +40,22 @@
 #include <CoreFoundation/CoreFoundation.h>
 #endif
 
+void free_dav_tag(DavTag* tag) {
+    free(tag->name);
+    free(tag->color);
+    free(tag);
+}
+
+int compare_tagname(DavTag* left, DavTag* right, void* ignorecase) {
+    sstr_t leftname = sstr(left->name);
+    sstr_t rightname = sstr(right->name);
+    if (ignorecase && *((int*) ignorecase)) {
+        return sstrcasecmp(leftname, rightname);
+    } else {
+        return sstrcmp(leftname, rightname);
+    }
+}
+
 UcxList* parse_text_taglist(const char *buf, size_t length) {
     UcxList *tags = NULL;
     
--- a/dav/tags.h	Wed May 30 12:10:58 2018 +0200
+++ b/dav/tags.h	Wed May 30 16:06:03 2018 +0200
@@ -44,6 +44,10 @@
     char *color;
 } DavTag;
 
+void free_dav_tag(DavTag* tag);
+
+int compare_tagname(DavTag* left, DavTag* right, void* ignorecase);
+
 UcxList* parse_text_taglist(const char *buf, size_t length);
 UcxBuffer* create_text_taglist(UcxList *tags);
 

mercurial