Browse code

core expr eval: special handling for undef cmp expr

undef == expression is evaluated in the following way:
- default:
(type_of(expression))(undef) == expression.
If the expression is undef too, the whole comparison it's
evaluated to true (internally it's evaluated to
(str) undef == (str) undef => "" == "" => true).
E.g.: undef == 0 -> (int)undef == 0 -> 0 == 0 -> true
undef == "a" -> (str)undef == "a" -> ""=="a" -> false
undef == undef -> true
- if UNDEF_EQ_UNDEF_TRUE is defined, the == comparison is always
false except for undef == undef which is true.
E.g.: undef == 0 -> false ; undef == "" false
- if UNDEF_EQ_ALWAY_FALSE is defined, the result is always false

!= is always the reverse of ==.

Note: this covers only the case when undef is on the _left_ side
(the case in which we do not know what to convert undef to). If
the undef is on the right side, it will work like for any other
comparison: expr == undef => expr == (type_of(expr)) undef.

Andrei Pelinescu-Onciul authored on 28/04/2009 14:07:23
Showing 1 changed files
... ...
@@ -26,7 +26,23 @@
26 26
  *  2009-04-24  added support for defined, strempty, strlen (andrei)
27 27
  *  2009-04-28  int and str automatic conversions: (int)undef=0,
28 28
  *               (str)undef="", (int)""=0, (int)"123"=123, (int)"abc"=0
29
- *               (andrei)
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 perorm 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
30 46
  */
31 47
 
32 48
 #include "rvalue.h"
... ...
@@ -1549,7 +1565,7 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1549 1565
 						int* res, struct rval_expr* rve)
1550 1566
 {
1551 1567
 	int i1, i2, ret;
1552
-	struct rval_cache c1;
1568
+	struct rval_cache c1, c2;
1553 1569
 	struct rvalue* rv1;
1554 1570
 	struct rvalue* rv2;
1555 1571
 	
... ...
@@ -1616,10 +1632,14 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1616 1632
 		case RVE_EQ_OP:
1617 1633
 		case RVE_DIFF_OP:
1618 1634
 			/* if left is string, eval left & right as string and
1619
-			   use string diff, else eval as int */
1635
+			 *   use string diff.
1636
+			 * if left is int eval as int using int diff
1637
+			 * if left is undef, look at right and convert to right type
1638
+			 */
1620 1639
 			rval_cache_init(&c1);
1621 1640
 			if (unlikely( (ret=rval_expr_eval_rvint(h, msg, &rv1, &i1,
1622 1641
 													rve->left.rve, &c1))<0)){
1642
+				/* error */
1623 1643
 				rval_cache_clean(&c1);
1624 1644
 				break;
1625 1645
 			}
... ...
@@ -1628,20 +1648,67 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
1628 1648
 				rval_cache_clean(&c1);
1629 1649
 				if (unlikely( (ret=rval_expr_eval_int(h, msg, &i2,
1630 1650
 														rve->right.rve)) <0) )
1631
-					break;
1651
+					break;  /* error */
1632 1652
 				ret=int_intop2(res, rve->op, i1, i2);
1633 1653
 			}else{
1634
-				if (unlikely((rv2=rval_expr_eval(h, msg,
1635
-													rve->right.rve))==0)){
1654
+				/* not int => str or undef */
1655
+				/* check for undefined left operand */
1656
+				if (unlikely( c1.cache_type!=RV_CACHE_EMPTY &&
1657
+								c1.val_type==RV_NONE)){
1658
+#ifdef UNDEF_EQ_ALWAYS_FALSE
1659
+					/* undef == something  always false
1660
+					   undef != something  always true*/
1661
+					ret=(rve->op==RVE_DIFF_OP);
1662
+#elif defined UNDEF_EQ_UNDEF_TRUE
1663
+					/* undef == something defined always false
1664
+					   undef == undef true */
1665
+					if (int_rve_defined(h, msg, &i2, rve->right.rve)<0){
1666
+						/* error */
1667
+						rval_cache_clean(&c1);
1668
+						rval_destroy(rv1);
1669
+						break;
1670
+					}
1671
+					ret=(!i2) ^ (rve->op==RVE_DIFF_OP);
1672
+#else  /* ! UNDEF_EQ_* */
1673
+					/*  undef == val
1674
+					 *  => convert to (type_of(val)) (undef) == val */
1675
+					rval_cache_init(&c2);
1676
+					if (unlikely( (ret=rval_expr_eval_rvint(h, msg, &rv2, &i2,
1677
+													rve->right.rve, &c2))<0)){
1678
+						/* error */
1679
+						rval_cache_clean(&c1);
1680
+						rval_cache_clean(&c2);
1681
+						rval_destroy(rv1);
1682
+						break;
1683
+					}
1684
+					if (rv2==0){
1685
+						/* int */
1686
+						ret=int_intop2(res, rve->op, 0 /* undef */, i2);
1687
+					}else{
1688
+						/* str or undef */
1689
+						ret=rval_str_lop2(h, msg, res, rve->op, rv1, &c1,
1690
+											rv2, &c2);
1691
+						rval_cache_clean(&c2);
1692
+						rval_destroy(rv2);
1693
+					}
1694
+#endif /* UNDEF_EQ_* */
1695
+					rval_cache_clean(&c1);
1636 1696
 					rval_destroy(rv1);
1697
+				}else{ 
1698
+					/* left value == defined and != int => str
1699
+					 * => lval == (str) val */
1700
+					if (unlikely((rv2=rval_expr_eval(h, msg,
1701
+														rve->right.rve))==0)){
1702
+						/* error */
1703
+						rval_destroy(rv1);
1704
+						rval_cache_clean(&c1);
1705
+						break;
1706
+					}
1707
+					ret=rval_str_lop2(h, msg, res, rve->op, rv1, &c1, rv2, 0);
1637 1708
 					rval_cache_clean(&c1);
1638
-					ret=-1;
1639
-					break;
1709
+					rval_destroy(rv1);
1710
+					rval_destroy(rv2);
1640 1711
 				}
1641
-				ret=rval_str_lop2(h, msg, res, rve->op, rv1, &c1, rv2, 0);
1642
-				rval_cache_clean(&c1);
1643
-				rval_destroy(rv1);
1644
-				rval_destroy(rv2);
1645 1712
 			}
1646 1713
 			break;
1647 1714
 #if 0