# HG changeset patch # User Mike Becker # Date 1527702988 -7200 # Node ID 1490c24c6077fb4d1002ccf509c4937f1664916b # Parent b491d207ee16676ce443ed96ca18254d0b5c1606 adds first working parser for the complete tag filter grammar diff -r b491d207ee16 -r 1490c24c6077 dav/sync.c --- a/dav/sync.c Wed May 30 18:38:42 2018 +0200 +++ b/dav/sync.c Wed May 30 19:56:28 2018 +0200 @@ -282,7 +282,6 @@ fs = sstrsubs(fs, consumed); if (fs.length == 0) { - memset(tagfilter, 0, sizeof(SyncTagFilter)); return consumed; } else { @@ -312,38 +311,107 @@ } if (fs.length > 0 && fs.ptr[0] == '(') { - consumed += parse_tagfilter_subfilters(fs, tagfilter); + size_t c = parse_tagfilter_subfilters(fs, tagfilter); + if (c) { + return consumed + c; + } else { + return 0; + } } else { tagfilter->subfilter_count = 0; tagfilter->subfilters = NULL; - consumed += parse_tagfilter_taglist(fs, tagfilter); + return consumed + parse_tagfilter_taglist(fs, tagfilter); } - - return consumed; } } /* * Parses: ( "(" , filter , ")" )+ */ -static size_t parse_tagfilter_subfilters(sstr_t fs, SyncTagFilter* tagfilter) { - // TODO: implement - tagfilter->subfilter_count = 0; - tagfilter->subfilters = NULL; +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; - return 0; + // 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 = malloc(sizeof(SyncTagFilter)); + SyncTagFilter* tagfilter = calloc(1, sizeof(SyncTagFilter)); if (!filterstring) { - memset(tagfilter, 0, sizeof(SyncTagFilter)); 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);