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 138
 }
139 139
 
140 140
 
141
-#define rv_chg_in_place(rv)  ((rv)->refcnt==1) 
141
+#define rv_chg_in_place(rv)  ((rv)->refcnt==1)
142 142
 
143 143
 
144 144
 
... ...
@@ -211,6 +229,46 @@ struct rvalue* rval_new_str(str* s, int extra_size)
211 211
 
212 212
 
213 213
 
214
+/** create a new pk_malloc'ed RE rv from a str re.
215
+  * It acts as rval_new_str, but also compiles a RE from the str
216
+  * and sets v->re.regex.
217
+  * @param s - pointer to str, must be non-null, zero-term'ed and a valid RE.
218
+  * @return new rv or 0 on error
219
+  */
220
+struct rvalue* rval_new_re(str* s)
221
+{
222
+	struct rvalue* rv;
223
+	long offs;
224
+	
225
+	offs=(long)&((struct rvalue*)0)->buf[0]; /* offset of the buf. member */
226
+	/* make sure we reserve enough space so that we can satisfy any regex_t
227
+	   alignment requirement (pointer) */
228
+	rv=rval_new_empty(ROUND_POINTER(offs)-offs+sizeof(*rv->v.re.regex)+
229
+						s->len+1/* 0 */);
230
+	if (likely(rv)){
231
+		rv->type=RV_STR;
232
+		/* make sure regex points to a properly aligned address
233
+		   (use max./pointer alignment to be sure ) */
234
+		rv->v.re.regex=(regex_t*)((char*)&rv->buf[0]+ROUND_POINTER(offs)-offs);
235
+		rv->v.s.s=(char*)rv->v.re.regex+sizeof(*rv->v.re.regex);
236
+		rv->v.s.len=s->len;
237
+		memcpy(rv->v.s.s, s->s, s->len);
238
+		rv->v.s.s[s->len]=0;
239
+		/* compile the regex */
240
+		/* same flags as for expr. =~ (fix_expr()) */
241
+		if (unlikely(regcomp(rv->v.re.regex, s->s,
242
+								REG_EXTENDED|REG_NOSUB|REG_ICASE))){
243
+			/* error */
244
+			pkg_free(rv);
245
+			rv=0;
246
+		}else /* success */
247
+			rv->flags|=RV_RE_F;
248
+	}
249
+	return rv;
250
+}
251
+
252
+
253
+
214 254
 /** get string name for a type.
215 255
   *
216 256
   * @return - null terminated name of the type
... ...
@@ -415,6 +473,7 @@ enum rval_type rve_guess_type( struct rval_expr* rve)
415 415
 		case RVE_IDIFF_OP:
416 416
 		case RVE_STREQ_OP:
417 417
 		case RVE_STRDIFF_OP:
418
+		case RVE_MATCH_OP:
418 419
 		case RVE_IPLUS_OP:
419 420
 		case RVE_STRLEN_OP:
420 421
 		case RVE_STREMPTY_OP:
... ...
@@ -479,6 +538,7 @@ int rve_is_constant(struct rval_expr* rve)
479 479
 		case RVE_IDIFF_OP:
480 480
 		case RVE_STREQ_OP:
481 481
 		case RVE_STRDIFF_OP:
482
+		case RVE_MATCH_OP:
482 483
 		case RVE_PLUS_OP:
483 484
 		case RVE_IPLUS_OP:
484 485
 		case RVE_CONCAT_OP:
... ...
@@ -535,6 +595,7 @@ static int rve_op_unary(enum rval_expr_op op)
535 535
 		case RVE_IDIFF_OP:
536 536
 		case RVE_STREQ_OP:
537 537
 		case RVE_STRDIFF_OP:
538
+		case RVE_MATCH_OP:
538 539
 		case RVE_PLUS_OP:
539 540
 		case RVE_IPLUS_OP:
540 541
 		case RVE_CONCAT_OP:
... ...
@@ -681,6 +742,7 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
681 681
 			break;
682 682
 		case RVE_STREQ_OP:
683 683
 		case RVE_STRDIFF_OP:
684
+		case RVE_MATCH_OP:
684 685
 			*type=RV_INT;
685 686
 			if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){
686 687
 				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 1199
 
1200 1200
 
1201 1201
 
1202
-inline static int bool_strop2( enum rval_expr_op op, int* res,
1203
-								str* s1, str* s2)
1202
+/** internal helper: compare 2 RV_STR RVs.
1203
+  * Warning: rv1 & rv2 must be RV_STR
1204
+  * @return 0 on success, -1 on error
1205
+  */
1206
+inline static int bool_rvstrop2( enum rval_expr_op op, int* res,
1207
+								struct rvalue* rv1, struct rvalue* rv2)
1204 1208
 {
1209
+	str* s1;
1210
+	str* s2;
1211
+	regex_t tmp_re;
1212
+	
1213
+	s1=&rv1->v.s;
1214
+	s2=&rv2->v.s;
1205 1215
 	switch(op){
1206 1216
 		case RVE_EQ_OP:
1207 1217
 		case RVE_STREQ_OP:
... ...
@@ -1211,11 +1283,29 @@ inline static int bool_strop2( enum rval_expr_op op, int* res,
1211 1211
 		case RVE_STRDIFF_OP:
1212 1212
 			*res= (s1->len!=s2->len) || (memcmp(s1->s, s2->s, s1->len)!=0);
1213 1213
 			break;
1214
+		case RVE_MATCH_OP:
1215
+			if (likely(rv2->flags & RV_RE_F)){
1216
+				*res=(regexec(rv2->v.re.regex, rv1->v.s.s, 0, 0, 0)==0);
1217
+			}else{
1218
+				/* we need to compile the RE on the fly */
1219
+				if (unlikely(regcomp(&tmp_re, s2->s,
1220
+										REG_EXTENDED|REG_NOSUB|REG_ICASE))){
1221
+					/* error */
1222
+					ERR("Bad regular expression \"%s\"\n", s2->s);
1223
+					goto error;
1224
+				}
1225
+				*res=(regexec(&tmp_re, s1->s, 0, 0, 0)==0);
1226
+				regfree(&tmp_re);
1227
+			}
1228
+			break;
1214 1229
 		default:
1215 1230
 			BUG("rv unsupported intop %d\n", op);
1216
-			return -1;
1231
+			goto error;
1217 1232
 	}
1218 1233
 	return 0;
1234
+error:
1235
+	*res=0; /* false */
1236
+	return -1;
1219 1237
 }
1220 1238
 
1221 1239
 
... ...
@@ -1482,7 +1572,7 @@ inline static int rval_str_lop2(struct run_act_ctx* h,
1482 1482
 		goto error;
1483 1483
 	if ((rv2=rval_convert(h, msg, RV_STR, r, c2))==0)
1484 1484
 		goto error;
1485
-	ret=bool_strop2(op, res, &rv1->v.s, &rv2->v.s);
1485
+	ret=bool_rvstrop2(op, res, rv1, rv2);
1486 1486
 	rval_destroy(rv1); 
1487 1487
 	rval_destroy(rv2); 
1488 1488
 	return ret;
... ...
@@ -1791,6 +1881,7 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1791 1791
 			break;
1792 1792
 		case RVE_STREQ_OP:
1793 1793
 		case RVE_STRDIFF_OP:
1794
+		case RVE_MATCH_OP:
1794 1795
 			if (unlikely((rv1=rval_expr_eval(h, msg, rve->left.rve))==0)){
1795 1796
 				ret=-1;
1796 1797
 				break;
... ...
@@ -1889,6 +1980,7 @@ int rval_expr_eval_rvint(			   struct run_act_ctx* h,
1889 1889
 		case RVE_IPLUS_OP:
1890 1890
 		case RVE_STREQ_OP:
1891 1891
 		case RVE_STRDIFF_OP:
1892
+		case RVE_MATCH_OP:
1892 1893
 		case RVE_STRLEN_OP:
1893 1894
 		case RVE_STREMPTY_OP:
1894 1895
 		case RVE_DEFINED_OP:
... ...
@@ -1991,6 +2083,7 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
1991 1991
 		case RVE_IPLUS_OP:
1992 1992
 		case RVE_STREQ_OP:
1993 1993
 		case RVE_STRDIFF_OP:
1994
+		case RVE_MATCH_OP:
1994 1995
 		case RVE_STRLEN_OP:
1995 1996
 		case RVE_STREMPTY_OP:
1996 1997
 		case RVE_DEFINED_OP:
... ...
@@ -2247,6 +2340,7 @@ struct rval_expr* mk_rval_expr2(enum rval_expr_op op, struct rval_expr* rve1,
2247 2247
 		case RVE_IDIFF_OP:
2248 2248
 		case RVE_STREQ_OP:
2249 2249
 		case RVE_STRDIFF_OP:
2250
+		case RVE_MATCH_OP:
2250 2251
 		case RVE_CONCAT_OP:
2251 2252
 			break;
2252 2253
 		default:
... ...
@@ -2306,6 +2400,7 @@ static int rve_op_is_assoc(enum rval_expr_op op)
2306 2306
 		case RVE_IDIFF_OP:
2307 2307
 		case RVE_STREQ_OP:
2308 2308
 		case RVE_STRDIFF_OP:
2309
+		case RVE_MATCH_OP:
2309 2310
 			return 0;
2310 2311
 	}
2311 2312
 	return 0;
... ...
@@ -2351,6 +2446,7 @@ static int rve_op_is_commutative(enum rval_expr_op op)
2351 2351
 		case RVE_LT_OP:
2352 2352
 		case RVE_LTE_OP:
2353 2353
 		case RVE_CONCAT_OP:
2354
+		case RVE_MATCH_OP:
2354 2355
 			return 0;
2355 2356
 		case RVE_DIFF_OP:
2356 2357
 		case RVE_EQ_OP:
... ...
@@ -2461,6 +2557,41 @@ static int fix_rval(struct rvalue* rv)
2461 2461
 
2462 2462
 
2463 2463
 
2464
+/** helper function: replace a rve (in-place) with a constant rval_val.
2465
+ * WARNING: since it replaces in-place, one should make sure that if
2466
+ * rve is in fact a rval (rve->op==RVE_RVAL_OP), no reference is kept
2467
+ * to the rval!
2468
+ * @param rve - expression to be replaced (in-place)
2469
+ * @param v   - pointer to a rval_val union containing the replacement
2470
+ *              value.
2471
+ * @param flags - value flags (how it was alloc'ed, e.g.: RV_CNT_ALLOCED_F)
2472
+ * @return 0 on success, -1 on error */
2473
+static int rve_replace_with_val(struct rval_expr* rve, enum rval_type type,
2474
+								union rval_val* v, int flags)
2475
+{
2476
+	int refcnt;
2477
+	
2478
+	refcnt=1; /* replaced-in-place rval refcnt */
2479
+	if (rve->op!=RVE_RVAL_OP){
2480
+		rve_destroy(rve->left.rve);
2481
+		if (rve_op_unary(rve->op)==0)
2482
+			rve_destroy(rve->right.rve);
2483
+	}else{
2484
+		rval_destroy(&rve->left.rval);
2485
+	}
2486
+	rval_init(&rve->left.rval, type, v, flags);
2487
+	rve->left.rval.refcnt=refcnt;
2488
+	rval_init(&rve->right.rval, RV_NONE, 0, 0);
2489
+	rve->op=RVE_RVAL_OP;
2490
+	return 0;
2491
+}
2492
+
2493
+
2494
+
2495
+/** helper function: replace a rve (in-place) with a constant rvalue.
2496
+ * @param rve - expression to be replaced (in-place)
2497
+ * @param rv   - pointer to the replacement _constant_ rvalue structure
2498
+ * @return 0 on success, -1 on error */
2464 2499
 static int rve_replace_with_ct_rv(struct rval_expr* rve, struct rvalue* rv)
2465 2500
 {
2466 2501
 	enum rval_type type;
... ...
@@ -2481,21 +2612,89 @@ static int rve_replace_with_ct_rv(struct rval_expr* rve, struct rvalue* rv)
2481 2481
 			BUG("unexpected str evaluation failure\n");
2482 2482
 			return -1;
2483 2483
 		}
2484
-		flags=RV_CNT_ALLOCED_F;
2484
+		flags|=RV_CNT_ALLOCED_F;
2485 2485
 	}else{
2486 2486
 		BUG("unknown constant expression type %d\n", rv->type);
2487 2487
 		return -1;
2488 2488
 	}
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;
2489
+	return rve_replace_with_val(rve, type, &v, flags);
2490
+}
2491
+
2492
+
2493
+
2494
+/** try to replace the right side of the rve with a compiled regex.
2495
+  * @return 0 on success and -1 on error.
2496
+ */
2497
+static int fix_match_rve(struct rval_expr* rve)
2498
+{
2499
+	struct rvalue* rv;
2500
+	regex_t* re;
2501
+	union rval_val v;
2502
+	int flags;
2503
+	int ret;
2504
+
2505
+	rv=0;
2506
+	v.s.s=0;
2507
+	v.re.regex=0;
2508
+	/* normal fix-up for the  left side */
2509
+	ret=fix_rval_expr((void**)&rve->left.rve);
2510
+	if (ret<0) return ret;
2511
+	
2512
+	/* fixup the right side (RE) */
2513
+	if (rve_is_constant(rve->right.rve)){
2514
+		if ((rve_guess_type(rve->right.rve)!=RV_STR)){
2515
+			ERR("fixup failure(%d,%d-%d,%d): left side of  =~ is not string"
2516
+					" (%d,%d)\n",   rve->fpos.s_line, rve->fpos.s_col,
2517
+									rve->fpos.e_line, rve->fpos.e_col,
2518
+									rve->right.rve->fpos.s_line,
2519
+									rve->right.rve->fpos.s_col);
2520
+			goto error;
2521
+		}
2522
+		if ((rv=rval_expr_eval(0, 0, rve->right.rve))==0){
2523
+			ERR("fixup failure(%d,%d-%d,%d):  bad RE expression\n",
2524
+					rve->right.rve->fpos.s_line, rve->right.rve->fpos.s_col,
2525
+					rve->right.rve->fpos.e_line, rve->right.rve->fpos.e_col);
2526
+			goto error;
2527
+		}
2528
+		if (rval_get_str(0, 0, &v.s, rv, 0)<0){
2529
+			BUG("fixup unexpected failure (%d,%d-%d,%d)\n",
2530
+					rve->fpos.s_line, rve->fpos.s_col,
2531
+					rve->fpos.e_line, rve->fpos.e_col);
2532
+			goto error;
2533
+		}
2534
+		/* we have the str, we don't need the rv anymore */
2535
+		rval_destroy(rv);
2536
+		rv=0;
2537
+		re=pkg_malloc(sizeof(*re));
2538
+		if (re==0){
2539
+			ERR("out of memory\n");
2540
+			goto error;
2541
+		}
2542
+		/* same flags as for expr. =~ (fix_expr()) */
2543
+		if (regcomp(re, v.s.s, REG_EXTENDED|REG_NOSUB|REG_ICASE)){
2544
+			pkg_free(re);
2545
+			ERR("Bad regular expression \"%s\"(%d,%d-%d,%d)\n", v.s.s,
2546
+					rve->right.rve->fpos.s_line, rve->right.rve->fpos.s_col,
2547
+					rve->right.rve->fpos.e_line, rve->right.rve->fpos.e_col);
2548
+			goto error;
2549
+		}
2550
+		v.re.regex=re;
2551
+		flags=RV_RE_F|RV_RE_ALLOCED_F|RV_CNT_ALLOCED_F;
2552
+		if (rve_replace_with_val(rve->right.rve, RV_STR, &v, flags)<0)
2553
+			goto error;
2554
+	}else{
2555
+		/* right side is not constant => normal fixup */
2556
+		return fix_rval_expr((void**)&rve->right.rve);
2557
+	}
2498 2558
 	return 0;
2559
+error:
2560
+	if (rv) rval_destroy(rv);
2561
+	if (v.s.s) pkg_free(v.s.s);
2562
+	if (v.re.regex){
2563
+		regfree(v.re.regex);
2564
+		pkg_free(v.re.regex);
2565
+	}
2566
+	return -1;
2499 2567
 }
2500 2568
 
2501 2569
 
... ...
@@ -3111,6 +3310,10 @@ int fix_rval_expr(void** p)
3111 3111
 			ret=fix_rval_expr((void**)&rve->right.rve);
3112 3112
 			if (ret<0) return ret;
3113 3113
 			break;
3114
+		case RVE_MATCH_OP:
3115
+			ret=fix_match_rve(rve);
3116
+			if (ret<0) return ret;
3117
+			break;
3114 3118
 		default:
3115 3119
 			BUG("unsupported op type %d\n", rve->op);
3116 3120
 	}
... ...
@@ -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 88
 	pv_spec_t pvs;
89 89
 	struct action* action;
90 90
 	struct expr* bexpr;
91
+	struct str_re re;
91 92
 };
92 93
 
93 94
 
... ...
@@ -105,6 +112,8 @@ struct rvalue{
105 105
 #define RV_CNT_ALLOCED_F  1  /* free contents  (pkg mem allocated) */
106 106
 #define RV_RV_ALLOCED_F   2  /* free rv itself (pkg_free(rv)) */
107 107
 #define RV_ALL_ALLOCED_F  (RV_CNT_ALLOCED|RV_RV_ALLOCED)
108
+#define RV_RE_F  4 /* string is a RE with a valid v->re member */
109
+#define RV_RE_ALLOCED_F 8 /* v->re.regex must be freed */
108 110
 
109 111
 
110 112
 struct rval_expr{