# HG changeset patch # User Mike Becker # Date 1527689163 -7200 # Node ID 26998dc980f97efdaeafbf0c7c8af20dcc023ef8 # Parent fe855ce911f931c84962872289ad3bec895b7a2f adds tag filter evaluation functions diff -r fe855ce911f9 -r 26998dc980f9 dav/sync.c --- 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) { diff -r fe855ce911f9 -r 26998dc980f9 dav/sync.h --- 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); diff -r fe855ce911f9 -r 26998dc980f9 dav/tags.c --- 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 #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; diff -r fe855ce911f9 -r 26998dc980f9 dav/tags.h --- 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);