Skip to content

Commit 628a126

Browse files
committed
cfg syntax: Fix all complex assignment operators
The opensips.cfg now fully supports the non-trivial assignment operators, such as: +=, -=, *=, /=, %=, &=, |= and ^=. Syntactially, they were supported until now, but were actually unimplemented (more precisely, they were equivalent to the "=" operator). Only the "+=" operator can also work with strings, for example: $var(x) = "foo"; $var(x) += "-bar"; # now contains "foo-bar" $rU = "+40"; $rU += "729" + "884950"; # now contains "+40729884950" All of them (including "+="), work with integers: $var(i) = 0; $var(i) += 2; # 2 $var(i) *= 3; # 6 $var(i) /= 6; # 1 ...
1 parent 536e7b0 commit 628a126

File tree

2 files changed

+138
-38
lines changed

2 files changed

+138
-38
lines changed

action.c

+127-37
Original file line numberDiff line numberDiff line change
@@ -217,11 +217,11 @@ int run_top_route(struct action* a, struct sip_msg* msg)
217217
/* execute assignment operation */
218218
int do_assign(struct sip_msg* msg, struct action* a)
219219
{
220+
str st;
220221
int ret;
221-
pv_value_t val;
222+
pv_value_t lval, val;
222223
pv_spec_p dspec;
223224

224-
ret = -1;
225225
dspec = (pv_spec_p)a->elem[0].u.data;
226226
if(!pv_is_w(dspec))
227227
{
@@ -241,52 +241,142 @@ int do_assign(struct sip_msg* msg, struct action* a)
241241
}
242242
}
243243

244-
switch ((unsigned char)a->type){
245-
case EQ_T:
246-
case COLONEQ_T:
247-
case PLUSEQ_T:
248-
case MINUSEQ_T:
249-
case DIVEQ_T:
250-
case MULTEQ_T:
251-
case MODULOEQ_T:
252-
case BANDEQ_T:
253-
case BOREQ_T:
254-
case BXOREQ_T:
255-
script_trace("assign",
256-
(unsigned char)a->type == EQ_T ? "equal" :
257-
(unsigned char)a->type == COLONEQ_T ? "colon-eq" :
258-
(unsigned char)a->type == PLUSEQ_T ? "plus-eq" :
259-
(unsigned char)a->type == MINUSEQ_T ? "minus-eq" :
260-
(unsigned char)a->type == DIVEQ_T ? "div-eq" :
261-
(unsigned char)a->type == MULTEQ_T ? "mult-eq" :
262-
(unsigned char)a->type == MODULOEQ_T? "modulo-eq" :
263-
(unsigned char)a->type == BANDEQ_T ? "b-and-eq" :
264-
(unsigned char)a->type == BOREQ_T ? "b-or-eq":"b-xor-eq",
265-
msg, a->file, a->line);
266-
267-
if(a->elem[1].type == NULLV_ST || (val.flags & PV_VAL_NULL))
268-
{
269-
if(pv_set_value(msg, dspec, (int)a->type, 0)<0)
270-
{
271-
LM_ERR("setting PV failed\n");
244+
switch (a->type) {
245+
case EQ_T:
246+
case COLONEQ_T:
247+
break;
248+
case PLUSEQ_T:
249+
case MINUSEQ_T:
250+
case DIVEQ_T:
251+
case MULTEQ_T:
252+
case MODULOEQ_T:
253+
case BANDEQ_T:
254+
case BOREQ_T:
255+
case BXOREQ_T:
256+
if (pv_get_spec_value(msg, dspec, &lval) != 0) {
257+
LM_ERR("failed to get left-hand side value\n");
258+
goto error;
259+
}
260+
261+
if (lval.flags & PV_VAL_NULL || val.flags & PV_VAL_NULL) {
262+
LM_ERR("NULL value(s) in complex assignment expressions "
263+
"(+=, -=, etc.)\n");
264+
goto error;
265+
}
266+
267+
/* both include STR versions and neither is primarily an INT */
268+
if ((lval.flags & PV_VAL_STR) && (val.flags & PV_VAL_STR) &&
269+
!(lval.flags & PV_TYPE_INT) && !(val.flags & PV_TYPE_INT)) {
270+
val.ri = 0;
271+
272+
if (a->type != PLUSEQ_T)
273+
goto bad_operands;
274+
275+
if (!(val.flags & PV_VAL_PKG)) {
276+
st = val.rs;
277+
val.rs.s = pkg_malloc(val.rs.len + lval.rs.len + 1);
278+
if (!val.rs.s) {
279+
val.rs.s = st.s;
280+
LM_ERR("oom 1\n");
272281
goto error;
273282
}
283+
284+
memcpy(val.rs.s, lval.rs.s, lval.rs.len);
285+
memcpy(val.rs.s + lval.rs.len, st.s, st.len);
286+
val.rs.len += lval.rs.len;
287+
val.rs.s[val.rs.len] = '\0';
288+
val.flags |= PV_VAL_PKG;
289+
290+
if (val.flags & PV_VAL_SHM) {
291+
val.flags &= ~PV_VAL_SHM;
292+
shm_free(st.s);
293+
}
274294
} else {
275-
if(pv_set_value(msg, dspec, (int)a->type, &val)<0)
276-
{
277-
LM_ERR("setting PV failed\n");
295+
st.len = val.rs.len;
296+
if (pkg_str_extend(&val.rs, val.rs.len + lval.rs.len + 1) != 0) {
297+
LM_ERR("oom 2\n");
278298
goto error;
279299
}
300+
val.rs.len--;
301+
memmove(val.rs.s + lval.rs.len, val.rs.s, st.len);
302+
memcpy(val.rs.s, lval.rs.s, lval.rs.len);
303+
val.rs.s[val.rs.len] = '\0';
280304
}
281-
ret = 1;
305+
} else if ((lval.flags & PV_VAL_INT) && (val.flags & PV_VAL_INT)) {
306+
if (val.flags & PV_VAL_STR)
307+
val.flags &= ~PV_VAL_STR;
308+
switch (a->type) {
309+
case PLUSEQ_T:
310+
val.ri = lval.ri + val.ri;
311+
break;
312+
case MINUSEQ_T:
313+
val.ri = lval.ri - val.ri;
314+
break;
315+
case DIVEQ_T:
316+
val.ri = lval.ri / val.ri;
317+
break;
318+
case MULTEQ_T:
319+
val.ri = lval.ri * val.ri;
320+
break;
321+
case MODULOEQ_T:
322+
val.ri = lval.ri % val.ri;
323+
break;
324+
case BANDEQ_T:
325+
val.ri = lval.ri & val.ri;
326+
break;
327+
case BOREQ_T:
328+
val.ri = lval.ri | val.ri;
329+
break;
330+
case BXOREQ_T:
331+
val.ri = lval.ri ^ val.ri;
332+
break;
333+
}
334+
} else {
335+
goto bad_operands;
336+
}
282337
break;
283-
default:
284-
LM_ALERT("BUG -> unknown op type %d\n", a->type);
338+
default:
339+
LM_ALERT("BUG -> unknown op type %d\n", a->type);
340+
goto error;
341+
}
342+
343+
script_trace("assign",
344+
(unsigned char)a->type == EQ_T ? "equal" :
345+
(unsigned char)a->type == COLONEQ_T ? "colon-eq" :
346+
(unsigned char)a->type == PLUSEQ_T ? "plus-eq" :
347+
(unsigned char)a->type == MINUSEQ_T ? "minus-eq" :
348+
(unsigned char)a->type == DIVEQ_T ? "div-eq" :
349+
(unsigned char)a->type == MULTEQ_T ? "mult-eq" :
350+
(unsigned char)a->type == MODULOEQ_T? "modulo-eq" :
351+
(unsigned char)a->type == BANDEQ_T ? "b-and-eq" :
352+
(unsigned char)a->type == BOREQ_T ? "b-or-eq":"b-xor-eq",
353+
msg, a->file, a->line);
354+
355+
if(a->elem[1].type == NULLV_ST || (val.flags & PV_VAL_NULL))
356+
{
357+
if(pv_set_value(msg, dspec, (int)a->type, 0)<0)
358+
{
359+
LM_ERR("setting PV failed\n");
285360
goto error;
361+
}
362+
} else {
363+
if(pv_set_value(msg, dspec, (int)a->type, &val)<0)
364+
{
365+
LM_ERR("setting PV failed\n");
366+
goto error;
367+
}
286368
}
287369

288370
pv_value_destroy(&val);
289-
return ret;
371+
return 1;
372+
373+
bad_operands:
374+
LM_ERR("unsupported operand type(s) for %s: %s and %s\n",
375+
assignop_str(a->type),
376+
lval.flags & PV_VAL_STR ? "string" : "int",
377+
val.flags & PV_VAL_STR ? "string" : "int");
378+
pv_value_destroy(&val);
379+
return -1;
290380

291381
error:
292382
LM_ERR("error at %s:%d\n", a->file, a->line);

route_struct.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,17 @@ struct action{
118118
struct action* next;
119119
};
120120

121-
121+
#define assignop_str(op) ( \
122+
(op) == EQ_T ? "=" : \
123+
(op) == COLONEQ_T ? ":=" : \
124+
(op) == PLUSEQ_T ? "+=" : \
125+
(op) == MINUSEQ_T ? "-=" : \
126+
(op) == DIVEQ_T ? "/=" : \
127+
(op) == MULTEQ_T ? "*=" : \
128+
(op) == MODULOEQ_T ? "%=" : \
129+
(op) == BANDEQ_T ? "&=" : \
130+
(op) == BOREQ_T ? "|=" : \
131+
(op) == BXOREQ_T ? "^=" : "unknown")
122132

123133
struct expr* mk_exp(int op, struct expr* left, struct expr* right);
124134
struct expr* mk_elem(int op, int leftt, void *leftd, int rightt, void *rightd);

0 commit comments

Comments
 (0)