implemented execution of field list expressions

Tue, 07 Jul 2015 20:47:02 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Tue, 07 Jul 2015 20:47:02 +0200
changeset 134
4bccc18820e8
parent 133
8c37028f5024
child 135
664aeaec8d25

implemented execution of field list expressions

libidav/davqlexec.c file | annotate | diff | comparison | revisions
libidav/davqlexec.h file | annotate | diff | comparison | revisions
libidav/resource.c file | annotate | diff | comparison | revisions
libidav/resource.h file | annotate | diff | comparison | revisions
libidav/webdav.c file | annotate | diff | comparison | revisions
libidav/webdav.h file | annotate | diff | comparison | revisions
--- a/libidav/davqlexec.c	Sat Jun 06 10:46:29 2015 +0200
+++ b/libidav/davqlexec.c	Tue Jul 07 20:47:02 2015 +0200
@@ -31,10 +31,12 @@
 #include <string.h>
 
 #include <ucx/utils.h>
+#include <ucx/map.h>
 #include "davqlexec.h"
 #include "utils.h"
 #include "methods.h"
 #include "session.h"
+#include "resource.h"
 
 DavResult* dav_statement_exec(DavSession *sn, DavQLStatement *st, ...) {
     va_list ap;
@@ -128,22 +130,228 @@
     return sstrdup_a(a, sstrn(buf->space, buf->size));
 }
 
+static int fl_add_properties(DavSession *sn, UcxMempool *mp, UcxMap *map, DavQLExpression *expression) {
+    if(!expression) {
+        return 0;
+    }
+    
+    if(expression->type == DAVQL_IDENTIFIER) {
+        DavProperty *property = ucx_mempool_malloc(mp, sizeof(DavProperty));
+
+        char *name;
+        DavNamespace *ns = dav_get_property_namespace(
+                sn->context,
+                sstrdup_a(mp->allocator, expression->srctext).ptr,
+                &name);
+        if(!ns) {
+            return -1;
+        }
+        
+        property->ns = ns;
+        property->name = name;
+        property->value = NULL;
+        
+        ucx_map_sstr_put(map, expression->srctext, property);
+    }
+    
+    if(expression->left) {
+        if(fl_add_properties(sn, mp, map, expression->left)) {
+            return -1;
+        }
+    }
+    if(expression->right) {
+        if(fl_add_properties(sn, mp, map, expression->right)) {
+            return -1;
+        }
+    }
+    
+    return 0;
+}
+
+static UcxBuffer* fieldlist2propfindrequest(DavSession *sn, UcxMempool *mp, UcxList *fields, int *isallprop) {
+    UcxMap *properties = ucx_map_new(32);
+    *isallprop = 0;
+    
+    UCX_FOREACH(elm, fields) {
+        DavQLField *field = elm->data;
+        if(!sstrcmp(field->name, S("*"))) {
+            ucx_map_free(properties);
+            *isallprop = 1;
+            return create_allprop_propfind_request();
+        } else if(!sstrcmp(field->name, S("-"))) {
+            ucx_map_free(properties);
+            return create_basic_propfind_request();
+        } else {
+            if(fl_add_properties(sn, mp, properties, field->expr)) {
+                // TODO: set error
+                return NULL;
+            }
+        }
+    }
+    
+    UcxMapIterator i = ucx_map_iterator(properties);
+    UcxKey key;
+    DavProperty *value;
+    UcxList *list = NULL;
+    UCX_MAP_FOREACH(key, value, i) {
+        list = ucx_list_append(list, value);
+    }
+    
+    UcxBuffer *reqbuf = create_propfind_request(sn, list);
+    ucx_list_free(list);
+    return reqbuf;
+}
+
+static int reset_properties(DavSession *sn, DavResult *result, DavResource *res, UcxList *fields) {
+    UcxMap *new_properties = ucx_map_new_a(sn->mp->allocator, 32);
+    DavResourceData *data = (DavResourceData*)res->data;
+    
+    // add basic properties
+    char *value;
+    
+    UcxKey cl_key = dav_property_key("DAV:", "getcontentlength");
+    value = ucx_map_get(data->properties, cl_key);
+    if(value) {
+        ucx_map_put(new_properties, cl_key, value);
+    }
+    
+    UcxKey cd_key = dav_property_key("DAV:", "creationdate");
+    value = ucx_map_get(data->properties, cd_key);
+    if(value) {
+        ucx_map_put(new_properties, cd_key, value);
+    }
+    
+    UcxKey lm_key = dav_property_key("DAV:", "getlastmodified");
+    value = ucx_map_get(data->properties, lm_key);
+    if(value) {
+        ucx_map_put(new_properties, lm_key, value);
+    }
+    
+    UcxKey ct_key = dav_property_key("DAV:", "getcontenttype");
+    value = ucx_map_get(data->properties, ct_key);
+    if(value) {
+        ucx_map_put(new_properties, ct_key, value);
+    }
+    
+    UcxKey rt_key = dav_property_key("DAV:", "resourcetype");
+    value = ucx_map_get(data->properties, rt_key);
+    if(value) {
+        ucx_map_put(new_properties, rt_key, value);
+    }
+    
+    UcxKey cn_key = dav_property_key("DAV:", "crypto-name");
+    value = ucx_map_get(data->properties, cn_key);
+    if(value) {
+        ucx_map_put(new_properties, cn_key, value);
+    }
+    
+    UcxKey ck_key = dav_property_key("DAV:", "crypto-key");
+    value = ucx_map_get(data->properties, ck_key);
+    if(value) {
+        ucx_map_put(new_properties, ck_key, value);
+    }
+    
+    // add properties from field list
+    UCX_FOREACH(elm, fields) {
+        DavCompiledField *field = elm->data;
+        DavQLStackObj field_result;
+        if(!dav_exec_expr(field->code, res, &field_result)) {
+            sstr_t str;
+            if(field_result.type == 0) {
+                str = ucx_asprintf(
+                        sn->mp->allocator,
+                        "%d",
+                        field_result.data.integer);
+            } else {
+                str = sstrdup_a(sn->mp->allocator, sstrn(
+                        field_result.data.string,
+                        field_result.length));
+            }
+            if(str.ptr) {
+                UcxKey key = dav_property_key(field->ns, field->name);
+                ucx_map_put(new_properties, key, str.ptr);
+            }
+        } else {
+            // TODO: error
+            resource_free_properties(sn, new_properties);
+            return -1;
+        }
+    }
+    
+    ucx_map_remove(data->properties, cl_key);
+    ucx_map_remove(data->properties, cd_key);
+    ucx_map_remove(data->properties, lm_key);
+    ucx_map_remove(data->properties, ct_key);
+    ucx_map_remove(data->properties, rt_key);
+    ucx_map_remove(data->properties, cn_key);
+    ucx_map_remove(data->properties, ck_key);
+    
+    resource_free_properties(sn, data->properties);
+    data->properties = new_properties;
+    
+    return 0;
+}
+
 /*
  * execute a davql select statement
  */
 DavResult dav_exec_select(DavSession *sn, DavQLStatement *st, char* path, va_list ap) {
     UcxMempool *mp = ucx_mempool_new(128);
+    DavResult result;
+    result.result = NULL;
+    result.status = 1;
     
-    // TODO: get property list
-    UcxBuffer *rqbuf = create_allprop_propfind_request();
+    int isallprop;
+    UcxBuffer *rqbuf = fieldlist2propfindrequest(sn, mp, st->fields, &isallprop);
+    if(!rqbuf) {
+        ucx_mempool_destroy(mp);
+        return result;
+    }
+    
+    // compile field list
+    UcxList *cfieldlist = NULL;
+    UCX_FOREACH(elm, st->fields) {
+        DavQLField *field = elm->data;
+        if(sstrcmp(field->name, S("*")) && sstrcmp(field->name, S("-"))) {
+            // compile field expression
+            UcxBuffer *code = dav_compile_expr(
+                    sn->context,
+                    mp->allocator,
+                    field->expr,
+                    ap);
+            if(!code) {
+                // TODO: set error string
+                return result;
+            }
+            DavCompiledField *cfield = ucx_mempool_malloc(
+                    mp,
+                    sizeof(DavCompiledField));
+            
+            char *ns;
+            char *name;
+            dav_get_property_namespace_str(
+                sn->context,
+                sstrdup_a(mp->allocator, field->name).ptr,
+                &ns,
+                &name);
+            if(!ns || !name) {
+                // TODO: set error string
+                return result;
+            }
+            cfield->ns = ns;
+            cfield->name = name;
+            cfield->code = code;
+            cfieldlist = ucx_list_append_a(mp->allocator, cfieldlist, cfield);
+        } 
+    }
     
     UcxBuffer *where = dav_compile_expr(sn->context, mp->allocator, st->where, ap);
+    if(!where) {
+        ucx_mempool_destroy(mp);
+        return result;
+    }
     
     DavResource *selroot = dav_resource_new(sn, path);
-    DavResult result;
-    result.result = selroot;
-    result.status = 0;
-    
     
     UcxList *stack = NULL; // stack with DavResource* elements
     // initialize the stack with the requested resource
@@ -181,7 +389,7 @@
                 }
                 
                 // the propfind multistatus response contains responses
-                // for the requsted resource and all childs
+                // for the requested resource and all childs
                 // determine if the response is a child or not
                 if(hrefeq(sn, root->href, response.href)) {
                     // response is the currently requested resource
@@ -199,7 +407,10 @@
                         DavQLStackObj where_result;
                         if(!dav_exec_expr(where, root, &where_result)) {
                             if(where_result.data.integer != 0) {
-                                continue;
+                                if(!reset_properties(sn, &result, root, cfieldlist)) {
+                                    continue;
+                                }
+                                result.status = -1;
                             }
                         } else {
                             result.status = -1;
@@ -217,16 +428,20 @@
                     DavQLStackObj where_result;
                     if(!dav_exec_expr(where, child, &where_result)) {
                         if(where_result.data.integer != 0) {
-                            resource_add_child(root, child);
-                            if(child->iscollection &&
-                                (st->depth < 0 || st->depth > sr->depth+1))
-                            {
-                                DavQLRes *rs = ucx_mempool_malloc(
-                                        mp,
-                                        sizeof(DavQLRes));
-                                rs->resource = child;
-                                rs->depth = sr->depth + 1;
-                                stack = ucx_list_prepend(stack, rs);
+                            if(!reset_properties(sn, &result, child, cfieldlist)) {
+                                resource_add_child(root, child);
+                                if(child->iscollection &&
+                                    (st->depth < 0 || st->depth > sr->depth+1))
+                                {
+                                    DavQLRes *rs = ucx_mempool_malloc(
+                                            mp,
+                                            sizeof(DavQLRes));
+                                    rs->resource = child;
+                                    rs->depth = sr->depth + 1;
+                                    stack = ucx_list_prepend(stack, rs);
+                                }
+                            } else {
+                                dav_resource_free(child);
                             }
                         } else {
                             dav_resource_free(child);
@@ -249,6 +464,7 @@
     ucx_mempool_destroy(mp);
     
     result.result = selroot;
+    result.status = 0;
     return result;
 }
 
@@ -314,7 +530,7 @@
                 cmd.type = DAVQL_CMD_PROP_IDENTIFIER;
                 char *ns;
                 char *name;
-                dav_get_property_namespace(
+                dav_get_property_namespace_str(
                         ctx,
                         sstrdup_a(a, src).ptr,
                         &ns,
@@ -788,18 +1004,38 @@
             }
             case DAVQL_CMD_OP_LOGICAL_AND: {
                 printf("land\n");
+                DavQLStackObj obj2 = DAVQL_POP();
+                DavQLStackObj obj1 = DAVQL_POP();
+                int v1 = obj1.type == 0 ? (int)obj1.data.integer : (obj1.data.string ? 1 : 0);
+                int v2 = obj2.type == 0 ? (int)obj2.data.integer : (obj2.data.string ? 1 : 0);
+                DAVQL_PUSH_INT(v1 && v2);
                 break;
             }
             case DAVQL_CMD_OP_LOGICAL_OR_L: {
                 printf("or_l %d\n", cmd.data.integer);
+                DavQLStackObj obj1 = DAVQL_POP();
+                if((obj1.type == 0 && obj1.data.integer) || (obj1.type == 1 && obj1.data.string)) {
+                    DAVQL_PUSH_INT(1);
+                    i += cmd.data.integer; // jump, skip right subtree of 'or'
+                }
                 break;
             }
             case DAVQL_CMD_OP_LOGICAL_OR: {
                 printf("or\n");
+                DavQLStackObj obj2 = DAVQL_POP();
+                DavQLStackObj obj1 = DAVQL_POP();
+                int v1 = obj1.type == 0 ? (int)obj1.data.integer : (obj1.data.string ? 1 : 0);
+                int v2 = obj2.type == 0 ? (int)obj2.data.integer : (obj2.data.string ? 1 : 0);
+                DAVQL_PUSH_INT(v1 || v2);
                 break;
             }
             case DAVQL_CMD_OP_LOGICAL_XOR: {
                 printf("lxor\n");
+                DavQLStackObj obj2 = DAVQL_POP();
+                DavQLStackObj obj1 = DAVQL_POP();
+                int v1 = obj1.type == 0 ? (int)obj1.data.integer : (obj1.data.string ? 1 : 0);
+                int v2 = obj2.type == 0 ? (int)obj2.data.integer : (obj2.data.string ? 1 : 0);
+                DAVQL_PUSH_INT(!v1 != !v2);
                 break;
             }
             case DAVQL_CMD_OP_EQ: {
@@ -892,132 +1128,3 @@
     
     return ret;
 }
-
-
-void print_bytecode(UcxBuffer *bcode) {
-    bcode->pos = 0;
-    DavQLCmd cmd;
-    while(ucx_buffer_read(&cmd, sizeof(DavQLCmd), 1, bcode) == 1) {
-        switch(cmd.type) {
-            case DAVQL_CMD_INT: {
-                printf("int %lld\n", cmd.data.integer);
-                break;
-            }
-            case DAVQL_CMD_STRING: {
-                printf("string \"%.*s\"\n", cmd.data.string.length, cmd.data.string.ptr);
-                break;
-            }
-            case DAVQL_CMD_TIMESTAMP: {
-                printf("timestamp %d\n", cmd.data.timestamp);
-                break;
-            }
-            case DAVQL_CMD_RES_IDENTIFIER: {
-                char *rid[8] = {"name", "path", "href", "contentlength", "contenttype", "creationdate", "lastmodified", "iscollection"};
-                printf("resprop %s\n", rid[cmd.data.resprop]);
-                break;
-            }
-            case DAVQL_CMD_PROP_IDENTIFIER: {
-                printf("property %s:%s\n", cmd.data.property.ns, cmd.data.property.name);
-                break;
-            }
-            case DAVQL_CMD_OP_UNARY_ADD: {
-                printf("uadd\n");
-                break;
-            }
-            case DAVQL_CMD_OP_UNARY_SUB: {
-                printf("usub\n");
-                break;
-            }
-            case DAVQL_CMD_OP_UNARY_NEG: {
-                printf("uneg\n");
-                break;
-            }
-            case DAVQL_CMD_OP_BINARY_ADD: {
-                printf("add\n");
-                break;
-            }
-            case DAVQL_CMD_OP_BINARY_SUB: {
-                printf("sub\n");
-                break;
-            }
-            case DAVQL_CMD_OP_BINARY_MUL: {
-                printf("mul\n");
-                break;
-            }
-            case DAVQL_CMD_OP_BINARY_DIV: {
-                printf("div\n");
-                break;
-            }
-            case DAVQL_CMD_OP_BINARY_AND: {
-                printf("and\n");
-                break;
-            }
-            case DAVQL_CMD_OP_BINARY_OR: {
-                printf("or\n");
-                break;
-            }
-            case DAVQL_CMD_OP_BINARY_XOR: {
-                printf("xor\n");
-                break;
-            }
-            case DAVQL_CMD_OP_LOGICAL_NOT: {
-                printf("not\n");
-                break;
-            }
-            case DAVQL_CMD_OP_LOGICAL_AND: {
-                printf("land\n");
-                break;
-            }
-            case DAVQL_CMD_OP_LOGICAL_OR_L: {
-                printf("or_l %d\n", cmd.data.integer);
-                break;
-            }
-            case DAVQL_CMD_OP_LOGICAL_OR: {
-                printf("or\n");
-                break;
-            }
-            case DAVQL_CMD_OP_LOGICAL_XOR: {
-                printf("lxor\n");
-                break;
-            }
-            case DAVQL_CMD_OP_EQ: {
-                printf("eq\n");
-                break;
-            }
-            case DAVQL_CMD_OP_NEQ: {
-                printf("neq\n");
-                break;
-            }
-            case DAVQL_CMD_OP_LT: {
-                printf("lt\n");
-                break;
-            }
-            case DAVQL_CMD_OP_GT: {
-                printf("gt\n");
-                break;
-            }
-            case DAVQL_CMD_OP_LE: {
-                printf("le\n");
-                break;
-            }
-            case DAVQL_CMD_OP_GE: {
-                printf("ge\n");
-                break;
-            }
-            case DAVQL_CMD_OP_LIKE: {
-                printf("like\n");
-                break;
-            }
-            case DAVQL_CMD_OP_UNLIKE: {
-                printf("unlike\n");
-                break;
-            }
-            case DAVQL_CMD_CALL: {
-                printf("call %x\n", cmd.data.func);
-                break;
-            }
-        }
-    }
-    printf("\n");
-}
-
--- a/libidav/davqlexec.h	Sat Jun 06 10:46:29 2015 +0200
+++ b/libidav/davqlexec.h	Tue Jul 07 20:47:02 2015 +0200
@@ -118,6 +118,12 @@
     DavResource *resource;
     int depth;
 };
+
+typedef struct DavCompiledField {
+    char *ns;
+    char *name;
+    UcxBuffer *code;
+} DavCompiledField;
     
 DavResult* dav_statement_exec(DavSession *sn, DavQLStatement *st, ...);
 DavResult* dav_statement_execv(DavSession *sn, DavQLStatement *st, va_list ap);
@@ -131,7 +137,7 @@
 
 int dav_exec_expr(UcxBuffer *bcode, DavResource *res, DavQLStackObj *result);
 
-void print_bytecode(UcxBuffer *bcode);
+
 
 #ifdef	__cplusplus
 }
--- a/libidav/resource.c	Sat Jun 06 10:46:29 2015 +0200
+++ b/libidav/resource.c	Tue Jul 07 20:47:02 2015 +0200
@@ -105,6 +105,15 @@
     return res;
 }
 
+void resource_free_properties(DavSession *sn, UcxMap *properties) {
+    UcxMapIterator i = ucx_map_iterator(properties);
+    char *property;
+    UCX_MAP_FOREACH(key, property, i) {
+        dav_session_free(sn, property);
+    }
+    ucx_map_free(properties);
+}
+
 void dav_resource_free(DavResource *res) {
     DavSession *sn = res->session;
     
@@ -115,13 +124,7 @@
     }
     
     DavResourceData *data = res->data;
-    UcxMapIterator i = ucx_map_iterator(data->properties);
-    UcxKey key;
-    char *property;
-    UCX_MAP_FOREACH(key, property, i) {
-        dav_session_free(sn, property);
-    }
-    ucx_map_free(data->properties);
+    resource_free_properties(sn, data->properties);
     
     UCX_FOREACH(elm, data->set) {
         DavProperty *p = elm->data;
@@ -272,7 +275,7 @@
 char* dav_get_property(DavResource *res, char *name) {
     char *pns;
     char *pname;
-    dav_get_property_namespace(res->session->context, name, &pns, &pname);
+    dav_get_property_namespace_str(res->session->context, name, &pns, &pname);
     return dav_get_property_ns(res, pns, pname);
 }
 
@@ -305,7 +308,7 @@
 void dav_set_property(DavResource *res, char *name, char *value) {
     char *pns;
     char *pname;
-    dav_get_property_namespace(res->session->context, name, &pns, &pname);
+    dav_get_property_namespace_str(res->session->context, name, &pns, &pname);
     dav_set_property_ns(res, pns, pname, value);
 }
 
@@ -332,7 +335,7 @@
 void dav_remove_property(DavResource *res, char *name) {
     char *pns;
     char *pname;
-    dav_get_property_namespace(res->session->context, name, &pns, &pname);
+    dav_get_property_namespace_str(res->session->context, name, &pns, &pname);
     dav_remove_property_ns(res, pns, pname);
 }
 
--- a/libidav/resource.h	Sat Jun 06 10:46:29 2015 +0200
+++ b/libidav/resource.h	Tue Jul 07 20:47:02 2015 +0200
@@ -59,6 +59,8 @@
 
 DavResource* dav_resource_new_full(DavSession *sn, char *parent_path, char *name, char *href);
 
+void resource_free_properties(DavSession *sn, UcxMap *properties);
+
 void resource_set_href(DavResource *res, sstr_t href);
 
 void resource_set_info(DavResource *res, char *href_str);
--- a/libidav/webdav.c	Sat Jun 06 10:46:29 2015 +0200
+++ b/libidav/webdav.c	Tue Jul 07 20:47:02 2015 +0200
@@ -208,12 +208,14 @@
     return ucx_map_sstr_get(context->namespaces, prefix);
 }
 
-void dav_get_property_namespace(
+void dav_get_property_namespace_str(
         DavContext *ctx,
         char *prefixed_name,
         char **ns,
         char **name)
 {
+    // TODO: rewrite using dav_get_property_ns
+    
     char *pname = strchr(prefixed_name, ':');
     char *pns = "DAV:";
     if(pname) {
@@ -234,6 +236,31 @@
     *name = pname;
 }
 
+DavNamespace* dav_get_property_namespace(
+        DavContext *ctx,
+        char *prefixed_name,
+        char **name)
+{
+    char *pname = strchr(prefixed_name, ':');
+    if(pname) {
+        DavNamespace *ns = dav_get_namespace_s(
+                ctx,
+                sstrn(prefixed_name, pname-prefixed_name));
+        if(ns) {
+            *name = pname +1;
+            return ns;
+        } else {
+            *name = NULL;
+            return NULL;
+        }
+    } else {
+        *name = prefixed_name;
+        return dav_get_namespace_s(ctx, S("D"));
+    }
+}
+
+// TODO: add sstr_t version of dav_get_property_ns
+
 
 DavResource* dav_get(DavSession *sn, char *path, char *properties) {  
     CURL *handle = sn->handle;
--- a/libidav/webdav.h	Sat Jun 06 10:46:29 2015 +0200
+++ b/libidav/webdav.h	Tue Jul 07 20:47:02 2015 +0200
@@ -197,11 +197,15 @@
 DavResource* dav_query(DavSession *sn, char *query, ...);
 
 UcxKey dav_property_key(char *ns, char *name);
-void dav_get_property_namespace(
+void dav_get_property_namespace_str(
         DavContext *ctx,
         char *prefixed_name,
         char **ns,
         char **name);
+DavNamespace* dav_get_property_namespace(
+        DavContext *ctx,
+        char *prefixed_name,
+        char **name);
 
 /* ------------------------ resource functions ------------------------ */
 

mercurial