# HG changeset patch # User Mike Becker # Date 1428178002 -7200 # Node ID 46971430650bfbf2a95038a2a14a9aaefdd06d7e # Parent 785f6007a0c1849774ec01ec843b3b02146d32db parser for with-clause ready to parse more attributes, but marks duplicated attributes as error diff -r 785f6007a0c1 -r 46971430650b libidav/davqlparser.c --- 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; } diff -r 785f6007a0c1 -r 46971430650b libidav/davqlparser.h --- 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