UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2018 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <inttypes.h> 33 34 #include <cx/utils.h> 35 #include <cx/map.h> 36 #include <cx/hash_map.h> 37 #include <cx/printf.h> 38 #include <cx/mempool.h> 39 40 #include "davqlexec.h" 41 #include "utils.h" 42 #include "methods.h" 43 #include "session.h" 44 #include "resource.h" 45 46 DavQLArgList* dav_ql_get_args(DavQLStatement *st, va_list ap) { 47 DavQLArgList *args = malloc(sizeof(DavQLArgList)); 48 if(!args) { 49 return NULL; 50 } 51 args->first = NULL; 52 53 if(!st->args) { 54 args->first = NULL; 55 args->current = NULL; 56 return args; 57 } 58 59 DavQLArg *cur = NULL; 60 CxIterator i = cxListIterator(st->args); 61 cx_foreach(void*, data, i) { 62 intptr_t type = (intptr_t)data; 63 DavQLArg *arg = calloc(1, sizeof(DavQLArg)); 64 if(!arg) { 65 dav_ql_free_arglist(args); 66 return NULL; 67 } 68 arg->type = type; 69 switch(type) { 70 case 'd': { 71 arg->value.d = va_arg(ap, int); 72 break; 73 } 74 case 'u': { 75 arg->value.u = va_arg(ap, unsigned int); 76 break; 77 } 78 case 's': { 79 arg->value.s = va_arg(ap, char*); 80 break; 81 } 82 case 't': { 83 arg->value.t = va_arg(ap, time_t); 84 break; 85 } 86 default: { 87 free(arg); 88 dav_ql_free_arglist(args); 89 return NULL; 90 } 91 } 92 if(cur) { 93 cur->next = arg; 94 } else { 95 args->first = arg; 96 } 97 cur = arg; 98 } 99 args->current = args->first; 100 return args; 101 } 102 103 void dav_ql_free_arglist(DavQLArgList *args) { 104 DavQLArg *arg = args->first; 105 while(arg) { 106 DavQLArg *next = arg->next; 107 free(arg); 108 arg = next; 109 } 110 free(args); 111 } 112 113 static DavQLArg* arglist_get(DavQLArgList *args) { 114 DavQLArg *a = args->current; 115 if(a) { 116 args->current = a->next; 117 } 118 return a; 119 } 120 121 int dav_ql_getarg_int(DavQLArgList *args) { 122 DavQLArg *a = arglist_get(args); 123 if(a && a->type == 'd') { 124 return a->value.d; 125 } 126 return 0; 127 } 128 129 unsigned int dav_ql_getarg_uint(DavQLArgList *args) { 130 DavQLArg *a = arglist_get(args); 131 if(a && a->type == 'u') { 132 return a->value.u; 133 } 134 return 0; 135 } 136 137 char* dav_ql_getarg_str(DavQLArgList *args) { 138 DavQLArg *a = arglist_get(args); 139 if(a && a->type == 's') { 140 return a->value.s; 141 } 142 return ""; 143 } 144 145 time_t dav_ql_getarg_time(DavQLArgList *args) { 146 DavQLArg *a = arglist_get(args); 147 if(a && a->type == 't') { 148 return a->value.t; 149 } 150 return 0; 151 } 152 153 154 DavResult dav_statement_exec(DavSession *sn, DavQLStatement *st, ...) { 155 va_list ap; 156 va_start(ap, st); 157 DavResult result = dav_statement_execv(sn, st, ap); 158 va_end(ap); 159 return result; 160 } 161 162 DavResult dav_statement_execv(DavSession *sn, DavQLStatement *st, va_list ap) { 163 DavResult result; 164 result.result = NULL; 165 result.status = 1; 166 167 // make sure the statement was successfully parsed 168 if(st->type == DAVQL_ERROR) { 169 return result; 170 } 171 172 if(st->type == DAVQL_SELECT) { 173 return dav_exec_select(sn, st, ap); 174 } else { 175 // TODO 176 } 177 178 return result; 179 } 180 181 cxmutstr dav_format_string(const CxAllocator *a, cxstring fstr, DavQLArgList *ap, davqlerror_t *error) { 182 CxBuffer buf; 183 cxBufferInit(&buf, NULL, 128, a, CX_BUFFER_AUTO_EXTEND); 184 185 int placeholder = 0; 186 for(int i=0;i<fstr.length;i++) { 187 char c = fstr.ptr[i]; 188 if(placeholder) { 189 if(c == '%') { 190 // no placeholder, %% transposes to % 191 cxBufferPut(&buf, c); 192 } else { 193 // detect placeholder type and insert arg 194 int err = 0; 195 switch(c) { 196 case 's': { 197 char *arg = dav_ql_getarg_str(ap); 198 cxBufferPutString(&buf, arg); 199 break; 200 } 201 case 'd': { 202 int arg = dav_ql_getarg_int(ap); 203 cx_bprintf(&buf, "%d", arg); 204 break; 205 } 206 case 'u': { 207 unsigned int arg = dav_ql_getarg_uint(ap); 208 cx_bprintf(&buf, "%u", arg); 209 break; 210 } 211 case 't': { 212 // time arguments not supported for strings 213 err = 1; 214 break; 215 } 216 default: { 217 *error = DAVQL_UNKNOWN_FORMATCHAR; 218 err = 1; 219 } 220 } 221 if(err) { 222 cxBufferDestroy(&buf); 223 return (cxmutstr){NULL,0}; 224 } 225 } 226 placeholder = 0; 227 } else { 228 if(c == '%') { 229 placeholder = 1; 230 } else { 231 cxBufferPut(&buf, c); 232 } 233 } 234 } 235 if(cxBufferPut(&buf, '\0')) { 236 *error = DAVQL_OOM; 237 cxBufferDestroy(&buf); 238 return (cxmutstr){NULL, 0}; 239 } 240 *error = DAVQL_OK; 241 242 return cx_mutstrn(buf.space, buf.size-1); 243 } 244 245 static int fl_add_properties(DavSession *sn, const CxAllocator *a, CxMap *map, DavQLExpression *expression) { 246 if(!expression) { 247 return 0; 248 } 249 250 if(expression->type == DAVQL_IDENTIFIER) { 251 DavProperty *property = cxMalloc(a, sizeof(DavProperty)); 252 253 char *name; 254 DavNamespace *ns = dav_get_property_namespace( 255 sn->context, 256 cx_strdup_a(a, expression->srctext).ptr, 257 &name); 258 if(!ns) { 259 return -1; 260 } 261 262 property->ns = ns; 263 property->name = name; 264 property->value = NULL; 265 266 cxMapPut(map, cx_hash_key(expression->srctext.ptr, expression->srctext.length), property); 267 } 268 269 if(expression->left) { 270 if(fl_add_properties(sn, a, map, expression->left)) { 271 return -1; 272 } 273 } 274 if(expression->right) { 275 if(fl_add_properties(sn, a, map, expression->right)) { 276 return -1; 277 } 278 } 279 280 return 0; 281 } 282 283 static CxBuffer* fieldlist2propfindrequest(DavSession *sn, const CxAllocator *a, CxList *fields, int *isallprop) { 284 CxMap *properties = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 32); 285 *isallprop = 0; 286 287 CxIterator i = cxListIterator(fields); 288 cx_foreach(DavQLField*, field, i) { 289 if(!cx_strcmp(field->name, CX_STR("*"))) { 290 cxMapDestroy(properties); 291 *isallprop = 1; 292 return create_allprop_propfind_request(); 293 } else if(!cx_strcmp(field->name, CX_STR("-"))) { 294 cxMapDestroy(properties); 295 return create_propfind_request(sn, NULL, "propfind", 0); 296 } else { 297 if(fl_add_properties(sn, a, properties, field->expr)) { 298 // TODO: set error 299 cxMapDestroy(properties); 300 return NULL; 301 } 302 } 303 } 304 305 i = cxMapIteratorValues(properties); 306 CxList *list = cxLinkedListCreateSimple(CX_STORE_POINTERS); 307 cx_foreach(DavProperty*, value, i) { 308 cxListAdd(list, value); 309 } 310 311 CxBuffer *reqbuf = create_propfind_request(sn, list, "propfind", 0); 312 cxListDestroy(list); 313 cxMapDestroy(properties); 314 return reqbuf; 315 } 316 317 static int reset_properties(DavSession *sn, DavResult *result, DavResource *res, CxList *fields) { 318 CxMap *new_properties = cxHashMapCreate(sn->mp->allocator, CX_STORE_POINTERS, 32); 319 DavResourceData *data = (DavResourceData*)res->data; 320 321 // add basic properties 322 void *value; 323 324 cxmutstr cl_keystr = dav_property_key("DAV:", "getcontentlength"); 325 CxHashKey cl_key = cx_hash_key(cl_keystr.ptr, cl_keystr.length); 326 value = cxMapGet(data->properties, cl_key); 327 if(value) { 328 cxMapPut(new_properties, cl_key, value); 329 } 330 331 cxmutstr cd_keystr = dav_property_key("DAV:", "creationdate"); 332 CxHashKey cd_key = cx_hash_key(cd_keystr.ptr, cd_keystr.length); 333 value = cxMapGet(data->properties, cd_key); 334 if(value) { 335 cxMapPut(new_properties, cd_key, value); 336 } 337 338 cxmutstr lm_keystr = dav_property_key("DAV:", "getlastmodified"); 339 CxHashKey lm_key = cx_hash_key(lm_keystr.ptr, lm_keystr.length); 340 value = cxMapGet(data->properties, lm_key); 341 if(value) { 342 cxMapPut(new_properties, lm_key, value); 343 } 344 345 cxmutstr ct_keystr = dav_property_key("DAV:", "getcontenttype"); 346 CxHashKey ct_key = cx_hash_key(ct_keystr.ptr, ct_keystr.length); 347 value = cxMapGet(data->properties, ct_key); 348 if(value) { 349 cxMapPut(new_properties, ct_key, value); 350 } 351 352 cxmutstr rt_keystr = dav_property_key("DAV:", "resourcetype"); 353 CxHashKey rt_key = cx_hash_key(rt_keystr.ptr, rt_keystr.length); 354 value = cxMapGet(data->properties, rt_key); 355 if(value) { 356 cxMapPut(new_properties, rt_key, value); 357 } 358 359 cxmutstr cn_keystr = dav_property_key(DAV_NS, "crypto-name"); 360 CxHashKey cn_key = cx_hash_key(cn_keystr.ptr, cn_keystr.length); 361 value = cxMapGet(data->properties, cn_key); 362 if(value) { 363 cxMapPut(new_properties, cn_key, value); 364 } 365 366 cxmutstr ck_keystr = dav_property_key(DAV_NS, "crypto-key"); 367 CxHashKey ck_key = cx_hash_key(ck_keystr.ptr, ck_keystr.length); 368 value = cxMapGet(data->properties, ck_key); 369 if(value) { 370 cxMapPut(new_properties, ck_key, value); 371 } 372 373 cxmutstr ch_keystr = dav_property_key(DAV_NS, "crypto-hash"); 374 CxHashKey ch_key = cx_hash_key(ch_keystr.ptr, ch_keystr.length); 375 value = cxMapGet(data->properties, ch_key); 376 if(value) { 377 cxMapPut(new_properties, ch_key, value); 378 } 379 380 // add properties from field list 381 if(fields) { 382 CxIterator i = cxListIterator(fields); 383 cx_foreach(DavCompiledField*, field, i) { 384 DavQLStackObj field_result; 385 if(!dav_exec_expr(field->code, res, &field_result)) { 386 cxmutstr str; 387 str.ptr = NULL; 388 str.length = 0; 389 DavXmlNode *node = NULL; 390 if(field_result.type == 0) { 391 str = cx_asprintf_a( 392 sn->mp->allocator, 393 "%" PRId64, 394 field_result.data.integer); 395 } else if(field_result.type == 1) { 396 if(field_result.data.string) { 397 str = cx_strdup_a(sn->mp->allocator, cx_strn( 398 field_result.data.string, 399 field_result.length)); 400 } 401 } else if(field_result.type == 2) { 402 node = dav_copy_node(field_result.data.node); 403 } else { 404 // unknown type 405 // TODO: error 406 resource_free_properties(sn, new_properties); 407 return -1; 408 } 409 if(str.ptr) { 410 node = dav_session_malloc(sn, sizeof(DavXmlNode)); 411 memset(node, 0, sizeof(DavXmlNode)); 412 node->type = DAV_XML_TEXT; 413 node->content = str.ptr; 414 node->contentlength = str.length; 415 } 416 if(node) { 417 cxmutstr key = dav_property_key(field->ns, field->name); 418 419 DavNamespace *namespace = dav_session_malloc(sn, sizeof(DavNamespace)); 420 namespace->prefix = NULL; 421 namespace->name = dav_session_strdup(sn, field->ns); 422 423 DavProperty *prop = dav_session_malloc(sn, sizeof(DavProperty)); 424 prop->name = dav_session_strdup(sn, field->name); 425 prop->ns = namespace; 426 prop->value = node; 427 428 cxMapPut(new_properties, cx_hash_key(key.ptr, key.length), prop); 429 free(key.ptr); 430 } 431 } else { 432 // TODO: error 433 resource_free_properties(sn, new_properties); 434 return -1; 435 } 436 } 437 } 438 439 cxMapRemove(data->properties, cl_key); 440 cxMapRemove(data->properties, cd_key); 441 cxMapRemove(data->properties, lm_key); 442 cxMapRemove(data->properties, ct_key); 443 cxMapRemove(data->properties, rt_key); 444 cxMapRemove(data->properties, cn_key); 445 cxMapRemove(data->properties, ck_key); 446 cxMapRemove(data->properties, ch_key); 447 448 resource_free_properties(sn, data->properties); 449 data->properties = new_properties; 450 451 free(cl_keystr.ptr); 452 free(cd_keystr.ptr); 453 free(lm_keystr.ptr); 454 free(ct_keystr.ptr); 455 free(rt_keystr.ptr); 456 free(cn_keystr.ptr); 457 free(ck_keystr.ptr); 458 free(ch_keystr.ptr); 459 460 return 0; 461 } 462 463 /* 464 * execute a davql select statement 465 */ 466 DavResult dav_exec_select(DavSession *sn, DavQLStatement *st, va_list ap) { 467 CxMempool *mp = cxBasicMempoolCreate(128); 468 DavResult result; 469 result.result = NULL; 470 result.status = 1; 471 472 DavQLArgList *args = dav_ql_get_args(st, ap); 473 if(!args) { 474 return result; 475 } 476 cxMempoolRegister(mp, args, (cx_destructor_func)dav_ql_free_arglist); 477 478 int isallprop; 479 CxBuffer *rqbuf = fieldlist2propfindrequest(sn, mp->allocator, st->fields, &isallprop); 480 if(!rqbuf) { 481 cxMempoolDestroy(mp); 482 return result; 483 } 484 cxMempoolRegister(mp, rqbuf, (cx_destructor_func)cxBufferFree); 485 486 // compile field list 487 CxList *cfieldlist = cxLinkedListCreate(mp->allocator, NULL, CX_STORE_POINTERS); 488 if(st->fields) { 489 CxIterator i = cxListIterator(st->fields); 490 cx_foreach(DavQLField*, field, i) { 491 if(cx_strcmp(field->name, CX_STR("*")) && cx_strcmp(field->name, CX_STR("-"))) { 492 // compile field expression 493 CxBuffer *code = dav_compile_expr( 494 sn->context, 495 mp->allocator, 496 field->expr, 497 args); 498 if(!code) { 499 // TODO: set error string 500 return result; 501 } 502 DavCompiledField *cfield = cxMalloc( 503 mp->allocator, 504 sizeof(DavCompiledField)); 505 506 char *ns; 507 char *name; 508 dav_get_property_namespace_str( 509 sn->context, 510 cx_strdup_a(mp->allocator, field->name).ptr, 511 &ns, 512 &name); 513 if(!ns || !name) { 514 // TODO: set error string 515 return result; 516 } 517 cfield->ns = ns; 518 cfield->name = name; 519 cfield->code = code; 520 cxListAdd(cfieldlist, cfield); 521 } 522 } 523 } 524 525 // get path string 526 davqlerror_t error; 527 cxmutstr path = dav_format_string(mp->allocator, st->path, args, &error); 528 if(error) { 529 // TODO: cleanup 530 cxMempoolDestroy(mp); 531 return result; 532 } 533 534 int depth = st->depth == DAV_DEPTH_PLACEHOLDER ? 535 dav_ql_getarg_int(args) : st->depth; 536 537 CxBuffer *where = dav_compile_expr(sn->context, mp->allocator, st->where, args); 538 if(st->where && !where) { 539 // TODO: cleanup 540 cxMempoolDestroy(mp); 541 return result; 542 } 543 544 // compile order criterion 545 CxList *ordercr = NULL; 546 if(st->orderby) { 547 ordercr = cxLinkedListCreate(mp->allocator, NULL, sizeof(DavOrderCriterion)); 548 CxIterator i = cxListIterator(st->orderby); 549 cx_foreach(DavQLOrderCriterion*, oc, i) { 550 DavQLExpression *column = oc->column; 551 //printf("%.*s %s\n", column->srctext.length, column->srctext.ptr, oc->descending ? "desc" : "asc"); 552 if(column->type == DAVQL_IDENTIFIER) { 553 // TODO: remove code duplication (add_cmd) 554 davqlresprop_t resprop; 555 cxstring propertyname = cx_strchr(column->srctext, ':'); 556 if(propertyname.length > 0) { 557 char *ns; 558 char *name; 559 dav_get_property_namespace_str( 560 sn->context, 561 cx_strdup_a(mp->allocator, column->srctext).ptr, 562 &ns, 563 &name); 564 if(ns && name) { 565 DavOrderCriterion cr; 566 cr.type = 1; 567 cxmutstr keystr = dav_property_key_a(mp->allocator, ns, name); 568 cr.column.property = cx_hash_key(keystr.ptr, keystr.length); 569 cr.descending = oc->descending; 570 cxListAdd(ordercr, &cr); 571 } else { 572 // error 573 // TODO: cleanup 574 cxMempoolDestroy(mp); 575 return result; 576 } 577 } else if(dav_identifier2resprop(column->srctext, &resprop)) { 578 DavOrderCriterion cr; 579 cr.type = 0; 580 cr.column.resprop = resprop; 581 cr.descending = oc->descending; 582 cxListAdd(ordercr, &cr); 583 } else { 584 // error 585 // TODO: cleanup 586 cxMempoolDestroy(mp); 587 return result; 588 } 589 590 } else if(column->type == DAVQL_NUMBER) { 591 // TODO: implement 592 fprintf(stderr, "order by number not supported\n"); 593 return result; 594 } else { 595 // something is broken 596 // TODO: cleanup 597 cxMempoolDestroy(mp); 598 return result; 599 } 600 } 601 } 602 603 DavResource *selroot = dav_resource_new(sn, path.ptr); 604 605 CxList *stack = cxLinkedListCreateSimple(sizeof(DavQLRes)); 606 // initialize the stack with the requested resource 607 DavQLRes res; 608 res.resource = selroot; 609 res.depth = 0; 610 cxListInsert(stack, 0, &res); 611 612 // reuseable response buffer 613 CxBuffer *rpbuf = cxBufferCreate(NULL, 4096, mp->allocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); 614 if(!rpbuf) { 615 // TODO: cleanup 616 cxMempoolDestroy(mp); 617 return result; 618 } 619 620 result.result = selroot; 621 result.status = 0; 622 623 // do a propfind request for each resource on the stack 624 while(cxListSize(stack) > 0) { 625 DavQLRes *sr_ptr = cxListAt(stack, 0); // get first element from the stack 626 DavResource *root = sr_ptr->resource; 627 int res_depth = sr_ptr->depth; 628 cxListRemove(stack, 0); // remove first element 629 630 util_set_url(sn, dav_resource_get_href(root)); 631 CURLcode ret = do_propfind_request(sn, rqbuf, rpbuf); 632 long http_status = 0; 633 curl_easy_getinfo(sn->handle, CURLINFO_RESPONSE_CODE, &http_status); 634 //printf("rpbuf: %s\n%.*s\n\n", root->href, (int)rpbuf->size, rpbuf->space); 635 //fflush(stdout); 636 637 if(ret == CURLE_OK && http_status == 207) { 638 // in case of an redirect we have to adjust resource->href 639 dav_set_effective_href(sn, root); 640 641 // propfind request successful, now parse the response 642 char *url = "http://url/"; 643 PropfindParser *parser = create_propfind_parser(rpbuf, url); 644 if(!parser) { 645 result.status = -1; 646 break; 647 } 648 649 ResponseTag response; 650 int r; 651 while((r = get_propfind_response(parser, &response)) != 0) { 652 if(r == -1) { 653 // error 654 result.status = -1; 655 // TODO: free resources 656 cleanup_response(&response); 657 break; 658 } 659 660 // the propfind multistatus response contains responses 661 // for the requested resource and all childs 662 // determine if the response is a child or not 663 if(hrefeq(sn, root->href, response.href)) { 664 // response is the currently requested resource 665 // and not a child 666 667 // add properties 668 add_properties(root, &response); 669 cleanup_response(&response); 670 671 if(root == selroot) { 672 // The current root is the root of the select query. 673 // In this case we have to check the where clause. 674 // If root is not selroot, the where clause was 675 // already checked for the resource before it was 676 // added to the stack. 677 DavQLStackObj where_result; 678 if(!dav_exec_expr(where, root, &where_result)) { 679 if(where_result.data.integer != 0) { 680 if(!reset_properties(sn, &result, root, cfieldlist)) { 681 continue; 682 } 683 result.status = -1; 684 } 685 } 686 result.result = NULL; 687 result.status = -1; 688 dav_resource_free_all(selroot); 689 cxListDestroy(stack); 690 break; 691 } 692 } else { 693 DavResource *child = response2resource( 694 sn, 695 &response, 696 root->path); 697 cleanup_response(&response); 698 // check where clause 699 DavQLStackObj where_result; 700 if(!dav_exec_expr(where, child, &where_result)) { 701 if(where_result.data.integer != 0) { 702 if(!reset_properties(sn, &result, child, cfieldlist)) { 703 //resource_add_child(root, child); 704 resource_add_ordered_child(root, child, ordercr); 705 if(child->iscollection && 706 (depth < 0 || depth > res_depth+1)) 707 { 708 DavQLRes rs; 709 rs.resource = child; 710 rs.depth = res_depth + 1; 711 cxListInsert(stack, 0, &rs); 712 } 713 } else { 714 dav_resource_free(child); 715 } 716 } else { 717 dav_resource_free(child); 718 } 719 } 720 } 721 } 722 destroy_propfind_parser(parser); 723 } else { 724 dav_session_set_error(sn, ret, http_status); 725 result.result = NULL; 726 result.status = -1; 727 dav_resource_free_all(selroot); 728 break; 729 } 730 731 // reset response buffer 732 cxBufferSeek(rpbuf, SEEK_SET, 0); 733 } 734 735 cxMempoolDestroy(mp); 736 return result; 737 } 738 739 static int count_func_args(DavQLExpression *expr) { 740 int count = 0; 741 DavQLExpression *arg = expr->right; 742 while(arg) { 743 count++; 744 if(arg->op == DAVQL_ARGLIST) { 745 arg = arg->right; 746 } else { 747 break; 748 } 749 } 750 return count; 751 } 752 753 int dav_identifier2resprop(cxstring src, davqlresprop_t *prop) { 754 if(!cx_strcmp(src, CX_STR("name"))) { 755 *prop = DAVQL_RES_NAME; 756 } else if(!cx_strcmp(src, CX_STR("path"))) { 757 *prop = DAVQL_RES_PATH; 758 } else if(!cx_strcmp(src, CX_STR("href"))) { 759 *prop = DAVQL_RES_HREF; 760 } else if(!cx_strcmp(src, CX_STR("contentlength"))) { 761 *prop = DAVQL_RES_CONTENTLENGTH; 762 } else if(!cx_strcmp(src, CX_STR("contenttype"))) { 763 *prop = DAVQL_RES_CONTENTTYPE; 764 } else if(!cx_strcmp(src, CX_STR("creationdate"))) { 765 *prop = DAVQL_RES_CREATIONDATE; 766 } else if(!cx_strcmp(src, CX_STR("lastmodified"))) { 767 *prop = DAVQL_RES_LASTMODIFIED; 768 } else if(!cx_strcmp(src, CX_STR("iscollection"))) { 769 *prop = DAVQL_RES_ISCOLLECTION; 770 } else { 771 return 0; 772 } 773 return 1; 774 } 775 776 static int add_cmd(DavContext *ctx, const CxAllocator *a, CxBuffer *bcode, DavQLExpression *expr, DavQLArgList *ap) { 777 if(!expr) { 778 return 0; 779 } 780 781 int numcmd = 1; 782 DavQLCmd cmd; 783 memset(&cmd, 0, sizeof(DavQLCmd)); 784 davqlerror_t error; 785 786 cxstring src = expr->srctext; 787 switch(expr->type) { 788 default: break; 789 case DAVQL_NUMBER: { 790 cmd.type = DAVQL_CMD_INT; 791 if(src.ptr[0] == '%') { 792 cmd.data.integer = dav_ql_getarg_int(ap); 793 } else if(util_strtoint(src.ptr, &cmd.data.integer)) { 794 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 795 } else { 796 // error 797 return -1; 798 } 799 800 break; 801 } 802 case DAVQL_STRING: { 803 cmd.type = DAVQL_CMD_STRING; 804 cmd.data.string = dav_format_string(a, src, ap, &error); 805 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 806 break; 807 } 808 case DAVQL_TIMESTAMP: { 809 if(src.ptr[0] == '%') { 810 cmd.type = DAVQL_CMD_TIMESTAMP; 811 cmd.data.timestamp = dav_ql_getarg_time(ap); 812 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 813 } else { 814 // error 815 return -1; 816 } 817 break; 818 } 819 case DAVQL_IDENTIFIER: { 820 cxstring propertyname = cx_strchr(src, ':'); 821 cmd.type = DAVQL_CMD_RES_IDENTIFIER; 822 if(propertyname.length > 0) { 823 cmd.type = DAVQL_CMD_PROP_IDENTIFIER; 824 char *ns; 825 char *name; 826 dav_get_property_namespace_str( 827 ctx, 828 cx_strdup_a(a, src).ptr, 829 &ns, 830 &name); 831 if(ns && name) { 832 cmd.data.property.ns = ns; 833 cmd.data.property.name = name; 834 } else { 835 // error 836 return -1; 837 } 838 } else if(!dav_identifier2resprop(src, &cmd.data.resprop)) { 839 if(!cx_strcmp(src, CX_STR("true"))) { 840 cmd.type = DAVQL_CMD_INT; 841 cmd.data.integer = 1; 842 } else if(!cx_strcmp(src, CX_STR("false"))) { 843 cmd.type = DAVQL_CMD_INT; 844 cmd.data.integer = 0; 845 } else { 846 // error, unknown identifier 847 return -1; 848 } 849 } 850 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 851 break; 852 } 853 case DAVQL_UNARY: { 854 numcmd += add_cmd(ctx, a, bcode, expr->left, ap); 855 switch(expr->op) { 856 case DAVQL_ADD: { 857 // noop 858 numcmd = 0; 859 break; 860 } 861 case DAVQL_SUB: { 862 cmd.type = DAVQL_CMD_OP_UNARY_SUB; 863 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 864 break; 865 } 866 case DAVQL_NEG: { 867 cmd.type = DAVQL_CMD_OP_UNARY_NEG; 868 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 869 break; 870 } 871 default: break; 872 } 873 break; 874 } 875 case DAVQL_BINARY: { 876 numcmd += add_cmd(ctx, a, bcode, expr->left, ap); 877 numcmd += add_cmd(ctx, a, bcode, expr->right, ap); 878 switch(expr->op) { 879 case DAVQL_ADD: { 880 cmd.type = DAVQL_CMD_OP_BINARY_ADD; 881 break; 882 } 883 case DAVQL_SUB: { 884 cmd.type = DAVQL_CMD_OP_BINARY_SUB; 885 break; 886 } 887 case DAVQL_MUL: { 888 cmd.type = DAVQL_CMD_OP_BINARY_MUL; 889 break; 890 } 891 case DAVQL_DIV: { 892 cmd.type = DAVQL_CMD_OP_BINARY_DIV; 893 break; 894 } 895 case DAVQL_AND: { 896 cmd.type = DAVQL_CMD_OP_BINARY_AND; 897 break; 898 } 899 case DAVQL_OR: { 900 cmd.type = DAVQL_CMD_OP_BINARY_OR; 901 break; 902 } 903 case DAVQL_XOR: { 904 cmd.type = DAVQL_CMD_OP_BINARY_XOR; 905 break; 906 } 907 default: break; 908 } 909 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 910 break; 911 } 912 case DAVQL_LOGICAL: { 913 if(expr->left && expr->right && expr->op != DAVQL_LOR) { 914 numcmd += add_cmd(ctx, a, bcode, expr->left, ap); 915 numcmd += add_cmd(ctx, a, bcode, expr->right, ap); 916 } 917 918 switch(expr->op) { 919 case DAVQL_NOT: { 920 numcmd += add_cmd(ctx, a, bcode, expr->left, ap); 921 cmd.type = DAVQL_CMD_OP_LOGICAL_NOT; 922 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 923 break; 924 } 925 case DAVQL_LAND: { 926 cmd.type = DAVQL_CMD_OP_LOGICAL_AND; 927 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 928 break; 929 } 930 case DAVQL_LOR: { 931 int nleft = add_cmd(ctx, a, bcode, expr->left, ap); 932 933 cmd.type = DAVQL_CMD_OP_LOGICAL_OR_L; 934 DavQLCmd *or_l = (DavQLCmd*)(bcode->space + bcode->pos); 935 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 936 937 int nright = add_cmd(ctx, a, bcode, expr->right, ap); 938 or_l->data.integer = nright + 1; 939 940 cmd.type = DAVQL_CMD_OP_LOGICAL_OR; 941 cmd.data.integer = 0; 942 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 943 944 numcmd += nleft + nright; 945 break; 946 } 947 case DAVQL_LXOR: { 948 cmd.type = DAVQL_CMD_OP_LOGICAL_XOR; 949 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 950 break; 951 } 952 case DAVQL_EQ: { 953 cmd.type = DAVQL_CMD_OP_EQ; 954 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 955 break; 956 } 957 case DAVQL_NEQ: { 958 cmd.type = DAVQL_CMD_OP_NEQ; 959 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 960 break; 961 } 962 case DAVQL_LT: { 963 cmd.type = DAVQL_CMD_OP_LT; 964 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 965 break; 966 } 967 case DAVQL_GT: { 968 cmd.type = DAVQL_CMD_OP_GT; 969 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 970 break; 971 } 972 case DAVQL_LE: { 973 cmd.type = DAVQL_CMD_OP_LE; 974 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 975 break; 976 } 977 case DAVQL_GE: { 978 cmd.type = DAVQL_CMD_OP_GE; 979 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 980 break; 981 } 982 case DAVQL_LIKE: { 983 cmd.type = DAVQL_CMD_OP_LIKE; 984 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 985 break; 986 } 987 case DAVQL_UNLIKE: { 988 cmd.type = DAVQL_CMD_OP_UNLIKE; 989 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 990 break; 991 } 992 default: break; 993 } 994 break; 995 } 996 case DAVQL_FUNCCALL: { 997 switch(expr->op) { 998 case DAVQL_CALL: { 999 int nright = add_cmd(ctx, a, bcode, expr->right, ap); 1000 // TODO: count args 1001 DavQLExpression *funcid = expr->left; 1002 if(!funcid && funcid->type != DAVQL_IDENTIFIER) { 1003 // fail 1004 return -1; 1005 } 1006 1007 // numargs 1008 cmd.type = DAVQL_CMD_INT; 1009 cmd.data.integer = count_func_args(expr); 1010 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 1011 1012 // TODO: resolve function name 1013 cmd.type = DAVQL_CMD_CALL; 1014 cmd.data.func = NULL; 1015 cxBufferWrite(&cmd, sizeof(cmd), 1, bcode); 1016 1017 numcmd = 2; 1018 numcmd += nright; 1019 break; 1020 } 1021 case DAVQL_ARGLIST: { 1022 numcmd = 0; 1023 numcmd += add_cmd(ctx, a, bcode, expr->left, ap); 1024 numcmd += add_cmd(ctx, a, bcode, expr->right, ap); 1025 break; 1026 } 1027 default: break; 1028 } 1029 break; 1030 } 1031 } 1032 return numcmd; 1033 } 1034 1035 CxBuffer* dav_compile_expr(DavContext *ctx, const CxAllocator *a, DavQLExpression *lexpr, DavQLArgList *ap) { 1036 CxBuffer *bcode = cxBufferCreate(NULL, 512, a, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND); 1037 if(!bcode) { 1038 return NULL; 1039 } 1040 1041 if(add_cmd(ctx, a, bcode, lexpr, ap) <= 0) { 1042 cxBufferFree(bcode); 1043 return NULL; 1044 } 1045 1046 return bcode; 1047 } 1048 1049 static int cmd_str_cmp(DavQLStackObj obj1, DavQLStackObj obj2, davqlcmdtype_t cmd) { 1050 cxmutstr s1m = obj1.type == 1 ? 1051 cx_mutstrn(obj1.data.string, obj1.length) : 1052 cx_asprintf("%" PRId64, obj1.data.integer); 1053 cxmutstr s2m = obj1.type == 1 ? 1054 cx_mutstrn(obj2.data.string, obj2.length) : 1055 cx_asprintf("%" PRId64, obj2.data.integer); 1056 1057 cxstring s1 = cx_strcast(s1m); 1058 cxstring s2 = cx_strcast(s2m); 1059 1060 int res = 0; 1061 switch(cmd) { 1062 case DAVQL_CMD_OP_EQ: { 1063 res = cx_strcmp(s1, s2) == 0; 1064 break; 1065 } 1066 case DAVQL_CMD_OP_NEQ: { 1067 res = cx_strcmp(s1, s2) != 0; 1068 break; 1069 } 1070 case DAVQL_CMD_OP_LT: { 1071 res = cx_strcmp(s1, s2) < 0; 1072 break; 1073 } 1074 case DAVQL_CMD_OP_GT: { 1075 res = cx_strcmp(s1, s2) > 0; 1076 break; 1077 } 1078 case DAVQL_CMD_OP_LE: { 1079 res = cx_strcmp(s1, s2) <= 0; 1080 break; 1081 } 1082 case DAVQL_CMD_OP_GE: { 1083 res = cx_strcmp(s1, s2) >= 0; 1084 break; 1085 } 1086 default: break; 1087 } 1088 1089 if(obj1.type == 0) { 1090 free(s1m.ptr); 1091 } 1092 if(obj2.type == 0) { 1093 free(s2m.ptr); 1094 } 1095 1096 return res; 1097 } 1098 1099 int dav_exec_expr(CxBuffer *bcode, DavResource *res, DavQLStackObj *result) { 1100 if(!bcode) { 1101 result->type = 0; 1102 result->length = 0; 1103 result->data.integer = 1; 1104 return 0; 1105 } 1106 1107 size_t count = bcode->pos / sizeof(DavQLCmd); 1108 DavQLCmd *cmds = (DavQLCmd*)bcode->space; 1109 1110 // create execution stack 1111 size_t stsize = 64; 1112 size_t stpos = 0; 1113 DavQLStackObj *stack = calloc(stsize, sizeof(DavQLStackObj)); 1114 #define DAVQL_PUSH(obj) \ 1115 if(stpos == stsize) { \ 1116 stsize += 64; \ 1117 DavQLStackObj *stack_newptr; \ 1118 stack_newptr = realloc(stack, stsize * sizeof(DavQLStackObj)); \ 1119 if(stack_newptr) { \ 1120 stack = stack_newptr; \ 1121 } else { \ 1122 free(stack); \ 1123 return -1; \ 1124 }\ 1125 } \ 1126 stack[stpos++] = obj; 1127 #define DAVQL_PUSH_INT(intval) \ 1128 { \ 1129 DavQLStackObj intobj; \ 1130 intobj.type = 0; \ 1131 intobj.length = 0; \ 1132 intobj.data.integer = intval; \ 1133 DAVQL_PUSH(intobj); \ 1134 } 1135 #define DAVQL_POP() stack[--stpos] 1136 1137 DavQLStackObj obj; 1138 int ret = 0; 1139 for(size_t i=0;i<count;i++) { 1140 DavQLCmd cmd = cmds[i]; 1141 switch(cmd.type) { 1142 case DAVQL_CMD_INT: { 1143 //printf("int %lld\n", cmd.data.integer); 1144 obj.type = 0; 1145 obj.length = 0; 1146 obj.data.integer = cmd.data.integer; 1147 DAVQL_PUSH(obj); 1148 break; 1149 } 1150 case DAVQL_CMD_STRING: { 1151 //printf("string \"%.*s\"\n", cmd.data.string.length, cmd.data.string.ptr); 1152 obj.type = 1; 1153 obj.length = cmd.data.string.length; 1154 obj.data.string = cmd.data.string.ptr; 1155 DAVQL_PUSH(obj); 1156 break; 1157 } 1158 case DAVQL_CMD_TIMESTAMP: { 1159 //printf("timestamp %d\n", cmd.data.timestamp); 1160 obj.type = 0; 1161 obj.length = 0; 1162 obj.data.integer = (int64_t)cmd.data.timestamp; 1163 DAVQL_PUSH(obj); 1164 break; 1165 } 1166 case DAVQL_CMD_RES_IDENTIFIER: { 1167 //char *rid[8] = {"name", "path", "href", "contentlength", "contenttype", "creationdate", "lastmodified", "iscollection"}; 1168 //printf("resprop %s\n", rid[cmd.data.resprop]); 1169 switch(cmd.data.resprop) { 1170 case DAVQL_RES_NAME: { 1171 obj.type = 1; 1172 obj.length = strlen(res->name); 1173 obj.data.string = res->name; 1174 break; 1175 } 1176 case DAVQL_RES_PATH: { 1177 obj.type = 1; 1178 obj.length = strlen(res->path); 1179 obj.data.string = res->path; 1180 break; 1181 } 1182 case DAVQL_RES_HREF: { 1183 obj.type = 1; 1184 obj.length = strlen(res->href); 1185 obj.data.string = res->href; 1186 break; 1187 } 1188 case DAVQL_RES_CONTENTLENGTH: { 1189 obj.type = 0; 1190 obj.length = 0; 1191 obj.data.integer = res->contentlength; 1192 break; 1193 } 1194 case DAVQL_RES_CONTENTTYPE: { 1195 obj.type = 1; 1196 obj.length = strlen(res->contenttype); 1197 obj.data.string = res->contenttype; 1198 break; 1199 } 1200 case DAVQL_RES_CREATIONDATE: { 1201 obj.type = 0; 1202 obj.length = 0; 1203 obj.data.integer = res->creationdate; 1204 break; 1205 } 1206 case DAVQL_RES_LASTMODIFIED: { 1207 obj.type = 0; 1208 obj.length = 0; 1209 obj.data.integer = res->lastmodified; 1210 break; 1211 } 1212 case DAVQL_RES_ISCOLLECTION: { 1213 obj.type = 0; 1214 obj.length = 0; 1215 obj.data.integer = res->iscollection; 1216 break; 1217 } 1218 } 1219 DAVQL_PUSH(obj); 1220 break; 1221 } 1222 case DAVQL_CMD_PROP_IDENTIFIER: { 1223 //printf("property %s:%s\n", cmd.data.property.ns, cmd.data.property.name); 1224 //char *value = dav_get_string_property_ns(res, cmd.data.property.ns, cmd.data.property.name); 1225 DavXmlNode *value = dav_get_property_ns(res, cmd.data.property.ns, cmd.data.property.name); 1226 if(dav_xml_isstring(value)) { 1227 obj.type = 1; 1228 obj.length = (uint32_t)value->contentlength; 1229 obj.data.string = value->content; 1230 } else { 1231 obj.type = 2; 1232 obj.length = 0; 1233 obj.data.node = value; 1234 } 1235 DAVQL_PUSH(obj); 1236 break; 1237 } 1238 //case DAVQL_CMD_OP_UNARY_ADD: { 1239 // printf("uadd\n"); 1240 // break; 1241 //} 1242 case DAVQL_CMD_OP_UNARY_SUB: { 1243 //printf("usub\n"); 1244 obj = DAVQL_POP(); 1245 if(obj.type == 0) { 1246 obj.data.integer = -obj.data.integer; 1247 DAVQL_PUSH(obj); 1248 } else { 1249 ret = -1; 1250 i = count; // end loop 1251 } 1252 break; 1253 } 1254 case DAVQL_CMD_OP_UNARY_NEG: { 1255 //printf("uneg\n"); 1256 obj = DAVQL_POP(); 1257 if(obj.type == 0) { 1258 obj.data.integer = obj.data.integer == 0 ? 1 : 0; 1259 DAVQL_PUSH(obj); 1260 } else { 1261 ret = -1; 1262 i = count; // end loop 1263 } 1264 break; 1265 } 1266 case DAVQL_CMD_OP_BINARY_ADD: { 1267 //printf("add\n"); 1268 DavQLStackObj obj2 = DAVQL_POP(); 1269 DavQLStackObj obj1 = DAVQL_POP(); 1270 if(obj1.type == 0 && obj2.type == 0) { 1271 DAVQL_PUSH_INT(obj1.data.integer + obj2.data.integer); 1272 } else { 1273 // TODO: string concat 1274 } 1275 break; 1276 } 1277 case DAVQL_CMD_OP_BINARY_SUB: { 1278 //printf("sub\n"); 1279 DavQLStackObj obj2 = DAVQL_POP(); 1280 DavQLStackObj obj1 = DAVQL_POP(); 1281 if(obj1.type == 0 && obj2.type == 0) { 1282 DAVQL_PUSH_INT(obj1.data.integer - obj2.data.integer); 1283 } else { 1284 // error 1285 ret = -1; 1286 i = count; // end loop 1287 } 1288 break; 1289 } 1290 case DAVQL_CMD_OP_BINARY_MUL: { 1291 //printf("mul\n"); 1292 DavQLStackObj obj2 = DAVQL_POP(); 1293 DavQLStackObj obj1 = DAVQL_POP(); 1294 if(obj1.type == 0 && obj2.type == 0) { 1295 DAVQL_PUSH_INT(obj1.data.integer * obj2.data.integer); 1296 } else { 1297 // error 1298 ret = -1; 1299 i = count; // end loop 1300 } 1301 break; 1302 } 1303 case DAVQL_CMD_OP_BINARY_DIV: { 1304 //printf("div\n"); 1305 DavQLStackObj obj2 = DAVQL_POP(); 1306 DavQLStackObj obj1 = DAVQL_POP(); 1307 if(obj1.type == 0 && obj2.type == 0) { 1308 DAVQL_PUSH_INT(obj1.data.integer / obj2.data.integer); 1309 } else { 1310 // error 1311 ret = -1; 1312 i = count; // end loop 1313 } 1314 break; 1315 } 1316 case DAVQL_CMD_OP_BINARY_AND: { 1317 //printf("and\n"); 1318 DavQLStackObj obj2 = DAVQL_POP(); 1319 DavQLStackObj obj1 = DAVQL_POP(); 1320 if(obj1.type == 0 && obj2.type == 0) { 1321 DAVQL_PUSH_INT(obj1.data.integer & obj2.data.integer); 1322 } else { 1323 // error 1324 ret = -1; 1325 i = count; // end loop 1326 } 1327 break; 1328 } 1329 case DAVQL_CMD_OP_BINARY_OR: { 1330 //printf("or\n"); 1331 DavQLStackObj obj2 = DAVQL_POP(); 1332 DavQLStackObj obj1 = DAVQL_POP(); 1333 if(obj1.type == 0 && obj2.type == 0) { 1334 DAVQL_PUSH_INT(obj1.data.integer | obj2.data.integer); 1335 } else { 1336 // error 1337 ret = -1; 1338 i = count; // end loop 1339 } 1340 break; 1341 } 1342 case DAVQL_CMD_OP_BINARY_XOR: { 1343 //printf("xor\n"); 1344 DavQLStackObj obj2 = DAVQL_POP(); 1345 DavQLStackObj obj1 = DAVQL_POP(); 1346 if(obj1.type == 0 && obj2.type == 0) { 1347 DAVQL_PUSH_INT(obj1.data.integer ^ obj2.data.integer); 1348 } else { 1349 // error 1350 ret = -1; 1351 i = count; // end loop 1352 } 1353 break; 1354 } 1355 case DAVQL_CMD_OP_LOGICAL_NOT: { 1356 //printf("not\n"); 1357 break; 1358 } 1359 case DAVQL_CMD_OP_LOGICAL_AND: { 1360 //printf("land\n"); 1361 DavQLStackObj obj2 = DAVQL_POP(); 1362 DavQLStackObj obj1 = DAVQL_POP(); 1363 int v1 = obj1.type == 0 ? (int)obj1.data.integer : (obj1.data.string ? 1 : 0); 1364 int v2 = obj2.type == 0 ? (int)obj2.data.integer : (obj2.data.string ? 1 : 0); 1365 DAVQL_PUSH_INT(v1 && v2); 1366 break; 1367 } 1368 case DAVQL_CMD_OP_LOGICAL_OR_L: { 1369 //printf("or_l %d\n", cmd.data.integer); 1370 DavQLStackObj obj1 = stack[stpos]; 1371 if((obj1.type == 0 && obj1.data.integer) || (obj1.type == 1 && obj1.data.string)) { 1372 stpos--; 1373 DAVQL_PUSH_INT(1); 1374 i += cmd.data.integer; // jump, skip right subtree of 'or' 1375 } 1376 break; 1377 } 1378 case DAVQL_CMD_OP_LOGICAL_OR: { 1379 //printf("or\n"); 1380 DavQLStackObj obj2 = DAVQL_POP(); 1381 DavQLStackObj obj1 = DAVQL_POP(); 1382 int v1 = obj1.type == 0 ? (int)obj1.data.integer : (obj1.data.string ? 1 : 0); 1383 int v2 = obj2.type == 0 ? (int)obj2.data.integer : (obj2.data.string ? 1 : 0); 1384 DAVQL_PUSH_INT(v1 || v2); 1385 break; 1386 } 1387 case DAVQL_CMD_OP_LOGICAL_XOR: { 1388 //printf("lxor\n"); 1389 DavQLStackObj obj2 = DAVQL_POP(); 1390 DavQLStackObj obj1 = DAVQL_POP(); 1391 int v1 = obj1.type == 0 ? (int)obj1.data.integer : (obj1.data.string ? 1 : 0); 1392 int v2 = obj2.type == 0 ? (int)obj2.data.integer : (obj2.data.string ? 1 : 0); 1393 DAVQL_PUSH_INT(!v1 != !v2); 1394 break; 1395 } 1396 case DAVQL_CMD_OP_EQ: { 1397 //printf("eq\n"); 1398 DavQLStackObj obj2 = DAVQL_POP(); 1399 DavQLStackObj obj1 = DAVQL_POP(); 1400 if(obj1.type == 0 && obj2.type == 0) { 1401 DAVQL_PUSH_INT(obj1.data.integer == obj2.data.integer); 1402 } else { 1403 DAVQL_PUSH_INT(cmd_str_cmp(obj1, obj2, cmd.type)); 1404 } 1405 break; 1406 } 1407 case DAVQL_CMD_OP_NEQ: { 1408 //printf("neq\n"); 1409 DavQLStackObj obj2 = DAVQL_POP(); 1410 DavQLStackObj obj1 = DAVQL_POP(); 1411 if(obj1.type == 0 && obj2.type == 0) { 1412 DAVQL_PUSH_INT(obj1.data.integer != obj2.data.integer); 1413 } else { 1414 DAVQL_PUSH_INT(cmd_str_cmp(obj1, obj2, cmd.type)); 1415 } 1416 break; 1417 } 1418 case DAVQL_CMD_OP_LT: { 1419 //printf("lt\n"); 1420 DavQLStackObj obj2 = DAVQL_POP(); 1421 DavQLStackObj obj1 = DAVQL_POP(); 1422 if(obj1.type == 0 && obj2.type == 0) { 1423 DAVQL_PUSH_INT(obj1.data.integer < obj2.data.integer); 1424 } else { 1425 DAVQL_PUSH_INT(cmd_str_cmp(obj1, obj2, cmd.type)); 1426 } 1427 break; 1428 } 1429 case DAVQL_CMD_OP_GT: { 1430 //printf("gt\n"); 1431 DavQLStackObj obj2 = DAVQL_POP(); 1432 DavQLStackObj obj1 = DAVQL_POP(); 1433 if(obj1.type == 0 && obj2.type == 0) { 1434 DAVQL_PUSH_INT(obj1.data.integer > obj2.data.integer); 1435 } else { 1436 DAVQL_PUSH_INT(cmd_str_cmp(obj1, obj2, cmd.type)); 1437 } 1438 break; 1439 } 1440 case DAVQL_CMD_OP_LE: { 1441 //printf("le\n"); 1442 DavQLStackObj obj2 = DAVQL_POP(); 1443 DavQLStackObj obj1 = DAVQL_POP(); 1444 if(obj1.type == 0 && obj2.type == 0) { 1445 DAVQL_PUSH_INT(obj1.data.integer <= obj2.data.integer); 1446 } else { 1447 DAVQL_PUSH_INT(cmd_str_cmp(obj1, obj2, cmd.type)); 1448 } 1449 break; 1450 } 1451 case DAVQL_CMD_OP_GE: { 1452 //printf("ge\n"); 1453 DavQLStackObj obj2 = DAVQL_POP(); 1454 DavQLStackObj obj1 = DAVQL_POP(); 1455 if(obj1.type == 0 && obj2.type == 0) { 1456 DAVQL_PUSH_INT(obj1.data.integer >= obj2.data.integer); 1457 } else { 1458 DAVQL_PUSH_INT(cmd_str_cmp(obj1, obj2, cmd.type)); 1459 } 1460 break; 1461 } 1462 case DAVQL_CMD_OP_LIKE: { 1463 //printf("like\n"); 1464 break; 1465 } 1466 case DAVQL_CMD_OP_UNLIKE: { 1467 //printf("unlike\n"); 1468 break; 1469 } 1470 case DAVQL_CMD_CALL: { 1471 //printf("call %x\n", cmd.data.func); 1472 break; 1473 } 1474 } 1475 } 1476 1477 if(stpos == 1) { 1478 *result = stack[0]; 1479 } else { 1480 ret = -1; 1481 } 1482 free(stack); 1483 1484 return ret; 1485 } 1486