Browse code

Merge commit 'origin/andrei/type_conversion'

* commit 'origin/andrei/type_conversion':
script parsing: fix bug in expression error checking
core expr eval: various fixes
news: update (new operators, expr. eval behaviour a.s.o.)
core: new script operators: eq, ne, ieq, ine
core expr eval: fix assoc., commut and 0 adding for +, ==
core expr eval: minor ==/!= optimization
core expr eval: internal == & != int and str only versions
core expr eval: special handling for undef cmp expr
core eval expr: cache undefined results too
core expr eval: str automatic conversion to int
core expr eval: undef conversion to int and str
core expr eval: defined @select

Andrei Pelinescu-Onciul authored on 04/05/2009 21:38:12
Showing 5 changed files
... ...
@@ -6,6 +6,33 @@ $Id$
6 6
 sip-router changes
7 7
 
8 8
 core:
9
+  - new operators eq, ne for string compares and ieq, ine for interger 
10
+    compares. The names are not yet final (use them at your own risk).
11
+    Future version might use ==/!= only for ints (ieq/ine) and eq/ne for
12
+    strings (under debate).
13
+    They are almost equivalent to == or !=, but they force the conversion 
14
+	of their operands (eq to string and ieq to int), allowing among other
15
+	things better type checking on startup and more optimizations.
16
+    Non equiv. examples: 0 == "" (true) is not equivalent to 0 eq ""
17
+    (false: it evaluates to "0" eq ""). "a" ieq "b" (true: (int)"a" is 0
18
+     and (int)"b" is 0) is not equivalent to "a" == "b" (false).
19
+    Note: internally == and != are converted on startup to eq/ne/ieq/ine 
20
+    whenever possible (both operand types can be safely determined at
21
+    start time and they are the same).
22
+  - try to guess what the user wanted when operators that support multiple
23
+     types are used on different typed operands. In general convert the
24
+     the right operand to the type of the left operand and then perform the
25
+     operation. Exception: the left operand is undef.
26
+     This applies to the following operators: +, == and !=.
27
+     Special case: undef as left operand:
28
+     For +: undef + expr -> undef is converted to string => "" + expr.
29
+     For == and !=:   undef == expr -> undef is converted to type_of expr.
30
+     If expr is undef, then undef == undef is true (internally is converted
31
+     to string).
32
+  - expression evaluation changes: auto-convert to interger or string
33
+     in function of the operators: 
34
+       int(undef)==0,  int("")==0, int("123")==123, int("abc")==0
35
+       str(undef)=="", str(123)=="123".
9 36
   - new script operators: defined, strlen, strempty
10 37
       defined expr - returns true if expr is defined, and false if not.
11 38
                      Note: only a standalone avp or pvar can be
... ...
@@ -248,6 +248,10 @@ MINUS	"-"
248 248
 STRLEN	"strlen"
249 249
 STREMPTY	"strempty"
250 250
 DEFINED		"defined"
251
+STREQ	eq
252
+INTEQ	ieq
253
+STRDIFF	ne
254
+INTDIFF	ine
251 255
 
252 256
 /* Attribute specification */
253 257
 ATTR_MARK   "%"
... ...
@@ -775,6 +779,10 @@ EAT_ABLE	[\ \t\b\r]
775 779
 <INITIAL>{STRLEN}	{ count(); return STRLEN; }
776 780
 <INITIAL>{STREMPTY}	{ count(); return STREMPTY; }
777 781
 <INITIAL>{DEFINED}	{ count(); return DEFINED; }
782
+<INITIAL>{STREQ}	{ count(); return STREQ; }
783
+<INITIAL>{INTEQ}	{ count(); return INTEQ; }
784
+<INITIAL>{STRDIFF}	{ count(); return STRDIFF; }
785
+<INITIAL>{INTDIFF}	{ count(); return INTDIFF; }
778 786
 
779 787
 <INITIAL>{SELECT_MARK}  { count(); state = SELECT_S; BEGIN(SELECT); return SELECT_MARK; }
780 788
 <SELECT>{ID}		{ count(); addstr(&s_buf, yytext, yyleng);
... ...
@@ -485,7 +485,7 @@ static int case_check_default(struct case_stms* stms);
485 485
 %left LOG_AND
486 486
 %left BIN_OR
487 487
 %left BIN_AND
488
-%left EQUAL_T DIFF MATCH
488
+%left EQUAL_T DIFF MATCH INTEQ INTDIFF STREQ STRDIFF
489 489
 %left GT LT GTE LTE
490 490
 %left PLUS MINUS
491 491
 %left STAR SLASH
... ...
@@ -1568,7 +1568,10 @@ send_route_stm: ROUTE_SEND LBRACE actions RBRACE {
1568 1568
 
1569 1569
 exp:	rval_expr
1570 1570
 		{
1571
-			if (!rve_check_type((enum rval_type*)&i_tmp, $1, 0, 0 ,0)){
1571
+			if ($1==0){
1572
+				yyerror("invalid expression");
1573
+				$$=0;
1574
+			}else if (!rve_check_type((enum rval_type*)&i_tmp, $1, 0, 0 ,0)){
1572 1575
 				yyerror("invalid expression");
1573 1576
 				$$=0;
1574 1577
 			}else if (i_tmp!=RV_INT && i_tmp!=RV_NONE){
... ...
@@ -1583,6 +1586,8 @@ exp:	rval_expr
1583 1586
 equalop:
1584 1587
 	EQUAL_T {$$=EQUAL_OP; }
1585 1588
 	| DIFF	{$$=DIFF_OP; }
1589
+	| STREQ	{$$=EQUAL_OP; }  /* for expr. elems equiv. to EQUAL_T*/
1590
+	| STRDIFF {$$=DIFF_OP; } /* for expr. elems. equiv. to DIFF */
1586 1591
 	;
1587 1592
 cmpop:
1588 1593
 	  GT	{$$=GT_OP; }
... ...
@@ -1600,6 +1605,10 @@ strop:
1600 1605
 rve_equalop:
1601 1606
 	EQUAL_T {$$=RVE_EQ_OP; }
1602 1607
 	| DIFF	{$$=RVE_DIFF_OP; }
1608
+	| INTEQ	{$$=RVE_IEQ_OP; }
1609
+	| INTDIFF {$$=RVE_IDIFF_OP; }
1610
+	| STREQ	{$$=RVE_STREQ_OP; }
1611
+	| STRDIFF {$$=RVE_STRDIFF_OP; }
1603 1612
 	;
1604 1613
 rve_cmpop:
1605 1614
 	  GT	{$$=RVE_GT_OP; }
... ...
@@ -2217,9 +2226,9 @@ rval: intno			{$$=mk_rve_rval(RV_INT, (void*)$1); }
2217 2226
 	| fcmd				{$$=mk_rve_rval(RV_ACTION_ST, $1); }
2218 2227
 	| exp_elem { $$=mk_rve_rval(RV_BEXPR, $1); }
2219 2228
 	| LBRACE actions RBRACE	{$$=mk_rve_rval(RV_ACTION_ST, $2); }
2220
-	| LBRACE error RBRACE	{ yyerror("bad command block"); }
2229
+	| LBRACE error RBRACE	{ $$=0; yyerror("bad command block"); }
2221 2230
 	| LPAREN assign_action RPAREN	{$$=mk_rve_rval(RV_ACTION_ST, $2); }
2222
-	| LPAREN error RPAREN	{ yyerror("bad expression"); }
2231
+	| LPAREN error RPAREN	{ $$=0; yyerror("bad expression"); }
2223 2232
 	;
2224 2233
 
2225 2234
 
... ...
@@ -2237,10 +2246,11 @@ rve_op:		PLUS		{ $$=RVE_PLUS_OP; }
2237 2246
 */
2238 2247
 
2239 2248
 rval_expr: rval						{ $$=$1;
2240
-											if ($$==0){
2249
+										/*	if ($$==0){
2241 2250
 												yyerror("out of memory\n");
2242 2251
 												YYABORT;
2243 2252
 											}
2253
+											*/
2244 2254
 									}
2245 2255
 		| rve_un_op %prec NOT rval_expr	{$$=mk_rve1($1, $2); }
2246 2256
 		| rval_expr PLUS rval_expr		{$$=mk_rve2(RVE_PLUS_OP, $1, $3); }
... ...
@@ -2258,7 +2268,7 @@ rval_expr: rval						{ $$=$1;
2258 2268
 		| STRLEN LPAREN rval_expr RPAREN { $$=mk_rve1(RVE_STRLEN_OP, $3);}
2259 2269
 		| STREMPTY LPAREN rval_expr RPAREN {$$=mk_rve1(RVE_STREMPTY_OP, $3);}
2260 2270
 		| DEFINED rval_expr				{ $$=mk_rve1(RVE_DEFINED_OP, $2);}
2261
-		| rve_un_op %prec NOT error		{ yyerror("bad expression"); }
2271
+		| rve_un_op %prec NOT error		{ $$=0; yyerror("bad expression"); }
2262 2272
 		| rval_expr PLUS error			{ yyerror("bad expression"); }
2263 2273
 		| rval_expr MINUS error			{ yyerror("bad expression"); }
2264 2274
 		| rval_expr STAR error			{ yyerror("bad expression"); }
... ...
@@ -2271,9 +2281,9 @@ rval_expr: rval						{ $$=$1;
2271 2281
 			{ yyerror("bad expression"); }
2272 2282
 		| rval_expr LOG_AND error		{ yyerror("bad expression"); }
2273 2283
 		| rval_expr LOG_OR error		{ yyerror("bad expression"); }
2274
-		| STRLEN LPAREN error RPAREN	{ yyerror("bad expression"); }
2275
-		| STREMPTY LPAREN error RPAREN	{ yyerror("bad expression"); }
2276
-		| DEFINED error					{ yyerror("bad expression"); }
2284
+		| STRLEN LPAREN error RPAREN	{ $$=0; yyerror("bad expression"); }
2285
+		| STREMPTY LPAREN error RPAREN	{ $$=0; yyerror("bad expression"); }
2286
+		| DEFINED error					{ $$=0; yyerror("bad expression"); }
2277 2287
 		;
2278 2288
 
2279 2289
 assign_action: lval assign_op  rval_expr	{ $$=mk_action($2, 2, LVAL_ST, $1, 
... ...
@@ -2901,13 +2911,19 @@ static struct rval_expr* mk_rve2(enum rval_expr_op op, struct rval_expr* rve1,
2901 2911
 	
2902 2912
 	if ((rve1==0) || (rve2==0))
2903 2913
 		return 0;
2914
+	bad_rve=0;
2915
+	bad_t=0;
2916
+	exp_t=0;
2904 2917
 	cfg_pos_join(&pos, &rve1->fpos, &rve2->fpos);
2905 2918
 	ret=mk_rval_expr2(op, rve1, rve2, &pos);
2906 2919
 	if (ret && (rve_check_type(&type, ret, &bad_rve, &bad_t, &exp_t)!=1)){
2907
-		yyerror_at(&pos, "bad expression: type mismatch:"
2920
+		if (bad_rve)
2921
+			yyerror_at(&pos, "bad expression: type mismatch:"
2908 2922
 						" %s instead of %s at (%d,%d)",
2909 2923
 						rval_type_name(bad_t), rval_type_name(exp_t),
2910 2924
 						bad_rve->fpos.s_line, bad_rve->fpos.s_col);
2925
+		else
2926
+			yyerror("BUG: unexpected null \"bad\" expression\n");
2911 2927
 	}
2912 2928
 	return ret;
2913 2929
 }
... ...
@@ -24,6 +24,25 @@
24 24
  * --------
25 25
  *  2008-12-01  initial version (andrei)
26 26
  *  2009-04-24  added support for defined, strempty, strlen (andrei)
27
+ *  2009-04-28  int and str automatic conversions: (int)undef=0,
28
+ *               (str)undef="", (int)""=0, (int)"123"=123, (int)"abc"=0
29
+ *              handle undef == expr, in function of the UNDEF_EQ_* defines.
30
+ *              (andrei)
31
+ */
32
+
33
+/* special defines:
34
+ *
35
+ *  UNDEF_EQ_* - how to behave when undef is on the right side of a generic
36
+ *               compare operator
37
+ *  UNDEF_EQ_ALWAYS_FALSE:  undef  == something  is always false
38
+ *  UNDEF_EQ_UNDEF_TRUE  :  undef == something false except for undef==undef
39
+ *                          which is true
40
+ *  no UNDEF_EQ* define  :  undef == expr => convert undef to typeof(expr)
41
+ *                          and perform normal ==. undef == undef will be
42
+ *                          converted to string and it will be true
43
+ *                          ("" == "")
44
+ * NOTE: expr == undef, with defined(expr) is always evaluated this way:
45
+         expr == (type_of(expr))undef
27 46
  */
28 47
 
29 48
 #include "rvalue.h"
... ...
@@ -111,7 +130,7 @@ void rve_destroy(struct rval_expr* rve)
111 130
 
112 131
 void rval_cache_clean(struct rval_cache* rvc)
113 132
 {
114
-	if (rvc->cache_type==RV_CACHE_PVAR){
133
+	if ((rvc->cache_type==RV_CACHE_PVAR) && (rvc->val_type!=RV_NONE)){
115 134
 		pv_value_destroy(&rvc->c.pval);
116 135
 	}
117 136
 	rvc->cache_type=RV_CACHE_EMPTY;
... ...
@@ -261,7 +280,7 @@ struct rvalue* rval_new(enum rval_type t, union rval_val* v, int extra_size)
261 280
   * rval_cache_clean()'en when no longer needed.
262 281
   *
263 282
   * @param rv - target rvalue
264
-  * @param val_cache - value cache, might be filled if non-null, 
283
+  * @param val_cache - write-only: value cache, might be filled if non-null,
265 284
   *                    it _must_ be rval_cache_clean()'en when done.
266 285
   * @return - basic type or RV_NONE on error
267 286
   */
... ...
@@ -288,36 +307,39 @@ inline static enum rval_type rval_get_btype(struct run_act_ctx* h,
288 307
 		case RV_PVAR:
289 308
 			if (likely(val_cache && val_cache->cache_type==RV_CACHE_EMPTY)){
290 309
 				pv=&val_cache->c.pval;
310
+				val_cache->cache_type=RV_CACHE_PVAR;
291 311
 			}else{
292 312
 				val_cache=0;
293 313
 				pv=&tmp_pval;
294 314
 			}
295 315
 			memset(pv, 0, sizeof(tmp_pval));
296 316
 			if (likely(pv_get_spec_value(msg, &rv->v.pvs, pv)==0)){
297
-				if (pv->flags & PV_VAL_STR){
298
-					if (unlikely(val_cache==0)) pv_value_destroy(pv);
299
-					else{
300
-						val_cache->cache_type=RV_CACHE_PVAR;
301
-						val_cache->val_type=RV_STR;
302
-					}
303
-					return RV_STR;
304
-				}else if (pv->flags & PV_TYPE_INT){
305
-					if (unlikely(val_cache==0)) pv_value_destroy(pv);
306
-					else{
307
-						val_cache->cache_type=RV_CACHE_PVAR;
317
+				if (pv->flags & PV_TYPE_INT){
318
+					if (likely(val_cache!=0))
308 319
 						val_cache->val_type=RV_INT;
309
-					}
320
+					else
321
+						pv_value_destroy(pv);
310 322
 					return RV_INT;
323
+				}else if (pv->flags & PV_VAL_STR){
324
+					if (likely(val_cache!=0))
325
+						val_cache->val_type=RV_STR;
326
+					else
327
+						pv_value_destroy(pv);
328
+					return RV_STR;
311 329
 				}else{
312 330
 					pv_value_destroy(pv);
331
+					if (likely(val_cache!=0))
332
+						val_cache->val_type=RV_NONE; /* undefined */
313 333
 					goto error;
314 334
 				}
315 335
 			}else{
336
+				if (likely(val_cache!=0))
337
+					val_cache->val_type=RV_NONE; /* undefined */
316 338
 				goto error;
317 339
 			}
318 340
 			break;
319 341
 		case RV_AVP:
320
-			if (likely(val_cache && val_cache==RV_CACHE_EMPTY)){
342
+			if (likely(val_cache && val_cache->cache_type==RV_CACHE_EMPTY)){
321 343
 				ptype=&val_cache->val_type;
322 344
 				avpv=&val_cache->c.avp_val;
323 345
 				val_cache->cache_type=RV_CACHE_AVP;
... ...
@@ -337,7 +359,6 @@ inline static enum rval_type rval_get_btype(struct run_act_ctx* h,
337 359
 				}
338 360
 			}else{
339 361
 				*ptype=RV_NONE;
340
-				if (val_cache) val_cache->cache_type=RV_CACHE_EMPTY;
341 362
 				goto error;
342 363
 			}
343 364
 			break;
... ...
@@ -390,6 +411,10 @@ enum rval_type rve_guess_type( struct rval_expr* rve)
390 411
 		case RVE_LTE_OP:
391 412
 		case RVE_EQ_OP:
392 413
 		case RVE_DIFF_OP:
414
+		case RVE_IEQ_OP:
415
+		case RVE_IDIFF_OP:
416
+		case RVE_STREQ_OP:
417
+		case RVE_STRDIFF_OP:
393 418
 		case RVE_IPLUS_OP:
394 419
 		case RVE_STRLEN_OP:
395 420
 		case RVE_STREMPTY_OP:
... ...
@@ -450,6 +475,10 @@ int rve_is_constant(struct rval_expr* rve)
450 475
 		case RVE_LTE_OP:
451 476
 		case RVE_EQ_OP:
452 477
 		case RVE_DIFF_OP:
478
+		case RVE_IEQ_OP:
479
+		case RVE_IDIFF_OP:
480
+		case RVE_STREQ_OP:
481
+		case RVE_STRDIFF_OP:
453 482
 		case RVE_PLUS_OP:
454 483
 		case RVE_IPLUS_OP:
455 484
 		case RVE_CONCAT_OP:
... ...
@@ -502,6 +531,10 @@ static int rve_op_unary(enum rval_expr_op op)
502 531
 		case RVE_LTE_OP:
503 532
 		case RVE_EQ_OP:
504 533
 		case RVE_DIFF_OP:
534
+		case RVE_IEQ_OP:
535
+		case RVE_IDIFF_OP:
536
+		case RVE_STREQ_OP:
537
+		case RVE_STRDIFF_OP:
505 538
 		case RVE_PLUS_OP:
506 539
 		case RVE_IPLUS_OP:
507 540
 		case RVE_CONCAT_OP:
... ...
@@ -564,6 +597,8 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
564 597
 		case RVE_GTE_OP:
565 598
 		case RVE_LT_OP:
566 599
 		case RVE_LTE_OP:
600
+		case RVE_IEQ_OP:
601
+		case RVE_IDIFF_OP:
567 602
 		case RVE_IPLUS_OP:
568 603
 			*type=RV_INT;
569 604
 			if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){
... ...
@@ -644,6 +679,30 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
644 679
 				}
645 680
 			}
646 681
 			break;
682
+		case RVE_STREQ_OP:
683
+		case RVE_STRDIFF_OP:
684
+			*type=RV_INT;
685
+			if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){
686
+				if (rve_check_type(&type2, rve->right.rve, bad_rve, bad_t,
687
+									exp_t)){
688
+					if ((type2!=type1) && (type1!=RV_NONE) &&
689
+							(type2!=RV_NONE) &&
690
+							!(type1==RV_STR && type2==RV_INT)){
691
+						if (bad_rve) *bad_rve=rve->right.rve;
692
+						if (bad_t) *bad_t=type2;
693
+						if (exp_t) *exp_t=type1;
694
+						return 0;
695
+					}
696
+					if (type1==RV_INT){
697
+						if (bad_rve) *bad_rve=rve->left.rve;
698
+						if (bad_t) *bad_t=type1;
699
+						if (exp_t) *exp_t=RV_STR;
700
+						return 0;
701
+					}
702
+					return 1;
703
+				}
704
+			}
705
+			break;
647 706
 		case RVE_STRLEN_OP:
648 707
 		case RVE_STREMPTY_OP:
649 708
 		case RVE_DEFINED_OP:
... ...
@@ -659,6 +718,11 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
659 718
 			}
660 719
 			break;
661 720
 		case RVE_NONE_OP:
721
+		default:
722
+			BUG("unexpected rve op %d\n", rve->op);
723
+			if (bad_rve) *bad_rve=rve;
724
+			if (bad_t) *bad_t=RV_NONE;
725
+			if (exp_t) *exp_t=RV_STR;
662 726
 			break;
663 727
 	}
664 728
 	return 0;
... ...
@@ -668,6 +732,15 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
668 732
 
669 733
 /** get the integer value of an rvalue.
670 734
   * *i=(int)rv
735
+  * if rv == undefined select, avp or pvar, return 0.
736
+  * if an error occurs while evaluating a select, avp or pvar, behave as
737
+  * for the undefined case (and return success).
738
+  * @param h - script context handle
739
+  * @param msg - sip msg
740
+  * @param i   - pointer to int, where the conversion result will be stored
741
+  * @param rv   - rvalue to be converted
742
+  * @param cache - cached rv value (read-only), can be 0
743
+  *
671 744
   * @return 0 on success, \<0 on error and EXPR_DROP on drop
672 745
  */
673 746
 int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg,
... ...
@@ -677,12 +750,19 @@ int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg,
677 750
 	avp_t* r_avp;
678 751
 	int_str avp_val;
679 752
 	pv_value_t pval;
753
+	str tmp;
754
+	str* s;
755
+	int r;
756
+	int destroy_pval;
680 757
 	
758
+	destroy_pval=0;
759
+	s=0;
681 760
 	switch(rv->type){
682 761
 		case RV_INT:
683 762
 			*i=rv->v.l;
684 763
 			break;
685 764
 		case RV_STR:
765
+			s=&rv->v.s;
686 766
 			goto rv_str;
687 767
 		case RV_BEXPR:
688 768
 			*i=eval_expr(h, rv->v.bexpr, msg);
... ...
@@ -698,36 +778,51 @@ int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg,
698 778
 				*i=0;
699 779
 			break;
700 780
 		case RV_SEL:
781
+			r=run_select(&tmp, &rv->v.sel, msg);
782
+			if (unlikely(r!=0)){
783
+				if (r<0)
784
+					goto eval_error;
785
+				else /* i>0  => undefined */
786
+					goto undef;
787
+			}
788
+			s=&tmp;
701 789
 			goto rv_str;
702 790
 		case RV_AVP:
703 791
 			if (unlikely(cache && cache->cache_type==RV_CACHE_AVP)){
704 792
 				if (likely(cache->val_type==RV_INT)){
705 793
 					*i=cache->c.avp_val.n;
706
-				}else if (cache->val_type==RV_STR)
794
+				}else if (cache->val_type==RV_STR){
795
+					s=&cache->c.avp_val.s;
707 796
 					goto rv_str;
708
-				else goto error;
797
+				}else if (cache->val_type==RV_NONE)
798
+					goto undef;
799
+				else goto error_cache;
709 800
 			}else{
710 801
 				r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
711 802
 											&avp_val, rv->v.avps.index);
712 803
 				if (likely(r_avp)){
713 804
 					if (unlikely(r_avp->flags & AVP_VAL_STR)){
805
+						s=&avp_val.s;
714 806
 						goto rv_str;
715 807
 					}else{
716 808
 						*i=avp_val.n;
717 809
 					}
718 810
 				}else{
719
-					goto error;
811
+					goto undef;
720 812
 				}
721 813
 			}
722 814
 			break;
723 815
 		case RV_PVAR:
724 816
 			if (unlikely(cache && cache->cache_type==RV_CACHE_PVAR)){
725
-				if (likely((cache->val_type==RV_INT) || 
817
+				if (likely((cache->val_type==RV_INT) ||
726 818
 								(cache->c.pval.flags & PV_VAL_INT))){
727 819
 					*i=cache->c.pval.ri;
728
-				}else if (cache->val_type==RV_STR)
820
+				}else if (cache->val_type==RV_STR){
821
+					s=&cache->c.pval.rs;
729 822
 					goto rv_str;
730
-				else goto error;
823
+				}else if (cache->val_type==RV_NONE)
824
+					goto undef;
825
+				else goto error_cache;
731 826
 			}else{
732 827
 				memset(&pval, 0, sizeof(pval));
733 828
 				if (likely(pv_get_spec_value(msg, &rv->v.pvs, &pval)==0)){
... ...
@@ -735,14 +830,17 @@ int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg,
735 830
 						*i=pval.ri;
736 831
 						pv_value_destroy(&pval);
737 832
 					}else if (likely(pval.flags & PV_VAL_STR)){
738
-						pv_value_destroy(&pval);
833
+						destroy_pval=1; /* we must pv_value_destroy() later*/
834
+						s=&pval.rs;
739 835
 						goto rv_str;
740 836
 					}else{
837
+						/* no PV_VAL_STR and no PV_VAL_INT => undef
838
+						   (PV_VAL_NULL) */
741 839
 						pv_value_destroy(&pval);
742
-						goto error;
840
+						goto undef;
743 841
 					}
744 842
 				}else{
745
-					goto error;
843
+					goto eval_error;
746 844
 				}
747 845
 			}
748 846
 			break;
... ...
@@ -751,10 +849,27 @@ int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg,
751 849
 			goto error;
752 850
 	}
753 851
 	return 0;
852
+undef:
853
+eval_error: /* same as undefined */
854
+	/* handle undefined => result 0, return success */
855
+	*i=0;
856
+	return 0;
857
+error_cache:
858
+	BUG("invalid cached value:cache type %d, value type %d\n",
859
+			cache?cache->cache_type:0, cache?cache->val_type:0);
754 860
 rv_str:
755
-	/* rv is of string type => error */
756
-	/* ERR("string in int expression\n"); */
861
+	/* rv is of string type => try to convert it to int */
862
+	/* if "" => 0 (most likely case) */
863
+	if (likely(s->len==0)) *i=0;
864
+	else if (unlikely(str2sint(s, i)!=0)){
865
+		/* error converting to int => non numeric => 0 */
866
+		*i=0;
867
+	}
868
+	if (destroy_pval)
869
+		pv_value_destroy(&pval);
870
+	return 0;
757 871
 error:
872
+	*i=0;
758 873
 	return -1;
759 874
 }
760 875
 
... ...
@@ -762,6 +877,9 @@ error:
762 877
 
763 878
 /** get the string value of an rv in a tmp variable
764 879
   * *s=(str)rv
880
+  * if rv == undefined select, avp or pvar, return "".
881
+  * if an error occurs while evaluating a select, avp or pvar, behave as
882
+  * for the undefined case (and return success).
765 883
   * The result points either to a temporary string or inside
766 884
   * new_cache. new_cache must be non zero, initialized previously,
767 885
   * and it _must_ be rval_cache_clean(...)'ed when done.
... ...
@@ -771,9 +889,9 @@ error:
771 889
   * @param h - script context handle
772 890
   * @param msg - sip msg
773 891
   * @param tmpv - str return value (pointer to a str struct that will be
774
-  *               be filled.
892
+  *               be filled with the conversion result)
775 893
   * @param rv   - rvalue to be converted
776
-  * @param cache - cached rv value (read-only)
894
+  * @param cache - cached rv value (read-only), can be 0
777 895
   * @param tmp_cache - used for temporary storage (so that tmpv will not
778 896
   *                 point to possible freed data), it must be non-null,
779 897
   *                 initialized and cleaned afterwards.
... ...
@@ -814,10 +932,9 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
814 932
 			i=run_select(tmpv, &rv->v.sel, msg);
815 933
 			if (unlikely(i!=0)){
816 934
 				if (i<0){
817
-					goto error;
818
-				}else { /* i>0 */
819
-					tmpv->s="";
820
-					tmpv->len=0;
935
+					goto eval_error;
936
+				}else { /* i>0  => undefined */
937
+					goto undef;
821 938
 				}
822 939
 			}
823 940
 			break;
... ...
@@ -828,7 +945,9 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
828 945
 				}else if (cache->val_type==RV_INT){
829 946
 					i=cache->c.avp_val.n;
830 947
 					tmpv->s=int2str(i, &tmpv->len);
831
-				}else goto error;
948
+				}else if (cache->val_type==RV_NONE){
949
+					goto undef;
950
+				}else goto error_cache;
832 951
 			}else{
833 952
 				r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
834 953
 											&tmp_cache->c.avp_val,
... ...
@@ -842,9 +961,7 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
842 961
 						i=tmp_cache->c.avp_val.n;
843 962
 						tmpv->s=int2str(i, &tmpv->len);
844 963
 					}
845
-				}else{
846
-					goto error;
847
-				}
964
+				}else goto undef;
848 965
 			}
849 966
 			break;
850 967
 		case RV_PVAR:
... ...
@@ -854,7 +971,9 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
854 971
 				}else if (cache->val_type==RV_INT){
855 972
 					i=cache->c.pval.ri;
856 973
 					tmpv->s=int2str(i, &tmpv->len);
857
-				}else goto error;
974
+				}else if (cache->val_type==RV_NONE){
975
+					goto undef;
976
+				}else goto error_cache;
858 977
 			}else{
859 978
 				memset(&tmp_cache->c.pval, 0, sizeof(tmp_cache->c.pval));
860 979
 				if (likely(pv_get_spec_value(msg, &rv->v.pvs,
... ...
@@ -871,11 +990,13 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
871 990
 						pv_value_destroy(&tmp_cache->c.pval);
872 991
 						tmpv->s=int2str(i, &tmpv->len);
873 992
 					}else{
993
+						/* no PV_VAL_STR and no PV_VAL_INT => undef
994
+						   (PV_VAL_NULL) */
874 995
 						pv_value_destroy(&tmp_cache->c.pval);
875
-						goto error;
996
+						goto undef;
876 997
 					}
877 998
 				}else{
878
-					goto error;
999
+					goto eval_error;
879 1000
 				}
880 1001
 			}
881 1002
 			break;
... ...
@@ -884,7 +1005,18 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
884 1005
 			goto error;
885 1006
 	}
886 1007
 	return 0;
1008
+undef:
1009
+eval_error: /* same as undefined */
1010
+	/* handle undefined => result "", return success */
1011
+	tmpv->s="";
1012
+	tmpv->len=0;
1013
+	return 0;
1014
+error_cache:
1015
+	BUG("invalid cached value:cache type %d, value type %d\n",
1016
+			cache?cache->cache_type:0, cache?cache->val_type:0);
887 1017
 error:
1018
+	tmpv->s="";
1019
+	tmpv->len=0;
888 1020
 	return -1;
889 1021
 }
890 1022
 
... ...
@@ -1047,9 +1179,11 @@ inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2)
1047 1179
 			*res=v1 <= v2;
1048 1180
 			break;
1049 1181
 		case RVE_EQ_OP:
1182
+		case RVE_IEQ_OP:
1050 1183
 			*res=v1 == v2;
1051 1184
 			break;
1052 1185
 		case RVE_DIFF_OP:
1186
+		case RVE_IDIFF_OP:
1053 1187
 			*res=v1 != v2;
1054 1188
 			break;
1055 1189
 		case RVE_CONCAT_OP:
... ...
@@ -1068,12 +1202,19 @@ inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2)
1068 1202
 inline static int bool_strop2( enum rval_expr_op op, int* res,
1069 1203
 								str* s1, str* s2)
1070 1204
 {
1071
-	if (s1->len!=s2->len)
1072
-		*res= op==RVE_DIFF_OP;
1073
-	else if (memcmp(s1->s, s2->s, s1->len)==0)
1074
-		*res= op==RVE_EQ_OP;
1075
-	else
1076
-		*res= op==RVE_DIFF_OP;
1205
+	switch(op){
1206
+		case RVE_EQ_OP:
1207
+		case RVE_STREQ_OP:
1208
+			*res= (s1->len==s2->len) && (memcmp(s1->s, s2->s, s1->len)==0);
1209
+			break;
1210
+		case RVE_DIFF_OP:
1211
+		case RVE_STRDIFF_OP:
1212
+			*res= (s1->len!=s2->len) || (memcmp(s1->s, s2->s, s1->len)!=0);
1213
+			break;
1214
+		default:
1215
+			BUG("rv unsupported intop %d\n", op);
1216
+			return -1;
1217
+	}
1077 1218
 	return 0;
1078 1219
 }
1079 1220
 
... ...
@@ -1386,9 +1527,11 @@ error:
1386 1527
 /** checks if rv is defined.
1387 1528
  * @param res - set to the result 1 - defined, 0 not defined
1388 1529
  * @return 0 on success, -1 on error
1389
- * Can use cached rvalues (c1).
1390
- * Note: a rv can be undefined if it's an undefined avp or pvar or
1530
+ * Can use cached rvalues (cache).
1531
+ * Note: a rv can be undefined if it's an undefined avp or pvar or select or
1391 1532
  * if it's NONE
1533
+ * Note2: an error in the avp, pvar or select search is equivalent to 
1534
+ *  undefined (and it's not reported)
1392 1535
  */
1393 1536
 inline static int rv_defined(struct run_act_ctx* h,
1394 1537
 						 struct sip_msg* msg, int* res,
... ...
@@ -1397,13 +1540,21 @@ inline static int rv_defined(struct run_act_ctx* h,
1397 1540
 	avp_t* r_avp;
1398 1541
 	int_str avp_val;
1399 1542
 	pv_value_t pval;
1543
+	str tmp;
1400 1544
 	
1401 1545
 	*res=1;
1402 1546
 	switch(rv->type){
1547
+		case RV_SEL:
1548
+			if (unlikely(cache && cache->cache_type==RV_CACHE_SELECT)){
1549
+				*res=(cache->val_type!=RV_NONE);
1550
+			}else
1551
+				/* run select returns 0 on success, -1 on error and >0 on 
1552
+				   undefined. error is considered undefined */
1553
+				*res=(run_select(&tmp, &rv->v.sel, msg)==0);
1554
+			break;
1403 1555
 		case RV_AVP:
1404 1556
 			if (unlikely(cache && cache->cache_type==RV_CACHE_AVP)){
1405
-				if (cache->val_type==RV_NONE)
1406
-					*res=0;
1557
+				*res=(cache->val_type!=RV_NONE);
1407 1558
 			}else{
1408 1559
 				r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
1409 1560
 											&avp_val, rv->v.avps.index);
... ...
@@ -1415,8 +1566,7 @@ inline static int rv_defined(struct run_act_ctx* h,
1415 1566
 		case RV_PVAR:
1416 1567
 			/* PV_VAL_NULL or pv_get_spec_value error => undef */
1417 1568
 			if (unlikely(cache && cache->cache_type==RV_CACHE_PVAR)){
1418
-				if (cache->val_type==RV_NONE)
1419
-					*res=0;
1569
+				*res=(cache->val_type!=RV_NONE);
1420 1570
 			}else{
1421 1571
 				memset(&pval, 0, sizeof(pval));
1422 1572
 				if (likely(pv_get_spec_value(msg, &rv->v.pvs, &pval)==0)){
... ...
@@ -1467,7 +1617,7 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1467 1617
 						int* res, struct rval_expr* rve)
1468 1618
 {
1469 1619
 	int i1, i2, ret;
1470
-	struct rval_cache c1;
1620
+	struct rval_cache c1, c2;
1471 1621
 	struct rvalue* rv1;
1472 1622
 	struct rvalue* rv2;
1473 1623
 	
... ...
@@ -1495,6 +1645,8 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1495 1645
 		case RVE_GTE_OP:
1496 1646
 		case RVE_LT_OP:
1497 1647
 		case RVE_LTE_OP:
1648
+		case RVE_IEQ_OP:
1649
+		case RVE_IDIFF_OP:
1498 1650
 			if (unlikely(
1499 1651
 					(ret=rval_expr_eval_int(h, msg, &i1, rve->left.rve)) <0) )
1500 1652
 				break;
... ...
@@ -1534,10 +1686,14 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1534 1686
 		case RVE_EQ_OP:
1535 1687
 		case RVE_DIFF_OP:
1536 1688
 			/* if left is string, eval left & right as string and
1537
-			   use string diff, else eval as int */
1689
+			 *   use string diff.
1690
+			 * if left is int eval as int using int diff
1691
+			 * if left is undef, look at right and convert to right type
1692
+			 */
1538 1693
 			rval_cache_init(&c1);
1539 1694
 			if (unlikely( (ret=rval_expr_eval_rvint(h, msg, &rv1, &i1,
1540 1695
 													rve->left.rve, &c1))<0)){
1696
+				/* error */
1541 1697
 				rval_cache_clean(&c1);
1542 1698
 				break;
1543 1699
 			}
... ...
@@ -1546,20 +1702,67 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1546 1702
 				rval_cache_clean(&c1);
1547 1703
 				if (unlikely( (ret=rval_expr_eval_int(h, msg, &i2,
1548 1704
 														rve->right.rve)) <0) )
1549
-					break;
1705
+					break;  /* error */
1550 1706
 				ret=int_intop2(res, rve->op, i1, i2);
1551 1707
 			}else{
1552
-				if (unlikely((rv2=rval_expr_eval(h, msg,
1553
-													rve->right.rve))==0)){
1708
+				/* not int => str or undef */
1709
+				/* check for undefined left operand */
1710
+				if (unlikely( c1.cache_type!=RV_CACHE_EMPTY &&
1711
+								c1.val_type==RV_NONE)){
1712
+#ifdef UNDEF_EQ_ALWAYS_FALSE
1713
+					/* undef == something  always false
1714
+					   undef != something  always true*/
1715
+					ret=(rve->op==RVE_DIFF_OP);
1716
+#elif defined UNDEF_EQ_UNDEF_TRUE
1717
+					/* undef == something defined always false
1718
+					   undef == undef true */
1719
+					if (int_rve_defined(h, msg, &i2, rve->right.rve)<0){
1720
+						/* error */
1721
+						rval_cache_clean(&c1);
1722
+						rval_destroy(rv1);
1723
+						break;
1724
+					}
1725
+					ret=(!i2) ^ (rve->op==RVE_DIFF_OP);
1726
+#else  /* ! UNDEF_EQ_* */
1727
+					/*  undef == val
1728
+					 *  => convert to (type_of(val)) (undef) == val */
1729
+					rval_cache_init(&c2);
1730
+					if (unlikely( (ret=rval_expr_eval_rvint(h, msg, &rv2, &i2,
1731
+													rve->right.rve, &c2))<0)){
1732
+						/* error */
1733
+						rval_cache_clean(&c1);
1734
+						rval_cache_clean(&c2);
1735
+						rval_destroy(rv1);
1736
+						break;
1737
+					}
1738
+					if (rv2==0){
1739
+						/* int */
1740
+						ret=int_intop2(res, rve->op, 0 /* undef */, i2);
1741
+					}else{
1742
+						/* str or undef */
1743
+						ret=rval_str_lop2(h, msg, res, rve->op, rv1, &c1,
1744
+											rv2, &c2);
1745
+						rval_cache_clean(&c2);
1746
+						rval_destroy(rv2);
1747
+					}
1748
+#endif /* UNDEF_EQ_* */
1749
+					rval_cache_clean(&c1);
1554 1750
 					rval_destroy(rv1);
1751
+				}else{ 
1752
+					/* left value == defined and != int => str
1753
+					 * => lval == (str) val */
1754
+					if (unlikely((rv2=rval_expr_eval(h, msg,
1755
+														rve->right.rve))==0)){
1756
+						/* error */
1757
+						rval_destroy(rv1);
1758
+						rval_cache_clean(&c1);
1759
+						break;
1760
+					}
1761
+					ret=rval_str_lop2(h, msg, res, rve->op, rv1, &c1, rv2, 0);
1555 1762
 					rval_cache_clean(&c1);
1556
-					ret=-1;
1557
-					break;
1763
+					rval_destroy(rv1);
1764
+					rval_destroy(rv2);
1558 1765
 				}
1559
-				ret=rval_str_lop2(h, msg, res, rve->op, rv1, &c1, rv2, 0);
1560
-				rval_cache_clean(&c1);
1561
-				rval_destroy(rv1);
1562
-				rval_destroy(rv2);
1563 1766
 			}
1564 1767
 			break;
1565 1768
 #if 0
... ...
@@ -1586,6 +1789,21 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1586 1789
 		case RVE_DEFINED_OP:
1587 1790
 			ret=int_rve_defined(h, msg, res, rve->left.rve);
1588 1791
 			break;
1792
+		case RVE_STREQ_OP:
1793
+		case RVE_STRDIFF_OP:
1794
+			if (unlikely((rv1=rval_expr_eval(h, msg, rve->left.rve))==0)){
1795
+				ret=-1;
1796
+				break;
1797
+			}
1798
+			if (unlikely((rv2=rval_expr_eval(h, msg, rve->right.rve))==0)){
1799
+				rval_destroy(rv1);
1800
+				ret=-1;
1801
+				break;
1802
+			}
1803
+			ret=rval_str_lop2(h, msg, res, rve->op, rv1, 0, rv2, 0);
1804
+			rval_destroy(rv1);
1805
+			rval_destroy(rv2);
1806
+			break;
1589 1807
 		case RVE_STRLEN_OP:
1590 1808
 		case RVE_STREMPTY_OP:
1591 1809
 			if (unlikely((rv1=rval_expr_eval(h, msg, rve->left.rve))==0)){
... ...
@@ -1666,7 +1884,11 @@ int rval_expr_eval_rvint(			   struct run_act_ctx* h,
1666 1884
 		case RVE_LTE_OP:
1667 1885
 		case RVE_EQ_OP:
1668 1886
 		case RVE_DIFF_OP:
1887
+		case RVE_IEQ_OP:
1888
+		case RVE_IDIFF_OP:
1669 1889
 		case RVE_IPLUS_OP:
1890
+		case RVE_STREQ_OP:
1891
+		case RVE_STRDIFF_OP:
1670 1892
 		case RVE_STRLEN_OP:
1671 1893
 		case RVE_STREMPTY_OP:
1672 1894
 		case RVE_DEFINED_OP:
... ...
@@ -1764,7 +1986,11 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
1764 1986
 		case RVE_LTE_OP:
1765 1987
 		case RVE_EQ_OP:
1766 1988
 		case RVE_DIFF_OP:
1989
+		case RVE_IEQ_OP:
1990
+		case RVE_IDIFF_OP:
1767 1991
 		case RVE_IPLUS_OP:
1992
+		case RVE_STREQ_OP:
1993
+		case RVE_STRDIFF_OP:
1768 1994
 		case RVE_STRLEN_OP:
1769 1995
 		case RVE_STREMPTY_OP:
1770 1996
 		case RVE_DEFINED_OP:
... ...
@@ -1820,6 +2046,7 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
1820 2046
 					}
1821 2047
 					break;
1822 2048
 				case RV_STR:
2049
+				case RV_NONE:
1823 2050
 					rv2=rval_expr_eval(h, msg, rve->right.rve);
1824 2051
 					if (unlikely(rv2==0)){
1825 2052
 						ERR("rval expression evaluation failed\n");
... ...
@@ -1830,9 +2057,6 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
1830 2057
 					break;
1831 2058
 				default:
1832 2059
 					BUG("rv unsupported basic type %d\n", type);
1833
-				case RV_NONE:
1834
-					rval_cache_clean(&c1);
1835
-					goto error;
1836 2060
 			}
1837 2061
 			rval_cache_clean(&c1);
1838 2062
 			break;
... ...
@@ -2019,6 +2243,10 @@ struct rval_expr* mk_rval_expr2(enum rval_expr_op op, struct rval_expr* rve1,
2019 2243
 		case RVE_IPLUS_OP:
2020 2244
 		case RVE_EQ_OP:
2021 2245
 		case RVE_DIFF_OP:
2246
+		case RVE_IEQ_OP:
2247
+		case RVE_IDIFF_OP:
2248
+		case RVE_STREQ_OP:
2249
+		case RVE_STRDIFF_OP:
2022 2250
 		case RVE_CONCAT_OP:
2023 2251
 			break;
2024 2252
 		default:
... ...
@@ -2056,6 +2284,9 @@ static int rve_op_is_assoc(enum rval_expr_op op)
2056 2284
 		case RVE_MINUS_OP:
2057 2285
 			return 0;
2058 2286
 		case RVE_PLUS_OP:
2287
+			/* the generic plus is not assoc, e.g.
2288
+			   "a" + 1 + "2" => "a12" in one case and "a3" in the other */
2289
+			return 0;
2059 2290
 		case RVE_IPLUS_OP:
2060 2291
 		case RVE_CONCAT_OP:
2061 2292
 		case RVE_MUL_OP:
... ...
@@ -2071,6 +2302,10 @@ static int rve_op_is_assoc(enum rval_expr_op op)
2071 2302
 		case RVE_LTE_OP:
2072 2303
 		case RVE_EQ_OP:
2073 2304
 		case RVE_DIFF_OP:
2305
+		case RVE_IEQ_OP:
2306
+		case RVE_IDIFF_OP:
2307
+		case RVE_STREQ_OP:
2308
+		case RVE_STRDIFF_OP:
2074 2309
 			return 0;
2075 2310
 	}
2076 2311
 	return 0;
... ...
@@ -2079,7 +2314,7 @@ static int rve_op_is_assoc(enum rval_expr_op op)
2079 2314
 
2080 2315
 
2081 2316
 /** returns true if the operator is commutative. */
2082
-static int rve_op_is_commutative(enum rval_expr_op op, enum rval_type type)
2317
+static int rve_op_is_commutative(enum rval_expr_op op)
2083 2318
 {
2084 2319
 	switch(op){
2085 2320
 		case RVE_NONE_OP:
... ...
@@ -2096,23 +2331,34 @@ static int rve_op_is_commutative(enum rval_expr_op op, enum rval_type type)
2096 2331
 		case RVE_MINUS_OP:
2097 2332
 			return 0;
2098 2333
 		case RVE_PLUS_OP:
2099
-			return type==RV_INT; /* commutative only for INT*/
2334
+			/* non commut. when diff. type 
2335
+			   (e.g 1 + "2" != "2" + 1 ) => non commut. in general
2336
+			   (specific same type versions are covered by IPLUS & CONCAT) */
2337
+			return 0;
2100 2338
 		case RVE_IPLUS_OP:
2101 2339
 		case RVE_MUL_OP:
2102 2340
 		case RVE_BAND_OP:
2103 2341
 		case RVE_BOR_OP:
2104
-			return 1;
2105 2342
 		case RVE_LAND_OP:
2106 2343
 		case RVE_LOR_OP:
2344
+		case RVE_IEQ_OP:
2345
+		case RVE_IDIFF_OP:
2346
+		case RVE_STREQ_OP:
2347
+		case RVE_STRDIFF_OP:
2107 2348
 			return 1;
2108 2349
 		case RVE_GT_OP:
2109 2350
 		case RVE_GTE_OP:
2110 2351
 		case RVE_LT_OP:
2111 2352
 		case RVE_LTE_OP:
2112
-		case RVE_EQ_OP:
2113
-		case RVE_DIFF_OP:
2114 2353
 		case RVE_CONCAT_OP:
2115 2354
 			return 0;
2355
+		case RVE_DIFF_OP:
2356
+		case RVE_EQ_OP:
2357
+			/* non. commut. in general, only for same type e.g.:
2358
+			   "" == 0  diff. 0 == "" ( "" == "0" and 0 == 0)
2359
+			   same type versions are covered by IEQ, IDIFF, STREQ, STRDIFF
2360
+			 */
2361
+			return 0 /* asymmetrical undef handling */;
2116 2362
 	}
2117 2363
 	return 0;
2118 2364
 }
... ...
@@ -2421,8 +2667,19 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
2421 2667
 			case RVE_PLUS_OP:
2422 2668
 			case RVE_IPLUS_OP:
2423 2669
 				/* we must make sure that this is an int PLUS
2424
-				   (because "foo"+0 is valid => "foo0") */
2425
-				if ((i==0) && ((op==RVE_IPLUS_OP)||(rve_type==RV_INT))){
2670
+				   (because "foo"+0 is valid => "foo0")
2671
+				  Even if overall type is RV_INT, it's still not safe
2672
+				  to optimize a generic PLUS: 0 + $v is not always equivalent
2673
+				  to $v (e.g. 0+"1" ==1 != "1") => optimize only if
2674
+				  IPLUS (always safe since it converts to int first) or
2675
+				  if generic PLUS and result is integer (rve_type) and
2676
+				  expression is of the form $v+ct (and not ct+$v).
2677
+				  TODO: dropping PLUS_OP all together and relying on the
2678
+				   optimizer replacing safe PLUS_OP with IPLUS_OP or CONCAT_OP
2679
+				   will simplify things.
2680
+				 */
2681
+				if ((i==0) && ((op==RVE_IPLUS_OP)||
2682
+							(rve_type==RV_INT && ct_rve==rve->right.rve))){
2426 2683
 					/* $v +  0 -> $v
2427 2684
 					 *  0 + $v -> $v */
2428 2685
 					rve_destroy(ct_rve);
... ...
@@ -2484,6 +2741,7 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
2484 2741
 				}
2485 2742
 				break;
2486 2743
 			case RVE_EQ_OP:
2744
+			case RVE_STREQ_OP:
2487 2745
 				if (rv->v.s.len==0){
2488 2746
 					/* $v == "" -> strempty($v) 
2489 2747
 					   "" == $v -> strempty ($v) */
... ...
@@ -2600,6 +2858,25 @@ static int rve_optimize(struct rval_expr* rve)
2600 2858
 						rve->fpos.e_line, rve->fpos.e_col);
2601 2859
 			}
2602 2860
 		}
2861
+		/* e1 EQ_OP e2 -> change op if we know e1 basic type
2862
+		   e1 DIFF_OP e2 -> change op if we know e2 basic type */
2863
+		if (rve->op==RVE_EQ_OP || rve->op==RVE_DIFF_OP){
2864
+			l_type=rve_guess_type(rve->left.rve);
2865
+			if (l_type==RV_INT){
2866
+				rve->op=(rve->op==RVE_EQ_OP)?RVE_IEQ_OP:RVE_IDIFF_OP;
2867
+				DBG("FIXUP RVE (%d,%d-%d,%d): changed ==/!= into interger"
2868
+						" ==/!=\n",
2869
+						rve->fpos.s_line, rve->fpos.s_col,
2870
+						rve->fpos.e_line, rve->fpos.e_col);
2871
+			}else if (l_type==RV_STR){
2872
+				rve->op=RVE_CONCAT_OP;
2873
+				rve->op=(rve->op==RVE_EQ_OP)?RVE_STREQ_OP:RVE_STRDIFF_OP;
2874
+				DBG("FIXUP RVE (%d,%d-%d,%d): changed ==/!= into string"
2875
+						" ==/!=\n",
2876
+						rve->fpos.s_line, rve->fpos.s_col,
2877
+						rve->fpos.e_line, rve->fpos.e_col);
2878
+			}
2879
+		}
2603 2880
 		
2604 2881
 		/* $v * 0 => 0; $v * 1 => $v (for *, /, &, |, &&, ||, +, -) */
2605 2882
 		if (rve_opt_01(rve, type)==1){
... ...
@@ -2651,7 +2928,7 @@ static int rve_optimize(struct rval_expr* rve)
2651 2928
 								trv->v.s.len, trv->v.s.s, rve->op);
2652 2929
 					ret=1;
2653 2930
 				}else if (rve_is_constant(rve->left.rve->left.rve) &&
2654
-							rve_op_is_commutative(rve->op, type)){
2931
+							rve_op_is_commutative(rve->op)){
2655 2932
 					/* op(op(a, $v), b) => op(op(a, b), $v) */
2656 2933
 					/* rv= op(a, b) */
2657 2934
 					tmp_rve.op=rve->op;
... ...
@@ -2693,7 +2970,7 @@ static int rve_optimize(struct rval_expr* rve)
2693 2970
 			if ((rve->op==rve->right.rve->op) && rve_op_is_assoc(rve->op)){
2694 2971
 				/* op(a, op(...)) */
2695 2972
 				if (rve_is_constant(rve->right.rve->right.rve) &&
2696
-						rve_op_is_commutative(rve->op, type)){
2973
+						rve_op_is_commutative(rve->op)){
2697 2974
 					/* op(a, op($v, b)) => op(op(a, b), $v) */
2698 2975
 					/* rv= op(a, b) */
2699 2976
 					tmp_rve.op=rve->op;
... ...
@@ -2824,6 +3101,10 @@ int fix_rval_expr(void** p)
2824 3101
 		case RVE_IPLUS_OP:
2825 3102
 		case RVE_EQ_OP:
2826 3103
 		case RVE_DIFF_OP:
3104
+		case RVE_IEQ_OP:
3105
+		case RVE_IDIFF_OP:
3106
+		case RVE_STREQ_OP:
3107
+		case RVE_STRDIFF_OP:
2827 3108
 		case RVE_CONCAT_OP:
2828 3109
 			ret=fix_rval_expr((void**)&rve->left.rve);
2829 3110
 			if (ret<0) return ret;
... ...
@@ -23,6 +23,8 @@
23 23
  * History:
24 24
  * --------
25 25
  *  2008-11-30  initial version (andrei)
26
+ *  2009-04-28  added string and interger versions for the EQ and DIFF
27
+ *              operators (andrei)
26 28
  */
27 29
 
28 30
 #ifndef _rvalue_h_
... ...
@@ -59,6 +61,8 @@ enum rval_expr_op{
59 61
 	RVE_GTE_OP,   /*  2 members, returns left >= right */
60 62
 	RVE_LT_OP,    /*  2 members, returns left  < right */
61 63
 	RVE_LTE_OP,   /*  2 members, returns left <= right */
64
+	RVE_IEQ_OP, /*  2 members, int == version, returns left == right */
65
+	RVE_IDIFF_OP,/* 2 members, int != version, returns left != right */
62 66
 	RVE_IPLUS_OP, /* 2 members, integer +, returns int(a)+int(b) */
63 67
 	/* common int & str */
64 68
 	RVE_PLUS_OP,  /* generic plus (int or str) returns left + right */
... ...
@@ -68,6 +72,8 @@ enum rval_expr_op{
68 72
 	RVE_CONCAT_OP,/* 2 members, string concat, returns left . right (str)*/
69 73
 	RVE_STRLEN_OP, /* one member, string length:, returns strlen(val) (int)*/
70 74
 	RVE_STREMPTY_OP, /* one member, returns val=="" (bool) */
75
+	RVE_STREQ_OP,  /* 2 members, string == , returns left == right (bool)*/
76
+	RVE_STRDIFF_OP,/* 2 members, string != , returns left != right (bool)*/
71 77
 	/* avp, pvars a.s.o */
72 78
 	RVE_DEFINED_OP, /* one member, returns is_defined(val) (bool) */
73 79
 };
... ...
@@ -118,7 +124,8 @@ struct rval_expr{
118 124
 enum rval_cache_type{
119 125
 	RV_CACHE_EMPTY,
120 126
 	RV_CACHE_PVAR,
121
-	RV_CACHE_AVP
127
+	RV_CACHE_AVP,
128
+	RV_CACHE_SELECT
122 129
 };
123 130
 
124 131
 /** value cache for a rvalue struct.