diff options
Diffstat (limited to 'src')
34 files changed, 1576 insertions, 203 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f5afb1803..984c5be15 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -27,6 +27,7 @@ wee-completion.c wee-completion.h wee-config.c wee-config.h wee-config-file.c wee-config-file.h wee-debug.c wee-debug.h +wee-eval.c wee-eval.h wee-hashtable.c wee-hashtable.h wee-hdata.c wee-hdata.h wee-hook.c wee-hook.h diff --git a/src/core/Makefile.am b/src/core/Makefile.am index ae69f3ec0..6abf84b99 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -35,6 +35,8 @@ lib_weechat_core_a_SOURCES = weechat.c \ wee-config-file.h \ wee-debug.c \ wee-debug.h \ + wee-eval.c \ + wee-eval.h \ wee-hashtable.c \ wee-hashtable.h \ wee-hdata.c \ diff --git a/src/core/wee-command.c b/src/core/wee-command.c index 99e26d7a4..c0fce2c86 100644 --- a/src/core/wee-command.c +++ b/src/core/wee-command.c @@ -39,6 +39,7 @@ #include "wee-config.h" #include "wee-config-file.h" #include "wee-debug.h" +#include "wee-eval.h" #include "wee-hashtable.h" #include "wee-hdata.h" #include "wee-hook.h" @@ -1444,6 +1445,73 @@ COMMAND_CALLBACK(debug) } /* + * command_eval: evaluate expression and send result to buffer + */ + +COMMAND_CALLBACK(eval) +{ + int print_only; + char *result, *ptr_args; + + /* make C compiler happy */ + (void) buffer; + (void) data; + (void) argv; + + print_only = 0; + + if (argc < 2) + return WEECHAT_RC_OK; + + ptr_args = argv_eol[1]; + if (string_strcasecmp (argv[1], "-n") == 0) + { + print_only = 1; + ptr_args = argv_eol[2]; + } + + if (ptr_args) + { + result = eval_expression (ptr_args, NULL, NULL); + if (print_only) + { + gui_chat_printf_date_tags (NULL, 0, "no_log", ">> %s", ptr_args); + if (result) + { + gui_chat_printf_date_tags (NULL, 0, "no_log", "== %s[%s%s%s]", + GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS), + GUI_COLOR(GUI_COLOR_CHAT), + result, + GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS)); + } + else + { + gui_chat_printf_date_tags (NULL, 0, "no_log", "== %s<%s%s%s>", + GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS), + GUI_COLOR(GUI_COLOR_CHAT), + _("error"), + GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS)); + } + } + else + { + if (result) + input_data (buffer, result); + else + { + gui_chat_printf (NULL, + _("%sError in expression to evaluate"), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]); + } + } + if (result) + free (result); + } + + return WEECHAT_RC_OK; +} + +/* * command_filter_display: display one filter */ @@ -5438,8 +5506,8 @@ command_init () hook_command (NULL, "bar", N_("manage bars"), N_("list|listfull|listitems" - " || add <name> <type>[,<cond1>[,<cond2>...]] <position> " - "<size> <separator> <item1>[,<item2>...]" + " || add <name> <type>[,<condition>] <position> <size> " + "<separator> <item1>[,<item2>...]" " || default [input|title|status|nicklist]" " || del <name>|-all" " || set <name> <option> <value>" @@ -5453,12 +5521,15 @@ command_init () " type: root: outside windows,\n" " window: inside windows, with optional " "conditions (see below)\n" - " cond1,...: condition(s) for displaying bar (only for " + " condition: condition(s) for displaying bar (only for " "type \"window\"):\n" " active: on active window\n" " inactive: on inactive windows\n" " nicklist: on windows with nicklist\n" - " without condition, bar is always displayed\n" + " other condition: see /help " + "weechat.bar.xxx.conditions and /help eval\n" + " without condition, the bar is always " + "displayed\n" " position: bottom, top, left or right\n" " size: size of bar (in chars)\n" " separator: 1 for using separator (line), 0 or nothing " @@ -5683,6 +5754,69 @@ command_init () " || term" " || windows", &command_debug, NULL); + hook_command (NULL, "eval", + N_("evaluate expression and send result to buffer"), + N_("[-n] <expression>" + " || [-n] <expression1> <operator> <expression2>"), + N_(" -n: display result without sending it to buffer " + "(debug mode)\n" + "expression: expression to evaluate, variables with format " + "${variable} are replaced (see below)\n" + " operator: a logical or comparison operator:\n" + " - logical operators:\n" + " && boolean \"and\"\n" + " || boolean \"or\"\n" + " - comparison operators:\n" + " == equal\n" + " != not equal\n" + " <= less or equal\n" + " < less\n" + " >= greater or equal\n" + " > greater\n" + " =~ is matching regex\n" + " !~ is NOT matching regex\n\n" + "An expression is considered as \"true\" if it is not NULL, " + "not empty, and different from \"0\".\n" + "The comparison is made using integers if the two " + "expressions are valid integers.\n" + "To force a string comparison, add double quotes around " + "each expression, for example:\n" + " 50 > 100 ==> 0\n" + " \"50\" > \"100\" ==> 1\n\n" + "Some variables are replaced in expression, using the " + "format ${variable}, variable can be, by order of prioity :\n" + " 1. the name of an option (file.section.option)\n" + " 2. 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" + " hdata.var1.var2...: start with a hdata (pointer must be " + "known), and ask variables one after one (other hdata can " + "be followed)\n" + " hdata(list).var1.var2...: start with a hdata using a " + "list, for example:\n" + " ${buffer[gui_buffers].full_name}: full name of first " + "buffer in linked list of buffers\n" + " ${plugin[weechat_plugins].name}: name of first plugin " + "in linked list of plugins\n" + "For name of hdata and variables, please look at \"Plugin " + "API reference\", function \"weechat_hdata_get\".\n\n" + "Examples:\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 ${window.buffer.number} > 2 ==> 0\n" + " /eval -n ${window.win_width} > 100 ==> 1\n" + " /eval -n (8 > 12) || (5 > 2) ==> 1\n" + " /eval -n (8 > 12) && (5 > 2) ==> 0\n" + " /eval -n abcd =~ ^ABC ==> 1\n" + " /eval -n abcd =~ (?-i)^ABC ==> 0\n" + " /eval -n abcd =~ (?-i)^abc ==> 1\n" + " /eval -n abcd !~ abc ==> 0"), + "-n", + &command_eval, NULL); hook_command (NULL, "filter", N_("filter messages in buffers, to hide/show them according " "to tags or regex"), diff --git a/src/core/wee-config.c b/src/core/wee-config.c index 7070fe75f..390a75ba6 100644 --- a/src/core/wee-config.c +++ b/src/core/wee-config.c @@ -1163,6 +1163,16 @@ config_weechat_proxy_read_cb (void *data, struct t_config_file *config_file, proxy_create_option_temp (ptr_temp_proxy, index_option, value); } + else + { + gui_chat_printf (NULL, + _("%sWarning: unknown option for " + "section \"%s\": %s (value: \"%s\")"), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], + section->name, + option_name, + value); + } } free (proxy_name); @@ -1232,6 +1242,16 @@ config_weechat_bar_read_cb (void *data, struct t_config_file *config_file, gui_bar_create_option_temp (ptr_temp_bar, index_option, value); } + else + { + gui_chat_printf (NULL, + _("%sWarning: unknown option for " + "section \"%s\": %s (value: \"%s\")"), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], + section->name, + option_name, + value); + } } free (bar_name); diff --git a/src/core/wee-eval.c b/src/core/wee-eval.c new file mode 100644 index 000000000..45b2e1f01 --- /dev/null +++ b/src/core/wee-eval.c @@ -0,0 +1,717 @@ +/* + * Copyright (C) 2012 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * wee-eval.c: evaluate expressions with references to internal vars + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> +#include <regex.h> + +#include "weechat.h" +#include "wee-eval.h" +#include "wee-config-file.h" +#include "wee-hashtable.h" +#include "wee-hdata.h" +#include "wee-hook.h" +#include "wee-string.h" +#include "../gui/gui-color.h" +#include "../gui/gui-window.h" +#include "../plugins/plugin.h" + + +char *logical_ops[EVAL_NUM_LOGICAL_OPS] = { "&&", "||" }; +char *comparisons[EVAL_NUM_COMPARISONS] = { "==", "!=", "<=", "<", ">=", ">", + "=~", "!~" }; + + +/* + * eval_is_true: return 1 if value is true, 0 otherwise + * A value is true if string is non-NULL, non-empty and different + * from "0". + */ + +int +eval_is_true (const char *value) +{ + return (value && value[0] && (strcmp (value, "0") != 0)) ? 1 : 0; +} + +/* + * eval_hdata_get_value: get value of hdata using "path" to a variable + * Note: result must be freed after use + */ + +char * +eval_hdata_get_value (struct t_hdata *hdata, void *pointer, const char *path) +{ + char *value, *old_value, *var_name, str_value[128], *pos; + const char *ptr_value, *hdata_name; + int type; + struct t_hashtable *hashtable; + + value = NULL; + var_name = NULL; + + /* NULL pointer? return empty string */ + if (!pointer) + return strdup (""); + + /* no path? just return current pointer as string */ + if (!path || !path[0]) + { + snprintf (str_value, sizeof (str_value), + "0x%lx", (long unsigned int)pointer); + return strdup (str_value); + } + + /* + * look for name of hdata, for example in "window.buffer.full_name", the + * hdata name is "window" + */ + pos = strchr (path, '.'); + if (pos > path) + var_name = string_strndup (path, pos - path); + else + var_name = strdup (path); + + if (!var_name) + goto end; + + /* search type of variable in hdata */ + type = hdata_get_var_type (hdata, var_name); + if (type < 0) + goto end; + + /* build a string with the value or variable */ + switch (type) + { + case WEECHAT_HDATA_CHAR: + snprintf (str_value, sizeof (str_value), + "%c", hdata_char (hdata, pointer, var_name)); + value = strdup (str_value); + break; + case WEECHAT_HDATA_INTEGER: + snprintf (str_value, sizeof (str_value), + "%d", hdata_integer (hdata, pointer, var_name)); + value = strdup (str_value); + break; + case WEECHAT_HDATA_LONG: + snprintf (str_value, sizeof (str_value), + "%ld", hdata_long (hdata, pointer, var_name)); + value = strdup (str_value); + break; + case WEECHAT_HDATA_STRING: + value = strdup (hdata_string (hdata, pointer, var_name)); + break; + case WEECHAT_HDATA_POINTER: + pointer = hdata_pointer (hdata, pointer, var_name); + snprintf (str_value, sizeof (str_value), + "0x%lx", (long unsigned int)pointer); + value = strdup (str_value); + break; + case WEECHAT_HDATA_TIME: + snprintf (str_value, sizeof (str_value), + "%ld", hdata_time (hdata, pointer, var_name)); + value = strdup (str_value); + break; + case WEECHAT_HDATA_HASHTABLE: + pointer = hdata_hashtable (hdata, pointer, var_name); + if (pos) + { + /* + * for a hashtable, if there is a "." after name of hdata, + * get the value for this key in hashtable + */ + hashtable = pointer; + ptr_value = hashtable_get (hashtable, pos + 1); + if (ptr_value) + { + switch (hashtable->type_values) + { + case HASHTABLE_INTEGER: + snprintf (str_value, sizeof (str_value), + "%d", *((int *)ptr_value)); + value = strdup (str_value); + break; + case HASHTABLE_STRING: + value = strdup (ptr_value); + break; + case HASHTABLE_POINTER: + case HASHTABLE_BUFFER: + snprintf (str_value, sizeof (str_value), + "0x%lx", (long unsigned int)ptr_value); + value = strdup (str_value); + break; + case HASHTABLE_TIME: + snprintf (str_value, sizeof (str_value), + "%ld", *((time_t *)ptr_value)); + value = strdup (str_value); + break; + case HASHTABLE_NUM_TYPES: + break; + } + } + } + else + { + snprintf (str_value, sizeof (str_value), + "0x%lx", (long unsigned int)pointer); + value = strdup (str_value); + } + break; + } + + /* + * if we are on a pointer and that something else is in path (after "."), + * go on with this pointer and remaining path + */ + if ((type == WEECHAT_HDATA_POINTER) && pos) + { + hdata_name = hdata_get_var_hdata (hdata, var_name); + if (!hdata_name) + goto end; + + hdata = hook_hdata_get (NULL, hdata_name); + old_value = value; + value = eval_hdata_get_value (hdata, pointer, (pos) ? pos + 1 : NULL); + if (old_value) + free (old_value); + } + +end: + if (var_name) + free (var_name); + + return value; +} + +/* + * eval_replace_vars_cb: callback to replace variables, which can be, + * by order of priority: + * 1. an extra variable (from hashtable "extra_vars") + * 2. an name of option (file.section.option) + * 3. a hdata name/variable + * Examples: + * option: ${weechat.look.scroll_amount} + * hdata : ${window.buffer.full_name} + * ${window.buffer.local_variables.type} + */ + +char * +eval_replace_vars_cb (void *data, const char *text) +{ + struct t_hashtable *pointers, *extra_vars; + struct t_config_option *ptr_option; + char str_value[64], *value, *pos, *pos1, *pos2, *hdata_name, *list_name; + char *tmp; + const char *ptr_value; + struct t_hdata *hdata; + void *pointer; + + pointers = (struct t_hashtable *)(((void **)data)[0]); + extra_vars = (struct t_hashtable *)(((void **)data)[1]); + + /* first look for var in hashtable "extra_vars" */ + ptr_value = hashtable_get (extra_vars, text); + if (ptr_value) + return strdup (ptr_value); + + /* look for name of option: if found, return this value */ + config_file_search_with_string (text, NULL, NULL, &ptr_option, NULL); + if (ptr_option) + { + switch (ptr_option->type) + { + case CONFIG_OPTION_TYPE_BOOLEAN: + return strdup (CONFIG_BOOLEAN(ptr_option) ? EVAL_STR_TRUE : EVAL_STR_FALSE); + case CONFIG_OPTION_TYPE_INTEGER: + if (ptr_option->string_values) + return strdup (ptr_option->string_values[CONFIG_INTEGER(ptr_option)]); + snprintf (str_value, sizeof (str_value), + "%d", CONFIG_INTEGER(ptr_option)); + return strdup (str_value); + case CONFIG_OPTION_TYPE_STRING: + return strdup (CONFIG_STRING(ptr_option)); + case CONFIG_OPTION_TYPE_COLOR: + return strdup (gui_color_get_name (CONFIG_COLOR(ptr_option))); + case CONFIG_NUM_OPTION_TYPES: + return NULL; + } + } + + /* look for hdata */ + value = NULL; + hdata_name = NULL; + list_name = NULL; + pointer = NULL; + + pos = strchr (text, '.'); + if (pos > text) + hdata_name = string_strndup (text, pos - text); + else + hdata_name = strdup (text); + + if (!hdata_name) + goto end; + + pos1 = strchr (hdata_name, '['); + if (pos1 > hdata_name) + { + pos2 = strchr (pos1 + 1, ']'); + if (pos2 > pos1 + 1) + { + list_name = string_strndup (pos1 + 1, pos2 - pos1 - 1); + } + tmp = string_strndup (hdata_name, pos1 - hdata_name); + if (tmp) + { + free (hdata_name); + hdata_name = tmp; + } + } + + hdata = hook_hdata_get (NULL, hdata_name); + if (!hdata) + goto end; + + if (list_name) + pointer = hdata_get_list (hdata, list_name); + if (!pointer) + { + pointer = hashtable_get (pointers, hdata_name); + if (!pointer) + goto end; + } + + value = eval_hdata_get_value (hdata, pointer, (pos) ? pos + 1 : NULL); + +end: + if (hdata_name) + free (hdata_name); + if (list_name) + free (list_name); + + return (value) ? value : strdup (""); +} + +/* + * eval_replace_vars: replace variables in a string + */ + +char * +eval_replace_vars (const char *expr, struct t_hashtable *pointers, + struct t_hashtable *extra_vars) +{ + int errors; + void *ptr[2]; + + ptr[0] = pointers; + ptr[1] = extra_vars; + + return string_replace_with_callback (expr, + &eval_replace_vars_cb, + ptr, + &errors); +} + +/* + * eval_compare: compate two expressions + */ + +char * +eval_compare (const char *expr1, int comparison, const char *expr2) +{ + int rc, string_compare, length1, length2; + regex_t regex; + long value1, value2; + char *error; + + rc = 0; + string_compare = 0; + + if (!expr1 || !expr2) + goto end; + + if ((comparison == EVAL_COMPARE_REGEX_MATCHING) + || (comparison == EVAL_COMPARE_REGEX_NOT_MATCHING)) + { + if (string_regcomp (®ex, expr2, + REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0) + { + goto end; + } + rc = (regexec (®ex, expr1, 0, NULL, 0) == 0) ? 1 : 0; + if (comparison == EVAL_COMPARE_REGEX_NOT_MATCHING) + rc ^= 1; + goto end; + } + + length1 = strlen (expr1); + length2 = strlen (expr2); + + /* + * string comparison is forced if expr1 and expr2 have double quotes at + * beginning/end + */ + if (((length1 == 0) || ((expr1[0] == '"') && expr1[length1 - 1] == '"')) + && ((length2 == 0) || ((expr2[0] == '"') && expr2[length2 - 1] == '"'))) + { + string_compare = 1; + } + + if (!string_compare) + { + value1 = strtol (expr1, &error, 10); + if (!error || error[0]) + string_compare = 1; + else + { + value2 = strtol (expr2, &error, 10); + if (!error || error[0]) + string_compare = 1; + } + } + + if (string_compare) + rc = strcmp (expr1, expr2); + else + rc = (value1 < value2) ? -1 : ((value1 > value2) ? 1 : 0); + + switch (comparison) + { + case EVAL_COMPARE_EQUAL: + rc = (rc == 0); + break; + case EVAL_COMPARE_NOT_EQUAL: + rc = (rc != 0); + break; + case EVAL_COMPARE_LESS_EQUAL: + rc = (rc <= 0); + break; + case EVAL_COMPARE_LESS: + rc = (rc < 0); + break; + case EVAL_COMPARE_GREATER_EQUAL: + rc = (rc >= 0); + break; + case EVAL_COMPARE_GREATER: + rc = (rc > 0); + break; + case EVAL_NUM_COMPARISONS: + break; + } + +end: + return strdup ((rc) ? EVAL_STR_TRUE : EVAL_STR_FALSE); +} + +/* + * eval_expression_internal: evaluate an expression and return a string with + * the result (see function eval_expression()) + * (should not be called directly) + * Argument keep_parentheses is almost always 0, + * it is 1 only if the expression is a regex (to keep + * flags inside the parentheses) + */ + +char * +eval_expression_internal (const char *expr, struct t_hashtable *pointers, + struct t_hashtable *extra_vars, + int keep_parentheses) +{ + int logic, comp, length, level, rc; + const char *pos_end; + char *expr2, *sub_expr, *pos, *value, *tmp_value, *tmp_value2; + + value = NULL; + + if (!expr) + return NULL; + + if (!expr[0]) + return strdup (expr); + + /* + * skip spaces at beginning of string + */ + while (expr[0] == ' ') + { + expr++; + } + if (!expr[0]) + return strdup (expr); + + /* skip spaces at end of string */ + pos_end = expr + strlen (expr) - 1; + while ((pos_end > expr) && (pos_end[0] == ' ')) + { + pos_end--; + } + + expr2 = string_strndup (expr, pos_end + 1 - expr); + if (!expr2) + return NULL; + + /* evaluate sub-expression in parentheses and replace it with value */ + if (!keep_parentheses) + { + while (expr2[0] == '(') + { + level = 0; + pos = expr2 + 1; + while (pos[0]) + { + if (pos[0] == '(') + level++; + else if (pos[0] == ')') + { + if (level == 0) + break; + level--; + } + pos++; + } + /* closing parenthese not found */ + if (pos[0] != ')') + goto end; + sub_expr = string_strndup (expr2 + 1, pos - expr2 - 1); + if (!sub_expr) + goto end; + tmp_value = eval_expression_internal (sub_expr, pointers, extra_vars, 0); + free (sub_expr); + if (!pos[1]) + { + /* nothing after ')', then return value of sub-expression as-is */ + value = tmp_value; + goto end; + } + length = ((tmp_value) ? strlen (tmp_value) : 0) + 1 + strlen (pos + 1) + 1; + tmp_value2 = malloc (length); + if (!tmp_value2) + goto end; + tmp_value2[0] = '\0'; + if (tmp_value) + strcat (tmp_value2, tmp_value); + strcat (tmp_value2, " "); + strcat (tmp_value2, pos + 1); + free (expr2); + expr2 = tmp_value2; + } + } + + /* + * search for a logical operator, and if one is found: + * - split expression into two sub-expressions + * - evaluate first sub-expression + * - if needed, evaluate second sub-expression + * - return result + */ + for (logic = 0; logic < EVAL_NUM_LOGICAL_OPS; logic++) + { + pos = strstr (expr2, logical_ops[logic]); + if (pos > expr2) + { + pos_end = pos - 1; + while ((pos_end > expr2) && (pos_end[0] == ' ')) + { + pos_end--; + } + sub_expr = string_strndup (expr2, pos_end + 1 - expr2); + if (!sub_expr) + goto end; + tmp_value = eval_expression_internal (sub_expr, pointers, extra_vars, 0); + free (sub_expr); + rc = eval_is_true (tmp_value); + /* + * if rc == 0 with "&&" or rc == 1 with "||", no need to evaluate + * second sub-expression, just return the rc + */ + if ((!rc && (logic == EVAL_LOGICAL_OP_AND)) + || (rc && (logic == EVAL_LOGICAL_OP_OR))) + { + if (tmp_value) + free (tmp_value); + value = strdup ((rc) ? EVAL_STR_TRUE : EVAL_STR_FALSE); + goto end; + } + pos += strlen (logical_ops[logic]); + while (pos[0] == ' ') + { + pos++; + } + tmp_value = eval_expression_internal (pos, pointers, extra_vars, 0); + rc = eval_is_true (tmp_value); + if (tmp_value) + free (tmp_value); + value = strdup ((rc) ? EVAL_STR_TRUE : EVAL_STR_FALSE); + goto end; + } + } + + /* + * search for a comparison, and if one is found: + * - split expression into two sub-expressions + * - evaluate the two sub-expressions + * - compare sub-expressions + * - return result + */ + for (comp = 0; comp < EVAL_NUM_COMPARISONS; comp++) + { + pos = strstr (expr2, comparisons[comp]); + if (pos > expr2) + { + pos_end = pos - 1; + while ((pos_end > expr2) && (pos_end[0] == ' ')) + { + pos_end--; + } + sub_expr = string_strndup (expr2, pos_end + 1 - expr2); + if (!sub_expr) + goto end; + tmp_value = eval_expression_internal (sub_expr, pointers, extra_vars, 0); + free (sub_expr); + pos += strlen (comparisons[comp]); + while (pos[0] == ' ') + { + pos++; + } + tmp_value2 = eval_expression_internal (pos, pointers, extra_vars, + ((comp == EVAL_COMPARE_REGEX_MATCHING) + || (comp == EVAL_COMPARE_REGEX_NOT_MATCHING)) ? 1 : 0); + value = eval_compare (tmp_value, comp, tmp_value2); + if (tmp_value) + free (tmp_value); + if (tmp_value2) + free (tmp_value2); + goto end; + } + } + + /* + * at this point, there is no more logical operator neither comparison, + * so we just replace variables in string and return the result + */ + value = eval_replace_vars (expr2, pointers, extra_vars); + +end: + if (expr2) + free (expr2); + + return value; +} + +/* + * eval_expression: evaluate an expression and return a string with the result + * The hashtable "pointers" must have string for keys, pointer + * for values. + * The hashtable "extra_vars" must have string for keys and + * values. + * The expression can contain: + * - conditions: == != < <= > >= + * - logical operators: && || + * - parentheses for priority + * Examples (the [ ] are NOT part of result): + * >> ${window.buffer.number} + * == [2] + * >> buffer:${window.buffer.full_name} + * == [buffer:irc.freenode.#weechat] + * >> ${window.buffer.full_name} == irc.freenode.#weechat + * == [1] + * >> ${window.buffer.full_name} == irc.freenode.#test + * == [0] + * >> ${window.win_width} + * == [112] + * >> ${window.win_height} + * == [40] + * >> ${window.win_width} >= 30 && ${window.win_height} >= 20 + * == [1] + * Note: result must be freed after use + */ + +char * +eval_expression (const char *expr, struct t_hashtable *pointers, + struct t_hashtable *extra_vars) +{ + int pointers_created, extra_vars_created; + char *value; + struct t_gui_window *window; + + if (!expr) + return NULL; + + pointers_created = 0; + extra_vars_created = 0; + + /* create hashtable pointers if it's NULL */ + if (!pointers) + { + pointers = hashtable_new (16, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_POINTER, + NULL, + NULL); + if (!pointers) + return NULL; + pointers_created = 1; + } + + /* + * set window/buffer with pointer to current window/buffer + * (if not already defined in the hashtable) + */ + if (gui_current_window) + { + if (!hashtable_has_key (pointers, "window")) + hashtable_set (pointers, "window", gui_current_window); + if (!hashtable_has_key (pointers, "buffer")) + { + window = (struct t_gui_window *)hashtable_get (pointers, "window"); + if (window) + hashtable_set (pointers, "buffer", window->buffer); + } + } + + /* create hashtable extra_vars if it's NULL */ + if (!extra_vars) + { + extra_vars = hashtable_new (16, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); + if (!extra_vars) + return NULL; + extra_vars_created = 1; + } + + value = eval_expression_internal (expr, pointers, extra_vars, 0); + + if (pointers_created) + hashtable_free (pointers); + if (extra_vars_created) + hashtable_free (extra_vars); + + return value; +} diff --git a/src/core/wee-eval.h b/src/core/wee-eval.h new file mode 100644 index 000000000..482de2e2e --- /dev/null +++ b/src/core/wee-eval.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __WEECHAT_EVAL_H +#define __WEECHAT_EVAL_H 1 + +#define EVAL_STR_FALSE "0" +#define EVAL_STR_TRUE "1" + +struct t_hashtable; + +enum t_eval_logical_op +{ + EVAL_LOGICAL_OP_AND = 0, + EVAL_LOGICAL_OP_OR, + /* number of comparison strings */ + EVAL_NUM_LOGICAL_OPS, +}; + +enum t_eval_comparison +{ + EVAL_COMPARE_EQUAL = 0, + EVAL_COMPARE_NOT_EQUAL, + EVAL_COMPARE_LESS_EQUAL, + EVAL_COMPARE_LESS, + EVAL_COMPARE_GREATER_EQUAL, + EVAL_COMPARE_GREATER, + EVAL_COMPARE_REGEX_MATCHING, + EVAL_COMPARE_REGEX_NOT_MATCHING, + /* number of comparison strings */ + EVAL_NUM_COMPARISONS, +}; + +extern int eval_is_true (const char *value); +extern char *eval_expression (const char *expr, + struct t_hashtable *pointers, + struct t_hashtable *extra_vars); + +#endif /* __WEECHAT_EVAL_H */ diff --git a/src/core/wee-string.c b/src/core/wee-string.c index 1d16d6d0f..269663cb8 100644 --- a/src/core/wee-string.c +++ b/src/core/wee-string.c @@ -49,7 +49,6 @@ #include "weechat.h" #include "wee-string.h" #include "wee-config.h" -#include "wee-hashtable.h" #include "wee-utf8.h" #include "../gui/gui-color.h" #include "../plugins/plugin.h" @@ -1774,28 +1773,29 @@ string_input_for_buffer (const char *string) } /* - * string_replace_with_hashtable: replace ${codes} with value from hashtable - * "errors" is set with number of keys not found - * in hashtable + * string_replace_with_callback: replace ${codes} using a callback that return + * replacement value (this value must be newly + * allocated because it will be freed in this + * function) + * "errors" is set with number of keys not found + * by callback */ char * -string_replace_with_hashtable (const char *string, - struct t_hashtable *hashtable, - int *errors) +string_replace_with_callback (const char *string, + char *(*callback)(void *data, const char *text), + void *callback_data, + int *errors) { int length, length_value, index_string, index_result; - char *result, *result2, *key; - const char *pos_end_name, *ptr_value; + char *result, *result2, *key, *value; + const char *pos_end_name; *errors = 0; if (!string) return NULL; - if (!hashtable) - return strdup (string); - length = strlen (string) + 1; result = malloc (length); if (result) @@ -1820,10 +1820,10 @@ string_replace_with_hashtable (const char *string, pos_end_name - (string + index_string + 2)); if (key) { - ptr_value = (const char *)hashtable_get (hashtable, key); - if (ptr_value) + value = (*callback) (callback_data, key); + if (value) { - length_value = strlen (ptr_value); + length_value = strlen (value); length += length_value; result2 = realloc (result, length); if (!result2) @@ -1831,13 +1831,15 @@ string_replace_with_hashtable (const char *string, if (result) free (result); free (key); + free (value); return NULL; } result = result2; - strcpy (result + index_result, ptr_value); + strcpy (result + index_result, value); index_result += length_value; index_string += pos_end_name - string - index_string + 1; + free (value); } else { diff --git a/src/core/wee-string.h b/src/core/wee-string.h index a000e65f3..a9fc76ea8 100644 --- a/src/core/wee-string.h +++ b/src/core/wee-string.h @@ -75,8 +75,9 @@ extern void string_encode_base64 (const char *from, int length, char *to); extern int string_decode_base64 (const char *from, char *to); extern int string_is_command_char (const char *string); extern const char *string_input_for_buffer (const char *string); -extern char *string_replace_with_hashtable (const char *string, - struct t_hashtable *hashtable, - int *errors); +extern char *string_replace_with_callback (const char *string, + char *(*callback)(void *data, const char *text), + void *callback_data, + int *errors); #endif /* __WEECHAT_STRING_H */ diff --git a/src/gui/gui-bar-item.c b/src/gui/gui-bar-item.c index fade60939..43d5dbb53 100644 --- a/src/gui/gui-bar-item.c +++ b/src/gui/gui-bar-item.c @@ -176,13 +176,52 @@ gui_bar_item_search_with_plugin (struct t_weechat_plugin *plugin, } /* - * gui_bar_item_used_in_a_bar: return 1 if an item is used in at least one bar - * if partial_name == 1, then search a bar that - * contains item beginning with "item_name" + * gui_bar_item_used_in_bar: return 1 if an item is used in the bar + * if partial_name == 1, then search if an item + * begins with "item_name" */ int -gui_bar_item_used_in_a_bar (const char *item_name, int partial_name) +gui_bar_item_used_in_bar (struct t_gui_bar *bar, const char *item_name, + int partial_name) +{ + int i, j, length; + + length = strlen (item_name); + + for (i = 0; i < bar->items_count; i++) + { + for (j = 0; j < bar->items_subcount[i]; j++) + { + if (bar->items_name[i][j]) + { + if ((partial_name + && strncmp (bar->items_name[i][j], + item_name, length) == 0) + || (!partial_name + && strcmp (bar->items_name[i][j], + item_name) == 0)) + { + return 1; + } + } + } + } + + /* item not used in the bar */ + return 0; +} + +/* + * gui_bar_item_used_in_at_least_one_bar: return 1 if an item is used in at + * least one bar + * if partial_name == 1, then search a + * bar that contains item beginning with + * "item_name" + */ + +int +gui_bar_item_used_in_at_least_one_bar (const char *item_name, int partial_name) { struct t_gui_bar *ptr_bar; int i, j, length; @@ -211,7 +250,7 @@ gui_bar_item_used_in_a_bar (const char *item_name, int partial_name) } } - /* item not used by any bar */ + /* item not used in any bar */ return 0; } diff --git a/src/gui/gui-bar-item.h b/src/gui/gui-bar-item.h index 2b7b92d6d..8e7ae338d 100644 --- a/src/gui/gui-bar-item.h +++ b/src/gui/gui-bar-item.h @@ -76,8 +76,11 @@ extern char *gui_bar_items_default_for_bars[][2]; extern int gui_bar_item_valid (struct t_gui_bar_item *bar_item); extern struct t_gui_bar_item *gui_bar_item_search (const char *name); -extern int gui_bar_item_used_in_a_bar (const char *item_name, - int partial_name); +extern int gui_bar_item_used_in_bar (struct t_gui_bar *bar, + const char *item_name, + int partial_name); +extern int gui_bar_item_used_in_at_least_one_bar (const char *item_name, + int partial_name); extern void gui_bar_item_set_prefix_name_suffix (const char *item_name, char **prefix, char **name, char **suffix); diff --git a/src/gui/gui-bar.c b/src/gui/gui-bar.c index 31ec7f677..eb2c4299c 100644 --- a/src/gui/gui-bar.c +++ b/src/gui/gui-bar.c @@ -32,6 +32,8 @@ #include "../core/weechat.h" #include "../core/wee-config.h" +#include "../core/wee-eval.h" +#include "../core/wee-hashtable.h" #include "../core/wee-hdata.h" #include "../core/wee-hook.h" #include "../core/wee-infolist.h" @@ -372,27 +374,64 @@ int gui_bar_check_conditions_for_window (struct t_gui_bar *bar, struct t_gui_window *window) { - int i, rc; - char str_modifier[256], str_window[128], *str_displayed; + int rc; + char str_modifier[256], str_window[128], *str_displayed, *result; + const char *conditions; + struct t_hashtable *pointers, *extra_vars; - /* check bar conditions */ - for (i = 0; i < bar->conditions_count; i++) + /* check bar condition(s) */ + conditions = CONFIG_STRING(bar->options[GUI_BAR_OPTION_CONDITIONS]); + if (string_strcasecmp (conditions, "active") == 0) { - if (string_strcasecmp (bar->conditions_array[i], "active") == 0) - { - if (gui_current_window && (gui_current_window != window)) - return 0; - } - else if (string_strcasecmp (bar->conditions_array[i], "inactive") == 0) + if (gui_current_window && (gui_current_window != window)) + return 0; + } + else if (string_strcasecmp (conditions, "inactive") == 0) + { + if (!gui_current_window || (gui_current_window == window)) + return 0; + } + else if (string_strcasecmp (conditions, "nicklist") == 0) + { + if (window->buffer && !window->buffer->nicklist) + return 0; + } + else if (conditions[0]) + { + pointers = hashtable_new (16, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_POINTER, + NULL, + NULL); + if (pointers) { - if (!gui_current_window || (gui_current_window == window)) - return 0; + hashtable_set (pointers, "window", window); + hashtable_set (pointers, "buffer", window->buffer); } - else if (string_strcasecmp (bar->conditions_array[i], "nicklist") == 0) + extra_vars = hashtable_new (16, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_POINTER, + NULL, + NULL); + if (extra_vars) { - if (window->buffer && !window->buffer->nicklist) - return 0; + hashtable_set (extra_vars, "active", + (gui_current_window && (gui_current_window == window)) ? "1" : "0"); + hashtable_set (extra_vars, "inactive", + (gui_current_window && (gui_current_window != window)) ? "1" : "0"); + hashtable_set (extra_vars, "nicklist", + (window->buffer && window->buffer->nicklist) ? "1" : "0"); } + result = eval_expression (conditions, pointers, extra_vars); + rc = eval_is_true (result); + if (result) + free (result); + if (pointers) + hashtable_free (pointers); + if (extra_vars) + hashtable_free (extra_vars); + if (!rc) + return 0; } /* @@ -413,6 +452,7 @@ gui_bar_check_conditions_for_window (struct t_gui_bar *bar, rc = 0; else rc = 1; + if (str_displayed) free (str_displayed); @@ -885,30 +925,9 @@ gui_bar_config_change_priority (void *data, struct t_config_option *option) void gui_bar_config_change_conditions (void *data, struct t_config_option *option) { - struct t_gui_bar *ptr_bar; - /* make C compiler happy */ (void) data; - - ptr_bar = gui_bar_search_with_option_name (option->name); - if (ptr_bar) - { - if (ptr_bar->conditions_array) - string_free_split (ptr_bar->conditions_array); - - if (CONFIG_STRING(ptr_bar->options[GUI_BAR_OPTION_CONDITIONS]) - && CONFIG_STRING(ptr_bar->options[GUI_BAR_OPTION_CONDITIONS])[0]) - { - ptr_bar->conditions_array = string_split (CONFIG_STRING(ptr_bar->options[GUI_BAR_OPTION_CONDITIONS]), - ",", 0, 0, - &ptr_bar->conditions_count); - } - else - { - ptr_bar->conditions_count = 0; - ptr_bar->conditions_array = NULL; - } - } + (void) option; gui_window_ask_refresh (1); } @@ -1343,9 +1362,13 @@ gui_bar_create_option (const char *bar_name, int index_option, const char *value weechat_config_file, weechat_config_section_bar, option_name, "string", N_("condition(s) for displaying bar (for bars of type " - "\"window\"): \"active\" = window must be active, " - "\"inactive\" = window must be inactive, " - "\"nicklist\" = buffer must have a nicklist"), + "\"window\"): a simple condition: \"active\", " + "\"inactive\", \"nicklist\" (window must be active/" + "inactive, buffer must have a nicklist), or an " + "expression with condition(s) (see /help eval), like: " + "\"${nicklist} && ${window.win_width} > 100\" " + "(local variables for expression are ${active}, " + "${inactive} and ${nicklist})"), NULL, 0, 0, value, NULL, 0, NULL, NULL, &gui_bar_config_change_conditions, NULL, NULL, NULL); break; @@ -1537,8 +1560,6 @@ gui_bar_alloc (const char *name) { new_bar->options[i] = NULL; } - new_bar->conditions_count = 0; - new_bar->conditions_array = NULL; new_bar->items_count = 0; new_bar->items_array = NULL; new_bar->items_prefix = NULL; @@ -1585,17 +1606,6 @@ gui_bar_new_with_options (const char *name, new_bar->options[GUI_BAR_OPTION_PRIORITY] = priority; new_bar->options[GUI_BAR_OPTION_TYPE] = type; new_bar->options[GUI_BAR_OPTION_CONDITIONS] = conditions; - if (CONFIG_STRING(conditions) && CONFIG_STRING(conditions)[0]) - { - new_bar->conditions_array = string_split (CONFIG_STRING(conditions), - ",", 0, 0, - &new_bar->conditions_count); - } - else - { - new_bar->conditions_count = 0; - new_bar->conditions_array = NULL; - } new_bar->options[GUI_BAR_OPTION_POSITION] = position; new_bar->options[GUI_BAR_OPTION_FILLING_TOP_BOTTOM] = filling_top_bottom; new_bar->options[GUI_BAR_OPTION_FILLING_LEFT_RIGHT] = filling_left_right; @@ -1832,7 +1842,7 @@ gui_bar_create_default_input () char *buf; /* search an input_text item */ - if (!gui_bar_item_used_in_a_bar (gui_bar_item_names[GUI_BAR_ITEM_INPUT_TEXT], 1)) + if (!gui_bar_item_used_in_at_least_one_bar (gui_bar_item_names[GUI_BAR_ITEM_INPUT_TEXT], 1)) { ptr_bar = gui_bar_search (GUI_BAR_DEFAULT_NAME_INPUT); if (ptr_bar) @@ -1973,7 +1983,7 @@ gui_bar_create_default_nicklist () "0", /* hidden */ "200", /* priority */ "window", /* type */ - "nicklist", /* conditions */ + "${nicklist}", /* conditions */ "right", /* position */ "columns_vertical", /* filling_top_bottom */ "vertical", /* filling_left_right */ @@ -2178,8 +2188,6 @@ gui_bar_free (struct t_gui_bar *bar) if (bar->options[i]) config_file_option_free (bar->options[i]); } - if (bar->conditions_array) - string_free_split (bar->conditions_array); gui_bar_free_items_arrays (bar); free (bar); @@ -2249,8 +2257,6 @@ gui_bar_hdata_bar_cb (void *data, const char *hdata_name) { HDATA_VAR(struct t_gui_bar, name, STRING, 0, NULL, NULL); HDATA_VAR(struct t_gui_bar, options, POINTER, 0, NULL, NULL); - HDATA_VAR(struct t_gui_bar, conditions_count, INTEGER, 0, NULL, NULL); - HDATA_VAR(struct t_gui_bar, conditions_array, STRING, 0, "conditions_count", NULL); HDATA_VAR(struct t_gui_bar, items_count, INTEGER, 0, NULL, NULL); HDATA_VAR(struct t_gui_bar, items_subcount, POINTER, 0, NULL, NULL); HDATA_VAR(struct t_gui_bar, items_array, POINTER, 0, NULL, NULL); @@ -2297,16 +2303,6 @@ gui_bar_add_to_infolist (struct t_infolist *infolist, return 0; if (!infolist_new_var_string (ptr_item, "conditions", CONFIG_STRING(bar->options[GUI_BAR_OPTION_CONDITIONS]))) return 0; - if (!infolist_new_var_integer (ptr_item, "conditions_count", bar->conditions_count)) - return 0; - for (i = 0; i < bar->conditions_count; i++) - { - snprintf (option_name, sizeof (option_name), - "conditions_array_%05d", i + 1); - if (!infolist_new_var_string (ptr_item, option_name, - bar->conditions_array[i])) - return 0; - } if (!infolist_new_var_integer (ptr_item, "position", CONFIG_INTEGER(bar->options[GUI_BAR_OPTION_POSITION]))) return 0; if (!infolist_new_var_integer (ptr_item, "filling_top_bottom", CONFIG_INTEGER(bar->options[GUI_BAR_OPTION_FILLING_TOP_BOTTOM]))) @@ -2377,8 +2373,6 @@ gui_bar_print_log () CONFIG_INTEGER(ptr_bar->options[GUI_BAR_OPTION_TYPE]), gui_bar_type_string[CONFIG_INTEGER(ptr_bar->options[GUI_BAR_OPTION_TYPE])]); log_printf (" conditions . . . . . . : '%s'", CONFIG_STRING(ptr_bar->options[GUI_BAR_OPTION_CONDITIONS])); - log_printf (" conditions_count . . . : %d", ptr_bar->conditions_count); - log_printf (" conditions_array . . . : 0x%lx", ptr_bar->conditions_array); log_printf (" position . . . . . . . : %d (%s)", CONFIG_INTEGER(ptr_bar->options[GUI_BAR_OPTION_POSITION]), gui_bar_position_string[CONFIG_INTEGER(ptr_bar->options[GUI_BAR_OPTION_POSITION])]); diff --git a/src/gui/gui-bar.h b/src/gui/gui-bar.h index aec264129..6743f9fc1 100644 --- a/src/gui/gui-bar.h +++ b/src/gui/gui-bar.h @@ -34,7 +34,7 @@ enum t_gui_bar_option GUI_BAR_OPTION_HIDDEN = 0, /* true if bar is hidden */ GUI_BAR_OPTION_PRIORITY, /* bar priority */ GUI_BAR_OPTION_TYPE, /* type (root or window) */ - GUI_BAR_OPTION_CONDITIONS, /* conditions for display */ + GUI_BAR_OPTION_CONDITIONS, /* condition(s) for display */ GUI_BAR_OPTION_POSITION, /* bottom, top, left, right */ GUI_BAR_OPTION_FILLING_TOP_BOTTOM, /* filling when pos. is top/bottom */ GUI_BAR_OPTION_FILLING_LEFT_RIGHT, /* filling when pos. is left/right */ @@ -84,8 +84,6 @@ struct t_gui_bar struct t_config_option *options[GUI_BAR_NUM_OPTIONS]; /* internal vars */ - int conditions_count; /* number of conditions */ - char **conditions_array; /* bar conditions (after split) */ int items_count; /* number of bar items */ int *items_subcount; /* number of sub items */ char ***items_array; /* bar items (after split) */ diff --git a/src/gui/gui-key.c b/src/gui/gui-key.c index 492e0d9e4..93938ec2a 100644 --- a/src/gui/gui-key.c +++ b/src/gui/gui-key.c @@ -950,6 +950,29 @@ gui_key_focus_matching (struct t_gui_key *key, } /* + * gui_key_focus_command_replace_cb: callback for replacing values in string + * with a hashtable + */ + +char * +gui_key_focus_command_replace_cb (void *data, const char *text) +{ + struct t_hashtable *ptr_hashtable; + const char *ptr_value; + + ptr_hashtable = (struct t_hashtable *)data; + + if (ptr_hashtable) + { + ptr_value = hashtable_get (ptr_hashtable, text); + if (ptr_value) + return strdup (ptr_value); + } + + return NULL; +} + +/* * gui_key_focus_command: run command according to focus * return 1 if a command was executed, otherwise 0 */ @@ -1038,9 +1061,10 @@ gui_key_focus_command (const char *key, int context, } else { - command = string_replace_with_hashtable (commands[i], - hashtable, - &errors); + command = string_replace_with_callback (commands[i], + &gui_key_focus_command_replace_cb, + hashtable, + &errors); if (command) { if (errors == 0) diff --git a/src/plugins/guile/weechat-guile-api.c b/src/plugins/guile/weechat-guile-api.c index 378fb7e0f..f2267b19d 100644 --- a/src/plugins/guile/weechat-guile-api.c +++ b/src/plugins/guile/weechat-guile-api.c @@ -421,6 +421,44 @@ weechat_guile_api_string_input_for_buffer (SCM string) } /* + * weechat_guile_api_string_eval_expression: evaluate an expression and return + * result + */ + +SCM +weechat_guile_api_string_eval_expression (SCM expr, SCM pointers, + SCM extra_vars) +{ + char *result; + SCM return_value; + struct t_hashtable *c_pointers, *c_extra_vars; + + API_FUNC(1, "string_eval_expression", API_RETURN_EMPTY); + if (!scm_is_string (expr) || !scm_list_p (pointers) + || !scm_list_p (extra_vars)) + API_WRONG_ARGS(API_RETURN_EMPTY); + + c_pointers = weechat_guile_alist_to_hashtable (pointers, + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_POINTER); + c_extra_vars = weechat_guile_alist_to_hashtable (extra_vars, + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); + + result = weechat_string_eval_expression (scm_i_string_chars (expr), + c_pointers, c_extra_vars); + + if (c_pointers) + weechat_hashtable_free (c_pointers); + if (c_extra_vars) + weechat_hashtable_free (c_extra_vars); + + API_RETURN_STRING_FREE(result); +} + +/* * weechat_guile_api_mkdir_home: create a directory in WeeChat home */ @@ -1933,7 +1971,9 @@ weechat_guile_api_key_bind (SCM context, SCM keys) API_WRONG_ARGS(API_RETURN_INT(0)); c_keys = weechat_guile_alist_to_hashtable (keys, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); num_keys = weechat_key_bind (scm_i_string_chars (context), c_keys); @@ -2454,7 +2494,9 @@ weechat_guile_api_hook_process_hashtable (SCM command, SCM options, SCM timeout, API_WRONG_ARGS(API_RETURN_EMPTY); c_options = weechat_guile_alist_to_hashtable (options, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); result = API_PTR2STR(plugin_script_api_hook_process_hashtable (weechat_guile_plugin, guile_current_script, @@ -2861,7 +2903,9 @@ weechat_guile_api_hook_hsignal_send (SCM signal, SCM hashtable) API_WRONG_ARGS(API_RETURN_ERROR); c_hashtable = weechat_guile_alist_to_hashtable (hashtable, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); weechat_hook_hsignal_send (scm_i_string_chars (signal), c_hashtable); @@ -4462,7 +4506,9 @@ weechat_guile_api_info_get_hashtable (SCM info_name, SCM hash) API_WRONG_ARGS(API_RETURN_EMPTY); c_hashtable = weechat_guile_alist_to_hashtable (hash, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); result_hashtable = weechat_info_get_hashtable (scm_i_string_chars (info_name), c_hashtable); @@ -5160,7 +5206,9 @@ weechat_guile_api_hdata_update (SCM hdata, SCM pointer, SCM hashtable) API_WRONG_ARGS(API_RETURN_INT(0)); c_hashtable = weechat_guile_alist_to_hashtable (hashtable, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); value = weechat_hdata_update (API_STR2PTR(scm_i_string_chars (hdata)), API_STR2PTR(scm_i_string_chars (pointer)), @@ -5358,6 +5406,7 @@ weechat_guile_api_module_init (void *data) API_DEF_FUNC(string_remove_color, 2); API_DEF_FUNC(string_is_command_char, 1); API_DEF_FUNC(string_input_for_buffer, 1); + API_DEF_FUNC(string_eval_expression, 3); API_DEF_FUNC(mkdir_home, 2); API_DEF_FUNC(mkdir, 2); API_DEF_FUNC(mkdir_parents, 2); diff --git a/src/plugins/guile/weechat-guile.c b/src/plugins/guile/weechat-guile.c index 7dbd5ce4b..a46093167 100644 --- a/src/plugins/guile/weechat-guile.c +++ b/src/plugins/guile/weechat-guile.c @@ -198,22 +198,21 @@ weechat_guile_hashtable_to_alist (struct t_hashtable *hashtable) /* * weechat_guile_alist_to_hashtable: get WeeChat hashtable with Guile alist - * Hashtable returned has type string for - * both keys and values * Note: hashtable has to be released after * use with call to weechat_hashtable_free() */ struct t_hashtable * -weechat_guile_alist_to_hashtable (SCM alist, int hashtable_size) +weechat_guile_alist_to_hashtable (SCM alist, int size, const char *type_keys, + const char *type_values) { struct t_hashtable *hashtable; int length, i; SCM pair; - hashtable = weechat_hashtable_new (hashtable_size, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_STRING, + hashtable = weechat_hashtable_new (size, + type_keys, + type_values, NULL, NULL); if (!hashtable) @@ -223,11 +222,24 @@ weechat_guile_alist_to_hashtable (SCM alist, int hashtable_size) for (i = 0; i < length; i++) { pair = scm_list_ref (alist, scm_from_int (i)); - weechat_hashtable_set (hashtable, - scm_i_string_chars (scm_list_ref (pair, - scm_from_int (0))), - scm_i_string_chars (scm_list_ref (pair, - scm_from_int (1)))); + if (strcmp (type_values, WEECHAT_HASHTABLE_STRING) == 0) + { + weechat_hashtable_set (hashtable, + scm_i_string_chars (scm_list_ref (pair, + scm_from_int (0))), + scm_i_string_chars (scm_list_ref (pair, + scm_from_int (1)))); + } + else if (strcmp (type_values, WEECHAT_HASHTABLE_POINTER) == 0) + { + weechat_hashtable_set (hashtable, + scm_i_string_chars (scm_list_ref (pair, + scm_from_int (0))), + plugin_script_str2ptr (weechat_guile_plugin, + NULL, NULL, + scm_i_string_chars (scm_list_ref (pair, + scm_from_int (1))))); + } } return hashtable; @@ -305,7 +317,9 @@ weechat_guile_exec (struct t_plugin_script *script, else if (ret_type == WEECHAT_SCRIPT_EXEC_HASHTABLE) { ret_value = weechat_guile_alist_to_hashtable (rc, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); } else { diff --git a/src/plugins/guile/weechat-guile.h b/src/plugins/guile/weechat-guile.h index b868a4c10..03c104b64 100644 --- a/src/plugins/guile/weechat-guile.h +++ b/src/plugins/guile/weechat-guile.h @@ -37,7 +37,9 @@ extern SCM guile_port; extern SCM weechat_guile_hashtable_to_alist (struct t_hashtable *hashtable); extern struct t_hashtable *weechat_guile_alist_to_hashtable (SCM dict, - int hashtable_size); + int size, + const char *type_keys, + const char *type_values); extern void *weechat_guile_exec (struct t_plugin_script *script, int ret_type, const char *function, char *format, void **argv); diff --git a/src/plugins/lua/weechat-lua-api.c b/src/plugins/lua/weechat-lua-api.c index ce8a1e61f..6c1f83537 100644 --- a/src/plugins/lua/weechat-lua-api.c +++ b/src/plugins/lua/weechat-lua-api.c @@ -461,6 +461,42 @@ weechat_lua_api_string_input_for_buffer (lua_State *L) } /* + * weechat_lua_api_string_eval_expression: evaluate an expression and return + * result + */ + +static int +weechat_lua_api_string_eval_expression (lua_State *L) +{ + const char *expr; + struct t_hashtable *pointers, *extra_vars; + char *result; + + API_FUNC(1, "string_eval_expression", API_RETURN_EMPTY); + if (lua_gettop (lua_current_interpreter) < 3) + API_WRONG_ARGS(API_RETURN_EMPTY); + + expr = lua_tostring (lua_current_interpreter, -3); + pointers = weechat_lua_tohashtable (lua_current_interpreter, -2, + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_POINTER); + extra_vars = weechat_lua_tohashtable (lua_current_interpreter, -1, + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); + + result = weechat_string_eval_expression (expr, pointers, extra_vars); + + if (pointers) + weechat_hashtable_free (pointers); + if (extra_vars) + weechat_hashtable_free (extra_vars); + + API_RETURN_STRING_FREE(result); +} + +/* * weechat_lua_api_mkdir_home: create a directory in WeeChat home */ @@ -2133,7 +2169,9 @@ weechat_lua_api_key_bind (lua_State *L) context = lua_tostring (lua_current_interpreter, -2); hashtable = weechat_lua_tohashtable (lua_current_interpreter, -1, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); num_keys = weechat_key_bind (context, hashtable); @@ -2702,7 +2740,9 @@ weechat_lua_api_hook_process_hashtable (lua_State *L) command = lua_tostring (lua_current_interpreter, -5); options = weechat_lua_tohashtable (lua_current_interpreter, -4, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); timeout = lua_tonumber (lua_current_interpreter, -3); function = lua_tostring (lua_current_interpreter, -2); data = lua_tostring (lua_current_interpreter, -1); @@ -3127,7 +3167,9 @@ weechat_lua_api_hook_hsignal_send (lua_State *L) signal = lua_tostring (lua_current_interpreter, -2); hashtable = weechat_lua_tohashtable (lua_current_interpreter, -1, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); weechat_hook_hsignal_send (signal, hashtable); @@ -4899,7 +4941,9 @@ weechat_lua_api_info_get_hashtable (lua_State *L) info_name = lua_tostring (lua_current_interpreter, -2); table = weechat_lua_tohashtable (lua_current_interpreter, -1, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); result_hashtable = weechat_info_get_hashtable (info_name, table); @@ -5695,7 +5739,9 @@ weechat_lua_api_hdata_update (lua_State *L) hdata = lua_tostring (lua_current_interpreter, -3); pointer = lua_tostring (lua_current_interpreter, -2); hashtable = weechat_lua_tohashtable (lua_current_interpreter, -1, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); value = weechat_hdata_update (API_STR2PTR(hdata), API_STR2PTR(pointer), @@ -6296,6 +6342,7 @@ const struct luaL_Reg weechat_lua_api_funcs[] = { API_DEF_FUNC(string_remove_color), API_DEF_FUNC(string_is_command_char), API_DEF_FUNC(string_input_for_buffer), + API_DEF_FUNC(string_eval_expression), API_DEF_FUNC(mkdir_home), API_DEF_FUNC(mkdir), API_DEF_FUNC(mkdir_parents), diff --git a/src/plugins/lua/weechat-lua.c b/src/plugins/lua/weechat-lua.c index 89cede0b8..8711eead1 100644 --- a/src/plugins/lua/weechat-lua.c +++ b/src/plugins/lua/weechat-lua.c @@ -108,20 +108,19 @@ weechat_lua_pushhashtable (lua_State *interpreter, struct t_hashtable *hashtable /* * weechat_lua_hash_to_hashtable: get WeeChat hashtable with lua hash (on stack) - * Hashtable returned has type string for - * both keys and values * Note: hashtable has to be released after use * with call to weechat_hashtable_free() */ struct t_hashtable * -weechat_lua_tohashtable (lua_State *interpreter, int index, int hashtable_size) +weechat_lua_tohashtable (lua_State *interpreter, int index, int size, + const char *type_keys, const char *type_values) { struct t_hashtable *hashtable; - hashtable = weechat_hashtable_new (hashtable_size, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_STRING, + hashtable = weechat_hashtable_new (size, + type_keys, + type_values, NULL, NULL); if (!hashtable) @@ -130,9 +129,20 @@ weechat_lua_tohashtable (lua_State *interpreter, int index, int hashtable_size) lua_pushnil (interpreter); while (lua_next (interpreter, index - 1) != 0) { - weechat_hashtable_set (hashtable, - lua_tostring (interpreter, -2), - lua_tostring (interpreter, -1)); + if (strcmp (type_values, WEECHAT_HASHTABLE_STRING) == 0) + { + weechat_hashtable_set (hashtable, + lua_tostring (interpreter, -2), + lua_tostring (interpreter, -1)); + } + else if (strcmp (type_values, WEECHAT_HASHTABLE_POINTER) == 0) + { + weechat_hashtable_set (hashtable, + lua_tostring (interpreter, -2), + plugin_script_str2ptr (weechat_lua_plugin, + NULL, NULL, + lua_tostring (interpreter, -1))); + } /* remove value from stack (keep key for next iteration) */ lua_pop (interpreter, 1); } @@ -209,7 +219,9 @@ weechat_lua_exec (struct t_plugin_script *script, int ret_type, else if (ret_type == WEECHAT_SCRIPT_EXEC_HASHTABLE) { ret_value = weechat_lua_tohashtable (lua_current_interpreter, -1, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); } else { diff --git a/src/plugins/lua/weechat-lua.h b/src/plugins/lua/weechat-lua.h index 0512d2272..7f4de2085 100644 --- a/src/plugins/lua/weechat-lua.h +++ b/src/plugins/lua/weechat-lua.h @@ -40,7 +40,9 @@ extern void weechat_lua_pushhashtable (lua_State *interpreter, struct t_hashtable *hashtable); extern struct t_hashtable *weechat_lua_tohashtable (lua_State *interpreter, int index, - int hashtable_size); + int size, + const char *type_keys, + const char *type_values); extern void *weechat_lua_exec (struct t_plugin_script *script, int ret_type, const char *function, const char *format, void **argv); diff --git a/src/plugins/perl/weechat-perl-api.c b/src/plugins/perl/weechat-perl-api.c index 3d0cb645e..d182bbb04 100644 --- a/src/plugins/perl/weechat-perl-api.c +++ b/src/plugins/perl/weechat-perl-api.c @@ -437,6 +437,40 @@ XS (XS_weechat_api_string_input_for_buffer) } /* + * weechat::string_eval_expression: evaluate expression and return result + */ + +XS (XS_weechat_api_string_eval_expression) +{ + char *expr, *result; + struct t_hashtable *pointers, *extra_vars; + dXSARGS; + + API_FUNC(1, "string_eval_expression", API_RETURN_EMPTY); + if (items < 3) + API_WRONG_ARGS(API_RETURN_EMPTY); + + expr = SvPV_nolen (ST (0)); + pointers = weechat_perl_hash_to_hashtable (ST (1), + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_POINTER); + extra_vars = weechat_perl_hash_to_hashtable (ST (2), + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); + + result = weechat_string_eval_expression (expr, pointers, extra_vars); + + if (pointers) + weechat_hashtable_free (pointers); + if (extra_vars) + weechat_hashtable_free (extra_vars); + + API_RETURN_STRING_FREE(result); +} + +/* * weechat::mkdir_home: create a directory in WeeChat home */ @@ -2003,7 +2037,9 @@ XS (XS_weechat_api_key_bind) context = SvPV_nolen (ST (0)); hashtable = weechat_perl_hash_to_hashtable (ST (1), - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); num_keys = weechat_key_bind (context, hashtable); @@ -2537,7 +2573,9 @@ XS (XS_weechat_api_hook_process_hashtable) command = SvPV_nolen (ST (0)); options = weechat_perl_hash_to_hashtable (ST (1), - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); function = SvPV_nolen (ST (3)); data = SvPV_nolen (ST (4)); @@ -2951,7 +2989,9 @@ XS (XS_weechat_api_hook_hsignal_send) signal = SvPV_nolen (ST (0)); hashtable = weechat_perl_hash_to_hashtable (ST (1), - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); weechat_hook_hsignal_send (signal, hashtable); @@ -4663,7 +4703,9 @@ XS (XS_weechat_api_info_get_hashtable) info_name = SvPV_nolen (ST (0)); hashtable = weechat_perl_hash_to_hashtable (ST (1), - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); result_hashtable = weechat_info_get_hashtable (info_name, hashtable); result_hash = weechat_perl_hashtable_to_hash (result_hashtable); @@ -5428,7 +5470,9 @@ XS (XS_weechat_api_hdata_update) hdata = SvPV_nolen (ST (0)); pointer = SvPV_nolen (ST (1)); hashtable = weechat_perl_hash_to_hashtable (ST (2), - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); value = weechat_hdata_update (API_STR2PTR(hdata), API_STR2PTR(pointer), @@ -5630,6 +5674,7 @@ weechat_perl_api_init (pTHX) API_DEF_FUNC(string_remove_color); API_DEF_FUNC(string_is_command_char); API_DEF_FUNC(string_input_for_buffer); + API_DEF_FUNC(string_eval_expression); API_DEF_FUNC(mkdir_home); API_DEF_FUNC(mkdir); API_DEF_FUNC(mkdir_parents); diff --git a/src/plugins/perl/weechat-perl.c b/src/plugins/perl/weechat-perl.c index f889aa6be..63ab186bd 100644 --- a/src/plugins/perl/weechat-perl.c +++ b/src/plugins/perl/weechat-perl.c @@ -169,14 +169,13 @@ weechat_perl_hashtable_to_hash (struct t_hashtable *hashtable) /* * weechat_perl_hash_to_hashtable: get WeeChat hashtable with perl hash - * Hashtable returned has type string for - * both keys and values * Note: hashtable has to be released after use * with call to weechat_hashtable_free() */ struct t_hashtable * -weechat_perl_hash_to_hashtable (SV *hash, int hashtable_size) +weechat_perl_hash_to_hashtable (SV *hash, int size, const char *type_keys, + const char *type_values) { struct t_hashtable *hashtable; HV *hash2; @@ -184,9 +183,9 @@ weechat_perl_hash_to_hashtable (SV *hash, int hashtable_size) char *str_key; I32 retlen; - hashtable = weechat_hashtable_new (hashtable_size, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_STRING, + hashtable = weechat_hashtable_new (size, + type_keys, + type_values, NULL, NULL); if (!hashtable) @@ -198,7 +197,15 @@ weechat_perl_hash_to_hashtable (SV *hash, int hashtable_size) hv_iterinit (hash2); while ((value = hv_iternextsv (hash2, &str_key, &retlen))) { - weechat_hashtable_set (hashtable, str_key, SvPV (value, PL_na)); + if (strcmp (type_values, WEECHAT_HASHTABLE_STRING) == 0) + weechat_hashtable_set (hashtable, str_key, SvPV (value, PL_na)); + else if (strcmp (type_values, WEECHAT_HASHTABLE_POINTER) == 0) + { + weechat_hashtable_set (hashtable, str_key, + plugin_script_str2ptr (weechat_perl_plugin, + NULL, NULL, + SvPV (value, PL_na))); + } } } @@ -316,7 +323,9 @@ weechat_perl_exec (struct t_plugin_script *script, else if (ret_type == WEECHAT_SCRIPT_EXEC_HASHTABLE) { ret_value = weechat_perl_hash_to_hashtable (POPs, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); } else { diff --git a/src/plugins/perl/weechat-perl.h b/src/plugins/perl/weechat-perl.h index 87a601aac..5e1eabe48 100644 --- a/src/plugins/perl/weechat-perl.h +++ b/src/plugins/perl/weechat-perl.h @@ -35,8 +35,9 @@ extern struct t_plugin_script *perl_registered_script; extern const char *perl_current_script_filename; extern HV *weechat_perl_hashtable_to_hash (struct t_hashtable *hashtable); -extern struct t_hashtable *weechat_perl_hash_to_hashtable (SV *hash, - int hashtable_size); +extern struct t_hashtable *weechat_perl_hash_to_hashtable (SV *hash, int size, + const char *type_keys, + const char *type_values); extern void *weechat_perl_exec (struct t_plugin_script *script, int ret_type, const char *function, const char *format, void **argv); diff --git a/src/plugins/plugin-script.c b/src/plugins/plugin-script.c index b1df0f49d..bc2babc49 100644 --- a/src/plugins/plugin-script.c +++ b/src/plugins/plugin-script.c @@ -286,7 +286,7 @@ plugin_script_str2ptr (struct t_weechat_plugin *weechat_plugin, return (void *)value; invalid: - if (weechat_plugin->debug >= 1) + if ((weechat_plugin->debug >= 1) && script_name && function_name) { ptr_buffer = weechat_buffer_search_main (); if (ptr_buffer) diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c index 323e5068b..dfec3a14c 100644 --- a/src/plugins/plugin.c +++ b/src/plugins/plugin.c @@ -39,6 +39,7 @@ #include "../core/weechat.h" #include "../core/wee-config.h" +#include "../core/wee-eval.h" #include "../core/wee-hashtable.h" #include "../core/wee-hdata.h" #include "../core/wee-hook.h" @@ -521,6 +522,7 @@ plugin_load (const char *filename, int argc, char **argv) new_plugin->string_decode_base64 = &string_decode_base64; new_plugin->string_is_command_char = &string_is_command_char; new_plugin->string_input_for_buffer = &string_input_for_buffer; + new_plugin->string_eval_expression = &eval_expression; new_plugin->utf8_has_8bits = &utf8_has_8bits; new_plugin->utf8_is_valid = &utf8_is_valid; diff --git a/src/plugins/python/weechat-python-api.c b/src/plugins/python/weechat-python-api.c index cc8f2a4e1..f450f556b 100644 --- a/src/plugins/python/weechat-python-api.c +++ b/src/plugins/python/weechat-python-api.c @@ -444,6 +444,43 @@ weechat_python_api_string_input_for_buffer (PyObject *self, PyObject *args) } /* + * weechat_python_api_string_eval_expression: evaluate expression and return + * result + */ + +static PyObject * +weechat_python_api_string_eval_expression (PyObject *self, PyObject *args) +{ + char *expr, *result; + struct t_hashtable *pointers, *extra_vars; + PyObject *dict, *dict2, *return_value; + + API_FUNC(1, "string_eval_expression", API_RETURN_EMPTY); + expr = NULL; + pointers = NULL; + extra_vars = NULL; + if (!PyArg_ParseTuple (args, "sOO", &expr, &dict, &dict2)) + API_WRONG_ARGS(API_RETURN_EMPTY); + pointers = weechat_python_dict_to_hashtable (dict, + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_POINTER); + extra_vars = weechat_python_dict_to_hashtable (dict2, + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); + + result = weechat_string_eval_expression (expr, pointers, extra_vars); + + if (pointers) + weechat_hashtable_free (pointers); + if (extra_vars) + weechat_hashtable_free (extra_vars); + + API_RETURN_STRING_FREE(result); +} + +/* * weechat_python_api_mkdir_home: create a directory in WeeChat home */ @@ -2081,7 +2118,9 @@ weechat_python_api_key_bind (PyObject *self, PyObject *args) API_WRONG_ARGS(API_RETURN_INT(0)); hashtable = weechat_python_dict_to_hashtable (dict, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); num_keys = weechat_key_bind (context, hashtable); @@ -2652,7 +2691,9 @@ weechat_python_api_hook_process_hashtable (PyObject *self, PyObject *args) &data)) API_WRONG_ARGS(API_RETURN_EMPTY); options = weechat_python_dict_to_hashtable (dict, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); result = API_PTR2STR(plugin_script_api_hook_process_hashtable (weechat_python_plugin, python_current_script, @@ -3077,7 +3118,9 @@ weechat_python_api_hook_hsignal_send (PyObject *self, PyObject *args) API_WRONG_ARGS(API_RETURN_ERROR); hashtable = weechat_python_dict_to_hashtable (dict, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); weechat_hook_hsignal_send (signal, hashtable); @@ -4840,7 +4883,9 @@ weechat_python_api_info_get_hashtable (PyObject *self, PyObject *args) if (!PyArg_ParseTuple (args, "sO", &info_name, &dict)) API_WRONG_ARGS(API_RETURN_EMPTY); hashtable = weechat_python_dict_to_hashtable (dict, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); result_hashtable = weechat_info_get_hashtable (info_name, hashtable); result_dict = weechat_python_hashtable_to_dict (result_hashtable); @@ -5613,7 +5658,9 @@ weechat_python_api_hdata_update (PyObject *self, PyObject *args) if (!PyArg_ParseTuple (args, "ssO", &hdata, &pointer, &dict)) API_WRONG_ARGS(API_RETURN_INT(0)); hashtable = weechat_python_dict_to_hashtable (dict, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); value = weechat_hdata_update (API_STR2PTR(hdata), API_STR2PTR(pointer), @@ -5807,6 +5854,7 @@ PyMethodDef weechat_python_funcs[] = API_DEF_FUNC(string_remove_color), API_DEF_FUNC(string_is_command_char), API_DEF_FUNC(string_input_for_buffer), + API_DEF_FUNC(string_eval_expression), API_DEF_FUNC(mkdir_home), API_DEF_FUNC(mkdir), API_DEF_FUNC(mkdir_parents), diff --git a/src/plugins/python/weechat-python.c b/src/plugins/python/weechat-python.c index 2eba42de4..d1a6d4185 100644 --- a/src/plugins/python/weechat-python.c +++ b/src/plugins/python/weechat-python.c @@ -232,23 +232,23 @@ weechat_python_hashtable_to_dict (struct t_hashtable *hashtable) /* * weechat_python_dict_to_hashtable: get WeeChat hashtable with python * dictionary - * Hashtable returned has type string for - * both keys and values * Note: hashtable has to be released after * use with call to weechat_hashtable_free() */ struct t_hashtable * -weechat_python_dict_to_hashtable (PyObject *dict, int hashtable_size) +weechat_python_dict_to_hashtable (PyObject *dict, int size, + const char *type_keys, + const char *type_values) { struct t_hashtable *hashtable; PyObject *key, *value; Py_ssize_t pos; char *str_key, *str_value; - hashtable = weechat_hashtable_new (hashtable_size, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_STRING, + hashtable = weechat_hashtable_new (size, + type_keys, + type_values, NULL, NULL); if (!hashtable) @@ -275,7 +275,17 @@ weechat_python_dict_to_hashtable (PyObject *dict, int hashtable_size) str_value = weechat_python_unicode_to_string (value); if (str_key) - weechat_hashtable_set (hashtable, str_key, str_value); + { + if (strcmp (type_values, WEECHAT_HASHTABLE_STRING) == 0) + weechat_hashtable_set (hashtable, str_key, str_value); + else if (strcmp (type_values, WEECHAT_HASHTABLE_POINTER) == 0) + { + weechat_hashtable_set (hashtable, str_key, + plugin_script_str2ptr (weechat_python_plugin, + NULL, NULL, + str_value)); + } + } if (str_key) free (str_key); @@ -388,7 +398,9 @@ weechat_python_exec (struct t_plugin_script *script, else if (ret_type == WEECHAT_SCRIPT_EXEC_HASHTABLE) { ret_value = weechat_python_dict_to_hashtable (rc, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); Py_XDECREF(rc); } else diff --git a/src/plugins/python/weechat-python.h b/src/plugins/python/weechat-python.h index 1a522603a..0a1aa2fe5 100644 --- a/src/plugins/python/weechat-python.h +++ b/src/plugins/python/weechat-python.h @@ -45,7 +45,9 @@ extern const char *python_current_script_filename; extern PyObject *weechat_python_hashtable_to_dict (struct t_hashtable *hashtable); extern struct t_hashtable *weechat_python_dict_to_hashtable (PyObject *dict, - int hashtable_size); + int size, + const char *type_keys, + const char *type_values); extern void *weechat_python_exec (struct t_plugin_script *script, int ret_type, const char *function, char *format, void **argv); diff --git a/src/plugins/ruby/weechat-ruby-api.c b/src/plugins/ruby/weechat-ruby-api.c index 23420282e..a0911bfe9 100644 --- a/src/plugins/ruby/weechat-ruby-api.c +++ b/src/plugins/ruby/weechat-ruby-api.c @@ -508,6 +508,47 @@ weechat_ruby_api_string_input_for_buffer (VALUE class, VALUE string) } /* + * weechat_ruby_api_string_eval_expression: evaluate an expression and return + * result + */ + +static VALUE +weechat_ruby_api_string_eval_expression (VALUE class, VALUE expr, + VALUE pointers, VALUE extra_vars) +{ + char *c_expr, *result; + struct t_hashtable *c_pointers, *c_extra_vars; + VALUE return_value; + + API_FUNC(1, "string_eval_expression", API_RETURN_EMPTY); + if (NIL_P (expr) || NIL_P (pointers) || NIL_P (extra_vars)) + API_WRONG_ARGS(API_RETURN_EMPTY); + + Check_Type (expr, T_STRING); + Check_Type (pointers, T_HASH); + Check_Type (extra_vars, T_HASH); + + c_expr = StringValuePtr (expr); + c_pointers = weechat_ruby_hash_to_hashtable (pointers, + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_POINTER); + c_extra_vars = weechat_ruby_hash_to_hashtable (extra_vars, + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); + + result = weechat_string_eval_expression (c_expr, c_pointers, c_extra_vars); + + if (c_pointers) + weechat_hashtable_free (c_pointers); + if (c_extra_vars) + weechat_hashtable_free (c_extra_vars); + + API_RETURN_STRING_FREE(result); +} + +/* * weechat_ruby_api_mkdir_home: create a directory in WeeChat home */ @@ -2389,7 +2430,9 @@ weechat_ruby_api_key_bind (VALUE class, VALUE context, VALUE keys) c_context = StringValuePtr (context); c_keys = weechat_ruby_hash_to_hashtable (keys, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); num_keys = weechat_key_bind (c_context, c_keys); @@ -3031,7 +3074,9 @@ weechat_ruby_api_hook_process_hashtable (VALUE class, VALUE command, c_command = StringValuePtr (command); c_options = weechat_ruby_hash_to_hashtable (options, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); c_timeout = FIX2INT (timeout); c_function = StringValuePtr (function); c_data = StringValuePtr (data); @@ -3498,7 +3543,9 @@ weechat_ruby_api_hook_hsignal_send (VALUE class, VALUE signal, VALUE hashtable) c_signal = StringValuePtr (signal); c_hashtable = weechat_ruby_hash_to_hashtable (hashtable, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); weechat_hook_hsignal_send (c_signal, c_hashtable); @@ -5543,7 +5590,9 @@ weechat_ruby_api_info_get_hashtable (VALUE class, VALUE info_name, c_info_name = StringValuePtr (info_name); c_hashtable = weechat_ruby_hash_to_hashtable (hash, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); result_hashtable = weechat_info_get_hashtable (c_info_name, c_hashtable); result_hash = weechat_ruby_hashtable_to_hash (result_hashtable); @@ -6465,7 +6514,9 @@ weechat_ruby_api_hdata_update (VALUE class, VALUE hdata, VALUE pointer, c_hdata = StringValuePtr (hdata); c_pointer = StringValuePtr (pointer); c_hashtable = weechat_ruby_hash_to_hashtable (hashtable, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); value = weechat_hdata_update (API_STR2PTR(c_hdata), API_STR2PTR(c_pointer), @@ -6732,6 +6783,7 @@ weechat_ruby_api_init (VALUE ruby_mWeechat) API_DEF_FUNC(string_remove_color, 2); API_DEF_FUNC(string_is_command_char, 1); API_DEF_FUNC(string_input_for_buffer, 1); + API_DEF_FUNC(string_eval_expression, 3); API_DEF_FUNC(mkdir_home, 2); API_DEF_FUNC(mkdir, 2); API_DEF_FUNC(mkdir_parents, 2); diff --git a/src/plugins/ruby/weechat-ruby.c b/src/plugins/ruby/weechat-ruby.c index 882796d7d..e2b68db58 100644 --- a/src/plugins/ruby/weechat-ruby.c +++ b/src/plugins/ruby/weechat-ruby.c @@ -147,32 +147,43 @@ int weechat_ruby_hash_foreach_cb (VALUE key, VALUE value, void *arg) { struct t_hashtable *hashtable; + const char *type_values; hashtable = (struct t_hashtable *)arg; if ((TYPE(key) == T_STRING) && (TYPE(value) == T_STRING)) { - weechat_hashtable_set (hashtable, StringValuePtr(key), - StringValuePtr(value)); + type_values = weechat_hashtable_get_string (hashtable, "type_values"); + if (strcmp (type_values, WEECHAT_HASHTABLE_STRING) == 0) + { + weechat_hashtable_set (hashtable, StringValuePtr(key), + StringValuePtr(value)); + } + else if (strcmp (type_values, WEECHAT_HASHTABLE_POINTER) == 0) + { + weechat_hashtable_set (hashtable, StringValuePtr(key), + plugin_script_str2ptr (weechat_ruby_plugin, + NULL, NULL, + StringValuePtr(value))); + } } return 0; } /* * weechat_ruby_hash_to_hashtable: get WeeChat hashtable with ruby hashtable - * Hashtable returned has type string for - * both keys and values * Note: hashtable has to be released after use * with call to weechat_hashtable_free() */ struct t_hashtable * -weechat_ruby_hash_to_hashtable (VALUE hash, int hashtable_size) +weechat_ruby_hash_to_hashtable (VALUE hash, int size, const char *type_keys, + const char *type_values) { struct t_hashtable *hashtable; - hashtable = weechat_hashtable_new (hashtable_size, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_STRING, + hashtable = weechat_hashtable_new (size, + type_keys, + type_values, NULL, NULL); if (!hashtable) @@ -375,7 +386,9 @@ weechat_ruby_exec (struct t_plugin_script *script, else if (ret_type == WEECHAT_SCRIPT_EXEC_HASHTABLE) { ret_value = weechat_ruby_hash_to_hashtable (rc, - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); } else { diff --git a/src/plugins/ruby/weechat-ruby.h b/src/plugins/ruby/weechat-ruby.h index cf3e7a1b2..398616afa 100644 --- a/src/plugins/ruby/weechat-ruby.h +++ b/src/plugins/ruby/weechat-ruby.h @@ -37,7 +37,9 @@ extern const char *ruby_current_script_filename; extern VALUE weechat_ruby_hashtable_to_hash (struct t_hashtable *hashtable); extern struct t_hashtable *weechat_ruby_hash_to_hashtable (VALUE dict, - int hashtable_size); + int size, + const char *type_keys, + const char *type_values); void *weechat_ruby_exec (struct t_plugin_script *script, int ret_type, const char *function, const char *format, void **argv); diff --git a/src/plugins/tcl/weechat-tcl-api.c b/src/plugins/tcl/weechat-tcl-api.c index 0738fc39e..5e89aa3f3 100644 --- a/src/plugins/tcl/weechat-tcl-api.c +++ b/src/plugins/tcl/weechat-tcl-api.c @@ -612,6 +612,45 @@ weechat_tcl_api_string_input_for_buffer (ClientData clientData, Tcl_Interp *inte } /* + * weechat_tcl_api_string_eval_expression: evaluate an expression and return + * result + */ + +static int +weechat_tcl_api_string_eval_expression (ClientData clientData, + Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]) +{ + Tcl_Obj *objp; + char *expr, *result; + struct t_hashtable *pointers, *extra_vars; + int i; + + API_FUNC(1, "string_eval_expression", API_RETURN_EMPTY); + if (objc < 4) + API_WRONG_ARGS(API_RETURN_EMPTY); + + expr = Tcl_GetStringFromObj (objv[1], &i); + pointers = weechat_tcl_dict_to_hashtable (interp, objv[2], + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_POINTER); + extra_vars = weechat_tcl_dict_to_hashtable (interp, objv[3], + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); + + result = weechat_string_eval_expression (expr, pointers, extra_vars); + + if (pointers) + weechat_hashtable_free (pointers); + if (extra_vars) + weechat_hashtable_free (extra_vars); + + API_RETURN_STRING_FREE(result); +} + +/* * weechat_tcl_api_mkdir_home: create a directory in WeeChat home */ @@ -2372,7 +2411,9 @@ weechat_tcl_api_key_bind (ClientData clientData, Tcl_Interp *interp, context = Tcl_GetStringFromObj (objv[1], &i); hashtable = weechat_tcl_dict_to_hashtable (interp, objv[2], - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); num_keys = weechat_key_bind (context, hashtable); @@ -2973,7 +3014,9 @@ weechat_tcl_api_hook_process_hashtable (ClientData clientData, command = Tcl_GetStringFromObj (objv[1], &i); options = weechat_tcl_dict_to_hashtable (interp, objv[2], - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); function = Tcl_GetStringFromObj (objv[4], &i); data = Tcl_GetStringFromObj (objv[5], &i); @@ -3416,7 +3459,9 @@ weechat_tcl_api_hook_hsignal_send (ClientData clientData, Tcl_Interp *interp, signal = Tcl_GetStringFromObj (objv[1], &i); hashtable = weechat_tcl_dict_to_hashtable (interp, objv[2], - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); weechat_hook_hsignal_send (signal, hashtable); @@ -5320,7 +5365,9 @@ weechat_tcl_api_info_get_hashtable (ClientData clientData, Tcl_Interp *interp, API_WRONG_ARGS(API_RETURN_EMPTY); hashtable = weechat_tcl_dict_to_hashtable (interp, objv[2], - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); result_hashtable = weechat_info_get_hashtable (Tcl_GetStringFromObj (objv[1], &i), hashtable); @@ -6178,7 +6225,9 @@ weechat_tcl_api_hdata_update (ClientData clientData, Tcl_Interp *interp, hdata = Tcl_GetStringFromObj (objv[1], &i); pointer = Tcl_GetStringFromObj (objv[2], &i); hashtable = weechat_tcl_dict_to_hashtable (interp, objv[3], - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); value = weechat_hdata_update (API_STR2PTR(hdata), API_STR2PTR(pointer), @@ -6495,6 +6544,7 @@ void weechat_tcl_api_init (Tcl_Interp *interp) API_DEF_FUNC(string_remove_color); API_DEF_FUNC(string_is_command_char); API_DEF_FUNC(string_input_for_buffer); + API_DEF_FUNC(string_eval_expression); API_DEF_FUNC(mkdir_home); API_DEF_FUNC(mkdir); API_DEF_FUNC(mkdir_parents); diff --git a/src/plugins/tcl/weechat-tcl.c b/src/plugins/tcl/weechat-tcl.c index 26095c467..95a55fe71 100644 --- a/src/plugins/tcl/weechat-tcl.c +++ b/src/plugins/tcl/weechat-tcl.c @@ -125,24 +125,23 @@ weechat_tcl_hashtable_to_dict (Tcl_Interp *interp, /* * weechat_tcl_dict_to_hashtable: get WeeChat hashtable with tcl dict - * Hashtable returned has type string for - * both keys and values * Note: hashtable has to be released after * use with call to weechat_hashtable_free() */ struct t_hashtable * weechat_tcl_dict_to_hashtable (Tcl_Interp *interp, Tcl_Obj *dict, - int hashtable_size) + int size, const char *type_keys, + const char *type_values) { struct t_hashtable *hashtable; Tcl_DictSearch search; Tcl_Obj *key, *value; int done; - hashtable = weechat_hashtable_new (hashtable_size, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_STRING, + hashtable = weechat_hashtable_new (size, + type_keys, + type_values, NULL, NULL); if (!hashtable) @@ -152,9 +151,20 @@ weechat_tcl_dict_to_hashtable (Tcl_Interp *interp, Tcl_Obj *dict, { for (; !done ; Tcl_DictObjNext(&search, &key, &value, &done)) { - weechat_hashtable_set (hashtable, - Tcl_GetString (key), - Tcl_GetString (value)); + if (strcmp (type_values, WEECHAT_HASHTABLE_STRING) == 0) + { + weechat_hashtable_set (hashtable, + Tcl_GetString (key), + Tcl_GetString (value)); + } + else if (strcmp (type_values, WEECHAT_HASHTABLE_POINTER) == 0) + { + weechat_hashtable_set (hashtable, + Tcl_GetString (key), + plugin_script_str2ptr (weechat_tcl_plugin, + NULL, NULL, + Tcl_GetString (value))); + } } } Tcl_DictObjDone(&search); @@ -246,7 +256,9 @@ weechat_tcl_exec (struct t_plugin_script *script, { ret_val = weechat_tcl_dict_to_hashtable (interp, Tcl_GetObjResult (interp), - WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE); + WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING); } tcl_current_script = old_tcl_script; diff --git a/src/plugins/tcl/weechat-tcl.h b/src/plugins/tcl/weechat-tcl.h index 62a258885..65453fc83 100644 --- a/src/plugins/tcl/weechat-tcl.h +++ b/src/plugins/tcl/weechat-tcl.h @@ -39,7 +39,9 @@ extern Tcl_Obj *weechat_tcl_hashtable_to_dict (Tcl_Interp *interp, struct t_hashtable *hashtable); extern struct t_hashtable *weechat_tcl_dict_to_hashtable (Tcl_Interp *interp, Tcl_Obj *dict, - int hashtable_size); + int size, + const char *type_keys, + const char *type_values); extern void *weechat_tcl_exec (struct t_plugin_script *script, int ret_type, const char *function, const char *format, void **argv); diff --git a/src/plugins/weechat-plugin.h b/src/plugins/weechat-plugin.h index b70c75de4..8b55e560c 100644 --- a/src/plugins/weechat-plugin.h +++ b/src/plugins/weechat-plugin.h @@ -50,7 +50,7 @@ struct timeval; * please change the date with current one; for a second change at same * date, increment the 01, otherwise please keep 01. */ -#define WEECHAT_PLUGIN_API_VERSION "20121014-01" +#define WEECHAT_PLUGIN_API_VERSION "20121102-01" /* macros for defining plugin infos */ #define WEECHAT_PLUGIN_NAME(__name) \ @@ -251,6 +251,9 @@ struct t_weechat_plugin int (*string_decode_base64) (const char *from, char *to); int (*string_is_command_char) (const char *string); const char *(*string_input_for_buffer) (const char *string); + char *(*string_eval_expression )(const char *expr, + struct t_hashtable *pointers, + struct t_hashtable *extra_vars); /* UTF-8 strings */ int (*utf8_has_8bits) (const char *string); @@ -1009,6 +1012,10 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin); weechat_plugin->string_is_command_char(__string) #define weechat_string_input_for_buffer(__string) \ weechat_plugin->string_input_for_buffer(__string) +#define weechat_string_eval_expression(__expr, __pointers, \ + __extra_vars) \ + weechat_plugin->string_eval_expression(__expr, __pointers, \ + __extra_vars) \ /* UTF-8 strings */ #define weechat_utf8_has_8bits(__string) \ |