diff -r a985a587787f -r 90c6bfa94fa2 dav/sync.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;