parser for with-clause ready to parse more attributes, but marks duplicated attributes as error

Sat, 04 Apr 2015 22:06:42 +0200

author
Mike Becker <universe@uap-core.de>
date
Sat, 04 Apr 2015 22:06:42 +0200
changeset 90
46971430650b
parent 89
785f6007a0c1
child 91
838b427267bb

parser for with-clause ready to parse more attributes, but marks duplicated attributes as error

libidav/davqlparser.c file | annotate | diff | comparison | revisions
libidav/davqlparser.h file | annotate | diff | comparison | revisions
--- a/libidav/davqlparser.c	Sat Apr 04 21:47:40 2015 +0200
+++ b/libidav/davqlparser.c	Sat Apr 04 22:06:42 2015 +0200
@@ -249,6 +249,7 @@
 #define _missing_quote "missing closing quote symbol (%.*s)"
 #define _parser_state "parser reached invalid state"
 #define _unknown_attribute "unknown attribute '%.*s'"
+#define _duplicated_attribute "duplicated attribute '%.*s'"
 #define _invalid_depth "invalid depth"
 
 static UcxList* dav_parse_tokenize(sstr_t src) {
@@ -408,6 +409,76 @@
     stmt->errormessage = errormsg.ptr;
 }
 
+static int dav_parse_with_clause(DavQLStatement *stmt, UcxList *token) {
+    sstr_t tokendata = *token_sstr(token);
+    /*
+     * 0: key
+     * 1: =
+     * 2: value
+     * TODO: commas
+     */
+    static int parsestate = 0;
+
+    /*
+     * 1: depth
+     */
+    int key = 0;
+    static int keymask = 0;
+
+    switch (parsestate) {
+    case 0:
+        if (!sstrcasecmp(tokendata, S("depth"))) {
+            key = 1;
+            parsestate = 1;
+        } else {
+            stmt->errorcode = DAVQL_ERROR_UNKNOWN_ATTRIBUTE;
+            stmt->errormessage = ucx_sprintf(_unknown_attribute,
+                sfmtarg(tokendata)).ptr;
+            break;
+        }
+        if (keymask & key) {
+            stmt->errorcode = DAVQL_ERROR_DUPLICATED_ATTRIBUTE;
+            stmt->errormessage = ucx_sprintf(_duplicated_attribute,
+                sfmtarg(tokendata)).ptr;
+        } else {
+            keymask |= key;
+        }
+        return 0;
+    case 1:
+        if (sstrcmp(tokendata, S("="))) {
+            stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN;
+            stmt->errormessage = ucx_sprintf(_expected_token,
+                "=", sfmtarg(tokendata)).ptr;
+        } else {
+            parsestate = 2;
+        }
+        return 0;
+    case 2:
+        switch (key) {
+        case 1: /* depth */
+            if (!sstrcasecmp(tokendata, S("infinity"))) {
+                stmt->depth = DAV_DEPTH_INFINITY;
+            } else {
+                char *conv = malloc(tokendata.length+1);
+                char *chk;
+                memcpy(conv, tokendata.ptr, tokendata.length);
+                conv[tokendata.length] = '\0';
+                stmt->depth = strtol(conv, &chk, 10);
+                if (*chk || stmt->depth < -1) {
+                    stmt->errorcode = DAVQL_ERROR_INVALID_DEPTH;
+                    stmt->errormessage = strdup(_invalid_depth);
+                }
+                free(conv);
+            }
+            break;
+        }
+        parsestate = 0;
+        return 1;
+    default:
+        return -1;
+    }
+}
+
 static void dav_parse_get_statement(DavQLStatement *stmt, UcxList *tokens) {
     stmt->type = DAVQL_GET;
     
@@ -417,6 +488,7 @@
      *  530: expecting WHERE or WITH clause
      *   30: WHERE clause
      *  540: expecting WITH clause
+     *  541: expecting comma for WITH clause
      *   40: WITH clause
      *  500: expect end
      * 
@@ -454,6 +526,14 @@
                 goto ultrabreak;
             }
             break;
+        case 541:
+            if (!sstrcmp(tokendata, S(","))) {
+                step = 40;
+            } else {
+                dav_parse_unexpected_token(stmt, token);
+                goto ultrabreak;
+            }
+            break;
         // field list
         case 10: {
             _Bool fromkeyword = !sstrcasecmp(tokendata, S("from"));
@@ -495,60 +575,12 @@
             break;
         // with clause
         case 40: {
-            /*
-             * 0: key
-             * 1: =
-             * 2: value
-             * TODO: commas
-             */
-            static int withparser = 0;
-            
-            /*
-             * 1: depth
-             */
-            int key;
-            
-            switch (withparser) {
-            case 0:
-                if (!sstrcasecmp(tokendata, S("depth"))) {
-                    key = 1;
-                    withparser = 1;
-                } else {
-                    stmt->errorcode = DAVQL_ERROR_UNKNOWN_ATTRIBUTE;
-                    stmt->errormessage = ucx_sprintf(_unknown_attribute,
-                        sfmtarg(tokendata)).ptr;
-                }
-                break;
-            case 1:
-                if (sstrcmp(tokendata, S("="))) {
-                    stmt->errorcode = DAVQL_ERROR_UNEXPECTED_TOKEN;
-                    stmt->errormessage = ucx_sprintf(_expected_token,
-                        "=", sfmtarg(tokendata)).ptr;
-                } else {
-                    withparser = 2;
-                }
-                break;
-            case 2:
-                switch (key) {
-                case 1: /* depth */
-                    if (!sstrcasecmp(tokendata, S("infinity"))) {
-                        stmt->depth = DAV_DEPTH_INFINITY;
-                    } else {
-                        char *conv = malloc(tokendata.length+1);
-                        char *chk;
-                        memcpy(conv, tokendata.ptr, tokendata.length);
-                        conv[tokendata.length] = '\0';
-                        stmt->depth = strtol(conv, &chk, 10);
-                        if (*chk || stmt->depth < -1) {
-                            stmt->errorcode = DAVQL_ERROR_INVALID_DEPTH;
-                            stmt->errormessage = strdup(_invalid_depth);
-                        }
-                        free(conv);
-                    }
-                    break;
-                }
-                step = 500;
-                break;
+            int withclause_result = dav_parse_with_clause(stmt, token);
+            if (withclause_result < 0) {
+                stmt->errorcode = DAVQL_ERROR_INVALID;
+                stmt->errormessage = strdup(_parser_state);
+            } else if (withclause_result > 0) {
+                step = 541;
             }
             break;
         }
--- a/libidav/davqlparser.h	Sat Apr 04 21:47:40 2015 +0200
+++ b/libidav/davqlparser.h	Sat Apr 04 22:06:42 2015 +0200
@@ -213,6 +213,9 @@
 /** Depth must be greater than zero or infinity. */
 #define DAVQL_ERROR_INVALID_DEPTH 21
 
+/** The with-clause contains an attribute more than once. */
+#define DAVQL_ERROR_DUPLICATED_ATTRIBUTE 29
+
 /** A quote symbol (' or `) is missing. */
 #define DAVQL_ERROR_MISSING_QUOTE 50
 

mercurial