diff options
author | Sébastien Helleu <flashcode@flashtux.org> | 2022-10-03 20:56:12 +0200 |
---|---|---|
committer | Sébastien Helleu <flashcode@flashtux.org> | 2022-11-05 22:34:38 +0100 |
commit | 196a0511418a7a1f406db45d23abd4697ad7f905 (patch) | |
tree | 85cac7f2989f04222823f1910438bf40ea415907 /src/core | |
parent | bc2fb071e22589aa219ce551b0112bacbd3cca8f (diff) | |
download | weechat-196a0511418a7a1f406db45d23abd4697ad7f905.zip |
core: add range of chars in evaluation of expressions with `chars:xxx`
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/wee-command.c | 61 | ||||
-rw-r--r-- | src/core/wee-eval.c | 241 | ||||
-rw-r--r-- | src/core/wee-eval.h | 7 |
3 files changed, 198 insertions, 111 deletions
diff --git a/src/core/wee-command.c b/src/core/wee-command.c index 5994ebbe7..c9052676b 100644 --- a/src/core/wee-command.c +++ b/src/core/wee-command.c @@ -7753,45 +7753,48 @@ command_init () "\n" "Some variables are replaced in expression, using the format " "${variable}, variable can be, by order of priority:\n" - " 1. the string itself without evaluation (format: \"raw:xxx\")\n" - " 2. a user-defined variable (format: \"name\")\n" - " 3. an evaluated sub-string (format: \"eval:xxx\")\n" - " 4. an evaluated condition (format: \"eval_cond:xxx\")\n" - " 5. a string with escaped chars (format: \"esc:xxx\" or \"\\xxx\")\n" - " 6. a string converted to lower case (format: \"lower:xxx\")\n" - " 7. a string converted to upper case (format: \"upper:xxx\")\n" - " 8. a string with chars to hide (format: \"hide:char,string\")\n" - " 9. a string with max chars (format: \"cut:max,suffix,string\" " + " - the string itself without evaluation (format: \"raw:xxx\")\n" + " - a user-defined variable (format: \"name\")\n" + " - an evaluated sub-string (format: \"eval:xxx\")\n" + " - an evaluated condition (format: \"eval_cond:xxx\")\n" + " - a string with escaped chars (format: \"esc:xxx\" or \"\\xxx\")\n" + " - a string with a range of chars (format: \"chars:xxx\" or " + "\"chars:c1-c2\" where \"xxx\" is one of: \"digit\", \"xdigit\", " + "\"lower\", \"upper\", \"alpha\", \"alnum\")\n" + " - a string converted to lower case (format: \"lower:xxx\")\n" + " - a string converted to upper case (format: \"upper:xxx\")\n" + " - a string with chars to hide (format: \"hide:char,string\")\n" + " - a string with max chars (format: \"cut:max,suffix,string\" " "or \"cut:+max,suffix,string\")\n" " or max chars displayed on screen " "(format: \"cutscr:max,suffix,string\" or " "\"cutscr:+max,suffix,string\")\n" - " 10. a reversed string (format: \"rev:xxx\" or \"revscr:xxx\")\n" - " 11. a repeated string (format: \"repeat:count,string\")\n" - " 12. length of a string (format: \"length:xxx\" or " + " - a reversed string (format: \"rev:xxx\" or \"revscr:xxx\")\n" + " - a repeated string (format: \"repeat:count,string\")\n" + " - length of a string (format: \"length:xxx\" or " "\"lengthscr:xxx\")\n" - " 13. split of a string (format: " + " - split of a string (format: " "\"split:number,separators,flags,xxx\")\n" - " 14. split of shell argmuents (format: \"split_shell:number,xxx\")\n" - " 15. a color (format: \"color:xxx\", see \"Plugin API " + " - split of shell argmuents (format: \"split_shell:number,xxx\")\n" + " - a color (format: \"color:xxx\", see \"Plugin API " "reference\", function \"color\")\n" - " 16. a modifier (format: \"modifier:name,data,string\")\n" - " 17. an info (format: \"info:name,arguments\", arguments are " + " - a modifier (format: \"modifier:name,data,string\")\n" + " - an info (format: \"info:name,arguments\", arguments are " "optional)\n" - " 18. a base 16/32/64 encoded/decoded string (format: " + " - a base 16/32/64 encoded/decoded string (format: " "\"base_encode:base,xxx\" or \"base_decode:base,xxx\")\n" - " 19. current date/time (format: \"date\" or \"date:format\")\n" - " 20. an environment variable (format: \"env:XXX\")\n" - " 21. a ternary operator (format: " + " - current date/time (format: \"date\" or \"date:format\")\n" + " - an environment variable (format: \"env:XXX\")\n" + " - a ternary operator (format: " "\"if:condition?value_if_true:value_if_false\")\n" - " 22. result of an expression with parentheses and operators " + " - result of an expression with parentheses and operators " "+ - * / // % ** (format: \"calc:xxx\")\n" - " 23. a random integer number (format: \"random:min,max\")\n" - " 24. a translated string (format: \"translate:xxx\")\n" - " 25. define a user variable (format: \"define:name,value\")\n" - " 26. an option (format: \"file.section.option\")\n" - " 27. a local variable in buffer\n" - " 28. a hdata name/variable (the value is automatically converted " + " - a random integer number (format: \"random:min,max\")\n" + " - a translated string (format: \"translate:xxx\")\n" + " - define a user variable (format: \"define:name,value\")\n" + " - an option (format: \"file.section.option\")\n" + " - a local variable in buffer\n" + " - 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" @@ -7824,6 +7827,8 @@ command_init () " /eval -n ${window.buffer.full_name} ==> core.weechat\n" " /eval -n ${window.buffer.number} ==> 1\n" " /eval -n ${\\t} ==> <tab>\n" + " /eval -n ${chars:digit} ==> 0123456789\n" + " /eval -n ${chars:J-T} ==> JKLMNOPQRST\n" " /eval -n ${lower:TEST} ==> test\n" " /eval -n ${upper:test} ==> TEST\n" " /eval -n ${hide:-,${relay.network.password}} ==> --------\n" diff --git a/src/core/wee-eval.c b/src/core/wee-eval.c index dbec3a39f..7d892b125 100644 --- a/src/core/wee-eval.c +++ b/src/core/wee-eval.c @@ -63,10 +63,10 @@ } -char *logical_ops[EVAL_NUM_LOGICAL_OPS] = +char *eval_logical_ops[EVAL_NUM_LOGICAL_OPS] = { "||", "&&" }; -char *comparisons[EVAL_NUM_COMPARISONS] = +char *eval_comparisons[EVAL_NUM_COMPARISONS] = { "=~", "!~", /* regex */ "==*", "!!*", "=*", "!*", /* string match */ "==-", "!!-", "=-", "!-", /* includes */ @@ -74,6 +74,16 @@ char *comparisons[EVAL_NUM_COMPARISONS] = "<=", "<", ">=", ">", /* less than, greater than */ }; +char *eval_range_chars[][2] = +{ + { "digit", EVAL_RANGE_DIGIT }, + { "xdigit", EVAL_RANGE_XDIGIT }, + { "lower", EVAL_RANGE_LOWER }, + { "upper", EVAL_RANGE_UPPER }, + { "alpha", EVAL_RANGE_ALPHA }, + { "alnum", EVAL_RANGE_ALNUM }, + { NULL, NULL }, +}; char *eval_replace_vars (const char *expr, struct t_eval_context *eval_context); @@ -274,6 +284,65 @@ eval_string_eval_cond (const char *text, struct t_eval_context *eval_context) } /* + * Adds range of chars. + * + * Note: result must be freed after use. + */ + +char * +eval_string_range_chars (const char *range) +{ + int i, char1, char2; + const char *ptr_char; + char **string, str_char[16], *result; + + string = NULL; + result = NULL; + + for (i = 0; eval_range_chars[i][0]; i++) + { + if (strcmp (range, eval_range_chars[i][0]) == 0) + return strdup (eval_range_chars[i][1]); + } + + char1 = utf8_char_int (range); + + /* next char must be '-' */ + ptr_char = utf8_next_char (range); + if (!ptr_char || !ptr_char[0] || (ptr_char[0] != '-')) + goto end; + + /* next char is the char2 */ + ptr_char = utf8_next_char (ptr_char); + if (!ptr_char || !ptr_char[0]) + goto end; + char2 = utf8_char_int (ptr_char); + + /* output is limited to 1024 chars (not bytes) */ + if ((char1 > char2) || (char2 - char1 + 1 > 4096)) + goto end; + + string = string_dyn_alloc (128); + if (!string) + goto end; + + for (i = char1; i <= char2; i++) + { + utf8_int_string (i, str_char); + string_dyn_concat (string, str_char, -1); + } + +end: + if (string) + { + result = *string; + string_dyn_free (string, 0); + } + + return (result) ? result : strdup (""); +} + +/* * Converts string to lower case. * * Note: result must be freed after use. @@ -1414,48 +1483,49 @@ end: /* * Replaces variables, which can be, by order of priority: - * 1. the string itself without evaluation (format: raw:xxx) - * 2. a variable from hashtable "user_vars" or "extra_vars" - * 3. a WeeChat home directory, one of: "weechat_config_dir", - * "weechat_data_dir", "weechat_cache_dir", "weechat_runtime_dir" - * 4. a string to evaluate (format: eval:xxx) - * 5. a condition to evaluate (format: eval_cond:xxx) - * 6. a string with escaped chars (format: esc:xxx or \xxx) - * 7. a string converted to lower case (format: lower:xxx) - * 8. a string converted to upper case (format: upper:xxx) - * 9. a string with chars to hide (format: hide:char,string) - * 10. a string with max chars (format: cut:max,suffix,string or - * cut:+max,suffix,string) or max chars on screen - * (format: cutscr:max,suffix,string or cutscr:+max,suffix,string) - * 11. a reversed string (format: rev:xxx) or reversed string for screen, - * color codes are not reversed (format: revscr:xxx) - * 12. a repeated string (format: repeat:count,string) - * 13. length of a string (format: length:xxx) or length of a string on screen - * (format: lengthscr:xxx); color codes are ignored - * 14. split string (format: split:number,separators,flags,xxx - * or split:count,separators,flags,xxx - * or split:random,separators,flags,xxx) - * 15. split shell arguments (format: split:number,xxx or split:count,xxx - * or split:random,xxx) - * 16. a regex group captured (format: re:N (0.99) or re:+) - * 17. a color (format: color:xxx) - * 18. a modifier (format: modifier:name,data,xxx) - * 19. an info (format: info:name,arguments) - * 20. a base 16/32/64 encoded/decoded string (format: base_encode:base,xxx - * or base_decode:base,xxx) - * 21. current date/time (format: date or date:xxx) - * 22. an environment variable (format: env:XXX) - * 23. a ternary operator (format: if:condition?value_if_true:value_if_false) - * 24. calculate result of an expression (format: calc:xxx) - * 25. a random integer number in the range from "min" to "max" - * (format: random:min,max) - * 26. a translated string (format: translate:xxx) - * 27. define a new variable (format: define:name,value) - * 28. an option (format: file.section.option) - * 29. a buffer local variable - * 30. a pointer name from hashtable "pointers" - * 31. a hdata variable (format: hdata.var1.var2 or hdata[list].var1.var2 - * or hdata[ptr].var1.var2 or hdata[ptr_name].var1.var2) + * - the string itself without evaluation (format: raw:xxx) + * - a variable from hashtable "user_vars" or "extra_vars" + * - a WeeChat home directory, one of: "weechat_config_dir", + * "weechat_data_dir", "weechat_cache_dir", "weechat_runtime_dir" + * - a string to evaluate (format: eval:xxx) + * - a condition to evaluate (format: eval_cond:xxx) + * - a string with escaped chars (format: esc:xxx or \xxx) + * - a string with a range of chars (format: chars:xxx) + * - a string converted to lower case (format: lower:xxx) + * - a string converted to upper case (format: upper:xxx) + * - a string with chars to hide (format: hide:char,string) + * - a string with max chars (format: cut:max,suffix,string or + * cut:+max,suffix,string) or max chars on screen + * (format: cutscr:max,suffix,string or cutscr:+max,suffix,string) + * - a reversed string (format: rev:xxx) or reversed string for screen, + * color codes are not reversed (format: revscr:xxx) + * - a repeated string (format: repeat:count,string) + * - length of a string (format: length:xxx) or length of a string on screen + * (format: lengthscr:xxx); color codes are ignored + * - split string (format: split:number,separators,flags,xxx + * or split:count,separators,flags,xxx + * or split:random,separators,flags,xxx) + * - split shell arguments (format: split:number,xxx or split:count,xxx + * or split:random,xxx) + * - a regex group captured (format: re:N (0.99) or re:+) + * - a color (format: color:xxx) + * - a modifier (format: modifier:name,data,xxx) + * - an info (format: info:name,arguments) + * - a base 16/32/64 encoded/decoded string (format: base_encode:base,xxx + * or base_decode:base,xxx) + * - current date/time (format: date or date:xxx) + * - an environment variable (format: env:XXX) + * - a ternary operator (format: if:condition?value_if_true:value_if_false) + * - calculate result of an expression (format: calc:xxx) + * - a random integer number in the range from "min" to "max" + * (format: random:min,max) + * - a translated string (format: translate:xxx) + * - define a new variable (format: define:name,value) + * - an option (format: file.section.option) + * - a buffer local variable + * - a pointer name from hashtable "pointers" + * - a hdata variable (format: hdata.var1.var2 or hdata[list].var1.var2 + * or hdata[ptr].var1.var2 or hdata[ptr_name].var1.var2) * * See /help in WeeChat for examples. * @@ -1478,16 +1548,14 @@ eval_replace_vars_cb (void *data, const char *text) EVAL_DEBUG_MSG(1, "eval_replace_vars_cb(\"%s\")", text); - /* - * 1. raw text (no evaluation at all) - */ + /* raw text (no evaluation at all) */ if (strncmp (text, "raw:", 4) == 0) { value = strdup (text + 4); goto end; } - /* 2. variable in hashtable "user_vars" or "extra_vars" */ + /* variable in hashtable "user_vars" or "extra_vars" */ ptr_value = hashtable_get (eval_context->user_vars, text); if (ptr_value) { @@ -1518,7 +1586,7 @@ eval_replace_vars_cb (void *data, const char *text) } } - /* 3. WeeChat home directory */ + /* WeeChat home directory */ if (strcmp (text, "weechat_config_dir") == 0) { value = strdup (weechat_config_dir); @@ -1541,8 +1609,8 @@ eval_replace_vars_cb (void *data, const char *text) } /* - * 4. force evaluation of string (recursive call) - * --> use with caution: the text must be safe! + * force evaluation of string (recursive call) + * --> use with caution: the text must be safe! */ if (strncmp (text, "eval:", 5) == 0) { @@ -1551,8 +1619,8 @@ eval_replace_vars_cb (void *data, const char *text) } /* - * 5. force evaluation of condition (recursive call) - * --> use with caution: the text must be safe! + * force evaluation of condition (recursive call) + * --> use with caution: the text must be safe! */ if (strncmp (text, "eval_cond:", 10) == 0) { @@ -1560,7 +1628,7 @@ eval_replace_vars_cb (void *data, const char *text) goto end; } - /* 6. convert escaped chars */ + /* convert escaped chars */ if (strncmp (text, "esc:", 4) == 0) { value = string_convert_escaped_chars (text + 4); @@ -1572,21 +1640,28 @@ eval_replace_vars_cb (void *data, const char *text) goto end; } - /* 7. convert to lower case */ + /* range of chars */ + if (strncmp (text, "chars:", 6) == 0) + { + value = eval_string_range_chars (text + 6); + goto end; + } + + /* convert to lower case */ if (strncmp (text, "lower:", 6) == 0) { value = eval_string_lower (text + 6); goto end; } - /* 8. convert to upper case */ + /* convert to upper case */ if (strncmp (text, "upper:", 6) == 0) { value = eval_string_upper (text + 6); goto end; } - /* 9. hide chars: replace all chars by a given char/string */ + /* hide chars: replace all chars by a given char/string */ if (strncmp (text, "hide:", 5) == 0) { value = eval_string_hide (text + 5); @@ -1594,7 +1669,7 @@ eval_replace_vars_cb (void *data, const char *text) } /* - * 10. cut chars: + * cut chars: * cut: max number of chars, and add an optional suffix when the * string is cut * cutscr: max number of chars displayed on screen, and add an optional @@ -1611,7 +1686,7 @@ eval_replace_vars_cb (void *data, const char *text) goto end; } - /* 11. reverse string */ + /* reverse string */ if (strncmp (text, "rev:", 4) == 0) { value = string_reverse (text + 4); @@ -1623,7 +1698,7 @@ eval_replace_vars_cb (void *data, const char *text) goto end; } - /* 12. repeated string */ + /* repeated string */ if (strncmp (text, "repeat:", 7) == 0) { value = eval_string_repeat (text + 7); @@ -1631,7 +1706,7 @@ eval_replace_vars_cb (void *data, const char *text) } /* - * 13. length of string: + * length of string: * length: number of chars * lengthscr: number of chars displayed on screen */ @@ -1650,49 +1725,49 @@ eval_replace_vars_cb (void *data, const char *text) goto end; } - /* 14: split string */ + /* split string */ if (strncmp (text, "split:", 6) == 0) { value = eval_string_split (text + 6); goto end; } - /* 15: split shell */ + /* split shell */ if (strncmp (text, "split_shell:", 12) == 0) { value = eval_string_split_shell (text + 12); goto end; } - /* 16. regex group captured */ + /* regex group captured */ if (strncmp (text, "re:", 3) == 0) { value = eval_string_regex_group (text + 3, eval_context); goto end; } - /* 17. color code */ + /* color code */ if (strncmp (text, "color:", 6) == 0) { value = eval_string_color (text + 6); goto end; } - /* 18. modifier */ + /* modifier */ if (strncmp (text, "modifier:", 9) == 0) { value = eval_string_modifier (text + 9); goto end; } - /* 19. info */ + /* info */ if (strncmp (text, "info:", 5) == 0) { value = eval_string_info (text + 5); goto end; } - /* 20. base_encode/base_decode */ + /* base_encode/base_decode */ if (strncmp (text, "base_encode:", 12) == 0) { value = eval_string_base_encode (text + 12); @@ -1704,14 +1779,14 @@ eval_replace_vars_cb (void *data, const char *text) goto end; } - /* 21. current date/time */ + /* current date/time */ if ((strncmp (text, "date", 4) == 0) && (!text[4] || (text[4] == ':'))) { value = eval_string_date (text + 4); goto end; } - /* 22. environment variable */ + /* environment variable */ if (strncmp (text, "env:", 4) == 0) { ptr_value = getenv (text + 4); @@ -1719,7 +1794,7 @@ eval_replace_vars_cb (void *data, const char *text) goto end; } - /* 23: ternary operator: if:condition?value_if_true:value_if_false */ + /* ternary operator: if:condition?value_if_true:value_if_false */ if (strncmp (text, "if:", 3) == 0) { value = eval_string_if (text + 3, eval_context); @@ -1727,7 +1802,7 @@ eval_replace_vars_cb (void *data, const char *text) } /* - * 24. calculate the result of an expression + * calculate the result of an expression * (with number, operators and parentheses) */ if (strncmp (text, "calc:", 5) == 0) @@ -1737,7 +1812,7 @@ eval_replace_vars_cb (void *data, const char *text) } /* - * 25. random number + * random number */ if (strncmp (text, "random:", 7) == 0) { @@ -1746,7 +1821,7 @@ eval_replace_vars_cb (void *data, const char *text) } /* - * 26. translated text + * translated text */ if (strncmp (text, "translate:", 10) == 0) { @@ -1754,7 +1829,7 @@ eval_replace_vars_cb (void *data, const char *text) goto end; } - /* 27. define a variable */ + /* define a variable */ if (strncmp (text, "define:", 7) == 0) { eval_string_define (text + 7, eval_context); @@ -1762,7 +1837,7 @@ eval_replace_vars_cb (void *data, const char *text) goto end; } - /* 28. option: if found, return this value */ + /* option: if found, return this value */ if (strncmp (text, "sec.data.", 9) == 0) { ptr_value = hashtable_get (secure_hashtable_data, text + 9); @@ -1805,7 +1880,7 @@ eval_replace_vars_cb (void *data, const char *text) } } - /* 29. local variable in buffer */ + /* local variable in buffer */ ptr_buffer = hashtable_get (eval_context->pointers, "buffer"); if (ptr_buffer) { @@ -1817,7 +1892,7 @@ eval_replace_vars_cb (void *data, const char *text) } } - /* 30. hdata */ + /* hdata */ value = eval_string_hdata (text, eval_context); end: @@ -1889,7 +1964,7 @@ eval_compare (const char *expr1, int comparison, const char *expr2, char *error, *value; EVAL_DEBUG_MSG(1, "eval_compare(\"%s\", \"%s\", \"%s\")", - expr1, comparisons[comparison], expr2); + expr1, eval_comparisons[comparison], expr2); rc = 0; string_compare = 0; @@ -2070,7 +2145,7 @@ eval_expression_condition (const char *expr, */ for (logic = 0; logic < EVAL_NUM_LOGICAL_OPS; logic++) { - pos = eval_strstr_level (expr2, logical_ops[logic], eval_context, + pos = eval_strstr_level (expr2, eval_logical_ops[logic], eval_context, "(", ")", 0); if (pos > expr2) { @@ -2097,7 +2172,7 @@ eval_expression_condition (const char *expr, value = strdup ((rc) ? EVAL_STR_TRUE : EVAL_STR_FALSE); goto end; } - pos += strlen (logical_ops[logic]); + pos += strlen (eval_logical_ops[logic]); while (pos[0] == ' ') { pos++; @@ -2120,7 +2195,7 @@ eval_expression_condition (const char *expr, */ for (comp = 0; comp < EVAL_NUM_COMPARISONS; comp++) { - pos = eval_strstr_level (expr2, comparisons[comp], eval_context, + pos = eval_strstr_level (expr2, eval_comparisons[comp], eval_context, "(", ")", 0); if (pos >= expr2) { @@ -2139,7 +2214,7 @@ eval_expression_condition (const char *expr, } if (!sub_expr) goto end; - pos += strlen (comparisons[comp]); + pos += strlen (eval_comparisons[comp]); while (pos[0] == ' ') { pos++; diff --git a/src/core/wee-eval.h b/src/core/wee-eval.h index 22ec58403..944390190 100644 --- a/src/core/wee-eval.h +++ b/src/core/wee-eval.h @@ -30,6 +30,13 @@ #define EVAL_RECURSION_MAX 32 +#define EVAL_RANGE_DIGIT "0123456789" +#define EVAL_RANGE_XDIGIT EVAL_RANGE_DIGIT "abcdefABCDEF" +#define EVAL_RANGE_LOWER "abcdefghijklmnopqrstuvwxyz" +#define EVAL_RANGE_UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define EVAL_RANGE_ALPHA EVAL_RANGE_LOWER EVAL_RANGE_UPPER +#define EVAL_RANGE_ALNUM EVAL_RANGE_ALPHA EVAL_RANGE_DIGIT + struct t_hashtable; enum t_eval_logical_op |