summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSébastien Helleu <flashcode@flashtux.org>2019-12-18 21:22:36 +0100
committerSébastien Helleu <flashcode@flashtux.org>2019-12-18 21:22:36 +0100
commite612e63140e5f272da3dda9443660534cb5e606a (patch)
treed7f697d44feaa247a46945a7e073b973b2f346fb
parenta13099aa635d7587f00bdd375c129b3e081e98b2 (diff)
downloadweechat-e612e63140e5f272da3dda9443660534cb5e606a.zip
core: fix evaluation of condition with nested "if" (closes #1434)
-rw-r--r--ChangeLog.adoc1
-rw-r--r--src/core/wee-eval.c63
-rw-r--r--tests/unit/core/test-core-eval.cpp6
3 files changed, 50 insertions, 20 deletions
diff --git a/ChangeLog.adoc b/ChangeLog.adoc
index 5b301e8aa..01ba63999 100644
--- a/ChangeLog.adoc
+++ b/ChangeLog.adoc
@@ -25,6 +25,7 @@ New features::
Bug fixes::
+ * core: fix evaluation of condition with nested "if" (issue #1434)
* irc: fix memory leak when the channel topic is changed
Build::
diff --git a/src/core/wee-eval.c b/src/core/wee-eval.c
index c63151291..40d958b37 100644
--- a/src/core/wee-eval.c
+++ b/src/core/wee-eval.c
@@ -102,7 +102,8 @@ eval_is_true (const char *value)
*
* If escape is 1, the prefix can be escaped with '\' (and then is ignored).
*
- * For example: eval_strstr_level ("(x || y) || z", "||")
+ * For example:
+ * eval_strstr_level ("(x || y) || z", "||", eval_context, "(", ")", 0)
* will return a pointer on "|| z" (because the first "||" is
* in a sub-expression, which is skipped).
*
@@ -111,37 +112,63 @@ eval_is_true (const char *value)
const char *
eval_strstr_level (const char *string, const char *search,
- const char *prefix, const char *suffix, int escape)
+ struct t_eval_context *eval_context,
+ const char *extra_prefix, const char *extra_suffix,
+ int escape)
{
const char *ptr_string;
- int level, length_search, length_prefix, length_suffix;
+ int level, length_search;
+ int length_prefix, length_prefix2, length_suffix, length_suffix2;
+
+ EVAL_DEBUG("eval_strstr_level(\"%s\", \"%s\", \"%s\", \"%s\", %d)",
+ string, search, extra_prefix, extra_suffix, escape);
if (!string || !search)
return NULL;
length_search = strlen (search);
- length_prefix = strlen (prefix);
- length_suffix = strlen (suffix);
+
+ length_prefix = strlen (eval_context->prefix);
+ length_suffix = strlen (eval_context->suffix);
+
+ length_prefix2 = (extra_prefix) ? strlen (extra_prefix) : 0;
+ length_suffix2 = (extra_suffix) ? strlen (extra_suffix) : 0;
ptr_string = string;
level = 0;
while (ptr_string[0])
{
- if (escape && (ptr_string[0] == '\\') && (ptr_string[1] == prefix[0]))
+ if (escape
+ && (ptr_string[0] == '\\')
+ && ((ptr_string[1] == eval_context->prefix[0])
+ || ((length_suffix2 > 0) && ptr_string[1] == extra_prefix[0])))
{
ptr_string++;
}
- else if (strncmp (ptr_string, prefix, length_prefix) == 0)
+ else if (strncmp (ptr_string, eval_context->prefix, length_prefix) == 0)
{
level++;
ptr_string += length_prefix;
}
- else if (strncmp (ptr_string, suffix, length_suffix) == 0)
+ else if ((length_prefix2 > 0)
+ && (strncmp (ptr_string, extra_prefix, length_prefix2) == 0))
+ {
+ level++;
+ ptr_string += length_prefix2;
+ }
+ else if (strncmp (ptr_string, eval_context->suffix, length_suffix) == 0)
{
if (level > 0)
level--;
ptr_string += length_suffix;
}
+ else if ((length_suffix2 > 0)
+ && (strncmp (ptr_string, extra_suffix, length_suffix2) == 0))
+ {
+ if (level > 0)
+ level--;
+ ptr_string += length_suffix2;
+ }
else if ((level == 0)
&& (strncmp (ptr_string, search, length_search) == 0))
{
@@ -643,17 +670,11 @@ eval_replace_vars_cb (void *data, const char *text)
if (strncmp (text, "if:", 3) == 0)
{
value = NULL;
- pos = (char *)eval_strstr_level (text + 3,
- "?",
- eval_context->prefix,
- eval_context->suffix,
- 1);
+ pos = (char *)eval_strstr_level (text + 3, "?",
+ eval_context, NULL, NULL, 1);
pos2 = (pos) ?
- (char *)eval_strstr_level (pos + 1,
- ":",
- eval_context->prefix,
- eval_context->suffix,
- 1) : NULL;
+ (char *)eval_strstr_level (pos + 1, ":",
+ eval_context, NULL, NULL, 1) : NULL;
condition = (pos) ?
strndup (text + 3, pos - (text + 3)) : strdup (text + 3);
if (!condition)
@@ -1037,7 +1058,8 @@ eval_expression_condition (const char *expr,
*/
for (logic = 0; logic < EVAL_NUM_LOGICAL_OPS; logic++)
{
- pos = eval_strstr_level (expr2, logical_ops[logic], "(", ")", 0);
+ pos = eval_strstr_level (expr2, logical_ops[logic], eval_context,
+ "(", ")", 0);
if (pos > expr2)
{
pos_end = pos - 1;
@@ -1086,7 +1108,8 @@ eval_expression_condition (const char *expr,
*/
for (comp = 0; comp < EVAL_NUM_COMPARISONS; comp++)
{
- pos = eval_strstr_level (expr2, comparisons[comp], "(", ")", 0);
+ pos = eval_strstr_level (expr2, comparisons[comp], eval_context,
+ "(", ")", 0);
if (pos >= expr2)
{
if (pos > expr2)
diff --git a/tests/unit/core/test-core-eval.cpp b/tests/unit/core/test-core-eval.cpp
index 0bb69701c..dcfb039c9 100644
--- a/tests/unit/core/test-core-eval.cpp
+++ b/tests/unit/core/test-core-eval.cpp
@@ -147,6 +147,9 @@ TEST(CoreEval, EvalCondition)
WEE_CHECK_EVAL("0", "${window.buffer.number} == 2");
WEE_CHECK_EVAL("0", "${calc:2+3} < 5");
WEE_CHECK_EVAL("0", "${calc:1.5*3} < 4.5");
+ WEE_CHECK_EVAL("0", "${if:${buffer.number}==2?yes:}");
+ WEE_CHECK_EVAL("0", "${if:${buffer.number}==2?yes:no} == yes");
+ WEE_CHECK_EVAL("0", "yes == ${if:${buffer.number}==2?yes:no}");
/* conditions evaluated as true */
WEE_CHECK_EVAL("1", "1");
@@ -207,6 +210,9 @@ TEST(CoreEval, EvalCondition)
WEE_CHECK_EVAL("1", "${window.buffer.number} == 1");
WEE_CHECK_EVAL("1", "${calc:2+3} >= 5");
WEE_CHECK_EVAL("1", "${calc:1.5*3} >= 4.5");
+ WEE_CHECK_EVAL("1", "${if:${buffer.number}==1?yes:}");
+ WEE_CHECK_EVAL("1", "${if:${buffer.number}==1?yes:no} == yes");
+ WEE_CHECK_EVAL("1", "yes == ${if:${buffer.number}==1?yes:no}");
/* evaluation of extra_vars */
hashtable_set (options, "extra", "eval");