adds first working parser for the complete tag filter grammar

Wed, 30 May 2018 19:56:28 +0200

author
Mike Becker <universe@uap-core.de>
date
Wed, 30 May 2018 19:56:28 +0200
changeset 396
1490c24c6077
parent 395
b491d207ee16
child 397
ddda42712f39

adds first working parser for the complete tag filter grammar

dav/sync.c file | annotate | diff | comparison | revisions
--- 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);

mercurial