moves tag filter to tags.c

Fri, 01 Jun 2018 09:01:00 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 01 Jun 2018 09:01:00 +0200
changeset 400
90c6bfa94fa2
parent 399
a985a587787f
child 401
3bb3210f3e6e

moves tag filter to tags.c

dav/scfg.h file | annotate | diff | comparison | revisions
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/scfg.h	Fri Jun 01 08:52:05 2018 +0200
+++ b/dav/scfg.h	Fri Jun 01 09:01:00 2018 +0200
@@ -35,6 +35,7 @@
 #include <regex.h>
 
 #include "db.h"
+#include "tags.h"
 
 #ifdef	__cplusplus
 extern "C" {
--- a/dav/sync.c	Fri Jun 01 08:52:05 2018 +0200
+++ b/dav/sync.c	Fri Jun 01 09:01:00 2018 +0200
@@ -257,282 +257,6 @@
     return 1;
 }
 
-// TODO: use scstr_t after update to UCX 2.0
-static size_t rtrimskip(sstr_t str, size_t skip) {
-    while (skip < str.length && isspace(str.ptr[skip])) skip++;
-    return skip;
-}
-
-static size_t parse_tagfilter_taglist(sstr_t fs, SyncTagFilter* tagfilter) {
-    size_t csvlen;
-    for (csvlen = 0 ; csvlen < fs.length ; ++csvlen) {
-        if (fs.ptr[csvlen] == ')') break;
-    }
-    fs.length = csvlen;
-        
-    tagfilter->tags = parse_csv_taglist(fs.ptr, fs.length);
-        
-    return csvlen;
-}
-
-static size_t parse_tagfilter_subfilters(sstr_t fs, SyncTagFilter* tagfilter);
-
-static size_t parse_tagfilter_filter(sstr_t fs, SyncTagFilter* tagfilter) {
-    
-    size_t consumed = rtrimskip(fs, 0);
-    fs = sstrsubs(fs, consumed);
-    
-    if (fs.length == 0) {
-        return consumed;
-    } else {
-
-        // optional operator
-        int hasop = 0;
-        if (fs.ptr[0] == '&') {
-            tagfilter->mode = DAV_SYNC_TAGFILTER_AND;
-            hasop = 1;
-        } else if (fs.ptr[0] == '|') {
-            tagfilter->mode = DAV_SYNC_TAGFILTER_OR;
-            hasop = 1;
-        } else if (fs.ptr[0] == '0') {
-            tagfilter->mode = DAV_SYNC_TAGFILTER_NONE;
-            hasop = 1;
-        } else if (fs.ptr[0] == '1') {
-            tagfilter->mode = DAV_SYNC_TAGFILTER_ONE;
-            hasop = 1;
-        } else {
-            // default operator is AND
-            tagfilter->mode = DAV_SYNC_TAGFILTER_AND;
-        }
-        
-        if (hasop) {
-            size_t skip = rtrimskip(fs, 1);
-            consumed += skip;
-            fs = sstrsubs(fs, skip);
-        }
-
-        if (fs.length > 0 && fs.ptr[0] == '(') {
-            size_t c = parse_tagfilter_subfilters(fs, tagfilter);
-            if (c) {
-                return consumed + c;
-            } else {
-                return 0;
-            }
-        } else {
-            tagfilter->subfilter_count = 0;
-            tagfilter->subfilters = NULL;
-            return consumed + parse_tagfilter_taglist(fs, tagfilter);
-        }
-    }
-}
-
-/*
- * Parses:  ( "(" , filter , ")" )+
- */
-static size_t parse_tagfilter_subfilters(sstr_t fs, SyncTagFilter* f) {
-    
-    // strategy: allocate much and give back later (instead of reallocs in loop)
-    size_t subfilter_cap = 8;
-    f->subfilters = calloc(subfilter_cap, sizeof(SyncTagFilter*));
-    f->subfilter_count = 0;
-    
-    size_t total_consumed = 0;
-    size_t c;
-    do {
-        // skip leading parenthesis (and white spaces)
-        c = rtrimskip(fs, 1);
-        fs = sstrsubs(fs, c);
-        total_consumed += c;
-    
-        // increase array capacity, if necessary
-        if (f->subfilter_count >= subfilter_cap) {
-            subfilter_cap *= 2;
-            SyncTagFilter** newarr = realloc(f->subfilters,
-                    subfilter_cap * sizeof(SyncTagFilter*));
-            if (newarr) {
-                f->subfilters = newarr;
-            } else {
-                abort(); // no error handling reachable, so we are fucked
-            }
-        }
-        
-        // allocate space for a new filter
-        SyncTagFilter* subf = calloc(1, sizeof(SyncTagFilter));
-        
-        // parse that filter
-        c = parse_tagfilter_filter(fs, subf);
-        
-        // sanity check: we must end with a closing parenthesis
-        if (c > 0 && fs.ptr[c] == ')') {
-            f->subfilters[f->subfilter_count++] = subf;
-            
-            // consume ')' and find the next parenthesis or the end-of-string
-            c = rtrimskip(fs, 1+c);
-            fs = sstrsubs(fs, c);
-            total_consumed += c;
-
-            if (fs.length == 0 || fs.ptr[0] == ')') {
-                // our job is done
-                break;
-            } else if (fs.ptr[0] != '(') {
-                // anything else than a parenthesis or end-of-string is an error
-                return 0;
-            }
-        } else {
-            free(subf);
-            break;
-        }
-        
-    } while(1);
-    
-    // try to shrink the array
-    if (f->subfilter_count > 0) {
-        SyncTagFilter** shrinked_array = realloc(f->subfilters,
-                f->subfilter_count * sizeof(SyncTagFilter*));
-        if (shrinked_array) {
-            f->subfilters = shrinked_array;
-        }
-    } else {
-        free(f->subfilters);
-        f->subfilters = NULL;
-    }
-        
-    return total_consumed;
-}
-
-SyncTagFilter* parse_tagfilter_string(const char* filterstring) {
-    SyncTagFilter* tagfilter = calloc(1, sizeof(SyncTagFilter));
-    if (!filterstring) {
-        return tagfilter;
-    }
-    
-    // TODO: use scstr_t after update to UCX 2.0
-    sstr_t fs = sstr((char*) filterstring);
-    size_t consumed = parse_tagfilter_filter(fs, tagfilter);
-    if (!consumed) {
-        free_tagfilter(tagfilter);
-        return NULL;
-    }
-    
-    // consume trailing white spaces
-    consumed = rtrimskip(fs, consumed);
-    
-    // sanity check: have we consumed the whole string?
-    if (consumed != fs.length) {
-        free_tagfilter(tagfilter);
-        return NULL;
-    }
-        
-    return tagfilter;
-}
-
-void free_tagfilter(SyncTagFilter* filter) {
-    for (size_t i = 0 ; i < filter->subfilter_count ; i++) {
-        free_tagfilter(filter->subfilters[i]);
-    }
-    free(filter->subfilters);
-    free(filter);
-}
-
-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;
-        }
-    }
-    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;
-        }
-    }
-    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;
-            }
-        }
-    }
-    return matches_exactly_one;
-}
-
-static int matches_tagfilter(UcxList *dav_tags, SyncTagFilter *tagfilter);
-
-static int matches_subfilters_and(UcxList *dav_tags, SyncTagFilter *filter) {
-    int ret = 1;
-    for (size_t i = 0 ; i < filter->subfilter_count ; i++) {
-        ret &= matches_tagfilter(dav_tags, filter->subfilters[i]);
-    }
-    return ret;
-}
-
-static int matches_subfilters_or(UcxList *dav_tags, SyncTagFilter *filter) {
-    int ret = 0;
-    for (size_t i = 0 ; i < filter->subfilter_count ; i++) {
-        ret |= matches_tagfilter(dav_tags, filter->subfilters[i]);
-    }
-    return ret;
-}
-
-static int matches_subfilters_one(UcxList *dav_tags, SyncTagFilter *filter) {
-    int one = 0;
-    for (size_t i = 0 ; i < filter->subfilter_count ; i++) {
-        if (matches_tagfilter(dav_tags, filter->subfilters[i])) {
-            if (one) {
-                return 0;
-            } else {
-                one = 1;
-            }
-        }
-    }
-    return one;
-}
-
-static int matches_tagfilter(UcxList *dav_tags, SyncTagFilter *tagfilter) {
-
-    if (tagfilter->subfilter_count > 0) {
-        switch (tagfilter->mode) {
-        case DAV_SYNC_TAGFILTER_OR:
-            return matches_subfilters_or(dav_tags, tagfilter);
-        case DAV_SYNC_TAGFILTER_AND:
-            return matches_subfilters_and(dav_tags, tagfilter);
-        case DAV_SYNC_TAGFILTER_NONE:
-            return !matches_subfilters_or(dav_tags, tagfilter);
-        case DAV_SYNC_TAGFILTER_ONE:
-            return matches_subfilters_one(dav_tags, tagfilter);
-        default:
-            abort();
-        }
-    } 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_or(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) {
     if(tagfilter->mode == DAV_SYNC_TAGFILTER_OFF) {
         return 1;
--- a/dav/sync.h	Fri Jun 01 08:52:05 2018 +0200
+++ b/dav/sync.h	Fri Jun 01 09:01:00 2018 +0200
@@ -113,29 +113,6 @@
 int cmd_trash_info(CmdArgs *args);
 int cmd_empty_trash(CmdArgs *args);
 
-/**
- * filter ::= operator? , (tag_list | ("(" , filter , ")")+)
- * tag_list ::= tag , ("," tag)*
- * operator ::= "&" | "|" | "1" | "0"
- */
-typedef struct SyncTagFilter SyncTagFilter;
-
-/* OFF must be zero, other constants are arbitrary */
-#define DAV_SYNC_TAGFILTER_OFF     0
-#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;
-    size_t subfilter_count;
-    SyncTagFilter** subfilters;
-};
-SyncTagFilter* parse_tagfilter_string(const char* filterstring);
-void free_tagfilter(SyncTagFilter* filter);
-
 int cmd_add_tag(CmdArgs *args);
 int cmd_remove_tag(CmdArgs *args);
 int cmd_set_tags(CmdArgs *args);
--- a/dav/tags.c	Fri Jun 01 08:52:05 2018 +0200
+++ b/dav/tags.c	Fri Jun 01 09:01:00 2018 +0200
@@ -28,6 +28,8 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
 
 #include <ucx/string.h>
 #include <ucx/utils.h>
@@ -324,3 +326,281 @@
 }
 #endif
 
+
+/* ----------- ----------- tag filter  ---------------------- */
+
+// TODO: use scstr_t after update to UCX 2.0
+static size_t rtrimskip(sstr_t str, size_t skip) {
+    while (skip < str.length && isspace(str.ptr[skip])) skip++;
+    return skip;
+}
+
+static size_t parse_tagfilter_taglist(sstr_t fs, SyncTagFilter* tagfilter) {
+    size_t csvlen;
+    for (csvlen = 0 ; csvlen < fs.length ; ++csvlen) {
+        if (fs.ptr[csvlen] == ')') break;
+    }
+    fs.length = csvlen;
+        
+    tagfilter->tags = parse_csv_taglist(fs.ptr, fs.length);
+        
+    return csvlen;
+}
+
+static size_t parse_tagfilter_subfilters(sstr_t fs, SyncTagFilter* tagfilter);
+
+static size_t parse_tagfilter_filter(sstr_t fs, SyncTagFilter* tagfilter) {
+    
+    size_t consumed = rtrimskip(fs, 0);
+    fs = sstrsubs(fs, consumed);
+    
+    if (fs.length == 0) {
+        return consumed;
+    } else {
+
+        // optional operator
+        int hasop = 0;
+        if (fs.ptr[0] == '&') {
+            tagfilter->mode = DAV_SYNC_TAGFILTER_AND;
+            hasop = 1;
+        } else if (fs.ptr[0] == '|') {
+            tagfilter->mode = DAV_SYNC_TAGFILTER_OR;
+            hasop = 1;
+        } else if (fs.ptr[0] == '0') {
+            tagfilter->mode = DAV_SYNC_TAGFILTER_NONE;
+            hasop = 1;
+        } else if (fs.ptr[0] == '1') {
+            tagfilter->mode = DAV_SYNC_TAGFILTER_ONE;
+            hasop = 1;
+        } else {
+            // default operator is AND
+            tagfilter->mode = DAV_SYNC_TAGFILTER_AND;
+        }
+        
+        if (hasop) {
+            size_t skip = rtrimskip(fs, 1);
+            consumed += skip;
+            fs = sstrsubs(fs, skip);
+        }
+
+        if (fs.length > 0 && fs.ptr[0] == '(') {
+            size_t c = parse_tagfilter_subfilters(fs, tagfilter);
+            if (c) {
+                return consumed + c;
+            } else {
+                return 0;
+            }
+        } else {
+            tagfilter->subfilter_count = 0;
+            tagfilter->subfilters = NULL;
+            return consumed + parse_tagfilter_taglist(fs, tagfilter);
+        }
+    }
+}
+
+/*
+ * Parses:  ( "(" , filter , ")" )+
+ */
+static size_t parse_tagfilter_subfilters(sstr_t fs, SyncTagFilter* f) {
+    
+    // strategy: allocate much and give back later (instead of reallocs in loop)
+    size_t subfilter_cap = 8;
+    f->subfilters = calloc(subfilter_cap, sizeof(SyncTagFilter*));
+    f->subfilter_count = 0;
+    
+    size_t total_consumed = 0;
+    size_t c;
+    do {
+        // skip leading parenthesis (and white spaces)
+        c = rtrimskip(fs, 1);
+        fs = sstrsubs(fs, c);
+        total_consumed += c;
+    
+        // increase array capacity, if necessary
+        if (f->subfilter_count >= subfilter_cap) {
+            subfilter_cap *= 2;
+            SyncTagFilter** newarr = realloc(f->subfilters,
+                    subfilter_cap * sizeof(SyncTagFilter*));
+            if (newarr) {
+                f->subfilters = newarr;
+            } else {
+                abort(); // no error handling reachable, so we are fucked
+            }
+        }
+        
+        // allocate space for a new filter
+        SyncTagFilter* subf = calloc(1, sizeof(SyncTagFilter));
+        
+        // parse that filter
+        c = parse_tagfilter_filter(fs, subf);
+        
+        // sanity check: we must end with a closing parenthesis
+        if (c > 0 && fs.ptr[c] == ')') {
+            f->subfilters[f->subfilter_count++] = subf;
+            
+            // consume ')' and find the next parenthesis or the end-of-string
+            c = rtrimskip(fs, 1+c);
+            fs = sstrsubs(fs, c);
+            total_consumed += c;
+
+            if (fs.length == 0 || fs.ptr[0] == ')') {
+                // our job is done
+                break;
+            } else if (fs.ptr[0] != '(') {
+                // anything else than a parenthesis or end-of-string is an error
+                return 0;
+            }
+        } else {
+            free(subf);
+            break;
+        }
+        
+    } while(1);
+    
+    // try to shrink the array
+    if (f->subfilter_count > 0) {
+        SyncTagFilter** shrinked_array = realloc(f->subfilters,
+                f->subfilter_count * sizeof(SyncTagFilter*));
+        if (shrinked_array) {
+            f->subfilters = shrinked_array;
+        }
+    } else {
+        free(f->subfilters);
+        f->subfilters = NULL;
+    }
+        
+    return total_consumed;
+}
+
+SyncTagFilter* parse_tagfilter_string(const char* filterstring) {
+    SyncTagFilter* tagfilter = calloc(1, sizeof(SyncTagFilter));
+    if (!filterstring) {
+        return tagfilter;
+    }
+    
+    // TODO: use scstr_t after update to UCX 2.0
+    sstr_t fs = sstr((char*) filterstring);
+    size_t consumed = parse_tagfilter_filter(fs, tagfilter);
+    if (!consumed) {
+        free_tagfilter(tagfilter);
+        return NULL;
+    }
+    
+    // consume trailing white spaces
+    consumed = rtrimskip(fs, consumed);
+    
+    // sanity check: have we consumed the whole string?
+    if (consumed != fs.length) {
+        free_tagfilter(tagfilter);
+        return NULL;
+    }
+        
+    return tagfilter;
+}
+
+void free_tagfilter(SyncTagFilter* filter) {
+    for (size_t i = 0 ; i < filter->subfilter_count ; i++) {
+        free_tagfilter(filter->subfilters[i]);
+    }
+    free(filter->subfilters);
+    free(filter);
+}
+
+
+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;
+        }
+    }
+    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;
+        }
+    }
+    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;
+            }
+        }
+    }
+    return matches_exactly_one;
+}
+
+static int matches_subfilters_and(UcxList *dav_tags, SyncTagFilter *filter) {
+    int ret = 1;
+    for (size_t i = 0 ; i < filter->subfilter_count ; i++) {
+        ret &= matches_tagfilter(dav_tags, filter->subfilters[i]);
+    }
+    return ret;
+}
+
+static int matches_subfilters_or(UcxList *dav_tags, SyncTagFilter *filter) {
+    int ret = 0;
+    for (size_t i = 0 ; i < filter->subfilter_count ; i++) {
+        ret |= matches_tagfilter(dav_tags, filter->subfilters[i]);
+    }
+    return ret;
+}
+
+static int matches_subfilters_one(UcxList *dav_tags, SyncTagFilter *filter) {
+    int one = 0;
+    for (size_t i = 0 ; i < filter->subfilter_count ; i++) {
+        if (matches_tagfilter(dav_tags, filter->subfilters[i])) {
+            if (one) {
+                return 0;
+            } else {
+                one = 1;
+            }
+        }
+    }
+    return one;
+}
+
+int matches_tagfilter(UcxList *dav_tags, SyncTagFilter *tagfilter) {
+
+    if (tagfilter->subfilter_count > 0) {
+        switch (tagfilter->mode) {
+        case DAV_SYNC_TAGFILTER_OR:
+            return matches_subfilters_or(dav_tags, tagfilter);
+        case DAV_SYNC_TAGFILTER_AND:
+            return matches_subfilters_and(dav_tags, tagfilter);
+        case DAV_SYNC_TAGFILTER_NONE:
+            return !matches_subfilters_or(dav_tags, tagfilter);
+        case DAV_SYNC_TAGFILTER_ONE:
+            return matches_subfilters_one(dav_tags, tagfilter);
+        default:
+            abort();
+        }
+    } 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_or(dav_tags, tagfilter->tags, ignorecase);
+        case DAV_SYNC_TAGFILTER_ONE:
+            return matches_tags_one(dav_tags, tagfilter->tags, ignorecase);
+        default:
+            abort();
+        }
+    }
+}
+
--- a/dav/tags.h	Fri Jun 01 08:52:05 2018 +0200
+++ b/dav/tags.h	Fri Jun 01 09:01:00 2018 +0200
@@ -39,11 +39,33 @@
 extern "C" {
 #endif
 
+
+/* OFF must be zero, other constants are arbitrary */
+#define DAV_SYNC_TAGFILTER_OFF     0
+#define DAV_SYNC_TAGFILTER_AND     1
+#define DAV_SYNC_TAGFILTER_OR      2
+#define DAV_SYNC_TAGFILTER_ONE     3
+#define DAV_SYNC_TAGFILTER_NONE    4
+    
 typedef struct DavTag {
     char *name;
     char *color;
 } DavTag;
 
+/**
+ * filter ::= operator? , (tag_list | ("(" , filter , ")")+)
+ * tag_list ::= tag , ("," tag)*
+ * operator ::= "&" | "|" | "1" | "0"
+ */
+typedef struct SyncTagFilter SyncTagFilter;
+
+struct SyncTagFilter {
+    int mode;
+    UcxList* tags;
+    size_t subfilter_count;
+    SyncTagFilter** subfilters;
+};
+
 void free_dav_tag(DavTag* tag);
 
 int compare_tagname(DavTag* left, DavTag* right, void* ignorecase);
@@ -60,6 +82,14 @@
 UcxList* parse_macos_taglist(const char *buf, size_t length);
 UcxBuffer* create_macos_taglist(UcxList *tags);
 
+
+/* ----------- ----------- tag filter  ---------------------- */
+
+SyncTagFilter* parse_tagfilter_string(const char* filterstring);
+void free_tagfilter(SyncTagFilter* filter);
+
+int matches_tagfilter(UcxList *dav_tags, SyncTagFilter *tagfilter);
+
 #ifdef __cplusplus
 }
 #endif

mercurial