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 912
 											   returns passthrough */
908 913
 			}
909 914
 			break;
915
+		case MATCH_COND_T:
916
+			mct=(struct match_cond_table*)a->val[1].u.data;
917
+			rval_cache_init(&c1);
918
+			rv=0;
919
+			rv1=0;
920
+			ret=rval_expr_eval_rvint(h, msg, &rv, &v, 
921
+									(struct rval_expr*)a->val[0].u.data, &c1);
922
+									
923
+			if (unlikely( ret<0)){
924
+				/* handle error in expression => use default */
925
+				ret=-1;
926
+				goto match_cond_def;
927
+			}
928
+			if (h->run_flags & EXIT_R_F){
929
+				ret=0;
930
+				break;
931
+			}
932
+			h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return & break
933
+													    in expr */
934
+			if (likely(rv)){
935
+				rv1=rval_convert(h, msg, RV_STR, rv, &c1);
936
+				if (unlikely(rv1==0)){
937
+					ret=-1;
938
+					goto match_cond_def;
939
+				}
940
+				s=rv1->v.s;
941
+			}else{
942
+				/* int result in v */
943
+				rval_cache_clean(&c1);
944
+				s.s=sint2str(v, &s.len);
945
+			}
946
+			ret=1; /* default is continue */
947
+			for(i=0; i<mct->n; i++)
948
+				if (( mct->match[i].type==MATCH_STR &&
949
+						mct->match[i].l.s.len==s.len &&
950
+						memcmp(mct->match[i].l.s.s, s.s, s.len) == 0 ) ||
951
+					 ( mct->match[i].type==MATCH_RE &&
952
+					  regexec(mct->match[i].l.regex, s.s, 0, 0, 0) == 0)
953
+					){
954
+					if (likely(mct->jump[i])){
955
+						ret=run_actions(h, mct->jump[i], msg);
956
+						h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
957
+													   returns passthrough */
958
+					}
959
+					goto match_cleanup;
960
+				}
961
+match_cond_def:
962
+			if (mct->def){
963
+				ret=run_actions(h, mct->def, msg);
964
+				h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
965
+											   returns passthrough */
966
+			}
967
+match_cleanup:
968
+			if (rv1){
969
+				rval_destroy(rv1);
970
+				rval_destroy(rv);
971
+				rval_cache_clean(&c1);
972
+			}else if (rv){
973
+				rval_destroy(rv);
974
+				rval_cache_clean(&c1);
975
+			}
976
+			break;
910 977
 		case WHILE_T:
911 978
 			i=0;
912 979
 			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 52
 	int n;                  /**< size */
44 53
 	int* cond;              /**< int labels array */
45 54
 	struct action** jump;   /**< jump points array */
46
-	struct action* def; /**< default jump  */
55
+	struct action* def;     /**< default jump  */
47 56
 };
48 57
 
49 58
 
... ...
@@ -54,6 +63,25 @@ struct switch_jmp_table{
54 63
 	struct switch_cond_table rest; /**< normal cond. table for the rest */
55 64
 };
56 65
 
66
+
67
+enum match_str_type { MATCH_UNKNOWN, MATCH_INT, MATCH_STR, MATCH_RE };
68
+
69
+struct match_str{
70
+	enum match_str_type type;/**< string or RE */
71
+	int flags;               /**< flags for re */
72
+	union{
73
+		str s;              /* string */
74
+		regex_t* regex;     /**< compiled regex */
75
+	}l;
76
+};
77
+
78
+struct match_cond_table{
79
+	int n;                   /**< size */
80
+	struct match_str* match; /**< match array */
81
+	struct action** jump;    /**< jump points array */
82
+	struct action* def;      /**< default jmp */
83
+};
84
+
57 85
 int fix_switch(struct action* t);
58 86
 
59 87
 #endif /*__switch_h*/