Browse code

core expr. eval: support for =~

The match regular expression operator (=~) is now supported in
rval_exprs.

Andrei Pelinescu-Onciul authored on 04/05/2009 19:09:23
Showing 3 changed files
... ...
@@ -1609,6 +1609,7 @@ rve_equalop:
1609 1609
 	| INTDIFF {$$=RVE_IDIFF_OP; }
1610 1610
 	| STREQ	{$$=RVE_STREQ_OP; }
1611 1611
 	| STRDIFF {$$=RVE_STRDIFF_OP; }
1612
+	| MATCH	{$$=RVE_MATCH_OP; }
1612 1613
 	;
1613 1614
 rve_cmpop:
1614 1615
 	  GT	{$$=RVE_GT_OP; }
... ...
@@ -71,17 +71,35 @@ inline static void rval_force_clean(struct rvalue* rv)
71 71
 		}
72 72
 		rv->flags&=~RV_CNT_ALLOCED_F;
73 73
 	}
74
+	if (rv->flags & RV_RE_ALLOCED_F){
75
+		if (rv->v.re.regex){
76
+			if (unlikely(rv->type!=RV_STR || !(rv->flags & RV_RE_F))){
77
+				BUG("RV_RE_ALLOCED_F not supported for type %d or "
78
+						"bad flags %x\n", rv->type, rv->flags);
79
+			}
80
+			regfree(rv->v.re.regex);
81
+			pkg_free(rv->v.re.regex);
82
+			rv->v.re.regex=0;
83
+		}
84
+		rv->flags&=~(RV_RE_ALLOCED_F|RV_RE_F);
85
+	}
74 86
 }
75 87
 
76 88
 
77 89
 
78 90
 /** frees a rval returned by rval_new(), rval_convert() or rval_expr_eval().
79
- *   Note: ir will be freed only when refcnt reaches 0
91
+ *   Note: it will be freed only when refcnt reaches 0
80 92
  */
81 93
 void rval_destroy(struct rvalue* rv)
82 94
 {
83 95
 	if (rv && rv_unref(rv)){
84 96
 		rval_force_clean(rv);
97
+		/* still an un-regfreed RE ? */
98
+		if ((rv->flags & RV_RE_F) && rv->v.re.regex){
99
+			if (unlikely(rv->type!=RV_STR))
100
+				BUG("RV_RE_F not supported for type %d\n", rv->type);
101
+			regfree(rv->v.re.regex);
102
+		}
85 103
 		if (rv->flags & RV_RV_ALLOCED_F){
86 104
 			pkg_free(rv);
87 105
 		}
... ...
@@ -138,7 +156,7 @@ void rval_cache_clean(struct rval_cache* rvc)
138 156
 }
139 157
 
140 158
 
141
-#define rv_chg_in_place(rv)  ((rv)->refcnt==1) 
159
+#define rv_chg_in_place(rv)  ((rv)->refcnt==1)
142 160
 
143 161
 
144 162
 
... ...
@@ -211,6 +229,46 @@ struct rvalue* rval_new_str(str* s, int extra_size)
211 229
 
212 230
 
213 231
 
232
+/** create a new pk_malloc'ed RE rv from a str re.
233
+  * It acts as rval_new_str, but also compiles a RE from the str
234
+  * and sets v->re.regex.
235
+  * @param s - pointer to str, must be non-null, zero-term'ed and a valid RE.
236
+  * @return new rv or 0 on error
237
+  */
238
+struct rvalue* rval_new_re(str* s)
239
+{
240
+	struct rvalue* rv;
241
+	long offs;
242
+	
243
+	offs=(long)&((struct rvalue*)0)->buf[0]; /* offset of the buf. member */
244
+	/* make sure we reserve enough space so that we can satisfy any regex_t
245
+	   alignment requirement (pointer) */
246
+	rv=rval_new_empty(ROUND_POINTER(offs)-offs+sizeof(*rv->v.re.regex)+
247
+						s->len+1/* 0 */);
248
+	if (likely(rv)){
249
+		rv->type=RV_STR;
250
+		/* make sure regex points to a properly aligned address
251
+		   (use max./pointer alignment to be sure ) */
252
+		rv->v.re.regex=(regex_t*)((char*)&rv->buf[0]+ROUND_POINTER(offs)-offs);
253
+		rv->v.s.s=(char*)rv->v.re.regex+sizeof(*rv->v.re.regex);
254
+		rv->v.s.len=s->len;
255
+		memcpy(rv->v.s.s, s->s, s->len);
256
+		rv->v.s.s[s->len]=0;
257
+		/* compile the regex */
258
+		/* same flags as for expr. =~ (fix_expr()) */
259
+		if (unlikely(regcomp(rv->v.re.regex, s->s,
260
+								REG_EXTENDED|REG_NOSUB|REG_ICASE))){
261
+			/* error */
262
+			pkg_free(rv);
263
+			rv=0;
264
+		}else /* success */
265
+			rv->flags|=RV_RE_F;
266
+	}
267
+	return rv;
268
+}
269
+
270
+
271
+
214 272
 /** get string name for a type.
215 273
   *
216 274
   * @return - null terminated name of the type
... ...
@@ -415,6 +473,7 @@ enum rval_type rve_guess_type( struct rval_expr* rve)
415 473
 		case RVE_IDIFF_OP:
416 474
 		case RVE_STREQ_OP:
417 475
 		case RVE_STRDIFF_OP:
476
+		case RVE_MATCH_OP:
418 477
 		case RVE_IPLUS_OP:
419 478
 		case RVE_STRLEN_OP:
420 479
 		case RVE_STREMPTY_OP:
... ...
@@ -479,6 +538,7 @@ int rve_is_constant(struct rval_expr* rve)
479 538
 		case RVE_IDIFF_OP:
480 539
 		case RVE_STREQ_OP:
481 540
 		case RVE_STRDIFF_OP:
541
+		case RVE_MATCH_OP:
482 542
 		case RVE_PLUS_OP:
483 543
 		case RVE_IPLUS_OP:
484 544
 		case RVE_CONCAT_OP:
... ...
@@ -535,6 +595,7 @@ static int rve_op_unary(enum rval_expr_op op)
535 595
 		case RVE_IDIFF_OP:
536 596
 		case RVE_STREQ_OP:
537 597
 		case RVE_STRDIFF_OP:
598
+		case RVE_MATCH_OP:
538 599
 		case RVE_PLUS_OP:
539 600
 		case RVE_IPLUS_OP:
540 601
 		case RVE_CONCAT_OP:
... ...
@@ -681,6 +742,7 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
681 742
 			break;
682 743
 		case RVE_STREQ_OP:
683 744
 		case RVE_STRDIFF_OP:
745
+		case RVE_MATCH_OP:
684 746
 			*type=RV_INT;
685 747
 			if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){
686 748
 				if (rve_check_type(&type2, rve->right.rve, bad_rve, bad_t,
... ...
@@ -1199,9 +1261,19 @@ inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2)
1199 1261
 
1200 1262
 
1201 1263
 
1202
-inline static int bool_strop2( enum rval_expr_op op, int* res,
1203
-								str* s1, str* s2)
1264
+/** internal helper: compare 2 RV_STR RVs.
1265
+  * Warning: rv1 & rv2 must be RV_STR
1266
+  * @return 0 on success, -1 on error
1267
+  */
1268
+inline static int bool_rvstrop2( enum rval_expr_op op, int* res,
1269
+								struct rvalue* rv1, struct rvalue* rv2)
1204 1270
 {
1271
+	str* s1;
1272
+	str* s2;
1273
+	regex_t tmp_re;
1274
+	
1275
+	s1=&rv1->v.s;
1276
+	s2=&rv2->v.s;
1205 1277
 	switch(op){
1206 1278
 		case RVE_EQ_OP:
1207 1279
 		case RVE_STREQ_OP:
... ...
@@ -1211,11 +1283,29 @@ inline static int bool_strop2( enum rval_expr_op op, int* res,
1211 1283
 		case RVE_STRDIFF_OP:
1212 1284
 			*res= (s1->len!=s2->len) || (memcmp(s1->s, s2->s, s1->len)!=0);
1213 1285
 			break;
1286
+		case RVE_MATCH_OP:
1287
+			if (likely(rv2->flags & RV_RE_F)){
1288
+				*res=(regexec(rv2->v.re.regex, rv1->v.s.s, 0, 0, 0)==0);
1289
+			}else{
1290
+				/* we need to compile the RE on the fly */
1291
+				if (unlikely(regcomp(&tmp_re, s2->s,
1292
+										REG_EXTENDED|REG_NOSUB|REG_ICASE))){
1293
+					/* error */
1294
+					ERR("Bad regular expression \"%s\"\n", s2->s);
1295
+					goto error;
1296
+				}
1297
+				*res=(regexec(&tmp_re, s1->s, 0, 0, 0)==0);
1298
+				regfree(&tmp_re);
1299
+			}
1300
+			break;
1214 1301
 		default:
1215 1302
 			BUG("rv unsupported intop %d\n", op);
1216
-			return -1;
1303
+			goto error;
1217 1304
 	}
1218 1305
 	return 0;
1306
+error:
1307
+	*res=0; /* false */
1308
+	return -1;
1219 1309
 }
1220 1310
 
1221 1311
 
... ...
@@ -1482,7 +1572,7 @@ inline static int rval_str_lop2(struct run_act_ctx* h,
1482 1572
 		goto error;
1483 1573
 	if ((rv2=rval_convert(h, msg, RV_STR, r, c2))==0)
1484 1574
 		goto error;
1485
-	ret=bool_strop2(op, res, &rv1->v.s, &rv2->v.s);
1575
+	ret=bool_rvstrop2(op, res, rv1, rv2);
1486 1576
 	rval_destroy(rv1); 
1487 1577
 	rval_destroy(rv2); 
1488 1578
 	return ret;
... ...
@@ -1791,6 +1881,7 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1791 1881
 			break;
1792 1882
 		case RVE_STREQ_OP:
1793 1883
 		case RVE_STRDIFF_OP:
1884
+		case RVE_MATCH_OP:
1794 1885
 			if (unlikely((rv1=rval_expr_eval(h, msg, rve->left.rve))==0)){
1795 1886
 				ret=-1;
1796 1887
 				break;
... ...
@@ -1889,6 +1980,7 @@ int rval_expr_eval_rvint(			   struct run_act_ctx* h,
1889 1980
 		case RVE_IPLUS_OP:
1890 1981
 		case RVE_STREQ_OP:
1891 1982
 		case RVE_STRDIFF_OP:
1983
+		case RVE_MATCH_OP:
1892 1984
 		case RVE_STRLEN_OP:
1893 1985
 		case RVE_STREMPTY_OP:
1894 1986
 		case RVE_DEFINED_OP:
... ...
@@ -1991,6 +2083,7 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
1991 2083
 		case RVE_IPLUS_OP:
1992 2084
 		case RVE_STREQ_OP:
1993 2085
 		case RVE_STRDIFF_OP:
2086
+		case RVE_MATCH_OP:
1994 2087
 		case RVE_STRLEN_OP:
1995 2088
 		case RVE_STREMPTY_OP:
1996 2089
 		case RVE_DEFINED_OP:
... ...
@@ -2247,6 +2340,7 @@ struct rval_expr* mk_rval_expr2(enum rval_expr_op op, struct rval_expr* rve1,
2247 2340
 		case RVE_IDIFF_OP:
2248 2341
 		case RVE_STREQ_OP:
2249 2342
 		case RVE_STRDIFF_OP:
2343
+		case RVE_MATCH_OP:
2250 2344
 		case RVE_CONCAT_OP:
2251 2345
 			break;
2252 2346
 		default:
... ...
@@ -2306,6 +2400,7 @@ static int rve_op_is_assoc(enum rval_expr_op op)
2306 2400
 		case RVE_IDIFF_OP:
2307 2401
 		case RVE_STREQ_OP:
2308 2402
 		case RVE_STRDIFF_OP:
2403
+		case RVE_MATCH_OP:
2309 2404
 			return 0;
2310 2405
 	}
2311 2406
 	return 0;
... ...
@@ -2351,6 +2446,7 @@ static int rve_op_is_commutative(enum rval_expr_op op)
2351 2446
 		case RVE_LT_OP:
2352 2447
 		case RVE_LTE_OP:
2353 2448
 		case RVE_CONCAT_OP:
2449
+		case RVE_MATCH_OP:
2354 2450
 			return 0;
2355 2451
 		case RVE_DIFF_OP:
2356 2452
 		case RVE_EQ_OP:
... ...
@@ -2461,6 +2557,41 @@ static int fix_rval(struct rvalue* rv)
2461 2557
 
2462 2558
 
2463 2559
 
2560
+/** helper function: replace a rve (in-place) with a constant rval_val.
2561
+ * WARNING: since it replaces in-place, one should make sure that if
2562
+ * rve is in fact a rval (rve->op==RVE_RVAL_OP), no reference is kept
2563
+ * to the rval!
2564
+ * @param rve - expression to be replaced (in-place)
2565
+ * @param v   - pointer to a rval_val union containing the replacement
2566
+ *              value.
2567
+ * @param flags - value flags (how it was alloc'ed, e.g.: RV_CNT_ALLOCED_F)
2568
+ * @return 0 on success, -1 on error */
2569
+static int rve_replace_with_val(struct rval_expr* rve, enum rval_type type,
2570
+								union rval_val* v, int flags)
2571
+{
2572
+	int refcnt;
2573
+	
2574
+	refcnt=1; /* replaced-in-place rval refcnt */
2575
+	if (rve->op!=RVE_RVAL_OP){
2576
+		rve_destroy(rve->left.rve);
2577
+		if (rve_op_unary(rve->op)==0)
2578
+			rve_destroy(rve->right.rve);
2579
+	}else{
2580
+		rval_destroy(&rve->left.rval);
2581
+	}
2582
+	rval_init(&rve->left.rval, type, v, flags);
2583
+	rve->left.rval.refcnt=refcnt;
2584
+	rval_init(&rve->right.rval, RV_NONE, 0, 0);
2585
+	rve->op=RVE_RVAL_OP;
2586
+	return 0;
2587
+}
2588
+
2589
+
2590
+
2591
+/** helper function: replace a rve (in-place) with a constant rvalue.
2592
+ * @param rve - expression to be replaced (in-place)
2593
+ * @param rv   - pointer to the replacement _constant_ rvalue structure
2594
+ * @return 0 on success, -1 on error */
2464 2595
 static int rve_replace_with_ct_rv(struct rval_expr* rve, struct rvalue* rv)
2465 2596
 {
2466 2597
 	enum rval_type type;
... ...
@@ -2481,21 +2612,89 @@ static int rve_replace_with_ct_rv(struct rval_expr* rve, struct rvalue* rv)
2481 2612
 			BUG("unexpected str evaluation failure\n");
2482 2613
 			return -1;
2483 2614
 		}
2484
-		flags=RV_CNT_ALLOCED_F;
2615
+		flags|=RV_CNT_ALLOCED_F;
2485 2616
 	}else{
2486 2617
 		BUG("unknown constant expression type %d\n", rv->type);
2487 2618
 		return -1;
2488 2619
 	}
2489
-	if (rve->op!=RVE_RVAL_OP){
2490
-		rve_destroy(rve->left.rve);
2491
-		if (rve_op_unary(rve->op)==0)
2492
-			rve_destroy(rve->right.rve);
2493
-	}else
2494
-		rval_destroy(&rve->left.rval);
2495
-	rval_init(&rve->left.rval, type, &v, flags);
2496
-	rval_init(&rve->right.rval, RV_NONE, 0, 0);
2497
-	rve->op=RVE_RVAL_OP;
2620
+	return rve_replace_with_val(rve, type, &v, flags);
2621
+}
2622
+
2623
+
2624
+
2625
+/** try to replace the right side of the rve with a compiled regex.
2626
+  * @return 0 on success and -1 on error.
2627
+ */
2628
+static int fix_match_rve(struct rval_expr* rve)
2629
+{
2630
+	struct rvalue* rv;
2631
+	regex_t* re;
2632
+	union rval_val v;
2633
+	int flags;
2634
+	int ret;
2635
+
2636
+	rv=0;
2637
+	v.s.s=0;
2638
+	v.re.regex=0;
2639
+	/* normal fix-up for the  left side */
2640
+	ret=fix_rval_expr((void**)&rve->left.rve);
2641
+	if (ret<0) return ret;
2642
+	
2643
+	/* fixup the right side (RE) */
2644
+	if (rve_is_constant(rve->right.rve)){
2645
+		if ((rve_guess_type(rve->right.rve)!=RV_STR)){
2646
+			ERR("fixup failure(%d,%d-%d,%d): left side of  =~ is not string"
2647
+					" (%d,%d)\n",   rve->fpos.s_line, rve->fpos.s_col,
2648
+									rve->fpos.e_line, rve->fpos.e_col,
2649
+									rve->right.rve->fpos.s_line,
2650
+									rve->right.rve->fpos.s_col);
2651
+			goto error;
2652
+		}
2653
+		if ((rv=rval_expr_eval(0, 0, rve->right.rve))==0){
2654
+			ERR("fixup failure(%d,%d-%d,%d):  bad RE expression\n",
2655
+					rve->right.rve->fpos.s_line, rve->right.rve->fpos.s_col,
2656
+					rve->right.rve->fpos.e_line, rve->right.rve->fpos.e_col);
2657
+			goto error;
2658
+		}
2659
+		if (rval_get_str(0, 0, &v.s, rv, 0)<0){
2660
+			BUG("fixup unexpected failure (%d,%d-%d,%d)\n",
2661
+					rve->fpos.s_line, rve->fpos.s_col,
2662
+					rve->fpos.e_line, rve->fpos.e_col);
2663
+			goto error;
2664
+		}
2665
+		/* we have the str, we don't need the rv anymore */
2666
+		rval_destroy(rv);
2667
+		rv=0;
2668
+		re=pkg_malloc(sizeof(*re));
2669
+		if (re==0){
2670
+			ERR("out of memory\n");
2671
+			goto error;
2672
+		}
2673
+		/* same flags as for expr. =~ (fix_expr()) */
2674
+		if (regcomp(re, v.s.s, REG_EXTENDED|REG_NOSUB|REG_ICASE)){
2675
+			pkg_free(re);
2676
+			ERR("Bad regular expression \"%s\"(%d,%d-%d,%d)\n", v.s.s,
2677
+					rve->right.rve->fpos.s_line, rve->right.rve->fpos.s_col,
2678
+					rve->right.rve->fpos.e_line, rve->right.rve->fpos.e_col);
2679
+			goto error;
2680
+		}
2681
+		v.re.regex=re;
2682
+		flags=RV_RE_F|RV_RE_ALLOCED_F|RV_CNT_ALLOCED_F;
2683
+		if (rve_replace_with_val(rve->right.rve, RV_STR, &v, flags)<0)
2684
+			goto error;
2685
+	}else{
2686
+		/* right side is not constant => normal fixup */
2687
+		return fix_rval_expr((void**)&rve->right.rve);
2688
+	}
2498 2689
 	return 0;
2690
+error:
2691
+	if (rv) rval_destroy(rv);
2692
+	if (v.s.s) pkg_free(v.s.s);
2693
+	if (v.re.regex){
2694
+		regfree(v.re.regex);
2695
+		pkg_free(v.re.regex);
2696
+	}
2697
+	return -1;
2499 2698
 }
2500 2699
 
2501 2700
 
... ...
@@ -3111,6 +3310,10 @@ int fix_rval_expr(void** p)
3111 3310
 			ret=fix_rval_expr((void**)&rve->right.rve);
3112 3311
 			if (ret<0) return ret;
3113 3312
 			break;
3313
+		case RVE_MATCH_OP:
3314
+			ret=fix_match_rve(rve);
3315
+			if (ret<0) return ret;
3316
+			break;
3114 3317
 		default:
3115 3318
 			BUG("unsupported op type %d\n", rve->op);
3116 3319
 	}
... ...
@@ -74,11 +74,17 @@ enum rval_expr_op{
74 74
 	RVE_STREMPTY_OP, /* one member, returns val=="" (bool) */
75 75
 	RVE_STREQ_OP,  /* 2 members, string == , returns left == right (bool)*/
76 76
 	RVE_STRDIFF_OP,/* 2 members, string != , returns left != right (bool)*/
77
+	RVE_MATCH_OP,  /* 2 members, string ~),  returns left matches re(right) */
77 78
 	/* avp, pvars a.s.o */
78 79
 	RVE_DEFINED_OP, /* one member, returns is_defined(val) (bool) */
79 80
 };
80 81
 
81 82
 
83
+struct str_re{
84
+	str s;
85
+	regex_t* regex;
86
+};
87
+
82 88
 union rval_val{
83 89
 	void* p;
84 90
 	long  l;
... ...
@@ -88,6 +94,7 @@ union rval_val{
88 94
 	pv_spec_t pvs;
89 95
 	struct action* action;
90 96
 	struct expr* bexpr;
97
+	struct str_re re;
91 98
 };
92 99
 
93 100
 
... ...
@@ -105,6 +112,8 @@ struct rvalue{
105 112
 #define RV_CNT_ALLOCED_F  1  /* free contents  (pkg mem allocated) */
106 113
 #define RV_RV_ALLOCED_F   2  /* free rv itself (pkg_free(rv)) */
107 114
 #define RV_ALL_ALLOCED_F  (RV_CNT_ALLOCED|RV_RV_ALLOCED)
115
+#define RV_RE_F  4 /* string is a RE with a valid v->re member */
116
+#define RV_RE_ALLOCED_F 8 /* v->re.regex must be freed */
108 117
 
109 118
 
110 119
 struct rval_expr{