Browse code

script engine: string switch execution

- support for matching strings and regular expressions in a string
switch (MATCH_T).

Andrei Pelinescu-Onciul authored on 19/02/2009 22:38:37
Showing 3 changed files
... ...
@@ -116,6 +116,11 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
116 116
 	struct switch_cond_table* sct;
117 117
 	struct switch_jmp_table*  sjt;
118 118
 	struct rval_expr* rve;
119
+	struct match_cond_table* mct;
120
+	struct rvalue* rv;
121
+	struct rvalue* rv1;
122
+	struct rval_cache c1;
123
+	str s;
119 124
 
120 125
 
121 126
 	/* reset the value of error to E_UNSPEC so avoid unknowledgable
... ...
@@ -907,6 +912,68 @@ sw_jt_def:
907 907
 											   returns passthrough */
908 908
 			}
909 909
 			break;
910
+		case MATCH_COND_T:
911
+			mct=(struct match_cond_table*)a->val[1].u.data;
912
+			rval_cache_init(&c1);
913
+			rv=0;
914
+			rv1=0;
915
+			ret=rval_expr_eval_rvint(h, msg, &rv, &v, 
916
+									(struct rval_expr*)a->val[0].u.data, &c1);
917
+									
918
+			if (unlikely( ret<0)){
919
+				/* handle error in expression => use default */
920
+				ret=-1;
921
+				goto match_cond_def;
922
+			}
923
+			if (h->run_flags & EXIT_R_F){
924
+				ret=0;
925
+				break;
926
+			}
927
+			h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return & break
928
+													    in expr */
929
+			if (likely(rv)){
930
+				rv1=rval_convert(h, msg, RV_STR, rv, &c1);
931
+				if (unlikely(rv1==0)){
932
+					ret=-1;
933
+					goto match_cond_def;
934
+				}
935
+				s=rv1->v.s;
936
+			}else{
937
+				/* int result in v */
938
+				rval_cache_clean(&c1);
939
+				s.s=sint2str(v, &s.len);
940
+			}
941
+			ret=1; /* default is continue */
942
+			for(i=0; i<mct->n; i++)
943
+				if (( mct->match[i].type==MATCH_STR &&
944
+						mct->match[i].l.s.len==s.len &&
945
+						memcmp(mct->match[i].l.s.s, s.s, s.len) == 0 ) ||
946
+					 ( mct->match[i].type==MATCH_RE &&
947
+					  regexec(mct->match[i].l.regex, s.s, 0, 0, 0) == 0)
948
+					){
949
+					if (likely(mct->jump[i])){
950
+						ret=run_actions(h, mct->jump[i], msg);
951
+						h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
952
+													   returns passthrough */
953
+					}
954
+					goto match_cleanup;
955
+				}
956
+match_cond_def:
957
+			if (mct->def){
958
+				ret=run_actions(h, mct->def, msg);
959
+				h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
960
+											   returns passthrough */
961
+			}
962
+match_cleanup:
963
+			if (rv1){
964
+				rval_destroy(rv1);
965
+				rval_destroy(rv);
966
+				rval_cache_clean(&c1);
967
+			}else if (rv){
968
+				rval_destroy(rv);
969
+				rval_cache_clean(&c1);
970
+			}
971
+			break;
910 972
 		case WHILE_T:
911 973
 			i=0;
912 974
 			flags=0;
... ...
@@ -71,7 +71,7 @@ enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
71 71
 		SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T,
72 72
 		SET_PORT_T, SET_URI_T, SET_HOSTPORTTRANS_T,
73 73
 		IF_T, SWITCH_T /* only until fixup*/,
74
-		BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T, WHILE_T,
74
+		BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T, MATCH_COND_T, WHILE_T,
75 75
 		MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T,
76 76
 		SETFLAG_T, RESETFLAG_T, ISFLAGSET_T ,
77 77
 		AVPFLAG_OPER_T,
... ...
@@ -99,7 +99,7 @@ enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST,
99 99
 		SELECT_ST, PVAR_ST,
100 100
 		LVAL_ST,  RVE_ST,
101 101
 		RETCODE_ST, CASE_ST,
102
-		BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST
102
+		BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST, MATCH_CONDTABLE_ST
103 103
 };
104 104
 
105 105
 /* run flags */
... ...
@@ -27,15 +27,24 @@
27 27
 #ifndef __switch_h
28 28
 #define __switch_h
29 29
 
30
+#include <regex.h>
31
+
30 32
 #include "route_struct.h"
31 33
 
34
+
32 35
 struct case_stms{
33 36
 	struct rval_expr* ct_rve;
34 37
 	struct action* actions;
35 38
 	struct case_stms* next;
36 39
 	struct case_stms** append;
37
-	int int_label;
40
+	int type;     /**< type: MATCH_UNKOWN, MATCH_INT, MATCH_STR, MATCH_RE */
41
+	int re_flags; /**< used only for REs */
38 42
 	int is_default;
43
+	union {
44
+		int match_int;
45
+		str match_str;
46
+		regex_t* match_re;
47
+	} label;  /**< fixed case argument */
39 48
 };
40 49
 
41 50
 
... ...
@@ -43,7 +52,7 @@ struct switch_cond_table{
43 43
 	int n;                  /**< size */
44 44
 	int* cond;              /**< int labels array */
45 45
 	struct action** jump;   /**< jump points array */
46
-	struct action* def; /**< default jump  */
46
+	struct action* def;     /**< default jump  */
47 47
 };
48 48
 
49 49
 
... ...
@@ -54,6 +63,25 @@ struct switch_jmp_table{
54 54
 	struct switch_cond_table rest; /**< normal cond. table for the rest */
55 55
 };
56 56
 
57
+
58
+enum match_str_type { MATCH_UNKNOWN, MATCH_INT, MATCH_STR, MATCH_RE };
59
+
60
+struct match_str{
61
+	enum match_str_type type;/**< string or RE */
62
+	int flags;               /**< flags for re */
63
+	union{
64
+		str s;              /* string */
65
+		regex_t* regex;     /**< compiled regex */
66
+	}l;
67
+};
68
+
69
+struct match_cond_table{
70
+	int n;                   /**< size */
71
+	struct match_str* match; /**< match array */
72
+	struct action** jump;    /**< jump points array */
73
+	struct action* def;      /**< default jmp */
74
+};
75
+
57 76
 int fix_switch(struct action* t);
58 77
 
59 78
 #endif /*__switch_h*/