Module: sip-router Branch: master Commit: ea1babd9d9e6e90629ad4ad091b1ab90241332fd URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=ea1babd9...
Author: Andrei Pelinescu-Onciul andrei@iptel.org Committer: Andrei Pelinescu-Onciul andrei@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) */ };