--- a/libidav/davqlparser.c Sun Apr 16 14:12:24 2023 +0200 +++ b/libidav/davqlparser.c Fri Apr 21 21:25:32 2023 +0200 @@ -27,7 +27,9 @@ */ #include "davqlparser.h" -#include <ucx/utils.h> +#include <cx/utils.h> +#include <cx/linked_list.h> +#include <cx/printf.h> #include <string.h> #include <stdio.h> #include <ctype.h> @@ -93,9 +95,9 @@ static void dav_debug_ql_fnames_print(DavQLStatement *stmt) { if (stmt->fields) { printf("Field names: "); - UCX_FOREACH(field, stmt->fields) { - DavQLField *f = field->data; - printf("%.*s, ", sfmtarg(f->name)); + CxIterator i = cxListIterator(stmt->fields); + cx_foreach(DavQLField *, f, i) { + printf("%.*s, ", (int)f->name.length, f->name.ptr); } printf("\b\b \b\b\n"); } @@ -103,10 +105,10 @@ static void dav_debug_ql_stmt_print(DavQLStatement *stmt) { // Basic information - size_t fieldcount = ucx_list_size(stmt->fields); + size_t fieldcount = stmt->fields ? stmt->fields->size : 0; int specialfield = 0; - if (stmt->fields) { - DavQLField* firstfield = (DavQLField*)stmt->fields->data; + if (stmt->fields && stmt->fields->size > 0) { + DavQLField* firstfield = (DavQLField*)cxListAt(stmt->fields, 0); if (firstfield->expr->type == DAVQL_IDENTIFIER) { switch (firstfield->expr->srctext.ptr[0]) { case '*': specialfield = 1; break; @@ -118,14 +120,14 @@ fieldcount--; } printf("Statement: %.*s\nType: %s\nField count: %zu %s\n", - sfmtarg(stmt->srctext), + (int)stmt->srctext.length, stmt->srctext.ptr, _map_querytype(stmt->type), fieldcount, _map_specialfield(specialfield)); dav_debug_ql_fnames_print(stmt); printf("Path: %.*s\nHas where clause: %s\n", - sfmtarg(stmt->path), + (int)stmt->path.length, stmt->path.ptr, stmt->where ? "yes" : "no"); // WITH attributes @@ -140,11 +142,11 @@ // order by clause printf("Order by: "); if (stmt->orderby) { - UCX_FOREACH(crit, stmt->orderby) { - DavQLOrderCriterion *critdata = crit->data; - printf("%.*s %s%s", sfmtarg(critdata->column->srctext), + CxIterator i = cxListIterator(stmt->orderby); + cx_foreach(DavQLOrderCriterion*, critdata, i) { + printf("%.*s %s%s", (int)critdata->column->srctext.length, critdata->column->srctext.ptr, critdata->descending ? "desc" : "asc", - crit->next ? ", " : "\n"); + i.index+1 < stmt->orderby->size ? ", " : "\n"); } } else { printf("nothing\n"); @@ -168,7 +170,7 @@ static void dav_debug_ql_expr_print(DavQLExpression *expr) { if (dav_debug_ql_expr_selected(expr)) { - sstr_t empty = ST("(empty)"); + cxstring empty = CX_STR("(empty)"); printf( "Text: %.*s\nType: %s\nOperator: %s\n", sfmtarg(expr->srctext), @@ -280,7 +282,7 @@ } DavQLExpression *examineexpr = NULL; - UcxList *examineelem = NULL; + CxList *examineelem = NULL; int examineclause = 0; while(1) { @@ -294,8 +296,8 @@ case DQLD_CMD_F: examineclause = DQLD_CMD_F; examineelem = stmt->fields; - if (stmt->fields) { - DavQLField* field = ((DavQLField*)stmt->fields->data); + if (stmt->fields && stmt->fields->size > 0) { + DavQLField* field = cxListAt(stmt->fields, 0); examineexpr = field->expr; dav_debug_ql_field_print(field); } else { @@ -310,14 +312,16 @@ case DQLD_CMD_O: examineclause = DQLD_CMD_O; examineelem = stmt->orderby; - examineexpr = stmt->orderby ? - ((DavQLOrderCriterion*)stmt->orderby->data)->column : NULL; + examineexpr = stmt->orderby && stmt->orderby->size > 0 ? + ((DavQLOrderCriterion*)cxListAt(stmt->orderby, 0))->column : NULL; dav_debug_ql_expr_print(examineexpr); break; case DQLD_CMD_N: case DQLD_CMD_P: + printf("TODO: port code to ucx 3\n"); + /* if (examineelem) { - UcxList *newelem = (cmd == DQLD_CMD_N ? + CxList *newelem = (cmd == DQLD_CMD_N ? examineelem->next : examineelem->prev); if (newelem) { examineelem = newelem; @@ -338,6 +342,7 @@ } else { printf("Currently not examining an expression list.\n"); } + */ break; case DQLD_CMD_L: if (dav_debug_ql_expr_selected(examineexpr)) { @@ -411,28 +416,28 @@ #define _error_invalid_string "string expected " _error_context #define _error_invalid_order_criterion "invalid order criterion " _error_context -#define token_sstr(token) (((DavQLToken*)(token)->data)->value) +#define token_sstr(token) ((token)->value) static void dav_error_in_context(int errorcode, const char *errormsg, - DavQLStatement *stmt, UcxList *token) { + DavQLStatement *stmt, DavQLToken *token) { // we try to achieve two things: get as many information as possible // and recover the concrete source string (and not the token strings) - sstr_t emptystring = ST(""); - sstr_t prev = token->prev ? (token->prev->prev ? + cxstring emptystring = CX_STR(""); + cxstring prev = token->prev ? (token->prev->prev ? token_sstr(token->prev->prev) : token_sstr(token->prev)) : emptystring; - sstr_t tokenstr = token_sstr(token); - sstr_t next = token->next ? (token->next->next ? + cxstring tokenstr = token_sstr(token); + cxstring next = token->next ? (token->next->next ? token_sstr(token->next->next) : token_sstr(token->next)) : emptystring; int lp = prev.length == 0 ? 0 : tokenstr.ptr-prev.ptr; - char *pn = tokenstr.ptr + tokenstr.length; + const char *pn = tokenstr.ptr + tokenstr.length; int ln = next.ptr+next.length - pn; stmt->errorcode = errorcode; - stmt->errormessage = ucx_sprintf(errormsg, + stmt->errormessage = cx_asprintf(errormsg, lp, prev.ptr, sfmtarg(tokenstr), ln, pn).ptr; @@ -448,30 +453,18 @@ #define dqlsec_mallocz(stmt, ptr, type) \ dqlsec_alloc_failed(ptr = calloc(1, sizeof(type)), stmt) -#define dqlsec_list_append_or_free(stmt, list, data) \ - do { \ - UcxList *_dqlsecbak_ = list; \ - list = ucx_list_append(list, data); \ - if (!list) { \ - free(data); \ - data = NULL; \ - (stmt)->errorcode = DAVQL_ERROR_OUT_OF_MEMORY; \ - list = _dqlsecbak_; \ - return 0; \ - } \ - } while(0) // special symbols are single tokens - the % sign MUST NOT be a special symbol static const char *special_token_symbols = ",()+-*/&|^~=!<>"; static _Bool iskeyword(DavQLToken *token) { - sstr_t keywords[] ={ST("select"), ST("set"), ST("from"), ST("at"), ST("as"), - ST("where"), ST("anywhere"), ST("like"), ST("unlike"), ST("and"), - ST("or"), ST("not"), ST("xor"), ST("with"), ST("infinity"), - ST("order"), ST("by"), ST("asc"), ST("desc") + cxstring keywords[] ={CX_STR("select"), CX_STR("set"), CX_STR("from"), CX_STR("at"), CX_STR("as"), + CX_STR("where"), CX_STR("anywhere"), CX_STR("like"), CX_STR("unlike"), CX_STR("and"), + CX_STR("or"), CX_STR("not"), CX_STR("xor"), CX_STR("with"), CX_STR("infinity"), + CX_STR("order"), CX_STR("by"), CX_STR("asc"), CX_STR("desc") }; - for (int i = 0 ; i < sizeof(keywords)/sizeof(sstr_t) ; i++) { - if (!sstrcasecmp(token->value, keywords[i])) { + for (int i = 0 ; i < sizeof(keywords)/sizeof(cxstring) ; i++) { + if (!cx_strcasecmp(token->value, keywords[i])) { return 1; } } @@ -479,18 +472,45 @@ } static _Bool islongoperator(DavQLToken *token) { - sstr_t operators[] = {ST("and"), ST("or"), ST("not"), ST("xor"), - ST("like"), ST("unlike") + cxstring operators[] = {CX_STR("and"), CX_STR("or"), CX_STR("not"), CX_STR("xor"), + CX_STR("like"), CX_STR("unlike") }; - for (int i = 0 ; i < sizeof(operators)/sizeof(sstr_t) ; i++) { - if (!sstrcasecmp(token->value, operators[i])) { + for (int i = 0 ; i < sizeof(operators)/sizeof(cxstring) ; i++) { + if (!cx_strcasecmp(token->value, operators[i])) { return 1; } } return 0; } -static UcxList* dav_parse_add_token(UcxList *tokenlist, DavQLToken *token) { +static int dav_stmt_add_field(DavQLStatement *stmt, DavQLField *field) { + if(!stmt->fields) { + stmt->fields = cxLinkedListCreateSimple(CX_STORE_POINTERS); + if(!stmt->fields) { + stmt->errorcode = DAVQL_ERROR_OUT_OF_MEMORY; + return 1; + } + } + + if(cxListAdd(stmt->fields, field)) { + stmt->errorcode = DAVQL_ERROR_OUT_OF_MEMORY; + return 1; + } + + return 0; +} + + +static void tokenlist_free(DavQLToken *tokenlist) { + DavQLToken *token = tokenlist; + while(token) { + DavQLToken *next = token->next; + free(token); + token = next; + } +} + +static int dav_parse_add_token(DavQLToken **begin, DavQLToken **end, DavQLToken *token) { // determine token class (order of if-statements is very important!) char firstchar = token->value.ptr[0]; @@ -541,24 +561,22 @@ } } - - UcxList *ret = ucx_list_append(tokenlist, token); - if (ret) { - return ret; - } else { - ucx_list_free(tokenlist); - return NULL; - } + cx_linked_list_add((void**)begin, (void**)end, offsetof(DavQLToken, prev), offsetof(DavQLToken, next), token); + return 0; } -static UcxList* dav_parse_tokenize(sstr_t src) { -#define alloc_token() do {token = malloc(sizeof(DavQLToken));\ - if(!token) {ucx_list_free(tokens); return NULL;}} while(0) -#define add_token() do {tokens = dav_parse_add_token(tokens, token); \ - if(!tokens) {return NULL;}} while(0) - UcxList *tokens = NULL; + + +static DavQLToken* dav_parse_tokenize(cxstring src) { +#define alloc_token() do {token = calloc(1, sizeof(DavQLToken));\ + if(!token) {tokenlist_free(tokens_begin); return NULL;}} while(0) +#define add_token() if(dav_parse_add_token(&tokens_begin, &tokens_end, token)) return NULL; + + DavQLToken *tokens_begin = NULL; + DavQLToken *tokens_end = NULL; DavQLToken *token = NULL; + char insequence = '\0'; for (size_t i = 0 ; i < src.length ; i++) { // quoted strings / identifiers are a single token @@ -628,14 +646,10 @@ alloc_token(); token->tokenclass = DAVQL_TOKEN_END; - token->value = S(""); - UcxList *ret = ucx_list_append(tokens, token); - if (ret) { - return ret; - } else { - ucx_list_free(tokens); - return NULL; - } + token->value = CX_STR(""); + + cx_linked_list_add((void**)&tokens_begin, (void**)&tokens_end, offsetof(DavQLToken, prev), offsetof(DavQLToken, next), token); + return tokens_begin; #undef alloc_token #undef add_token } @@ -661,18 +675,17 @@ if (crit->column) { // do it null-safe though column is expected to be set dav_free_expression(crit->column); } - free(crit); } #define token_is(token, expectedclass) (token && \ - (((DavQLToken*)(token)->data)->tokenclass == expectedclass)) + (token->tokenclass == expectedclass)) #define tokenvalue_is(token, expectedvalue) (token && \ - !sstrcasecmp(((DavQLToken*)(token)->data)->value, S(expectedvalue))) + !cx_strcasecmp(token->value, cx_str(expectedvalue))) -typedef int(*exprparser_f)(DavQLStatement*,UcxList*,DavQLExpression*); +typedef int(*exprparser_f)(DavQLStatement*,DavQLToken*,DavQLExpression*); -static int dav_parse_binary_expr(DavQLStatement* stmt, UcxList* token, +static int dav_parse_binary_expr(DavQLStatement* stmt, DavQLToken* token, DavQLExpression* expr, exprparser_f parseL, char* opc, int* opv, exprparser_f parseR) { @@ -692,7 +705,7 @@ return 0; } total_consumed += consumed; - token = ucx_list_get(token, consumed); + token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed); char *op; if (token_is(token, DAVQL_TOKEN_OPERATOR) && @@ -731,15 +744,20 @@ return total_consumed; } -static void dav_add_fmt_args(DavQLStatement *stmt, sstr_t str) { +static void fmt_args_add(DavQLStatement *stmt, void *data) { + if(!stmt->args) { + stmt->args = cxLinkedListCreateSimple(CX_STORE_POINTERS); + } + cxListAdd(stmt->args, data); +} + +static void dav_add_fmt_args(DavQLStatement *stmt, cxstring str) { int placeholder = 0; for (size_t i=0;i<str.length;i++) { char c = str.ptr[i]; if (placeholder) { if (c != '%') { - stmt->args = ucx_list_append( - stmt->args, - (void*)(intptr_t)c); + fmt_args_add(stmt, (void*)(intptr_t)c); } placeholder = 0; } else if (c == '%') { @@ -748,7 +766,7 @@ } } -static int dav_parse_literal(DavQLStatement* stmt, UcxList* token, +static int dav_parse_literal(DavQLStatement* stmt, DavQLToken* token, DavQLExpression* expr) { expr->srctext = token_sstr(token); @@ -772,7 +790,7 @@ return 0; } // add fmtspec type to query arg list - stmt->args = ucx_list_append(stmt->args, (void*)(intptr_t)expr->srctext.ptr[1]); + fmt_args_add(stmt, (void*)(intptr_t)expr->srctext.ptr[1]); } else { return 0; } @@ -781,10 +799,10 @@ } // forward declaration -static int dav_parse_expression(DavQLStatement* stmt, UcxList* token, +static int dav_parse_expression(DavQLStatement* stmt, DavQLToken* token, DavQLExpression* expr); -static int dav_parse_arglist(DavQLStatement* stmt, UcxList* token, +static int dav_parse_arglist(DavQLStatement* stmt, DavQLToken* token, DavQLExpression* expr) { expr->srctext.ptr = token_sstr(token).ptr; @@ -796,7 +814,7 @@ // RULE: Expression, {",", Expression}; DavQLExpression *arglist = expr; DavQLExpression arg; - char *lastchar = expr->srctext.ptr; + const char *lastchar = expr->srctext.ptr; int consumed; do { memset(&arg, 0, sizeof(DavQLExpression)); @@ -804,7 +822,7 @@ if (consumed) { lastchar = arg.srctext.ptr + arg.srctext.length; total_consumed += consumed; - token = ucx_list_get(token, consumed); + token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed); // look ahead for a comma if (token_is(token, DAVQL_TOKEN_COMMA)) { total_consumed++; @@ -837,7 +855,7 @@ return total_consumed; } -static int dav_parse_funccall(DavQLStatement* stmt, UcxList* token, +static int dav_parse_funccall(DavQLStatement* stmt, DavQLToken* token, DavQLExpression* expr) { // RULE: Identifier, "(", ArgumentList, ")"; @@ -861,7 +879,7 @@ return 2; } if (argtokens) { - token = ucx_list_get(token, argtokens); + token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), argtokens); dqlsec_malloc(stmt, expr->right, DavQLExpression); memcpy(expr->right, &arg, sizeof(DavQLExpression)); } else { @@ -881,10 +899,10 @@ } } -static int dav_parse_unary_expr(DavQLStatement* stmt, UcxList* token, +static int dav_parse_unary_expr(DavQLStatement* stmt, DavQLToken* token, DavQLExpression* expr) { - UcxList *firsttoken = token; // save for srctext recovery + DavQLToken *firsttoken = token; // save for srctext recovery DavQLExpression* atom = expr; int total_consumed = 0; @@ -923,7 +941,7 @@ _error_invalid_expr, stmt, token); return 0; } - token = ucx_list_get(token, consumed); + token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed); total_consumed += consumed; if (token_is(token, DAVQL_TOKEN_CLOSEP)) { token = token->next; total_consumed++; @@ -951,8 +969,8 @@ // recover source text expr->srctext.ptr = token_sstr(firsttoken).ptr; if (total_consumed > 0) { - sstr_t lasttoken = - token_sstr(ucx_list_get(firsttoken, total_consumed-1)); + cxstring lasttoken = + token_sstr((DavQLToken*)cx_linked_list_at(token, 0, offsetof(DavQLToken, next), total_consumed-1)); expr->srctext.length = lasttoken.ptr - expr->srctext.ptr + lasttoken.length; } else { @@ -964,7 +982,7 @@ return total_consumed; } -static int dav_parse_bitexpr(DavQLStatement* stmt, UcxList* token, +static int dav_parse_bitexpr(DavQLStatement* stmt, DavQLToken* token, DavQLExpression* expr) { return dav_parse_binary_expr(stmt, token, expr, @@ -973,7 +991,7 @@ dav_parse_bitexpr); } -static int dav_parse_multexpr(DavQLStatement* stmt, UcxList* token, +static int dav_parse_multexpr(DavQLStatement* stmt, DavQLToken* token, DavQLExpression* expr) { return dav_parse_binary_expr(stmt, token, expr, @@ -982,7 +1000,7 @@ dav_parse_multexpr); } -static int dav_parse_expression(DavQLStatement* stmt, UcxList* token, +static int dav_parse_expression(DavQLStatement* stmt, DavQLToken* token, DavQLExpression* expr) { return dav_parse_binary_expr(stmt, token, expr, @@ -991,7 +1009,7 @@ dav_parse_expression); } -static int dav_parse_named_field(DavQLStatement *stmt, UcxList *token, +static int dav_parse_named_field(DavQLStatement *stmt, DavQLToken *token, DavQLField *field) { int total_consumed = 0, consumed; @@ -1010,7 +1028,7 @@ return 0; } - token = ucx_list_get(token, consumed); + token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed); total_consumed += consumed; if (token_is(token, DAVQL_TOKEN_KEYWORD) && tokenvalue_is(token, "as")) { @@ -1034,13 +1052,16 @@ } } -static int dav_parse_fieldlist(DavQLStatement *stmt, UcxList *token) { +static int dav_parse_fieldlist(DavQLStatement *stmt, DavQLToken *token) { // RULE: "-" if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "-")) { DavQLField *field; dqlsec_malloc(stmt, field, DavQLField); - dqlsec_list_append_or_free(stmt, stmt->fields, field); + if(dav_stmt_add_field(stmt, field)) { + free(field); + return 0; + } dqlsec_mallocz(stmt, field->expr, DavQLExpression); field->expr->type = DAVQL_IDENTIFIER; field->expr->srctext = field->name = token_sstr(token); @@ -1051,7 +1072,10 @@ if (token_is(token, DAVQL_TOKEN_OPERATOR) && tokenvalue_is(token, "*")) { DavQLField *field; dqlsec_malloc(stmt, field, DavQLField); - dqlsec_list_append_or_free(stmt, stmt->fields, field); + if(dav_stmt_add_field(stmt, field)) { + free(field); + return 0; + } dqlsec_mallocz(stmt, field->expr, DavQLExpression); field->expr->type = DAVQL_IDENTIFIER; field->expr->srctext = field->name = token_sstr(token); @@ -1060,7 +1084,7 @@ int consumed = 1; do { - token = ucx_list_get(token, consumed); + token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed); total_consumed += consumed; if (token_is(token, DAVQL_TOKEN_COMMA)) { @@ -1071,7 +1095,10 @@ DavQLField *field; dqlsec_malloc(stmt, field, DavQLField); memcpy(field, &localfield, sizeof(DavQLField)); - dqlsec_list_append_or_free(stmt, stmt->fields, field); + if(dav_stmt_add_field(stmt, field)) { + free(field); + return 0; + } } } else { consumed = 0; @@ -1092,8 +1119,11 @@ DavQLField *field; dqlsec_malloc(stmt, field, DavQLField); memcpy(field, &localfield, sizeof(DavQLField)); - dqlsec_list_append_or_free(stmt, stmt->fields, field); - token = ucx_list_get(token, consumed); + if(dav_stmt_add_field(stmt, field)) { + free(field); + return 0; + } + token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed); total_consumed += consumed; } else if (token_is(token, DAVQL_TOKEN_IDENTIFIER) // look ahead, if the field is JUST the identifier @@ -1105,7 +1135,10 @@ dqlsec_mallocz(stmt, field->expr, DavQLExpression); field->expr->type = DAVQL_IDENTIFIER; field->expr->srctext = field->name = token_sstr(token); - dqlsec_list_append_or_free(stmt, stmt->fields, field); + if(dav_stmt_add_field(stmt, field)) { + free(field); + return 0; + } consumed = 1; total_consumed++; @@ -1137,10 +1170,10 @@ } // forward declaration -static int dav_parse_logical_expr(DavQLStatement *stmt, UcxList *token, +static int dav_parse_logical_expr(DavQLStatement *stmt, DavQLToken *token, DavQLExpression *expr); -static int dav_parse_bool_prim(DavQLStatement *stmt, UcxList *token, +static int dav_parse_bool_prim(DavQLStatement *stmt, DavQLToken *token, DavQLExpression *expr) { expr->type = DAVQL_LOGICAL; @@ -1154,9 +1187,9 @@ if (!total_consumed || stmt->errorcode) { return 0; } - token = ucx_list_get(token, total_consumed); + token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), total_consumed); - UcxList* optok = token; + DavQLToken* optok = token; // RULE: Expression, (" like " | " unlike "), String if (token_is(optok, DAVQL_TOKEN_OPERATOR) && (tokenvalue_is(optok, "like") || tokenvalue_is(optok, "unlike"))) { @@ -1248,7 +1281,7 @@ } } -static int dav_parse_bool_expr(DavQLStatement *stmt, UcxList *token, +static int dav_parse_bool_expr(DavQLStatement *stmt, DavQLToken *token, DavQLExpression *expr) { // RULE: "not ", LogicalExpression @@ -1264,7 +1297,7 @@ return 0; } if (consumed) { - sstr_t lasttok = token_sstr(ucx_list_get(token, consumed-1)); + cxstring lasttok = token_sstr((DavQLToken*)cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed-1)); expr->srctext.length = lasttok.ptr - expr->srctext.ptr + lasttok.length; return consumed + 1; @@ -1278,7 +1311,7 @@ else if (token_is(token, DAVQL_TOKEN_OPENP)) { int consumed = dav_parse_logical_expr(stmt, token->next, expr); if (consumed) { - token = ucx_list_get(token->next, consumed); + token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed); if (token_is(token, DAVQL_TOKEN_CLOSEP)) { token = token->next; @@ -1301,10 +1334,10 @@ return dav_parse_bool_prim(stmt, token, expr); } -static int dav_parse_logical_expr(DavQLStatement *stmt, UcxList *token, +static int dav_parse_logical_expr(DavQLStatement *stmt, DavQLToken *token, DavQLExpression *expr) { - UcxList *firsttoken = token; + DavQLToken *firsttoken = token; int total_consumed = 0; // RULE: BooleanLiteral, [LogicalOperator, LogicalExpression]; @@ -1320,7 +1353,7 @@ return 0; } total_consumed += consumed; - token = ucx_list_get(token, consumed); + token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed); if (token_is(token, DAVQL_TOKEN_OPERATOR)) { expr->type = DAVQL_LOGICAL; @@ -1354,7 +1387,7 @@ return 0; } total_consumed += consumed; - token = ucx_list_get(token, consumed); + token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed); dqlsec_malloc(stmt, expr->left, DavQLExpression); memcpy(expr->left, &left, sizeof(DavQLExpression)); @@ -1368,20 +1401,20 @@ // set type and recover source text if (total_consumed > 0) { expr->srctext.ptr = token_sstr(firsttoken).ptr; - sstr_t lasttok = token_sstr(ucx_list_get(firsttoken, total_consumed-1)); + cxstring lasttok = token_sstr((DavQLToken*)cx_linked_list_at(firsttoken, 0, offsetof(DavQLToken, next), total_consumed-1)); expr->srctext.length = lasttok.ptr-expr->srctext.ptr+lasttok.length; } return total_consumed; } -static int dav_parse_where_clause(DavQLStatement *stmt, UcxList *token) { +static int dav_parse_where_clause(DavQLStatement *stmt, DavQLToken *token) { dqlsec_mallocz(stmt, stmt->where, DavQLExpression); return dav_parse_logical_expr(stmt, token, stmt->where); } -static int dav_parse_with_clause(DavQLStatement *stmt, UcxList *token) { +static int dav_parse_with_clause(DavQLStatement *stmt, DavQLToken *token) { int total_consumed = 0; @@ -1404,7 +1437,7 @@ if (depthexpr->srctext.ptr[0] == '%') { stmt->depth = DAV_DEPTH_PLACEHOLDER; } else { - sstr_t depthstr = depthexpr->srctext; + cxstring depthstr = depthexpr->srctext; char *conv = malloc(depthstr.length+1); if (!conv) { dav_free_expression(depthexpr); @@ -1436,7 +1469,7 @@ return total_consumed; } -static int dav_parse_order_crit(DavQLStatement *stmt, UcxList *token, +static int dav_parse_order_crit(DavQLStatement *stmt, DavQLToken *token, DavQLOrderCriterion *crit) { // RULE: (Identifier | Number), [" asc"|" desc"]; @@ -1456,7 +1489,7 @@ dqlsec_malloc(stmt, crit->column, DavQLExpression); memcpy(crit->column, &expr, sizeof(DavQLExpression)); - token = ucx_list_get(token, consumed); + token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed); if (token_is(token, DAVQL_TOKEN_KEYWORD) && ( tokenvalue_is(token, "asc") || tokenvalue_is(token, "desc"))) { @@ -1469,12 +1502,19 @@ } } -static int dav_parse_orderby_clause(DavQLStatement *stmt, UcxList *token) { +static int dav_parse_orderby_clause(DavQLStatement *stmt, DavQLToken *token) { int total_consumed = 0, consumed; DavQLOrderCriterion crit; + if(!stmt->orderby) { + stmt->orderby = cxLinkedListCreateSimple(sizeof(DavQLOrderCriterion)); + if(!stmt->orderby) { + return 0; + } + } + // RULE: OrderByCriterion, {",", OrderByCriterion}; do { consumed = dav_parse_order_crit(stmt, token, &crit); @@ -1486,13 +1526,13 @@ stmt, token); return 0; } - token = ucx_list_get(token, consumed); + token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed); total_consumed += consumed; - DavQLOrderCriterion *criterion; - dqlsec_malloc(stmt, criterion, DavQLOrderCriterion); - memcpy(criterion, &crit, sizeof(DavQLOrderCriterion)); - dqlsec_list_append_or_free(stmt, stmt->orderby, criterion); + if(cxListAdd(stmt->orderby, &crit)) { + stmt->errorcode = DAVQL_ERROR_OUT_OF_MEMORY; + return 0; + } if (token_is(token, DAVQL_TOKEN_COMMA)) { total_consumed++; @@ -1506,7 +1546,7 @@ } -static int dav_parse_assignments(DavQLStatement *stmt, UcxList *token) { +static int dav_parse_assignments(DavQLStatement *stmt, DavQLToken *token) { // RULE: Assignment, {",", Assignment} int total_consumed = 0, consumed; @@ -1540,11 +1580,14 @@ dav_free_field(field); return total_consumed; } - token = ucx_list_get(token, consumed); + token = cx_linked_list_at(token, 0, offsetof(DavQLToken, next), consumed); total_consumed += consumed; // Add assignment to list and check if there's another one - dqlsec_list_append_or_free(stmt, stmt->fields, field); + if(dav_stmt_add_field(stmt, field)) { + free(field); + return 0; + } consumed = token_is(token, DAVQL_TOKEN_COMMA) ? 1 : 0; if (consumed) { token = token->next; @@ -1560,7 +1603,7 @@ return total_consumed; } -static int dav_parse_path(DavQLStatement *stmt, UcxList *tokens) { +static int dav_parse_path(DavQLStatement *stmt, DavQLToken *tokens) { if (token_is(tokens, DAVQL_TOKEN_STRING)) { stmt->path = token_sstr(tokens); tokens = tokens->next; @@ -1572,7 +1615,7 @@ int consumed = 1; while (!token_is(tokens, DAVQL_TOKEN_KEYWORD) && !token_is(tokens, DAVQL_TOKEN_END)) { - sstr_t toksstr = token_sstr(tokens); + cxstring toksstr = token_sstr(tokens); stmt->path.length = toksstr.ptr-stmt->path.ptr+toksstr.length; tokens = tokens->next; consumed++; @@ -1582,7 +1625,7 @@ tokenvalue_is(tokens, "%s")) { stmt->path = token_sstr(tokens); tokens = tokens->next; - stmt->args = ucx_list_append(stmt->args, (void*)(intptr_t)'s'); + fmt_args_add(stmt, (void*)(intptr_t)'s'); return 1; } else { dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, @@ -1596,11 +1639,11 @@ * @param stmt the statement object that shall contain the syntax tree * @param tokens the token list */ -static void dav_parse_select_statement(DavQLStatement *stmt, UcxList *tokens) { +static void dav_parse_select_statement(DavQLStatement *stmt, DavQLToken *tokens) { stmt->type = DAVQL_SELECT; // Consume field list - tokens = ucx_list_get(tokens, dav_parse_fieldlist(stmt, tokens)); + tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next), dav_parse_fieldlist(stmt, tokens)); if (stmt->errorcode) { return; } @@ -1616,7 +1659,7 @@ } // Consume path - tokens = ucx_list_get(tokens, dav_parse_path(stmt, tokens)); + tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next), dav_parse_path(stmt, tokens)); if (stmt->errorcode) { return; } @@ -1626,7 +1669,7 @@ if (token_is(tokens, DAVQL_TOKEN_KEYWORD) && tokenvalue_is(tokens, "with")) { tokens = tokens->next; - tokens = ucx_list_get(tokens, + tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next), dav_parse_with_clause(stmt, tokens)); } if (stmt->errorcode) { @@ -1637,7 +1680,7 @@ if (token_is(tokens, DAVQL_TOKEN_KEYWORD) && tokenvalue_is(tokens, "where")) { tokens = tokens->next; - tokens = ucx_list_get(tokens, + tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next), dav_parse_where_clause(stmt, tokens)); } else if (token_is(tokens, DAVQL_TOKEN_KEYWORD) && tokenvalue_is(tokens, "anywhere")) { @@ -1656,7 +1699,7 @@ if (token_is(tokens, DAVQL_TOKEN_KEYWORD) && tokenvalue_is(tokens, "by")) { tokens = tokens->next; - tokens = ucx_list_get(tokens, + tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next), dav_parse_orderby_clause(stmt, tokens)); } else { dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, @@ -1680,11 +1723,11 @@ } } -static void dav_parse_set_statement(DavQLStatement *stmt, UcxList *tokens) { +static void dav_parse_set_statement(DavQLStatement *stmt, DavQLToken *tokens) { stmt->type = DAVQL_SET; // Consume assignments - tokens = ucx_list_get(tokens, dav_parse_assignments(stmt, tokens)); + tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next), dav_parse_assignments(stmt, tokens)); if (stmt->errorcode) { return; } @@ -1700,7 +1743,7 @@ } // Consume path - tokens = ucx_list_get(tokens, dav_parse_path(stmt, tokens)); + tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next), dav_parse_path(stmt, tokens)); if (stmt->errorcode) { return; } @@ -1709,7 +1752,7 @@ if (token_is(tokens, DAVQL_TOKEN_KEYWORD) && tokenvalue_is(tokens, "with")) { tokens = tokens->next; - tokens = ucx_list_get(tokens, + tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next), dav_parse_with_clause(stmt, tokens)); } if (stmt->errorcode) { @@ -1720,7 +1763,7 @@ if (token_is(tokens, DAVQL_TOKEN_KEYWORD) && tokenvalue_is(tokens, "where")) { tokens = tokens->next; - tokens = ucx_list_get(tokens, + tokens = cx_linked_list_at(tokens, 0, offsetof(DavQLToken, next), dav_parse_where_clause(stmt, tokens)); } else if (token_is(tokens, DAVQL_TOKEN_KEYWORD) && tokenvalue_is(tokens, "anywhere")) { @@ -1734,7 +1777,7 @@ } } -DavQLStatement* dav_parse_statement(sstr_t srctext) { +DavQLStatement* dav_parse_statement(cxstring srctext) { DavQLStatement *stmt = calloc(1, sizeof(DavQLStatement)); // if we can't even get enough memory for the statement object or an error @@ -1753,11 +1796,11 @@ stmt->depth = 1; // save trimmed source text - stmt->srctext = sstrtrim(srctext); + stmt->srctext = cx_strtrim(srctext); if (stmt->srctext.length) { // tokenization - UcxList* tokens = dav_parse_tokenize(stmt->srctext); + DavQLToken* tokens = dav_parse_tokenize(stmt->srctext); if (tokens) { // use first token to determine query type @@ -1773,10 +1816,7 @@ } // free token data - UCX_FOREACH(token, tokens) { - free(token->data); - } - ucx_list_free(tokens); + tokenlist_free(tokens); } else { stmt->errorcode = DAVQL_ERROR_OUT_OF_MEMORY; } @@ -1797,10 +1837,10 @@ } void dav_free_statement(DavQLStatement *stmt) { - UCX_FOREACH(expr, stmt->fields) { - dav_free_field(expr->data); + if(stmt->fields) { + stmt->fields->simple_destructor = (cx_destructor_func)dav_free_field; + cxListDestroy(stmt->fields); } - ucx_list_free(stmt->fields); if (stmt->where) { dav_free_expression(stmt->where); @@ -1808,10 +1848,13 @@ if (stmt->errormessage) { free(stmt->errormessage); } - UCX_FOREACH(crit, stmt->orderby) { - dav_free_order_criterion(crit->data); + + if(stmt->orderby) { + stmt->orderby->simple_destructor = (cx_destructor_func)dav_free_order_criterion; + cxListDestroy(stmt->orderby); } - ucx_list_free(stmt->orderby); - ucx_list_free(stmt->args); + if(stmt->args) { + cxListDestroy(stmt->args); + } free(stmt); }