Module: sip-router
Branch: master
Commit: ea1babd9d9e6e90629ad4ad091b1ab90241332fd
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=ea1babd…
Author: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei(a)iptel.org>
Date: Fri Apr 24 14:45:36 2009 +0200
core expr: new internal operators
- added RVE_STRLEN_OP, RVE_STREMPTY_OP and RVE_DEFINED_OP
---
rvalue.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
rvalue.h | 6 ++-
2 files changed, 182 insertions(+), 3 deletions(-)
diff --git a/rvalue.c b/rvalue.c
index 8bd0aa2..74e8df5 100644
--- a/rvalue.c
+++ b/rvalue.c
@@ -23,6 +23,7 @@
* History:
* --------
* 2008-12-01 initial version (andrei)
+ * 2009-04-24 added support for defined, strempty, strlen (andrei)
*/
#include "rvalue.h"
@@ -390,6 +391,9 @@ enum rval_type rve_guess_type( struct rval_expr* rve)
case RVE_EQ_OP:
case RVE_DIFF_OP:
case RVE_IPLUS_OP:
+ case RVE_STRLEN_OP:
+ case RVE_STREMPTY_OP:
+ case RVE_DEFINED_OP:
return RV_INT;
case RVE_PLUS_OP:
/* '+' evaluates to the type of the left operand */
@@ -429,6 +433,9 @@ int rve_is_constant(struct rval_expr* rve)
case RVE_UMINUS_OP:
case RVE_BOOL_OP:
case RVE_LNOT_OP:
+ case RVE_STRLEN_OP:
+ case RVE_STREMPTY_OP:
+ case RVE_DEFINED_OP:
return rve_is_constant(rve->left.rve);
case RVE_MINUS_OP:
case RVE_MUL_OP:
@@ -478,6 +485,9 @@ static int rve_op_unary(enum rval_expr_op op)
case RVE_UMINUS_OP:
case RVE_BOOL_OP:
case RVE_LNOT_OP:
+ case RVE_STRLEN_OP:
+ case RVE_STREMPTY_OP:
+ case RVE_DEFINED_OP:
return 1;
case RVE_MINUS_OP:
case RVE_MUL_OP:
@@ -610,6 +620,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,6 +643,21 @@ int rve_check_type(enum rval_type* type, struct rval_expr* rve,
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_NONE_OP:
break;
}
@@ -974,7 +1000,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)
@@ -1054,6 +1080,27 @@ inline static int bool_strop2( enum rval_expr_op op, int* res,
+/** 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);
+ return -1;
+ }
+ return 0;
+}
+
+
+
/** integer operation: ret= op v (returns a rvalue).
* @return rvalue on success, 0 on error
*/
@@ -1306,6 +1353,107 @@ error:
+/** integer operation on rval evaluated as string.
+ * Can use cached rvalues (c1 & c2).
+ * @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:
+ rval_destroy(rv1);
+ return 0;
+}
+
+
+
+/** checks if rv is defined.
+ * @return 1 defined, 0 not defined, -1 on error
+ * Can use cached rvalues (c1).
+ * Note: a rv can be undefined if it's an undefined avp or pvar or
+ * if it's NONE
+ */
+inline static int rv_defined(struct run_act_ctx* h,
+ struct sip_msg* msg,
+ struct rvalue* rv, struct rval_cache* cache)
+{
+ avp_t* r_avp;
+ int_str avp_val;
+ pv_value_t pval;
+ int ret;
+
+ ret=1;
+ switch(rv->type){
+ case RV_AVP:
+ if (unlikely(cache && cache->cache_type==RV_CACHE_AVP)){
+ if (cache->val_type==RV_NONE)
+ ret=0;
+ }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)){
+ ret=0;
+ }
+ }
+ break;
+ case RV_PVAR:
+ /* PV_VAL_NULL or pv_get_spec_value error => undef */
+ if (unlikely(cache && cache->cache_type==RV_CACHE_PVAR)){
+ if (cache->val_type==RV_NONE)
+ ret=0;
+ }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))){
+ ret=0;
+ }
+ pv_value_destroy(&pval);
+ }else{
+ ret=0; /* in case of error, consider it undef */
+ }
+ }
+ break;
+ case RV_NONE:
+ ret=0;
+ break;
+ default:
+ break;
+ }
+ return 1; /* defined */
+}
+
+
+/** defined (integer) operation on rve.
+ * @return 1 defined, 0 not defined, -1 on error
+ */
+inline static int int_rve_defined(struct run_act_ctx* h,
+ struct sip_msg* msg,
+ 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, &rve->left.rval, 0);
+ return 1;
+}
+
+
+
/** evals an integer expr to an int.
*
* *res=(int)eval(rve)
@@ -1431,6 +1579,18 @@ int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg*
msg,
*res=0;
ret=-1;
break;
+ case RVE_DEFINED_OP:
+ ret=int_rve_defined(h, msg, rve->left.rve);
+ break;
+ 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);
@@ -1503,6 +1663,9 @@ int rval_expr_eval_rvint( struct run_act_ctx* h,
case RVE_EQ_OP:
case RVE_DIFF_OP:
case RVE_IPLUS_OP:
+ case RVE_STRLEN_OP:
+ case RVE_STREMPTY_OP:
+ case RVE_DEFINED_OP:
/* operator forces integer type */
ret=rval_expr_eval_int(h, msg, res_i, rve);
*res_rv=0;
@@ -1560,7 +1723,7 @@ error:
* 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
+ * @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)
@@ -1598,6 +1761,9 @@ struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg*
msg,
case RVE_EQ_OP:
case RVE_DIFF_OP:
case RVE_IPLUS_OP:
+ case RVE_STRLEN_OP:
+ case RVE_STREMPTY_OP:
+ case RVE_DEFINED_OP:
/* operator forces integer type */
r=rval_expr_eval_int(h, msg, &i, rve);
if (likely(r==0)){
@@ -1800,6 +1966,9 @@ 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_STRLEN_OP:
+ case RVE_STREMPTY_OP:
+ case RVE_DEFINED_OP:
break;
default:
BUG("unsupported unary operator %d\n", op);
@@ -1874,6 +2043,9 @@ 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_STRLEN_OP:
+ case RVE_STREMPTY_OP:
+ case RVE_DEFINED_OP:
/* one operand expression => cannot be assoc. */
return 0;
case RVE_DIV_OP:
@@ -1911,6 +2083,9 @@ 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_STRLEN_OP:
+ case RVE_STREMPTY_OP:
+ case RVE_DEFINED_OP:
/* one operand expression => cannot be commut. */
return 0;
case RVE_DIV_OP:
diff --git a/rvalue.h b/rvalue.h
index 88fd6f2..a9dbe0d 100644
--- a/rvalue.h
+++ b/rvalue.h
@@ -64,8 +64,12 @@ enum rval_expr_op{
RVE_PLUS_OP, /* generic plus (int or str) returns left + right */
RVE_EQ_OP, /* 2 members, returns left == right (int)*/
RVE_DIFF_OP, /* 2 members, returns left != right (int)*/
- RVE_CONCAT_OP,/* string concatenation, returns left . right */
/* str only */
+ RVE_CONCAT_OP,/* 2 members, string concat, returns left . right (str)*/
+ RVE_STRLEN_OP, /* one member, string length:, returns strlen(val) (int)*/
+ RVE_STREMPTY_OP, /* one member, returns val=="" (bool) */
+ /* avp, pvars a.s.o */
+ RVE_DEFINED_OP, /* one member, returns is_defined(val) (bool) */
};