Browse code

script engine: generalised lvalues & rvalues

- support for rvalues (anything that can appear on the right side
of an assignment). For now an rvalue can be an avp, pvar,
select, number, string, logical expression or script command.
rvalues expressions are also supported (rvalue operator rvalue
...).
Evaluation of integer rvalue expression is highly optimized.
For performance reasons the rvalue expressions are completely
separated from the logical expressions (eval_elem/eval_expr).
- rvalue expression fixup (apart for normal fixup stuff will also
optimize away simple expressions, like 2+3 or "a" + "b").
- support for more general lvalues (anything in the left side of
an assignment operator). For now an lvalue is either an avp or a
script pvar. lvalue = rvalue_expression.
Direct assignments (lvalue to avp or pvar) are optimised.

Andrei Pelinescu-Onciul authored on 03/12/2008 23:47:29
Showing 4 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,361 @@
1
+/* 
2
+ * $Id$
3
+ * 
4
+ * Copyright (C) 2008 iptelorg GmbH
5
+ *
6
+ * Permission to use, copy, modify, and distribute this software for any
7
+ * purpose with or without fee is hereby granted, provided that the above
8
+ * copyright notice and this permission notice appear in all copies.
9
+ *
10
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ */
18
+/**
19
+ * @file 
20
+ * @brief lvalues (assignment)
21
+ */
22
+/* 
23
+ * History:
24
+ * --------
25
+ *  2008-11-30  initial version (andrei)
26
+ */
27
+
28
+#include "lvalue.h"
29
+#include "dprint.h"
30
+#include "route.h"
31
+
32
+
33
+
34
+/** eval rve and assign the result to an avp
35
+ * lv->lv.avp=eval(rve)
36
+ *
37
+ * based on do_action() ASSIGN_T
38
+ *
39
+ * @param h  - script context
40
+ * @param msg - sip msg
41
+ * @param lv - lvalue
42
+ * @param rve - rvalue expression
43
+ * @return >= 0 on success (expr. bool value), -1 on error
44
+ */
45
+inline static int lval_avp_assign(struct run_act_ctx* h, struct sip_msg* msg,
46
+									struct lvalue* lv, struct rvalue* rv)
47
+{
48
+	avp_spec_t* avp;
49
+	avp_t* r_avp;
50
+	avp_t* avp_mark;
51
+	pv_value_t pval;
52
+	int_str value;
53
+	unsigned short flags;
54
+	struct search_state st;
55
+	int ret;
56
+	int v;
57
+	int destroy_pval;
58
+	
59
+	destroy_pval=0;
60
+	avp=&lv->lv.avps;
61
+	ret=0;
62
+	/* If the left attr was specified without indexing brackets delete
63
+	 * existing AVPs before adding new ones */
64
+	if ((avp->type & AVP_INDEX_ALL) != AVP_INDEX_ALL)
65
+		delete_avp(avp->type, avp->name);
66
+	switch(rv->type){
67
+		case RV_NONE:
68
+			BUG("non-intialized rval / rval expr \n");
69
+			goto error;
70
+		case RV_INT:
71
+			value.n=rv->v.l;
72
+			flags=avp->type;
73
+			ret=!(!value.n);
74
+			break;
75
+		case RV_STR:
76
+			value.s=rv->v.s;
77
+			flags=avp->type | AVP_VAL_STR;
78
+			ret=(value.s.len>0);
79
+			break;
80
+		case RV_ACTION_ST:
81
+			flags=avp->type;
82
+			if (rv->v.action)
83
+				value.n=run_actions(h, rv->v.action, msg);
84
+			else
85
+				value.n=-1;
86
+			ret=value.n;
87
+			break;
88
+		case RV_BEXPR: /* logic/boolean expr. */
89
+			value.n=eval_expr(h, rv->v.bexpr, msg);
90
+			if (unlikely(value.n<0)){
91
+				if (value.n==EXPR_DROP) /* hack to quit on drop */
92
+					goto drop;
93
+				WARN("error in expression\n");
94
+				value.n=0; /* expr. is treated as false */
95
+			}
96
+			flags=avp->type;
97
+			ret=value.n;
98
+			break;
99
+		case RV_SEL:
100
+			v=run_select(&value.s, &rv->v.sel, msg);
101
+			if (unlikely(v!=0)){
102
+				if (v<0){
103
+					ret=-1;
104
+					goto error;
105
+				}else { /* v>0 */
106
+					value.s.s="";
107
+					value.s.len=0;
108
+				}
109
+			}
110
+			flags=avp->type;
111
+			ret=(value.s.len>0);
112
+			break;
113
+		case RV_AVP:
114
+			avp_mark=0;
115
+			if (unlikely((rv->v.avps.type & AVP_INDEX_ALL) == AVP_INDEX_ALL)){
116
+				r_avp = search_first_avp(rv->v.avps.type, rv->v.avps.name,
117
+											&value, &st);
118
+				while(r_avp){
119
+					/* We take only the type and name from the source avp
120
+					 * and reset the class and track flags */
121
+					flags=(avp->type & ~AVP_INDEX_ALL) | 
122
+							(r_avp->flags & ~(AVP_CLASS_ALL|AVP_TRACK_ALL));
123
+					if (add_avp_before(avp_mark, flags, avp->name, value)<0){
124
+						ERR("failed to assign avp\n");
125
+						ret=-1;
126
+						goto error;
127
+					}
128
+					/* move the mark, so the next found AVP will come before
129
+					   the one currently added so they will have the same 
130
+					   order as in the source list */
131
+					if (avp_mark) avp_mark=avp_mark->next;
132
+					else
133
+						avp_mark=search_first_avp(flags, avp->name, 0, 0);
134
+					r_avp=search_next_avp(&st, &value);
135
+				}
136
+				ret=1;
137
+				goto end;
138
+			}else{
139
+				r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
140
+											&value, rv->v.avps.index);
141
+				if (likely(r_avp)){
142
+					flags=avp->type | (r_avp->flags & 
143
+								~(AVP_CLASS_ALL|AVP_TRACK_ALL));
144
+					ret=1;
145
+				}else{
146
+					ret=-1;
147
+					goto error;
148
+				}
149
+			}
150
+			break;
151
+		case RV_PVAR:
152
+			flags=avp->type;
153
+			memset(&pval, 0, sizeof(pval));
154
+			if (likely(pv_get_spec_value(msg, &rv->v.pvs, &pval)==0)){
155
+				destroy_pval=1;
156
+				if (pval.flags & PV_VAL_STR){
157
+					value.s=pval.rs;
158
+					ret=(value.s.len>0);
159
+				}else if (pval.flags & PV_TYPE_INT){
160
+					value.n=pval.ri;
161
+					ret=value.n;
162
+				}else if (pval.flags==PV_VAL_NONE ||
163
+							(pval.flags & (PV_VAL_NULL|PV_VAL_EMPTY))){
164
+					value.s.s="";
165
+					value.s.len=0;
166
+					ret=0;
167
+				}
168
+			}else{
169
+				/* non existing pvar */
170
+				value.s.s="";
171
+				value.s.len=0;
172
+				ret=0;
173
+			}
174
+			break;
175
+	}
176
+	if (add_avp(flags & ~AVP_INDEX_ALL, avp->name, value) < 0) {
177
+		ERR("failed to assign value to avp\n");
178
+		goto error;
179
+	}
180
+end:
181
+	if (destroy_pval) pv_value_destroy(&pval);
182
+	return ret;
183
+error:
184
+	if (destroy_pval) pv_value_destroy(&pval);
185
+	return -1;
186
+drop:
187
+	if (destroy_pval) pv_value_destroy(&pval);
188
+	return EXPR_DROP;
189
+}
190
+
191
+
192
+
193
+/** eval rve and assign the result to a pvar
194
+ * lv->lv.pvar=eval(rve)
195
+ *
196
+ * based on do_action() ASSIGN_T
197
+ *
198
+ * @param h  - script context
199
+ * @param msg - sip msg
200
+ * @param lv - lvalue
201
+ * @param rve - rvalue expression
202
+ * @return >= 0 on success (expr. bool value), -1 on error
203
+ */
204
+inline static int lval_pvar_assign(struct run_act_ctx* h, struct sip_msg* msg,
205
+									struct lvalue* lv, struct rvalue* rv)
206
+{
207
+	pv_spec_t* pvar;
208
+	pv_value_t pval;
209
+	avp_t* r_avp;
210
+	int_str avp_val;
211
+	int ret;
212
+	int v;
213
+	int destroy_pval;
214
+	
215
+	destroy_pval=0;
216
+	pvar=&lv->lv.pvs;
217
+	if (unlikely(!pv_is_w(pvar))){
218
+		ERR("read only pvar\n");
219
+		goto error;
220
+	}
221
+	memset(&pval, 0, sizeof(pval));
222
+	ret=0;
223
+	switch(rv->type){
224
+		case RV_NONE:
225
+			BUG("non-intialized rval / rval expr \n");
226
+			goto error;
227
+		case RV_INT:
228
+			pval.flags=PV_TYPE_INT|PV_VAL_INT;
229
+			pval.ri=rv->v.l;
230
+			ret=!(!pval.ri);
231
+			break;
232
+		case RV_STR:
233
+			pval.flags=PV_VAL_STR;
234
+			pval.rs=rv->v.s;
235
+			ret=(pval.rs.len>0);
236
+			break;
237
+		case RV_ACTION_ST:
238
+			pval.flags=PV_TYPE_INT|PV_VAL_INT;
239
+			if (rv->v.action)
240
+				pval.ri=run_actions(h, rv->v.action, msg);
241
+			else
242
+				pval.ri=0;
243
+			ret=pval.ri;
244
+			break;
245
+		case RV_BEXPR: /* logic/boolean expr. */
246
+			pval.flags=PV_TYPE_INT|PV_VAL_INT;
247
+			pval.ri=eval_expr(h, rv->v.bexpr, msg);
248
+			if (unlikely(pval.ri<0)){
249
+				if (pval.ri==EXPR_DROP) /* hack to quit on drop */
250
+					goto drop;
251
+				WARN("error in expression\n");
252
+				pval.ri=0; /* expr. is treated as false */
253
+			}
254
+			ret=pval.ri;
255
+			break;
256
+		case RV_SEL:
257
+			pval.flags=PV_VAL_STR;
258
+			v=run_select(&pval.rs, &rv->v.sel, msg);
259
+			if (unlikely(v!=0)){
260
+				if (v<0){
261
+					ret=-1;
262
+					goto error;
263
+				}else { /* v>0 */
264
+					pval.rs.s="";
265
+					pval.rs.len=0;
266
+				}
267
+			}
268
+			ret=(pval.rs.len)>0;
269
+			break;
270
+		case RV_AVP:
271
+				r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
272
+											&avp_val, rv->v.avps.index);
273
+				if (likely(r_avp)){
274
+					if (r_avp->flags & AVP_VAL_STR){
275
+						pval.flags=PV_VAL_STR;
276
+						pval.rs=avp_val.s;
277
+						ret=(pval.rs.len>0);
278
+					}else{
279
+						pval.flags=PV_TYPE_INT|PV_VAL_INT;
280
+						pval.ri=avp_val.n;
281
+						ret=!(!pval.ri);
282
+					}
283
+				}else{
284
+					ret=-1;
285
+					goto error;
286
+				}
287
+			break;
288
+		case RV_PVAR:
289
+			memset(&pval, 0, sizeof(pval));
290
+			if (likely(pv_get_spec_value(msg, &rv->v.pvs, &pval)==0)){
291
+				destroy_pval=1;
292
+				if (pval.flags & PV_VAL_STR){
293
+					ret=(pval.rs.len>0);
294
+				}else if (pval.flags & PV_TYPE_INT){
295
+					ret=!(!pval.ri);
296
+				}else{
297
+					ERR("no value in pvar assignment rval\n");
298
+					ret=-1;
299
+					goto error;
300
+				}
301
+			}else{
302
+				ERR("non existing right pvar\n");
303
+				ret=-1;
304
+				goto error;
305
+			}
306
+			break;
307
+	}
308
+	if (unlikely(pvar->setf(msg, &pvar->pvp, EQ_T, &pval)<0)){
309
+		ERR("setting pvar failed\n");
310
+		goto error;
311
+	}
312
+	if (destroy_pval) pv_value_destroy(&pval);
313
+	return ret;
314
+error:
315
+	if (destroy_pval) pv_value_destroy(&pval);
316
+	return -1;
317
+drop:
318
+	if (destroy_pval) pv_value_destroy(&pval);
319
+	return EXPR_DROP;
320
+}
321
+
322
+
323
+
324
+/** eval rve and assign the result to lv
325
+ * lv=eval(rve)
326
+ *
327
+ * @param h  - script context
328
+ * @param msg - sip msg
329
+ * @param lv - lvalue
330
+ * @param rve - rvalue expression
331
+ * @return >= 0 on success (expr. bool value), -1 on error
332
+ */
333
+int lval_assign(struct run_act_ctx* h, struct sip_msg* msg, 
334
+				struct lvalue* lv, struct rval_expr* rve)
335
+{
336
+	struct rvalue* rv;
337
+	int ret;
338
+	
339
+	ret=0;
340
+	rv=rval_expr_eval(h, msg, rve);
341
+	if (unlikely(rv==0)){
342
+		ERR("rval expression evaluation failed\n");
343
+		goto error;
344
+	}
345
+	switch(lv->type){
346
+		case LV_NONE:
347
+			BUG("uninitialized/invalid lvalue (%d)\n", lv->type);
348
+			goto error;
349
+		case LV_AVP:
350
+			ret=lval_avp_assign(h, msg, lv, rv);
351
+			break;
352
+		case LV_PVAR:
353
+			ret=lval_pvar_assign(h, msg, lv, rv);
354
+			break;
355
+	}
356
+	rval_destroy(rv);
357
+	return ret;
358
+error:
359
+	if (rv) rval_destroy(rv);
360
+	return -1;
361
+}
0 362
new file mode 100644
... ...
@@ -0,0 +1,67 @@
1
+/* 
2
+ * $Id$
3
+ * 
4
+ * Copyright (C) 2008 iptelorg GmbH
5
+ *
6
+ * Permission to use, copy, modify, and distribute this software for any
7
+ * purpose with or without fee is hereby granted, provided that the above
8
+ * copyright notice and this permission notice appear in all copies.
9
+ *
10
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ */
18
+/**
19
+ * @file 
20
+ * @brief lvalues (assignment)
21
+ */
22
+/* 
23
+ * History:
24
+ * --------
25
+ *  2008-11-30  initial version (andrei)
26
+ */
27
+
28
+#ifndef __lvalue_h_
29
+#define __lvalue_h_
30
+
31
+#include "rvalue.h"
32
+#include "usr_avp.h"
33
+#include "pvar.h"
34
+#include "parser/msg_parser.h"
35
+#include "action.h"
36
+
37
+union lval_u{
38
+	pv_spec_t pvs;
39
+	avp_spec_t avps;
40
+};
41
+
42
+enum lval_type{
43
+	LV_NONE, LV_AVP, LV_PVAR
44
+};
45
+
46
+struct lvalue{
47
+	enum lval_type type;
48
+	union lval_u lv;
49
+};
50
+
51
+/* lval operators */
52
+#define EQ_T 254 /* k compatibility */
53
+
54
+
55
+
56
+/** eval rve and assign the result to lv
57
+ * lv=eval(rve)
58
+ *
59
+ * @param h  - script context
60
+ * @param msg - sip msg
61
+ * @param lv - lvalue
62
+ * @param rve - rvalue expression
63
+ * @return >= 0 on success (expr. bool value), -1 on error
64
+ */
65
+int lval_assign(struct run_act_ctx* h, struct sip_msg* msg, 
66
+				struct lvalue* lv, struct rval_expr* rve);
67
+#endif /* __lvalue_h_*/
0 68
new file mode 100644
... ...
@@ -0,0 +1,1377 @@
1
+/* 
2
+ * $Id$
3
+ * 
4
+ * Copyright (C) 2008 iptelorg GmbH
5
+ *
6
+ * Permission to use, copy, modify, and distribute this software for any
7
+ * purpose with or without fee is hereby granted, provided that the above
8
+ * copyright notice and this permission notice appear in all copies.
9
+ *
10
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ */
18
+/**
19
+ * @file 
20
+ * @brief rvalue expressions
21
+ */
22
+/* 
23
+ * History:
24
+ * --------
25
+ *  2008-12-01  initial version (andrei)
26
+ */
27
+
28
+#include "rvalue.h"
29
+
30
+/* minimum size alloc'ed for STR RVs (to accomodate
31
+ * strops without reallocs) */
32
+#define RV_STR_EXTRA 80
33
+
34
+#define rv_ref(rv) ((rv)->refcnt++)
35
+
36
+/** unref rv and returns true if 0 */
37
+#define rv_unref(rv) (((rv)->refcnt--)==0)
38
+
39
+
40
+inline static void rval_force_clean(struct rvalue* rv)
41
+{
42
+	if (rv->flags & RV_CNT_ALLOCED_F){
43
+		switch(rv->type){
44
+			case RV_STR:
45
+				pkg_free(rv->v.s.s);
46
+				rv->v.s.s=0;
47
+				rv->v.s.len=0;
48
+				break;
49
+			default:
50
+				BUG("RV_CNT_ALLOCED_F not supported for type %d\n", rv->type);
51
+		}
52
+		rv->flags&=~RV_CNT_ALLOCED_F;
53
+	}
54
+}
55
+
56
+
57
+
58
+/** frees a rval returned by rval_new(), rval_convert() or rval_expr_eval().
59
+ *   Note: ir will be freed only when refcnt reaches 0
60
+ */
61
+void rval_destroy(struct rvalue* rv)
62
+{
63
+	if (rv && rv_unref(rv)){
64
+		rval_force_clean(rv);
65
+		if (rv->flags & RV_RV_ALLOCED_F)
66
+			pkg_free(rv);
67
+	}
68
+}
69
+
70
+
71
+
72
+void rval_clean(struct rvalue* rv)
73
+{
74
+	if (rv_unref(rv))
75
+		rval_force_clean(rv);
76
+}
77
+
78
+
79
+
80
+void rve_destroy(struct rval_expr* rve)
81
+{
82
+	if (rve){
83
+		if (rve->op==RVE_RVAL_OP){
84
+			if (rve->left.rval.refcnt){
85
+				if (rve->left.rval.refcnt==1)
86
+					rval_destroy(&rve->left.rval);
87
+				else
88
+					BUG("rval expr rval with invalid refcnt: %d\n", 
89
+							rve->left.rval.refcnt);
90
+			}
91
+			if (rve->right.rval.refcnt){
92
+				if (rve->right.rval.refcnt==1)
93
+					rval_destroy(&rve->right.rval);
94
+				else
95
+					BUG("rval expr rval with invalid refcnt: %d\n", 
96
+							rve->right.rval.refcnt);
97
+			}
98
+		}else{
99
+			if (rve->left.rve)
100
+				rve_destroy(rve->left.rve);
101
+			if (rve->right.rve)
102
+				rve_destroy(rve->right.rve);
103
+		}
104
+		pkg_free(rve);
105
+	}
106
+}
107
+
108
+
109
+
110
+void rval_cache_clean(struct rval_cache* rvc)
111
+{
112
+	if (rvc->cache_type==RV_CACHE_PVAR){
113
+		pv_value_destroy(&rvc->c.pval);
114
+	}
115
+	rvc->cache_type=RV_CACHE_EMPTY;
116
+	rvc->val_type=RV_NONE;
117
+}
118
+
119
+
120
+#define rv_chg_in_place(rv)  ((rv)->refcnt==1) 
121
+
122
+
123
+
124
+/** init a rvalue structure.
125
+ * Note: not needed if the structure is allocate with one of the 
126
+ * rval_new* functions
127
+ */
128
+void rval_init(struct rvalue* rv, enum rval_type t, union rval_val* v, 
129
+				int flags)
130
+{
131
+	rv->flags=flags;
132
+	rv->refcnt=1;
133
+	rv->type=t;
134
+	if (v){
135
+		rv->v=*v;
136
+	}else{
137
+		memset (&rv->v, 0, sizeof(rv->v));
138
+	}
139
+}
140
+
141
+
142
+
143
+/** create a new pk_malloc'ed empty rvalue.
144
+  *
145
+  * @param extra_size - extra space to allocate
146
+  *                    (e.g.: so that future string operation can reuse
147
+  *                     the space)
148
+  * @return new rv or 0 on error
149
+  */
150
+struct rvalue* rval_new_empty(int extra_size)
151
+{
152
+	struct rvalue* rv;
153
+	int size; /* extra size at the end */
154
+	
155
+	size=ROUND_LONG(sizeof(*rv)-sizeof(rv->buf)+extra_size); /* round up */
156
+	rv=pkg_malloc(size);
157
+	if (likely(rv)){
158
+		rv->bsize=size-sizeof(*rv)-sizeof(rv->buf); /* remaining size->buffer*/
159
+		rv->flags=RV_RV_ALLOCED_F;
160
+		rv->refcnt=1;
161
+		rv->type=RV_NONE;
162
+	}
163
+	return rv;
164
+}
165
+
166
+
167
+
168
+/** create a new pk_malloc'ed rv from a str.
169
+  *
170
+  * @param s - pointer to str, must be non-null
171
+  * @param extra_size - extra space to allocate
172
+  *                    (so that future string operation can reuse
173
+  *                     the space)
174
+  * @return new rv or 0 on error
175
+  */
176
+struct rvalue* rval_new_str(str* s, int extra_size)
177
+{
178
+	struct rvalue* rv;
179
+	
180
+	rv=rval_new_empty(extra_size+s->len+1/* 0 term */);
181
+	if (likely(rv)){
182
+		rv->type=RV_STR;
183
+		rv->v.s.s=&rv->buf[0];
184
+		rv->v.s.len=s->len;
185
+		memcpy(rv->v.s.s, s->s, s->len);
186
+		rv->v.s.s[s->len]=0;
187
+	}
188
+	return rv;
189
+}
190
+
191
+
192
+
193
+/** create a new pk_malloc'ed rvalue from a rval_val union.
194
+  *
195
+  * @param s - pointer to str, must be non-null
196
+  * @param extra_size - extra space to allocate
197
+  *                    (so that future string operation can reuse
198
+  *                     the space)
199
+  * @return new rv or 0 on error
200
+  */
201
+struct rvalue* rval_new(enum rval_type t, union rval_val* v, int extra_size)
202
+{
203
+	struct rvalue* rv;
204
+	
205
+	if (t==RV_STR && v && v->s.len)
206
+		return rval_new_str(&v->s, extra_size);
207
+	rv=rval_new_empty(extra_size);
208
+	if (likely(rv)){
209
+		rv->type=t;
210
+		if (likely(v)){
211
+			rv->v=*v;
212
+		}else
213
+			memset (&rv->v, 0, sizeof(rv->v));
214
+	}
215
+	return rv;
216
+}
217
+
218
+
219
+
220
+/** get rvalue basic type (RV_INT or RV_STR).
221
+  *
222
+  * Given a rvalue it tries to determinte its basic type.
223
+  * Fills val_cache if non-null and empty (can be used in other rval*
224
+  * function calls, to avoid re-resolving avps or pvars). It must be
225
+  * rval_cache_clean()'en when no longer needed.
226
+  *
227
+  * @param rv - target rvalue
228
+  * @param val_cache - value cache, might be filled if non-null, 
229
+  *                    it _must_ be rval_cache_clean()'en when done.
230
+  * @return - basic type or RV_NONE on error
231
+  */
232
+inline static enum rval_type rval_get_btype(struct run_act_ctx* h,
233
+											struct sip_msg* msg,
234
+											struct rvalue* rv,
235
+											struct rval_cache* val_cache)
236
+{
237
+	avp_t* r_avp;
238
+	int_str tmp_avp_val;
239
+	int_str* avpv;
240
+	pv_value_t tmp_pval;
241
+	pv_value_t* pv;
242
+	enum rval_type tmp;
243
+	enum rval_type* ptype;
244
+
245
+	switch(rv->type){
246
+		case RV_INT:
247
+		case RV_STR:
248
+			return rv->type;
249
+		case RV_BEXPR:
250
+		case RV_ACTION_ST:
251
+			return RV_INT;
252
+		case RV_PVAR:
253
+			if (likely(val_cache && val_cache->cache_type==RV_CACHE_EMPTY)){
254
+				pv=&val_cache->c.pval;
255
+			}else{
256
+				val_cache=0;
257
+				pv=&tmp_pval;
258
+			}
259
+			memset(pv, 0, sizeof(tmp_pval));
260
+			if (likely(pv_get_spec_value(msg, &rv->v.pvs, pv)==0)){
261
+				if (pv->flags & PV_VAL_STR){
262
+					if (unlikely(val_cache==0)) pv_value_destroy(pv);
263
+					else{
264
+						val_cache->cache_type=RV_CACHE_PVAR;
265
+						val_cache->val_type=RV_STR;
266
+					}
267
+					return RV_STR;
268
+				}else if (pv->flags & PV_TYPE_INT){
269
+					if (unlikely(val_cache==0)) pv_value_destroy(pv);
270
+					else{
271
+						val_cache->cache_type=RV_CACHE_PVAR;
272
+						val_cache->val_type=RV_INT;
273
+					}
274
+					return RV_INT;
275
+				}else{
276
+					pv_value_destroy(pv);
277
+					goto error;
278
+				}
279
+			}else{
280
+				goto error;
281
+			}
282
+			break;
283
+		case RV_AVP:
284
+			if (likely(val_cache && val_cache==RV_CACHE_EMPTY)){
285
+				ptype=&val_cache->val_type;
286
+				avpv=&val_cache->c.avp_val;
287
+				val_cache->cache_type=RV_CACHE_AVP;
288
+			}else{
289
+				ptype=&tmp;
290
+				avpv=&tmp_avp_val;
291
+			}
292
+			r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
293
+											avpv, rv->v.avps.index);
294
+			if (likely(r_avp)){
295
+				if (r_avp->flags & AVP_VAL_STR){
296
+					*ptype=RV_STR;
297
+					return RV_STR;
298
+				}else{
299
+					*ptype=RV_INT;
300
+					return RV_INT;
301
+				}
302
+			}else{
303
+				*ptype=RV_NONE;
304
+				if (val_cache) val_cache->cache_type=RV_CACHE_EMPTY;
305
+				goto error;
306
+			}
307
+			break;
308
+		case RV_SEL:
309
+			return RV_STR;
310
+		default:
311
+			BUG("rv type %d not handled\n", rv->type);
312
+	}
313
+error:
314
+	return RV_NONE;
315
+}
316
+
317
+
318
+
319
+/** get the integer value of an rvalue.
320
+  * *i=(int)rv
321
+  * @return 0 on success, \<0 on error and EXPR_DROP on drop
322
+ */
323
+int rval_get_int(struct run_act_ctx* h, struct sip_msg* msg,
324
+								int* i, struct rvalue* rv,
325
+								struct rval_cache* cache)
326
+{
327
+	avp_t* r_avp;
328
+	int_str avp_val;
329
+	pv_value_t pval;
330
+	
331
+	switch(rv->type){
332
+		case RV_INT:
333
+			*i=rv->v.l;
334
+			break;
335
+		case RV_STR:
336
+			goto rv_str;
337
+		case RV_BEXPR:
338
+			*i=eval_expr(h, rv->v.bexpr, msg);
339
+			if (*i==EXPR_DROP){
340
+				*i=0; /* false */
341
+				return EXPR_DROP;
342
+			}
343
+			break;
344
+		case RV_ACTION_ST:
345
+			if (rv->v.action)
346
+				*i=run_actions(h, rv->v.action, msg);
347
+			else 
348
+				*i=0;
349
+			break;
350
+		case RV_SEL:
351
+			goto rv_str;
352
+		case RV_AVP:
353
+			if (unlikely(cache && cache->cache_type==RV_CACHE_AVP)){
354
+				if (likely(cache->val_type==RV_INT)){
355
+					*i=cache->c.avp_val.n;
356
+				}else if (cache->val_type==RV_STR)
357
+					goto rv_str;
358
+				else goto error;
359
+			}else{
360
+				r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
361
+											&avp_val, rv->v.avps.index);
362
+				if (likely(r_avp)){
363
+					if (unlikely(r_avp->flags & AVP_VAL_STR)){
364
+						goto rv_str;
365
+					}else{
366
+						*i=avp_val.n;
367
+					}
368
+				}else{
369
+					goto error;
370
+				}
371
+			}
372
+			break;
373
+		case RV_PVAR:
374
+			if (unlikely(cache && cache->cache_type==RV_CACHE_PVAR)){
375
+				if (likely((cache->val_type==RV_INT) || 
376
+								(cache->c.pval.flags & PV_VAL_INT))){
377
+					*i=cache->c.pval.ri;
378
+				}else if (cache->val_type==RV_STR)
379
+					goto rv_str;
380
+				else goto error;
381
+			}else{
382
+				memset(&pval, 0, sizeof(pval));
383
+				if (likely(pv_get_spec_value(msg, &rv->v.pvs, &pval)==0)){
384
+					if (likely(pval.flags & PV_VAL_INT)){
385
+						pv_value_destroy(&pval);
386
+						*i=pval.ri;
387
+					}else if (likely(pval.flags & PV_VAL_STR)){
388
+						pv_value_destroy(&pval);
389
+						goto rv_str;
390
+					}else{
391
+						pv_value_destroy(&pval);
392
+						goto error;
393
+					}
394
+				}else{
395
+					goto error;
396
+				}
397
+			}
398
+			break;
399
+		default:
400
+			BUG("rv type %d not handled\n", rv->type);
401
+			goto error;
402
+	}
403
+	return 0;
404
+rv_str:
405
+	/* rv is of string type => error */
406
+	ERR("string in int expression\n");
407
+error:
408
+	return -1;
409
+}
410
+
411
+
412
+
413
+/** get the string value of an rv in a tmp variable
414
+  * *s=(str)rv
415
+  * The result points either to a temporary string or inside
416
+  * new_cache. new_cache must be non zero, initialized previously,
417
+  * and it _must_ be rval_cache_clean(...)'ed when done.
418
+  * WARNING: it's not intended for general use, it might return a pointer
419
+  * to a static buffer (int2str) so use the result a.s.a.p, make a copy.
420
+  * or use rval_get_str() instead.
421
+  * @param h - script context handle
422
+  * @param msg - sip msg
423
+  * @param tmpv - str return value (pointer to a str struct that will be
424
+  *               be filled.
425
+  * @param rv   - rvalue to be converted
426
+  * @param cache - cached rv value (read-only)
427
+  * @param tmp_cache - used for temporary storage (so that tmpv will not
428
+  *                 point to possible freed data), it must be non-null,
429
+  *                 initialized and cleaned afterwards.
430
+  * @return 0 on success, <0 on error and EXPR_DROP on drop
431
+ */
432
+int rval_get_tmp_str(struct run_act_ctx* h, struct sip_msg* msg,
433
+								str* tmpv, struct rvalue* rv,
434
+								struct rval_cache* cache,
435
+								struct rval_cache* tmp_cache)
436
+{
437
+	avp_t* r_avp;
438
+	pv_value_t pval;
439
+	int i;
440
+	
441
+	switch(rv->type){
442
+		case RV_INT:
443
+			tmpv->s=int2str(rv->v.l, &tmpv->len);
444
+			break;
445
+		case RV_STR:
446
+			*tmpv=rv->v.s;
447
+			break;
448
+		case RV_ACTION_ST:
449
+			if (rv->v.action)
450
+				i=run_actions(h, rv->v.action, msg);
451
+			else 
452
+				i=0;
453
+			tmpv->s=int2str(i, &tmpv->len);
454
+			break;
455
+		case RV_BEXPR:
456
+			i=eval_expr(h, rv->v.bexpr, msg);
457
+			if (i==EXPR_DROP){
458
+				i=0; /* false */
459
+				tmpv->s=int2str(i, &tmpv->len);
460
+				return EXPR_DROP;
461
+			}
462
+			tmpv->s=int2str(i, &tmpv->len);
463
+			break;
464
+		case RV_SEL:
465
+			i=run_select(tmpv, &rv->v.sel, msg);
466
+			if (unlikely(i!=0)){
467
+				if (i<0){
468
+					goto error;
469
+				}else { /* i>0 */
470
+					tmpv->s="";
471
+					tmpv->len=0;
472
+				}
473
+			}
474
+			break;
475
+		case RV_AVP:
476
+			if (likely(cache && cache->cache_type==RV_CACHE_AVP)){
477
+				if (likely(cache->val_type==RV_STR)){
478
+					*tmpv=cache->c.avp_val.s;
479
+				}else if (cache->val_type==RV_INT){
480
+					i=cache->c.avp_val.n;
481
+					tmpv->s=int2str(i, &tmpv->len);
482
+				}else goto error;
483
+			}else{
484
+				r_avp = search_avp_by_index(rv->v.avps.type, rv->v.avps.name,
485
+											&tmp_cache->c.avp_val,
486
+											rv->v.avps.index);
487
+				if (likely(r_avp)){
488
+					if (likely(r_avp->flags & AVP_VAL_STR)){
489
+						tmp_cache->cache_type=RV_CACHE_AVP;
490
+						tmp_cache->val_type=RV_STR;
491
+						*tmpv=tmp_cache->c.avp_val.s;
492
+					}else{
493
+						i=tmp_cache->c.avp_val.n;
494
+						tmpv->s=int2str(i, &tmpv->len);
495
+					}
496
+				}else{
497
+					goto error;
498
+				}
499
+			}
500
+			break;
501
+		case RV_PVAR:
502
+			if (likely(cache && cache->cache_type==RV_CACHE_PVAR)){
503
+				if (likely(cache->val_type==RV_STR)){
504
+					*tmpv=cache->c.pval.rs;
505
+				}else if (cache->val_type==RV_INT){
506
+					i=cache->c.pval.ri;
507
+					tmpv->s=int2str(i, &tmpv->len);
508
+				}else goto error;
509
+			}else{
510
+				memset(&pval, 0, sizeof(pval));
511
+				if (likely(pv_get_spec_value(msg, &rv->v.pvs,
512
+												&tmp_cache->c.pval)==0)){
513
+					if (likely(pval.flags & PV_VAL_STR)){
514
+						/*  the value is not destroyed, but saved instead
515
+							in tmp_cache so that it can be destroyed later
516
+							when no longer needed */
517
+						tmp_cache->cache_type=RV_CACHE_PVAR;
518
+						tmp_cache->val_type=RV_STR;
519
+						*tmpv=tmp_cache->c.pval.rs;
520
+					}else if (likely(pval.flags & PV_VAL_INT)){
521
+						i=pval.ri;
522
+						pv_value_destroy(&tmp_cache->c.pval);
523
+						tmpv->s=int2str(i, &tmpv->len);
524
+					}else{
525
+						pv_value_destroy(&tmp_cache->c.pval);
526
+						goto error;
527
+					}
528
+				}else{
529
+					goto error;
530
+				}
531
+			}
532
+			break;
533
+		default:
534
+			BUG("rv type %d not handled\n", rv->type);
535
+			goto error;
536
+	}
537
+	return 0;
538
+error:
539
+	return -1;
540
+}
541
+
542
+
543
+
544
+/** get the string value of an rv.
545
+  * *s=(str)rv
546
+  * The result is pkg malloc'ed (so it should be pkg_free()'ed when finished.
547
+  * @return 0 on success, <0 on error and EXPR_DROP on drop
548
+ */
549
+int rval_get_str(struct run_act_ctx* h, struct sip_msg* msg,
550
+								str* s, struct rvalue* rv,
551
+								struct rval_cache* cache)
552
+{
553
+	str tmp;
554
+	struct rval_cache tmp_cache;
555
+	
556
+	rval_cache_init(&tmp_cache);
557
+	if (unlikely(rval_get_tmp_str(h, msg, &tmp, rv, cache, &tmp_cache)<0))
558
+		goto error;
559
+	s->s=pkg_malloc(tmp.len+1/* 0 term */);
560
+	if (unlikely(s->s==0)){
561
+		ERR("memory allocation error\n");
562
+		goto error;
563
+	}
564
+	s->len=tmp.len;
565
+	memcpy(s->s, tmp.s, tmp.len);
566
+	s->s[tmp.len]=0; /* 0 term */
567
+	rval_cache_clean(&tmp_cache);
568
+	return 0;
569
+error:
570
+	rval_cache_clean(&tmp_cache);
571
+	return -1;
572
+}
573
+
574
+
575
+
576
+/** convert a rvalue to another rvalue, of a specific type.
577
+ *
578
+ * The result is read-only in most cases (can be a reference
579
+ * to another rvalue, can be checked by using rv_chg_in_place()) and
580
+ * _must_ be rval_destroy()'ed.
581
+ *
582
+ * @param type - type to convert to
583
+ * @param v - rvalue to convert
584
+ * @param c - rval_cache (cached v value if known/filled by another
585
+ *            function), can be 0 (unknown/not needed)
586
+ * @return pointer to a rvalue (reference to an existing one or a new
587
+ *   one, @see rv_chg_in_place() and the above comment) or 0 on error.
588
+ */
589
+struct rvalue* rval_convert(struct run_act_ctx* h, struct sip_msg* msg,
590
+							enum rval_type type, struct rvalue* v,
591
+							struct rval_cache* c)
592
+{
593
+	int i;
594
+	struct rval_cache tmp_cache;
595
+	str tmp;
596
+	struct rvalue* ret;
597
+	union rval_val val;
598
+	
599
+	if (v->type==type){
600
+		rv_ref(v);
601
+		return v;
602
+	}
603
+	switch(type){
604
+		case RV_INT:
605
+			if (unlikely(rval_get_int(h, msg, &i, v, c) < 0))
606
+				return 0;
607
+			val.l=i;
608
+			return rval_new(RV_INT, &val, 0);
609
+		case RV_STR:
610
+			rval_cache_init(&tmp_cache);
611
+			if (unlikely(rval_get_tmp_str(h, msg, &tmp, v, c, &tmp_cache) < 0))
612
+			{
613
+				rval_cache_clean(&tmp_cache);
614
+				return 0;
615
+			}
616
+			ret=rval_new_str(&tmp, RV_STR_EXTRA);
617
+			rval_cache_clean(&tmp_cache);
618
+			return ret;
619
+		case RV_NONE:
620
+		default:
621
+			BUG("unsupported conversion to type %d\n", type);
622
+			return 0;
623
+	}
624
+	return 0;
625
+}
626
+
627
+
628
+
629
+/** integer operation: *res= op v.
630
+  * @return 0 on succes, \<0 on error
631
+  */
632
+inline static int int_intop1(int* res, enum rval_expr_op op, int v)
633
+{
634
+	switch(op){
635
+		case RVE_UMINUS_OP:
636
+			*res=-v;
637
+			break;
638
+		case RVE_BOOL_OP:
639
+			*res=!!v;
640
+			break;
641
+		case RVE_LNOT_OP:
642
+			*res=!v;
643
+			break;
644
+		default:
645
+			BUG("rv unsupported intop1 %d\n", op);
646
+			return -1;
647
+	}
648
+	return 0;
649
+}
650
+
651
+
652
+
653
+/** integer operation: *res= op v.
654
+  * @return 0 on succes, \<0 on error
655
+  */
656
+inline static int int_intop2(int* res, enum rval_expr_op op, int v1, int v2)
657
+{
658
+	switch(op){
659
+		case RVE_PLUS_OP:
660
+			*res=v1+v2;
661
+			break;
662
+		case RVE_MINUS_OP:
663
+			*res=v1-v2;
664
+			break;
665
+		case RVE_MUL_OP:
666
+			*res=v1*v2;
667
+			break;
668
+		case RVE_DIV_OP:
669
+			if (unlikely(v2==0)){
670
+				ERR("rv div by 0\n");
671
+				return -1;
672
+			}
673
+			*res=v1/v2;
674
+			break;
675
+		default:
676
+			BUG("rv unsupported intop %d\n", op);
677
+			return -1;
678
+	}
679
+	return 0;
680
+}
681
+
682
+
683
+
684
+/** integer operation: ret= op v (returns a rvalue).
685
+ * @return rvalue on success, 0 on error
686
+ */
687
+inline static struct rvalue* rval_intop1(struct run_act_ctx* h,
688
+											struct sip_msg* msg,
689
+											enum rval_expr_op op,
690
+											struct rvalue* v)
691
+{
692
+	struct rvalue* rv2;
693
+	struct rvalue* ret;
694
+	int i;
695
+	
696
+	i=0;
697
+	rv2=rval_convert(h, msg, RV_INT, v, 0);
698
+	if (unlikely(rv2==0)){
699
+		ERR("rval int conversion failed\n");
700
+		goto error;
701
+	}
702
+	if (unlikely(int_intop1(&i, op, rv2->v.l)<0))
703
+		goto error;
704
+	if (rv_chg_in_place(rv2)){
705
+		ret=rv2;
706
+		rv_ref(ret);
707
+	}else if (rv_chg_in_place(v)){
708
+		ret=v;
709
+		rv_ref(ret);
710
+	}else{
711
+		ret=rval_new(RV_INT, &rv2->v, 0);
712
+		if (unlikely(ret==0)){
713
+			ERR("eval out of memory\n");
714
+			goto error;
715
+		}
716
+	}
717
+	rval_destroy(rv2);
718
+	ret->v.l=i;
719
+	return ret;
720
+error:
721
+	rval_destroy(rv2);
722
+	return 0;
723
+}
724
+
725
+
726
+
727
+/** integer operation: ret= l op r (returns a rvalue).
728
+ * @return rvalue on success, 0 on error
729
+ */
730
+inline static struct rvalue* rval_intop2(struct run_act_ctx* h,
731
+											struct sip_msg* msg,
732
+											enum rval_expr_op op,
733
+											struct rvalue* l,
734
+											struct rvalue* r)
735
+{
736
+	struct rvalue* rv1;
737
+	struct rvalue* rv2;
738
+	struct rvalue* ret;
739
+	int i;
740
+
741
+	rv2=rv1=0;
742
+	ret=0;
743
+	if ((rv1=rval_convert(h, msg, RV_INT, l, 0))==0)
744
+		goto error;
745
+	if ((rv2=rval_convert(h, msg, RV_INT, r, 0))==0)
746
+		goto error;
747
+	if (unlikely(int_intop2(&i, op, rv1->v.l, rv2->v.l)<0))
748
+		goto error;
749
+	if (rv_chg_in_place(rv1)){
750
+		/* try reusing rv1 */
751
+		ret=rv1;
752
+		rv_ref(ret);
753
+	}else if (rv_chg_in_place(rv2)){
754
+		/* try reusing rv2 */
755
+		ret=rv2;
756
+		rv_ref(ret);
757
+	}else if ((l->type==RV_INT) && (rv_chg_in_place(l))){
758
+		ret=l;
759
+		rv_ref(ret);
760
+	} else if ((r->type==RV_INT) && (rv_chg_in_place(r))){
761
+		ret=r;
762
+		rv_ref(ret);
763
+	}else{
764
+		ret=rval_new(RV_INT, &rv1->v, 0);
765
+		if (unlikely(ret==0)){
766
+			ERR("rv eval out of memory\n");
767
+			goto error;
768
+		}
769
+	}
770
+	rval_destroy(rv1); 
771
+	rval_destroy(rv2); 
772
+	ret->v.l=i;
773
+	return ret;
774
+error:
775
+	rval_destroy(rv1); 
776
+	rval_destroy(rv2); 
777
+	return 0;
778
+}
779
+
780
+
781
+
782
+/** string add operation: ret= l . r (returns a rvalue).
783
+ * Can use cached rvalues (c1 & c2).
784
+ * @return rvalue on success, 0 on error
785
+ */
786
+inline static struct rvalue* rval_str_add2(struct run_act_ctx* h,
787
+											struct sip_msg* msg,
788
+											struct rvalue* l,
789
+											struct rval_cache* c1,
790
+											struct rvalue* r,
791
+											struct rval_cache* c2
792
+											)
793
+{
794
+	struct rvalue* rv1;
795
+	struct rvalue* rv2;
796
+	struct rvalue* ret;
797
+	str* s1;
798
+	str* s2;
799
+	str tmp;
800
+	short flags;
801
+	int len;
802
+	
803
+	rv2=rv1=0;
804
+	ret=0;
805
+	flags=0;
806
+	s1=0;
807
+	s2=0;
808
+	if ((rv1=rval_convert(h, msg, RV_STR, l, c1))==0)
809
+		goto error;
810
+	if ((rv2=rval_convert(h, msg, RV_STR, r, c2))==0)
811
+		goto error;
812
+	
813
+	len=rv1->v.s.len + rv2->v.s.len + 1 /* 0 */;
814
+	
815
+	if (rv_chg_in_place(rv1) && (rv1->bsize>=len)){
816
+		/* try reusing rv1 */
817
+		ret=rv1;
818
+		rv_ref(ret);
819
+		s2=&rv2->v.s;
820
+		if (ret->v.s.s == &ret->buf[0]) s1=0;
821
+		else{
822
+			tmp=ret->v.s;
823
+			flags=ret->flags;
824
+			ret->flags &= ~RV_CNT_ALLOCED_F;
825
+			ret->v.s.s=&ret->buf[0];
826
+			ret->v.s.len=0;
827
+			s1=&tmp;
828
+		}
829
+	}else if (rv_chg_in_place(rv2) && (rv2->bsize>=len)){
830
+		/* try reusing rv2 */
831
+		ret=rv2;
832
+		rv_ref(ret);
833
+		s1=&rv1->v.s;
834
+		if (ret->v.s.s == &ret->buf[0]) 
835
+			s2=&ret->v.s;
836
+		else{
837
+			tmp=ret->v.s;
838
+			flags=ret->flags;
839
+			ret->flags &= ~RV_CNT_ALLOCED_F;
840
+			ret->v.s.s=&ret->buf[0];
841
+			ret->v.s.len=0;
842
+			s2=&tmp;
843
+		}
844
+	}else if ((l->type==RV_STR) && (rv_chg_in_place(l)) && (l->bsize>=len)){
845
+		ret=l;
846
+		rv_ref(ret);
847
+		s2=&rv2->v.s;
848
+		if (ret->v.s.s == &ret->buf[0]) s1=0;
849
+		else{
850
+			tmp=ret->v.s;
851
+			flags=ret->flags;
852
+			ret->flags &= ~RV_CNT_ALLOCED_F;
853
+			ret->v.s.s=&ret->buf[0];
854
+			ret->v.s.len=0;
855
+			s1=&tmp;
856
+		}
857
+	} else if ((r->type==RV_STR) && (rv_chg_in_place(r) && (r->bsize>=len))){
858
+		ret=r;
859
+		rv_ref(ret);
860
+		s1=&rv1->v.s;
861
+		if (ret->v.s.s == &ret->buf[0]) 
862
+			s2=&ret->v.s;
863
+		else{
864
+			tmp=ret->v.s;
865
+			flags=ret->flags;
866
+			ret->flags &= ~RV_CNT_ALLOCED_F;
867
+			ret->v.s.s=&ret->buf[0];
868
+			ret->v.s.len=0;
869
+			s2=&tmp;
870
+		}
871
+	}else{
872
+		ret=rval_new(RV_STR, &rv1->v, len + RV_STR_EXTRA);
873
+		if (unlikely(ret==0)){
874
+			ERR("rv eval out of memory\n");
875
+			goto error;
876
+		}
877
+		s1=0;
878
+		s2=&rv2->v.s;
879
+	}
880
+	/* do the actual copy */
881
+	ret->v.s.len=rv1->v.s.len;
882
+	memmove(ret->buf+ret->v.s.len, s2->s, s2->len);
883
+	if (s1){
884
+		memcpy(ret->buf, s1->s, s1->len);
885
+	}
886
+	ret->v.s.len+=s2->len;
887
+	ret->v.s.s[ret->v.s.len]=0;
888
+	/* cleanup if needed */
889
+	if (flags & RV_CNT_ALLOCED_F)
890
+		pkg_free(tmp.s);
891
+	rval_destroy(rv1); 
892
+	rval_destroy(rv2); 
893
+	return ret;
894
+error:
895
+	rval_destroy(rv1); 
896
+	rval_destroy(rv2); 
897
+	return 0;
898
+}
899
+
900
+
901
+
902
+/** evals an integer expr  to an int.
903
+ * 
904
+ *  *res=(int)eval(rve)
905
+ *  @return 0 on success, \<0 on error
906
+ */
907
+int rval_expr_eval_int( struct run_act_ctx* h, struct sip_msg* msg,
908
+						int* res, struct rval_expr* rve)
909
+{
910
+	int i1, i2, ret;
911
+	
912
+	switch(rve->op){
913
+		case RVE_RVAL_OP:
914
+			ret=rval_get_int(h, msg, res,  &rve->left.rval, 0);
915
+			break;
916
+		case RVE_UMINUS_OP:
917
+		case RVE_BOOL_OP:
918
+		case RVE_LNOT_OP:
919
+			if (unlikely(
920
+					(ret=rval_expr_eval_int(h, msg, &i1, rve->left.rve)) <0) )
921
+				break;
922
+			ret=int_intop1(res, rve->op, i1);
923
+			break;
924
+		case RVE_MUL_OP:
925
+		case RVE_DIV_OP:
926
+		case RVE_MINUS_OP:
927
+		case RVE_PLUS_OP:
928
+			if (unlikely(
929
+					(ret=rval_expr_eval_int(h, msg, &i1, rve->left.rve)) <0) )
930
+				break;
931
+			if (unlikely(
932
+					(ret=rval_expr_eval_int(h, msg, &i2, rve->right.rve)) <0) )
933
+				break;
934
+			ret=int_intop2(res, rve->op, i1, i2);
935
+			break;
936
+		case RVE_NONE_OP:
937
+		default:
938
+			BUG("invalid rval int expression operation %d\n", rve->op);
939
+			ret=-1;
940
+	};
941
+	return ret;
942
+}
943
+
944
+
945
+
946
+/** evals a rval expr..
947
+ * WARNING: result must be rval_destroy()'ed if non-null (it might be
948
+ * a reference to another rval). The result can be modified only
949
+ * if rv_chg_in_place() returns true.
950
+ * @result rvalue on success, 0 on error
951
+ */
952
+struct rvalue* rval_expr_eval(struct run_act_ctx* h, struct sip_msg* msg,
953
+								struct rval_expr* rve)
954
+{
955
+	struct rvalue* rv1;
956
+	struct rvalue* rv2;
957
+	struct rvalue* ret;
958
+	struct rval_cache c1;
959
+	union rval_val v;
960
+	int r, i, j;
961
+	enum rval_type type;
962
+	
963
+	rv1=0;
964
+	rv2=0;
965
+	switch(rve->op){
966
+		case RVE_RVAL_OP:
967
+			rv_ref(&rve->left.rval);
968
+			return &rve->left.rval;
969
+			break;
970
+		case RVE_UMINUS_OP:
971
+		case RVE_BOOL_OP:
972
+		case RVE_LNOT_OP:
973
+		case RVE_MINUS_OP:
974
+		case RVE_MUL_OP:
975
+		case RVE_DIV_OP:
976
+			/* operator forces integer type */
977
+			r=rval_expr_eval_int(h, msg, &i, rve);
978
+			if (likely(r==0)){
979
+				v.l=i;
980
+				ret=rval_new(RV_INT, &v, 0);
981
+				if (unlikely(ret==0)){
982
+					ERR("rv eval int expression: out of memory\n");
983
+					goto error;
984
+				}
985
+				return ret;
986
+			}else{
987
+				ERR("rval expression evaluation failed\n");
988
+				goto error;
989
+			}