# HG changeset patch # User Olaf Wintermann # Date 1436294822 -7200 # Node ID 4bccc18820e8f5b6c36d8342921d0ba7840fe603 # Parent 8c37028f5024cf261c6f2168b52990a7a15d7e69 implemented execution of field list expressions diff -r 8c37028f5024 -r 4bccc18820e8 libidav/davqlexec.c --- 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 #include +#include #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"); -} - diff -r 8c37028f5024 -r 4bccc18820e8 libidav/davqlexec.h --- 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 } diff -r 8c37028f5024 -r 4bccc18820e8 libidav/resource.c --- 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); } diff -r 8c37028f5024 -r 4bccc18820e8 libidav/resource.h --- 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); diff -r 8c37028f5024 -r 4bccc18820e8 libidav/webdav.c --- 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; diff -r 8c37028f5024 -r 4bccc18820e8 libidav/webdav.h --- 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 ------------------------ */