8 #include "obj_filter.h"
11 #include "xmlconfig.h"
19 enum error_t {ERR_NONE=0, ERR_SYNTAX, ERR_UNKNOWN_ATTRIBUTE, ERR_INTERNAL, ERR_NONTERMINATED_STRING };
25 struct attr *navit_obj;
26 struct object_func *obj_func;
30 static int parse_numeric_expr(struct ctx*the_ctx);
31 static int parse_cond_expr(struct ctx*the_ctx);
32 static int parse_bool_expr(struct ctx*the_ctx);
33 static enum operator_t get_operator_by_symbol(char*sym);
34 static char* get_opstr_by_op(enum operator_t op);
35 static int whitespace_num(char*str);
37 static char*next_sym_ptr;
40 * parses an input like osd[attr1==2 && attr2==3][2] or [attr1==2 && attr2==3]
41 * returns 0 on failure , returns the number of parsed characters on success
43 int parse_obj_filter(const char*input, struct obj_filter_t* out)
45 char *curr_ch, *itt, *expr;
46 out->idx = 0; //default idx
49 curr_ch = (char*)input;
50 while(isspace(*curr_ch)) {++curr_ch;}
52 //parse attr type for the list(iterator)
53 itt = out->iterator_type;
54 if(isalpha(*curr_ch) || *curr_ch=='_') {
55 while(isalnum(*curr_ch) || *curr_ch=='_' ) {
63 while(isspace(*curr_ch)) {++curr_ch;}
64 //parse the filter expression (first section between[]), ignore [] chars between "" or ''
65 expr = out->filter_expr;
66 if(*curr_ch++ == '[') {
67 while (*curr_ch && *curr_ch!=']') {
80 while(isspace(*curr_ch)) {++curr_ch;}
81 end1 = curr_ch; //possible end of expression if no idx specified
82 //parse the optional idx part (another part between [] contains numeric expreession(currently only constant numers are supported))
88 while(isspace(*curr_ch)) {++curr_ch;}
91 while ('0'<=*curr_ch && *curr_ch<='9') {
98 while(isspace(*curr_ch)) {++curr_ch;}
103 out->idx = atoi(numstr);
104 return curr_ch-input;
116 struct attr* filter_object(struct attr* root,char*iter_type,char*expr, int idx)
118 struct attr_iter *iter;
119 struct attr the_attr;
121 struct object_func *obj_func_root;
122 struct object_func *obj_func_iter;
124 if (!root || !iter_type || !expr) {
128 obj_func_root = object_func_lookup(((struct attr*)root)->type);
129 obj_func_iter = object_func_lookup(attr_from_name(iter_type));
130 if( !obj_func_root || !obj_func_root->get_attr || !obj_func_root->iter_new || !obj_func_root->iter_destroy ||
131 !obj_func_iter || !obj_func_iter->get_attr ) {
135 iter = obj_func_root->iter_new(NULL);
136 while ( obj_func_root->get_attr(root->u.data, attr_from_name(iter_type), &the_attr, iter ) ) {
139 the_ctx.navit_obj = &the_attr;
140 the_ctx.obj_func = obj_func_iter;
141 if (parse_bool_expr(&the_ctx)) {
142 if(the_ctx.res.res_bool) {
144 return attr_dup(&the_attr);
150 obj_func_root->iter_destroy(iter);
155 enum operator_t {OP_NONE=0, OP_GT, OP_GE, OP_LT, OP_LE, OP_EQ, OP_NE, OP_LOGICAL_AND, OP_LOGICAL_OR, OP_LOGICAL_XOR, OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD};
157 struct op_table_entry {
159 enum operator_t op_type;
162 struct op_table_entry op_table[] = {
169 {"&&", OP_LOGICAL_AND},
170 {"||", OP_LOGICAL_OR},
171 {"^" , OP_LOGICAL_XOR},
180 static enum operator_t get_operator_by_symbol(char*sym)
182 struct op_table_entry* ote = op_table;
183 while(sym && ote->name) {
184 if ( ! strcmp(ote->name, sym)) {
192 static char* get_opstr_by_op(enum operator_t op)
194 struct op_table_entry* ote = op_table;
196 if ( ote->op_type == op ) {
207 ident = [ [A-Z,a-z][A-Z,a-z,0-9]+
210 number = [ [A-Z,a-z][A-Z,a-z,0-9]+
213 numeric_additive_expr = [
214 | numeric_mul_operand numeric_mul_operator numeric_mul_expr
215 | numeric_add_operand numeric_add_operator numeric_add_expr
216 | "(" numeric_expr ")"
220 bool_expr = [ bool_expr bool_operator bool_operand
226 cond_operand cond_operator cond_operand
229 //TODO support precedence between additive and multiplicative operators (the order of +- and * / evaluation)
231 numeric_multiplicative_operator = [ "*" "/" "%"
234 numeric_additive_operator = [ "+" "-"
237 bool_operator = [ "&&" "||" "^"
240 cond_operator = [ "==" "!=" "< "> "<=" ">="
252 | "(" numeric_expr ")"
263 static int whitespace_num(char*str)
266 while(isspace(*str)) {
274 get_op(char *expr, ...)
280 while (isspace(*expr)) {
285 while ((op = va_arg(ap, char *))) {
286 if (!strncmp(expr, op, strlen(op))) {
295 static int ident_length(char*input)
298 if(input[0] != '@') {
301 if(isalpha((int)input[1])) {
304 for(ii=2 ; ii<strlen(input) ; ++ii) {
305 if(!isalnum((int)input[ii])) {
316 static enum operator_t parse_bool_operator(struct ctx*the_ctx)
318 char* input = the_ctx->expr;
321 sym = get_op(input,"&&","||","^",NULL);
323 op = get_operator_by_symbol(sym);
336 static enum operator_t parse_cond_operator(struct ctx*the_ctx)
338 char* input = the_ctx->expr;
341 sym = get_op(input, "==", "<", ">", "<=", ">=", "!=", NULL);
343 op = get_operator_by_symbol(sym);
359 static enum operator_t parse_numeric_multiplicative_operator(struct ctx*the_ctx)
361 char* input = the_ctx->expr;
364 sym = get_op(input, "*", "/", "%", NULL);
366 op = get_operator_by_symbol(sym);
379 static enum operator_t parse_numeric_additive_operator(struct ctx*the_ctx)
381 char* input = the_ctx->expr;
384 sym = get_op(input, "+", "-", NULL);
386 op = get_operator_by_symbol(sym);
398 static int parse_string_operand(struct ctx*the_ctx)
400 char* input = the_ctx->expr;
404 sub_ctx.navit_obj = the_ctx->navit_obj;
405 sub_ctx.obj_func = the_ctx->obj_func;
407 while(isspace(*input)) {++input;}
409 if (*input == '"' || *input=='\'') {
410 char delimiter = *input;
413 while(*input != delimiter && *input!='\0') {
419 the_ctx->error = ERR_NONTERMINATED_STRING;
421 } else { //terminating delimiter found
423 the_ctx->res.res_str = g_strdup(sym);
424 the_ctx->error = ERR_NONE;
425 next_sym_ptr = input + 1;
430 ilen = ident_length(input);
432 struct attr the_attr;
433 strncpy(sym,input+1,ilen);
435 if ( attr_from_name(sym)!=attr_none && the_ctx->obj_func->get_attr(the_ctx->navit_obj->u.data, attr_from_name(sym), &the_attr, NULL )
436 && attr_type_string_begin<=the_attr.type && the_attr.type <= attr_type_string_end) {
437 the_ctx->res.res_str = g_strdup(the_attr.u.str);
438 the_ctx->error = ERR_NONE;
439 next_sym_ptr = input+ilen+1;
442 the_ctx->error = ERR_UNKNOWN_ATTRIBUTE;
447 //currently we are not supporting string expressions (eg: concatenation)
449 if(get_op(input,"(",NULL)) {
450 sub_ctx.expr = input + 1 + whitespace_num(input);
451 if ( ! parse_string_expr(&sub_ctx)) {
452 the_ctx->error = ERR_SYNTAX;
455 the_ctx->res.res_int = sub_ctx.res.res_int;
456 the_ctx->error = ERR_NONE;
459 if ( get_op(next_sym_ptr,")",NULL)) {
460 next_sym_ptr += 1 + whitespace_num(next_sym_ptr);
463 the_ctx->res.res_int = 0;
464 the_ctx->error = ERR_SYNTAX;
473 static int parse_numeric_operand(struct ctx*the_ctx)
475 char* input = the_ctx->expr;
480 sub_ctx.navit_obj = the_ctx->navit_obj;
481 sub_ctx.obj_func = the_ctx->obj_func;
483 res = strtol(input,&endptr,0);
484 if( endptr!=input ) {
485 the_ctx->res.res_int = res;
486 the_ctx->error = ERR_NONE;
487 next_sym_ptr = endptr;
491 while(isspace(*input)) {++input;}
492 ilen = ident_length(input);
494 //get int value from context object and set result member of context argument
495 struct attr the_attr;
496 strncpy(sym,input+1,ilen);
498 if ( attr_from_name(sym)!=attr_none && the_ctx->obj_func->get_attr(the_ctx->navit_obj->u.data, attr_from_name(sym), &the_attr, NULL )
499 && attr_type_int_begin<=the_attr.type && the_attr.type <= attr_type_int_end) { //TODO support other numeric types
500 the_ctx->res.res_int = the_attr.u.num;
501 the_ctx->error = ERR_NONE;
502 next_sym_ptr = input+ilen+1;
505 the_ctx->error = ERR_UNKNOWN_ATTRIBUTE;
509 if(get_op(input,"(",NULL)) {
510 sub_ctx.expr = input + 1 + whitespace_num(input);
511 if ( ! parse_numeric_expr(&sub_ctx)) {
512 the_ctx->error = ERR_SYNTAX;
515 the_ctx->res.res_int = sub_ctx.res.res_int;
516 the_ctx->error = ERR_NONE;
519 if ( get_op(next_sym_ptr,")",NULL)) {
520 next_sym_ptr += 1 + whitespace_num(next_sym_ptr);
523 the_ctx->res.res_int = 0;
524 the_ctx->error = ERR_SYNTAX;
531 static int parse_cond_operand(struct ctx*the_ctx)
533 char* input = the_ctx->expr;
537 struct attr the_attr;
539 sub_ctx.navit_obj = the_ctx->navit_obj;
540 sub_ctx.obj_func = the_ctx->obj_func;
541 sub_ctx.expr = input;
542 if(parse_numeric_expr(&sub_ctx)) {
543 the_ctx->res.res_int = sub_ctx.res.res_int;
544 the_ctx->error = ERR_NONE;
548 res = strtol(input,&endptr,0);
549 if( endptr!=input ) {
550 the_ctx->res.res_int = res;
551 the_ctx->error = ERR_NONE;
552 next_sym_ptr = endptr;
555 while(isspace(*input)) {++input;}
556 ilen = ident_length(input);
557 strncpy(sym,input+1,ilen);
559 if ( attr_from_name(sym)!=attr_none && the_ctx->obj_func->get_attr(the_ctx->navit_obj->u.data, attr_from_name(sym), &the_attr, NULL )
560 && attr_type_int_begin<=the_attr.type && the_attr.type <= attr_type_int_end) { //TODO support other numeric types
561 the_ctx->res.res_int = the_attr.u.num;
562 the_ctx->error = ERR_NONE;
563 next_sym_ptr = input+ilen+1;
566 the_ctx->error = ERR_UNKNOWN_ATTRIBUTE;
569 the_ctx->error = ERR_SYNTAX;
573 static int parse_bool_operand(struct ctx*the_ctx)
575 char* input = the_ctx->expr;
577 sub_ctx.navit_obj = the_ctx->navit_obj;
578 sub_ctx.obj_func = the_ctx->obj_func;
579 if(get_op(input,"true",NULL)) {
580 the_ctx->res.res_bool = 1;
581 the_ctx->error = ERR_NONE;
582 next_sym_ptr += whitespace_num(input)+strlen("true");
585 if(get_op(input,"false",NULL)) {
586 the_ctx->res.res_bool = 0;
587 the_ctx->error = ERR_NONE;
588 next_sym_ptr += whitespace_num(input)+strlen("false");
591 if(get_op(input,"(",NULL)) {
592 sub_ctx.expr = input + 1 + whitespace_num(input);
593 if ( ! parse_bool_expr(&sub_ctx)) {
594 the_ctx->error = ERR_SYNTAX;
597 the_ctx->res.res_bool = sub_ctx.res.res_bool;
598 the_ctx->error = ERR_NONE;
601 if(get_op(next_sym_ptr,"(",NULL)) {
602 next_sym_ptr += 1 + whitespace_num(next_sym_ptr);
605 the_ctx->error = ERR_SYNTAX;
610 sub_ctx.expr = input;
611 if (parse_cond_expr(&sub_ctx)) {
612 the_ctx->res.res_bool = sub_ctx.res.res_bool;
613 the_ctx->error = ERR_NONE;
616 the_ctx->error = ERR_SYNTAX;
620 static int parse_cond_expr(struct ctx*the_ctx)
622 char* input = the_ctx->expr;
624 sub_ctx.navit_obj = the_ctx->navit_obj;
625 sub_ctx.obj_func = the_ctx->obj_func;
626 sub_ctx.expr = input;
629 //expect cond operand
630 if(parse_cond_operand(&sub_ctx)) {
632 int op1 = sub_ctx.res.res_int;
633 //expect cond operand
634 sub_ctx.expr = next_sym_ptr;
635 if( (op=parse_cond_operator(&sub_ctx)) ) {
636 next_sym_ptr += whitespace_num(next_sym_ptr) + strlen(get_opstr_by_op(op));
637 sub_ctx.expr = next_sym_ptr;
638 if(parse_cond_operand(&sub_ctx)) {
639 int op2 = sub_ctx.res.res_int;
642 the_ctx->res.res_bool = op1==op2;
645 the_ctx->res.res_bool = op1<op2;
648 the_ctx->res.res_bool = op1>op2;
651 the_ctx->res.res_bool = op1<=op2;
654 the_ctx->res.res_bool = op1>=op2;
657 the_ctx->res.res_bool = op1!=op2;
661 the_ctx->error = ERR_INTERNAL;
665 the_ctx->error = ERR_NONE;
673 //expect cond operand
674 if(parse_string_operand(&sub_ctx)) {
675 char* op1 = sub_ctx.res.res_str;
678 //expect cond operand
679 sub_ctx.expr = next_sym_ptr;
680 if( (op=parse_cond_operator(&sub_ctx)) ) {
681 next_sym_ptr += whitespace_num(next_sym_ptr) + strlen(get_opstr_by_op(op));
682 sub_ctx.expr = next_sym_ptr;
683 if(parse_string_operand(&sub_ctx)) {
684 char* op2 = sub_ctx.res.res_str;
687 the_ctx->res.res_bool = !strcmp(op1,op2);
690 the_ctx->res.res_bool = strcmp(op1,op2)<=0;
693 the_ctx->res.res_bool = strcmp(op1,op2)>=0;
696 the_ctx->res.res_bool = strcmp(op1,op2)<0;
699 the_ctx->res.res_bool = strcmp(op1,op2)>0;
702 the_ctx->res.res_bool = !!strcmp(op1,op2);
706 the_ctx->error = ERR_INTERNAL;
710 the_ctx->error = ERR_NONE;
715 the_ctx->error = ERR_SYNTAX;
721 | numeric_operand numeric_multiplicative_operator numeric_expr
722 | numeric_operand numeric_additive_operator numeric_expr
723 | "(" numeric_expr ")"
727 static int parse_numeric_expr(struct ctx*the_ctx)
729 char* input = the_ctx->expr;
731 sub_ctx.navit_obj = the_ctx->navit_obj;
732 sub_ctx.obj_func = the_ctx->obj_func;
733 sub_ctx.expr = input;
734 if(parse_numeric_operand(&sub_ctx)) {
736 int op1 = sub_ctx.res.res_int;
737 //expect numeric_multiplicative operator
738 sub_ctx.expr = next_sym_ptr;
739 if( (op=parse_numeric_multiplicative_operator(&sub_ctx)) ) {
740 next_sym_ptr += whitespace_num(next_sym_ptr) + strlen(get_opstr_by_op(op));
741 sub_ctx.expr = next_sym_ptr;
742 if(parse_numeric_expr(&sub_ctx)) {
743 int op2 = sub_ctx.res.res_int;
746 the_ctx->res.res_int = op1*op2;
749 the_ctx->res.res_int = op1/op2;
752 the_ctx->res.res_int = op1%op2;
756 the_ctx->error = ERR_INTERNAL;
760 the_ctx->error = ERR_NONE;
766 sub_ctx.expr = input;
767 if(parse_numeric_operand(&sub_ctx)) {
768 //expect numeric_additive operator
770 int op1 = sub_ctx.res.res_int;
771 sub_ctx.expr = next_sym_ptr;
772 if((op=parse_numeric_additive_operator(&sub_ctx))) {
773 next_sym_ptr += whitespace_num(next_sym_ptr) + strlen(get_opstr_by_op(op));
774 sub_ctx.expr = next_sym_ptr;
775 if(parse_numeric_expr(&sub_ctx)) {
776 int op2 = sub_ctx.res.res_int;
779 the_ctx->res.res_int = op1+op2;
782 the_ctx->res.res_int = op1-op2;
786 the_ctx->error = ERR_INTERNAL;
790 the_ctx->error = ERR_NONE;
796 sub_ctx.expr = input;
797 if(parse_numeric_operand(&sub_ctx) ) {
798 the_ctx->res.res_int = sub_ctx.res.res_int;
799 the_ctx->error = ERR_NONE;
802 the_ctx->error = ERR_SYNTAX;
807 bool_expr = [ bool_operand bool_operator bool_expr
811 static int parse_bool_expr(struct ctx*the_ctx)
813 char* input = the_ctx->expr;
815 sub_ctx.navit_obj = the_ctx->navit_obj;
816 sub_ctx.obj_func = the_ctx->obj_func;
817 sub_ctx.expr = input;
818 if(parse_bool_operand(&sub_ctx)) {
820 int op1 = sub_ctx.res.res_bool;
821 //expect bool operator
822 sub_ctx.expr = next_sym_ptr;
823 if((op=parse_bool_operator(&sub_ctx))) {
824 next_sym_ptr += whitespace_num(next_sym_ptr) + strlen(get_opstr_by_op(op));
825 sub_ctx.expr = next_sym_ptr;
826 if(parse_bool_expr(&sub_ctx)) {
827 int op2 = sub_ctx.res.res_bool;
830 the_ctx->res.res_bool = op1 && op2;
833 the_ctx->res.res_bool = op1 || op2;
836 the_ctx->res.res_bool = op1 ^ op2;
840 the_ctx->error = ERR_INTERNAL;
849 if(get_op(input,"!",NULL)) {
850 next_sym_ptr += 1 + whitespace_num(input);
851 sub_ctx.expr = next_sym_ptr;
852 if(parse_bool_expr(&sub_ctx)) {
853 the_ctx->res.res_bool = ! sub_ctx.res.res_bool;
854 the_ctx->error = ERR_NONE;
858 sub_ctx.expr = input;
859 if(parse_bool_operand(&sub_ctx) ) {
860 the_ctx->res.res_bool = sub_ctx.res.res_bool;
861 the_ctx->error = ERR_NONE;
864 the_ctx->error = ERR_SYNTAX;