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