pkg: fix wrong package name, closes FS#148, reported from Andrew Pogrebennyk
[sip-router] / rvalue.c
index 8bd0aa2..00dc19d 100644 (file)
--- a/rvalue.c
+++ b/rvalue.c
@@ -1,6 +1,4 @@
 /* 
- * $Id$
- * 
  * Copyright (C) 2008 iptelorg GmbH
  *
  * Permission to use, copy, modify, and distribute this software for any
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
+
 /**
  * @file 
- * @brief rvalue expressions
+ * @brief SIP-router core :: rvalue expressions
+ * @ingroup core
+ * Module: \ref core
  */
+
 /* 
  * History:
  * --------
  *  2008-12-01  initial version (andrei)
+ *  2009-04-24  added support for defined, strempty, strlen (andrei)
+ *  2009-04-28  int and str automatic conversions: (int)undef=0,
+ *               (str)undef="", (int)""=0, (int)"123"=123, (int)"abc"=0
+ *              handle undef == expr, in function of the UNDEF_EQ_* defines.
+ *              (andrei)
+ *  2009-05-05  casts operator for int & string (andrei)
+ */
+
+/* special defines:
+ *
+ *  UNDEF_EQ_* - how to behave when undef is on the right side of a generic
+ *               compare operator
+ *  UNDEF_EQ_ALWAYS_FALSE:  undef  == something  is always false
+ *  UNDEF_EQ_UNDEF_TRUE  :  undef == something false except for undef==undef
+ *                          which is true
+ *  no UNDEF_EQ* define  :  undef == expr => convert undef to typeof(expr)
+ *                          and perform normal ==. undef == undef will be
+ *                          converted to string and it will be true
+ *                          ("" == "")
+ * NOTE: expr == undef, with defined(expr) is always evaluated this way:
+         expr == (type_of(expr))undef
+ *  RV_STR2INT_VERBOSE_ERR - if a string conversion to int fails, log (L_WARN)
+ *                           the string that caused it (only the string, not
+ *                           the expression position).
+ *  RV_STR2INT_ERR         - if a string conversion to int fails, don't ignore
+ *                           the error (return error).
+ *  RVAL_GET_INT_ERR_WARN  - if a conversion to int fails, log a warning with
+ *                           the expression position.
+ *                           Depends on RV_STR2INT_ERR.
+ *  RVAL_GET_INT_ERR_IGN   - if a conversion to int fails, ignore the error
+ *                           (the result will be 0). Can be combined with
+ *                           RVAL_GET_INT_ERR_WARN.
+ *                           Depends on RV_STR2INT_ERR.
  */
 
+
 #include "rvalue.h"
 
+#include <stdlib.h> /* abort() */
+
+/* if defined warn when str2int conversions fail */
+#define RV_STR2INT_VERBOSE_ERR
+
+/* if defined rval_get_int will fail if str2int conversion fail
+   (else convert to 0) */
+#define RV_STR2INT_ERR
+
+/* if a rval_get_int fails (conversion to int), warn
+   Depends on RV_STR2INT_ERR.
+ */
+#define RVAL_GET_INT_ERR_WARN
+
+/* if a rval_get_int fails, ignore it (expression evaluation will not fail,
+   the int conversion will result in 0).
+   Can be combined with RVAL_GET_INT_ERR_WARN.
+   Depends on RV_STR2INT_ERR.
+ */
+#define RVAL_GET_INT_ERR_IGN
+
 /* minimum size alloc'ed for STR RVs (to accomodate
  * strops without reallocs) */
 #define RV_STR_EXTRA 80
@@ -51,17 +108,35 @@ inline static void rval_force_clean(struct rvalue* rv)
                }
                rv->flags&=~RV_CNT_ALLOCED_F;
        }
+       if (rv->flags & RV_RE_ALLOCED_F){
+               if (rv->v.re.regex){
+                       if (unlikely(rv->type!=RV_STR || !(rv->flags & RV_RE_F))){
+                               BUG("RV_RE_ALLOCED_F not supported for type %d or "
+                                               "bad flags %x\n", rv->type, rv->flags);
+                       }
+                       regfree(rv->v.re.regex);
+                       pkg_free(rv->v.re.regex);
+                       rv->v.re.regex=0;
+               }
+               rv->flags&=~(RV_RE_ALLOCED_F|RV_RE_F);
+       }
 }
 
 
 
 /** frees a rval returned by rval_new(), rval_convert() or rval_expr_eval().
- *   Note: ir will be freed only when refcnt reaches 0
+ *   Note: it will be freed only when refcnt reaches 0
  */
 void rval_destroy(struct rvalue* rv)
 {
        if (rv && rv_unref(rv)){
                rval_force_clean(rv);
+               /* still an un-regfreed RE ? */
+               if ((rv->flags & RV_RE_F) && rv->v.re.regex){
+                       if (unlikely(rv->type!=RV_STR))
+                               BUG("RV_RE_F not supported for type %d\n", rv->type);
+                       regfree(rv->v.re.regex);
+               }
                if (rv->flags & RV_RV_ALLOCED_F){
                        pkg_free(rv);
                }
@@ -86,15 +161,19 @@ void rve_destroy(struct rval_expr* rve)
                                if (rve->left.rval.refcnt==1)
                                        rval_destroy(&rve->left.rval);
                                else
-                                       BUG("rval expr rval with invalid refcnt: %d\n", 
-                                                       rve->left.rval.refcnt);
+                                       BUG("rval expr rval with invalid refcnt: %d (%d,%d-%d,%d)"
+                                                       "\n", rve->left.rval.refcnt,
+                                                       rve->fpos.s_line, rve->fpos.s_col,
+                                                       rve->fpos.e_line, rve->fpos.e_col);
                        }
                        if (rve->right.rval.refcnt){
                                if (rve->right.rval.refcnt==1)
                                        rval_destroy(&rve->right.rval);
                                else
-                                       BUG("rval expr rval with invalid refcnt: %d\n", 
-                                                       rve->right.rval.refcnt);
+                                       BUG("rval expr rval with invalid refcnt: %d (%d,%d-%d,%d)"
+                                                       "\n", rve->right.rval.refcnt,
+                                                       rve->fpos.s_line, rve->fpos.s_col,
+                                                       rve->fpos.e_line, rve->fpos.e_col);
                        }
                }else{
                        if (rve->left.rve)
@@ -110,7 +189,7 @@ void rve_destroy(struct rval_expr* rve)
 
 void rval_cache_clean(struct rval_cache* rvc)
 {
-       if (rvc->cache_type==RV_CACHE_PVAR){
+       if ((rvc->cache_type==RV_CACHE_PVAR) && (rvc->val_type!=RV_NONE)){
                pv_value_destroy(&rvc->c.pval);
        }
        rvc->cache_type=RV_CACHE_EMPTY;
@@ -118,7 +197,7 @@ void rval_cache_clean(struct rval_cache* rvc)
 }
 
 
-#define rv_chg_in_place(rv)  ((rv)->refcnt==1) 
+#define rv_chg_in_place(rv)  ((rv)->refcnt==1)
 
 
 
@@ -191,6 +270,46 @@ struct rvalue* rval_new_str(str* s, int extra_size)
 
 
 
+/** create a new pk_malloc'ed RE rv from a str re.
+  * It acts as rval_new_str, but also compiles a RE from the str
+  * and sets v->re.regex.
+  * @param s - pointer to str, must be non-null, zero-term'ed and a valid RE.
+  * @return new rv or 0 on error
+  */
+struct rvalue* rval_new_re(str* s)
+{
+       struct rvalue* rv;
+       long offs;
+       
+       offs=(long)&((struct rvalue*)0)->buf[0]; /* offset of the buf. member */
+       /* make sure we reserve enough space so that we can satisfy any regex_t
+          alignment requirement (pointer) */
+       rv=rval_new_empty(ROUND_POINTER(offs)-offs+sizeof(*rv->v.re.regex)+
+                                               s->len+1/* 0 */);
+       if (likely(rv)){
+               rv->type=RV_STR;
+               /* make sure regex points to a properly aligned address
+                  (use max./pointer alignment to be sure ) */
+               rv->v.re.regex=(regex_t*)((char*)&rv->buf[0]+ROUND_POINTER(offs)-offs);
+               rv->v.s.s=(char*)rv->v.re.regex+sizeof(*rv->v.re.regex);
+               rv->v.s.len=s->len;
+               memcpy(rv->v.s.s, s->s, s->len);
+               rv->v.s.s[s->len]=0;
+               /* compile the regex */
+               /* same flags as for expr. =~ (fix_expr()) */
+               if (unlikely(regcomp(rv->v.re.regex, s->s,
+                                                               REG_EXTENDED|REG_NOSUB|REG_ICASE))){
+                       /* error */
+                       pkg_free(rv);
+                       rv=0;
+               }else /* success */
+                       rv->flags|=RV_RE_F;
+       }
+       return rv;
+}
+
+
+
 /** get string name for a type.
   *
   * @return - null terminated name of the type
@@ -221,14 +340,14 @@ char* rval_type_name(enum rval_type type)
 
 
 
-/** create a new pk_malloc'ed rvalue from a rval_val union.
-  *
-  * @param s - pointer to str, must be non-null
 * @param extra_size - extra space to allocate
 *                    (so that future string operation can reuse
 *                     the space)
 * @return new rv or 0 on error
 */
+/**
+ * @brief create a new pk_malloc'ed rvalue from a rval_val union
+ * @param t rvalue type
* @param v rvalue value
* @param extra_size extra space to allocate
* (so that future string operation can reuse the space)
+ * @return new rv or 0 on error
+ */
 struct rvalue* rval_new(enum rval_type t, union rval_val* v, int extra_size)
 {
        struct rvalue* rv;
@@ -252,18 +371,21 @@ struct rvalue* rval_new(enum rval_type t, union rval_val* v, int extra_size)
 
 
 
-/** get rvalue basic type (RV_INT or RV_STR).
-  *
-  * Given a rvalue it tries to determinte its basic type.
-  * Fills val_cache if non-null and empty (can be used in other rval*
-  * function calls, to avoid re-resolving avps or pvars). It must be
-  * rval_cache_clean()'en when no longer needed.
-  *
-  * @param rv - target rvalue
-  * @param val_cache - value cache, might be filled if non-null, 
-  *                    it _must_ be rval_cache_clean()'en when done.
-  * @return - basic type or RV_NONE on error
-  */
+/**
+ * @brief get rvalue basic type (RV_INT or RV_STR)
+ *
+ * Given a rvalue it tries to determinte its basic type.
+ * Fills val_cache if non-null and empty (can be used in other rval*
+ * function calls, to avoid re-resolving avps or pvars). It must be
+ * rval_cache_clean()'en when no longer needed.
+ *
+ * @param h run action context
+ * @param msg SIP message
+ * @param rv target rvalue
+ * @param val_cache write-only value cache, might be filled if non-null,
+ * it _must_ be rval_cache_clean()'en when done.
+ * @return basic type or RV_NONE on error
+ */
 inline static enum rval_type rval_get_btype(struct run_act_ctx* h,
                                                                                        struct sip_msg* msg,
                                                                                        struct rvalue* rv,
@@ -287,36 +409,39 @@ inline static enum rval_type rval_get_btype(struct run_act_ctx* h,
                case RV_PVAR:
                        if (likely(val_cache && val_cache->cache_type==RV_CACHE_EMPTY)){
                                pv=&val_cache->c.pval;
+                               val_cache->cache_type=RV_CACHE_PVAR;
                        }else{
                                val_cache=0;
                                pv=&tmp_pval;
                        }
                        memset(pv, 0, sizeof(tmp_pval));
                        if (likely(pv_get_spec_value(msg, &rv->v.pvs, pv)==0)){
-                               if (pv->flags & PV_VAL_STR){
-                                       if (unlikely(val_cache==0)) pv_value_destroy(pv);
-                                       else{
-                                               val_cache->cache_type=RV_CACHE_PVAR;
-                                               val_cache->val_type=RV_STR;
-                                       }
-                                       return RV_STR;
-                               }else if (pv->flags & PV_TYPE_INT){
-                                       if (unlikely(val_cache==0)) pv_value_destroy(pv);
-                                       else{
-                                               val_cache->cache_type=RV_CACHE_PVAR;
+                               if (pv->flags & PV_TYPE_INT){
+                                       if (likely(val_cache!=0))
                                                val_cache->val_type=RV_INT;
-                                       }
+                                       else
+                                               pv_value_destroy(pv);
                                        return RV_INT;
+                               }else if (pv->flags & PV_VAL_STR){
+                                       if (likely(val_cache!=0))
+                                               val_cache->val_type=RV_STR;
+                                       else
+                                               pv_value_destroy(pv);
+                                       return RV_STR;
                                }else{
                                        pv_value_destroy(pv);
+                                       if (likely(val_cache!=0))
+                                               val_cache->val_type=RV_NONE; /* undefined */
                                        goto error;
                                }
                        }else{
+                               if (likely(val_cache!=0))
+                                       val_cache->val_type=RV_NONE; /* undefined */
                                goto error;
                        }
                        break;
                case RV_AVP:
-                       if (likely(val_cache && val_cache==RV_CACHE_EMPTY)){
+                       if (likely(val_cache && val_cache->cache_type==RV_CACHE_EMPTY)){
                                ptype=&val_cache->val_type;
                                avpv=&val_cache->c.avp_val;
                                val_cache->cache_type=RV_CACHE_AVP;
@@ -336,7 +461,6 @@ inline static enum rval_type rval_get_btype(struct run_act_ctx* h,
                                }
                        }else{
                                *ptype=RV_NONE;
-                               if (val_cache) val_cache->cache_type=RV_CACHE_EMPTY;
                                goto error;
                        }
                        break;
@@ -376,11 +500,16 @@ enum rval_type rve_guess_type( struct rval_expr* rve)
                case RVE_UMINUS_OP:
                case RVE_BOOL_OP:
                case RVE_LNOT_OP:
+               case RVE_BNOT_OP:
                case RVE_MINUS_OP:
                case RVE_MUL_OP:
                case RVE_DIV_OP:
+               case RVE_MOD_OP:
                case RVE_BOR_OP:
                case RVE_BAND_OP:
+               case RVE_BXOR_OP:
+               case RVE_BLSHIFT_OP:
+               case RVE_BRSHIFT_OP:
                case RVE_LAND_OP:
                case RVE_LOR_OP:
                case RVE_GT_OP:
@@ -389,12 +518,22 @@ enum rval_type rve_guess_type( struct rval_expr* rve)
                case RVE_LTE_OP:
                case RVE_EQ_OP:
                case RVE_DIFF_OP:
+               case RVE_IEQ_OP:
+               case RVE_IDIFF_OP:
+               case RVE_STREQ_OP:
+               case RVE_STRDIFF_OP:
+               case RVE_MATCH_OP:
                case RVE_IPLUS_OP:
+               case RVE_STRLEN_OP:
+               case RVE_STREMPTY_OP:
+               case RVE_DEFINED_OP:
+               case RVE_INT_OP:
                        return RV_INT;
                case RVE_PLUS_OP:
                        /* '+' evaluates to the type of the left operand */
                        return rve_guess_type(rve->left.rve);
                case RVE_CONCAT_OP:
+               case RVE_STR_OP:
                        return RV_STR;
                case RVE_NONE_OP:
                        break;
@@ -429,12 +568,22 @@ int rve_is_constant(struct rval_expr* rve)
                case RVE_UMINUS_OP:
                case RVE_BOOL_OP:
                case RVE_LNOT_OP:
+               case RVE_BNOT_OP:
+               case RVE_STRLEN_OP:
+               case RVE_STREMPTY_OP:
+               case RVE_DEFINED_OP:
+               case RVE_INT_OP:
+               case RVE_STR_OP:
                        return rve_is_constant(rve->left.rve);
                case RVE_MINUS_OP:
                case RVE_MUL_OP:
                case RVE_DIV_OP:
+               case RVE_MOD_OP:
                case RVE_BOR_OP:
                case RVE_BAND_OP:
+               case RVE_BXOR_OP:
+               case RVE_BLSHIFT_OP:
+               case RVE_BRSHIFT_OP:
                case RVE_LAND_OP:
                case RVE_LOR_OP:
                case RVE_GT_OP:
@@ -443,6 +592,11 @@ int rve_is_constant(struct rval_expr* rve)
                case RVE_LTE_OP:
                case RVE_EQ_OP:
                case RVE_DIFF_OP:
+               case RVE_IEQ_OP:
+               case RVE_IDIFF_OP:
+               case RVE_STREQ_OP:
+               case RVE_STRDIFF_OP:
+               case RVE_MATCH_OP:
                case RVE_PLUS_OP:
                case RVE_IPLUS_OP:
                case RVE_CONCAT_OP:
@@ -478,12 +632,22 @@ static int rve_op_unary(enum rval_expr_op op)
                case RVE_UMINUS_OP:
                case RVE_BOOL_OP:
                case RVE_LNOT_OP:
+               case RVE_BNOT_OP:
+               case RVE_STRLEN_OP:
+               case RVE_STREMPTY_OP:
+               case RVE_DEFINED_OP:
+               case RVE_INT_OP:
+               case RVE_STR_OP:
                        return 1;
                case RVE_MINUS_OP:
                case RVE_MUL_OP:
                case RVE_DIV_OP:
+               case RVE_MOD_OP:
                case RVE_BOR_OP:
                case RVE_BAND_OP:
+               case RVE_BXOR_OP:
+               case RVE_BLSHIFT_OP:
+               case RVE_BRSHIFT_OP:
                case RVE_LAND_OP:
                case RVE_LOR_OP:
                case RVE_GT_OP:
@@ -492,6 +656,11 @@ static int rve_op_unary(enum rval_expr_op op)
                case RVE_LTE_OP:
                case RVE_EQ_OP:
                case RVE_DIFF_OP:
+               case RVE_IEQ_OP:
+               case RVE_IDIFF_OP:
+               case RVE_STREQ_OP:
+               case RVE_STRDIFF_OP:
+               case RVE_MATCH_OP:
                case RVE_PLUS_OP:
                case RVE_IPLUS_OP:
                case RVE_CONCAT_OP:
@@ -505,18 +674,19 @@ static int rve_op_unary(enum rval_expr_op op)
 
 
 
-/** returns 1 if expression is valid (type-wise).
-  * @param type - filled with the type of the expression (RV_INT, RV_STR or
-  *                RV_NONE if it's dynamic)
-  * @param rve  - checked expression
-  * @param bad_rve - set on failure to the subexpression for which the 
-  *                    type check failed
-  * @param bad_type - set on failure to the type of the bad subexpression
-  * @param exp_type - set on failure to the expected type for the bad
-  *                   subexpression
-  * @return 0 or 1  and sets *type to the resulting type
-  * (RV_INT, RV_STR or RV_NONE if it can be found only at runtime)
-  */
+/**
+ * @brief Returns 1 if expression is valid (type-wise)
+ * @param type filled with the type of the expression (RV_INT, RV_STR or
+ *                RV_NONE if it's dynamic)
+ * @param rve  checked expression
+ * @param bad_rve set on failure to the subexpression for which the 
+ * type check failed
+ * @param bad_t set on failure to the type of the bad subexpression
+ * @param exp_t set on failure to the expected type for the bad
+ * subexpression
+ * @return 0 or 1 and sets *type to the resulting type
+ * (RV_INT, RV_STR or RV_NONE if it can be found only at runtime)
+ */
 int rve_check_type(enum rval_type* type, struct rval_expr* rve,
                                        struct rval_expr** bad_rve, 
                                        enum rval_type* bad_t,
@@ -531,6 +701,7 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
                case RVE_UMINUS_OP:
                case RVE_BOOL_OP:
                case RVE_LNOT_OP:
+               case RVE_BNOT_OP:
                        *type=RV_INT;
                        if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){
                                if (type1==RV_STR){
@@ -546,14 +717,20 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
                case RVE_MINUS_OP:
                case RVE_MUL_OP:
                case RVE_DIV_OP:
+               case RVE_MOD_OP:
                case RVE_BOR_OP:
                case RVE_BAND_OP:
+               case RVE_BXOR_OP:
+               case RVE_BLSHIFT_OP:
+               case RVE_BRSHIFT_OP:
                case RVE_LAND_OP:
                case RVE_LOR_OP:
                case RVE_GT_OP:
                case RVE_GTE_OP:
                case RVE_LT_OP:
                case RVE_LTE_OP:
+               case RVE_IEQ_OP:
+               case RVE_IDIFF_OP:
                case RVE_IPLUS_OP:
                        *type=RV_INT;
                        if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){
@@ -610,6 +787,7 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
                                        return 1;
                                }
                        }
+                       break;
                case RVE_CONCAT_OP:
                        *type=RV_STR;
                        if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){
@@ -632,7 +810,62 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
                                        return 1;
                                }
                        }
+                       break;
+               case RVE_STREQ_OP:
+               case RVE_STRDIFF_OP:
+               case RVE_MATCH_OP:
+                       *type=RV_INT;
+                       if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){
+                               if (rve_check_type(&type2, rve->right.rve, bad_rve, bad_t,
+                                                                       exp_t)){
+                                       if ((type2!=type1) && (type1!=RV_NONE) &&
+                                                       (type2!=RV_NONE) &&
+                                                       !(type1==RV_STR && type2==RV_INT)){
+                                               if (bad_rve) *bad_rve=rve->right.rve;
+                                               if (bad_t) *bad_t=type2;
+                                               if (exp_t) *exp_t=type1;
+                                               return 0;
+                                       }
+                                       if (type1==RV_INT){
+                                               if (bad_rve) *bad_rve=rve->left.rve;
+                                               if (bad_t) *bad_t=type1;
+                                               if (exp_t) *exp_t=RV_STR;
+                                               return 0;
+                                       }
+                                       return 1;
+                               }
+                       }
+                       break;
+               case RVE_STRLEN_OP:
+               case RVE_STREMPTY_OP:
+               case RVE_DEFINED_OP:
+                       *type=RV_INT;
+                       if (rve_check_type(&type1, rve->left.rve, bad_rve, bad_t, exp_t)){
+                               if (type1==RV_INT){
+                                       if (bad_rve) *bad_rve=rve->left.rve;
+                                       if (bad_t) *bad_t=type1;
+                                       if (exp_t) *exp_t=RV_STR;
+                                       return 0;
+                               }
+                               return 1;
+                       }
+                       break;
+               case RVE_INT_OP:
+                       *type=RV_INT;
+                       return 1;
+                       break;
+               case RVE_STR_OP:
+                       *type=RV_STR;
+                       return 1;
+                       break;
                case RVE_NONE_OP:
+               default:
+                       BUG("unexpected rve op %d (%d,%d-%d,%d)\n", rve->op,
+                                       rve->fpos.s_line, rve->fpos.s_col,
+                                       rve->fpos.e_line, rve->fpos.e_col);
+                       if (bad_rve) *bad_rve=rve;
+                       if (bad_t) *bad_t=RV_NONE;
+                       if (exp_t) *exp_t=RV_STR;
                        break;
        }
        return 0;
@@ -642,6 +875,15 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
 
 /** get the integer value of an rvalue.
   * *i=(int)rv
+  * if rv == undefined select, avp or pvar, return 0.
+  * if an error occurs while evaluating a select, avp or pvar, behave as
+  * for the undefined case (and return success).
+  * @param h - script context handle
+  * @param msg - sip msg
+  * @param i   - pointer to int, where the conversion result will be stored
+  * @param rv   - rvalue to be converted
+  * @param cache - cached rv value (read-only), can be 0
+  *
   * @return 0 on success, \<0 on error and EXPR_DROP on drop
  */
 int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg,
@@ -651,12 +893,20 @@ int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg,
        avp_t* r_avp;
        int_str avp_val;
        pv_value_t pval;
+       str tmp;
+       str* s;
+       int r, ret;
+       int destroy_pval;
        
+       destroy_pval=0;
+       s=0;
+       ret=0;
        switch(rv->type){
                case RV_INT:
                        *i=rv->v.l;
                        break;
                case RV_STR:
+                       s=&rv->v.s;
                        goto rv_str;
                case RV_BEXPR:
                        *i=eval_expr(h, rv->v.bexpr, msg);
@@ -666,42 +916,59 @@ int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg,
                        }
                        break;
                case RV_ACTION_ST:
-                       if (rv->v.action)
-                               *i=run_actions(h, rv->v.action, msg);
-                       else 
+                       if (rv->v.action) {
+                               *i=(run_actions_safe(h, rv->v.action, msg)>0);
+                               h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return &
+                                                                                                                   break in expr*/
+                       } else
                                *i=0;
                        break;
                case RV_SEL:
+                       r=run_select(&tmp, &rv->v.sel, msg);
+                       if (unlikely(r!=0)){
+                               if (r<0)
+                                       goto eval_error;
+                               else /* i>0  => undefined */
+                                       goto undef;
+                       }
+                       s=&tmp;
                        goto rv_str;
                case RV_AVP:
                        if (unlikely(cache && cache->cache_type==RV_CACHE_AVP)){
                                if (likely(cache->val_type==RV_INT)){
                                        *i=cache->c.avp_val.n;
-                               }else if (cache->val_type==RV_STR)
+                               }else if (cache->val_type==RV_STR){
+                                       s=&cache->c.avp_val.s;
                                        goto rv_str;
-                               else goto error;
+                               }else if (cache->val_type==RV_NONE)
+                                       goto undef;
+                               else goto error_cache;
                        }else{
                                r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
                                                                                        &avp_val, rv->v.avps.index);
                                if (likely(r_avp)){
                                        if (unlikely(r_avp->flags & AVP_VAL_STR)){
+                                               s=&avp_val.s;
                                                goto rv_str;
                                        }else{
                                                *i=avp_val.n;
                                        }
                                }else{
-                                       goto error;
+                                       goto undef;
                                }
                        }
                        break;
                case RV_PVAR:
                        if (unlikely(cache && cache->cache_type==RV_CACHE_PVAR)){
-                               if (likely((cache->val_type==RV_INT) || 
+                               if (likely((cache->val_type==RV_INT) ||
                                                                (cache->c.pval.flags & PV_VAL_INT))){
                                        *i=cache->c.pval.ri;
-                               }else if (cache->val_type==RV_STR)
+                               }else if (cache->val_type==RV_STR){
+                                       s=&cache->c.pval.rs;
                                        goto rv_str;
-                               else goto error;
+                               }else if (cache->val_type==RV_NONE)
+                                       goto undef;
+                               else goto error_cache;
                        }else{
                                memset(&pval, 0, sizeof(pval));
                                if (likely(pv_get_spec_value(msg, &rv->v.pvs, &pval)==0)){
@@ -709,14 +976,17 @@ int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg,
                                                *i=pval.ri;
                                                pv_value_destroy(&pval);
                                        }else if (likely(pval.flags & PV_VAL_STR)){
-                                               pv_value_destroy(&pval);
+                                               destroy_pval=1; /* we must pv_value_destroy() later*/
+                                               s=&pval.rs;
                                                goto rv_str;
                                        }else{
+                                               /* no PV_VAL_STR and no PV_VAL_INT => undef
+                                                  (PV_VAL_NULL) */
                                                pv_value_destroy(&pval);
-                                               goto error;
+                                               goto undef;
                                        }
                                }else{
-                                       goto error;
+                                       goto eval_error;
                                }
                        }
                        break;
@@ -724,30 +994,106 @@ int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg,
                        BUG("rv type %d not handled\n", rv->type);
                        goto error;
        }
+       return ret;
+undef:
+eval_error: /* same as undefined */
+       /* handle undefined => result 0, return success */
+       *i=0;
        return 0;
 rv_str:
-       /* rv is of string type => error */
-       /* ERR("string in int expression\n"); */
+       /* rv is of string type => try to convert it to int */
+       /* if "" => 0 (most likely case) */
+       if (likely(s->len==0)) *i=0;
+       else if (unlikely(str2sint(s, i)!=0)){
+               /* error converting to int => non numeric => 0 */
+               *i=0;
+#ifdef RV_STR2INT_VERBOSE_ERR
+               WARN("automatic string to int conversion for \"%.*s\" failed\n",
+                               s->len, ZSW(s->s));
+               /* return an error code */
+#endif
+#ifdef RV_STR2INT_ERR
+               ret=-1;
+#endif
+       }
+       if (destroy_pval)
+               pv_value_destroy(&pval);
+       return ret;
+error_cache:
+       BUG("invalid cached value:cache type %d, value type %d\n",
+                       cache?cache->cache_type:0, cache?cache->val_type:0);
 error:
+       if (destroy_pval)
+               pv_value_destroy(&pval);
+       *i=0;
        return -1;
 }
 
 
 
+/** log a message, appending rve position and a '\n'.*/
+#define RVE_LOG(lev, rve, txt) \
+       LOG((lev), txt " (%d,%d-%d,%d)\n", \
+                       (rve)->fpos.s_line, rve->fpos.s_col, \
+                       (rve)->fpos.e_line, rve->fpos.e_col )
+
+
+/** macro for checking and handling rval_get_int() retcode.
+ * check if the return code is an rval_get_int error and if so
+ * handle the error (e.g. print a log message, ignore the error by
+ * setting ret to 0 a.s.o.)
+ * @param ret - retcode as returned by rval_get_int() (might be changed)
+ * @param txt - warning message txt (no pointer allowed)
+ * @param rve - rval_expr, used to access the config. pos
+ */
+#if defined RVAL_GET_INT_ERR_WARN && defined RVAL_GET_INT_ERR_IGN
+#define rval_get_int_handle_ret(ret, txt, rve) \
+       do { \
+               if (unlikely((ret)<0)) { \
+                       RVE_LOG(L_WARN, rve, txt); \
+                       (ret)=0; \
+               } \
+       }while(0)
+#elif defined RVAL_GET_INT_ERR_WARN
+#define rval_get_int_handle_ret(ret, txt, rve) \
+       do { \
+               if (unlikely((ret)<0)) \
+                       RVE_LOG(L_WARN, rve, txt); \
+       }while(0)
+#elif defined RVAL_GET_INT_ERR_IGN
+#define rval_get_int_handle_ret(ret, txt, rve) \
+       do { \
+               if (unlikely((ret)<0)) \
+                               (ret)=0; \
+       } while(0)
+#else
+#define rval_get_int_handle_ret(ret, txt, rve) /* do nothing */
+#endif
+
+
+
+
+
+
 /** get the string value of an rv in a tmp variable
   * *s=(str)rv
-  * The result points either to a temporary string or inside
-  * new_cache. new_cache must be non zero, initialized previously,
-  * and it _must_ be rval_cache_clean(...)'ed when done.
-  * WARNING: it's not intended for general use, it might return a pointer
-  * to a static buffer (int2str) so use the result a.s.a.p, make a copy.
-  * or use rval_get_str() instead.
+  * if rv == undefined select, avp or pvar, return "".
+  * if an error occurs while evaluating a select, avp or pvar, behave as
+  * for the undefined case (and return success).
+  * The result points either inside the passed rv, inside
+  * new_cache or inside an avp. new_cache must be non zero,
+  * initialized previously and it _must_ be rval_cache_clean(...)'ed when
+  * done.
+  * WARNING: it's not intended for general use. It might return a pointer
+  * inside rv so the result _must_ be treated as read-only. rv and new_cache
+  * must not be released/freed until the result is no longer needed.
+  * For general use see  rval_get_str().
   * @param h - script context handle
   * @param msg - sip msg
   * @param tmpv - str return value (pointer to a str struct that will be
-  *               be filled.
+  *               be filled with the conversion result)
   * @param rv   - rvalue to be converted
-  * @param cache - cached rv value (read-only)
+  * @param cache - cached rv value (read-only), can be 0
   * @param tmp_cache - used for temporary storage (so that tmpv will not
   *                 point to possible freed data), it must be non-null,
   *                 initialized and cleaned afterwards.
@@ -759,40 +1105,48 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
                                                                struct rval_cache* tmp_cache)
 {
        avp_t* r_avp;
-       pv_value_t pval;
        int i;
        
        switch(rv->type){
                case RV_INT:
-                       tmpv->s=int2str(rv->v.l, &tmpv->len);
+                       tmpv->s=sint2strbuf(rv->v.l, tmp_cache->i2s,
+                                                               sizeof(tmp_cache->i2s), &tmpv->len);
+                       tmp_cache->cache_type = RV_CACHE_INT2STR;
                        break;
                case RV_STR:
                        *tmpv=rv->v.s;
                        break;
                case RV_ACTION_ST:
-                       if (rv->v.action)
-                               i=run_actions(h, rv->v.action, msg);
-                       else 
+                       if (rv->v.action) {
+                               i=(run_actions_safe(h, rv->v.action, msg)>0);
+                               h->run_flags &= ~(RETURN_R_F|BREAK_R_F); /* catch return &
+                                                                                                                   break in expr*/
+                       } else
                                i=0;
-                       tmpv->s=int2str(i, &tmpv->len);
+                       tmpv->s=sint2strbuf(i, tmp_cache->i2s,
+                                                               sizeof(tmp_cache->i2s), &tmpv->len);
+                       tmp_cache->cache_type = RV_CACHE_INT2STR;
                        break;
                case RV_BEXPR:
                        i=eval_expr(h, rv->v.bexpr, msg);
                        if (i==EXPR_DROP){
                                i=0; /* false */
-                               tmpv->s=int2str(i, &tmpv->len);
+                               tmpv->s=sint2strbuf(i, tmp_cache->i2s,
+                                               sizeof(tmp_cache->i2s), &tmpv->len);
+                               tmp_cache->cache_type = RV_CACHE_INT2STR;
                                return EXPR_DROP;
                        }
-                       tmpv->s=int2str(i, &tmpv->len);
+                       tmpv->s=sint2strbuf(i, tmp_cache->i2s, sizeof(tmp_cache->i2s),
+                                                               &tmpv->len);
+                       tmp_cache->cache_type = RV_CACHE_INT2STR;
                        break;
                case RV_SEL:
                        i=run_select(tmpv, &rv->v.sel, msg);
                        if (unlikely(i!=0)){
                                if (i<0){
-                                       goto error;
-                               }else { /* i>0 */
-                                       tmpv->s="";
-                                       tmpv->len=0;
+                                       goto eval_error;
+                               }else { /* i>0  => undefined */
+                                       goto undef;
                                }
                        }
                        break;
@@ -802,8 +1156,12 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
                                        *tmpv=cache->c.avp_val.s;
                                }else if (cache->val_type==RV_INT){
                                        i=cache->c.avp_val.n;
-                                       tmpv->s=int2str(i, &tmpv->len);
-                               }else goto error;
+                                       tmpv->s=sint2strbuf(i, tmp_cache->i2s,
+                                                                               sizeof(tmp_cache->i2s), &tmpv->len);
+                                       tmp_cache->cache_type = RV_CACHE_INT2STR;
+                               }else if (cache->val_type==RV_NONE){
+                                       goto undef;
+                               }else goto error_cache;
                        }else{
                                r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
                                                                                        &tmp_cache->c.avp_val,
@@ -815,11 +1173,11 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
                                                *tmpv=tmp_cache->c.avp_val.s;
                                        }else{
                                                i=tmp_cache->c.avp_val.n;
-                                               tmpv->s=int2str(i, &tmpv->len);
+                                               tmpv->s=sint2strbuf(i, tmp_cache->i2s,
+                                                                               sizeof(tmp_cache->i2s), &tmpv->len);
+                                               tmp_cache->cache_type = RV_CACHE_INT2STR;
                                        }
-                               }else{
-                                       goto error;
-                               }
+                               }else goto undef;
                        }
                        break;
                case RV_PVAR:
@@ -828,29 +1186,37 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
                                        *tmpv=cache->c.pval.rs;
                                }else if (cache->val_type==RV_INT){
                                        i=cache->c.pval.ri;
-                                       tmpv->s=int2str(i, &tmpv->len);
-                               }else goto error;
+                                       tmpv->s=sint2strbuf(i, tmp_cache->i2s,
+                                                                               sizeof(tmp_cache->i2s), &tmpv->len);
+                                       tmp_cache->cache_type = RV_CACHE_INT2STR;
+                               }else if (cache->val_type==RV_NONE){
+                                       goto undef;
+                               }else goto error_cache;
                        }else{
-                               memset(&pval, 0, sizeof(pval));
+                               memset(&tmp_cache->c.pval, 0, sizeof(tmp_cache->c.pval));
                                if (likely(pv_get_spec_value(msg, &rv->v.pvs,
                                                                                                &tmp_cache->c.pval)==0)){
-                                       if (likely(pval.flags & PV_VAL_STR)){
+                                       if (likely(tmp_cache->c.pval.flags & PV_VAL_STR)){
                                                /*  the value is not destroyed, but saved instead
                                                        in tmp_cache so that it can be destroyed later
                                                        when no longer needed */
                                                tmp_cache->cache_type=RV_CACHE_PVAR;
                                                tmp_cache->val_type=RV_STR;
                                                *tmpv=tmp_cache->c.pval.rs;
-                                       }else if (likely(pval.flags & PV_VAL_INT)){
-                                               i=pval.ri;
+                                       }else if (likely(tmp_cache->c.pval.flags & PV_VAL_INT)){
+                                               i=tmp_cache->c.pval.ri;
                                                pv_value_destroy(&tmp_cache->c.pval);
-                                               tmpv->s=int2str(i, &tmpv->len);
+                                               tmpv->s=sint2strbuf(i, tmp_cache->i2s,
+                                                                               sizeof(tmp_cache->i2s), &tmpv->len);
+                                               tmp_cache->cache_type = RV_CACHE_INT2STR;
                                        }else{
+                                               /* no PV_VAL_STR and no PV_VAL_INT => undef
+                                                  (PV_VAL_NULL) */
                                                pv_value_destroy(&tmp_cache->c.pval);
-                                               goto error;
+                                               goto undef;
                                        }
                                }else{
-                                       goto error;
+                                       goto eval_error;
                                }
                        }
                        break;
@@ -859,7 +1225,18 @@ int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
                        goto error;
        }
        return 0;
+undef:
+eval_error: /* same as undefined */
+       /* handle undefined => result "", return success */
+       tmpv->s="";
+       tmpv->len=0;
+       return 0;
+error_cache:
+       BUG("invalid cached value:cache type %d, value type %d\n",
+                       cache?cache->cache_type:0, cache?cache->val_type:0);
 error:
+       tmpv->s="";
+       tmpv->len=0;
        return -1;
 }
 
@@ -897,18 +1274,22 @@ error:
 
 
 
-/** convert a rvalue to another rvalue, of a specific type.
+/**
+ * @brief Convert a rvalue to another rvalue, of a specific type
  *
+ * Convert a rvalue to another rvalue, of a specific type.
  * The result is read-only in most cases (can be a reference
  * to another rvalue, can be checked by using rv_chg_in_place()) and
  * _must_ be rval_destroy()'ed.
  *
+ * @param h run action context
+ * @param msg SIP mesasge
  * @param type - type to convert to
  * @param v - rvalue to convert
  * @param c - rval_cache (cached v value if known/filled by another
  *            function), can be 0 (unknown/not needed)
  * @return pointer to a rvalue (reference to an existing one or a new
- *   one, @see rv_chg_in_place() and the above comment) or 0 on error.
+ * one, @see rv_chg_in_place() and the above comment), or 0 on error.
  */
 struct rvalue* rval_convert(struct run_act_ctx* h, struct sip_msg* msg,
                                                        enum rval_type type, struct rvalue* v,
@@ -965,6 +1346,9 @@ inline static int int_intop1(int* res, enum rval_expr_op op, int v)
                case RVE_LNOT_OP:
                        *res=!v;
                        break;
+               case RVE_BNOT_OP:
+                       *res=~v;
+                       break;
                default:
                        BUG("rv unsupported intop1 %d\n", op);
                        return -1;
@@ -974,7 +1358,7 @@ inline static int int_intop1(int* res, enum rval_expr_op op, int v)
 
 
 
-/** integer operation: *res= op v.
+/** integer operation: *res= v1 op v2
   * @return 0 on succes, \<0 on error
   */
 inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2)
@@ -997,12 +1381,28 @@ inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2)
                        }
                        *res=v1/v2;
                        break;
+               case RVE_MOD_OP:
+                       if (unlikely(v2==0)){
+                               ERR("rv mod by 0\n");
+                               return -1;
+                       }
+                       *res=v1%v2;
+                       break;
                case RVE_BOR_OP:
                        *res=v1|v2;
                        break;
                case RVE_BAND_OP:
                        *res=v1&v2;
                        break;
+               case RVE_BXOR_OP:
+                       *res=v1^v2;
+                       break;
+               case RVE_BLSHIFT_OP:
+                       *res=v1<<v2;
+                       break;
+               case RVE_BRSHIFT_OP:
+                       *res=v1>>v2;
+                       break;
                case RVE_LAND_OP:
                        *res=v1 && v2;
                        break;
@@ -1022,9 +1422,11 @@ inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2)
                        *res=v1 <= v2;
                        break;
                case RVE_EQ_OP:
+               case RVE_IEQ_OP:
                        *res=v1 == v2;
                        break;
                case RVE_DIFF_OP:
+               case RVE_IDIFF_OP:
                        *res=v1 != v2;
                        break;
                case RVE_CONCAT_OP:
@@ -1040,15 +1442,72 @@ inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2)
 
 
 
-inline static int bool_strop2( enum rval_expr_op op, int* res,
-                                                               str* s1, str* s2)
+/** internal helper: compare 2 RV_STR RVs.
+  * Warning: rv1 & rv2 must be RV_STR
+  * @return 0 on success, -1 on error
+  */
+inline static int bool_rvstrop2( enum rval_expr_op op, int* res,
+                                                               struct rvalue* rv1, struct rvalue* rv2)
 {
-       if (s1->len!=s2->len)
-               *res= op==RVE_DIFF_OP;
-       else if (memcmp(s1->s, s2->s, s1->len)==0)
-               *res= op==RVE_EQ_OP;
-       else
-               *res= op==RVE_DIFF_OP;
+       str* s1;
+       str* s2;
+       regex_t tmp_re;
+       
+       s1=&rv1->v.s;
+       s2=&rv2->v.s;
+       switch(op){
+               case RVE_EQ_OP:
+               case RVE_STREQ_OP:
+                       *res= (s1->len==s2->len) && (memcmp(s1->s, s2->s, s1->len)==0);
+                       break;
+               case RVE_DIFF_OP:
+               case RVE_STRDIFF_OP:
+                       *res= (s1->len!=s2->len) || (memcmp(s1->s, s2->s, s1->len)!=0);
+                       break;
+               case RVE_MATCH_OP:
+                       if (likely(rv2->flags & RV_RE_F)){
+                               *res=(regexec(rv2->v.re.regex, rv1->v.s.s, 0, 0, 0)==0);
+                       }else{
+                               /* we need to compile the RE on the fly */
+                               if (unlikely(regcomp(&tmp_re, s2->s,
+                                                                               REG_EXTENDED|REG_NOSUB|REG_ICASE))){
+                                       /* error */
+                                       ERR("Bad regular expression \"%s\"\n", s2->s);
+                                       goto error;
+                               }
+                               *res=(regexec(&tmp_re, s1->s, 0, 0, 0)==0);
+                               regfree(&tmp_re);
+                       }
+                       break;
+               default:
+                       BUG("rv unsupported intop %d\n", op);
+                       goto error;
+       }
+       return 0;
+error:
+       *res=0; /* false */
+       return -1;
+}
+
+
+
+/** integer returning operation on string: *res= op str (returns integer)
+  * @return 0 on succes, \<0 on error
+  */
+inline static int int_strop1(int* res, enum rval_expr_op op, str* s1)
+{
+       switch(op){
+               case RVE_STRLEN_OP:
+                       *res=s1->len;
+                       break;
+               case RVE_STREMPTY_OP:
+                       *res=(s1->len==0);
+                       break;
+               default:
+                       BUG("rv unsupported int_strop1 %d\n", op);
+                       *res=0;
+                       return -1;
+       }
        return 0;
 }
 
@@ -1294,7 +1753,7 @@ inline static int rval_str_lop2(struct run_act_ctx* h,
                goto error;
        if ((rv2=rval_convert(h, msg, RV_STR, r, c2))==0)
                goto error;
-       ret=bool_strop2(op, res, &rv1->v.s, &rv2->v.s);
+       ret=bool_rvstrop2(op, res, rv1, rv2);
        rval_destroy(rv1); 
        rval_destroy(rv2); 
        return ret;
@@ -1306,6 +1765,136 @@ error:
 
 
 
+/**
+ * @brief Integer operation on rval evaluated as string
+ * 
+ * Integer operation on rval evaluated as string, can use cached
+ * rvalues (c1 & c2).
+ * @param h run action context
+ * @param msg SIP message
+ * @param res will be set to the result
+ * @param op rvalue expression operation
+ * @param l rvalue
+ * @param c1 rvalue cache
+ * @return 0 success, -1 on error
+ */
+inline static int rval_int_strop1(struct run_act_ctx* h,
+                                                struct sip_msg* msg,
+                                                int* res,
+                                                enum rval_expr_op op,
+                                                struct rvalue* l,
+                                                struct rval_cache* c1)
+{
+       struct rvalue* rv1;
+       int ret;
+       
+       rv1=0;
+       ret=0;
+       if ((rv1=rval_convert(h, msg, RV_STR, l, c1))==0)
+               goto error;
+       ret=int_strop1(res, op, &rv1->v.s);
+       rval_destroy(rv1); 
+       return ret;
+error:
+       *res=0;
+       rval_destroy(rv1); 
+       return -1;
+}
+
+
+
+/**
+ * @brief Checks if rv is defined
+ * @param h run action context
+ * @param msg SIP message
+ * @param res set to the result 1 is defined, 0 not defined
+ * @param rv rvalue
+ * @param cache rvalue cache
+ * @return 0 on success, -1 on error
+ * @note Can use cached rvalues (cache). A rv can be undefined if it's
+ * an undefined avp or pvar or select or if it's NONE
+ * @note An error in the avp, pvar or select search is equivalent to
+ * undefined (and it's not reported)
+ */
+inline static int rv_defined(struct run_act_ctx* h,
+                                                struct sip_msg* msg, int* res,
+                                                struct rvalue* rv, struct rval_cache* cache)
+{
+       avp_t* r_avp;
+       int_str avp_val;
+       pv_value_t pval;
+       str tmp;
+       
+       *res=1;
+       switch(rv->type){
+               case RV_SEL:
+                       if (unlikely(cache && cache->cache_type==RV_CACHE_SELECT)){
+                               *res=(cache->val_type!=RV_NONE);
+                       }else
+                               /* run select returns 0 on success, -1 on error and >0 on 
+                                  undefined. error is considered undefined */
+                               *res=(run_select(&tmp, &rv->v.sel, msg)==0);
+                       break;
+               case RV_AVP:
+                       if (unlikely(cache && cache->cache_type==RV_CACHE_AVP)){
+                               *res=(cache->val_type!=RV_NONE);
+                       }else{
+                               r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
+                                                                                       &avp_val, rv->v.avps.index);
+                               if (unlikely(r_avp==0)){
+                                       *res=0;
+                               }
+                       }
+                       break;
+               case RV_PVAR:
+                       /* PV_VAL_NULL or pv_get_spec_value error => undef */
+                       if (unlikely(cache && cache->cache_type==RV_CACHE_PVAR)){
+                               *res=(cache->val_type!=RV_NONE);
+                       }else{
+                               memset(&pval, 0, sizeof(pval));
+                               if (likely(pv_get_spec_value(msg, &rv->v.pvs, &pval)==0)){
+                                       if ((pval.flags & PV_VAL_NULL) &&
+                                                       ! (pval.flags & (PV_VAL_INT|PV_VAL_STR))){
+                                               *res=0;
+                                       }
+                                       pv_value_destroy(&pval);
+                               }else{
+                                       *res=0; /* in case of error, consider it undef */
+                               }
+                       }
+                       break;
+               case RV_NONE:
+                       *res=0;
+                       break;
+               default:
+                       break;
+       }
+       return 0;
+}
+
+
+/**
+ * @brief Defined (integer) operation on rve
+ * @param h run action context
+ * @param msg SIP message
+ * @param res - set to  1 defined, 0 not defined
+ * @param rve rvalue expression
+ * @return 0 on success, -1 on error
+ */
+inline static int int_rve_defined(struct run_act_ctx* h,
+                                                struct sip_msg* msg, int* res,
+                                                struct rval_expr* rve)
+{
+       /* only a rval can be undefined, any expression consisting on more
+          then one rval => defined */
+       if (likely(rve->op==RVE_RVAL_OP))
+               return rv_defined(h, msg, res, &rve->left.rval, 0);
+       *res=1;
+       return 0;
+}
+
+
+
 /** evals an integer expr  to an int.
  * 
  *  *res=(int)eval(rve)
@@ -1315,7 +1904,7 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
                                                int* res, struct rval_expr* rve)
 {
        int i1, i2, ret;
-       struct rval_cache c1;
+       struct rval_cache c1, c2;
        struct rvalue* rv1;
        struct rvalue* rv2;
        
@@ -1323,26 +1912,38 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
        switch(rve->op){
                case RVE_RVAL_OP:
                        ret=rval_get_int(h, msg, res,  &rve->left.rval, 0);
+                       rval_get_int_handle_ret(ret, "rval expression conversion to int"
+                                                                               " failed", rve);
                        break;
                case RVE_UMINUS_OP:
                case RVE_BOOL_OP:
                case RVE_LNOT_OP:
+               case RVE_BNOT_OP:
                        if (unlikely(
                                        (ret=rval_expr_eval_int(h, msg, &i1, rve->left.rve)) <0) )
                                break;
                        ret=int_intop1(res, rve->op, i1);
                        break;
+               case RVE_INT_OP:
+                       ret=rval_expr_eval_int(h, msg, res, rve->left.rve);
+                       break;
                case RVE_MUL_OP:
                case RVE_DIV_OP:
+               case RVE_MOD_OP:
                case RVE_MINUS_OP:
                case RVE_PLUS_OP:
                case RVE_IPLUS_OP:
                case RVE_BOR_OP:
                case RVE_BAND_OP:
+               case RVE_BXOR_OP:
+               case RVE_BLSHIFT_OP:
+               case RVE_BRSHIFT_OP:
                case RVE_GT_OP:
                case RVE_GTE_OP:
                case RVE_LT_OP:
                case RVE_LTE_OP:
+               case RVE_IEQ_OP:
+               case RVE_IDIFF_OP:
                        if (unlikely(
                                        (ret=rval_expr_eval_int(h, msg, &i1, rve->left.rve)) <0) )
                                break;
@@ -1382,10 +1983,14 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
                case RVE_EQ_OP:
                case RVE_DIFF_OP:
                        /* if left is string, eval left & right as string and
-                          use string diff, else eval as int */
+                        *   use string diff.
+                        * if left is int eval as int using int diff
+                        * if left is undef, look at right and convert to right type
+                        */
                        rval_cache_init(&c1);
                        if (unlikely( (ret=rval_expr_eval_rvint(h, msg, &rv1, &i1,
                                                                                                        rve->left.rve, &c1))<0)){
+                               /* error */
                                rval_cache_clean(&c1);
                                break;
                        }
@@ -1394,46 +1999,149 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
                                rval_cache_clean(&c1);
                                if (unlikely( (ret=rval_expr_eval_int(h, msg, &i2,
                                                                                                                rve->right.rve)) <0) )
-                                       break;
+                                       break;  /* error */
                                ret=int_intop2(res, rve->op, i1, i2);
                        }else{
-                               if (unlikely((rv2=rval_expr_eval(h, msg,
-                                                                                                       rve->right.rve))==0)){
+                               /* not int => str or undef */
+                               /* check for undefined left operand */
+                               if (unlikely( c1.cache_type!=RV_CACHE_EMPTY &&
+                                                               c1.val_type==RV_NONE)){
+#ifdef UNDEF_EQ_ALWAYS_FALSE
+                                       /* undef == something  always false
+                                          undef != something  always true*/
+                                       ret=(rve->op==RVE_DIFF_OP);
+#elif defined UNDEF_EQ_UNDEF_TRUE
+                                       /* undef == something defined always false
+                                          undef == undef true */
+                                       if (int_rve_defined(h, msg, &i2, rve->right.rve)<0){
+                                               /* error */
+                                               rval_cache_clean(&c1);
+                                               rval_destroy(rv1);
+                                               break;
+                                       }
+                                       ret=(!i2) ^ (rve->op==RVE_DIFF_OP);
+#else  /* ! UNDEF_EQ_* */
+                                       /*  undef == val
+                                        *  => convert to (type_of(val)) (undef) == val */
+                                       rval_cache_init(&c2);
+                                       if (unlikely( (ret=rval_expr_eval_rvint(h, msg, &rv2, &i2,
+                                                                                                       rve->right.rve, &c2))<0)){
+                                               /* error */
+                                               rval_cache_clean(&c1);
+                                               rval_cache_clean(&c2);
+                                               rval_destroy(rv1);
+                                               break;
+                                       }
+                                       if (rv2==0){
+                                               /* int */
+                                               ret=int_intop2(res, rve->op, 0 /* undef */, i2);
+                                       }else{
+                                               /* str or undef */
+                                               ret=rval_str_lop2(h, msg, res, rve->op, rv1, &c1,
+                                                                                       rv2, &c2);
+                                               rval_cache_clean(&c2);
+                                               rval_destroy(rv2);
+                                       }
+#endif /* UNDEF_EQ_* */
+                                       rval_cache_clean(&c1);
                                        rval_destroy(rv1);
+                               }else{
+                                       /* left value == defined and != int => str
+                                        * => lval == (str) val */
+                                       if (unlikely((rv2=rval_expr_eval(h, msg,
+                                                                                                               rve->right.rve))==0)){
+                                               /* error */
+                                               rval_destroy(rv1);
+                                               rval_cache_clean(&c1);
+                                               break;
+                                       }
+                                       ret=rval_str_lop2(h, msg, res, rve->op, rv1, &c1, rv2, 0);
                                        rval_cache_clean(&c1);
-                                       ret=-1;
-                                       break;
+                                       rval_destroy(rv1);
+                                       rval_destroy(rv2);
                                }
-                               ret=rval_str_lop2(h, msg, res, rve->op, rv1, &c1, rv2, 0);
+                       }
+                       break;
+               case RVE_CONCAT_OP:
+                       /* eval expression => string */
+                       if (unlikely((rv1=rval_expr_eval(h, msg, rve))==0)){
+                               ret=-1;
+                               break;
+                       }
+                       /* convert to int */
+                       ret=rval_get_int(h, msg, res, rv1, 0); /* convert to int */
+                       rval_get_int_handle_ret(ret, "rval expression conversion to int"
+                                                                               " failed", rve);
+                       rval_destroy(rv1);
+                       break;
+               case RVE_STR_OP:
+                       /* (str)expr => eval expression */
+                       rval_cache_init(&c1);
+                       if (unlikely((ret=rval_expr_eval_rvint(h, msg, &rv1, res,
+                                                                                                       rve->left.rve, &c1))<0)){
+                               /* error */
                                rval_cache_clean(&c1);
-                               rval_destroy(rv1);
-                               rval_destroy(rv2);
+                               break;
                        }
+                       if (unlikely(rv1)){
+                               /* expr evaluated to string => (int)(str)v == (int)v */
+                               ret=rval_get_int(h, msg, res, rv1, &c1); /* convert to int */
+                               rval_get_int_handle_ret(ret, "rval expression conversion"
+                                                                                               " to int failed", rve);
+                               rval_destroy(rv1);
+                               rval_cache_clean(&c1);
+                       } /* else (rv1==0)
+                                => expr evaluated to int => 
+                                return (int)(str)v == (int)v => do nothing */
                        break;
+
 #if 0
+                       /* same thing as above, but in a not optimized, easier to
+                          understand way */
+                       /* 1. (str) expr => eval expr */
+                       if (unlikely((rv1=rval_expr_eval(h, msg, rve->left.rve))==0)){
+                               ret=-1;
+                               break;
+                       }
+                       /* 2. convert to str and then convert to int
+                          but since (int)(str)v == (int)v skip over (str)v */
+                       ret=rval_get_int(h, msg, res, rv1, 0); /* convert to int */
+                       rval_destroy(rv1);
+                       break;
+#endif
+               case RVE_DEFINED_OP:
+                       ret=int_rve_defined(h, msg, res, rve->left.rve);
+                       break;
+               case RVE_STREQ_OP:
+               case RVE_STRDIFF_OP:
                case RVE_MATCH_OP:
-                               if (unlikely((rv1=rval_expr_eval(h, msg, rve->left.rve))==0)){
-                                       ret=-1;
-                                       break;
-                               }
-                               if (unlikely((rv2=rval_expr_eval(h, msg,
-                                                                                                       rve->right.rve))==0)){
-                                       rval_destroy(rv1);
-                                       ret=-1;
-                                       break;
-                               }
-                               ret=rval_str_lop2(res, rve->op, rv1, 0, rv2, 0);
+                       if (unlikely((rv1=rval_expr_eval(h, msg, rve->left.rve))==0)){
+                               ret=-1;
+                               break;
+                       }
+                       if (unlikely((rv2=rval_expr_eval(h, msg, rve->right.rve))==0)){
                                rval_destroy(rv1);
-                               rval_destroy(rv2);
+                               ret=-1;
+                               break;
+                       }
+                       ret=rval_str_lop2(h, msg, res, rve->op, rv1, 0, rv2, 0);
+                       rval_destroy(rv1);
+                       rval_destroy(rv2);
                        break;
-#endif
-               case RVE_CONCAT_OP:
-                       *res=0;
-                       ret=-1;
+               case RVE_STRLEN_OP:
+               case RVE_STREMPTY_OP:
+                       if (unlikely((rv1=rval_expr_eval(h, msg, rve->left.rve))==0)){
+                                       ret=-1;
+                                       break;
+                       }
+                       ret=rval_int_strop1(h, msg, res, rve->op, rv1, 0);
+                       rval_destroy(rv1);
                        break;
                case RVE_NONE_OP:
                /*default:*/
-                       BUG("invalid rval int expression operation %d\n", rve->op);
+                       BUG("invalid rval int expression operation %d (%d,%d-%d,%d)\n",
+                                       rve->op, rve->fpos.s_line, rve->fpos.s_col,
+                                       rve->fpos.e_line, rve->fpos.e_col);
                        ret=-1;
        };
        return ret;
@@ -1441,11 +2149,22 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
 
 
 
-/** evals a rval expr. into an int or another rv(str).
- * WARNING: rv result (rv_res) must be rval_destroy()'ed if non-null
- * (it might be a reference to another rval). The result can be 
+/**
+ * @brief Evals a rval expression into an int or another rv(str)
+ * @warning rv result (rv_res) must be rval_destroy()'ed if non-null
+ * (it might be a reference to another rval). The result can be
  * modified only if rv_chg_in_place() returns true.
- * @result  0 on success, -1 on error,  sets *res_rv or *res_i.
+ * @param h run action context
+ * @param msg SIP message
+ * @param res_rv pointer to rvalue result, if non-null it means the 
+ * expression evaluated to a non-int (str), which will be stored here.
+ * @param res_i pointer to int result, if res_rv==0 and the function
+ * returns success => the result is an int which will be stored here.
+ * @param rve expression that will be evaluated.
+ * @param cache write-only value cache, it might be filled if non-null and
+ * empty (rval_cache_init()). If non-null, it _must_ be rval_cache_clean()'ed
+ * when done. 
+ * @return 0 on success, -1 on error, sets *res_rv or *res_i.
  */
 int rval_expr_eval_rvint(                         struct run_act_ctx* h,
                                                                           struct sip_msg* msg,
@@ -1472,12 +2191,10 @@ int rval_expr_eval_rvint(                          struct run_act_ctx* h,
                        type=rval_get_btype(h, msg, rv1, cache);
                        if (type==RV_INT){
                                        r=rval_get_int(h, msg, res_i, rv1, cache);
-                                       if (unlikely(r<0)){
-                                               ERR("rval expression evaluation failed\n");
-                                               goto error;
-                                       }
+                                       rval_get_int_handle_ret(r, "rval expression conversion"
+                                                                                               " to int failed", rve);
                                        *res_rv=0;
-                                       ret=0;
+                                       ret=r; /* equiv. to if (r<0) goto error */
                        }else{
                                /* RV_STR, RV_PVAR, RV_AVP a.s.o => return rv1 and the 
                                   cached resolved value in cache*/
@@ -1489,11 +2206,16 @@ int rval_expr_eval_rvint(                          struct run_act_ctx* h,
                case RVE_UMINUS_OP:
                case RVE_BOOL_OP:
                case RVE_LNOT_OP:
+               case RVE_BNOT_OP:
                case RVE_MINUS_OP:
                case RVE_MUL_OP:
                case RVE_DIV_OP:
+               case RVE_MOD_OP:
                case RVE_BOR_OP:
                case RVE_BAND_OP:
+               case RVE_BXOR_OP:
+               case RVE_BLSHIFT_OP:
+               case RVE_BRSHIFT_OP:
                case RVE_LAND_OP:
                case RVE_LOR_OP:
                case RVE_GT_OP:
@@ -1502,7 +2224,16 @@ int rval_expr_eval_rvint(                           struct run_act_ctx* h,
                case RVE_LTE_OP:
                case RVE_EQ_OP:
                case RVE_DIFF_OP:
+               case RVE_IEQ_OP:
+               case RVE_IDIFF_OP:
                case RVE_IPLUS_OP:
+               case RVE_STREQ_OP:
+               case RVE_STRDIFF_OP:
+               case RVE_MATCH_OP:
+               case RVE_STRLEN_OP:
+               case RVE_STREMPTY_OP:
+               case RVE_DEFINED_OP:
+               case RVE_INT_OP:
                        /* operator forces integer type */
                        ret=rval_expr_eval_int(h, msg, res_i, rve);
                        *res_rv=0;
@@ -1511,14 +2242,21 @@ int rval_expr_eval_rvint(                          struct run_act_ctx* h,
                        rval_cache_init(&c1);
                        r=rval_expr_eval_rvint(h, msg, &rv1, &i, rve->left.rve, &c1);
                        if (unlikely(r<0)){
-                               ERR("rval expression evaluation failed\n");
+                               ERR("rval expression evaluation failed (%d,%d-%d,%d)\n",
+                                               rve->left.rve->fpos.s_line, rve->left.rve->fpos.s_col,
+                                               rve->left.rve->fpos.e_line, rve->left.rve->fpos.e_col
+                                       );
                                rval_cache_clean(&c1);
                                goto error;
                        }
                        if (rv1==0){
                                if (unlikely((r=rval_expr_eval_int(h, msg, &j,
                                                                                                                rve->right.rve))<0)){
-                                               ERR("rval expression evaluation failed\n");
+                                               ERR("rval expression evaluation failed (%d,%d-%d,%d)"
+                                                               "\n", rve->right.rve->fpos.s_line,
+                                                               rve->right.rve->fpos.s_col,
+                                                               rve->right.rve->fpos.e_line,
+                                                               rve->right.rve->fpos.e_col);
                                                rval_cache_clean(&c1);
                                                goto error;
                                }
@@ -1527,7 +2265,11 @@ int rval_expr_eval_rvint(                           struct run_act_ctx* h,
                        }else{
                                rv2=rval_expr_eval(h, msg, rve->right.rve);
                                if (unlikely(rv2==0)){
-                                       ERR("rval expression evaluation failed\n");
+                                       ERR("rval expression evaluation failed (%d,%d-%d,%d)\n",
+                                                               rve->right.rve->fpos.s_line,
+                                                               rve->right.rve->fpos.s_col,
+                                                               rve->right.rve->fpos.e_line,
+                                                               rve->right.rve->fpos.e_col);
                                        rval_cache_clean(&c1);
                                        goto error;
                                }
@@ -1537,12 +2279,15 @@ int rval_expr_eval_rvint(                          struct run_act_ctx* h,
                        rval_cache_clean(&c1);
                        break;
                case RVE_CONCAT_OP:
+               case RVE_STR_OP:
                        *res_rv=rval_expr_eval(h, msg, rve);
                        ret=-(*res_rv==0);
                        break;
                case RVE_NONE_OP:
                /*default:*/
-                       BUG("invalid rval expression operation %d\n", rve->op);
+                       BUG("invalid rval expression operation %d (%d,%d-%d,%d)\n",
+                                       rve->op, rve->fpos.s_line, rve->fpos.s_col,
+                                       rve->fpos.e_line, rve->fpos.e_col);
                        goto error;
        };
        rval_destroy(rv1);
@@ -1556,11 +2301,15 @@ error:
 
 
 
-/** evals a rval expr..
- * WARNING: result must be rval_destroy()'ed if non-null (it might be
+/**
+ * @brief Evals a rval expression
+ * @warning result must be rval_destroy()'ed if non-null (it might be
  * a reference to another rval). The result can be modified only
  * if rv_chg_in_place() returns true.
- * @result rvalue on success, 0 on error
+ * @param h run action context
+ * @param msg SIP message
+ * @param rve rvalue expression
+ * @return rvalue on success, 0 on error
  */
 struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
                                                                struct rval_expr* rve)
@@ -1584,11 +2333,16 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
                case RVE_UMINUS_OP:
                case RVE_BOOL_OP:
                case RVE_LNOT_OP:
+               case RVE_BNOT_OP:
                case RVE_MINUS_OP:
                case RVE_MUL_OP:
                case RVE_DIV_OP:
+               case RVE_MOD_OP:
                case RVE_BOR_OP:
                case RVE_BAND_OP:
+               case RVE_BXOR_OP:
+               case RVE_BLSHIFT_OP:
+               case RVE_BRSHIFT_OP:
                case RVE_LAND_OP:
                case RVE_LOR_OP:
                case RVE_GT_OP:
@@ -1597,7 +2351,16 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
                case RVE_LTE_OP:
                case RVE_EQ_OP:
                case RVE_DIFF_OP:
+               case RVE_IEQ_OP:
+               case RVE_IDIFF_OP:
                case RVE_IPLUS_OP:
+               case RVE_STREQ_OP:
+               case RVE_STRDIFF_OP:
+               case RVE_MATCH_OP:
+               case RVE_STRLEN_OP:
+               case RVE_STREMPTY_OP:
+               case RVE_DEFINED_OP:
+               case RVE_INT_OP:
                        /* operator forces integer type */
                        r=rval_expr_eval_int(h, msg, &i, rve);
                        if (likely(r==0)){
@@ -1609,29 +2372,39 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
                                }
                                return ret;
                        }else{
-                               ERR("rval expression evaluation failed\n");
+                               ERR("rval expression evaluation failed (%d,%d-%d,%d)\n",
+                                               rve->fpos.s_line, rve->fpos.s_col,
+                                               rve->fpos.e_line, rve->fpos.e_col);
                                goto error;
                        }
                        break;
                case RVE_PLUS_OP:
                        rv1=rval_expr_eval(h, msg, rve->left.rve);
                        if (unlikely(rv1==0)){
-                               ERR("rval expression evaluation failed\n");
+                               ERR("rval expression evaluation failed (%d,%d-%d,%d)\n",
+                                               rve->left.rve->fpos.s_line, rve->left.rve->fpos.s_col,
+                                               rve->left.rve->fpos.e_line, rve->left.rve->fpos.e_col);
                                goto error;
                        }
                        rval_cache_init(&c1);
                        type=rval_get_btype(h, msg, rv1, &c1);
                        switch(type){
                                case RV_INT:
-                                       if (unlikely((r=rval_get_int(h, msg, &i, rv1, &c1))<0)){
+                                       r=rval_get_int(h, msg, &i, rv1, &c1);
+                                       rval_get_int_handle_ret(r, "rval expression left side "
+                                                                                               "conversion to int failed",
+                                                                                       rve);
+                                       if (unlikely(r<0)){
                                                rval_cache_clean(&c1);
-                                               ERR("rval expression evaluation failed\n");
                                                goto error;
                                        }
                                        if (unlikely((r=rval_expr_eval_int(h, msg, &j,
                                                                                                                rve->right.rve))<0)){
                                                rval_cache_clean(&c1);
-                                               ERR("rval expression evaluation failed\n");
+                                               ERR("rval expression evaluation failed (%d,%d-%d,%d):"
+                                                               " could not evaluate right side to int\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col);
                                                goto error;
                                        }
                                        int_intop2(&r, rve->op, i, j);
@@ -1650,38 +2423,60 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
                                        }
                                        break;
                                case RV_STR:
+                               case RV_NONE:
                                        rv2=rval_expr_eval(h, msg, rve->right.rve);
                                        if (unlikely(rv2==0)){
-                                               ERR("rval expression evaluation failed\n");
+                                               ERR("rval expression evaluation failed (%d,%d-%d,%d)"
+                                                               "\n", rve->right.rve->fpos.s_line,
+                                                               rve->right.rve->fpos.s_col,
+                                                               rve->right.rve->fpos.e_line,
+                                                               rve->right.rve->fpos.e_col);
                                                rval_cache_clean(&c1);
                                                goto error;
                                        }
                                        ret=rval_str_add2(h, msg, rv1, &c1, rv2, 0);
                                        break;
                                default:
-                                       BUG("rv unsupported basic type %d\n", type);
-                               case RV_NONE:
-                                       rval_cache_clean(&c1);
-                                       goto error;
+                                       BUG("rv unsupported basic type %d (%d,%d-%d,%d)\n", type,
+                                                       rve->fpos.s_line, rve->fpos.s_col,
+                                                       rve->fpos.e_line, rve->fpos.e_col);
                        }
                        rval_cache_clean(&c1);
                        break;
                case RVE_CONCAT_OP:
                        rv1=rval_expr_eval(h, msg, rve->left.rve);
                        if (unlikely(rv1==0)){
-                               ERR("rval expression evaluation failed\n");
+                               ERR("rval expression evaluation failed (%d,%d-%d,%d)\n",
+                                               rve->left.rve->fpos.s_line, rve->left.rve->fpos.s_col,
+                                               rve->left.rve->fpos.e_line, rve->left.rve->fpos.e_col);
                                goto error;
                        }
                        rv2=rval_expr_eval(h, msg, rve->right.rve);
                        if (unlikely(rv2==0)){
-                               ERR("rval expression evaluation failed\n");
+                               ERR("rval expression evaluation failed (%d,%d-%d,%d)\n",
+                                               rve->right.rve->fpos.s_line,
+                                               rve->right.rve->fpos.s_col,
+                                               rve->right.rve->fpos.e_line,
+                                               rve->right.rve->fpos.e_col);
                                goto error;
                        }
                        ret=rval_str_add2(h, msg, rv1, 0, rv2, 0);
                        break;
+               case RVE_STR_OP:
+                       rv1=rval_expr_eval(h, msg, rve->left.rve);
+                       if (unlikely(rv1==0)){
+                               ERR("rval expression evaluation failed (%d,%d-%d,%d)\n",
+                                               rve->left.rve->fpos.s_line, rve->left.rve->fpos.s_col,
+                                               rve->left.rve->fpos.e_line, rve->left.rve->fpos.e_col);
+                               goto error;
+                       }
+                       ret=rval_convert(h, msg, RV_STR, rv1, 0);
+                       break;
                case RVE_NONE_OP:
                /*default:*/
-                       BUG("invalid rval expression operation %d\n", rve->op);
+                       BUG("invalid rval expression operation %d (%d,%d-%d,%d)\n",
+                                       rve->op, rve->fpos.s_line, rve->fpos.s_col,
+                                       rve->fpos.e_line, rve->fpos.e_col);
                        goto error;
        };
        rval_destroy(rv1);
@@ -1739,7 +2534,7 @@ struct rval_expr* mk_rval_expr_v(enum rval_type rv_type, void* val,
        rve=pkg_malloc(sizeof(*rve));
        if (rve==0) 
                return 0;
-       memset(rve, sizeof(*rve), 0);
+       memset(rve, 0, sizeof(*rve));
        flags=0;
        switch(rv_type){
                case RV_INT:
@@ -1785,10 +2580,12 @@ struct rval_expr* mk_rval_expr_v(enum rval_type rv_type, void* val,
 
 
 
-/** create a unary op. rval_expr..
+/**
+ * @brief Create a unary op. rval_expr
  * ret= op rve1
  * @param op   - rval expr. unary operator
  * @param rve1 - rval expr. on which the operator will act.
+ * @param pos configuration position
  * @return new pkg_malloc'ed rval_expr or 0 on error.
  */
 struct rval_expr* mk_rval_expr1(enum rval_expr_op op, struct rval_expr* rve1,
@@ -1800,6 +2597,12 @@ struct rval_expr* mk_rval_expr1(enum rval_expr_op op, struct rval_expr* rve1,
                case RVE_UMINUS_OP:
                case RVE_BOOL_OP:
                case RVE_LNOT_OP:
+               case RVE_BNOT_OP:
+               case RVE_STRLEN_OP:
+               case RVE_STREMPTY_OP:
+               case RVE_DEFINED_OP:
+               case RVE_INT_OP:
+               case RVE_STR_OP:
                        break;
                default:
                        BUG("unsupported unary operator %d\n", op);
@@ -1808,7 +2611,7 @@ struct rval_expr* mk_rval_expr1(enum rval_expr_op op, struct rval_expr* rve1,
        ret=pkg_malloc(sizeof(*ret));
        if (ret==0) 
                return 0;
-       memset(ret, sizeof(*ret), 0);
+       memset(ret, 0, sizeof(*ret));
        ret->op=op;
        ret->left.rve=rve1;
        if (pos) ret->fpos=*pos;
@@ -1817,11 +2620,13 @@ struct rval_expr* mk_rval_expr1(enum rval_expr_op op, struct rval_expr* rve1,
 
 
 
-/** create a rval_expr. from 2 other rval exprs, using op.
+/**
+ * @brief Create a rval_expr. from 2 other rval exprs, using op
  * ret = rve1 op rve2
  * @param op   - rval expr. operator
  * @param rve1 - rval expr. on which the operator will act.
  * @param rve2 - rval expr. on which the operator will act.
+ * @param pos configuration position
  * @return new pkg_malloc'ed rval_expr or 0 on error.
  */
 struct rval_expr* mk_rval_expr2(enum rval_expr_op op, struct rval_expr* rve1,
@@ -1833,9 +2638,13 @@ struct rval_expr* mk_rval_expr2(enum rval_expr_op op, struct rval_expr* rve1,
        switch(op){
                case RVE_MUL_OP:
                case RVE_DIV_OP:
+               case RVE_MOD_OP:
                case RVE_MINUS_OP:
                case RVE_BOR_OP:
                case RVE_BAND_OP:
+               case RVE_BXOR_OP:
+               case RVE_BLSHIFT_OP:
+               case RVE_BRSHIFT_OP:
                case RVE_LAND_OP:
                case RVE_LOR_OP:
                case RVE_GT_OP:
@@ -1846,6 +2655,11 @@ struct rval_expr* mk_rval_expr2(enum rval_expr_op op, struct rval_expr* rve1,
                case RVE_IPLUS_OP:
                case RVE_EQ_OP:
                case RVE_DIFF_OP:
+               case RVE_IEQ_OP:
+               case RVE_IDIFF_OP:
+               case RVE_STREQ_OP:
+               case RVE_STRDIFF_OP:
+               case RVE_MATCH_OP:
                case RVE_CONCAT_OP:
                        break;
                default:
@@ -1855,7 +2669,7 @@ struct rval_expr* mk_rval_expr2(enum rval_expr_op op, struct rval_expr* rve1,
        ret=pkg_malloc(sizeof(*ret));
        if (ret==0) 
                return 0;
-       memset(ret, sizeof(*ret), 0);
+       memset(ret, 0, sizeof(*ret));
        ret->op=op;
        ret->left.rve=rve1;
        ret->right.rve=rve2;
@@ -1874,17 +2688,30 @@ static int rve_op_is_assoc(enum rval_expr_op op)
                case RVE_UMINUS_OP:
                case RVE_BOOL_OP:
                case RVE_LNOT_OP:
+               case RVE_BNOT_OP:
+               case RVE_STRLEN_OP:
+               case RVE_STREMPTY_OP:
+               case RVE_DEFINED_OP:
+               case RVE_INT_OP:
+               case RVE_STR_OP:
                        /* one operand expression => cannot be assoc. */
                        return 0;
                case RVE_DIV_OP:
+               case RVE_MOD_OP:
                case RVE_MINUS_OP:
+               case RVE_BLSHIFT_OP:
+               case RVE_BRSHIFT_OP:
                        return 0;
                case RVE_PLUS_OP:
+                       /* the generic plus is not assoc, e.g.
+                          "a" + 1 + "2" => "a12" in one case and "a3" in the other */
+                       return 0;
                case RVE_IPLUS_OP:
                case RVE_CONCAT_OP:
                case RVE_MUL_OP:
                case RVE_BAND_OP:
                case RVE_BOR_OP:
+               case RVE_BXOR_OP:
                        return 1;
                case RVE_LAND_OP:
                case RVE_LOR_OP:
@@ -1895,6 +2722,11 @@ static int rve_op_is_assoc(enum rval_expr_op op)
                case RVE_LTE_OP:
                case RVE_EQ_OP:
                case RVE_DIFF_OP:
+               case RVE_IEQ_OP:
+               case RVE_IDIFF_OP:
+               case RVE_STREQ_OP:
+               case RVE_STRDIFF_OP:
+               case RVE_MATCH_OP:
                        return 0;
        }
        return 0;
@@ -1903,7 +2735,7 @@ static int rve_op_is_assoc(enum rval_expr_op op)
 
 
 /** returns true if the operator is commutative. */
-static int rve_op_is_commutative(enum rval_expr_op op, enum rval_type type)
+static int rve_op_is_commutative(enum rval_expr_op op)
 {
        switch(op){
                case RVE_NONE_OP:
@@ -1911,29 +2743,51 @@ static int rve_op_is_commutative(enum rval_expr_op op, enum rval_type type)
                case RVE_UMINUS_OP:
                case RVE_BOOL_OP:
                case RVE_LNOT_OP:
+               case RVE_BNOT_OP:
+               case RVE_STRLEN_OP:
+               case RVE_STREMPTY_OP:
+               case RVE_DEFINED_OP:
+               case RVE_INT_OP:
+               case RVE_STR_OP:
                        /* one operand expression => cannot be commut. */
                        return 0;
                case RVE_DIV_OP:
+               case RVE_MOD_OP:
                case RVE_MINUS_OP:
+               case RVE_BLSHIFT_OP:
+               case RVE_BRSHIFT_OP:
                        return 0;
                case RVE_PLUS_OP:
-                       return type==RV_INT; /* commutative only for INT*/
+                       /* non commut. when diff. type 
+                          (e.g 1 + "2" != "2" + 1 ) => non commut. in general
+                          (specific same type versions are covered by IPLUS & CONCAT) */
+                       return 0;
                case RVE_IPLUS_OP:
                case RVE_MUL_OP:
                case RVE_BAND_OP:
                case RVE_BOR_OP:
-                       return 1;
+               case RVE_BXOR_OP:
                case RVE_LAND_OP:
                case RVE_LOR_OP:
+               case RVE_IEQ_OP:
+               case RVE_IDIFF_OP:
+               case RVE_STREQ_OP:
+               case RVE_STRDIFF_OP:
                        return 1;
                case RVE_GT_OP:
                case RVE_GTE_OP:
                case RVE_LT_OP:
                case RVE_LTE_OP:
-               case RVE_EQ_OP:
-               case RVE_DIFF_OP:
                case RVE_CONCAT_OP:
+               case RVE_MATCH_OP:
                        return 0;
+               case RVE_DIFF_OP:
+               case RVE_EQ_OP:
+                       /* non. commut. in general, only for same type e.g.:
+                          "" == 0  diff. 0 == "" ( "" == "0" and 0 == 0)
+                          same type versions are covered by IEQ, IDIFF, STREQ, STRDIFF
+                        */
+                       return 0 /* asymmetrical undef handling */;
        }
        return 0;
 }
@@ -2016,7 +2870,7 @@ static int fix_rval(struct rvalue* rv)
                        return fix_actions(rv->v.action);
                case RV_SEL:
                        if (resolve_select(&rv->v.sel)<0){
-                               BUG("Unable to resolve select\n");
+                               ERR("Unable to resolve select\n");
                                print_select(&rv->v.sel);
                        }
                        return 0;
@@ -2036,6 +2890,50 @@ static int fix_rval(struct rvalue* rv)
 
 
 
+/**
+ * @brief Helper function: replace a rve (in-place) with a constant rval_val
+ * @warning since it replaces in-place, one should make sure that if
+ * rve is in fact a rval (rve->op==RVE_RVAL_OP), no reference is kept
+ * to the rval!
+ * @param rve expression to be replaced (in-place)
+ * @param type rvalue type
+ * @param v pointer to a rval_val union containing the replacement value.
+ * @param flags value flags (how it was alloc'ed, e.g.: RV_CNT_ALLOCED_F)
+ * @return 0 on success, -1 on error
+ */
+static int rve_replace_with_val(struct rval_expr* rve, enum rval_type type,
+                                                               union rval_val* v, int flags)
+{
+       int refcnt;
+       
+       refcnt=1; /* replaced-in-place rval refcnt */
+       if (rve->op!=RVE_RVAL_OP){
+               rve_destroy(rve->left.rve);
+               if (rve_op_unary(rve->op)==0)
+                       rve_destroy(rve->right.rve);
+       }else{
+               if (rve->left.rval.refcnt!=1){
+                       BUG("trying to replace a referenced rval! (refcnt=%d)\n",
+                                       rve->left.rval.refcnt);
+                       /* try to recover */
+                       refcnt=rve->left.rval.refcnt;
+                       abort(); /* find bugs quicker -- andrei */
+               }
+               rval_destroy(&rve->left.rval);
+       }
+       rval_init(&rve->left.rval, type, v, flags);
+       rve->left.rval.refcnt=refcnt;
+       rval_init(&rve->right.rval, RV_NONE, 0, 0);
+       rve->op=RVE_RVAL_OP;
+       return 0;
+}
+
+
+
+/** helper function: replace a rve (in-place) with a constant rvalue.
+ * @param rve - expression to be replaced (in-place)
+ * @param rv   - pointer to the replacement _constant_ rvalue structure
+ * @return 0 on success, -1 on error */
 static int rve_replace_with_ct_rv(struct rval_expr* rve, struct rvalue* rv)
 {
        enum rval_type type;
@@ -2047,30 +2945,104 @@ static int rve_replace_with_ct_rv(struct rval_expr* rve, struct rvalue* rv)
        flags=0;
        if (rv->type==RV_INT){
                if (rval_get_int(0, 0, &i, rv, 0)!=0){
-                       BUG("unexpected int evaluation failure\n");
+                       BUG("unexpected int evaluation failure (%d,%d-%d,%d)\n",
+                                       rve->fpos.s_line, rve->fpos.s_col,
+                                       rve->fpos.e_line, rve->fpos.e_col);
                        return -1;
                }
                v.l=i;
        }else if(rv->type==RV_STR){
                if (rval_get_str(0, 0, &v.s, rv, 0)<0){
-                       BUG("unexpected str evaluation failure\n");
+                       BUG("unexpected str evaluation failure(%d,%d-%d,%d)\n",
+                                       rve->fpos.s_line, rve->fpos.s_col,
+                                       rve->fpos.e_line, rve->fpos.e_col);
                        return -1;
                }
-               flags=RV_CNT_ALLOCED_F;
+               flags|=RV_CNT_ALLOCED_F;
        }else{
-               BUG("unknown constant expression type %d\n", rv->type);
+               BUG("unknown constant expression type %d (%d,%d-%d,%d)\n", rv->type,
+                               rve->fpos.s_line, rve->fpos.s_col,
+                               rve->fpos.e_line, rve->fpos.e_col);
                return -1;
        }
-       if (rve->op!=RVE_RVAL_OP){
-               rve_destroy(rve->left.rve);
-               if (rve_op_unary(rve->op)==0)
-                       rve_destroy(rve->right.rve);
-       }else
-               rval_destroy(&rve->left.rval);
-       rval_init(&rve->left.rval, type, &v, flags);
-       rval_init(&rve->right.rval, RV_NONE, 0, 0);
-       rve->op=RVE_RVAL_OP;
+       return rve_replace_with_val(rve, type, &v, flags);
+}
+
+
+
+/** try to replace the right side of the rve with a compiled regex.
+  * @return 0 on success and -1 on error.
+ */
+static int fix_match_rve(struct rval_expr* rve)
+{
+       struct rvalue* rv;
+       regex_t* re;
+       union rval_val v;
+       int flags;
+       int ret;
+
+       rv=0;
+       v.s.s=0;
+       v.re.regex=0;
+       /* normal fix-up for the  left side */
+       ret=fix_rval_expr((void*)rve->left.rve);
+       if (ret<0) return ret;
+       
+       /* fixup the right side (RE) */
+       if (rve_is_constant(rve->right.rve)){
+               if ((rve_guess_type(rve->right.rve)!=RV_STR)){
+                       ERR("fixup failure(%d,%d-%d,%d): left side of  =~ is not string"
+                                       " (%d,%d)\n",   rve->fpos.s_line, rve->fpos.s_col,
+                                                                       rve->fpos.e_line, rve->fpos.e_col,
+                                                                       rve->right.rve->fpos.s_line,
+                                                                       rve->right.rve->fpos.s_col);
+                       goto error;
+               }
+               if ((rv=rval_expr_eval(0, 0, rve->right.rve))==0){
+                       ERR("fixup failure(%d,%d-%d,%d):  bad RE expression\n",
+                                       rve->right.rve->fpos.s_line, rve->right.rve->fpos.s_col,
+                                       rve->right.rve->fpos.e_line, rve->right.rve->fpos.e_col);
+                       goto error;
+               }
+               if (rval_get_str(0, 0, &v.s, rv, 0)<0){
+                       BUG("fixup unexpected failure (%d,%d-%d,%d)\n",
+                                       rve->fpos.s_line, rve->fpos.s_col,
+                                       rve->fpos.e_line, rve->fpos.e_col);
+                       goto error;
+               }
+               /* we have the str, we don't need the rv anymore */
+               rval_destroy(rv);
+               rv=0;
+               re=pkg_malloc(sizeof(*re));
+               if (re==0){
+                       ERR("out of memory\n");
+                       goto error;
+               }
+               /* same flags as for expr. =~ (fix_expr()) */
+               if (regcomp(re, v.s.s, REG_EXTENDED|REG_NOSUB|REG_ICASE)){
+                       pkg_free(re);
+                       ERR("Bad regular expression \"%s\"(%d,%d-%d,%d)\n", v.s.s,
+                                       rve->right.rve->fpos.s_line, rve->right.rve->fpos.s_col,
+                                       rve->right.rve->fpos.e_line, rve->right.rve->fpos.e_col);
+                       goto error;
+               }
+               v.re.regex=re;
+               flags=RV_RE_F|RV_RE_ALLOCED_F|RV_CNT_ALLOCED_F;
+               if (rve_replace_with_val(rve->right.rve, RV_STR, &v, flags)<0)
+                       goto error;
+       }else{
+               /* right side is not constant => normal fixup */
+               return fix_rval_expr((void*)rve->right.rve);
+       }
        return 0;
+error:
+       if (rv) rval_destroy(rv);
+       if (v.s.s) pkg_free(v.s.s);
+       if (v.re.regex){
+               regfree(v.re.regex);
+               pkg_free(v.re.regex);
+       }
+       return -1;
 }
 
 
@@ -2091,10 +3063,43 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
        enum rval_expr_op op;
        struct cfg_pos pos;
        int right; /* debugging msg */
+       int dbg; /* debugging msg on/off */
+
+/* helper macro: replace in-place a <ctype> type rve with v (another rve).
+ * if type_of(v)== <ctype> => rve:=*v (copy v contents into rve and free v)
+ * else if type_of(v)!=<ctype> => rve:= (ctype) v (casts v to <ctype>)
+ * Uses pos.
+ * ctype can be INT or STR
+ * WARNING: - v might be pkg_free()'d
+ *          - rve members _are_ _not_ freed or destroyed
+ */
+#define replace_rve_type_cast(e, v, ctype) \
+       do{\
+               if ( rve_guess_type((v)) == RV_##ctype ){\
+                       /* if type_of($v)==int we don't need to add an \
+                          int cast operator => replace with v */\
+                       pos=(e)->fpos; \
+                       *(e)=*(v); /* replace e with v (in-place) */ \
+                       (e)->fpos=pos; \
+                       pkg_free((v)); /* rve_destroy(v_rve) would free everything*/ \
+               }else{\
+                       /* unknown type or str => (int) $v */ \
+                       (e)->op=RVE_##ctype##_OP; \
+                       (e)->left.rve=(v); \
+                       (e)->right.rve=0; \
+               }\
+       }while(0)
+       
+/* helper macro: replace in-place an int type rve with v (another rve).*/
+#define replace_int_rve(e, v) replace_rve_type_cast(e, v, INT)
+/* helper macro: replace in-place a str type rve with v (another rve).*/
+#define replace_str_rve(e, v) replace_rve_type_cast(e, v, STR)
+       
        
        rv=0;
        ret=0;
        right=0;
+       dbg=1;
        
        if (rve_is_constant(rve->right.rve)){
                ct_rve=rve->right.rve;
@@ -2111,7 +3116,9 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
           referencing a ct_rve->left.rval if ct_rve is a rval, which
           would prevent rve_destroy(ct_rve) from working */
        if ((rv=rval_expr_eval_new(0, 0, ct_rve))==0){
-               ERR("optimization failure, bad expression\n");
+               ERR("optimization failure, bad expression (%d,%d-%d,%d)\n",
+                               ct_rve->fpos.s_line, ct_rve->fpos.s_col,
+                               ct_rve->fpos.e_line, ct_rve->fpos.e_col);
                goto error;
        }
        op=rve->op;
@@ -2126,14 +3133,10 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
                                                goto error;
                                        ret=1;
                                }else if (i==1){
-                                       /* $v *  1 -> $v
-                                        *  1 * $v -> $v */
+                                       /* $v *  1 -> (int)$v
+                                        *  1 * $v -> (int)$v */
                                        rve_destroy(ct_rve);
-                                       pos=rve->fpos;
-                                       *rve=*v_rve; /* replace current expr. with $v */
-                                       rve->fpos=pos;
-                                       pkg_free(v_rve);/* rve_destroy(v_rve) would free
-                                                                          everything*/
+                                       replace_int_rve(rve, v_rve);
                                        ret=1;
                                }
                                break;
@@ -2151,27 +3154,34 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
                                        }
                                }else if (i==1){
                                        if (ct_rve==rve->right.rve){
-                                               /* $v / 1 -> $v */
+                                               /* $v / 1 -> (int)$v */
                                                rve_destroy(ct_rve);
-                                               pos=rve->fpos;
-                                               *rve=*v_rve; /* replace current expr. with $v */
-                                               rve->fpos=pos;
-                                               pkg_free(v_rve);/* rve_destroy(v_rve) would free
-                                                                                  everything*/
+                                               replace_int_rve(rve, v_rve);
                                                ret=1;
                                        }
                                }
                                break;
+                       case RVE_MOD_OP:
+                               if (i==0){
+                                       if (ct_rve==rve->left.rve){
+                                               /* 0 % $v -> 0 */
+                                               if (rve_replace_with_ct_rv(rve, rv)<0)
+                                                       goto error;
+                                               ret=1;
+                                       }else{
+                                               /* $v % 0 */
+                                               ERR("RVE modulo by 0 at %d,%d\n",
+                                                               ct_rve->fpos.s_line, ct_rve->fpos.s_col);
+                                       }
+                               }
+                               /* $v % 1 -> 0 ? */
+                               break;
                        case RVE_MINUS_OP:
                                if (i==0){
                                        if (ct_rve==rve->right.rve){
                                                /* $v - 0 -> $v */
                                                rve_destroy(ct_rve);
-                                               pos=rve->fpos;
-                                               *rve=*v_rve; /* replace current expr. with $v */
-                                               rve->fpos=pos;
-                                               pkg_free(v_rve);/* rve_destroy(v_rve) would free
-                                                                                  everything*/
+                                               replace_int_rve(rve, v_rve);
                                                ret=1;
                                        }
                                        /* ? 0 - $v -> -($v)  ? */
@@ -2185,19 +3195,15 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
                                                goto error;
                                        ret=1;
                                }
-                               /* no 0xffffff optimization for now (haven't decide on
+                               /* no 0xffffff optimization for now (haven't decided on
                                   the number of bits ) */
                                break;
                        case RVE_BOR_OP:
                                if (i==0){
-                                       /* $v |  0 -> $v
-                                        *  0 | $v -> $v */
+                                       /* $v |  0 -> (int)$v
+                                        *  0 | $v -> (int)$v */
                                        rve_destroy(ct_rve);
-                                       pos=rve->fpos;
-                                       *rve=*v_rve; /* replace current expr. with $v */
-                                       rve->fpos=pos;
-                                       pkg_free(v_rve);/* rve_destroy(v_rve) would free
-                                                                          everything*/
+                                       replace_int_rve(rve, v_rve);
                                        ret=1;
                                }
                                break;
@@ -2209,14 +3215,10 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
                                                goto error;
                                        ret=1;
                                }else if (i==1){
-                                       /* $v &&  1 -> $v
-                                        *  1 && $v -> $v */
+                                       /* $v &&  1 -> (int)$v
+                                        *  1 && $v -> (int)$v */
                                        rve_destroy(ct_rve);
-                                       pos=rve->fpos;
-                                       *rve=*v_rve; /* replace current expr. with $v */
-                                       rve->fpos=pos;
-                                       pkg_free(v_rve);/* rve_destroy(v_rve) would free
-                                                                          everything*/
+                                       replace_int_rve(rve, v_rve);
                                        ret=1;
                                }
                                break;
@@ -2228,30 +3230,25 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
                                                goto error;
                                        ret=1;
                                }else if (i==0){
-                                       /* $v ||  0 -> $v
-                                        *  0 && $v -> $v */
+                                       /* $v ||  0 -> (int)$v
+                                        *  0 && $v -> (int)$v */
                                        rve_destroy(ct_rve);
-                                       pos=rve->fpos;
-                                       *rve=*v_rve; /* replace current expr. with $v */
-                                       rve->fpos=pos;
-                                       pkg_free(v_rve);/* rve_destroy(v_rve) would free
-                                                                          everything*/
+                                       replace_int_rve(rve, v_rve);
                                        ret=1;
                                }
                                break;
                        case RVE_PLUS_OP:
                        case RVE_IPLUS_OP:
                                /* we must make sure that this is an int PLUS
-                                  (because "foo"+0 is valid => "foo0") */
-                               if ((i==0) && ((op==RVE_IPLUS_OP)||(rve_type==RV_INT))){
-                                       /* $v +  0 -> $v
-                                        *  0 + $v -> $v */
+                                  (because "foo"+0 is valid => "foo0") =>
+                                  check if it's an IPLUS or the result is an integer
+                                  (which generally means unoptimized <int> + <something>).
+                                */
+                               if ((i==0) && ((op==RVE_IPLUS_OP) || (rve_type==RV_INT))){
+                                       /* $v +  0 -> (int)$v
+                                        *  0 + $v -> (int)$v */
                                        rve_destroy(ct_rve);
-                                       pos=rve->fpos;
-                                       *rve=*v_rve; /* replace current expr. with $v */
-                                       rve->fpos=pos;
-                                       pkg_free(v_rve);/* rve_destroy(v_rve) would free
-                                                                          everything*/
+                                       replace_int_rve(rve, v_rve);
                                        ret=1;
                                }
                                break;
@@ -2260,60 +3257,186 @@ static int rve_opt_01(struct rval_expr* rve, enum rval_type rve_type)
                                break;
                }
                /* debugging messages */
-               if (ret==1){
+               if (ret==1 && dbg){
                        if (right){
-                               if ((rve->op==RVE_RVAL_OP) && (rve->left.rval.type==RV_INT))
-                                       DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
-                                                       " op%d($v, %d) -> %d\n", 
-                                                       rve->fpos.s_line, rve->fpos.s_col,
-                                                       rve->fpos.e_line, rve->fpos.e_col,
-                                                       op, i, (int)rve->left.rval.v.l);
-                               else
+                               if (rve->op==RVE_RVAL_OP){
+                                       if (rve->left.rval.type==RV_INT)
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d($v, %d) -> %d\n", 
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
+                                                               op, i, (int)rve->left.rval.v.l);
+                                       else
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d($v, %d) -> $v (rval)\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
+                                                               op, i);
+                               }else if (rve->op==RVE_INT_OP){
+                                       if (rve->left.rve->op==RVE_RVAL_OP &&
+                                                       rve->left.rve->left.rval.type==RV_INT)
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d($v, %d) -> (int)%d\n", 
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
+                                                               op, i, (int)rve->left.rve->left.rval.v.l);
+                                       else
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d($v, %d) -> (int)$v\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
+                                                               op, i);
+                               }else{
                                        DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
                                                        " op%d($v, %d) -> $v\n",
                                                        rve->fpos.s_line, rve->fpos.s_col,
                                                        rve->fpos.e_line, rve->fpos.e_col,
                                                        op, i);
+                               }
                        }else{
-                               if ((rve->op==RVE_RVAL_OP) && (rve->left.rval.type==RV_INT))
-                                       DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
-                                                       " op%d(%d, $v) -> %d\n", 
-                                                       rve->fpos.s_line, rve->fpos.s_col,
-                                                       rve->fpos.e_line, rve->fpos.e_col,
-                                                       op, i, (int)rve->left.rval.v.l);
-                               else
+                               if (rve->op==RVE_RVAL_OP){
+                                       if (rve->left.rval.type==RV_INT)
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d(%d, $v) -> %d\n", 
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
+                                                               op, i, (int)rve->left.rval.v.l);
+                                       else
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d(%d, $v) -> $v (rval)\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
+                                                               op, i);
+                               }else if (rve->op==RVE_INT_OP){
+                                       if (rve->left.rve->op==RVE_RVAL_OP &&
+                                                       rve->left.rve->left.rval.type==RV_INT)
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d(%d, $v) -> (int)%d\n", 
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
+                                                               op, i, (int)rve->left.rve->left.rval.v.l);
+                                       else
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d(%d, $v) -> (int)$v\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
+                                                               op, i);
+                               }else{
                                        DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
                                                        " op%d(%d, $v) -> $v\n",
                                                        rve->fpos.s_line, rve->fpos.s_col,
                                                        rve->fpos.e_line, rve->fpos.e_col,
                                                        op, i);
+                               }
                        }
                }
        }else if (rv->type==RV_STR){
                switch(op){
                        case RVE_CONCAT_OP:
                                if (rv->v.s.len==0){
-                                       /* $v . "" -> $v 
-                                          "" . $v -> $v */
+                                       /* $v . "" -> (str)$v
+                                          "" . $v -> (str)$v */
                                        rve_destroy(ct_rve);
-                                       pos=rve->fpos;
-                                       *rve=*v_rve; /* replace current expr. with $v */
-                                       rve->fpos=pos;
-                                       pkg_free(v_rve);/* rve_destroy(v_rve) would free
-                                                                          everything*/
+                                       replace_str_rve(rve, v_rve);
                                        ret=1;
                                }
                                break;
+                       case RVE_EQ_OP:
+                       case RVE_STREQ_OP:
+                               if (rv->v.s.len==0){
+                                       /* $v == "" -> strempty($v) 
+                                          "" == $v -> strempty ($v) */
+                                       rve_destroy(ct_rve);
+                                       /* replace current expr. with strempty(rve) */
+                                       rve->op=RVE_STREMPTY_OP;
+                                       rve->left.rve=v_rve;
+                                       rve->right.rve=0;
+                                       ret=1;
+                                       if (dbg)
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d($v, \"\") -> strempty($v)\n", 
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
+                                                               op);
+                                       dbg=0;
+                               }
+                               break;
                        default:
                                break;
                }
        /* no optimization for generic RVE_PLUS_OP for now, only for RVE_CONCAT_OP
-          (We could optimize $v + "" or ""+$v, but this ""+$v is a way
-           to force convert $v to str , it might mess up type checking
-           (e.g. errors w/o optimization and no errors with) and it brings
-           a very small benefit anyway (it's unlikely we'll see a lot of
-           "")
-       */
+          (RVE_PLUS_OP should be converted to RVE_CONCAT_OP if it's supposed
+           to work on strings. If it's not converted/optimized it means it's type
+           can be determined only at runtime => we cannot optimize */
+               
+               /* debugging messages */
+               if (ret==1 && dbg){
+                       if (right){
+                               if (rve->op==RVE_RVAL_OP){
+                                       if (rve->left.rval.type==RV_STR)
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d($v, <string>) -> \"%s\"\n", 
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
+                                                               op, rve->left.rval.v.s.s);
+                                       else
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d($v, <string>) -> $v (rval)\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col, op);
+                               }else if (rve->op==RVE_STR_OP){
+                                       if (rve->left.rve->op==RVE_RVAL_OP &&
+                                                       rve->left.rve->left.rval.type==RV_STR)
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d($v, <string>) -> (str)\"%s\"\n", 
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
+                                                               op, rve->left.rve->left.rval.v.s.s);
+                                       else
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d($v, <string>) -> (str)$v\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col, op);
+                               }else{
+                                       DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                       " op%d($v, <string>) -> $v\n",
+                                                       rve->fpos.s_line, rve->fpos.s_col,
+                                                       rve->fpos.e_line, rve->fpos.e_col, op);
+                               }
+                       }else{
+                               if (rve->op==RVE_RVAL_OP){
+                                       if (rve->left.rval.type==RV_STR)
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d(<string>, $v) -> \"%s\"\n", 
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
+                                                               op, rve->left.rval.v.s.s);
+                                       else
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d(<string>, $v) -> $v (rval)\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col, op);
+                               }else if (rve->op==RVE_STR_OP){
+                                       if (rve->left.rve->op==RVE_RVAL_OP &&
+                                                       rve->left.rve->left.rval.type==RV_STR)
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d(<string>, $v) -> (str)\"%s\"\n", 
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
+                                                               op, rve->left.rve->left.rval.v.s.s);
+                                       else
+                                               DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                               " op%d(<string>, $v) -> (str)$v\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col, op);
+                               }else{
+                                       DBG("FIXUP RVE: (%d,%d-%d,%d) optimized"
+                                                       " op%d(<string>, $v) -> $v\n",
+                                                       rve->fpos.s_line, rve->fpos.s_col,
+                                                       rve->fpos.e_line, rve->fpos.e_col, op);
+                               }
+                       }
+               }
        }
        if (rv) rval_destroy(rv);
        return ret;
@@ -2331,22 +3454,22 @@ static int rve_optimize(struct rval_expr* rve)
        struct rvalue* rv;
        struct rvalue* trv; /* used only for DBG() */
        enum rval_expr_op op;
-       int flags;
        struct rval_expr tmp_rve;
        enum rval_type type, l_type;
        struct rval_expr* bad_rve;
        enum rval_type bad_type, exp_type;
        
        ret=0;
-       flags=0;
        rv=0;
        if (scr_opt_lev<1)
                return 0;
        if (rve->op == RVE_RVAL_OP) /* if rval, nothing to do */
                return 0;
        if (rve_is_constant(rve)){
-               if ((rv=rval_expr_eval(0, 0, rve))==0){
-                       ERR("optimization failure, bad expression\n");
+               if ((rv=rval_expr_eval_new(0, 0, rve))==0){
+                       ERR("optimization failure, bad expression (%d,%d-%d,%d)\n",
+                                       rve->fpos.s_line, rve->fpos.s_col,
+                                       rve->fpos.e_line, rve->fpos.e_col);
                        goto error;
                }
                op=rve->op;
@@ -2356,11 +3479,17 @@ static int rve_optimize(struct rval_expr* rve)
                rv=0;
                trv=&rve->left.rval;
                if (trv->type==RV_INT)
-                       DBG("FIXUP RVE: optimized constant int rve (old op %d) to %d\n",
+                       DBG("FIXUP RVE (%d,%d-%d,%d): optimized constant int rve "
+                                       "(old op %d) to %d\n",
+                                       rve->fpos.s_line, rve->fpos.s_col,
+                                       rve->fpos.e_line, rve->fpos.e_col,
                                        op, (int)trv->v.l);
                else if (trv->type==RV_STR)
-                       DBG("FIXUP RVE: optimized constant str rve (old op %d) to"
-                                       " \"%.*s\"\n", op, trv->v.s.len, trv->v.s.s);
+                       DBG("FIXUP RVE (%d,%d-%d,%d): optimized constant str rve "
+                                       "(old op %d) to \"%.*s\"\n",
+                                       rve->fpos.s_line, rve->fpos.s_col,
+                                       rve->fpos.e_line, rve->fpos.e_col,
+                                       op, trv->v.s.len, trv->v.s.s);
                ret=1;
        }else{
                /* expression is not constant */
@@ -2370,16 +3499,24 @@ static int rve_optimize(struct rval_expr* rve)
                rve_optimize(rve->left.rve);
                rve_optimize(rve->right.rve);
                if (!rve_check_type(&type, rve, &bad_rve, &bad_type, &exp_type)){
-                       ERR("optimization failure, type mismatch in expression (%d,%d), "
+                       ERR("optimization failure while optimizing %d,%d-%d,%d:"
+                                       " type mismatch in expression (%d,%d-%d,%d), "
                                        "type %s, but expected %s\n",
+                                       rve->fpos.s_line, rve->fpos.s_col,
+                                       rve->fpos.e_line, rve->fpos.e_col,
                                        bad_rve->fpos.s_line, bad_rve->fpos.s_col,
+                                       bad_rve->fpos.e_line, bad_rve->fpos.e_col,
                                        rval_type_name(bad_type), rval_type_name(exp_type));
                        return 0;
                }
                /* $v - a => $v + (-a)  (easier to optimize)*/
                if ((rve->op==RVE_MINUS_OP) && (rve_is_constant(rve->right.rve))){
-                       if ((rv=rval_expr_eval(0, 0, rve->right.rve))==0){
-                               ERR("optimization failure, bad expression\n");
+                       if ((rv=rval_expr_eval_new(0, 0, rve->right.rve))==0){
+                               ERR("optimization failure, bad expression (%d,%d-%d,%d)\n",
+                                                               rve->right.rve->fpos.s_line,
+                                                               rve->right.rve->fpos.s_col,
+                                                               rve->right.rve->fpos.e_line,
+                                                               rve->right.rve->fpos.e_col);
                                goto error;
                        }
                        if (rv->type==RV_INT){
@@ -2387,8 +3524,11 @@ static int rve_optimize(struct rval_expr* rve)
                                if (rve_replace_with_ct_rv(rve->right.rve, rv)<0)
                                        goto error;
                                rve->op=RVE_IPLUS_OP;
-                               DBG("FIXUP RVE: optimized $v - a into $v + (%d)\n",
-                                                               (int)rve->right.rve->left.rval.v.l);
+                               DBG("FIXUP RVE (%d,%d-%d,%d): optimized $v - a into "
+                                               "$v + (%d)\n",
+                                               rve->fpos.s_line, rve->fpos.s_col,
+                                               rve->fpos.e_line, rve->fpos.e_col,
+                                               (int)rve->right.rve->left.rval.v.l);
                        }
                        rval_destroy(rv);
                        rv=0;
@@ -2399,7 +3539,7 @@ static int rve_optimize(struct rval_expr* rve)
                        l_type=rve_guess_type(rve->left.rve);
                        if (l_type==RV_INT){
                                rve->op=RVE_IPLUS_OP;
-                               DBG("FIXUP RVE (%d,%d-%d,%d): changed + into interger plus\n",
+                               DBG("FIXUP RVE (%d,%d-%d,%d): changed + into integer plus\n",
                                                rve->fpos.s_line, rve->fpos.s_col,
                                                rve->fpos.e_line, rve->fpos.e_col);
                        }else if (l_type==RV_STR){
@@ -2409,6 +3549,24 @@ static int rve_optimize(struct rval_expr* rve)
                                                rve->fpos.e_line, rve->fpos.e_col);
                        }
                }
+               /* e1 EQ_OP e2 -> change op if we know e1 basic type
+                  e1 DIFF_OP e2 -> change op if we know e2 basic type */
+               if (rve->op==RVE_EQ_OP || rve->op==RVE_DIFF_OP){
+                       l_type=rve_guess_type(rve->left.rve);
+                       if (l_type==RV_INT){
+                               rve->op=(rve->op==RVE_EQ_OP)?RVE_IEQ_OP:RVE_IDIFF_OP;
+                               DBG("FIXUP RVE (%d,%d-%d,%d): changed ==/!= into integer"
+                                               " ==/!=\n",
+                                               rve->fpos.s_line, rve->fpos.s_col,
+                                               rve->fpos.e_line, rve->fpos.e_col);
+                       }else if (l_type==RV_STR){
+                               rve->op=(rve->op==RVE_EQ_OP)?RVE_STREQ_OP:RVE_STRDIFF_OP;
+                               DBG("FIXUP RVE (%d,%d-%d,%d): changed ==/!= into string"
+                                               " ==/!=\n",
+                                               rve->fpos.s_line, rve->fpos.s_col,
+                                               rve->fpos.e_line, rve->fpos.e_col);
+                       }
+               }
                
                /* $v * 0 => 0; $v * 1 => $v (for *, /, &, |, &&, ||, +, -) */
                if (rve_opt_01(rve, type)==1){
@@ -2434,11 +3592,13 @@ static int rve_optimize(struct rval_expr* rve)
                                           or a combination of them */
                                        if ((rve->op==RVE_PLUS_OP) &&
                                                (rve_guess_type(tmp_rve.left.rve)!=RV_STR)){
-                                               DBG("RVE optimization failed: cannot optimize"
-                                                               " +(+($v, a), b) when typeof(a)==INT\n");
+                                               DBG("RVE optimization failed (%d,%d-%d,%d): cannot "
+                                                       "optimize +(+($v, a), b) when typeof(a)==INT\n",
+                                                       rve->fpos.s_line, rve->fpos.s_col,
+                                                       rve->fpos.e_line, rve->fpos.e_col);
                                                return 0;
                                        }
-                                       if ((rv=rval_expr_eval(0, 0, &tmp_rve))==0){
+                                       if ((rv=rval_expr_eval_new(0, 0, &tmp_rve))==0){
                                                ERR("optimization failure, bad expression\n");
                                                goto error;
                                        }
@@ -2451,16 +3611,21 @@ static int rve_optimize(struct rval_expr* rve)
                                        rve->left.rve=rve->left.rve->left.rve;
                                        trv=&rve->right.rve->left.rval;
                                        if (trv->type==RV_INT)
-                                               DBG("FIXUP RVE: optimized int rve: op(op($v, a), b)"
-                                                               " with op($v, %d); op=%d\n",
+                                               DBG("FIXUP RVE (%d,%d-%d,%d): optimized int rve: "
+                                                               "op(op($v, a), b) with op($v, %d); op=%d\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
                                                                (int)trv->v.l, rve->op);
                                        else if (trv->type==RV_STR)
-                                               DBG("FIXUP RVE: optimized str rve op(op($v, a), b)"
-                                                               " with op($v, \"%.*s\"); op=%d\n",
+                                               DBG("FIXUP RVE (%d,%d-%d,%d): optimized str rve "
+                                                               "op(op($v, a), b) with op($v, \"%.*s\");"
+                                                               " op=%d\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
                                                                trv->v.s.len, trv->v.s.s, rve->op);
                                        ret=1;
                                }else if (rve_is_constant(rve->left.rve->left.rve) &&
-                                                       rve_op_is_commutative(rve->op, type)){
+                                                       rve_op_is_commutative(rve->op)){
                                        /* op(op(a, $v), b) => op(op(a, b), $v) */
                                        /* rv= op(a, b) */
                                        tmp_rve.op=rve->op;
@@ -2470,7 +3635,7 @@ static int rve_optimize(struct rval_expr* rve)
                                           cases are caught by rve_op_is_commutative()
                                           (in this case type will be typeof(a)) => ok only if
                                           typeof(a) is int) */
-                                       if ((rv=rval_expr_eval(0, 0, &tmp_rve))==0){
+                                       if ((rv=rval_expr_eval_new(0, 0, &tmp_rve))==0){
                                                ERR("optimization failure, bad expression\n");
                                                goto error;
                                        }
@@ -2484,12 +3649,17 @@ static int rve_optimize(struct rval_expr* rve)
                                        rv=0;
                                        trv=&rve->left.rve->left.rval;
                                        if (trv->type==RV_INT)
-                                               DBG("FIXUP RVE: optimized int rve: op(op(a, $v), b)"
-                                                               " with op(%d, $v); op=%d\n",
+                                               DBG("FIXUP RVE (%d,%d-%d,%d): optimized int rve: "
+                                                               "op(op(a, $v), b) with op(%d, $v); op=%d\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
                                                                (int)trv->v.l, rve->op);
                                        else if (trv->type==RV_STR)
-                                               DBG("FIXUP RVE: optimized str rve op(op(a, $v), b)"
-                                                               " with op(\"%.*s\", $v); op=%d\n",
+                                               DBG("FIXUP RVE (%d,%d-%d,%d): optimized str rve "
+                                                               "op(op(a, $v), b) with op(\"%.*s\", $v);"
+                                                               " op=%d\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
                                                                trv->v.s.len, trv->v.s.s, rve->op);
                                        ret=1;
                                }
@@ -2502,7 +3672,7 @@ static int rve_optimize(struct rval_expr* rve)
                        if ((rve->op==rve->right.rve->op) && rve_op_is_assoc(rve->op)){
                                /* op(a, op(...)) */
                                if (rve_is_constant(rve->right.rve->right.rve) &&
-                                               rve_op_is_commutative(rve->op, type)){
+                                               rve_op_is_commutative(rve->op)){
                                        /* op(a, op($v, b)) => op(op(a, b), $v) */
                                        /* rv= op(a, b) */
                                        tmp_rve.op=rve->op;
@@ -2512,7 +3682,7 @@ static int rve_optimize(struct rval_expr* rve)
                                           cases are caught by rve_op_is_commutative()
                                           (in this case type will be typeof(a)) => ok only if
                                           typeof(a) is int) */
-                                       if ((rv=rval_expr_eval(0, 0, &tmp_rve))==0){
+                                       if ((rv=rval_expr_eval_new(0, 0, &tmp_rve))==0){
                                                ERR("optimization failure, bad expression\n");
                                                goto error;
                                        }
@@ -2525,12 +3695,17 @@ static int rve_optimize(struct rval_expr* rve)
                                        rve->right.rve=rve->right.rve->left.rve;
                                        trv=&rve->left.rve->left.rval;
                                        if (trv->type==RV_INT)
-                                               DBG("FIXUP RVE: optimized int rve: op(a, op($v, b))"
-                                                               " with op(%d, $v); op=%d\n",
+                                               DBG("FIXUP RVE (%d,%d-%d,%d): optimized int rve: "
+                                                               "op(a, op($v, b)) with op(%d, $v); op=%d\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
                                                                (int)trv->v.l, rve->op);
                                        else if (trv->type==RV_STR)
-                                               DBG("FIXUP RVE: optimized str rve op(a, op($v, b))"
-                                                               " with op(\"%.*s\", $v); op=%d\n",
+                                               DBG("FIXUP RVE (%d,%d-%d,%d): optimized str rve "
+                                                               "op(a, op($v, b)) with op(\"%.*s\", $v);"
+                                                               " op=%d\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
                                                                trv->v.s.len, trv->v.s.s, rve->op);
                                        ret=1;
                                }else if (rve_is_constant(rve->right.rve->left.rve)){
@@ -2544,11 +3719,14 @@ static int rve_optimize(struct rval_expr* rve)
                                        if ((rve->op==RVE_PLUS_OP) &&
                                                (rve_guess_type(tmp_rve.left.rve) != 
                                                        rve_guess_type(tmp_rve.right.rve))){
-                                               DBG("RVE optimization failed: cannot optimize"
-                                                               " +(a, +(b, $v)) when typeof(a)!=typeof(b)\n");
+                                               DBG("RVE optimization failed (%d,%d-%d,%d): cannot "
+                                                               "optimize +(a, +(b, $v)) when "
+                                                               "typeof(a)!=typeof(b)\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col);
                                                return 0;
                                        }
-                                       if ((rv=rval_expr_eval(0, 0, &tmp_rve))==0){
+                                       if ((rv=rval_expr_eval_new(0, 0, &tmp_rve))==0){
                                                ERR("optimization failure, bad expression\n");
                                                goto error;
                                        }
@@ -2561,12 +3739,17 @@ static int rve_optimize(struct rval_expr* rve)
                                        rve->right.rve=rve->right.rve->right.rve;
                                        trv=&rve->left.rve->left.rval;
                                        if (trv->type==RV_INT)
-                                               DBG("FIXUP RVE: optimized int rve: op(a, op(b, $v))"
-                                                               " with op(%d, $v); op=%d\n",
+                                               DBG("FIXUP RVE (%d,%d-%d,%d): optimized int rve: "
+                                                               "op(a, op(b, $v)) with op(%d, $v); op=%d\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
                                                                (int)trv->v.l, rve->op);
                                        else if (trv->type==RV_STR)
-                                               DBG("FIXUP RVE: optimized str rve op(a, op(b, $v))"
-                                                               " with op(\"%.*s\", $v); op=%d\n",
+                                               DBG("FIXUP RVE (%d,%d-%d,%d): optimized str rve "
+                                                               "op(a, op(b, $v)) with op(\"%.*s\", $v);"
+                                                               " op=%d\n",
+                                                               rve->fpos.s_line, rve->fpos.s_col,
+                                                               rve->fpos.e_line, rve->fpos.e_col,
                                                                trv->v.s.len, trv->v.s.s, rve->op);
                                        ret=1;
                                }
@@ -2589,19 +3772,16 @@ error:
 /** fix a rval_expr.
  * fixes action, bexprs, resolves selects, pvars and
  * optimizes simple sub expressions (e.g. 1+2).
- * It might modify *p.
  *
- * @param p - double pointer to a rval_expr (might be changed to a new one)
- * @return 0 on success, <0 on error (modifies also *p)
+ * @param p - pointer to a rval_expr
+ * @return 0 on success, <0 on error (modifies also *(struct rval_expr*)p)
  */
-int fix_rval_expr(void** p)
+int fix_rval_expr(void* p)
 {
-       struct rval_expr** prve;
        struct rval_expr* rve;
        int ret;
        
-       prve=(struct rval_expr**)p;
-       rve=*prve;
+       rve=(struct rval_expr*)p;
        
        switch(rve->op){
                case RVE_NONE_OP:
@@ -2612,14 +3792,24 @@ int fix_rval_expr(void** p)
                case RVE_UMINUS_OP: /* unary operators */
                case RVE_BOOL_OP:
                case RVE_LNOT_OP:
-                       ret=fix_rval_expr((void**)&rve->left.rve);
+               case RVE_BNOT_OP:
+               case RVE_STRLEN_OP:
+               case RVE_STREMPTY_OP:
+               case RVE_DEFINED_OP:
+               case RVE_INT_OP:
+               case RVE_STR_OP:
+                       ret=fix_rval_expr((void*)rve->left.rve);
                        if (ret<0) return ret;
                        break;
                case RVE_MUL_OP:
                case RVE_DIV_OP:
+               case RVE_MOD_OP:
                case RVE_MINUS_OP:
                case RVE_BOR_OP:
                case RVE_BAND_OP:
+               case RVE_BXOR_OP:
+               case RVE_BLSHIFT_OP:
+               case RVE_BRSHIFT_OP:
                case RVE_LAND_OP:
                case RVE_LOR_OP:
                case RVE_GT_OP:
@@ -2630,10 +3820,18 @@ int fix_rval_expr(void** p)
                case RVE_IPLUS_OP:
                case RVE_EQ_OP:
                case RVE_DIFF_OP:
+               case RVE_IEQ_OP:
+               case RVE_IDIFF_OP:
+               case RVE_STREQ_OP:
+               case RVE_STRDIFF_OP:
                case RVE_CONCAT_OP:
-                       ret=fix_rval_expr((void**)&rve->left.rve);
+                       ret=fix_rval_expr((void*)rve->left.rve);
                        if (ret<0) return ret;
-                       ret=fix_rval_expr((void**)&rve->right.rve);
+                       ret=fix_rval_expr((void*)rve->right.rve);
+                       if (ret<0) return ret;
+                       break;
+               case RVE_MATCH_OP:
+                       ret=fix_match_rve(rve);
                        if (ret<0) return ret;
                        break;
                default: