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 775
 <INITIAL>{STRLEN}	{ count(); return STRLEN; }
776 776
 <INITIAL>{STREMPTY}	{ count(); return STREMPTY; }
777 777
 <INITIAL>{DEFINED}	{ count(); return DEFINED; }
778
+<INITIAL>{STREQ}	{ count(); return STREQ; }
779
+<INITIAL>{INTEQ}	{ count(); return INTEQ; }
780
+<INITIAL>{STRDIFF}	{ count(); return STRDIFF; }
781
+<INITIAL>{INTDIFF}	{ count(); return INTDIFF; }
778 782
 
779 783
 <INITIAL>{SELECT_MARK}  { count(); state = SELECT_S; BEGIN(SELECT); return SELECT_MARK; }
780 784
 <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 1583
 equalop:
1584 1584
 	EQUAL_T {$$=EQUAL_OP; }
1585 1585
 	| DIFF	{$$=DIFF_OP; }
1586
+	| STREQ	{$$=EQUAL_OP; }  /* for expr. elems equiv. to EQUAL_T*/
1587
+	| STRDIFF {$$=DIFF_OP; } /* for expr. elems. equiv. to DIFF */
1586 1588
 	;
1587 1589
 cmpop:
1588 1590
 	  GT	{$$=GT_OP; }
... ...
@@ -1600,6 +1605,10 @@ strop:
1600 1600
 rve_equalop:
1601 1601
 	EQUAL_T {$$=RVE_EQ_OP; }
1602 1602
 	| DIFF	{$$=RVE_DIFF_OP; }
1603
+	| INTEQ	{$$=RVE_IEQ_OP; }
1604
+	| INTDIFF {$$=RVE_IDIFF_OP; }
1605
+	| STREQ	{$$=RVE_STREQ_OP; }
1606
+	| STRDIFF {$$=RVE_STRDIFF_OP; }
1603 1607
 	;
1604 1608
 rve_cmpop:
1605 1609
 	  GT	{$$=RVE_GT_OP; }
... ...
@@ -2217,9 +2226,9 @@ rval: intno			{$$=mk_rve_rval(RV_INT, (void*)$1); }
2217 2217
 	| fcmd				{$$=mk_rve_rval(RV_ACTION_ST, $1); }
2218 2218
 	| exp_elem { $$=mk_rve_rval(RV_BEXPR, $1); }
2219 2219
 	| LBRACE actions RBRACE	{$$=mk_rve_rval(RV_ACTION_ST, $2); }
2220
-	| LBRACE error RBRACE	{ yyerror("bad command block"); }
2220
+	| LBRACE error RBRACE	{ $$=0; yyerror("bad command block"); }
2221 2221
 	| LPAREN assign_action RPAREN	{$$=mk_rve_rval(RV_ACTION_ST, $2); }
2222
-	| LPAREN error RPAREN	{ yyerror("bad expression"); }
2222
+	| LPAREN error RPAREN	{ $$=0; yyerror("bad expression"); }
2223 2223
 	;
2224 2224
 
2225 2225
 
... ...
@@ -2237,10 +2246,11 @@ rve_op:		PLUS		{ $$=RVE_PLUS_OP; }
2237 2237
 */
2238 2238
 
2239 2239
 rval_expr: rval						{ $$=$1;
2240
-											if ($$==0){
2240
+										/*	if ($$==0){
2241 2241
 												yyerror("out of memory\n");
2242 2242
 												YYABORT;
2243 2243
 											}
2244
+											*/
2244 2245
 									}
2245 2246
 		| rve_un_op %prec NOT rval_expr	{$$=mk_rve1($1, $2); }
2246 2247
 		| rval_expr PLUS rval_expr		{$$=mk_rve2(RVE_PLUS_OP, $1, $3); }
... ...
@@ -2258,7 +2268,7 @@ rval_expr: rval						{ $$=$1;
2258 2258
 		| STRLEN LPAREN rval_expr RPAREN { $$=mk_rve1(RVE_STRLEN_OP, $3);}
2259 2259
 		| STREMPTY LPAREN rval_expr RPAREN {$$=mk_rve1(RVE_STREMPTY_OP, $3);}
2260 2260
 		| DEFINED rval_expr				{ $$=mk_rve1(RVE_DEFINED_OP, $2);}
2261
-		| rve_un_op %prec NOT error		{ yyerror("bad expression"); }
2261
+		| rve_un_op %prec NOT error		{ $$=0; yyerror("bad expression"); }
2262 2262
 		| rval_expr PLUS error			{ yyerror("bad expression"); }
2263 2263
 		| rval_expr MINUS error			{ yyerror("bad expression"); }
2264 2264
 		| rval_expr STAR error			{ yyerror("bad expression"); }
... ...
@@ -2271,9 +2281,9 @@ rval_expr: rval						{ $$=$1;
2271 2271
 			{ yyerror("bad expression"); }
2272 2272
 		| rval_expr LOG_AND error		{ yyerror("bad expression"); }
2273 2273
 		| 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"); }
2274
+		| STRLEN LPAREN error RPAREN	{ $$=0; yyerror("bad expression"); }
2275
+		| STREMPTY LPAREN error RPAREN	{ $$=0; yyerror("bad expression"); }
2276
+		| DEFINED error					{ $$=0; yyerror("bad expression"); }
2277 2277
 		;
2278 2278
 
2279 2279
 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 2901
 	
2902 2902
 	if ((rve1==0) || (rve2==0))
2903 2903
 		return 0;
2904
+	bad_rve=0;
2905
+	bad_t=0;
2906
+	exp_t=0;
2904 2907
 	cfg_pos_join(&pos, &rve1->fpos, &rve2->fpos);
2905 2908
 	ret=mk_rval_expr2(op, rve1, rve2, &pos);
2906 2909
 	if (ret && (rve_check_type(&type, ret, &bad_rve, &bad_t, &exp_t)!=1)){
2907
-		yyerror_at(&pos, "bad expression: type mismatch:"
2910
+		if (bad_rve)
2911
+			yyerror_at(&pos, "bad expression: type mismatch:"
2908 2912
 						" %s instead of %s at (%d,%d)",
2909 2913
 						rval_type_name(bad_t), rval_type_name(exp_t),
2910 2914
 						bad_rve->fpos.s_line, bad_rve->fpos.s_col);
2915
+		else
2916
+			yyerror("BUG: unexpected null \"bad\" expression\n");
2911 2917
 	}
2912 2918
 	return ret;
2913 2919
 }
... ...
@@ -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 111
 
112 112
 void rval_cache_clean(struct rval_cache* rvc)
113 113
 {
114
-	if (rvc->cache_type==RV_CACHE_PVAR){
114
+	if ((rvc->cache_type==RV_CACHE_PVAR) && (rvc->val_type!=RV_NONE)){
115 115
 		pv_value_destroy(&rvc->c.pval);
116 116
 	}
117 117
 	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 261
   * rval_cache_clean()'en when no longer needed.
262 262
   *
263 263
   * @param rv - target rvalue
264
-  * @param val_cache - value cache, might be filled if non-null, 
264
+  * @param val_cache - write-only: value cache, might be filled if non-null,
265 265
   *                    it _must_ be rval_cache_clean()'en when done.
266 266
   * @return - basic type or RV_NONE on error
267 267
   */
... ...
@@ -288,36 +307,39 @@ inline static enum rval_type rval_get_btype(struct run_act_ctx* h,
288 288
 		case RV_PVAR:
289 289
 			if (likely(val_cache && val_cache->cache_type==RV_CACHE_EMPTY)){
290 290
 				pv=&val_cache->c.pval;
291
+				val_cache->cache_type=RV_CACHE_PVAR;
291 292
 			}else{
292 293
 				val_cache=0;
293 294
 				pv=&tmp_pval;
294 295
 			}
295 296
 			memset(pv, 0, sizeof(tmp_pval));
296 297
 			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;
298
+				if (pv->flags & PV_TYPE_INT){
299
+					if (likely(val_cache!=0))
308 300
 						val_cache->val_type=RV_INT;
309
-					}
301
+					else
302
+						pv_value_destroy(pv);
310 303
 					return RV_INT;
304
+				}else if (pv->flags & PV_VAL_STR){
305
+					if (likely(val_cache!=0))
306
+						val_cache->val_type=RV_STR;
307
+					else
308
+						pv_value_destroy(pv);
309
+					return RV_STR;
311 310
 				}else{
312 311
 					pv_value_destroy(pv);
312
+					if (likely(val_cache!=0))
313
+						val_cache->val_type=RV_NONE; /* undefined */
313 314
 					goto error;
314 315
 				}
315 316
 			}else{
317
+				if (likely(val_cache!=0))
318
+					val_cache->val_type=RV_NONE; /* undefined */
316 319
 				goto error;
317 320
 			}
318 321
 			break;
319 322
 		case RV_AVP:
320
-			if (likely(val_cache && val_cache==RV_CACHE_EMPTY)){
323
+			if (likely(val_cache && val_cache->cache_type==RV_CACHE_EMPTY)){
321 324
 				ptype=&val_cache->val_type;
322 325
 				avpv=&val_cache->c.avp_val;
323 326
 				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 337
 				}
338 338
 			}else{
339 339
 				*ptype=RV_NONE;
340
-				if (val_cache) val_cache->cache_type=RV_CACHE_EMPTY;
341 340
 				goto error;
342 341
 			}
343 342
 			break;
... ...
@@ -390,6 +411,10 @@ enum rval_type rve_guess_type( struct rval_expr* rve)
390 390
 		case RVE_LTE_OP:
391 391
 		case RVE_EQ_OP:
392 392
 		case RVE_DIFF_OP:
393
+		case RVE_IEQ_OP:
394
+		case RVE_IDIFF_OP:
395
+		case RVE_STREQ_OP:
396
+		case RVE_STRDIFF_OP:
393 397
 		case RVE_IPLUS_OP:
394 398
 		case RVE_STRLEN_OP:
395 399
 		case RVE_STREMPTY_OP:
... ...
@@ -450,6 +475,10 @@ int rve_is_constant(struct rval_expr* rve)
450 450
 		case RVE_LTE_OP:
451 451
 		case RVE_EQ_OP:
452 452
 		case RVE_DIFF_OP:
453
+		case RVE_IEQ_OP:
454
+		case RVE_IDIFF_OP:
455
+		case RVE_STREQ_OP:
456
+		case RVE_STRDIFF_OP:
453 457
 		case RVE_PLUS_OP:
454 458
 		case RVE_IPLUS_OP:
455 459
 		case RVE_CONCAT_OP:
... ...
@@ -502,6 +531,10 @@ static int rve_op_unary(enum rval_expr_op op)
502 502
 		case RVE_LTE_OP:
503 503
 		case RVE_EQ_OP:
504 504
 		case RVE_DIFF_OP:
505
+		case RVE_IEQ_OP:
506
+		case RVE_IDIFF_OP:
507
+		case RVE_STREQ_OP:
508
+		case RVE_STRDIFF_OP:
505 509
 		case RVE_PLUS_OP:
506 510
 		case RVE_IPLUS_OP:
507 511
 		case RVE_CONCAT_OP:
... ...
@@ -564,6 +597,8 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
564 564
 		case RVE_GTE_OP:
565 565
 		case RVE_LT_OP:
566 566
 		case RVE_LTE_OP:
567
+		case RVE_IEQ_OP:
568
+		case RVE_IDIFF_OP:
567 569
 		case RVE_IPLUS_OP:
568 570
 			*type=RV_INT;
569 571
 			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 644
 				}
645 645
 			}
646 646
 			break;
647
+		case RVE_STREQ_OP:
648
+		case RVE_STRDIFF_OP:
649
+			*type=RV_INT;
650
+			if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){
651
+				if (rve_check_type(&type2, rve->right.rve, bad_rve, bad_t,
652
+									exp_t)){
653
+					if ((type2!=type1) && (type1!=RV_NONE) &&
654
+							(type2!=RV_NONE) &&
655
+							!(type1==RV_STR && type2==RV_INT)){
656
+						if (bad_rve) *bad_rve=rve->right.rve;
657
+						if (bad_t) *bad_t=type2;
658
+						if (exp_t) *exp_t=type1;
659
+						return 0;
660
+					}
661
+					if (type1==RV_INT){
662
+						if (bad_rve) *bad_rve=rve->left.rve;
663
+						if (bad_t) *bad_t=type1;
664
+						if (exp_t) *exp_t=RV_STR;
665
+						return 0;
666
+					}
667
+					return 1;
668
+				}
669
+			}
670
+			break;
647 671
 		case RVE_STRLEN_OP:
648 672
 		case RVE_STREMPTY_OP:
649 673
 		case RVE_DEFINED_OP:
... ...
@@ -659,6 +718,11 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
659 659
 			}
660 660
 			break;
661 661
 		case RVE_NONE_OP:
662
+		default:
663
+			BUG("unexpected rve op %d\n", rve->op);
664
+			if (bad_rve) *bad_rve=rve;
665
+			if (bad_t) *bad_t=RV_NONE;
666
+			if (exp_t) *exp_t=RV_STR;
662 667
 			break;
663 668
 	}
664 669
 	return 0;
... ...
@@ -668,6 +732,15 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
668 668
 
669 669
 /** get the integer value of an rvalue.
670 670
   * *i=(int)rv
671
+  * if rv == undefined select, avp or pvar, return 0.
672
+  * if an error occurs while evaluating a select, avp or pvar, behave as
673
+  * for the undefined case (and return success).
674
+  * @param h - script context handle
675
+  * @param msg - sip msg
676
+  * @param i   - pointer to int, where the conversion result will be stored
677
+  * @param rv   - rvalue to be converted
678
+  * @param cache - cached rv value (read-only), can be 0
679
+  *
671 680
   * @return 0 on success, \<0 on error and EXPR_DROP on drop
672 681
  */
673 682
 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 677
 	avp_t* r_avp;
678 678
 	int_str avp_val;
679 679
 	pv_value_t pval;
680
+	str tmp;
681
+	str* s;
682
+	int r;
683
+	int destroy_pval;
680 684
 	
685
+	destroy_pval=0;
686
+	s=0;
681 687
 	switch(rv->type){
682 688
 		case RV_INT:
683 689
 			*i=rv->v.l;
684 690
 			break;
685 691
 		case RV_STR:
692
+			s=&rv->v.s;
686 693
 			goto rv_str;
687 694
 		case RV_BEXPR:
688 695
 			*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 698
 				*i=0;
699 699
 			break;
700 700
 		case RV_SEL:
701
+			r=run_select(&tmp, &rv->v.sel, msg);
702
+			if (unlikely(r!=0)){
703
+				if (r<0)
704
+					goto eval_error;
705
+				else /* i>0  => undefined */
706
+					goto undef;
707
+			}
708
+			s=&tmp;
701 709
 			goto rv_str;
702 710
 		case RV_AVP:
703 711
 			if (unlikely(cache && cache->cache_type==RV_CACHE_AVP)){
704 712
 				if (likely(cache->val_type==RV_INT)){
705 713
 					*i=cache->c.avp_val.n;
706
-				}else if (cache->val_type==RV_STR)
714
+				}else if (cache->val_type==RV_STR){
715
+					s=&cache->c.avp_val.s;
707 716
 					goto rv_str;
708
-				else goto error;
717
+				}else if (cache->val_type==RV_NONE)
718
+					goto undef;
719
+				else goto error_cache;
709 720
 			}else{
710 721
 				r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
711 722
 											&avp_val, rv->v.avps.index);
712 723
 				if (likely(r_avp)){
713 724
 					if (unlikely(r_avp->flags & AVP_VAL_STR)){
725
+						s=&avp_val.s;
714 726
 						goto rv_str;
715 727
 					}else{
716 728
 						*i=avp_val.n;
717 729
 					}
718 730
 				}else{
719
-					goto error;
731
+					goto undef;
720 732
 				}
721 733
 			}
722 734
 			break;
723 735
 		case RV_PVAR:
724 736
 			if (unlikely(cache && cache->cache_type==RV_CACHE_PVAR)){
725
-				if (likely((cache->val_type==RV_INT) || 
737
+				if (likely((cache->val_type==RV_INT) ||
726 738
 								(cache->c.pval.flags & PV_VAL_INT))){
727 739
 					*i=cache->c.pval.ri;
728
-				}else if (cache->val_type==RV_STR)
740
+				}else if (cache->val_type==RV_STR){
741
+					s=&cache->c.pval.rs;
729 742
 					goto rv_str;
730
-				else goto error;
743
+				}else if (cache->val_type==RV_NONE)
744
+					goto undef;
745
+				else goto error_cache;
731 746
 			}else{
732 747
 				memset(&pval, 0, sizeof(pval));
733 748
 				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 735
 						*i=pval.ri;
736 736
 						pv_value_destroy(&pval);
737 737
 					}else if (likely(pval.flags & PV_VAL_STR)){
738
-						pv_value_destroy(&pval);
738
+						destroy_pval=1; /* we must pv_value_destroy() later*/
739
+						s=&pval.rs;
739 740
 						goto rv_str;
740 741
 					}else{
742
+						/* no PV_VAL_STR and no PV_VAL_INT => undef
743
+						   (PV_VAL_NULL) */
741 744
 						pv_value_destroy(&pval);
742
-						goto error;
745
+						goto undef;
743 746
 					}
744 747
 				}else{
745
-					goto error;
748
+					goto eval_error;
746 749
 				}
747 750
 			}
748 751
 			break;
... ...
@@ -751,10 +849,27 @@ int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg,
751 751
 			goto error;
752 752
 	}
753 753
 	return 0;
754
+undef:
755
+eval_error: /* same as undefined */
756
+	/* handle undefined => result 0, return success */
757
+	*i=0;
758
+	return 0;
759
+error_cache:
760
+	BUG("invalid cached value:cache type %d, value type %d\n",
761
+			cache?cache->cache_type:0, cache?cache->val_type:0);
754 762
 rv_str:
755
-	/* rv is of string type => error */
756
-	/* ERR("string in int expression\n"); */
763
+	/* rv is of string type => try to convert it to int */
764
+	/* if "" => 0 (most likely case) */
765
+	if (likely(s->len==0)) *i=0;
766
+	else if (unlikely(str2sint(s, i)!=0)){
767
+		/* error converting to int => non numeric => 0 */
768
+		*i=0;
769
+	}
770
+	if (destroy_pval)
771
+		pv_value_destroy(&pval);
772
+	return 0;
757 773
 error:
774
+	*i=0;
758 775
 	return -1;
759 776
 }
760 777
 
... ...
@@ -762,6 +877,9 @@ error:
762 762
 
763 763
 /** get the string value of an rv in a tmp variable
764 764
   * *s=(str)rv
765
+  * if rv == undefined select, avp or pvar, return "".
766
+  * if an error occurs while evaluating a select, avp or pvar, behave as
767
+  * for the undefined case (and return success).
765 768
   * The result points either to a temporary string or inside
766 769
   * new_cache. new_cache must be non zero, initialized previously,
767 770
   * and it _must_ be rval_cache_clean(...)'ed when done.
... ...
@@ -771,9 +889,9 @@ error:
771 771
   * @param h - script context handle
772 772
   * @param msg - sip msg
773 773
   * @param tmpv - str return value (pointer to a str struct that will be
774
-  *               be filled.
774
+  *               be filled with the conversion result)
775 775
   * @param rv   - rvalue to be converted
776
-  * @param cache - cached rv value (read-only)
776
+  * @param cache - cached rv value (read-only), can be 0
777 777
   * @param tmp_cache - used for temporary storage (so that tmpv will not
778 778
   *                 point to possible freed data), it must be non-null,
779 779
   *                 initialized and cleaned afterwards.
... ...
@@ -814,10 +932,9 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
814 814
 			i=run_select(tmpv, &rv->v.sel, msg);
815 815
 			if (unlikely(i!=0)){
816 816
 				if (i<0){
817
-					goto error;
818
-				}else { /* i>0 */
819
-					tmpv->s="";
820
-					tmpv->len=0;
817
+					goto eval_error;
818
+				}else { /* i>0  => undefined */
819
+					goto undef;
821 820
 				}
822 821
 			}
823 822
 			break;
... ...
@@ -828,7 +945,9 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
828 828
 				}else if (cache->val_type==RV_INT){
829 829
 					i=cache->c.avp_val.n;
830 830
 					tmpv->s=int2str(i, &tmpv->len);
831
-				}else goto error;
831
+				}else if (cache->val_type==RV_NONE){
832
+					goto undef;
833
+				}else goto error_cache;
832 834
 			}else{
833 835
 				r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
834 836
 											&tmp_cache->c.avp_val,
... ...
@@ -842,9 +961,7 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
842 842
 						i=tmp_cache->c.avp_val.n;
843 843
 						tmpv->s=int2str(i, &tmpv->len);
844 844
 					}
845
-				}else{
846
-					goto error;
847
-				}
845
+				}else goto undef;
848 846
 			}
849 847
 			break;
850 848
 		case RV_PVAR:
... ...
@@ -854,7 +971,9 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
854 854
 				}else if (cache->val_type==RV_INT){
855 855
 					i=cache->c.pval.ri;
856 856
 					tmpv->s=int2str(i, &tmpv->len);
857
-				}else goto error;
857
+				}else if (cache->val_type==RV_NONE){
858
+					goto undef;
859
+				}else goto error_cache;
858 860
 			}else{
859 861
 				memset(&tmp_cache->c.pval, 0, sizeof(tmp_cache->c.pval));
860 862
 				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 871
 						pv_value_destroy(&tmp_cache->c.pval);
872 872
 						tmpv->s=int2str(i, &tmpv->len);
873 873
 					}else{
874
+						/* no PV_VAL_STR and no PV_VAL_INT => undef
875
+						   (PV_VAL_NULL) */
874 876
 						pv_value_destroy(&tmp_cache->c.pval);
875
-						goto error;
877
+						goto undef;
876 878
 					}
877 879
 				}else{
878
-					goto error;
880
+					goto eval_error;
879 881
 				}
880 882
 			}
881 883
 			break;
... ...
@@ -884,7 +1005,18 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
884 884
 			goto error;
885 885
 	}
886 886
 	return 0;
887
+undef:
888
+eval_error: /* same as undefined */
889
+	/* handle undefined => result "", return success */
890
+	tmpv->s="";
891
+	tmpv->len=0;
892
+	return 0;
893
+error_cache:
894
+	BUG("invalid cached value:cache type %d, value type %d\n",
895
+			cache?cache->cache_type:0, cache?cache->val_type:0);
887 896
 error:
897
+	tmpv->s="";
898
+	tmpv->len=0;
888 899
 	return -1;
889 900
 }
890 901
 
... ...
@@ -1047,9 +1179,11 @@ inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2)
1047 1047
 			*res=v1 <= v2;
1048 1048
 			break;
1049 1049
 		case RVE_EQ_OP:
1050
+		case RVE_IEQ_OP:
1050 1051
 			*res=v1 == v2;
1051 1052
 			break;
1052 1053
 		case RVE_DIFF_OP:
1054
+		case RVE_IDIFF_OP:
1053 1055
 			*res=v1 != v2;
1054 1056
 			break;
1055 1057
 		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 1068
 inline static int bool_strop2( enum rval_expr_op op, int* res,
1069 1069
 								str* s1, str* s2)
1070 1070
 {
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;
1071
+	switch(op){
1072
+		case RVE_EQ_OP:
1073
+		case RVE_STREQ_OP:
1074
+			*res= (s1->len==s2->len) && (memcmp(s1->s, s2->s, s1->len)==0);
1075
+			break;
1076
+		case RVE_DIFF_OP:
1077
+		case RVE_STRDIFF_OP:
1078
+			*res= (s1->len!=s2->len) || (memcmp(s1->s, s2->s, s1->len)!=0);
1079
+			break;
1080
+		default:
1081
+			BUG("rv unsupported intop %d\n", op);
1082
+			return -1;
1083
+	}
1077 1084
 	return 0;
1078 1085
 }
1079 1086
 
... ...
@@ -1386,9 +1527,11 @@ error:
1386 1386
 /** checks if rv is defined.
1387 1387
  * @param res - set to the result 1 - defined, 0 not defined
1388 1388
  * @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
1389
+ * Can use cached rvalues (cache).
1390
+ * Note: a rv can be undefined if it's an undefined avp or pvar or select or
1391 1391
  * if it's NONE
1392
+ * Note2: an error in the avp, pvar or select search is equivalent to 
1393
+ *  undefined (and it's not reported)
1392 1394
  */
1393 1395
 inline static int rv_defined(struct run_act_ctx* h,
1394 1396
 						 struct sip_msg* msg, int* res,
... ...
@@ -1397,13 +1540,21 @@ inline static int rv_defined(struct run_act_ctx* h,
1397 1397
 	avp_t* r_avp;
1398 1398
 	int_str avp_val;
1399 1399
 	pv_value_t pval;
1400
+	str tmp;
1400 1401
 	
1401 1402
 	*res=1;
1402 1403
 	switch(rv->type){
1404
+		case RV_SEL:
1405
+			if (unlikely(cache && cache->cache_type==RV_CACHE_SELECT)){
1406
+				*res=(cache->val_type!=RV_NONE);
1407
+			}else
1408
+				/* run select returns 0 on success, -1 on error and >0 on 
1409
+				   undefined. error is considered undefined */
1410
+				*res=(run_select(&tmp, &rv->v.sel, msg)==0);
1411
+			break;
1403 1412
 		case RV_AVP:
1404 1413
 			if (unlikely(cache && cache->cache_type==RV_CACHE_AVP)){
1405
-				if (cache->val_type==RV_NONE)
1406
-					*res=0;
1414
+				*res=(cache->val_type!=RV_NONE);
1407 1415
 			}else{
1408 1416
 				r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
1409 1417
 											&avp_val, rv->v.avps.index);
... ...
@@ -1415,8 +1566,7 @@ inline static int rv_defined(struct run_act_ctx* h,
1415 1415
 		case RV_PVAR:
1416 1416
 			/* PV_VAL_NULL or pv_get_spec_value error => undef */
1417 1417
 			if (unlikely(cache && cache->cache_type==RV_CACHE_PVAR)){
1418
-				if (cache->val_type==RV_NONE)
1419
-					*res=0;
1418
+				*res=(cache->val_type!=RV_NONE);
1420 1419
 			}else{
1421 1420
 				memset(&pval, 0, sizeof(pval));
1422 1421
 				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 1467
 						int* res, struct rval_expr* rve)
1468 1468
 {
1469 1469
 	int i1, i2, ret;
1470
-	struct rval_cache c1;
1470
+	struct rval_cache c1, c2;
1471 1471
 	struct rvalue* rv1;
1472 1472
 	struct rvalue* rv2;
1473 1473
 	
... ...
@@ -1495,6 +1645,8 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1495 1495
 		case RVE_GTE_OP:
1496 1496
 		case RVE_LT_OP:
1497 1497
 		case RVE_LTE_OP:
1498
+		case RVE_IEQ_OP:
1499
+		case RVE_IDIFF_OP:
1498 1500
 			if (unlikely(
1499 1501
 					(ret=rval_expr_eval_int(h, msg, &i1, rve->left.rve)) <0) )
1500 1502
 				break;
... ...
@@ -1534,10 +1686,14 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1534 1534
 		case RVE_EQ_OP:
1535 1535
 		case RVE_DIFF_OP:
1536 1536
 			/* if left is string, eval left & right as string and
1537
-			   use string diff, else eval as int */
1537
+			 *   use string diff.
1538
+			 * if left is int eval as int using int diff
1539
+			 * if left is undef, look at right and convert to right type
1540
+			 */
1538 1541
 			rval_cache_init(&c1);
1539 1542
 			if (unlikely( (ret=rval_expr_eval_rvint(h, msg, &rv1, &i1,
1540 1543
 													rve->left.rve, &c1))<0)){
1544
+				/* error */
1541 1545
 				rval_cache_clean(&c1);
1542 1546
 				break;
1543 1547
 			}
... ...
@@ -1546,20 +1702,67 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1546 1546
 				rval_cache_clean(&c1);
1547 1547
 				if (unlikely( (ret=rval_expr_eval_int(h, msg, &i2,
1548 1548
 														rve->right.rve)) <0) )
1549
-					break;
1549
+					break;  /* error */
1550 1550
 				ret=int_intop2(res, rve->op, i1, i2);
1551 1551
 			}else{
1552
-				if (unlikely((rv2=rval_expr_eval(h, msg,
1553
-													rve->right.rve))==0)){
1552
+				/* not int => str or undef */
1553
+				/* check for undefined left operand */
1554
+				if (unlikely( c1.cache_type!=RV_CACHE_EMPTY &&
1555
+								c1.val_type==RV_NONE)){
1556
+#ifdef UNDEF_EQ_ALWAYS_FALSE
1557
+					/* undef == something  always false
1558
+					   undef != something  always true*/
1559
+					ret=(rve->op==RVE_DIFF_OP);
1560
+#elif defined UNDEF_EQ_UNDEF_TRUE
1561
+					/* undef == something defined always false
1562
+					   undef == undef true */
1563
+					if (int_rve_defined(h, msg, &i2, rve->right.rve)<0){
1564
+						/* error */
1565
+						rval_cache_clean(&c1);
1566
+						rval_destroy(rv1);
1567
+						break;
1568
+					}
1569
+					ret=(!i2) ^ (rve->op==RVE_DIFF_OP);
1570
+#else  /* ! UNDEF_EQ_* */
1571
+					/*  undef == val
1572
+					 *  => convert to (type_of(val)) (undef) == val */
1573
+					rval_cache_init(&c2);
1574
+					if (unlikely( (ret=rval_expr_eval_rvint(h, msg, &rv2, &i2,
1575
+													rve->right.rve, &c2))<0)){
1576
+						/* error */
1577
+						rval_cache_clean(&c1);
1578
+						rval_cache_clean(&c2);
1579
+						rval_destroy(rv1);
1580
+						break;
1581
+					}
1582
+					if (rv2==0){
1583
+						/* int */
1584
+						ret=int_intop2(res, rve->op, 0 /* undef */, i2);
1585
+					}else{
1586
+						/* str or undef */
1587
+						ret=rval_str_lop2(h, msg, res, rve->op, rv1, &c1,
1588
+											rv2, &c2);
1589
+						rval_cache_clean(&c2);
1590
+						rval_destroy(rv2);
1591
+					}
1592
+#endif /* UNDEF_EQ_* */
1593
+					rval_cache_clean(&c1);
1554 1594
 					rval_destroy(rv1);
1595
+				}else{ 
1596
+					/* left value == defined and != int => str
1597
+					 * => lval == (str) val */
1598
+					if (unlikely((rv2=rval_expr_eval(h, msg,
1599
+														rve->right.rve))==0)){
1600
+						/* error */
1601
+						rval_destroy(rv1);
1602
+						rval_cache_clean(&c1);
1603
+						break;
1604
+					}
1605
+					ret=rval_str_lop2(h, msg, res, rve->op, rv1, &c1, rv2, 0);
1555 1606
 					rval_cache_clean(&c1);
1556
-					ret=-1;
1557
-					break;
1607
+					rval_destroy(rv1);
1608
+					rval_destroy(rv2);
1558 1609
 				}
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 1610
 			}
1564 1611
 			break;
1565 1612
 #if 0
... ...
@@ -1586,6 +1789,21 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1586 1586
 		case RVE_DEFINED_OP:
1587 1587
 			ret=int_rve_defined(h, msg, res, rve->left.rve);
1588 1588
 			break;
1589
+		case RVE_STREQ_OP:
1590
+		case RVE_STRDIFF_OP:
1591
+			if (unlikely((rv1=rval_expr_eval(h, msg, rve->left.rve))==0)){
1592
+				ret=-1;
1593
+				break;
1594
+			}
1595
+			if (unlikely((rv2=rval_expr_eval(h, msg, rve->right.rve))==0)){
1596
+				rval_destroy(rv1);
1597
+				ret=-1;
1598
+				break;
1599
+			}
1600
+			ret=rval_str_lop2(h, msg, res, rve->op, rv1, 0, rv2, 0);
1601
+			rval_destroy(rv1);
1602
+			rval_destroy(rv2);
1603
+			break;
1589 1604
 		case RVE_STRLEN_OP:
1590 1605
 		case RVE_STREMPTY_OP:
1591 1606
 			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 1666
 		case RVE_LTE_OP:
1667 1667
 		case RVE_EQ_OP:
1668 1668
 		case RVE_DIFF_OP:
1669
+		case RVE_IEQ_OP:
1670
+		case RVE_IDIFF_OP:
1669 1671
 		case RVE_IPLUS_OP:
1672
+		case RVE_STREQ_OP:
1673
+		case RVE_STRDIFF_OP:
1670 1674
 		case RVE_STRLEN_OP:
1671 1675
 		case RVE_STREMPTY_OP:
1672 1676
 		case RVE_DEFINED_OP:
... ...
@@ -1764,7 +1986,11 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
1764 1764
 		case RVE_LTE_OP:
1765 1765
 		case RVE_EQ_OP:
1766 1766
 		case RVE_DIFF_OP:
1767
+		case RVE_IEQ_OP:
1768
+		case RVE_IDIFF_OP:
1767 1769
 		case RVE_IPLUS_OP:
1770
+		case RVE_STREQ_OP:
1771
+		case RVE_STRDIFF_OP:
1768 1772
 		case RVE_STRLEN_OP:
1769 1773
 		case RVE_STREMPTY_OP:
1770 1774
 		case RVE_DEFINED_OP:
... ...
@@ -1820,6 +2046,7 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
1820 1820
 					}
1821 1821
 					break;
1822 1822
 				case RV_STR:
1823
+				case RV_NONE:
1823 1824
 					rv2=rval_expr_eval(h, msg, rve->right.rve);
1824 1825
 					if (unlikely(rv2==0)){
1825 1826
 						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 1830
 					break;
1831 1831
 				default:
1832 1832
 					BUG("rv unsupported basic type %d\n", type);
1833
-				case RV_NONE:
1834
-					rval_cache_clean(&c1);
1835
-					goto error;
1836 1833
 			}
1837 1834
 			rval_cache_clean(&c1);
1838 1835
 			break;
... ...
@@ -2019,6 +2243,10 @@ struct rval_expr* mk_rval_expr2(enum rval_expr_op op, struct rval_expr* rve1,
2019 2019
 		case RVE_IPLUS_OP:
2020 2020
 		case RVE_EQ_OP:
2021 2021
 		case RVE_DIFF_OP:
2022
+		case RVE_IEQ_OP:
2023
+		case RVE_IDIFF_OP:
2024
+		case RVE_STREQ_OP:
2025
+		case RVE_STRDIFF_OP:
2022 2026
 		case RVE_CONCAT_OP:
2023 2027
 			break;
2024 2028
 		default:
... ...
@@ -2056,6 +2284,9 @@ static int rve_op_is_assoc(enum rval_expr_op op)
2056 2056
 		case RVE_MINUS_OP:
2057 2057
 			return 0;
2058 2058
 		case RVE_PLUS_OP:
2059
+			/* the generic plus is not assoc, e.g.
2060
+			   "a" + 1 + "2" => "a12" in one case and "a3" in the other */
2061
+			return 0;
2059 2062
 		case RVE_IPLUS_OP:
2060 2063
 		case RVE_CONCAT_OP:
2061 2064
 		case RVE_MUL_OP:
... ...
@@ -2071,6 +2302,10 @@ static int rve_op_is_assoc(enum rval_expr_op op)
2071 2071
 		case RVE_LTE_OP:
2072 2072
 		case RVE_EQ_OP:
2073 2073
 		case RVE_DIFF_OP:
2074
+		case RVE_IEQ_OP:
2075
+		case RVE_IDIFF_OP:
2076
+		case RVE_STREQ_OP:
2077
+		case RVE_STRDIFF_OP:
2074 2078
 			return 0;
2075 2079
 	}
2076 2080
 	return 0;
... ...
@@ -2079,7 +2314,7 @@ static int rve_op_is_assoc(enum rval_expr_op op)
2079 2079
 
2080 2080
 
2081 2081
 /** returns true if the operator is commutative. */
2082
-static int rve_op_is_commutative(enum rval_expr_op op, enum rval_type type)
2082
+static int rve_op_is_commutative(enum rval_expr_op op)
2083 2083
 {
2084 2084
 	switch(op){
2085 2085
 		case RVE_NONE_OP:
... ...
@@ -2096,23 +2331,34 @@ static int rve_op_is_commutative(enum rval_expr_op op, enum rval_type type)
2096 2096
 		case RVE_MINUS_OP:
2097 2097
 			return 0;
2098 2098
 		case RVE_PLUS_OP:
2099
-			return type==RV_INT; /* commutative only for INT*/
2099
+			/* non commut. when diff. type 
2100
+			   (e.g 1 + "2" != "2" + 1 ) => non commut. in general
2101
+			   (specific same type versions are covered by IPLUS & CONCAT) */
2102
+			return 0;
2100 2103
 		case RVE_IPLUS_OP:
2101 2104
 		case RVE_MUL_OP:
2102 2105
 		case RVE_BAND_OP:
2103 2106
 		case RVE_BOR_OP:
2104
-			return 1;
2105 2107
 		case RVE_LAND_OP:
2106 2108
 		case RVE_LOR_OP:
2109
+		case RVE_IEQ_OP:
2110
+		case RVE_IDIFF_OP:
2111
+		case RVE_STREQ_OP:
2112
+		case RVE_STRDIFF_OP:
2107 2113
 			return 1;
2108 2114
 		case RVE_GT_OP:
2109 2115
 		case RVE_GTE_OP:
2110 2116
 		case RVE_LT_OP:
2111 2117
 		case RVE_LTE_OP:
2112
-		case RVE_EQ_OP:
2113
-		case RVE_DIFF_OP:
2114 2118
 		case RVE_CONCAT_OP:
2115 2119
 			return 0;
2120
+		case RVE_DIFF_OP:
2121
+		case RVE_EQ_OP:
2122
+			/* non. commut. in general, only for same type e.g.:
2123
+			   "" == 0  diff. 0 == "" ( "" == "0" and 0 == 0)
2124
+			   same type versions are covered by IEQ, IDIFF, STREQ, STRDIFF
2125
+			 */
2126
+			return 0 /* asymmetrical undef handling */;
2116 2127
 	}
2117 2128
 	return 0;
2118 2129
 }
... ...
@@ -2421,8 +2667,19 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
2421 2421
 			case RVE_PLUS_OP:
2422 2422
 			case RVE_IPLUS_OP:
2423 2423
 				/* 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))){
2424
+				   (because "foo"+0 is valid => "foo0")
2425
+				  Even if overall type is RV_INT, it's still not safe
2426
+				  to optimize a generic PLUS: 0 + $v is not always equivalent
2427
+				  to $v (e.g. 0+"1" ==1 != "1") => optimize only if
2428
+				  IPLUS (always safe since it converts to int first) or
2429
+				  if generic PLUS and result is integer (rve_type) and
2430
+				  expression is of the form $v+ct (and not ct+$v).
2431
+				  TODO: dropping PLUS_OP all together and relying on the
2432
+				   optimizer replacing safe PLUS_OP with IPLUS_OP or CONCAT_OP
2433
+				   will simplify things.
2434
+				 */
2435
+				if ((i==0) && ((op==RVE_IPLUS_OP)||
2436
+							(rve_type==RV_INT && ct_rve==rve->right.rve))){
2426 2437
 					/* $v +  0 -> $v
2427 2438
 					 *  0 + $v -> $v */
2428 2439
 					rve_destroy(ct_rve);
... ...
@@ -2484,6 +2741,7 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
2484 2484
 				}
2485 2485
 				break;
2486 2486
 			case RVE_EQ_OP:
2487
+			case RVE_STREQ_OP:
2487 2488
 				if (rv->v.s.len==0){
2488 2489
 					/* $v == "" -> strempty($v) 
2489 2490
 					   "" == $v -> strempty ($v) */
... ...
@@ -2600,6 +2858,25 @@ static int rve_optimize(struct rval_expr* rve)
2600 2600
 						rve->fpos.e_line, rve->fpos.e_col);
2601 2601
 			}
2602 2602
 		}
2603
+		/* e1 EQ_OP e2 -> change op if we know e1 basic type
2604
+		   e1 DIFF_OP e2 -> change op if we know e2 basic type */
2605
+		if (rve->op==RVE_EQ_OP || rve->op==RVE_DIFF_OP){
2606
+			l_type=rve_guess_type(rve->left.rve);
2607
+			if (l_type==RV_INT){
2608
+				rve->op=(rve->op==RVE_EQ_OP)?RVE_IEQ_OP:RVE_IDIFF_OP;
2609
+				DBG("FIXUP RVE (%d,%d-%d,%d): changed ==/!= into interger"
2610
+						" ==/!=\n",
2611
+						rve->fpos.s_line, rve->fpos.s_col,
2612
+						rve->fpos.e_line, rve->fpos.e_col);
2613
+			}else if (l_type==RV_STR){
2614
+				rve->op=RVE_CONCAT_OP;
2615
+				rve->op=(rve->op==RVE_EQ_OP)?RVE_STREQ_OP:RVE_STRDIFF_OP;
2616
+				DBG("FIXUP RVE (%d,%d-%d,%d): changed ==/!= into string"
2617
+						" ==/!=\n",
2618
+						rve->fpos.s_line, rve->fpos.s_col,
2619
+						rve->fpos.e_line, rve->fpos.e_col);
2620
+			}
2621
+		}
2603 2622
 		
2604 2623
 		/* $v * 0 => 0; $v * 1 => $v (for *, /, &, |, &&, ||, +, -) */
2605 2624
 		if (rve_opt_01(rve, type)==1){
... ...
@@ -2651,7 +2928,7 @@ static int rve_optimize(struct rval_expr* rve)
2651 2651
 								trv->v.s.len, trv->v.s.s, rve->op);
2652 2652
 					ret=1;
2653 2653
 				}else if (rve_is_constant(rve->left.rve->left.rve) &&
2654
-							rve_op_is_commutative(rve->op, type)){
2654
+							rve_op_is_commutative(rve->op)){
2655 2655
 					/* op(op(a, $v), b) => op(op(a, b), $v) */
2656 2656
 					/* rv= op(a, b) */
2657 2657
 					tmp_rve.op=rve->op;
... ...
@@ -2693,7 +2970,7 @@ static int rve_optimize(struct rval_expr* rve)
2693 2693
 			if ((rve->op==rve->right.rve->op) && rve_op_is_assoc(rve->op)){
2694 2694
 				/* op(a, op(...)) */
2695 2695
 				if (rve_is_constant(rve->right.rve->right.rve) &&
2696
-						rve_op_is_commutative(rve->op, type)){
2696
+						rve_op_is_commutative(rve->op)){
2697 2697
 					/* op(a, op($v, b)) => op(op(a, b), $v) */
2698 2698
 					/* rv= op(a, b) */
2699 2699
 					tmp_rve.op=rve->op;
... ...
@@ -2824,6 +3101,10 @@ int fix_rval_expr(void** p)
2824 2824
 		case RVE_IPLUS_OP:
2825 2825
 		case RVE_EQ_OP:
2826 2826
 		case RVE_DIFF_OP:
2827
+		case RVE_IEQ_OP:
2828
+		case RVE_IDIFF_OP:
2829
+		case RVE_STREQ_OP:
2830
+		case RVE_STRDIFF_OP:
2827 2831
 		case RVE_CONCAT_OP:
2828 2832
 			ret=fix_rval_expr((void**)&rve->left.rve);
2829 2833
 			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 59
 	RVE_GTE_OP,   /*  2 members, returns left >= right */
60 60
 	RVE_LT_OP,    /*  2 members, returns left  < right */
61 61
 	RVE_LTE_OP,   /*  2 members, returns left <= right */
62
+	RVE_IEQ_OP, /*  2 members, int == version, returns left == right */
63
+	RVE_IDIFF_OP,/* 2 members, int != version, returns left != right */
62 64
 	RVE_IPLUS_OP, /* 2 members, integer +, returns int(a)+int(b) */
63 65
 	/* common int & str */
64 66
 	RVE_PLUS_OP,  /* generic plus (int or str) returns left + right */
... ...
@@ -68,6 +72,8 @@ enum rval_expr_op{
68 68
 	RVE_CONCAT_OP,/* 2 members, string concat, returns left . right (str)*/
69 69
 	RVE_STRLEN_OP, /* one member, string length:, returns strlen(val) (int)*/
70 70
 	RVE_STREMPTY_OP, /* one member, returns val=="" (bool) */
71
+	RVE_STREQ_OP,  /* 2 members, string == , returns left == right (bool)*/
72
+	RVE_STRDIFF_OP,/* 2 members, string != , returns left != right (bool)*/
71 73
 	/* avp, pvars a.s.o */
72 74
 	RVE_DEFINED_OP, /* one member, returns is_defined(val) (bool) */
73 75
 };
... ...
@@ -118,7 +124,8 @@ struct rval_expr{
118 118
 enum rval_cache_type{
119 119
 	RV_CACHE_EMPTY,
120 120
 	RV_CACHE_PVAR,
121
-	RV_CACHE_AVP
121
+	RV_CACHE_AVP,
122
+	RV_CACHE_SELECT
122 123
 };
123 124
 
124 125
 /** value cache for a rvalue struct.