libidav/davql.c

changeset 33
0bbbb0341606
child 43
03076907b58a
equal deleted inserted replaced
32:c9d37bb97ea8 33:0bbbb0341606
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2013 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
33 #include "davql.h"
34 #include "methods.h"
35 #include "utils.h"
36
37 DavQuery dav_ql_parse(char *query, va_list ap) {
38 DavQuery davquery;
39 davquery.command = DAV_QUERY_ERROR;
40 davquery.command_data = NULL;
41 sstr_t q = sstr(query);
42 q = sstrtrim(q);
43
44 // get query command
45 sstr_t cmd;
46 cmd.ptr = NULL;
47 int i;
48 for(i=0;i<q.length;i++) {
49 if(q.ptr[i] == ' ') {
50 cmd = sstrsubsl(q, 0, i);
51 break;
52 }
53 }
54 if(!cmd.ptr) {
55 fprintf(stderr, "DQL syntax error\n");
56 return davquery;
57 }
58
59 cmd = sstrtrim(cmd);
60 q = sstrtrim(sstrsubs(q, i));
61 if(!sstrcmp(cmd, S("get"))) {
62 davquery.command = DAV_QUERY_GET;
63 davquery.command_data = dav_ql_parse_get(q, ap);
64 }
65
66 return davquery;
67 }
68
69 DavGetQuery* dav_ql_parse_get(sstr_t q, va_list ap) {
70 sstr_t property_query = q;
71 q = util_getsubstr_until_token(q, S("from"), &property_query);
72
73 sstr_t from_query = q;
74 sstr_t cond = util_getsubstr_until_token(q, S("where"), &from_query);
75
76 // insert variable values
77 UcxBuffer *fbuf = ucx_buffer_new(NULL, 128, UCX_BUFFER_AUTOEXTEND);
78 int var = 0;
79 for(int i=0;i<from_query.length;i++) {
80 char c = from_query.ptr[i];
81 if(c == '%') {
82 if(var) {
83 ucx_buffer_putc(fbuf, '%'); // previous '%'
84 } else {
85 var = 1;
86 }
87 } else if(var) {
88 switch(c) {
89 case 's': {
90 char *arg = va_arg(ap, char*);
91 ucx_buffer_puts(fbuf, arg);
92 break;
93 }
94 default: {
95 ucx_buffer_putc(fbuf, '%');
96 ucx_buffer_putc(fbuf, c);
97 }
98 }
99 var = 0;
100 } else {
101 ucx_buffer_putc(fbuf, c);
102 }
103 }
104
105 // condition
106 DavQOp *condition = NULL;
107 size_t oplen = 0;
108 if(cond.ptr) {
109 //printf("cond: {%.*s}\n", cond.length, cond.ptr);
110 UcxList *ops = NULL;
111 if(dav_parse_condition(&ops, cond, ap)) {
112 // TODO: error
113 printf("parse error\n");
114 return NULL;
115 }
116 oplen = ucx_list_size(ops);
117 condition = calloc(sizeof(DavQOp), oplen);
118 int l = 0;
119 UCX_FOREACH(elm, ops) {
120 condition[l] = *(DavQOp*)elm->data;
121 free(elm->data);
122 l++;
123 }
124 ucx_list_free(ops);
125 }
126
127 DavGetQuery *getquery = malloc(sizeof(DavGetQuery));
128 getquery->properties = sstrdup(property_query);
129 getquery->from = sstrn(fbuf->space, fbuf->pos);
130 if(condition) {
131 getquery->condition = condition;
132 getquery->condlen = oplen;
133 } else {
134 getquery->condition = NULL;
135 getquery->condlen = 0;
136 }
137 return getquery;
138 }
139
140 void free_get_query(DavGetQuery *q) {
141 free(q->from.ptr);
142 free(q->properties.ptr);
143 free(q);
144 }
145
146 int parse_path_query(sstr_t query, char **path, int *depth) {
147 if(query.length == 1) {
148 if(query.ptr[0] == '/') {
149 *path = sstrdup(query).ptr;
150 *depth = 1;
151 return 0;
152 } else {
153 *path = NULL;
154 return 1;
155 }
156 }
157
158 if(query.ptr[query.length-1] == '*') {
159 *depth = -1;
160 *path = sstrdup(sstrsubsl(query, 0, query.length-1)).ptr;
161 } else {
162 *path = sstrdup(query).ptr;
163 *depth = 1;
164 }
165
166 return 0;
167 }
168
169 int dav_parse_condition(UcxList **ops, sstr_t cond, va_list ap) {
170 sstr_t token;
171 DavQOp *op1 = NULL; // level 1 operator
172 DavQOp *op2 = NULL; // level 2 operator
173 DavQOp *op3 = NULL; // level 3 operator
174 while((token = condition_parser_next_token(&cond)).length > 0) {
175 //printf("token: {%.*s}[%d]\n", token.length, token.ptr, token.length);
176 int64_t type = 0;
177 int tkop = condition_operator_type(token, &type);
178 DavQOp *operation = malloc(sizeof(DavQOp));
179 if(tkop > 0) {
180 // operator token
181 operation->type = DAVQOP_OPERATOR;
182 operation->val = NULL;
183 operation->intval = type;
184 switch(tkop) {
185 case 1: {
186 // operators: + - / * not
187 // add operation after next non operator token
188 op1 = operation;
189 break;
190 }
191 case 2: {
192 // operators: < > == != <= >=
193 if(op2) {
194 *ops = ucx_list_append(*ops, op2);
195 }
196 op2 = operation;
197 break;
198 }
199 case 3: {
200 // operators: and or xor
201 if(op2) {
202 *ops = ucx_list_append(*ops, op2);
203 op2 = NULL;
204 }
205 if(op3) {
206 *ops = ucx_list_append(*ops, op3);
207 }
208 op3 = operation;
209 break;
210 }
211 }
212 } else {
213 if(token.ptr[0] == '"' || token.ptr[0] == '\'') {
214 operation->type = DAVQOP_STRING;
215 operation->val = token.ptr+1;
216 operation->intval = token.length-2;
217 } else if(!sstrcmp(token, S("true")) ||
218 !sstrcmp(token, S("false")))
219 {
220 operation->type = DAVQOP_INTEGER;
221 operation->val = NULL;
222 operation->intval = util_getboolean(token.ptr);
223 } else if(token.length == 2 && token.ptr[0] == '%') {
224 switch(token.ptr[1]) {
225 case 's': {
226 char *arg = va_arg(ap, char*);
227 operation->type = DAVQOP_STRING;
228 operation->val = arg;
229 operation->intval = strlen(arg);
230 break;
231 }
232 case 'd': {
233 operation->type = DAVQOP_INTEGER;
234 operation->val = NULL;
235 operation->intval = va_arg(ap, int);
236 break;
237 }
238 case 't': {
239 operation->type = DAVQOP_INTEGER;
240 operation->val = NULL;
241 operation->intval = va_arg(ap, time_t);
242 break;
243 }
244 default: {
245 operation->type = DAVQOP_STRING;
246 operation->val = token.ptr;
247 operation->intval = token.length;
248 }
249 }
250 } else {
251 sstr_t d = sstrdup(token);
252 int64_t val = 0;
253 int intval = util_strtoint(d.ptr, &val);
254 free(d.ptr);
255 if(intval) {
256 operation->type = DAVQOP_INTEGER;
257 operation->val = NULL;
258 operation->intval = val;
259 } else {
260 if(!sstrcmp(token, S("contentlength"))) {
261 operation->type = DAVQOP_RESPROP;
262 } else if(!sstrcmp(token, S("lastmodified"))) {
263 operation->type = DAVQOP_RESPROP;
264 } else if(!sstrcmp(token, S("creationdate"))) {
265 operation->type = DAVQOP_RESPROP;
266 } else if(!sstrcmp(token, S("name"))) {
267 operation->type = DAVQOP_RESPROP;
268 } else if(!sstrcmp(token, S("path"))) {
269 operation->type = DAVQOP_RESPROP;
270 } else if(!sstrcmp(token, S("iscollection"))) {
271 operation->type = DAVQOP_RESPROP;
272 } else {
273 operation->type = DAVQOP_PROPERTY;
274 }
275 operation->val = token.ptr;
276 operation->intval = token.length;
277 }
278 }
279
280 // add operation
281 *ops = ucx_list_append(*ops, operation);
282 if(op1) {
283 // add level 1 operator
284 *ops = ucx_list_append(*ops, op1);
285 op1 = NULL;
286 }
287 }
288 }
289 if(op1) {
290 *ops = ucx_list_append(*ops, op1);
291 }
292 if(op2) {
293 *ops = ucx_list_append(*ops, op2);
294 }
295 if(op3) {
296 *ops = ucx_list_append(*ops, op3);
297 }
298 return 0;
299 }
300
301 sstr_t condition_parser_next_token(sstr_t *str) {
302 sstr_t s = *str;
303 sstr_t t;
304 t.ptr = NULL;
305 t.length = 0;
306 // remove leading space
307 int i;
308 for(i=0;i<s.length;i++) {
309 if(s.ptr[i] > 32) {
310 break;
311 }
312 }
313 s.length -= i;
314 s.ptr += i;
315
316 if(s.length == 0) {
317 *str = s;
318 return t;
319 }
320
321 // check for single char operators
322 switch(s.ptr[0]) {
323 case '<':
324 case '>':
325 case '+':
326 case '-':
327 case '*':
328 case '/': {
329 t.ptr = s.ptr;
330 t.length = 1;
331 str->ptr = s.ptr + 1;
332 str->length = s.length - 1;
333 return t;
334 }
335 }
336
337 if(s.length > 1) {
338 // check for double char operators
339 int16_t op = *(int16_t*)s.ptr;
340 if(op == '==' || op == '!=' || op == '>=' || op == '=<') {
341 t.ptr = s.ptr;
342 t.length = 2;
343 str->ptr = s.ptr + 2;
344 str->length = s.length - 2;
345 return t;
346 }
347 } else {
348 t.ptr = s.ptr;
349 t.length = 1;
350 str->ptr = s.ptr + 1;
351 str->length = s.length - 1;
352 return t;
353 }
354
355 // TODO: brackets
356
357 // check for string literal
358 if(s.ptr[0] == '\'' || s.ptr[0] == '"') {
359 for(i=1;i<s.length;i++) {
360 if(s.ptr[0] == s.ptr[i]) {
361 i++;
362 break;
363 }
364 }
365 t.ptr = s.ptr;
366 t.length = i;
367 str->ptr = s.ptr + i;
368 str->length = s.length - i;
369 return t;
370 }
371
372 for(i=0;i<s.length;i++) {
373 char c = s.ptr[i];
374 if((c < 33) || (c > 41 && c < 48) || (c > 59 && c < 63)) {
375 break;
376 }
377 }
378 t.ptr = s.ptr;
379 t.length = i;
380 str->ptr = s.ptr + i;
381 str->length = s.length - i;
382 return t;
383 }
384
385 int condition_operator_type(sstr_t token, int64_t *type) {
386 // returns the operator level and sets the type
387
388 if(token.ptr[0] == '"' || token.ptr[0] == '\'' || token.ptr[0] == '(') {
389 return 0;
390 }
391
392 if(token.length == 1) {
393 switch(token.ptr[0]) {
394 case '+': *type = 1; return 1;
395 case '-': *type = 2; return 1;
396 case '*': *type = 3; return 1;
397 case '/': *type = 4; return 1;
398 case '<': *type = 5; return 2;
399 case '>': *type = 6; return 2;
400 }
401 }
402 if(!sstrcmp(token, S("not"))) {
403 *type = 0;
404 return 1;
405 }
406
407 if(!sstrcmp(token, S("=="))) {
408 *type = 7;
409 return 2;
410 }
411 if(!sstrcmp(token, S("!="))) {
412 *type = 8;
413 return 2;
414 }
415 if(!sstrcmp(token, S("<="))) {
416 *type = 9;
417 return 2;
418 }
419 if(!sstrcmp(token, S(">="))) {
420 *type = 10;
421 return 2;
422 }
423
424 if(!sstrcmp(token, S("and"))) {
425 *type = 11;
426 return 3;
427 }
428 if(!sstrcmp(token, S("or"))) {
429 *type = 12;
430 return 3;
431 }
432 if(!sstrcmp(token, S("xor"))) {
433 *type = 13;
434 return 3;
435 }
436
437 return 0;
438 }
439
440 int condition_eval(DavResource *res, DavQOp *cond, size_t len) {
441 DavQOp stack[128];
442 int stackpos = 0;
443 for(int i=0;i<len;i++) {
444 DavQOp op = cond[i];
445 switch(op.type) {
446 case DAVQOP_OPERATOR: {
447 if(op.intval == 0) {
448 // not operator
449 if(stackpos < 1) {
450 // error
451 printf("no data on stack\n");
452 return 0;
453 }
454 int pos = stackpos-1;
455 if(stack[pos].type == DAVQOP_INTEGER) {
456 //printf("not %" PRId64 "\n", stack[pos].intval);
457 stack[pos].intval = !stack[pos].intval;
458 } else {
459 // error
460 printf("wrong value for 'not' operator\n");
461 return 0;
462 }
463 } else {
464 DavQOp val1 = stack[stackpos-2];
465 DavQOp val2 = stack[stackpos-1];
466 DavQOp result;
467 if(val1.type == DAVQOP_INTEGER) {
468 if(val2.type == DAVQOP_INTEGER) {
469 result = compare_intint(
470 op.intval,
471 val1.intval,
472 val2.intval);
473 } else {
474 result = compare_intstr(op.intval, val1, val2);
475 }
476 } else {
477 if(val2.type == DAVQOP_INTEGER) {
478 result = compare_strint(op.intval, val1, val2);
479 } else {
480 result = compare_strstr(op.intval, val1, val2);
481 }
482 }
483 stack[stackpos-2] = result;
484 stackpos--;
485 }
486 break;
487 }
488 case DAVQOP_STRING:
489 case DAVQOP_INTEGER:
490 case DAVQOP_TIME: {
491 if(op.type == DAVQOP_STRING) {
492 //printf("put on stack: '%s'\n", op.val);
493 } else {
494 //printf("put on stack[%d]: %" PRId64 "\n", stackpos, op.intval);
495 }
496 stack[stackpos++] = op;
497 break;
498 }
499 case DAVQOP_PROPERTY: {
500 sstr_t pname = sstrn(op.val, op.intval);
501 pname = sstrdup(pname);
502 char *property_value = dav_get_property(res, pname.ptr);
503 free(pname.ptr);
504 DavQOp value;
505 value.type = DAVQOP_STRING;
506 if(property_value) {
507 //printf("put on stack: \"%s\"\n", property_value);
508 value.val = property_value;
509 value.intval = strlen(property_value);
510 } else {
511 //printf("put on stack: null string\n");
512 value.val = NULL;
513 value.intval = 0;
514 }
515 stack[stackpos++] = value;
516 break;
517 }
518 case DAVQOP_RESPROP: {
519 sstr_t name = sstrn(op.val, op.intval);
520 DavQOp value;
521 value.type = DAVQOP_INTEGER;
522 value.val = NULL;
523 if(!sstrcmp(name, S("contentlength"))) {
524 //printf("put contentlength\n");
525 value.intval = res->contentlength;
526 } else if(!sstrcmp(name, S("lastmodified"))) {
527 //printf("put getlastmodified\n");
528 value.intval = res->lastmodified;
529 } else if(!sstrcmp(name, S("creationdate"))) {
530 value.intval = res->creationdate;
531 } else if(!sstrcmp(name, S("name"))) {
532 value.type = DAVQOP_STRING;
533 value.val = res->name;
534 value.intval = strlen(res->name);
535 } else if(!sstrcmp(name, S("path"))) {
536 value.type = DAVQOP_STRING;
537 value.val = res->path;
538 value.intval = strlen(res->path);
539 } else if(!sstrcmp(name, S("iscollection"))) {
540 value.type = DAVQOP_INTEGER;
541 value.val = NULL;
542 value.intval = res->iscollection;
543 }
544 stack[stackpos++] = value;
545 break;
546 }
547 }
548 }
549 if(stackpos != 1) {
550 return 0;
551 }
552 DavQOp result = stack[0];
553 //printf("result: %" PRId64 "\n", result.intval);
554 return (int)result.intval;
555 }
556
557 DavQOp compare_intint(int op, int64_t v1, int64_t v2) {
558 DavQOp res;
559 res.type = DAVQOP_INTEGER;
560 res.val = NULL;
561 res.intval = 0;
562 switch(op) {
563 case 5: {
564 // <
565 //printf("compare: %" PRId64 " < %" PRId64 "\n", v1, v2);
566 res.intval = v1 < v2;
567 break;
568 }
569 case 6: {
570 // >
571 //printf("compare: %" PRId64 " > %" PRId64 "\n", v1, v2);
572 res.intval = v1 > v2;
573 break;
574 }
575 case 7: {
576 // ==
577 //printf("compare: %" PRId64 " == %" PRId64 "\n", v1, v2);
578 res.intval = v1 == v2;
579 break;
580 }
581 case 8: {
582 // !=
583 //printf("compare: %" PRId64 " != %" PRId64 "\n", v1, v2);
584 res.intval = v1 != v2;
585 break;
586 }
587 case 9: {
588 // <=
589 //printf("compare: %" PRId64 " <= %" PRId64 "\n", v1, v2);
590 res.intval = v1 <= v2;
591 break;
592 }
593 case 10: {
594 // >=
595 //printf("compare: %" PRId64 " >= %" PRId64 "\n", v1, v2);
596 res.intval = v1 >= v2;
597 break;
598 }
599 case 11: {
600 // and
601 //printf("compare: %" PRId64 " and %" PRId64 "\n", v1, v2);
602 res.intval = v1 && v2;
603 break;
604 }
605 case 12: {
606 // or
607 //printf("compare: %" PRId64 " or %" PRId64 "\n", v1, v2);
608 res.intval = v1 || v2;
609 break;
610 }
611 case 13: {
612 // xor
613 //printf("compare: %" PRId64 " xor %" PRId64 "\n", v1, v2);
614 res.intval = v1 ^ v2;
615 break;
616 }
617 }
618 return res;
619 }
620
621 DavQOp compare_strint(int op, DavQOp v1, DavQOp v2) {
622 int64_t v1int;
623 sstr_t s1 = sstrn(v1.val, v1.intval);
624 s1 = sstrdup(s1);
625 if(util_strtoint(s1.ptr, &v1int)) {
626 free(s1.ptr);
627 return compare_intint(op, v1int, v2.intval);
628 } else {
629 free(s1.ptr);
630 // TODO
631 }
632 }
633
634 DavQOp compare_intstr(int op, DavQOp v1, DavQOp v2) {
635 // TODO
636 }
637
638 DavQOp compare_strstr(int op, DavQOp v1, DavQOp v2) {
639 DavQOp res;
640 res.type = DAVQOP_INTEGER;
641 res.val = NULL;
642 res.intval = 0;
643 sstr_t s1 = sstrn(v1.val, v1.intval);
644 sstr_t s2 = sstrn(v2.val, v2.intval);
645 switch(op) {
646 case 5: {
647 // <
648 //printf("str compare: %.*s < %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
649 res.intval = s1.length < s2.length;
650 break;
651 }
652 case 6: {
653 // >
654 //printf("str compare: %.*s > %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
655 res.intval = s1.length > s2.length;
656 break;
657 }
658 case 7: {
659 // ==
660 //printf("str compare: %.*s == %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
661 res.intval = sstrcmp(s1, s2) == 0;
662 break;
663 }
664 case 8: {
665 // !=
666 //printf("str compare: %.*s != %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
667 res.intval = sstrcmp(s1, s2) != 0;
668 break;
669 }
670 case 9: {
671 // <=
672 //printf("str compare: %.*s <= %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
673 res.intval = s1.length <= s2.length;
674 break;
675 }
676 case 10: {
677 // >=
678 //printf("str compare: %.*s >= %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
679 res.intval = s1.length >= s2.length;
680 break;
681 }
682 case 11: {
683 // and
684 //printf("str compare: %.*s and %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
685 res.intval = s1.ptr && s2.ptr;
686 break;
687 }
688 case 12: {
689 // or
690 //printf("str compare: %.*s or %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
691 res.intval = s1.ptr || s2.ptr;
692 break;
693 }
694 case 13: {
695 // xor
696 //printf("str compare: %.*s xor %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr);
697 res.intval = (intptr_t)s1.ptr ^ (intptr_t)s2.ptr;
698 break;
699 }
700 }
701 return res;
702 }

mercurial