core: add indentation and colors in /eval debug output

This commit is contained in:
Sébastien Helleu 2021-01-01 17:08:59 +01:00
parent 63ead3da49
commit d413ccdf4f
5 changed files with 476 additions and 166 deletions

View File

@ -20,7 +20,7 @@ https://weechat.org/files/releasenotes/ReleaseNotes-devel.html[release notes]
New features:: New features::
* core: display more verbose debug with two "-d" in command /eval * core: improve debug in command /eval: display more verbose debug with two "-d", add indentation and colors
* core: add options "setvar" and "delvar" in command /buffer, rename option "localvar" to "listvar" * core: add options "setvar" and "delvar" in command /buffer, rename option "localvar" to "listvar"
* core: add buffer local variable "completion_default_template" (evaluated) to override the value of option "weechat.completion.default_template" (issue #1600) * core: add buffer local variable "completion_default_template" (evaluated) to override the value of option "weechat.completion.default_template" (issue #1600)
* core: add option "recreate" in command /filter * core: add option "recreate" in command /filter

View File

@ -34,6 +34,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <regex.h>
#include <time.h> #include <time.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -2015,6 +2016,36 @@ COMMAND_CALLBACK(debug)
COMMAND_ERROR; COMMAND_ERROR;
} }
/*
* Prints eval debug output.
*/
void
command_eval_print_debug (const char *debug)
{
regex_t regex;
char str_replace[1024], *string;
string = NULL;
if (string_regcomp (&regex, "(^|\n)( *)([0-9]+:)", REG_EXTENDED) == 0)
{
/* colorize debug ids and the following colon with delimiter color */
snprintf (str_replace, sizeof (str_replace),
"$1$2%s$3%s",
GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS),
GUI_COLOR(GUI_COLOR_CHAT));
string = string_replace_regex (debug, &regex, str_replace, '$',
NULL, NULL);
regfree (&regex);
}
gui_chat_printf (NULL, "%s", (string) ? string : debug);
if (string)
free (string);
}
/* /*
* Callback for command "/eval": evaluates an expression and sends result to * Callback for command "/eval": evaluates an expression and sends result to
* buffer. * buffer.
@ -2024,7 +2055,7 @@ COMMAND_CALLBACK(eval)
{ {
int i, print_only, split_command, condition, debug, error; int i, print_only, split_command, condition, debug, error;
char *result, *ptr_args, **commands, str_debug[32]; char *result, *ptr_args, **commands, str_debug[32];
const char **debug_output; const char *debug_output;
struct t_hashtable *pointers, *options; struct t_hashtable *pointers, *options;
/* make C compiler happy */ /* make C compiler happy */
@ -2130,7 +2161,7 @@ COMMAND_CALLBACK(eval)
debug_output = hashtable_get (options, debug_output = hashtable_get (options,
"debug_output"); "debug_output");
if (debug_output) if (debug_output)
gui_chat_printf (NULL, "%s", debug_output); command_eval_print_debug (debug_output);
} }
} }
else else
@ -2158,7 +2189,7 @@ COMMAND_CALLBACK(eval)
debug_output = hashtable_get (options, debug_output = hashtable_get (options,
"debug_output"); "debug_output");
if (debug_output) if (debug_output)
gui_chat_printf (NULL, "%s", debug_output); command_eval_print_debug (debug_output);
} }
} }
string_free_split_command (commands); string_free_split_command (commands);
@ -2181,7 +2212,7 @@ COMMAND_CALLBACK(eval)
debug_output = hashtable_get (options, debug_output = hashtable_get (options,
"debug_output"); "debug_output");
if (debug_output) if (debug_output)
gui_chat_printf (NULL, "%s", debug_output); command_eval_print_debug (debug_output);
} }
} }
} }

View File

@ -46,9 +46,21 @@
#include "../plugins/plugin.h" #include "../plugins/plugin.h"
#define EVAL_DEBUG(level, msg, argz...) \ #define EVAL_DEBUG_MSG(level, msg, argz...) \
if (eval_context->debug_level >= level) \ if (eval_context->debug_level >= level) \
eval_debug_message (eval_context, msg, ##argz); { \
debug_id = ++(eval_context->debug_id); \
(eval_context->debug_depth)++; \
eval_debug_message_vargs (eval_context, debug_id, msg, ##argz); \
}
#define EVAL_DEBUG_RESULT(level, result) \
if (eval_context->debug_level >= level) \
{ \
eval_debug_message (eval_context, debug_id, 1, result); \
(eval_context->debug_depth)--; \
}
char *logical_ops[EVAL_NUM_LOGICAL_OPS] = char *logical_ops[EVAL_NUM_LOGICAL_OPS] =
{ "||", "&&" }; { "||", "&&" };
@ -73,17 +85,62 @@ char *eval_expression_condition (const char *expr,
*/ */
void void
eval_debug_message (struct t_eval_context *eval_context, char *message, ...) eval_debug_message (struct t_eval_context *eval_context, int debug_id,
int result, const char *message)
{
int i;
char str_id[64];
if (*(eval_context->debug_output)[0])
string_dyn_concat (eval_context->debug_output, "\n", -1);
/* indentation */
for (i = 1; i < eval_context->debug_depth; i++)
{
string_dyn_concat (eval_context->debug_output, " ", -1);
}
/* debug id */
if (debug_id >= 0)
{
snprintf (str_id, sizeof (str_id), "%d:", debug_id);
string_dyn_concat (eval_context->debug_output, str_id, -1);
}
/* debug message */
if (result)
{
string_dyn_concat (eval_context->debug_output, "== ", -1);
if (message)
string_dyn_concat (eval_context->debug_output, "\"", -1);
string_dyn_concat (eval_context->debug_output,
(message) ? message : "null",
-1);
if (message)
string_dyn_concat (eval_context->debug_output, "\"", -1);
}
else
{
string_dyn_concat (eval_context->debug_output, message, -1);
}
}
/*
* Adds a debug message in the debug output, with variable arguments.
*/
void
eval_debug_message_vargs (struct t_eval_context *eval_context, int debug_id,
const char *message, ...)
{ {
weechat_va_format (message); weechat_va_format (message);
if (!vbuffer) if (vbuffer)
return; {
eval_debug_message (eval_context, debug_id, 0,
if (*(eval_context->debug)[0]) vbuffer);
string_dyn_concat (eval_context->debug, "\n", -1); free (vbuffer);
string_dyn_concat (eval_context->debug, vbuffer, -1); }
free (vbuffer);
} }
/* /*
@ -122,14 +179,20 @@ eval_strstr_level (const char *string, const char *search,
int escape) int escape)
{ {
const char *ptr_string; const char *ptr_string;
int level, length_search; int level, length_search, debug_id;
int length_prefix, length_prefix2, length_suffix, length_suffix2; int length_prefix, length_prefix2, length_suffix, length_suffix2;
EVAL_DEBUG(2, "eval_strstr_level(\"%s\", \"%s\", \"%s\", \"%s\", %d)", ptr_string = NULL;
string, search, extra_prefix, extra_suffix, escape);
debug_id = -1;
EVAL_DEBUG_MSG(2, "eval_strstr_level(\"%s\", \"%s\", \"%s\", \"%s\", %d)",
string, search, extra_prefix, extra_suffix, escape);
if (!string || !search) if (!string || !search)
return NULL; {
ptr_string = NULL;
goto end;
}
length_search = strlen (search); length_search = strlen (search);
@ -177,15 +240,19 @@ eval_strstr_level (const char *string, const char *search,
else if ((level == 0) else if ((level == 0)
&& (strncmp (ptr_string, search, length_search) == 0)) && (strncmp (ptr_string, search, length_search) == 0))
{ {
return ptr_string; goto end;
} }
else else
{ {
ptr_string++; ptr_string++;
} }
} }
ptr_string = NULL;
return NULL; end:
EVAL_DEBUG_RESULT(2, ptr_string);
return ptr_string;
} }
/* /*
@ -673,25 +740,30 @@ eval_hdata_get_value (struct t_hdata *hdata, void *pointer, const char *path,
{ {
char *value, *old_value, *var_name, str_value[128], *pos; char *value, *old_value, *var_name, str_value[128], *pos;
const char *ptr_value, *hdata_name, *ptr_var_name; const char *ptr_value, *hdata_name, *ptr_var_name;
int type; int type, debug_id;
struct t_hashtable *hashtable; struct t_hashtable *hashtable;
EVAL_DEBUG(1, "eval_hdata_get_value(\"%s\", 0x%lx, \"%s\")", debug_id = -1;
hdata->name, pointer, path); EVAL_DEBUG_MSG(1, "eval_hdata_get_value(\"%s\", 0x%lx, \"%s\")",
hdata->name, pointer, path);
value = NULL; value = NULL;
var_name = NULL; var_name = NULL;
/* NULL pointer? return empty string */ /* NULL pointer? return empty string */
if (!pointer) if (!pointer)
return strdup (""); {
value = strdup ("");
goto end;
}
/* no path? just return current pointer as string */ /* no path? just return current pointer as string */
if (!path || !path[0]) if (!path || !path[0])
{ {
snprintf (str_value, sizeof (str_value), snprintf (str_value, sizeof (str_value),
"0x%lx", (unsigned long)pointer); "0x%lx", (unsigned long)pointer);
return strdup (str_value); value = strdup (str_value);
goto end;
} }
/* /*
@ -818,6 +890,8 @@ end:
if (var_name) if (var_name)
free (var_name); free (var_name);
EVAL_DEBUG_RESULT(1, value);
return value; return value;
} }
@ -951,14 +1025,16 @@ eval_replace_vars_cb (void *data, const char *text)
struct t_eval_context *eval_context; struct t_eval_context *eval_context;
struct t_config_option *ptr_option; struct t_config_option *ptr_option;
struct t_gui_buffer *ptr_buffer; struct t_gui_buffer *ptr_buffer;
char str_value[512], *value; char str_value[512], *value, *tmp;
char *tmp;
const char *ptr_value; const char *ptr_value;
int length; int length, debug_id;
value = NULL;
eval_context = (struct t_eval_context *)data; eval_context = (struct t_eval_context *)data;
EVAL_DEBUG(1, "eval_replace_vars_cb(\"%s\")", text); debug_id = -1;
EVAL_DEBUG_MSG(1, "eval_replace_vars_cb(\"%s\")", text);
/* 1. variable in hashtable "extra_vars" */ /* 1. variable in hashtable "extra_vars" */
if (eval_context->extra_vars) if (eval_context->extra_vars)
@ -970,16 +1046,17 @@ eval_replace_vars_cb (void *data, const char *text)
{ {
tmp = strdup (ptr_value); tmp = strdup (ptr_value);
if (!tmp) if (!tmp)
return NULL; goto end;
hashtable_remove (eval_context->extra_vars, text); hashtable_remove (eval_context->extra_vars, text);
value = eval_replace_vars (tmp, eval_context); value = eval_replace_vars (tmp, eval_context);
hashtable_set (eval_context->extra_vars, text, tmp); hashtable_set (eval_context->extra_vars, text, tmp);
free (tmp); free (tmp);
return value; goto end;
} }
else else
{ {
return strdup (ptr_value); value = strdup (ptr_value);
goto end;
} }
} }
} }
@ -989,24 +1066,39 @@ eval_replace_vars_cb (void *data, const char *text)
* --> use with caution: the text must be safe! * --> use with caution: the text must be safe!
*/ */
if (strncmp (text, "eval:", 5) == 0) if (strncmp (text, "eval:", 5) == 0)
return eval_replace_vars (text + 5, eval_context); {
value = eval_replace_vars (text + 5, eval_context);
goto end;
}
/* /*
* 3. force evaluation of condition (recursive call) * 3. force evaluation of condition (recursive call)
* --> use with caution: the text must be safe! * --> use with caution: the text must be safe!
*/ */
if (strncmp (text, "eval_cond:", 10) == 0) if (strncmp (text, "eval_cond:", 10) == 0)
return eval_string_eval_cond (text + 10, eval_context); {
value = eval_string_eval_cond (text + 10, eval_context);
goto end;
}
/* 4. convert escaped chars */ /* 4. convert escaped chars */
if (strncmp (text, "esc:", 4) == 0) if (strncmp (text, "esc:", 4) == 0)
return string_convert_escaped_chars (text + 4); {
value = string_convert_escaped_chars (text + 4);
goto end;
}
if ((text[0] == '\\') && text[1] && (text[1] != '\\')) if ((text[0] == '\\') && text[1] && (text[1] != '\\'))
return string_convert_escaped_chars (text); {
value = string_convert_escaped_chars (text);
goto end;
}
/* 5. hide chars: replace all chars by a given char/string */ /* 5. hide chars: replace all chars by a given char/string */
if (strncmp (text, "hide:", 5) == 0) if (strncmp (text, "hide:", 5) == 0)
return eval_string_hide (text + 5); {
value = eval_string_hide (text + 5);
goto end;
}
/* /*
* 6. cut chars: * 6. cut chars:
@ -1016,19 +1108,34 @@ eval_replace_vars_cb (void *data, const char *text)
* suffix when the string is cut * suffix when the string is cut
*/ */
if (strncmp (text, "cut:", 4) == 0) if (strncmp (text, "cut:", 4) == 0)
return eval_string_cut (text + 4, 0); {
value = eval_string_cut (text + 4, 0);
goto end;
}
if (strncmp (text, "cutscr:", 7) == 0) if (strncmp (text, "cutscr:", 7) == 0)
return eval_string_cut (text + 7, 1); {
value = eval_string_cut (text + 7, 1);
goto end;
}
/* 7. reverse string */ /* 7. reverse string */
if (strncmp (text, "rev:", 4) == 0) if (strncmp (text, "rev:", 4) == 0)
return string_reverse (text + 4); {
value = string_reverse (text + 4);
goto end;
}
if (strncmp (text, "revscr:", 7) == 0) if (strncmp (text, "revscr:", 7) == 0)
return string_reverse_screen (text + 7); {
value = string_reverse_screen (text + 7);
goto end;
}
/* 8. repeated string */ /* 8. repeated string */
if (strncmp (text, "repeat:", 7) == 0) if (strncmp (text, "repeat:", 7) == 0)
return eval_string_repeat (text + 7); {
value = eval_string_repeat (text + 7);
goto end;
}
/* /*
* 9. length of string: * 9. length of string:
@ -1039,87 +1146,129 @@ eval_replace_vars_cb (void *data, const char *text)
{ {
length = gui_chat_strlen (text + 7); length = gui_chat_strlen (text + 7);
snprintf (str_value, sizeof (str_value), "%d", length); snprintf (str_value, sizeof (str_value), "%d", length);
return strdup (str_value); value = strdup (str_value);
goto end;
} }
if (strncmp (text, "lengthscr:", 10) == 0) if (strncmp (text, "lengthscr:", 10) == 0)
{ {
length = gui_chat_strlen_screen (text + 10); length = gui_chat_strlen_screen (text + 10);
snprintf (str_value, sizeof (str_value), "%d", length); snprintf (str_value, sizeof (str_value), "%d", length);
return strdup (str_value); value = strdup (str_value);
goto end;
} }
/* 10. regex group captured */ /* 10. regex group captured */
if (strncmp (text, "re:", 3) == 0) if (strncmp (text, "re:", 3) == 0)
return eval_string_regex_group (text + 3, eval_context); {
value = eval_string_regex_group (text + 3, eval_context);
goto end;
}
/* 11. color code */ /* 11. color code */
if (strncmp (text, "color:", 6) == 0) if (strncmp (text, "color:", 6) == 0)
return eval_string_color (text + 6); {
value = eval_string_color (text + 6);
goto end;
}
/* 12. modifier */ /* 12. modifier */
if (strncmp (text, "modifier:", 9) == 0) if (strncmp (text, "modifier:", 9) == 0)
return eval_string_modifier (text + 9); {
value = eval_string_modifier (text + 9);
goto end;
}
/* 13. info */ /* 13. info */
if (strncmp (text, "info:", 5) == 0) if (strncmp (text, "info:", 5) == 0)
return eval_string_info (text + 5); {
value = eval_string_info (text + 5);
goto end;
}
/* 14. base_encode/base_decode */ /* 14. base_encode/base_decode */
if (strncmp (text, "base_encode:", 12) == 0) if (strncmp (text, "base_encode:", 12) == 0)
return eval_string_base_encode (text + 12); {
value = eval_string_base_encode (text + 12);
goto end;
}
if (strncmp (text, "base_decode:", 12) == 0) if (strncmp (text, "base_decode:", 12) == 0)
return eval_string_base_decode (text + 12); {
value = eval_string_base_decode (text + 12);
goto end;
}
/* 15. current date/time */ /* 15. current date/time */
if ((strncmp (text, "date", 4) == 0) && (!text[4] || (text[4] == ':'))) if ((strncmp (text, "date", 4) == 0) && (!text[4] || (text[4] == ':')))
return eval_string_date (text + 4); {
value = eval_string_date (text + 4);
goto end;
}
/* 16. environment variable */ /* 16. environment variable */
if (strncmp (text, "env:", 4) == 0) if (strncmp (text, "env:", 4) == 0)
{ {
ptr_value = getenv (text + 4); ptr_value = getenv (text + 4);
if (ptr_value) value = strdup ((ptr_value) ? ptr_value : "");
return strdup (ptr_value); goto end;
} }
/* 17: ternary operator: if:condition?value_if_true:value_if_false */ /* 17: ternary operator: if:condition?value_if_true:value_if_false */
if (strncmp (text, "if:", 3) == 0) if (strncmp (text, "if:", 3) == 0)
return eval_string_if (text + 3, eval_context); {
value = eval_string_if (text + 3, eval_context);
goto end;
}
/* /*
* 18. calculate the result of an expression * 18. calculate the result of an expression
* (with number, operators and parentheses) * (with number, operators and parentheses)
*/ */
if (strncmp (text, "calc:", 5) == 0) if (strncmp (text, "calc:", 5) == 0)
return calc_expression (text + 5); {
value = calc_expression (text + 5);
goto end;
}
/* 19. option: if found, return this value */ /* 19. option: if found, return this value */
if (strncmp (text, "sec.data.", 9) == 0) if (strncmp (text, "sec.data.", 9) == 0)
{ {
ptr_value = hashtable_get (secure_hashtable_data, text + 9); ptr_value = hashtable_get (secure_hashtable_data, text + 9);
return strdup ((ptr_value) ? ptr_value : ""); value = strdup ((ptr_value) ? ptr_value : "");
goto end;
} }
config_file_search_with_string (text, NULL, NULL, &ptr_option, NULL); config_file_search_with_string (text, NULL, NULL, &ptr_option, NULL);
if (ptr_option) if (ptr_option)
{ {
if (!ptr_option->value) if (!ptr_option->value)
return strdup (""); {
value = strdup ("");
goto end;
}
switch (ptr_option->type) switch (ptr_option->type)
{ {
case CONFIG_OPTION_TYPE_BOOLEAN: case CONFIG_OPTION_TYPE_BOOLEAN:
return strdup (CONFIG_BOOLEAN(ptr_option) ? EVAL_STR_TRUE : EVAL_STR_FALSE); value = strdup (CONFIG_BOOLEAN(ptr_option) ?
EVAL_STR_TRUE : EVAL_STR_FALSE);
goto end;
case CONFIG_OPTION_TYPE_INTEGER: case CONFIG_OPTION_TYPE_INTEGER:
if (ptr_option->string_values) if (ptr_option->string_values)
return strdup (ptr_option->string_values[CONFIG_INTEGER(ptr_option)]); {
value = strdup (ptr_option->string_values[CONFIG_INTEGER(ptr_option)]);
goto end;
}
snprintf (str_value, sizeof (str_value), snprintf (str_value, sizeof (str_value),
"%d", CONFIG_INTEGER(ptr_option)); "%d", CONFIG_INTEGER(ptr_option));
return strdup (str_value); value = strdup (str_value);
goto end;
case CONFIG_OPTION_TYPE_STRING: case CONFIG_OPTION_TYPE_STRING:
return strdup (CONFIG_STRING(ptr_option)); value = strdup (CONFIG_STRING(ptr_option));
goto end;
case CONFIG_OPTION_TYPE_COLOR: case CONFIG_OPTION_TYPE_COLOR:
return strdup (gui_color_get_name (CONFIG_COLOR(ptr_option))); value = strdup (gui_color_get_name (CONFIG_COLOR(ptr_option)));
goto end;
case CONFIG_NUM_OPTION_TYPES: case CONFIG_NUM_OPTION_TYPES:
return strdup (""); value = strdup ("");
goto end;
} }
} }
@ -1129,11 +1278,19 @@ eval_replace_vars_cb (void *data, const char *text)
{ {
ptr_value = hashtable_get (ptr_buffer->local_variables, text); ptr_value = hashtable_get (ptr_buffer->local_variables, text);
if (ptr_value) if (ptr_value)
return strdup (ptr_value); {
value = strdup (ptr_value);
goto end;
}
} }
/* 21. hdata */ /* 21. hdata */
return eval_string_hdata (text, eval_context); value = eval_string_hdata (text, eval_context);
end:
EVAL_DEBUG_RESULT(1, value);
return value;
} }
/* /*
@ -1147,8 +1304,10 @@ eval_replace_vars (const char *expr, struct t_eval_context *eval_context)
{ {
const char *no_replace_prefix_list[] = { "if:", NULL }; const char *no_replace_prefix_list[] = { "if:", NULL };
char *result; char *result;
int debug_id;
EVAL_DEBUG(1, "eval_replace_vars(\"%s\")", expr); debug_id = -1;
EVAL_DEBUG_MSG(1, "eval_replace_vars(\"%s\")", expr);
eval_context->recursion_count++; eval_context->recursion_count++;
@ -1169,6 +1328,8 @@ eval_replace_vars (const char *expr, struct t_eval_context *eval_context)
eval_context->recursion_count--; eval_context->recursion_count--;
EVAL_DEBUG_RESULT(1, result);
return result; return result;
} }
@ -1190,13 +1351,14 @@ char *
eval_compare (const char *expr1, int comparison, const char *expr2, eval_compare (const char *expr1, int comparison, const char *expr2,
struct t_eval_context *eval_context) struct t_eval_context *eval_context)
{ {
int rc, string_compare, length1, length2; int rc, string_compare, length1, length2, debug_id;
regex_t regex; regex_t regex;
double value1, value2; double value1, value2;
char *error; char *error, *value;
EVAL_DEBUG(1, "eval_compare(\"%s\", \"%s\", \"%s\")", debug_id = -1;
expr1, comparisons[comparison], expr2); EVAL_DEBUG_MSG(1, "eval_compare(\"%s\", \"%s\", \"%s\")",
expr1, comparisons[comparison], expr2);
rc = 0; rc = 0;
string_compare = 0; string_compare = 0;
@ -1309,7 +1471,11 @@ eval_compare (const char *expr1, int comparison, const char *expr2,
} }
end: end:
return strdup ((rc) ? EVAL_STR_TRUE : EVAL_STR_FALSE); value = strdup ((rc) ? EVAL_STR_TRUE : EVAL_STR_FALSE);
EVAL_DEBUG_RESULT(1, value);
return value;
} }
/* /*
@ -1324,19 +1490,24 @@ char *
eval_expression_condition (const char *expr, eval_expression_condition (const char *expr,
struct t_eval_context *eval_context) struct t_eval_context *eval_context)
{ {
int logic, comp, length, level, rc; int logic, comp, length, level, rc, debug_id;
const char *pos, *pos_end; const char *pos, *pos_end;
char *expr2, *sub_expr, *value, *tmp_value, *tmp_value2; char *expr2, *sub_expr, *value, *tmp_value, *tmp_value2;
EVAL_DEBUG(1, "eval_expression_condition(\"%s\")", expr); debug_id = -1;
EVAL_DEBUG_MSG(1, "eval_expression_condition(\"%s\")", expr);
value = NULL; value = NULL;
expr2 = NULL;
if (!expr) if (!expr)
return NULL; goto end;
if (!expr[0]) if (!expr[0])
return strdup (expr); {
value = strdup (expr);
goto end;
}
/* skip spaces at beginning of string */ /* skip spaces at beginning of string */
while (expr[0] == ' ') while (expr[0] == ' ')
@ -1344,7 +1515,10 @@ eval_expression_condition (const char *expr,
expr++; expr++;
} }
if (!expr[0]) if (!expr[0])
return strdup (expr); {
value = strdup (expr);
goto end;
}
/* skip spaces at end of string */ /* skip spaces at end of string */
pos_end = expr + strlen (expr) - 1; pos_end = expr + strlen (expr) - 1;
@ -1355,7 +1529,7 @@ eval_expression_condition (const char *expr,
expr2 = string_strndup (expr, pos_end + 1 - expr); expr2 = string_strndup (expr, pos_end + 1 - expr);
if (!expr2) if (!expr2)
return NULL; goto end;
/* /*
* search for a logical operator, and if one is found: * search for a logical operator, and if one is found:
@ -1530,6 +1704,8 @@ end:
if (expr2) if (expr2)
free (expr2); free (expr2);
EVAL_DEBUG_RESULT(1, value);
return value; return value;
} }
@ -1562,20 +1738,23 @@ eval_replace_regex (const char *string, regex_t *regex, const char *replace,
struct t_eval_context *eval_context) struct t_eval_context *eval_context)
{ {
char *result, *result2, *str_replace; char *result, *result2, *str_replace;
int length, length_replace, start_offset, i, rc, end; int length, length_replace, start_offset, i, rc, end, debug_id;
int empty_replace_allowed; int empty_replace_allowed;
struct t_eval_regex eval_regex; struct t_eval_regex eval_regex;
EVAL_DEBUG(1, "eval_replace_regex(\"%s\", 0x%lx, \"%s\")", result = NULL;
string, regex, replace);
debug_id = -1;
EVAL_DEBUG_MSG(1, "eval_replace_regex(\"%s\", 0x%lx, \"%s\")",
string, regex, replace);
if (!string || !regex || !replace) if (!string || !regex || !replace)
return NULL; goto end;
length = strlen (string) + 1; length = strlen (string) + 1;
result = malloc (length); result = malloc (length);
if (!result) if (!result)
return NULL; goto end;
snprintf (result, length, "%s", string); snprintf (result, length, "%s", string);
eval_context->regex = &eval_regex; eval_context->regex = &eval_regex;
@ -1636,7 +1815,8 @@ eval_replace_regex (const char *string, regex_t *regex, const char *replace,
if (!result2) if (!result2)
{ {
free (result); free (result);
return NULL; result = NULL;
goto end;
} }
result2[0] = '\0'; result2[0] = '\0';
if (eval_regex.match[0].rm_so > 0) if (eval_regex.match[0].rm_so > 0)
@ -1663,6 +1843,9 @@ eval_replace_regex (const char *string, regex_t *regex, const char *replace,
break; break;
} }
end:
EVAL_DEBUG_RESULT(1, result);
return result; return result;
} }
@ -1712,7 +1895,7 @@ eval_expression (const char *expr, struct t_hashtable *pointers,
struct t_hashtable *extra_vars, struct t_hashtable *options) struct t_hashtable *extra_vars, struct t_hashtable *options)
{ {
struct t_eval_context context, *eval_context; struct t_eval_context context, *eval_context;
int condition, rc, pointers_allocated, regex_allocated; int condition, rc, pointers_allocated, regex_allocated, debug_id;
int ptr_window_added, ptr_buffer_added; int ptr_window_added, ptr_buffer_added;
long number; long number;
char *value, *error; char *value, *error;
@ -1760,7 +1943,9 @@ eval_expression (const char *expr, struct t_hashtable *pointers,
eval_context->regex = NULL; eval_context->regex = NULL;
eval_context->recursion_count = 0; eval_context->recursion_count = 0;
eval_context->debug_level = 0; eval_context->debug_level = 0;
eval_context->debug = NULL; eval_context->debug_depth = 0;
eval_context->debug_id = 0;
eval_context->debug_output = NULL;
/* /*
* set window/buffer with pointer to current window/buffer * set window/buffer with pointer to current window/buffer
@ -1839,12 +2024,13 @@ eval_expression (const char *expr, struct t_hashtable *pointers,
if (error && !error[0] && (number >= 1)) if (error && !error[0] && (number >= 1))
{ {
eval_context->debug_level = (int)number; eval_context->debug_level = (int)number;
eval_context->debug = string_dyn_alloc (256); eval_context->debug_output = string_dyn_alloc (256);
} }
} }
} }
EVAL_DEBUG(1, "eval_expression(\"%s\")", expr); debug_id = -1;
EVAL_DEBUG_MSG(1, "eval_expression(\"%s\")", expr);
/* evaluate expression */ /* evaluate expression */
if (condition) if (condition)
@ -1888,10 +2074,13 @@ eval_expression (const char *expr, struct t_hashtable *pointers,
free (regex); free (regex);
} }
if (options && eval_context->debug) EVAL_DEBUG_RESULT(1, value);
hashtable_set (options, "debug_output", *(eval_context->debug));
if (eval_context->debug) /* set debug in options hashtable */
string_dyn_free (eval_context->debug, 1); if (options && eval_context->debug_output)
hashtable_set (options, "debug_output", *(eval_context->debug_output));
if (eval_context->debug_output)
string_dyn_free (eval_context->debug_output, 1);
return value; return value;
} }

View File

@ -79,7 +79,9 @@ struct t_eval_context
struct t_eval_regex *regex; /* in case of replace with regex */ struct t_eval_regex *regex; /* in case of replace with regex */
int recursion_count; /* to prevent infinite recursion */ int recursion_count; /* to prevent infinite recursion */
int debug_level; /* 0: no debug, 1: debug, 2: extra */ int debug_level; /* 0: no debug, 1: debug, 2: extra */
char **debug; /* not NULL if debug_level >= 1 */ int debug_depth; /* used for debug indentation */
int debug_id; /* operation id in debug output */
char **debug_output; /* string with debug output */
}; };
extern int eval_is_true (const char *value); extern int eval_is_true (const char *value);

View File

@ -282,13 +282,20 @@ TEST(CoreEval, EvalCondition)
hashtable_set (options, "debug", "1"); hashtable_set (options, "debug", "1");
WEE_CHECK_EVAL("1", "abc < def"); WEE_CHECK_EVAL("1", "abc < def");
ptr_debug_output = (const char *)hashtable_get (options, "debug_output"); ptr_debug_output = (const char *)hashtable_get (options, "debug_output");
STRCMP_EQUAL("eval_expression(\"abc < def\")\n" STRCMP_EQUAL("1:eval_expression(\"abc < def\")\n"
"eval_expression_condition(\"abc < def\")\n" " 2:eval_expression_condition(\"abc < def\")\n"
"eval_expression_condition(\"abc\")\n" " 3:eval_expression_condition(\"abc\")\n"
"eval_replace_vars(\"abc\")\n" " 4:eval_replace_vars(\"abc\")\n"
"eval_expression_condition(\"def\")\n" " 4:== \"abc\"\n"
"eval_replace_vars(\"def\")\n" " 3:== \"abc\"\n"
"eval_compare(\"abc\", \"<\", \"def\")", " 5:eval_expression_condition(\"def\")\n"
" 6:eval_replace_vars(\"def\")\n"
" 6:== \"def\"\n"
" 5:== \"def\"\n"
" 7:eval_compare(\"abc\", \"<\", \"def\")\n"
" 7:== \"1\"\n"
" 2:== \"1\"\n"
"1:== \"1\"",
ptr_debug_output); ptr_debug_output);
hashtable_remove (options, "debug"); hashtable_remove (options, "debug");
hashtable_remove (options, "debug_output"); hashtable_remove (options, "debug_output");
@ -297,66 +304,126 @@ TEST(CoreEval, EvalCondition)
hashtable_set (options, "debug", "2"); hashtable_set (options, "debug", "2");
WEE_CHECK_EVAL("1", "abc < def"); WEE_CHECK_EVAL("1", "abc < def");
ptr_debug_output = (const char *)hashtable_get (options, "debug_output"); ptr_debug_output = (const char *)hashtable_get (options, "debug_output");
STRCMP_EQUAL("eval_expression(\"abc < def\")\n" STRCMP_EQUAL(
"eval_expression_condition(\"abc < def\")\n" "1:eval_expression(\"abc < def\")\n"
"eval_strstr_level(\"abc < def\", \"||\", \"(\", \")\", 0)\n" " 2:eval_expression_condition(\"abc < def\")\n"
"eval_strstr_level(\"abc < def\", \"&&\", \"(\", \")\", 0)\n" " 3:eval_strstr_level(\"abc < def\", \"||\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc < def\", \"=~\", \"(\", \")\", 0)\n" " 3:== null\n"
"eval_strstr_level(\"abc < def\", \"!~\", \"(\", \")\", 0)\n" " 4:eval_strstr_level(\"abc < def\", \"&&\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc < def\", \"==*\", \"(\", \")\", 0)\n" " 4:== null\n"
"eval_strstr_level(\"abc < def\", \"!!*\", \"(\", \")\", 0)\n" " 5:eval_strstr_level(\"abc < def\", \"=~\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc < def\", \"=*\", \"(\", \")\", 0)\n" " 5:== null\n"
"eval_strstr_level(\"abc < def\", \"!*\", \"(\", \")\", 0)\n" " 6:eval_strstr_level(\"abc < def\", \"!~\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc < def\", \"==-\", \"(\", \")\", 0)\n" " 6:== null\n"
"eval_strstr_level(\"abc < def\", \"!!-\", \"(\", \")\", 0)\n" " 7:eval_strstr_level(\"abc < def\", \"==*\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc < def\", \"=-\", \"(\", \")\", 0)\n" " 7:== null\n"
"eval_strstr_level(\"abc < def\", \"!-\", \"(\", \")\", 0)\n" " 8:eval_strstr_level(\"abc < def\", \"!!*\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc < def\", \"==\", \"(\", \")\", 0)\n" " 8:== null\n"
"eval_strstr_level(\"abc < def\", \"!=\", \"(\", \")\", 0)\n" " 9:eval_strstr_level(\"abc < def\", \"=*\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc < def\", \"<=\", \"(\", \")\", 0)\n" " 9:== null\n"
"eval_strstr_level(\"abc < def\", \"<\", \"(\", \")\", 0)\n" " 10:eval_strstr_level(\"abc < def\", \"!*\", \"(\", \")\", 0)\n"
"eval_expression_condition(\"abc\")\n" " 10:== null\n"
"eval_strstr_level(\"abc\", \"||\", \"(\", \")\", 0)\n" " 11:eval_strstr_level(\"abc < def\", \"==-\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc\", \"&&\", \"(\", \")\", 0)\n" " 11:== null\n"
"eval_strstr_level(\"abc\", \"=~\", \"(\", \")\", 0)\n" " 12:eval_strstr_level(\"abc < def\", \"!!-\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc\", \"!~\", \"(\", \")\", 0)\n" " 12:== null\n"
"eval_strstr_level(\"abc\", \"==*\", \"(\", \")\", 0)\n" " 13:eval_strstr_level(\"abc < def\", \"=-\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc\", \"!!*\", \"(\", \")\", 0)\n" " 13:== null\n"
"eval_strstr_level(\"abc\", \"=*\", \"(\", \")\", 0)\n" " 14:eval_strstr_level(\"abc < def\", \"!-\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc\", \"!*\", \"(\", \")\", 0)\n" " 14:== null\n"
"eval_strstr_level(\"abc\", \"==-\", \"(\", \")\", 0)\n" " 15:eval_strstr_level(\"abc < def\", \"==\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc\", \"!!-\", \"(\", \")\", 0)\n" " 15:== null\n"
"eval_strstr_level(\"abc\", \"=-\", \"(\", \")\", 0)\n" " 16:eval_strstr_level(\"abc < def\", \"!=\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc\", \"!-\", \"(\", \")\", 0)\n" " 16:== null\n"
"eval_strstr_level(\"abc\", \"==\", \"(\", \")\", 0)\n" " 17:eval_strstr_level(\"abc < def\", \"<=\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc\", \"!=\", \"(\", \")\", 0)\n" " 17:== null\n"
"eval_strstr_level(\"abc\", \"<=\", \"(\", \")\", 0)\n" " 18:eval_strstr_level(\"abc < def\", \"<\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"abc\", \"<\", \"(\", \")\", 0)\n" " 18:== \"< def\"\n"
"eval_strstr_level(\"abc\", \">=\", \"(\", \")\", 0)\n" " 19:eval_expression_condition(\"abc\")\n"
"eval_strstr_level(\"abc\", \">\", \"(\", \")\", 0)\n" " 20:eval_strstr_level(\"abc\", \"||\", \"(\", \")\", 0)\n"
"eval_replace_vars(\"abc\")\n" " 20:== null\n"
"eval_expression_condition(\"def\")\n" " 21:eval_strstr_level(\"abc\", \"&&\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"def\", \"||\", \"(\", \")\", 0)\n" " 21:== null\n"
"eval_strstr_level(\"def\", \"&&\", \"(\", \")\", 0)\n" " 22:eval_strstr_level(\"abc\", \"=~\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"def\", \"=~\", \"(\", \")\", 0)\n" " 22:== null\n"
"eval_strstr_level(\"def\", \"!~\", \"(\", \")\", 0)\n" " 23:eval_strstr_level(\"abc\", \"!~\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"def\", \"==*\", \"(\", \")\", 0)\n" " 23:== null\n"
"eval_strstr_level(\"def\", \"!!*\", \"(\", \")\", 0)\n" " 24:eval_strstr_level(\"abc\", \"==*\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"def\", \"=*\", \"(\", \")\", 0)\n" " 24:== null\n"
"eval_strstr_level(\"def\", \"!*\", \"(\", \")\", 0)\n" " 25:eval_strstr_level(\"abc\", \"!!*\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"def\", \"==-\", \"(\", \")\", 0)\n" " 25:== null\n"
"eval_strstr_level(\"def\", \"!!-\", \"(\", \")\", 0)\n" " 26:eval_strstr_level(\"abc\", \"=*\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"def\", \"=-\", \"(\", \")\", 0)\n" " 26:== null\n"
"eval_strstr_level(\"def\", \"!-\", \"(\", \")\", 0)\n" " 27:eval_strstr_level(\"abc\", \"!*\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"def\", \"==\", \"(\", \")\", 0)\n" " 27:== null\n"
"eval_strstr_level(\"def\", \"!=\", \"(\", \")\", 0)\n" " 28:eval_strstr_level(\"abc\", \"==-\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"def\", \"<=\", \"(\", \")\", 0)\n" " 28:== null\n"
"eval_strstr_level(\"def\", \"<\", \"(\", \")\", 0)\n" " 29:eval_strstr_level(\"abc\", \"!!-\", \"(\", \")\", 0)\n"
"eval_strstr_level(\"def\", \">=\", \"(\", \")\", 0)\n" " 29:== null\n"
"eval_strstr_level(\"def\", \">\", \"(\", \")\", 0)\n" " 30:eval_strstr_level(\"abc\", \"=-\", \"(\", \")\", 0)\n"
"eval_replace_vars(\"def\")\n" " 30:== null\n"
"eval_compare(\"abc\", \"<\", \"def\")", " 31:eval_strstr_level(\"abc\", \"!-\", \"(\", \")\", 0)\n"
ptr_debug_output); " 31:== null\n"
" 32:eval_strstr_level(\"abc\", \"==\", \"(\", \")\", 0)\n"
" 32:== null\n"
" 33:eval_strstr_level(\"abc\", \"!=\", \"(\", \")\", 0)\n"
" 33:== null\n"
" 34:eval_strstr_level(\"abc\", \"<=\", \"(\", \")\", 0)\n"
" 34:== null\n"
" 35:eval_strstr_level(\"abc\", \"<\", \"(\", \")\", 0)\n"
" 35:== null\n"
" 36:eval_strstr_level(\"abc\", \">=\", \"(\", \")\", 0)\n"
" 36:== null\n"
" 37:eval_strstr_level(\"abc\", \">\", \"(\", \")\", 0)\n"
" 37:== null\n"
" 38:eval_replace_vars(\"abc\")\n"
" 38:== \"abc\"\n"
" 19:== \"abc\"\n"
" 39:eval_expression_condition(\"def\")\n"
" 40:eval_strstr_level(\"def\", \"||\", \"(\", \")\", 0)\n"
" 40:== null\n"
" 41:eval_strstr_level(\"def\", \"&&\", \"(\", \")\", 0)\n"
" 41:== null\n"
" 42:eval_strstr_level(\"def\", \"=~\", \"(\", \")\", 0)\n"
" 42:== null\n"
" 43:eval_strstr_level(\"def\", \"!~\", \"(\", \")\", 0)\n"
" 43:== null\n"
" 44:eval_strstr_level(\"def\", \"==*\", \"(\", \")\", 0)\n"
" 44:== null\n"
" 45:eval_strstr_level(\"def\", \"!!*\", \"(\", \")\", 0)\n"
" 45:== null\n"
" 46:eval_strstr_level(\"def\", \"=*\", \"(\", \")\", 0)\n"
" 46:== null\n"
" 47:eval_strstr_level(\"def\", \"!*\", \"(\", \")\", 0)\n"
" 47:== null\n"
" 48:eval_strstr_level(\"def\", \"==-\", \"(\", \")\", 0)\n"
" 48:== null\n"
" 49:eval_strstr_level(\"def\", \"!!-\", \"(\", \")\", 0)\n"
" 49:== null\n"
" 50:eval_strstr_level(\"def\", \"=-\", \"(\", \")\", 0)\n"
" 50:== null\n"
" 51:eval_strstr_level(\"def\", \"!-\", \"(\", \")\", 0)\n"
" 51:== null\n"
" 52:eval_strstr_level(\"def\", \"==\", \"(\", \")\", 0)\n"
" 52:== null\n"
" 53:eval_strstr_level(\"def\", \"!=\", \"(\", \")\", 0)\n"
" 53:== null\n"
" 54:eval_strstr_level(\"def\", \"<=\", \"(\", \")\", 0)\n"
" 54:== null\n"
" 55:eval_strstr_level(\"def\", \"<\", \"(\", \")\", 0)\n"
" 55:== null\n"
" 56:eval_strstr_level(\"def\", \">=\", \"(\", \")\", 0)\n"
" 56:== null\n"
" 57:eval_strstr_level(\"def\", \">\", \"(\", \")\", 0)\n"
" 57:== null\n"
" 58:eval_replace_vars(\"def\")\n"
" 58:== \"def\"\n"
" 39:== \"def\"\n"
" 59:eval_compare(\"abc\", \"<\", \"def\")\n"
" 59:== \"1\"\n"
" 2:== \"1\"\n"
"1:== \"1\"",
ptr_debug_output);
hashtable_remove (options, "debug"); hashtable_remove (options, "debug");
hashtable_remove (options, "debug_output"); hashtable_remove (options, "debug_output");
@ -702,7 +769,7 @@ TEST(CoreEval, EvalExpression)
WEE_CHECK_EVAL("1", "<<<buffer.number>>>"); WEE_CHECK_EVAL("1", "<<<buffer.number>>>");
hashtable_free (options); hashtable_free (options);
/* test with debug */ /* test with debug level 1 */
options = hashtable_new (32, options = hashtable_new (32,
WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_STRING,
@ -711,9 +778,30 @@ TEST(CoreEval, EvalExpression)
hashtable_set (options, "debug", "1"); hashtable_set (options, "debug", "1");
WEE_CHECK_EVAL("fedcba", "${rev:abcdef}"); WEE_CHECK_EVAL("fedcba", "${rev:abcdef}");
ptr_debug_output = (const char *)hashtable_get (options, "debug_output"); ptr_debug_output = (const char *)hashtable_get (options, "debug_output");
STRCMP_EQUAL("eval_expression(\"${rev:abcdef}\")\n" STRCMP_EQUAL("1:eval_expression(\"${rev:abcdef}\")\n"
"eval_replace_vars(\"${rev:abcdef}\")\n" " 2:eval_replace_vars(\"${rev:abcdef}\")\n"
"eval_replace_vars_cb(\"rev:abcdef\")", " 3:eval_replace_vars_cb(\"rev:abcdef\")\n"
" 3:== \"fedcba\"\n"
" 2:== \"fedcba\"\n"
"1:== \"fedcba\"",
ptr_debug_output);
hashtable_free (options);
/* test with debug level 2 */
options = hashtable_new (32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL, NULL);
CHECK(options);
hashtable_set (options, "debug", "2");
WEE_CHECK_EVAL("fedcba", "${rev:abcdef}");
ptr_debug_output = (const char *)hashtable_get (options, "debug_output");
STRCMP_EQUAL("1:eval_expression(\"${rev:abcdef}\")\n"
" 2:eval_replace_vars(\"${rev:abcdef}\")\n"
" 3:eval_replace_vars_cb(\"rev:abcdef\")\n"
" 3:== \"fedcba\"\n"
" 2:== \"fedcba\"\n"
"1:== \"fedcba\"",
ptr_debug_output); ptr_debug_output);
hashtable_free (options); hashtable_free (options);