Module: sip-router Branch: andrei/switch Commit: 8c09d09b62681ae4e25709cd291796880dfb91e6 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=8c09d09b...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@iptel.org Date: Thu Feb 19 23:48:34 2009 +0100
script parsing: string switch support
- switch() modified to work on string if the first case contains a string as the label - switch() support for regular expressions. Regular expression are prefixed by `/`. E.g.: switch("a"){ case / ""+"["+"a"+"bc" +"]" : log(1, "case a:a\n"); break; case "b": log(1, "case a:b\n"); break; }
---
cfg.y | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 112 insertions(+), 12 deletions(-)
diff --git a/cfg.y b/cfg.y index e1758bf..0ebb3a9 100644 --- a/cfg.y +++ b/cfg.y @@ -215,7 +215,11 @@ static struct socket_id* mk_listen_id2(struct name_lst*, int, int); static void free_name_lst(struct name_lst* lst); static void free_socket_id_lst(struct socket_id* i);
-static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a); +static struct case_stms* mk_case_stm(struct rval_expr* ct, int is_re, + struct action* a, int* err); +static int case_check_type(struct case_stms* stms); +static int case_check_default(struct case_stms* stms); +
%}
@@ -1793,10 +1797,12 @@ ct_rval: rval_expr { $$=0; if (!rve_is_constant($1)){ yyerror("constant expected"); - }else if (!rve_check_type((enum rval_type*)&i_tmp, $1, 0, 0 ,0)){ + /* + } else if (!rve_check_type((enum rval_type*)&i_tmp, $1, 0, 0 ,0)){ yyerror("invalid expression (bad type)"); }else if (i_tmp!=RV_INT){ yyerror("invalid expression type, int expected\n"); + */ }else $$=$1; } @@ -1805,28 +1811,38 @@ single_case: CASE ct_rval COLON actions { $$=0; if ($2==0) yyerror ("bad case label"); - else if (($$=mk_case_stm($2, $4))==0){ - yyerror("internal error: memory allocation failure"); + else if ((($$=mk_case_stm($2, 0, $4, &i_tmp))==0) && (i_tmp==-10)){ + YYABORT; + } + } +| CASE SLASH ct_rval COLON actions { + $$=0; + if ($3==0) yyerror ("bad case label"); + else if ((($$=mk_case_stm($3, 1, $5, &i_tmp))==0) && (i_tmp==-10)){ YYABORT; } } | CASE ct_rval COLON { $$=0; if ($2==0) yyerror ("bad case label"); - else if (($$=mk_case_stm($2, 0))==0){ - yyerror("internal error: memory allocation failure"); + else if ((($$=mk_case_stm($2, 0, 0, &i_tmp))==0) && (i_tmp==-10)){ + YYABORT; + } + } + | CASE SLASH ct_rval COLON { + $$=0; + if ($3==0) yyerror ("bad case label"); + else if ((($$=mk_case_stm($3, 1, 0, &i_tmp))==0) && (i_tmp==-10)){ YYABORT; } } | DEFAULT COLON actions { - if (($$=mk_case_stm(0, $3))==0){ - yyerror("internal error: memory allocation failure"); + if ((($$=mk_case_stm(0, 0, $3, &i_tmp))==0) && (i_tmp=-10)){ YYABORT; } } | DEFAULT COLON { - if (($$=mk_case_stm(0, 0))==0){ - yyerror("internal error: memory allocation failure"); + if ((($$=mk_case_stm(0, 0, 0, &i_tmp))==0) && (i_tmp==-10)){ YYABORT; } } @@ -1854,6 +1870,12 @@ switch_cmd: $$=0; if ($2==0) yyerror("bad expression in switch(...)"); else if ($4==0) yyerror ("bad switch body"); + else if (case_check_default($4)!=0) + yyerror_at(&$2->fpos, "bad switch(): too many " + ""default:" labels\n"); + else if (case_check_type($4)!=0) + yyerror_at(&$2->fpos, "bad switch(): mixed integer and" + " string/RE cases not allowed\n"); else{ $$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, $4); if ($$==0) { @@ -2910,15 +2932,52 @@ static void free_socket_id_lst(struct socket_id* lst) }
-static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a) +/** create a temporary case statmenet structure. + * *err will be filled in case of error (return == 0): + * -1 - non constant expression + * -2 - expression error (bad type) + * -10 - memory allocation error + */ +static struct case_stms* mk_case_stm(struct rval_expr* ct, int is_re, + struct action* a, int* err) { struct case_stms* s; + struct rval_expr* bad_rve; + enum rval_type type, bad_t, exp_t; + enum match_str_type t; + + t=MATCH_UNKNOWN; + if (ct){ + /* if ct!=0 => case, else if ct==0 is a default */ + if (!rve_is_constant(ct)){ + yyerror_at(&ct->fpos, "non constant expression in case"); + *err=-1; + return 0; + } + if (rve_check_type(&type, ct, &bad_rve, &bad_t, &exp_t)!=1){ + yyerror_at(&ct->fpos, "bad expression: type mismatch:" + " %s instead of %s at (%d,%d)", + rval_type_name(bad_t), rval_type_name(exp_t), + bad_rve->fpos.s_line, bad_rve->fpos.s_col); + *err=-2; + return 0; + } + if (is_re) + t=MATCH_RE; + else if (type==RV_STR) + t=MATCH_STR; + else + t=MATCH_INT; + } + s=pkg_malloc(sizeof(*s)); if (s==0) { - LOG(L_CRIT,"ERROR: cfg. parser: out of memory.\n"); + yyerror("internal error: memory allocation failure"); + *err=-10; } else { memset(s, 0, sizeof(*s)); s->ct_rve=ct; + s->type=t; s->actions=a; s->next=0; s->append=0; @@ -2926,6 +2985,47 @@ static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a) return s; }
+ +/* + * @return 0 on success, -1 on error. + */ +static int case_check_type(struct case_stms* stms) +{ + struct case_stms* c; + struct case_stms* s; + + for(c=stms; c ; c=c->next){ + if (!c->ct_rve) continue; + for (s=c->next; s; s=s->next){ + if (!s->ct_rve) continue; + if ((s->type!=c->type) && + !( (c->type==MATCH_STR || c->type==MATCH_RE) && + (s->type==MATCH_STR || s->type==MATCH_RE) ) ){ + yyerror_at(&s->ct_rve->fpos, "type mismatch in case"); + return -1; + } + } + } + return 0; +} + + +/* + * @return 0 on success, -1 on error. + */ +static int case_check_default(struct case_stms* stms) +{ + struct case_stms* c; + int default_no; + + default_no=0; + for(c=stms; c ; c=c->next) + if (c->ct_rve==0) default_no++; + return (default_no<=1)?0:-1; +} + + + /* int main(int argc, char ** argv) {