parser for with clause + unexpected token message, if something is beyond the with clause

Sat, 04 Apr 2015 21:47:40 +0200

author
Mike Becker <universe@uap-core.de>
date
Sat, 04 Apr 2015 21:47:40 +0200
changeset 89
785f6007a0c1
parent 88
4d6b03bd7034
child 90
46971430650b

parser for with clause + unexpected token message, if something is beyond the with clause

libidav/davqlparser.c file | annotate | diff | comparison | revisions
libidav/davqlparser.h file | annotate | diff | comparison | revisions
--- a/libidav/davqlparser.c	Sat Apr 04 20:37:03 2015 +0200
+++ b/libidav/davqlparser.c	Sat Apr 04 21:47:40 2015 +0200
@@ -245,7 +245,11 @@
 #define _unexpected_end_msg "unexpected end of statement"
 #define _invalid_msg "invalid statement"
 #define _unexpected_token "unexpected token (%.*s [->]%.*s %.*s)"
+#define _expected_token "expected token '%s' before '%.*s'"
 #define _missing_quote "missing closing quote symbol (%.*s)"
+#define _parser_state "parser reached invalid state"
+#define _unknown_attribute "unknown attribute '%.*s'"
+#define _invalid_depth "invalid depth"
 
 static UcxList* dav_parse_tokenize(sstr_t src) {
     UcxList *tokens = NULL;
@@ -410,12 +414,11 @@
     /*
      *   10: field list
      *   20: FROM clause
-     *  520: expecting WHERE or WITH clause
+     *  530: expecting WHERE or WITH clause
      *   30: WHERE clause
-     *  530: expecting WITH clause
+     *  540: expecting WITH clause
      *   40: WITH clause
-     *  500: ready to quit
-     *  999: error
+     *  500: expect end
      * 
      */
     int step = 10;
@@ -433,13 +436,17 @@
         sstr_t tokendata = *token_sstr(token);
         
         switch (step) {
+        // too much input data
+        case 500:
+            dav_parse_unexpected_token(stmt, token);
+            goto ultrabreak;
         // optional clauses
-        case 520:
+        case 530:
             if (!sstrcasecmp(tokendata, S("where"))) {
                 step = 30;
             }
             /* no break and no else*/
-        case 530:
+        case 540:
             if (!sstrcasecmp(tokendata, S("with"))) {
                 step = 40;
             } else {
@@ -479,21 +486,79 @@
             DavQLExpression *expr = dav_parse_expression(stmt, token, 1);
             stmt->path = expr->srctext;
             dav_free_expression(expr);
-            step = 520;
+            step = 530;
             break;
         }
         // where clause
         case 30:
-            step = 530;
+            step = 540;
             break;
         // with clause
-        case 40:
-            step = 500;
+        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;
+            }
             break;
         }
+        default:
+            stmt->errorcode = DAVQL_ERROR_INVALID;
+            stmt->errormessage = strdup(_parser_state);
+        }
     }
     
-    if (step < 500) {
+    if (!stmt->errorcode && step < 500) {
         stmt->errorcode = DAVQL_ERROR_UNEXPECTED_END;
         stmt->errormessage = strdup(_unexpected_end_msg);
     }
--- a/libidav/davqlparser.h	Sat Apr 04 20:37:03 2015 +0200
+++ b/libidav/davqlparser.h	Sat Apr 04 21:47:40 2015 +0200
@@ -207,6 +207,12 @@
 /** Infinity recursion depth for a DavQLStatement. */
 #define DAV_DEPTH_INFINITY -1
 
+/** The with-clause contains an unknown attribute. */
+#define DAVQL_ERROR_UNKNOWN_ATTRIBUTE 20
+
+/** Depth must be greater than zero or infinity. */
+#define DAVQL_ERROR_INVALID_DEPTH 21
+
 /** A quote symbol (' or `) is missing. */
 #define DAVQL_ERROR_MISSING_QUOTE 50
 

mercurial