fixes misuse of vaarg on all platforms

Thu, 01 Feb 2018 18:25:23 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Thu, 01 Feb 2018 18:25:23 +0100
changeset 365
f04ab0420512
parent 364
3769ba002fd1
child 366
5228b912c925

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. */

mercurial