Thu, 01 Feb 2018 18:25:23 +0100
fixes misuse of vaarg on all platforms
The parser creates a list of all required args now. The executor then gets all arguments at once.
libidav/davqlexec.c | file | annotate | diff | comparison | revisions | |
libidav/davqlexec.h | file | annotate | diff | comparison | revisions | |
libidav/davqlparser.c | file | annotate | diff | comparison | revisions | |
libidav/davqlparser.h | file | annotate | diff | comparison | revisions |
--- a/libidav/davqlexec.c Thu Feb 01 16:31:24 2018 +0100 +++ b/libidav/davqlexec.c Thu Feb 01 18:25:23 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2018 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -39,6 +39,106 @@ #include "session.h" #include "resource.h" +DavQLArgList* dav_ql_get_args(DavQLStatement *st, va_list ap) { + DavQLArgList *args = malloc(sizeof(DavQLArgList)); + if(!args) { + return NULL; + } + args->first = NULL; + + DavQLArg *cur = NULL; + UCX_FOREACH(elm, st->args) { + intptr_t type = (intptr_t)elm->data; + DavQLArg *arg = calloc(1, sizeof(DavQLArg)); + if(!arg) { + dav_ql_free_arglist(args); + return NULL; + } + arg->type = type; + switch(type) { + case 'd': { + arg->value.d = va_arg(ap, int); + break; + } + case 'u': { + arg->value.u = va_arg(ap, unsigned int); + break; + } + case 's': { + arg->value.s = va_arg(ap, char*); + break; + } + case 't': { + arg->value.t = va_arg(ap, time_t); + break; + } + default: { + free(arg); + dav_ql_free_arglist(args); + return NULL; + } + } + if(cur) { + cur->next = arg; + } else { + args->first = arg; + } + cur = arg; + } + args->current = args->first; + return args; +} + +void dav_ql_free_arglist(DavQLArgList *args) { + DavQLArg *arg = args->first; + while(arg) { + DavQLArg *next = arg->next; + free(arg); + arg = next; + } +} + +static DavQLArg* arglist_get(DavQLArgList *args) { + DavQLArg *a = args->current; + if(a) { + args->current = a->next; + } + return a; +} + +int dav_ql_getarg_int(DavQLArgList *args) { + DavQLArg *a = arglist_get(args); + if(a && a->type == 'd') { + return a->value.d; + } + return 0; +} + +unsigned int dav_ql_getarg_uint(DavQLArgList *args) { + DavQLArg *a = arglist_get(args); + if(a && a->type == 'u') { + return a->value.u; + } + return 0; +} + +char* dav_ql_getarg_str(DavQLArgList *args) { + DavQLArg *a = arglist_get(args); + if(a && a->type == 's') { + return a->value.s; + } + return ""; +} + +time_t dav_ql_getarg_time(DavQLArgList *args) { + DavQLArg *a = arglist_get(args); + if(a && a->type == 't') { + return a->value.t; + } + return 0; +} + + DavResult dav_statement_exec(DavSession *sn, DavQLStatement *st, ...) { va_list ap; va_start(ap, st); @@ -66,7 +166,7 @@ return result; } -sstr_t dav_format_string(UcxAllocator *a, sstr_t fstr, va_list ap, davqlerror_t *error) { +sstr_t dav_format_string(UcxAllocator *a, sstr_t fstr, DavQLArgList *ap, davqlerror_t *error) { UcxBuffer *buf = ucx_buffer_new(NULL, 128, UCX_BUFFER_AUTOEXTEND); int placeholder = 0; @@ -81,17 +181,17 @@ int err = 0; switch(c) { case 's': { - char *arg = va_arg(ap, char*); + char *arg = dav_ql_getarg_str(ap); ucx_buffer_puts(buf, arg); break; } case 'd': { - int arg = va_arg(ap, int); + int arg = dav_ql_getarg_int(ap); ucx_bprintf(buf, "%d", arg); break; } case 'u': { - unsigned int arg = va_arg(ap, unsigned int); + unsigned int arg = dav_ql_getarg_uint(ap); ucx_bprintf(buf, "%u", arg); break; } @@ -338,6 +438,12 @@ result.result = NULL; result.status = 1; + DavQLArgList *args = dav_ql_get_args(st, ap); + if(!args) { + return result; + } + ucx_mempool_reg_destr(mp, args, (ucx_destructor)dav_ql_free_arglist); + int isallprop; UcxBuffer *rqbuf = fieldlist2propfindrequest(sn, mp, st->fields, &isallprop); if(!rqbuf) { @@ -356,7 +462,7 @@ sn->context, mp->allocator, field->expr, - ap); + args); if(!code) { // TODO: set error string return result; @@ -386,16 +492,17 @@ // get path string davqlerror_t error; - sstr_t path = dav_format_string(mp->allocator, st->path, ap, &error); + sstr_t path = dav_format_string(mp->allocator, st->path, args, &error); if(error) { // TODO: cleanup ucx_mempool_destroy(mp); return result; } - int depth = st->depth == DAV_DEPTH_PLACEHOLDER ? va_arg(ap, int) : st->depth; + int depth = st->depth == DAV_DEPTH_PLACEHOLDER ? + dav_ql_getarg_int(args) : st->depth; - UcxBuffer *where = dav_compile_expr(sn->context, mp->allocator, st->where, ap); + UcxBuffer *where = dav_compile_expr(sn->context, mp->allocator, st->where, args); if(st->where && !where) { // TODO: cleanup ucx_mempool_destroy(mp); @@ -627,7 +734,7 @@ return 1; } -static int add_cmd(DavContext *ctx, UcxAllocator *a, UcxBuffer *bcode, DavQLExpression *expr, va_list ap) { +static int add_cmd(DavContext *ctx, UcxAllocator *a, UcxBuffer *bcode, DavQLExpression *expr, DavQLArgList *ap) { if(!expr) { return 0; } @@ -643,7 +750,7 @@ case DAVQL_NUMBER: { cmd.type = DAVQL_CMD_INT; if(src.ptr[0] == '%') { - cmd.data.integer = va_arg(ap, int); + cmd.data.integer = dav_ql_getarg_int(ap); } else if(util_strtoint(src.ptr, &cmd.data.integer)) { ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); } else { @@ -662,7 +769,7 @@ case DAVQL_TIMESTAMP: { if(src.ptr[0] == '%') { cmd.type = DAVQL_CMD_TIMESTAMP; - cmd.data.timestamp = va_arg(ap, time_t); + cmd.data.timestamp = dav_ql_getarg_time(ap); ucx_buffer_write(&cmd, sizeof(cmd), 1, bcode); } else { // error @@ -886,7 +993,7 @@ return numcmd; } -UcxBuffer* dav_compile_expr(DavContext *ctx, UcxAllocator *a, DavQLExpression *lexpr, va_list ap) { +UcxBuffer* dav_compile_expr(DavContext *ctx, UcxAllocator *a, DavQLExpression *lexpr, DavQLArgList *ap) { UcxBuffer *bcode = ucx_buffer_new(NULL, 512, UCX_BUFFER_AUTOEXTEND); if(!bcode) { return NULL;
--- a/libidav/davqlexec.h Thu Feb 01 16:31:24 2018 +0100 +++ b/libidav/davqlexec.h Thu Feb 01 18:25:23 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2018 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -42,8 +42,27 @@ typedef struct DavQLStackObj DavQLStackObj; typedef struct DavQLRes DavQLRes; +typedef struct DavQLArg DavQLArg; +typedef struct DavQLArgList DavQLArgList; + typedef void*(*davql_func)(); // TODO: interface? +struct DavQLArg { + int type; + union DavQLArgValue{ + int d; + unsigned int u; + char *s; + time_t t; + } value; + DavQLArg *next; +}; + +struct DavQLArgList { + DavQLArg *first; + DavQLArg *current; +}; + typedef enum { DAVQL_OK = 0, DAVQL_UNSUPPORTED_FORMATCHAR, @@ -134,18 +153,26 @@ } column; _Bool descending; } DavOrderCriterion; - + +DavQLArgList* dav_ql_get_args(DavQLStatement *st, va_list ap); +void dav_ql_free_arglist(DavQLArgList *args); + +int dav_ql_getarg_int(DavQLArgList *args); +unsigned int dav_ql_getarg_uint(DavQLArgList *args); +char* dav_ql_getarg_str(DavQLArgList *args); +time_t dav_ql_getarg_time(DavQLArgList *args); + DavResult dav_statement_exec(DavSession *sn, DavQLStatement *st, ...); DavResult dav_statement_execv(DavSession *sn, DavQLStatement *st, va_list ap); -UcxBuffer* dav_path_string(sstr_t src, va_list ap, davqlerror_t *error); -sstr_t dav_format_string(UcxAllocator *a, sstr_t fstr, va_list ap, davqlerror_t *error); +UcxBuffer* dav_path_string(sstr_t src, DavQLArgList *args, davqlerror_t *error); +sstr_t dav_format_string(UcxAllocator *a, sstr_t fstr, DavQLArgList *ap, davqlerror_t *error); DavResult dav_exec_select(DavSession *sn, DavQLStatement *st, va_list ap); int dav_identifier2resprop(sstr_t src, davqlresprop_t *prop); -UcxBuffer* dav_compile_expr(DavContext *ctx, UcxAllocator *a, DavQLExpression *lexpr, va_list ap); +UcxBuffer* dav_compile_expr(DavContext *ctx, UcxAllocator *a, DavQLExpression *lexpr, DavQLArgList *ap); int dav_exec_expr(UcxBuffer *bcode, DavResource *res, DavQLStackObj *result);
--- a/libidav/davqlparser.c Thu Feb 01 16:31:24 2018 +0100 +++ b/libidav/davqlparser.c Thu Feb 01 18:25:23 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2018 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -731,6 +731,23 @@ return total_consumed; } +static void dav_add_fmt_args(DavQLStatement *stmt, sstr_t 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); + } + placeholder = 0; + } else if (c == '%') { + placeholder = 1; + } + } +} + static int dav_parse_literal(DavQLStatement* stmt, UcxList* token, DavQLExpression* expr) { @@ -739,6 +756,8 @@ expr->type = DAVQL_NUMBER; } else if (token_is(token, DAVQL_TOKEN_STRING)) { expr->type = DAVQL_STRING; + // check for format specifiers and add args + dav_add_fmt_args(stmt, expr->srctext); } else if (token_is(token, DAVQL_TOKEN_TIMESTAMP)) { expr->type = DAVQL_TIMESTAMP; } else if (token_is(token, DAVQL_TOKEN_FMTSPEC) @@ -752,6 +771,8 @@ _error_invalid_fmtspec, stmt, token); return 0; } + // add fmtspec type to query arg list + stmt->args = ucx_list_append(stmt->args, (void*)(intptr_t)expr->srctext.ptr[1]); } else { return 0; } @@ -1152,6 +1173,9 @@ expr->right->srctext = token_sstr(token); expr->srctext.length = expr->right->srctext.ptr - expr->srctext.ptr + expr->right->srctext.length; + + // fmt args + dav_add_fmt_args(stmt, expr->right->srctext); return total_consumed + 1; } else { @@ -1379,6 +1403,9 @@ if (depthexpr->type == DAVQL_NUMBER) { if (depthexpr->srctext.ptr[0] == '%') { stmt->depth = DAV_DEPTH_PLACEHOLDER; + stmt->args = ucx_list_append( + stmt->args, + (void*)(intptr_t)depthexpr->srctext.ptr[1]); } else { sstr_t depthstr = depthexpr->srctext; char *conv = malloc(depthstr.length+1); @@ -1558,6 +1585,7 @@ tokenvalue_is(tokens, "%s")) { stmt->path = token_sstr(tokens); tokens = tokens->next; + stmt->args = ucx_list_append(stmt->args, (void*)(intptr_t)'s'); return 1; } else { dav_error_in_context(DAVQL_ERROR_MISSING_TOKEN, @@ -1595,6 +1623,7 @@ if (stmt->errorcode) { return; } + dav_add_fmt_args(stmt, stmt->path); // add possible path args // Consume with clause (if any) if (token_is(tokens, DAVQL_TOKEN_KEYWORD) @@ -1786,5 +1815,6 @@ dav_free_order_criterion(crit->data); } ucx_list_free(stmt->orderby); + ucx_list_free(stmt->args); free(stmt); }
--- a/libidav/davqlparser.h Thu Feb 01 16:31:24 2018 +0100 +++ b/libidav/davqlparser.h Thu Feb 01 18:25:23 2018 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2018 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -281,6 +281,10 @@ * DAV_DEPTH_PLACEHOLDER for a placeholder. */ int depth; + /** + * A list of all required arguments + */ + UcxList* args; } DavQLStatement; /** Infinity recursion depth for a DavQLStatement. */