Browse code

Merge commit 'origin/andrei/switch'

* commit 'origin/andrei/switch':
script parsing: string switch support
script engine: string switch optimization and fixup
script engine: string switch execution
rvalues: fix rval_new( empty string )
core: sint2str check for space before adding the sign

Andrei Pelinescu-Onciul authored on 20/02/2009 17:20:20
Showing 7 changed files
... ...
@@ -117,6 +117,11 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
117 117
 	struct switch_cond_table* sct;
118 118
 	struct switch_jmp_table*  sjt;
119 119
 	struct rval_expr* rve;
120
+	struct match_cond_table* mct;
121
+	struct rvalue* rv;
122
+	struct rvalue* rv1;
123
+	struct rval_cache c1;
124
+	str s;
120 125
 
121 126
 
122 127
 	/* reset the value of error to E_UNSPEC so avoid unknowledgable
... ...
@@ -908,6 +913,68 @@ sw_jt_def:
908 913
 											   returns passthrough */
909 914
 			}
910 915
 			break;
916
+		case MATCH_COND_T:
917
+			mct=(struct match_cond_table*)a->val[1].u.data;
918
+			rval_cache_init(&c1);
919
+			rv=0;
920
+			rv1=0;
921
+			ret=rval_expr_eval_rvint(h, msg, &rv, &v, 
922
+									(struct rval_expr*)a->val[0].u.data, &c1);
923
+									
924
+			if (unlikely( ret<0)){
925
+				/* handle error in expression => use default */
926
+				ret=-1;
927
+				goto match_cond_def;
928
+			}
929
+			if (h->run_flags & EXIT_R_F){
930
+				ret=0;
931
+				break;
932
+			}
933
+			h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return & break
934
+													    in expr */
935
+			if (likely(rv)){
936
+				rv1=rval_convert(h, msg, RV_STR, rv, &c1);
937
+				if (unlikely(rv1==0)){
938
+					ret=-1;
939
+					goto match_cond_def;
940
+				}
941
+				s=rv1->v.s;
942
+			}else{
943
+				/* int result in v */
944
+				rval_cache_clean(&c1);
945
+				s.s=sint2str(v, &s.len);
946
+			}
947
+			ret=1; /* default is continue */
948
+			for(i=0; i<mct->n; i++)
949
+				if (( mct->match[i].type==MATCH_STR &&
950
+						mct->match[i].l.s.len==s.len &&
951
+						memcmp(mct->match[i].l.s.s, s.s, s.len) == 0 ) ||
952
+					 ( mct->match[i].type==MATCH_RE &&
953
+					  regexec(mct->match[i].l.regex, s.s, 0, 0, 0) == 0)
954
+					){
955
+					if (likely(mct->jump[i])){
956
+						ret=run_actions(h, mct->jump[i], msg);
957
+						h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
958
+													   returns passthrough */
959
+					}
960
+					goto match_cleanup;
961
+				}
962
+match_cond_def:
963
+			if (mct->def){
964
+				ret=run_actions(h, mct->def, msg);
965
+				h->run_flags &= ~BREAK_R_F; /* catch breaks, but let
966
+											   returns passthrough */
967
+			}
968
+match_cleanup:
969
+			if (rv1){
970
+				rval_destroy(rv1);
971
+				rval_destroy(rv);
972
+				rval_cache_clean(&c1);
973
+			}else if (rv){
974
+				rval_destroy(rv);
975
+				rval_cache_clean(&c1);
976
+			}
977
+			break;
911 978
 		case WHILE_T:
912 979
 			i=0;
913 980
 			flags=0;
... ...
@@ -216,7 +216,11 @@ static struct socket_id* mk_listen_id2(struct name_lst*, int, int);
216 216
 static void free_name_lst(struct name_lst* lst);
217 217
 static void free_socket_id_lst(struct socket_id* i);
218 218
 
219
-static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a);
219
+static struct case_stms* mk_case_stm(struct rval_expr* ct, int is_re, 
220
+									struct action* a, int* err);
221
+static int case_check_type(struct case_stms* stms);
222
+static int case_check_default(struct case_stms* stms);
223
+
220 224
 
221 225
 %}
222 226
 
... ...
@@ -1805,10 +1809,12 @@ ct_rval: rval_expr {
1805 1809
 			$$=0;
1806 1810
 			if (!rve_is_constant($1)){
1807 1811
 				yyerror("constant expected");
1808
-			}else if (!rve_check_type((enum rval_type*)&i_tmp, $1, 0, 0 ,0)){
1812
+			/*
1813
+			} else if (!rve_check_type((enum rval_type*)&i_tmp, $1, 0, 0 ,0)){
1809 1814
 				yyerror("invalid expression (bad type)");
1810 1815
 			}else if (i_tmp!=RV_INT){
1811 1816
 				yyerror("invalid expression type, int expected\n");
1817
+			*/
1812 1818
 			}else
1813 1819
 				$$=$1;
1814 1820
 		}
... ...
@@ -1817,28 +1823,38 @@ single_case:
1817 1823
 	CASE ct_rval COLON actions {
1818 1824
 		$$=0;
1819 1825
 		if ($2==0) yyerror ("bad case label");
1820
-		else if (($$=mk_case_stm($2, $4))==0){
1821
-				yyerror("internal error: memory allocation failure");
1826
+		else if ((($$=mk_case_stm($2, 0, $4, &i_tmp))==0) && (i_tmp==-10)){
1827
+				YYABORT;
1828
+		}
1829
+	}
1830
+| CASE SLASH ct_rval COLON actions {
1831
+		$$=0;
1832
+		if ($3==0) yyerror ("bad case label");
1833
+		else if ((($$=mk_case_stm($3, 1, $5, &i_tmp))==0) && (i_tmp==-10)){
1822 1834
 				YYABORT;
1823 1835
 		}
1824 1836
 	}
1825 1837
 	| CASE ct_rval COLON {
1826 1838
 		$$=0;
1827 1839
 		if ($2==0) yyerror ("bad case label");
1828
-		else if (($$=mk_case_stm($2, 0))==0){
1829
-				yyerror("internal error: memory allocation failure");
1840
+		else if ((($$=mk_case_stm($2, 0, 0, &i_tmp))==0) && (i_tmp==-10)){
1841
+				YYABORT;
1842
+		}
1843
+	}
1844
+	| CASE SLASH ct_rval COLON {
1845
+		$$=0;
1846
+		if ($3==0) yyerror ("bad case label");
1847
+		else if ((($$=mk_case_stm($3, 1, 0, &i_tmp))==0) && (i_tmp==-10)){
1830 1848
 				YYABORT;
1831 1849
 		}
1832 1850
 	}
1833 1851
 	| DEFAULT COLON actions {
1834
-		if (($$=mk_case_stm(0, $3))==0){
1835
-				yyerror("internal error: memory allocation failure");
1852
+		if ((($$=mk_case_stm(0, 0, $3, &i_tmp))==0) && (i_tmp=-10)){
1836 1853
 				YYABORT;
1837 1854
 		}
1838 1855
 	}
1839 1856
 	| DEFAULT COLON {
1840
-		if (($$=mk_case_stm(0, 0))==0){
1841
-				yyerror("internal error: memory allocation failure");
1857
+		if ((($$=mk_case_stm(0, 0, 0, &i_tmp))==0) && (i_tmp==-10)){
1842 1858
 				YYABORT;
1843 1859
 		}
1844 1860
 	}
... ...
@@ -1866,6 +1882,12 @@ switch_cmd:
1866 1882
 		$$=0;
1867 1883
 		if ($2==0) yyerror("bad expression in switch(...)");
1868 1884
 		else if ($4==0) yyerror ("bad switch body");
1885
+		else if (case_check_default($4)!=0)
1886
+			yyerror_at(&$2->fpos, "bad switch(): too many "
1887
+							"\"default:\" labels\n");
1888
+		else if (case_check_type($4)!=0)
1889
+			yyerror_at(&$2->fpos, "bad switch(): mixed integer and"
1890
+							" string/RE cases not allowed\n");
1869 1891
 		else{
1870 1892
 			$$=mk_action(SWITCH_T, 2, RVE_ST, $2, CASE_ST, $4);
1871 1893
 			if ($$==0) {
... ...
@@ -2926,15 +2948,52 @@ static void free_socket_id_lst(struct socket_id* lst)
2926 2948
 }
2927 2949
 
2928 2950
 
2929
-static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a)
2951
+/** create a temporary case statmenet structure.
2952
+ *  *err will be filled in case of error (return == 0):
2953
+ *   -1 - non constant expression
2954
+ *   -2 - expression error (bad type)
2955
+ *   -10 - memory allocation error
2956
+ */
2957
+static struct case_stms* mk_case_stm(struct rval_expr* ct, int is_re,
2958
+											struct action* a, int* err)
2930 2959
 {
2931 2960
 	struct case_stms* s;
2961
+	struct rval_expr* bad_rve;
2962
+	enum rval_type type, bad_t, exp_t;
2963
+	enum match_str_type t;
2964
+	
2965
+	t=MATCH_UNKNOWN;
2966
+	if (ct){
2967
+		/* if ct!=0 => case, else if ct==0 is a default */
2968
+		if (!rve_is_constant(ct)){
2969
+			yyerror_at(&ct->fpos, "non constant expression in case");
2970
+			*err=-1;
2971
+			return 0;
2972
+		}
2973
+		if (rve_check_type(&type, ct, &bad_rve, &bad_t, &exp_t)!=1){
2974
+			yyerror_at(&ct->fpos, "bad expression: type mismatch:"
2975
+							" %s instead of %s at (%d,%d)",
2976
+							rval_type_name(bad_t), rval_type_name(exp_t),
2977
+							bad_rve->fpos.s_line, bad_rve->fpos.s_col);
2978
+			*err=-2;
2979
+			return 0;
2980
+		}
2981
+		if (is_re)
2982
+			t=MATCH_RE;
2983
+		else if (type==RV_STR)
2984
+			t=MATCH_STR;
2985
+		else
2986
+			t=MATCH_INT;
2987
+	}
2988
+
2932 2989
 	s=pkg_malloc(sizeof(*s));
2933 2990
 	if (s==0) {
2934
-		LOG(L_CRIT,"ERROR: cfg. parser: out of memory.\n");
2991
+		yyerror("internal error: memory allocation failure");
2992
+		*err=-10;
2935 2993
 	} else {
2936 2994
 		memset(s, 0, sizeof(*s));
2937 2995
 		s->ct_rve=ct;
2996
+		s->type=t;
2938 2997
 		s->actions=a;
2939 2998
 		s->next=0;
2940 2999
 		s->append=0;
... ...
@@ -2942,6 +3001,47 @@ static struct case_stms* mk_case_stm(struct rval_expr* ct, struct action* a)
2942 3001
 	return s;
2943 3002
 }
2944 3003
 
3004
+
3005
+/*
3006
+ * @return 0 on success, -1 on error.
3007
+ */
3008
+static int case_check_type(struct case_stms* stms)
3009
+{
3010
+	struct case_stms* c;
3011
+	struct case_stms* s;
3012
+	
3013
+	for(c=stms; c ; c=c->next){
3014
+		if (!c->ct_rve) continue;
3015
+		for (s=c->next; s; s=s->next){
3016
+			if (!s->ct_rve) continue;
3017
+			if ((s->type!=c->type) &&
3018
+				!(	(c->type==MATCH_STR || c->type==MATCH_RE) &&
3019
+					(s->type==MATCH_STR || s->type==MATCH_RE) ) ){
3020
+					yyerror_at(&s->ct_rve->fpos, "type mismatch in case");
3021
+					return -1;
3022
+			}
3023
+		}
3024
+	}
3025
+	return 0;
3026
+}
3027
+
3028
+
3029
+/*
3030
+ * @return 0 on success, -1 on error.
3031
+ */
3032
+static int case_check_default(struct case_stms* stms)
3033
+{
3034
+	struct case_stms* c;
3035
+	int default_no;
3036
+	
3037
+	default_no=0;
3038
+	for(c=stms; c ; c=c->next)
3039
+		if (c->ct_rve==0) default_no++;
3040
+	return (default_no<=1)?0:-1;
3041
+}
3042
+
3043
+
3044
+
2945 3045
 /*
2946 3046
 int main(int argc, char ** argv)
2947 3047
 {
... ...
@@ -72,7 +72,7 @@ enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
72 72
 		SET_HOST_T, SET_HOSTPORT_T, SET_USER_T, SET_USERPASS_T,
73 73
 		SET_PORT_T, SET_URI_T, SET_HOSTPORTTRANS_T,
74 74
 		IF_T, SWITCH_T /* only until fixup*/,
75
-		BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T, WHILE_T,
75
+		BLOCK_T, EVAL_T, SWITCH_JT_T, SWITCH_COND_T, MATCH_COND_T, WHILE_T,
76 76
 		MODULE_T, MODULE3_T, MODULE4_T, MODULE5_T, MODULE6_T, MODULEX_T,
77 77
 		SETFLAG_T, RESETFLAG_T, ISFLAGSET_T ,
78 78
 		AVPFLAG_OPER_T,
... ...
@@ -101,7 +101,7 @@ enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST,
101 101
 		SELECT_ST, PVAR_ST,
102 102
 		LVAL_ST,  RVE_ST,
103 103
 		RETCODE_ST, CASE_ST,
104
-		BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST
104
+		BLOCK_ST, JUMPTABLE_ST, CONDTABLE_ST, MATCH_CONDTABLE_ST
105 105
 };
106 106
 
107 107
 /* run flags */
... ...
@@ -233,13 +233,17 @@ struct rvalue* rval_new(enum rval_type t, union rval_val* v, int extra_size)
233 233
 {
234 234
 	struct rvalue* rv;
235 235
 	
236
-	if (t==RV_STR && v && v->s.len)
236
+	if (t==RV_STR && v && v->s.s)
237 237
 		return rval_new_str(&v->s, extra_size);
238 238
 	rv=rval_new_empty(extra_size);
239 239
 	if (likely(rv)){
240 240
 		rv->type=t;
241
-		if (likely(v)){
241
+		if (likely(v && t!=RV_STR)){
242 242
 			rv->v=*v;
243
+		}else if (t==RV_STR){
244
+			rv->v.s.s=&rv->buf[0];
245
+			rv->v.s.len=0;
246
+			if (likely(extra_size)) rv->v.s.s[0]=0;
243 247
 		}else
244 248
 			memset (&rv->v, 0, sizeof(rv->v));
245 249
 	}
... ...
@@ -22,6 +22,7 @@
22 22
  * History:
23 23
  * --------
24 24
  *  2009-02-02  initial version (andrei)
25
+ *  2009-02-19  string and RE switch support added (andrei)
25 26
 */
26 27
 
27 28
 #include "switch.h"
... ...
@@ -84,6 +85,32 @@ static struct switch_jmp_table* mk_switch_jmp_table(int jmp_size, int rest)
84 85
 
85 86
 
86 87
 
88
+/** create a match cond table structure (pkg_malloc'ed).
89
+ * @return 0 on error, pointer on success
90
+ */
91
+static struct match_cond_table* mk_match_cond_table(int n)
92
+{
93
+	struct match_cond_table* mct;
94
+	
95
+	/* allocate everything in a single block, better for cache locality */
96
+	mct=pkg_malloc(ROUND_POINTER(sizeof(*mct))+
97
+					ROUND_POINTER(n*sizeof(mct->match[0]))+
98
+					n*sizeof(mct->jump[0]));
99
+	if (mct==0) return 0;
100
+	mct->n=n;
101
+	mct->match=(struct match_str*)((char*)mct+ROUND_POINTER(sizeof(*mct)));
102
+	mct->jump=(struct action**)
103
+				((char*)mct->match+ROUND_POINTER(n*sizeof(mct->match[0])));
104
+	mct->def=0;
105
+	return mct;
106
+}
107
+
108
+
109
+
110
+static int fix_match(struct action* t);
111
+
112
+
113
+
87 114
 void destroy_case_stms(struct case_stms *lst)
88 115
 {
89 116
 	struct case_stms* l;
... ...
@@ -138,6 +165,11 @@ int fix_switch(struct action* t)
138 165
 	def_jmp_bm=0;
139 166
 	labels_no=0;
140 167
 	default_found=0;
168
+	/* check if string switch (first case is string or RE) */
169
+	for (c=(struct case_stms*)t->val[1].u.data; c && c->is_default; c=c->next);
170
+	if (c && (c->type==MATCH_STR || c->type==MATCH_RE))
171
+		return fix_match(t);
172
+	
141 173
 	sw_rve=(struct rval_expr*)t->val[0].u.data;
142 174
 	/*  handle null actions: optimize away if no
143 175
 	   sideffects */
... ...
@@ -159,12 +191,17 @@ int fix_switch(struct action* t)
159 191
 	n=0;
160 192
 	for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
161 193
 		if (c->ct_rve){
194
+			if (c->type!=MATCH_INT){
195
+				LOG(L_ERR, "ERROR: fix_switch: wrong case type %d (int"
196
+							"expected)\n", c->type);
197
+				return E_UNSPEC;
198
+			}
162 199
 			if (!rve_is_constant(c->ct_rve)){
163 200
 				LOG(L_ERR, "ERROR: fix_switch: non constant "
164 201
 						"expression in case\n");
165 202
 				return E_BUG;
166 203
 			}
167
-			if (rval_expr_eval_int(0, 0,  &c->int_label, c->ct_rve)
204
+			if (rval_expr_eval_int(0, 0,  &c->label.match_int, c->ct_rve)
168 205
 					<0){
169 206
 				LOG(L_ERR, "ERROR: fix_switch: case expression"
170 207
 						" (%d,%d) has non-interger type\n",
... ...
@@ -183,7 +220,7 @@ int fix_switch(struct action* t)
183 220
 				return E_UNSPEC;
184 221
 			}
185 222
 			default_found=1;
186
-			c->int_label=-1;
223
+			c->label.match_int=-1;
187 224
 			c->is_default=1;
188 225
 			def_a=c->actions;
189 226
 		}
... ...
@@ -241,14 +278,14 @@ int fix_switch(struct action* t)
241 278
 			def_jmp_bm=tail;
242 279
 		} else {
243 280
 			for (j=0; j<n; j++){
244
-				if (cond[j]==c->int_label){
281
+				if (cond[j]==c->label.match_int){
245 282
 					LOG(L_ERR, "ERROR: fix_switch: duplicate case (%d,%d)\n",
246 283
 							c->ct_rve->fpos.s_line, c->ct_rve->fpos.s_col);
247 284
 					ret=E_UNSPEC;
248 285
 					goto error;
249 286
 				}
250 287
 			}
251
-			cond[n]=c->int_label;
288
+			cond[n]=c->label.match_int;
252 289
 			jmp_bm[n]=tail;
253 290
 			n++;
254 291
 		}
... ...
@@ -371,4 +408,300 @@ error:
371 408
 	return ret;
372 409
 }
373 410
 
411
+
412
+
413
+/** fixup function for MATCH_T actions.
414
+ * can produce 3 different action types:
415
+ *  - BLOCK_T (actions) - actions grouped in a block, break ends the block
416
+ *    execution.
417
+ *  - EVAL_T (cond)  - null switch block, but the condition has to be
418
+ *                       evaluated due to possible side-effects.
419
+ *  - MATCH_COND_T(cond, jumps) - condition table
420
+ */
421
+static int fix_match(struct action* t)
422
+{
423
+	struct case_stms* c;
424
+	int n, i, j, ret;
425
+	struct action* a;
426
+	struct action* block;
427
+	struct action* def_a;
428
+	struct action* action_lst;
429
+	struct action** tail;
430
+	struct match_cond_table* mct;
431
+	int labels_no;
432
+	struct action** def_jmp_bm;
433
+	struct match_str* match;
434
+	struct action*** jmp_bm;
435
+	int default_found;
436
+	struct rval_expr* m_rve;
437
+	struct rvalue* rv;
438
+	regex_t* regex;
439
+	str s;
440
+	
441
+	ret=E_BUG;
442
+	match=0;
443
+	jmp_bm=0;
444
+	def_jmp_bm=0;
445
+	labels_no=0;
446
+	default_found=0;
447
+	rv=0;
448
+	s.s=0;
449
+	s.len=0;
450
+	m_rve=(struct rval_expr*)t->val[0].u.data;
451
+	/*  handle null actions: optimize away if no
452
+	   sideffects */
453
+	if (t->val[1].u.data==0){
454
+		if (!rve_has_side_effects(m_rve)){
455
+			t->type=BLOCK_T;
456
+			rve_destroy(m_rve);
457
+			t->val[0].type=BLOCK_ST;
458
+			t->val[0].u.data=0;
459
+			DBG("MATCH: null switch optimized away\n");
460
+		}else{
461
+			t->type=EVAL_T;
462
+			t->val[0].type=RVE_ST;
463
+			DBG("MATCH: null switch turned to EVAL_T\n");
464
+		}
465
+		return 0;
466
+	}
467
+	def_a=0;
468
+	n=0;
469
+	for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
470
+		if (c->ct_rve){
471
+			if (c->type!=MATCH_STR && c->type!=MATCH_RE){
472
+				LOG(L_ERR, "ERROR: fix_match: wrong case type %d (string"
473
+							"or RE expected)\n", c->type);
474
+				return E_UNSPEC;
475
+			}
476
+			if (!rve_is_constant(c->ct_rve)){
477
+				LOG(L_ERR, "ERROR: fix_match: non constant "
478
+						"expression in case\n");
479
+				ret=E_BUG;
480
+				goto error;
481
+			}
482
+			if ((rv=rval_expr_eval(0, 0, c->ct_rve)) == 0 ){
483
+				LOG(L_ERR, "ERROR: fix_match: bad case expression"
484
+						" (%d,%d)\n",
485
+						c->ct_rve->fpos.s_line,
486
+						c->ct_rve->fpos.s_col);
487
+				ret=E_BUG;
488
+				goto error;
489
+			}
490
+			if (rval_get_str(0, 0, &s, rv, 0)<0){
491
+				LOG(L_ERR, "ERROR: fix_match (%d,%d): out of memory?\n",
492
+						c->ct_rve->fpos.s_line,
493
+						c->ct_rve->fpos.s_col);
494
+				ret=E_BUG;
495
+				goto error;
496
+			}
497
+			if (c->type==MATCH_RE){
498
+				if ((regex=pkg_malloc(sizeof(regex_t))) == 0){
499
+					LOG(L_ERR, "ERROR: fix_match: out of memory\n");
500
+					ret=E_OUT_OF_MEM;
501
+					goto error;
502
+				}
503
+				if (regcomp(regex, s.s, 
504
+							REG_EXTENDED | REG_NOSUB | c->re_flags) !=0){
505
+					pkg_free(regex);
506
+					regex=0;
507
+					LOG(L_ERR, "ERROR: fix_match (%d, %d): bad regular"
508
+								" expression %.*s\n",
509
+							c->ct_rve->fpos.s_line,
510
+							c->ct_rve->fpos.s_col,
511
+							s.len, ZSW(s.s));
512
+					ret=E_UNSPEC;
513
+					goto error;
514
+				}
515
+				c->label.match_re=regex;
516
+				regex=0;
517
+			}else if (c->type==MATCH_STR){
518
+				c->label.match_str=s;
519
+				s.s=0;
520
+				s.len=0;
521
+			}else{
522
+				LOG(L_CRIT, "BUG: fix_match (%d,%d): wrong case type %d\n",
523
+						c->ct_rve->fpos.s_line, c->ct_rve->fpos.s_col,
524
+						c->type);
525
+				ret=E_BUG;
526
+				goto error;
527
+			}
528
+			c->is_default=0;
529
+			n++; /* count only non-default cases */
530
+			/* cleanup */
531
+			rval_destroy(rv);
532
+			rv=0;
533
+			if (s.s){
534
+				pkg_free(s.s);
535
+				s.s=0;
536
+				s.len=0;
537
+			}
538
+		}else{
539
+			if (default_found){
540
+				LOG(L_ERR, "ERROR: fix_match: more then one \"default\""
541
+						" label found (%d, %d)\n",
542
+						c->ct_rve->fpos.s_line,
543
+						c->ct_rve->fpos.s_col);
544
+				ret=E_UNSPEC;
545
+				goto error;
546
+			}
547
+			default_found=1;
548
+			c->is_default=1;
549
+			def_a=c->actions;
550
+		}
551
+		if ( c->actions && ((ret=fix_actions(c->actions))<0))
552
+			goto error;
553
+	}
554
+	DBG("MATCH: %d cases, %d default\n", n, default_found);
555
+	/*: handle n==0 (no case only a default:) */
556
+	if (n==0){
557
+		if (default_found){
558
+			if (!rve_has_side_effects(m_rve)){
559
+				t->type=BLOCK_T;
560
+				rve_destroy(m_rve);
561
+				destroy_case_stms(t->val[1].u.data);
562
+				t->val[0].type=BLOCK_ST;
563
+				t->val[0].u.data=def_a;
564
+				t->val[1].type=0;
565
+				t->val[1].u.data=0;
566
+				DBG("MATCH: default only switch optimized away (BLOCK_T)\n");
567
+				return 0;
568
+			}
569
+			DBG("MATCH: default only switch with side-effect...\n");
570
+		}else{
571
+			LOG(L_CRIT, "BUG: fix_match: empty switch not expected at this"
572
+					" point\n");
573
+			ret=E_BUG;
574
+			goto error;
575
+		}
576
+	}
577
+	labels_no=n;
578
+	match=pkg_malloc(sizeof(match[0])*n);
579
+	jmp_bm=pkg_malloc(sizeof(jmp_bm[0])*n);
580
+	if (match==0 || jmp_bm==0){
581
+		LOG(L_ERR, "ERROR: fix_match: memory allocation failure\n");
582
+		ret=E_OUT_OF_MEM;
583
+		goto error;
584
+	}
585
+	
586
+	/* fill condition table and jump point bookmarks and "flatten" the action 
587
+	   lists (transform them into a single list for the entire switch, rather
588
+	    then one block per case ) */
589
+	n=0;
590
+	action_lst=0;
591
+	tail=&action_lst;
592
+	for (c=(struct case_stms*)t->val[1].u.data; c; c=c->next){
593
+		a=c->actions;
594
+		if (a){
595
+			for (; a->next; a=a->next);
596
+			if (action_lst==0)
597
+				action_lst=c->actions;
598
+			else
599
+				*tail=c->actions;
600
+		}
601
+		if (c->is_default){
602
+			def_jmp_bm=tail;
603
+		} else{
604
+			match[n].type=c->type;
605
+			if (match[n].type == MATCH_STR){
606
+				for (j=0; j<n; j++){
607
+					if ( match[j].type == c->type &&
608
+						 match[j].l.s.len ==  c->label.match_str.len &&
609
+						 memcmp(match[j].l.s.s, c->label.match_str.s,
610
+							 		match[j].l.s.len) == 0 ){
611
+						LOG(L_ERR, "ERROR: fix_match: duplicate case"
612
+								" (%d,%d)\n", c->ct_rve->fpos.s_line,
613
+								c->ct_rve->fpos.s_col);
614
+						ret=E_UNSPEC;
615
+						goto error;
616
+					}
617
+				}
618
+				match[n].flags=0;
619
+				match[n].l.s=c->label.match_str;
620
+				c->label.match_str.s=0; /* prevent s being freed */
621
+				c->label.match_str.len=0;
622
+			} else {
623
+				match[n].flags=c->re_flags | REG_EXTENDED | REG_NOSUB;
624
+				match[n].l.regex=c->label.match_re;
625
+				c->label.match_re=0;
626
+			}
627
+			jmp_bm[n]=tail;
628
+			n++;
629
+		}
630
+		if (c->actions)
631
+			tail=&a->next;
632
+	}
633
+	/* handle constant rve w/ no side-effects: replace the whole case 
634
+	   with the case rve block */
635
+	if ( (scr_opt_lev>=2) &&
636
+			!rve_has_side_effects(m_rve) && rve_is_constant(m_rve)){
637
+		if ((rv=rval_expr_eval(0, 0, m_rve)) == 0){
638
+			LOG(L_ERR, "ERROR: fix_match: bad expression (%d,%d)\n", 
639
+					m_rve->fpos.s_line, m_rve->fpos.s_col);
640
+			ret=E_UNSPEC;
641
+			goto error;
642
+		}
643
+		if (rval_get_str(0, 0, &s, rv, 0) < 0 ){
644
+				LOG(L_ERR, "ERROR: fix_match (%d,%d): bad string expression\n",
645
+						m_rve->fpos.s_line,
646
+						m_rve->fpos.s_col);
647
+			ret=E_UNSPEC;
648
+			goto error;
649
+		}
650
+		/* start with the "default:" value in case nothing is found */
651
+		block=def_jmp_bm?*def_jmp_bm:0;
652
+		for (i=0; i<n; i++){
653
+			if (((match[i].type == MATCH_STR) && (match[i].l.s.len == s.len) &&
654
+					(memcmp(match[i].l.s.s, s.s, s.len) == 0)) ||
655
+				((match[i].type == MATCH_RE) && 
656
+					regexec(match[i].l.regex, s.s, 0, 0, 0) == 0) ) {
657
+				block=*jmp_bm[i];
658
+				break;
659
+			}
660
+		}
661
+		DBG("MATCH: constant switch(\"%.*s\") with %d cases optimized away"
662
+				" to case no. %d\n", s.len, ZSW(s.s), n, i);
663
+		/* cleanup */
664
+		rval_destroy(rv);
665
+		rv=0;
666
+		pkg_free(s.s);
667
+		s.s=0;
668
+		s.len=0;
669
+		ret=0;
670
+		/* replace with BLOCK_ST */
671
+		rve_destroy(m_rve);
672
+		destroy_case_stms(t->val[1].u.data);
673
+		t->type=BLOCK_T;
674
+		t->val[0].type=BLOCK_ST;
675
+		t->val[0].u.data=block;
676
+		t->val[1].type=0;
677
+		t->val[1].u.data=0;
678
+		goto end;
679
+	}
680
+	mct=mk_match_cond_table(n);
681
+	if (mct==0){
682
+		LOG(L_ERR, "ERROR: fix_match: memory allocation error\n");
683
+		ret=E_OUT_OF_MEM;
684
+		goto error;
685
+	}
686
+	mct->n=n;
687
+	for (i=0; i<n; i++){
688
+		mct->match[i]=match[i];
689
+		mct->jump[i]=*jmp_bm[i];
690
+	}
691
+	mct->def=def_jmp_bm?*def_jmp_bm:0;
692
+	t->type=MATCH_COND_T;
693
+	t->val[1].type=MATCH_CONDTABLE_ST;
694
+	t->val[1].u.data=mct;
695
+	DBG("MATCH: optimized to match condtable (%d) default: %s\n ",
696
+				mct->n, mct->def?"yes":"no");
697
+		ret=0;
698
+end:
699
+error:
700
+	if (match) pkg_free(match);
701
+	if (jmp_bm) pkg_free(jmp_bm);
702
+	/* cleanup rv & s*/
703
+	if (rv) rval_destroy(rv);
704
+	if (s.s) pkg_free(s.s);
705
+	return ret;
706
+}
374 707
 /* vi: set ts=4 sw=4 tw=79:ai:cindent: */
... ...
@@ -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*/
... ...
@@ -312,7 +312,7 @@ static inline char* sint2str(long l, int* len)
312 312
 		l = -l;
313 313
 	}
314 314
 	p = int2str((unsigned long)l, len);
315
-	if(sign) {
315
+	if(sign && *len<(INT2STR_MAX_LEN-1)) {
316 316
 		*(--p) = '-';
317 317
 		if (len) (*len)++;
318 318
 	}