[SR-Dev] git:andrei/switch: script parsing: string switch support

Andrei Pelinescu-Onciul andrei at iptel.org
Thu Feb 19 23:50:55 CET 2009


Module: sip-router
Branch: andrei/switch
Commit: 8c09d09b62681ae4e25709cd291796880dfb91e6
URL:    http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=8c09d09b62681ae4e25709cd291796880dfb91e6

Author: Andrei Pelinescu-Onciul <andrei at iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei at 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)
 {




More information about the sr-dev mailing list