Wed, 30 May 2018 18:38:42 +0200
fixes whitespace handling and error detection for basic tag filters
dav/sync.c | file | annotate | diff | comparison | revisions | |
dav/sync.h | file | annotate | diff | comparison | revisions |
--- a/dav/sync.c Wed May 30 18:04:43 2018 +0200 +++ b/dav/sync.c Wed May 30 18:38:42 2018 +0200 @@ -257,9 +257,9 @@ } // TODO: use scstr_t after update to UCX 2.0 -static sstr_t rtrimskip(sstr_t str, size_t skip) { +static size_t rtrimskip(sstr_t str, size_t skip) { while (skip < str.length && isspace(str.ptr[skip])) skip++; - return sstrsubs(str, skip); + return skip; } static size_t parse_tagfilter_taglist(sstr_t fs, SyncTagFilter* tagfilter) { @@ -274,6 +274,55 @@ 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) { + memset(tagfilter, 0, sizeof(SyncTagFilter)); + 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] == '(') { + consumed += parse_tagfilter_subfilters(fs, tagfilter); + } else { + tagfilter->subfilter_count = 0; + tagfilter->subfilters = NULL; + consumed += parse_tagfilter_taglist(fs, tagfilter); + } + + return consumed; + } +} + /* * Parses: ( "(" , filter , ")" )+ */ @@ -293,50 +342,29 @@ } // TODO: use scstr_t after update to UCX 2.0 - sstr_t fs = sstrtrim(sstr((char*) filterstring)); + sstr_t fs = sstr((char*) filterstring); + size_t consumed = parse_tagfilter_filter(fs, tagfilter); - if (fs.length == 0) { - memset(tagfilter, 0, sizeof(SyncTagFilter)); - return tagfilter; - } else { - - // optional operator - if (fs.ptr[0] == '&') { - tagfilter->mode = DAV_SYNC_TAGFILTER_AND; - fs = rtrimskip(fs, 1); - } else if (fs.ptr[0] == '|') { - tagfilter->mode = DAV_SYNC_TAGFILTER_OR; - fs = rtrimskip(fs, 1); - } else if (fs.ptr[0] == '0') { - tagfilter->mode = DAV_SYNC_TAGFILTER_NONE; - fs = rtrimskip(fs, 1); - } else if (fs.ptr[0] == '1') { - tagfilter->mode = DAV_SYNC_TAGFILTER_ONE; - fs = rtrimskip(fs, 1); - } else { - // default operator is AND - tagfilter->mode = DAV_SYNC_TAGFILTER_AND; - } - - size_t consumed; - if (fs.length > 0 && fs.ptr[0] == '(') { - consumed = parse_tagfilter_subfilters(fs, tagfilter); - } else { - tagfilter->subfilter_count = 0; - tagfilter->subfilters = NULL; - consumed = parse_tagfilter_taglist(fs, tagfilter); - } - - if (consumed != fs.length) { - free(tagfilter->subfilters); - free(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, @@ -387,7 +415,7 @@ 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])); + ret &= matches_tags(dav_tags, tagfilter->subfilters[i]); } return ret; } else { @@ -489,6 +517,8 @@ fprintf(stderr, "Malformed tag filter\n"); return -1; } + // TODO: tons of memory leaks... + // call free_tagfilter() before each return SyncDirectory *dir = scfg_get_dir(a->argv[0]); if(!dir) {
--- a/dav/sync.h Wed May 30 18:04:43 2018 +0200 +++ b/dav/sync.h Wed May 30 18:38:42 2018 +0200 @@ -129,9 +129,10 @@ int mode; UcxList* tags; size_t subfilter_count; - SyncTagFilter* subfilters; + 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);