summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSébastien Helleu <flashcode@flashtux.org>2017-03-04 19:41:23 +0100
committerSébastien Helleu <flashcode@flashtux.org>2017-03-25 14:18:19 +0100
commit83117f8d2a823b229b96a93d3591704a045eb502 (patch)
treeea00f29e5fdb3b1f2eb5e17792127d69821ddb3e /src
parent07d16903f3c4f8be84e777a2067085f305e8d2f0 (diff)
downloadweechat-83117f8d2a823b229b96a93d3591704a045eb502.zip
core: add ternary operator (condition) in evaluation of expressions
Diffstat (limited to 'src')
-rw-r--r--src/core/wee-command.c29
-rw-r--r--src/core/wee-eval.c197
-rw-r--r--src/core/wee-string.c48
-rw-r--r--src/core/wee-string.h1
4 files changed, 198 insertions, 77 deletions
diff --git a/src/core/wee-command.c b/src/core/wee-command.c
index be8e0f759..a6f03f3c0 100644
--- a/src/core/wee-command.c
+++ b/src/core/wee-command.c
@@ -7273,9 +7273,11 @@ command_init ()
"optional)\n"
" 6. current date/time (format: \"date\" or \"date:format\")\n"
" 7. an environment variable (format: \"env:XXX\")\n"
- " 8. an option (format: \"file.section.option\")\n"
- " 9. a local variable in buffer\n"
- " 10. a hdata name/variable (the value is automatically converted "
+ " 8. a ternary operator (format: "
+ "if:condition?value_if_true:value_if_false)\n"
+ " 9. an option (format: \"file.section.option\")\n"
+ " 10. a local variable in buffer\n"
+ " 11. a hdata name/variable (the value is automatically converted "
"to string), by default \"window\" and \"buffer\" point to current "
"window/buffer.\n"
"Format for hdata can be one of following:\n"
@@ -7295,16 +7297,17 @@ command_init ()
"reference\", function \"weechat_hdata_get\".\n"
"\n"
"Examples (simple strings):\n"
- " /eval -n ${info:version} ==> 0.4.3\n"
- " /eval -n ${env:HOME} ==> /home/user\n"
- " /eval -n ${weechat.look.scroll_amount} ==> 3\n"
- " /eval -n ${window} ==> 0x2549aa0\n"
- " /eval -n ${window.buffer} ==> 0x2549320\n"
- " /eval -n ${window.buffer.full_name} ==> core.weechat\n"
- " /eval -n ${window.buffer.number} ==> 1\n"
- " /eval -n ${\\t} ==> <tab>\n"
- " /eval -n ${hide:-,${relay.network.password}} ==> --------\n"
- " /eval -n ${date:%H:%M:%S} ==> 07:46:40\n"
+ " /eval -n ${info:version} ==> 0.4.3\n"
+ " /eval -n ${env:HOME} ==> /home/user\n"
+ " /eval -n ${weechat.look.scroll_amount} ==> 3\n"
+ " /eval -n ${window} ==> 0x2549aa0\n"
+ " /eval -n ${window.buffer} ==> 0x2549320\n"
+ " /eval -n ${window.buffer.full_name} ==> core.weechat\n"
+ " /eval -n ${window.buffer.number} ==> 1\n"
+ " /eval -n ${\\t} ==> <tab>\n"
+ " /eval -n ${hide:-,${relay.network.password}} ==> --------\n"
+ " /eval -n ${date:%H:%M:%S} ==> 07:46:40\n"
+ " /eval -n ${if:${info:term_width}>80?big:small} ==> big\n"
"\n"
"Examples (conditions):\n"
" /eval -n -c ${window.buffer.number} > 2 ==> 0\n"
diff --git a/src/core/wee-eval.c b/src/core/wee-eval.c
index 4a63b7ee4..eb332c8cd 100644
--- a/src/core/wee-eval.c
+++ b/src/core/wee-eval.c
@@ -49,10 +49,17 @@ char *logical_ops[EVAL_NUM_LOGICAL_OPS] =
char *comparisons[EVAL_NUM_COMPARISONS] =
{ "=~", "!~", "==", "!=", "<=", "<", ">=", ">" };
+
char *eval_replace_vars (const char *expr, struct t_hashtable *pointers,
struct t_hashtable *extra_vars, int extra_vars_eval,
const char *prefix, const char *suffix,
struct t_eval_regex *eval_regex);
+char *eval_expression_condition (const char *expr,
+ struct t_hashtable *pointers,
+ struct t_hashtable *extra_vars,
+ int extra_vars_eval,
+ const char *prefix,
+ const char *suffix);
/*
@@ -71,6 +78,66 @@ eval_is_true (const char *value)
}
/*
+ * Searches a string in another at same level (skip sub-expressions between
+ * prefix/suffix).
+ *
+ * If escape is 1, the prefix can be escaped with '\' (and then is ignored).
+ *
+ * For example: eval_strstr_level ("(x || y) || z", "||")
+ * will return a pointer on "|| z" (because the first "||" is
+ * in a sub-expression, which is skipped).
+ *
+ * Returns pointer to string found, or NULL if not found.
+ */
+
+const char *
+eval_strstr_level (const char *string, const char *search,
+ const char *prefix, const char *suffix, int escape)
+{
+ const char *ptr_string;
+ int level, length_search, length_prefix, length_suffix;
+
+ if (!string || !search)
+ return NULL;
+
+ length_search = strlen (search);
+ length_prefix = strlen (prefix);
+ length_suffix = strlen (suffix);
+
+ ptr_string = string;
+ level = 0;
+ while (ptr_string[0])
+ {
+ if (escape && (ptr_string[0] == '\\') && (ptr_string[1] == prefix[0]))
+ {
+ ptr_string++;
+ }
+ else if (strncmp (ptr_string, prefix, length_prefix) == 0)
+ {
+ level++;
+ ptr_string += length_prefix;
+ }
+ else if (strncmp (ptr_string, suffix, length_suffix) == 0)
+ {
+ if (level > 0)
+ level--;
+ ptr_string += length_suffix;
+ }
+ else if ((level == 0)
+ && (strncmp (ptr_string, search, length_search) == 0))
+ {
+ return ptr_string;
+ }
+ else
+ {
+ ptr_string++;
+ }
+ }
+
+ return NULL;
+}
+
+/*
* Gets value of hdata using "path" to a variable.
*
* Note: result must be freed after use.
@@ -233,9 +300,10 @@ end:
* 7. an info (format: info:name,arguments)
* 8. current date/time (format: date or date:xxx)
* 9. an environment variable (format: env:XXX)
- * 10. an option (format: file.section.option)
- * 11. a buffer local variable
- * 12. a hdata variable (format: hdata.var1.var2 or hdata[list].var1.var2
+ * 10. a ternary operator (format: if:condition?value_if_true:value_if_false)
+ * 11. an option (format: file.section.option)
+ * 12. a buffer local variable
+ * 13. a hdata variable (format: hdata.var1.var2 or hdata[list].var1.var2
* or hdata[ptr].var1.var2)
*
* See /help in WeeChat for examples.
@@ -251,7 +319,7 @@ eval_replace_vars_cb (void *data, const char *text)
struct t_config_option *ptr_option;
struct t_gui_buffer *ptr_buffer;
char str_value[512], *value, *pos, *pos1, *pos2, *hdata_name, *list_name;
- char *tmp, *info_name, *hide_char, *hidden_string, *error;
+ char *tmp, *info_name, *hide_char, *hidden_string, *error, *condition;
const char *prefix, *suffix, *ptr_value, *ptr_arguments, *ptr_string;
struct t_hdata *hdata;
void *pointer;
@@ -410,7 +478,71 @@ eval_replace_vars_cb (void *data, const char *text)
return strdup (ptr_value);
}
- /* 10. option: if found, return this value */
+ /* 10: ternary operator: if:condition?value_if_true:value_if_false */
+ if (strncmp (text, "if:", 3) == 0)
+ {
+ value = NULL;
+ pos = (char *)eval_strstr_level (text + 3, "?", prefix, suffix, 1);
+ pos2 = (pos) ?
+ (char *)eval_strstr_level (pos + 1, ":", prefix, suffix, 1) : NULL;
+ condition = (pos) ?
+ strndup (text + 3, pos - (text + 3)) : strdup (text + 3);
+ if (!condition)
+ return strdup ("");
+ tmp = eval_expression_condition (condition, pointers,
+ extra_vars, extra_vars_eval,
+ prefix, suffix);
+ rc = (tmp && strcmp (tmp, "1") == 0);
+ if (tmp)
+ free (tmp);
+ if (rc)
+ {
+ /*
+ * condition is true: return the "value_if_true"
+ * (or EVAL_STR_TRUE if value is missing)
+ */
+ if (pos)
+ {
+ tmp = (pos2) ?
+ strndup (pos + 1, pos2 - pos - 1) : strdup (pos + 1);
+ if (tmp)
+ {
+ value = eval_replace_vars (tmp, pointers,
+ extra_vars, extra_vars_eval,
+ prefix, suffix,
+ eval_regex);
+ free (tmp);
+ }
+ }
+ else
+ {
+ value = strdup (EVAL_STR_TRUE);
+ }
+ }
+ else
+ {
+ /*
+ * condition is false: return the "value_if_false"
+ * (or EVAL_STR_FALSE if both values are missing)
+ */
+ if (pos2)
+ {
+ value = eval_replace_vars (pos2 + 1, pointers,
+ extra_vars, extra_vars_eval,
+ prefix, suffix,
+ eval_regex);
+ }
+ else
+ {
+ if (!pos)
+ value = strdup (EVAL_STR_FALSE);
+ }
+ }
+ free (condition);
+ return (value) ? value : strdup ("");
+ }
+
+ /* 11. option: if found, return this value */
if (strncmp (text, "sec.data.", 9) == 0)
{
ptr_value = hashtable_get (secure_hashtable_data, text + 9);
@@ -443,7 +575,7 @@ eval_replace_vars_cb (void *data, const char *text)
}
}
- /* 11. local variable in buffer */
+ /* 12. local variable in buffer */
ptr_buffer = hashtable_get (pointers, "buffer");
if (ptr_buffer)
{
@@ -452,7 +584,7 @@ eval_replace_vars_cb (void *data, const char *text)
return strdup (ptr_value);
}
- /* 12. hdata */
+ /* 13. hdata */
value = NULL;
hdata_name = NULL;
list_name = NULL;
@@ -536,6 +668,7 @@ eval_replace_vars (const char *expr, struct t_hashtable *pointers,
struct t_eval_regex *eval_regex)
{
const void *ptr[6];
+ const char *no_replace_prefix_list[] = { "if:", NULL };
ptr[0] = pointers;
ptr[1] = extra_vars;
@@ -545,6 +678,7 @@ eval_replace_vars (const char *expr, struct t_hashtable *pointers,
ptr[5] = eval_regex;
return string_replace_with_callback (expr, prefix, suffix,
+ no_replace_prefix_list,
&eval_replace_vars_cb, ptr, NULL);
}
@@ -651,51 +785,6 @@ end:
}
/*
- * Searches a string in another at same level (skip sub-expressions between
- * parentheses).
- *
- * For example: eval_strstr_level ("(x || y) || z", "||")
- * will return a pointer on "|| z" (because the first "||" is
- * in a sub-expression, which is skipped).
- *
- * Returns pointer to string found, or NULL if not found.
- */
-
-const char *
-eval_strstr_level (const char *string, const char *search)
-{
- const char *ptr_string;
- int level, length;
-
- if (!string || !search)
- return NULL;
-
- length = strlen (search);
-
- ptr_string = string;
- level = 0;
- while (ptr_string[0])
- {
- if (ptr_string[0] == '(')
- {
- level++;
- }
- else if (ptr_string[0] == ')')
- {
- if (level > 0)
- level--;
- }
-
- if ((level == 0) && (strncmp (ptr_string, search, length) == 0))
- return ptr_string;
-
- ptr_string++;
- }
-
- return NULL;
-}
-
-/*
* Evaluates a condition (this function must not be called directly).
*
* For return value, see function eval_expression().
@@ -751,7 +840,7 @@ eval_expression_condition (const char *expr,
*/
for (logic = 0; logic < EVAL_NUM_LOGICAL_OPS; logic++)
{
- pos = eval_strstr_level (expr2, logical_ops[logic]);
+ pos = eval_strstr_level (expr2, logical_ops[logic], "(", ")", 0);
if (pos > expr2)
{
pos_end = pos - 1;
@@ -804,7 +893,7 @@ eval_expression_condition (const char *expr,
*/
for (comp = 0; comp < EVAL_NUM_COMPARISONS; comp++)
{
- pos = eval_strstr_level (expr2, comparisons[comp]);
+ pos = eval_strstr_level (expr2, comparisons[comp], "(", ")", 0);
if (pos > expr2)
{
pos_end = pos - 1;
diff --git a/src/core/wee-string.c b/src/core/wee-string.c
index 2c4711b09..cd21a94c7 100644
--- a/src/core/wee-string.c
+++ b/src/core/wee-string.c
@@ -2910,6 +2910,12 @@ string_input_for_buffer (const char *string)
*
* Nested variables are supported, for example: "${var1:${var2}}".
*
+ * Argument "list_prefix_no_replace" is a list to prevent replacements in
+ * string if beginning with one of the prefixes. For example if the list is
+ * { "if:", NULL } and string is: "${if:cond?true:false}${test${abc}}"
+ * then the "if:cond?true:false" is NOT replaced (via a recursive call) but
+ * "test${abc}" will be replaced.
+ *
* Argument "errors" (if not NULL) is set with number of keys not found by
* callback.
*
@@ -2920,12 +2926,13 @@ char *
string_replace_with_callback (const char *string,
const char *prefix,
const char *suffix,
+ const char **list_prefix_no_replace,
char *(*callback)(void *data, const char *text),
void *callback_data,
int *errors)
{
int length_prefix, length_suffix, length, length_value, index_string;
- int index_result, sub_count, sub_level, sub_errors;
+ int index_result, sub_count, sub_level, sub_errors, replace, i;
char *result, *result2, *key, *key2, *value;
const char *pos_end_name;
@@ -2991,15 +2998,36 @@ string_replace_with_callback (const char *string,
{
if (sub_count > 0)
{
- sub_errors = 0;
- key2 = string_replace_with_callback (key, prefix,
- suffix, callback,
- callback_data,
- &sub_errors);
- if (errors)
- (*errors) += sub_errors;
- free (key);
- key = key2;
+ replace = 1;
+ if (list_prefix_no_replace)
+ {
+ for (i = 0; list_prefix_no_replace[i]; i++)
+ {
+ if (strncmp (
+ key, list_prefix_no_replace[i],
+ strlen (list_prefix_no_replace[i])) == 0)
+ {
+ replace = 0;
+ break;
+ }
+ }
+ }
+ if (replace)
+ {
+ sub_errors = 0;
+ key2 = string_replace_with_callback (
+ key,
+ prefix,
+ suffix,
+ list_prefix_no_replace,
+ callback,
+ callback_data,
+ &sub_errors);
+ if (errors)
+ (*errors) += sub_errors;
+ free (key);
+ key = key2;
+ }
}
value = (*callback) (callback_data, (key) ? key : "");
if (value)
diff --git a/src/core/wee-string.h b/src/core/wee-string.h
index bfed81411..c3d6b933e 100644
--- a/src/core/wee-string.h
+++ b/src/core/wee-string.h
@@ -110,6 +110,7 @@ extern const char *string_input_for_buffer (const char *string);
extern char *string_replace_with_callback (const char *string,
const char *prefix,
const char *suffix,
+ const char **list_prefix_no_replace,
char *(*callback)(void *data, const char *text),
void *callback_data,
int *errors);