diff --git a/ChangeLog.asciidoc b/ChangeLog.asciidoc index aba4adf84..3db27131b 100644 --- a/ChangeLog.asciidoc +++ b/ChangeLog.asciidoc @@ -23,6 +23,7 @@ http://weechat.org/files/releasenotes/ReleaseNotes-devel.html[release notes] of status bar * core: allow incomplete commands if unambiguous, new option weechat.look.command_incomplete (task #5419) +* api: add regex replace feature in function string_eval_expression * api: use microseconds instead of milliseconds in functions util_timeval_diff and util_timeval_add * irc: display own nick changes in server buffer (closes #188) diff --git a/doc/en/weechat_plugin_api.en.asciidoc b/doc/en/weechat_plugin_api.en.asciidoc index 99017b3e6..ae25da2b6 100644 --- a/doc/en/weechat_plugin_api.en.asciidoc +++ b/doc/en/weechat_plugin_api.en.asciidoc @@ -1826,11 +1826,10 @@ str3 = weechat.string_input_for_buffer("//test") # "/test" ==== weechat_string_eval_expression -_WeeChat ≥ 0.4.0, updated in 0.4.2._ +_WeeChat ≥ 0.4.0, updated in 0.4.2 and 1.1._ Evaluate an expression and return result as a string. -Special variables with format `${variable}` are expanded (see command `/eval` in -'WeeChat User's guide'). +Special variables with format `${variable}` are expanded (see table below). [NOTE] Since version 1.0, nested variables are supported, for example: @@ -1848,10 +1847,14 @@ char *weechat_string_eval_expression (const char *expr, Arguments: -* 'expr': the expression to evaluate +* 'expr': the expression to evaluate (see table below) * 'pointers': hashtable with pointers (keys must be string, values must be pointer); pointers "window" and "buffer" are automatically added if they are - not in hashtable (with pointer to current window/buffer) (can be NULL) + not in hashtable (with pointer to current window/buffer) (can be NULL): +** 'regex': pointer to a regular expression ('regex_t' structure) compiled with + WeeChat function <<_weechat_string_regcomp,weechat_string_regcomp>> or + regcomp (see `man regcomp`); this option is similar to 'regex' in hashtable + 'options' (below), but is used for better performance * 'extra_vars': extra variables that will be expanded (can be NULL) * 'options': a hashtable with some options (keys and values must be string) (can be NULL): @@ -1861,26 +1864,118 @@ Arguments: parentheses are used, result is a boolean ("0" or "1") ** 'prefix': prefix before variables to replace (default: "${") ** 'suffix': suffix after variables to replace (default: "}") +** 'regex': a regex used to replace text in 'expr' (which is then not + evaluated) +** 'regex_replace': the replacement text to use with 'regex', to replace + text in 'expr' (the 'regex_replace' is evaluated on each match of 'regex' + against 'expr', until no match is found) Return value: * evaluated expression (must be freed by calling "free" after use), or NULL if problem (invalid expression or not enough memory) +List of variables expanded in expression (by order of priority, from first +expanded to last): + +[width="100%",cols="2,8,3,3",options="header"] +|=== +| Format | Description | Examples | Results + +| `${name}` | Variable `name` from hashtable 'extra_vars' | + `${name}` | `value` + +| `${esc:xxx}` + + `${\xxx}` | String with escaped chars | + `${esc:prefix\tmessage}` + + `${\ua9}` | + `prefixmessage` + + `©` + +| `${hide:x,value}` | + String with hidden chars (all chars in `value` replaced `x`) | + `${hide:*,password}` | + `********` + +| `${re:N}` | + Regex captured group: 0 = whole string matching, 1 to 99 = group captured, + `+` = last group captured | + `${re:1}` | + `test` + +| `${color:name}` | + WeeChat color code (the name of color has optional attributes) | + `${color:red}red text` + + `${color:*214}bold orange text` | + `red text` (in red) + + `bold orange text` (in bold orange) + +| `${info:name}` + + `${indo:name,arguments}` | + Info from WeeChat or a plugin, see function + <<_weechat_info_get,weechat_info_get>> | + `${info:version}` + + `${info:irc_nick_color_name,foo}` | + `1.0` + + `lightblue` + +| `${sec.data.name}` | + Value of the secured data `name` | + `${sec.data.freenode_pass}` | + `my_password` + +| `${file.section.option}` | + Value of the option | + `${weechat.look.buffer_time_format}` | + `%H:%M:%S` + +| `${name}` | + Value of local variable `name` in buffer | + `${nick}` | + `FlashCode` + +| `${hdata.var1.var2...}` + + `${hdata[list].var1.var2...}` | + Hdata value (pointers `window` and `buffer` are set by default with current + window/buffer) | + `${buffer[gui_buffers].full_name}` + + `${window.buffer.number}` | + `core.weechat` + + `1` +|=== + C examples: [source,C] ---- -struct t_hashtable *options = weechat_hashtable_new (8, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_STRING, - NULL, - NULL); -if (options) - weechat_hashtable_set (options, "type", "condition"); -char *str1 = weechat_string_eval_expression ("${buffer.full_name}", NULL, NULL, NULL); /* "core.weechat" */ -char *str2 = weechat_string_eval_expression ("${window.win_width} > 100", NULL, NULL, options); /* "1" */ -char *str3 = weechat_string_eval_expression ("abc =~ def", NULL, NULL, options); /* "0" */ +/* conditions */ +struct t_hashtable *options1 = weechat_hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); +weechat_hashtable_set (options1, "type", "condition"); +char *str1 = weechat_string_eval_expression ("${window.win_width} > 100", NULL, NULL, options1); /* "1" */ +char *str2 = weechat_string_eval_expression ("abc =~ def", NULL, NULL, options1); /* "0" */ + +/* simple expression */ +char *str3 = weechat_string_eval_expression ("${buffer.full_name}", NULL, NULL, NULL); /* "core.weechat" */ + +/* replace with regex */ +struct t_hashtable *options2 = weechat_hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); +/* add brackets around URLs */ +weechat_hashtable_set (options2, "regex", "\\w+://\\S+"); +weechat_hashtable_set (options2, "regex_replace", "[ ${re:0} ]"); +char *str4 = weechat_string_eval_expression ("test: http://weechat.org", NULL, NULL, NULL); /* "test: [ http://weechat.org ]" */ + +/* hide passwords */ +weechat_hashtable_set (options2, "regex", "(password=)(\\S+)"); +weechat_hashtable_set (options2, "regex_replace", "${re:1}${hide:*,${re:2}}"); +char *str5 = weechat_string_eval_expression ("password=abc password=def", NULL, NULL, NULL); /* "password=*** password=***" */ ---- Script (Python): @@ -1891,9 +1986,27 @@ Script (Python): str = weechat.string_eval_expression(expr, pointers, extra_vars, options) # examples -str1 = weechat.string_eval_expression("${buffer.full_name}", {}, {}, {}) # "core.weechat" -str2 = weechat.string_eval_expression("${window.win_width} > 100", {}, {}, {"type": "condition"}) # "1" -str3 = weechat.string_eval_expression("abc =~ def", {}, {}, {"type": "condition"}) # "0" + +# conditions +str1 = weechat.string_eval_expression("${window.win_width} > 100", {}, {}, {"type": "condition"}) # "1" +str2 = weechat.string_eval_expression("abc =~ def", {}, {}, {"type": "condition"}) # "0" + +# simple expression +str3 = weechat.string_eval_expression("${buffer.full_name}", {}, {}, {}) # "core.weechat" + +# replace with regex: add brackets around URLs +options = { + "regex": "\\w+://\\S+", + "regex_replace": "[ ${re:0} ]", +} +str4 = weechat.string_eval_expression("test: http://weechat.org", {}, {}, options) # "test: [ http://weechat.org ]" + +# replace with regex: hide passwords +options = { + "regex": "(password=)(\\S+)", + "regex_replace": "${re:1}${hide:*,${re:2}}", +} +str5 = weechat.string_eval_expression("password=abc password=def", {}, {}, options) # "password=*** password=***" ---- [[utf-8]] diff --git a/doc/fr/weechat_plugin_api.fr.asciidoc b/doc/fr/weechat_plugin_api.fr.asciidoc index 17c8c7799..4102bb62f 100644 --- a/doc/fr/weechat_plugin_api.fr.asciidoc +++ b/doc/fr/weechat_plugin_api.fr.asciidoc @@ -1858,11 +1858,11 @@ str3 = weechat.string_input_for_buffer("//test") # "/test" ==== weechat_string_eval_expression -_WeeChat ≥ 0.4.0, mis à jour dans la 0.4.2._ +_WeeChat ≥ 0.4.0, mis à jour dans la 0.4.2 et 1.1._ Évaluer l'expression et retourner le résultat sous forme de chaîne. -Les variables spéciales avec le format `${variable}` sont étendues (voir la -commande `/eval` dans le 'Guide utilisateur WeeChat'). +Les variables spéciales avec le format `${variable}` sont étendues (voir le +tableau ci-dessous). [NOTE] Depuis la version 1.0, les variables imbriquées sont supportées, par exemple : @@ -1880,11 +1880,17 @@ char *weechat_string_eval_expression (const char *expr, Paramètres : -* 'expr' : l'expression à évaluer +* 'expr' : l'expression à évaluer (voir le tableau ci-dessous) * 'pointers' : table de hachage avec les pointeurs (les clés doivent être des chaînes, les valeurs doivent être des pointeurs); les pointeurs "window" et "buffer" sont automatiquement ajoutés s'ils ne sont pas dans la table de - hachage (avec le pointer vers fenêtre/tampon courants) (peut être NULL) + hachage (avec le pointer vers fenêtre/tampon courants) (peut être NULL) : +** 'regex' : pointeur vers une expression régulière (structure 'regex_t') + compilée avec la fonction WeeChat + <<_weechat_string_regcomp,weechat_string_regcomp>> ou regcomp (voir + `man regcomp`) ; cette option est similaire à 'regex' dans la table de + hachage 'options' (ci-dessous), mais est utilisée pour de meilleures + performances * 'extra_vars' : variables additionnelles qui seront étendues (peut être NULL) * 'options' : table de hachage avec des options (les clés et valeurs doivent être des chaînes) (peut être NULL) : @@ -1894,6 +1900,12 @@ Paramètres : et parenthèses sont utilisés, le résultat est un booléen ("0" ou "1") ** 'prefix' : préfixe avant les variables à remplacer (par défaut : "${") ** 'suffix' : suffixe après les variables à remplacer (par défaut : "}") +** 'regex' : une expression regulière pour remplacer du texte dans 'expr' (qui + n'est alors pas évalué) +** 'regex_replace' : le texte de remplacement à utiliser avec 'regex', pour + remplacer du texte dans 'expr' ('regex_replace' est évalué sur chaque + correspondance de 'regex' sur 'expr', jusqu'à ce que plus aucune + correspondance ne soit trouvée) Valeur de retour : @@ -1901,20 +1913,108 @@ Valeur de retour : utilisation), ou NULL si problème (expression invalide ou pas assez de mémoire) +Liste des variables étendues dans l'expression (par ordre de priorité, de la +première étendue à la dernière) : + +[width="100%",cols="2,8,3,3",options="header"] +|=== +| Format | Description | Exemples | Résultats + +| `${nom}` | Variable `nom` de la table de hachage 'extra_vars' | + `${nom}` | `valeur` + +| `${esc:xxx}` + + `${\xxx}` | Chaîne avec caractères échappés | + `${esc:préfixe\tmessage}` + + `${\ua9}` | + `préfixemessage` + + `©` + +| `${hide:x,valeur}` | + Chaîne avec les caractères masqués (tous les caractères dans `valeur` + remplacés par `x` | + `${hide:*,mot_de_passe}` | + `************` + +| `${re:N}` | + Groupe regex capturé : 0 = toute la chaîne correspondante, 1 à 99 = groupe + capturé, `+` = dernier groupe capturé | + `${re:1}` | + `test` + +| `${color:nom}` | + Code couleur WeeChat (le nom de couleur a des attributs facultatifs) | + `${color:red}texte rouge` + + `${color:*214}texte orange gras` | + `texte rouge` (en rouge) + + `texte orange gras` (en orange gras) + +| `${info:name}` + + `${indo:name,arguments}` | + Info de WeeChat ou d'une extension, voir la fonction + <<_weechat_info_get,weechat_info_get>> | + `${info:version}` + + `${info:irc_nick_color_name,foo}` | + `1.0` + + `lightblue` + +| `${sec.data.nom}` | + Valeur de la donnée sécurisée `nom` | + `${sec.data.freenode_pass}` | + `mon_mot_de_passe` + +| `${file.section.option}` | + Valeur de l'option | + `${weechat.look.buffer_time_format}` | + `%H:%M:%S` + +| `${nom}` | + Valeur de la variable locale `nom` dans le tampon | + `${nick}` | + `FlashCode` + +| `${hdata.var1.var2...}` + + `${hdata[list].var1.var2...}` | + Valeur d'un hdata (les pointeurs `window` et `buffer` sont définis par défaut + avec la fenêtre et tampon courants) | + `${buffer[gui_buffers].full_name}` + + `${window.buffer.number}` | + `core.weechat` + + `1` +|=== + Exemples en C : [source,C] ---- -struct t_hashtable *options = weechat_hashtable_new (8, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_STRING, - NULL, - NULL); -if (options) - weechat_hashtable_set (options, "type", "condition"); -char *str1 = weechat_string_eval_expression ("${buffer.full_name}", NULL, NULL, NULL); /* "core.weechat" */ -char *str2 = weechat_string_eval_expression ("${window.win_width} > 100", NULL, NULL, options); /* "1" */ -char *str3 = weechat_string_eval_expression ("abc =~ def", NULL, NULL, options); /* "0" */ +/* conditions */ +struct t_hashtable *options1 = weechat_hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); +weechat_hashtable_set (options1, "type", "condition"); +char *str1 = weechat_string_eval_expression ("${window.win_width} > 100", NULL, NULL, options1); /* "1" */ +char *str2 = weechat_string_eval_expression ("abc =~ def", NULL, NULL, options1); /* "0" */ + +/* expression simple */ +char *str3 = weechat_string_eval_expression ("${buffer.full_name}", NULL, NULL, NULL); /* "core.weechat" */ + +/* remplacement avec regex */ +struct t_hashtable *options2 = weechat_hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); +/* ajout de crochets autour des URLs */ +weechat_hashtable_set (options2, "regex", "\\w+://\\S+"); +weechat_hashtable_set (options2, "regex_replace", "[ ${re:0} ]"); +char *str4 = weechat_string_eval_expression ("test: http://weechat.org", NULL, NULL, NULL); /* "test: [ http://weechat.org ]" */ + +/* masquage des mots de passe */ +weechat_hashtable_set (options2, "regex", "(password=)(\\S+)"); +weechat_hashtable_set (options2, "regex_replace", "${re:1}${hide:*,${re:2}}"); +char *str5 = weechat_string_eval_expression ("password=abc password=def", NULL, NULL, NULL); /* "password=*** password=***" */ ---- Script (Python) : @@ -1925,9 +2025,27 @@ Script (Python) : str = weechat.string_eval_expression(expr, pointers, extra_vars, options) # exemples -str1 = weechat.string_eval_expression("${buffer.full_name}", {}, {}, {}) # "core.weechat" -str2 = weechat.string_eval_expression("${window.win_width} > 100", {}, {}, {"type": "condition"}) # "1" -str3 = weechat.string_eval_expression("abc =~ def", {}, {}, {"type": "condition"}) # "0" + +# conditions +str1 = weechat.string_eval_expression("${window.win_width} > 100", {}, {}, {"type": "condition"}) # "1" +str2 = weechat.string_eval_expression("abc =~ def", {}, {}, {"type": "condition"}) # "0" + +# expression simple +str3 = weechat.string_eval_expression("${buffer.full_name}", {}, {}, {}) # "core.weechat" + +# remplacement avec regex : ajout de crochets autour des URLs +options = { + "regex": "\\w+://\\S+", + "regex_replace": "[ ${re:0} ]", +} +str4 = weechat.string_eval_expression("test: http://weechat.org", {}, {}, options) # "test: [ http://weechat.org ]" + +# replace with regex : masquage des mots de passe +options = { + "regex": "(password=)(\\S+)", + "regex_replace": "${re:1}${hide:*,${re:2}}", +} +str5 = weechat.string_eval_expression("password=abc password=def", {}, {}, options) # "password=*** password=***" ---- [[utf-8]] diff --git a/doc/it/weechat_plugin_api.it.asciidoc b/doc/it/weechat_plugin_api.it.asciidoc index b643527a3..f3af1c2aa 100644 --- a/doc/it/weechat_plugin_api.it.asciidoc +++ b/doc/it/weechat_plugin_api.it.asciidoc @@ -1879,12 +1879,11 @@ str3 = weechat.string_input_for_buffer("//test") # "/test" ==== weechat_string_eval_expression // TRANSLATION MISSING -_WeeChat ≥ 0.4.0, updated in 0.4.2._ +_WeeChat ≥ 0.4.0, updated in 0.4.2 and 1.1._ // TRANSLATION MISSING Evaluate an expression and return result as a string. -Special variables with format `${variable}` are expanded (see command `/eval` in -'WeeChat User's guide'). +Special variables with format `${variable}` are expanded (see table below). // TRANSLATION MISSING [NOTE] @@ -1904,10 +1903,14 @@ char *weechat_string_eval_expression (const char *expr, Argomenti: // TRANSLATION MISSING -* 'expr': the expression to evaluate +* 'expr': the expression to evaluate (see table below) * 'pointers': hashtable with pointers (keys must be string, values must be pointer); pointers "window" and "buffer" are automatically added if they are - not in hashtable (with pointer to current window/buffer) (can be NULL) + not in hashtable (with pointer to current window/buffer) (can be NULL): +** 'regex': pointer to a regular expression ('regex_t' structure) compiled with + WeeChat function <<_weechat_string_regcomp,weechat_string_regcomp>> or + regcomp (see `man regcomp`); this option is similar to 'regex' in hashtable + 'options' (below), but is used for better performance * 'extra_vars': extra variables that will be expanded (can be NULL) * 'options': a hashtable with some options (keys and values must be string) (can be NULL): @@ -1917,6 +1920,11 @@ Argomenti: parentheses are used, result is a boolean ("0" or "1") ** 'prefix': prefix before variables to replace (default: "${") ** 'suffix': suffix after variables to replace (default: "}") +** 'regex': a regex used to replace text in 'expr' (which is then not + evaluated) +** 'regex_replace': the replacement text to use with 'regex', to replace + text in 'expr' (the 'regex_replace' is evaluated on each match of 'regex' + against 'expr', until no match is found) Valore restituito: @@ -1924,20 +1932,109 @@ Valore restituito: * evaluated expression (must be freed by calling "free" after use), or NULL if problem (invalid expression or not enough memory) +// TRANSLATION MISSING +List of variables expanded in expression (by order of priority, from first +expanded to last): + +// TRANSLATION MISSING +[width="100%",cols="2,8,3,3",options="header"] +|=== +| Format | Description | Examples | Results + +| `${name}` | Variable `name` from hashtable 'extra_vars' | + `${name}` | `value` + +| `${esc:xxx}` + + `${\xxx}` | String with escaped chars | + `${esc:prefix\tmessage}` + + `${\ua9}` | + `prefixmessage` + + `©` + +| `${hide:x,value}` | + String with hidden chars (all chars in `value` replaced `x`) | + `${hide:*,password}` | + `********` + +| `${re:N}` | + Regex captured group: 0 = whole string matching, 1 to 99 = group captured, + `+` = last group captured | + `${re:1}` | + `test` + +| `${color:name}` | + WeeChat color code (the name of color has optional attributes) | + `${color:red}red text` + + `${color:*214}bold orange text` | + `red text` (in red) + + `bold orange text` (in bold orange) + +| `${info:name}` + + `${indo:name,arguments}` | + Info from WeeChat or a plugin, see function + <<_weechat_info_get,weechat_info_get>> | + `${info:version}` + + `${info:irc_nick_color_name,foo}` | + `1.0` + + `lightblue` + +| `${sec.data.name}` | + Value of the secured data `name` | + `${sec.data.freenode_pass}` | + `my_password` + +| `${file.section.option}` | + Value of the option | + `${weechat.look.buffer_time_format}` | + `%H:%M:%S` + +| `${name}` | + Value of local variable `name` in buffer | + `${nick}` | + `FlashCode` + +| `${hdata.var1.var2...}` + + `${hdata[list].var1.var2...}` | + Hdata value (pointers `window` and `buffer` are set by default with current + window/buffer) | + `${buffer[gui_buffers].full_name}` + + `${window.buffer.number}` | + `core.weechat` + + `1` +|=== + Esempi in C: [source,C] ---- -struct t_hashtable *options = weechat_hashtable_new (8, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_STRING, - NULL, - NULL); -if (options) - weechat_hashtable_set (options, "type", "condition"); -char *str1 = weechat_string_eval_expression ("${buffer.full_name}", NULL, NULL, NULL); /* "core.weechat" */ -char *str2 = weechat_string_eval_expression ("${window.win_width} > 100", NULL, NULL, options); /* "1" */ -char *str3 = weechat_string_eval_expression ("abc =~ def", NULL, NULL, options); /* "0" */ +/* conditions */ +struct t_hashtable *options1 = weechat_hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); +weechat_hashtable_set (options1, "type", "condition"); +char *str1 = weechat_string_eval_expression ("${window.win_width} > 100", NULL, NULL, options1); /* "1" */ +char *str2 = weechat_string_eval_expression ("abc =~ def", NULL, NULL, options1); /* "0" */ + +/* simple expression */ +char *str3 = weechat_string_eval_expression ("${buffer.full_name}", NULL, NULL, NULL); /* "core.weechat" */ + +/* replace with regex */ +struct t_hashtable *options2 = weechat_hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); +/* add brackets around URLs */ +weechat_hashtable_set (options2, "regex", "\\w+://\\S+"); +weechat_hashtable_set (options2, "regex_replace", "[ ${re:0} ]"); +char *str4 = weechat_string_eval_expression ("test: http://weechat.org", NULL, NULL, NULL); /* "test: [ http://weechat.org ]" */ + +/* hide passwords */ +weechat_hashtable_set (options2, "regex", "(password=)(\\S+)"); +weechat_hashtable_set (options2, "regex_replace", "${re:1}${hide:*,${re:2}}"); +char *str5 = weechat_string_eval_expression ("password=abc password=def", NULL, NULL, NULL); /* "password=*** password=***" */ ---- Script (Python): @@ -1948,9 +2045,27 @@ Script (Python): str = weechat.string_eval_expression(expr, pointers, extra_vars, options) # esempi -str1 = weechat.string_eval_expression("${buffer.full_name}", {}, {}, {}) # "core.weechat" -str2 = weechat.string_eval_expression("${window.win_width} > 100", {}, {}, {"type": "condition"}) # "1" -str3 = weechat.string_eval_expression("abc =~ def", {}, {}, {"type": "condition"}) # "0" + +# conditions +str1 = weechat.string_eval_expression("${window.win_width} > 100", {}, {}, {"type": "condition"}) # "1" +str2 = weechat.string_eval_expression("abc =~ def", {}, {}, {"type": "condition"}) # "0" + +# simple expression +str3 = weechat.string_eval_expression("${buffer.full_name}", {}, {}, {}) # "core.weechat" + +# replace with regex: add brackets around URLs +options = { + "regex": "\\w+://\\S+", + "regex_replace": "[ ${re:0} ]", +} +str4 = weechat.string_eval_expression("test: http://weechat.org", {}, {}, options) # "test: [ http://weechat.org ]" + +# replace with regex: hide passwords +options = { + "regex": "(password=)(\\S+)", + "regex_replace": "${re:1}${hide:*,${re:2}}", +} +str5 = weechat.string_eval_expression("password=abc password=def", {}, {}, options) # "password=*** password=***" ---- [[utf-8]] diff --git a/doc/ja/weechat_plugin_api.ja.asciidoc b/doc/ja/weechat_plugin_api.ja.asciidoc index 90cf05914..75bac3864 100644 --- a/doc/ja/weechat_plugin_api.ja.asciidoc +++ b/doc/ja/weechat_plugin_api.ja.asciidoc @@ -1822,11 +1822,12 @@ str3 = weechat.string_input_for_buffer("//test") # "/test" ==== weechat_string_eval_expression -_WeeChat バージョン 0.4.0 以上で利用可、バージョン 0.4.2 で更新。_ +// TRANSLATION MISSING +_WeeChat ≥ 0.4.0, updated in 0.4.2 and 1.1._ -式を評価して文字列として返す。`${variable}` -という書式で書かれた特殊変数は展開される -('WeeChat ユーザガイド' のコマンド `/eval` を参照)。 +// TRANSLATION MISSING +Evaluate an expression and return result as a string. +Special variables with format `${variable}` are expanded (see table below). [NOTE] バージョン 1.0 以降、入れ子変数を使えるようになりました、例: @@ -1844,10 +1845,16 @@ char *weechat_string_eval_expression (const char *expr, 引数: -* 'expr': 評価する式 +// TRANSLATION MISSING +* 'expr': 評価する式 (see table below) * 'pointers': ポインタを含むハッシュテーブル (キーは文字列、値はポインタ); (現在のウィンドウやバッファへのポインタを持つ) ハッシュテーブルが "window" と - "buffer" ポインタを持たない場合はこれらは自動的に追加される (NULL でも可) + "buffer" ポインタを持たない場合はこれらは自動的に追加される (NULL でも可): +// TRANSLATION MISSING +** 'regex': pointer to a regular expression ('regex_t' structure) compiled with + WeeChat function <<_weechat_string_regcomp,weechat_string_regcomp>> or + regcomp (see `man regcomp`); this option is similar to 'regex' in hashtable + 'options' (below), but is used for better performance * 'extra_vars': 展開される追加変数 (NULL でも可) * 'options': いくつかのオプションを含むハッシュテーブル (キーと値は必ず文字列) (NULL でも可): @@ -1857,39 +1864,155 @@ char *weechat_string_eval_expression (const char *expr, 演算子と括弧が使われます、結果はブール値 ("0" または "1") です ** 'prefix': 置換する変数のプレフィックス (デフォルト: "${") ** 'suffix': 置換する変数のサフィックス (デフォルト: "}") +// TRANSLATION MISSING +** 'regex': a regex used to replace text in 'expr' (which is then not + evaluated) +// TRANSLATION MISSING +** 'regex_replace': the replacement text to use with 'regex', to replace + text in 'expr' (the 'regex_replace' is evaluated on each match of 'regex' + against 'expr', until no match is found) 戻り値: * 評価された式 (使用後には必ず "free" を呼び出して領域を開放してください)、失敗した場合は NULL (式が不正な場合やメモリが不足している場合) +// TRANSLATION MISSING +List of variables expanded in expression (by order of priority, from first +expanded to last): + +// TRANSLATION MISSING +[width="100%",cols="2,8,3,3",options="header"] +|=== +| Format | Description | Examples | Results + +| `${name}` | Variable `name` from hashtable 'extra_vars' | + `${name}` | `value` + +| `${esc:xxx}` + + `${\xxx}` | String with escaped chars | + `${esc:prefix\tmessage}` + + `${\ua9}` | + `prefixmessage` + + `©` + +| `${hide:x,value}` | + String with hidden chars (all chars in `value` replaced `x`) | + `${hide:*,password}` | + `********` + +| `${re:N}` | + Regex captured group: 0 = whole string matching, 1 to 99 = group captured, + `+` = last group captured | + `${re:1}` | + `test` + +| `${color:name}` | + WeeChat color code (the name of color has optional attributes) | + `${color:red}red text` + + `${color:*214}bold orange text` | + `red text` (in red) + + `bold orange text` (in bold orange) + +| `${info:name}` + + `${indo:name,arguments}` | + Info from WeeChat or a plugin, see function + <<_weechat_info_get,weechat_info_get>> | + `${info:version}` + + `${info:irc_nick_color_name,foo}` | + `1.0` + + `lightblue` + +| `${sec.data.name}` | + Value of the secured data `name` | + `${sec.data.freenode_pass}` | + `my_password` + +| `${file.section.option}` | + Value of the option | + `${weechat.look.buffer_time_format}` | + `%H:%M:%S` + +| `${name}` | + Value of local variable `name` in buffer | + `${nick}` | + `FlashCode` + +| `${hdata.var1.var2...}` + + `${hdata[list].var1.var2...}` | + Hdata value (pointers `window` and `buffer` are set by default with current + window/buffer) | + `${buffer[gui_buffers].full_name}` + + `${window.buffer.number}` | + `core.weechat` + + `1` +|=== + C 言語での使用例: +// TRANSLATION MISSING [source,C] ---- -struct t_hashtable *options = weechat_hashtable_new (8, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_STRING, - NULL, - NULL); -if (options) - weechat_hashtable_set (options, "type", "condition"); -char *str1 = weechat_string_eval_expression ("${buffer.full_name}", NULL, NULL, NULL); /* "core.weechat" */ -char *str2 = weechat_string_eval_expression ("${window.win_width} > 100", NULL, NULL, options); /* "1" */ -char *str3 = weechat_string_eval_expression ("abc =~ def", NULL, NULL, options); /* "0" */ +/* conditions */ +struct t_hashtable *options1 = weechat_hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); +weechat_hashtable_set (options1, "type", "condition"); +char *str1 = weechat_string_eval_expression ("${window.win_width} > 100", NULL, NULL, options1); /* "1" */ +char *str2 = weechat_string_eval_expression ("abc =~ def", NULL, NULL, options1); /* "0" */ + +/* simple expression */ +char *str3 = weechat_string_eval_expression ("${buffer.full_name}", NULL, NULL, NULL); /* "core.weechat" */ + +/* replace with regex */ +struct t_hashtable *options2 = weechat_hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); +/* add brackets around URLs */ +weechat_hashtable_set (options2, "regex", "\\w+://\\S+"); +weechat_hashtable_set (options2, "regex_replace", "[ ${re:0} ]"); +char *str4 = weechat_string_eval_expression ("test: http://weechat.org", NULL, NULL, NULL); /* "test: [ http://weechat.org ]" */ + +/* hide passwords */ +weechat_hashtable_set (options2, "regex", "(password=)(\\S+)"); +weechat_hashtable_set (options2, "regex_replace", "${re:1}${hide:*,${re:2}}"); +char *str5 = weechat_string_eval_expression ("password=abc password=def", NULL, NULL, NULL); /* "password=*** password=***" */ ---- スクリプト (Python) での使用例: +// TRANSLATION MISSING [source,python] ---- # プロトタイプ str = weechat.string_eval_expression(expr, pointers, extra_vars, options) # 例s -str1 = weechat.string_eval_expression("${buffer.full_name}", {}, {}, {}) # "core.weechat" -str2 = weechat.string_eval_expression("${window.win_width} > 100", {}, {}, {"type": "condition"}) # "1" -str3 = weechat.string_eval_expression("abc =~ def", {}, {}, {"type": "condition"}) # "0" + +# conditions +str1 = weechat.string_eval_expression("${window.win_width} > 100", {}, {}, {"type": "condition"}) # "1" +str2 = weechat.string_eval_expression("abc =~ def", {}, {}, {"type": "condition"}) # "0" + +# simple expression +str3 = weechat.string_eval_expression("${buffer.full_name}", {}, {}, {}) # "core.weechat" + +# replace with regex: add brackets around URLs +options = { + "regex": "\\w+://\\S+", + "regex_replace": "[ ${re:0} ]", +} +str4 = weechat.string_eval_expression("test: http://weechat.org", {}, {}, options) # "test: [ http://weechat.org ]" + +# replace with regex: hide passwords +options = { + "regex": "(password=)(\\S+)", + "regex_replace": "${re:1}${hide:*,${re:2}}", +} +str5 = weechat.string_eval_expression("password=abc password=def", {}, {}, options) # "password=*** password=***" ---- [[utf-8]] diff --git a/src/core/wee-eval.c b/src/core/wee-eval.c index 061a41263..2bbd0a15c 100644 --- a/src/core/wee-eval.c +++ b/src/core/wee-eval.c @@ -220,11 +220,15 @@ end: /* * Replaces variables, which can be, by order of priority: - * 1. an extra variable (from hashtable "extra_vars") - * 2. a color (format: color:xxx) - * 3. an option (format: file.section.option) - * 4. a buffer local variable - * 5. a hdata name/variable + * 1. an extra variable from hashtable "extra_vars" + * 2. a string with escaped chars (format: esc:xxx or \xxx) + * 3. a string with chars to hide (format: hide:char,string) + * 4. a regex group captured (format: re:N (0.99) or re:+) + * 5. a color (format: color:xxx) + * 6. an info (format: info:name,arguments) + * 7. an option (format: file.section.option) + * 8. a buffer local variable + * 9. a hdata variable (format: hdata.var1.var2 or hdata[list].var1.var2) * * Examples: * option: ${weechat.look.scroll_amount} @@ -236,19 +240,22 @@ char * eval_replace_vars_cb (void *data, const char *text) { struct t_hashtable *pointers, *extra_vars; + struct t_eval_regex *eval_regex; struct t_config_option *ptr_option; struct t_gui_buffer *ptr_buffer; char str_value[64], *value, *pos, *pos1, *pos2, *hdata_name, *list_name; - char *tmp, *info_name, *hide_char, *hidden_string; + char *tmp, *info_name, *hide_char, *hidden_string, *error; const char *ptr_value, *ptr_arguments, *ptr_string; struct t_hdata *hdata; void *pointer; int i, length_hide_char, length, index; + long number; pointers = (struct t_hashtable *)(((void **)data)[0]); extra_vars = (struct t_hashtable *)(((void **)data)[1]); + eval_regex = (struct t_eval_regex *)(((void **)data)[2]); - /* 1. look for var in hashtable "extra_vars" */ + /* 1. variable in hashtable "extra_vars" */ if (extra_vars) { ptr_value = hashtable_get (extra_vars, text); @@ -262,7 +269,7 @@ eval_replace_vars_cb (void *data, const char *text) if ((text[0] == '\\') && text[1] && (text[1] != '\\')) return string_convert_escaped_chars (text); - /* 3. hide chars: replace all chars by a given char */ + /* 3. hide chars: replace all chars by a given char/string */ if (strncmp (text, "hide:", 5) == 0) { hidden_string = NULL; @@ -292,14 +299,37 @@ eval_replace_vars_cb (void *data, const char *text) return (hidden_string) ? hidden_string : strdup (""); } - /* 4. look for a color */ + /* 4. regex group captured */ + if (strncmp (text, "re:", 3) == 0) + { + if (eval_regex && eval_regex->result) + { + if (strcmp (text + 3, "+") == 0) + number = eval_regex->last_match; + else + { + number = strtol (text + 3, &error, 10); + if (!error || error[0]) + number = -1; + } + if ((number >= 0) && (number <= eval_regex->last_match)) + { + return string_strndup ( + eval_regex->result + eval_regex->match[number].rm_so, + eval_regex->match[number].rm_eo - eval_regex->match[number].rm_so); + } + } + return strdup (""); + } + + /* 5. color code */ if (strncmp (text, "color:", 6) == 0) { ptr_value = gui_color_get_custom (text + 6); return strdup ((ptr_value) ? ptr_value : ""); } - /* 5. look for an info */ + /* 6. info */ if (strncmp (text, "info:", 5) == 0) { ptr_value = NULL; @@ -319,7 +349,7 @@ eval_replace_vars_cb (void *data, const char *text) return strdup ((ptr_value) ? ptr_value : ""); } - /* 6. look for name of option: if found, return this value */ + /* 7. option: if found, return this value */ if (strncmp (text, "sec.data.", 9) == 0) { ptr_value = hashtable_get (secure_hashtable_data, text + 9); @@ -352,7 +382,7 @@ eval_replace_vars_cb (void *data, const char *text) } } - /* 7. look for local variable in buffer */ + /* 8. local variable in buffer */ ptr_buffer = hashtable_get (pointers, "buffer"); if (ptr_buffer) { @@ -361,7 +391,7 @@ eval_replace_vars_cb (void *data, const char *text) return strdup (ptr_value); } - /* 8. look for hdata */ + /* 9. hdata */ value = NULL; hdata_name = NULL; list_name = NULL; @@ -425,12 +455,14 @@ end: char * eval_replace_vars (const char *expr, struct t_hashtable *pointers, struct t_hashtable *extra_vars, - const char *prefix, const char *suffix) + const char *prefix, const char *suffix, + struct t_eval_regex *eval_regex) { - void *ptr[2]; + void *ptr[3]; ptr[0] = pointers; ptr[1] = extra_vars; + ptr[2] = eval_regex; return string_replace_with_callback (expr, prefix, suffix, &eval_replace_vars_cb, ptr, NULL); @@ -712,10 +744,12 @@ eval_expression_condition (const char *expr, /* for regex: just replace vars in both expressions */ tmp_value = eval_replace_vars (sub_expr, pointers, extra_vars, - prefix, suffix); + prefix, suffix, + NULL); tmp_value2 = eval_replace_vars (pos, pointers, extra_vars, - prefix, suffix); + prefix, suffix, + NULL); } else { @@ -799,7 +833,8 @@ eval_expression_condition (const char *expr, * 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, prefix, suffix); + value = eval_replace_vars (expr2, pointers, extra_vars, prefix, suffix, + NULL); end: if (expr2) @@ -808,6 +843,125 @@ end: return value; } +/* + * Replaces text in a string using a regular expression and replacement text. + * + * The argument "regex" is a pointer to a regex compiled with WeeChat function + * string_regcomp (or function regcomp). + * + * The argument "replace" is evaluated and can contain any valid expression, + * and these ones: + * ${re:0} .. ${re:99} match 0 to 99 (0 is whole match, 1 .. 99 are groups + * captured) + * ${re:+} the last match (with highest number) + * + * Examples: + * + * string | regex | replace | result + * ----------+---------------+----------------------------+------------- + * test foo | test | Z | Z foo + * test foo | ^(test +)(.*) | ${re:2} | foo + * test foo | ^(test +)(.*) | ${re:1}/ ${hide:*,${re:2}} | test / *** + * test foo | ^(test +)(.*) | ${hide:%,${re:+}} | %%% + * + * Note: result must be freed after use. + */ + +char * +eval_replace_regex (const char *string, regex_t *regex, const char *replace, + struct t_hashtable *pointers, + struct t_hashtable *extra_vars, + const char *prefix, const char *suffix) +{ + char *result, *result2, *str_replace; + int length, length_replace, start_offset, i, rc, end; + struct t_eval_regex eval_regex; + + if (!string || !regex || !replace) + return NULL; + + length = strlen (string) + 1; + result = malloc (length); + if (!result) + return NULL; + snprintf (result, length, "%s", string); + + start_offset = 0; + while (result && result[start_offset]) + { + for (i = 0; i < 100; i++) + { + eval_regex.match[i].rm_so = -1; + } + + rc = regexec (regex, result + start_offset, 100, eval_regex.match, 0); + /* + * no match found: exit the loop (if rm_eo == 0, it is an empty match + * at beginning of string: we consider there is no match, to prevent an + * infinite loop) + */ + if ((rc != 0) + || (eval_regex.match[0].rm_so < 0) + || (eval_regex.match[0].rm_eo <= 0)) + { + break; + } + + /* adjust the start/end offsets */ + eval_regex.last_match = 0; + for (i = 0; i < 100; i++) + { + if (eval_regex.match[i].rm_so >= 0) + { + eval_regex.last_match = i; + eval_regex.match[i].rm_so += start_offset; + eval_regex.match[i].rm_eo += start_offset; + } + } + + /* check if the regex matched the end of string */ + end = !result[eval_regex.match[0].rm_eo]; + + eval_regex.result = result; + + str_replace = eval_replace_vars (replace, pointers, extra_vars, + prefix, suffix, &eval_regex); + + length_replace = (str_replace) ? strlen (str_replace) : 0; + + length = eval_regex.match[0].rm_so + length_replace + + strlen (result + eval_regex.match[0].rm_eo) + 1; + result2 = malloc (length); + if (!result2) + { + free (result); + return NULL; + } + result2[0] = '\0'; + if (eval_regex.match[0].rm_so > 0) + { + memcpy (result2, result, eval_regex.match[0].rm_so); + result2[eval_regex.match[0].rm_so] = '\0'; + } + if (str_replace) + strcat (result2, str_replace); + strcat (result2, result + eval_regex.match[0].rm_eo); + + free (result); + result = result2; + + if (str_replace) + free (str_replace); + + if (end) + break; + + start_offset = eval_regex.match[0].rm_so + length_replace; + } + + return result; +} + /* * Evaluates an expression. * @@ -853,25 +1007,33 @@ char * eval_expression (const char *expr, struct t_hashtable *pointers, struct t_hashtable *extra_vars, struct t_hashtable *options) { - int condition, rc, pointers_allocated; + int condition, rc, pointers_allocated, regex_allocated; char *value; const char *prefix, *suffix; const char *default_prefix = EVAL_DEFAULT_PREFIX; const char *default_suffix = EVAL_DEFAULT_SUFFIX; - const char *ptr_value; + const char *ptr_value, *regex_replace; struct t_gui_window *window; + regex_t *regex; if (!expr) return NULL; condition = 0; pointers_allocated = 0; + regex_allocated = 0; prefix = default_prefix; suffix = default_suffix; + regex = NULL; + regex_replace = NULL; - /* create hashtable pointers if it's NULL */ - if (!pointers) + if (pointers) { + regex = (regex_t *)hashtable_get (pointers, "regex"); + } + else + { + /* create hashtable pointers if it's NULL */ pointers = hashtable_new (32, WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_POINTER, @@ -915,6 +1077,30 @@ eval_expression (const char *expr, struct t_hashtable *pointers, ptr_value = hashtable_get (options, "suffix"); if (ptr_value && ptr_value[0]) suffix = ptr_value; + + /* check for regex */ + ptr_value = hashtable_get (options, "regex"); + if (ptr_value && ptr_value[0]) + { + regex = malloc (sizeof (*regex)); + if (string_regcomp (regex, ptr_value, + REG_EXTENDED | REG_ICASE) == 0) + { + regex_allocated = 1; + } + else + { + free (regex); + regex = NULL; + } + } + + /* check for regex replacement (evaluated later) */ + ptr_value = hashtable_get (options, "regex_replace"); + if (ptr_value && ptr_value[0]) + { + regex_replace = ptr_value; + } } /* evaluate expression */ @@ -930,12 +1116,28 @@ eval_expression (const char *expr, struct t_hashtable *pointers, } else { - /* only replace variables in expression */ - value = eval_replace_vars (expr, pointers, extra_vars, prefix, suffix); + if (regex && regex_replace) + { + /* replace with regex */ + value = eval_replace_regex (expr, regex, regex_replace, + pointers, extra_vars, + prefix, suffix); + } + else + { + /* only replace variables in expression */ + value = eval_replace_vars (expr, pointers, extra_vars, + prefix, suffix, NULL); + } } if (pointers_allocated) hashtable_free (pointers); + if (regex && regex_allocated) + { + regfree (regex); + free (regex); + } return value; } diff --git a/src/core/wee-eval.h b/src/core/wee-eval.h index eb20e5192..4e4af7f17 100644 --- a/src/core/wee-eval.h +++ b/src/core/wee-eval.h @@ -20,6 +20,8 @@ #ifndef WEECHAT_EVAL_H #define WEECHAT_EVAL_H 1 +#include + #define EVAL_STR_FALSE "0" #define EVAL_STR_TRUE "1" @@ -50,6 +52,13 @@ enum t_eval_comparison EVAL_NUM_COMPARISONS, }; +struct t_eval_regex +{ + const char *result; + regmatch_t match[100]; + int last_match; +}; + extern int eval_is_true (const char *value); extern char *eval_expression (const char *expr, struct t_hashtable *pointers, diff --git a/tests/unit/core/test-eval.cpp b/tests/unit/core/test-eval.cpp index d8d3d52b5..d9fc79241 100644 --- a/tests/unit/core/test-eval.cpp +++ b/tests/unit/core/test-eval.cpp @@ -24,23 +24,20 @@ extern "C" { #include +#include #include "src/core/wee-eval.h" #include "src/core/wee-config.h" #include "src/core/wee-hashtable.h" +#include "src/core/wee-string.h" #include "src/core/wee-version.h" #include "src/gui/gui-color.h" #include "src/plugins/plugin.h" } #define WEE_CHECK_EVAL(__result, __expr) \ - value = eval_expression (__expr, NULL, extra_vars, NULL); \ + value = eval_expression (__expr, pointers, extra_vars, options); \ STRCMP_EQUAL(__result, value); \ free (value); -#define WEE_CHECK_EVAL_COND(__result, __expr) \ - value = eval_expression (__expr, NULL, extra_vars, options); \ - STRCMP_EQUAL(__result, value); \ - free (value); - TEST_GROUP(Eval) { }; @@ -71,94 +68,96 @@ TEST(Eval, Boolean) TEST(Eval, EvalCondition) { - struct t_hashtable *extra_vars, *options; + struct t_hashtable *pointers, *extra_vars, *options; char *value; + pointers = NULL; + extra_vars = hashtable_new (32, WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_STRING, NULL, NULL); - hashtable_set (extra_vars, "test", "value"); CHECK(extra_vars); + hashtable_set (extra_vars, "test", "value"); options = hashtable_new (32, WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_STRING, NULL, NULL); - hashtable_set (options, "type", "condition"); CHECK(options); + hashtable_set (options, "type", "condition"); POINTERS_EQUAL(NULL, eval_expression (NULL, NULL, NULL, options)); /* conditions evaluated as false */ - WEE_CHECK_EVAL_COND("0", ""); - WEE_CHECK_EVAL_COND("0", "0"); - WEE_CHECK_EVAL_COND("0", "1 == 2"); - WEE_CHECK_EVAL_COND("0", "1 >= 2"); - WEE_CHECK_EVAL_COND("0", "2 <= 1"); - WEE_CHECK_EVAL_COND("0", "2 != 2"); - WEE_CHECK_EVAL_COND("0", "18 < 5"); - WEE_CHECK_EVAL_COND("0", "5 > 18"); - WEE_CHECK_EVAL_COND("0", "1 == 5 > 18"); - WEE_CHECK_EVAL_COND("0", "abc == def"); - WEE_CHECK_EVAL_COND("0", "()"); - WEE_CHECK_EVAL_COND("0", "(5 > 26)"); - WEE_CHECK_EVAL_COND("0", "((5 > 26))"); - WEE_CHECK_EVAL_COND("0", "(26 < 5)"); - WEE_CHECK_EVAL_COND("0", "abc > def"); - WEE_CHECK_EVAL_COND("0", "1 && 0"); - WEE_CHECK_EVAL_COND("0", "abc && 0"); - WEE_CHECK_EVAL_COND("0", "0 || 0"); - WEE_CHECK_EVAL_COND("0", "0 || 0 || 0"); - WEE_CHECK_EVAL_COND("0", "0 || 1 && 0"); - WEE_CHECK_EVAL_COND("0", "0 || (1 && 0)"); - WEE_CHECK_EVAL_COND("0", "0 || (0 || (1 && 0))"); - WEE_CHECK_EVAL_COND("0", "1 && (0 || 0)"); - WEE_CHECK_EVAL_COND("0", "(0 || 1) && 0"); - WEE_CHECK_EVAL_COND("0", "((0 || 1) && 1) && 0"); - WEE_CHECK_EVAL_COND("0", "abcd =~ (?-i)^ABC"); - WEE_CHECK_EVAL_COND("0", "abcd =~ \\(abcd\\)"); - WEE_CHECK_EVAL_COND("0", "(abcd) =~ \\(\\(abcd\\)\\)"); - WEE_CHECK_EVAL_COND("0", "${test} == test"); - WEE_CHECK_EVAL_COND("0", "${test2} == value2"); - WEE_CHECK_EVAL_COND("0", "${buffer.number} == 2"); - WEE_CHECK_EVAL_COND("0", "${window.buffer.number} == 2"); + WEE_CHECK_EVAL("0", ""); + WEE_CHECK_EVAL("0", "0"); + WEE_CHECK_EVAL("0", "1 == 2"); + WEE_CHECK_EVAL("0", "1 >= 2"); + WEE_CHECK_EVAL("0", "2 <= 1"); + WEE_CHECK_EVAL("0", "2 != 2"); + WEE_CHECK_EVAL("0", "18 < 5"); + WEE_CHECK_EVAL("0", "5 > 18"); + WEE_CHECK_EVAL("0", "1 == 5 > 18"); + WEE_CHECK_EVAL("0", "abc == def"); + WEE_CHECK_EVAL("0", "()"); + WEE_CHECK_EVAL("0", "(5 > 26)"); + WEE_CHECK_EVAL("0", "((5 > 26))"); + WEE_CHECK_EVAL("0", "(26 < 5)"); + WEE_CHECK_EVAL("0", "abc > def"); + WEE_CHECK_EVAL("0", "1 && 0"); + WEE_CHECK_EVAL("0", "abc && 0"); + WEE_CHECK_EVAL("0", "0 || 0"); + WEE_CHECK_EVAL("0", "0 || 0 || 0"); + WEE_CHECK_EVAL("0", "0 || 1 && 0"); + WEE_CHECK_EVAL("0", "0 || (1 && 0)"); + WEE_CHECK_EVAL("0", "0 || (0 || (1 && 0))"); + WEE_CHECK_EVAL("0", "1 && (0 || 0)"); + WEE_CHECK_EVAL("0", "(0 || 1) && 0"); + WEE_CHECK_EVAL("0", "((0 || 1) && 1) && 0"); + WEE_CHECK_EVAL("0", "abcd =~ (?-i)^ABC"); + WEE_CHECK_EVAL("0", "abcd =~ \\(abcd\\)"); + WEE_CHECK_EVAL("0", "(abcd) =~ \\(\\(abcd\\)\\)"); + WEE_CHECK_EVAL("0", "${test} == test"); + WEE_CHECK_EVAL("0", "${test2} == value2"); + WEE_CHECK_EVAL("0", "${buffer.number} == 2"); + WEE_CHECK_EVAL("0", "${window.buffer.number} == 2"); /* conditions evaluated as true */ - WEE_CHECK_EVAL_COND("1", "1"); - WEE_CHECK_EVAL_COND("1", "123"); - WEE_CHECK_EVAL_COND("1", "abc"); - WEE_CHECK_EVAL_COND("1", "2 == 2"); - WEE_CHECK_EVAL_COND("1", "2 >= 1"); - WEE_CHECK_EVAL_COND("1", "1 <= 2"); - WEE_CHECK_EVAL_COND("1", "1 != 2"); - WEE_CHECK_EVAL_COND("1", "18 > 5"); - WEE_CHECK_EVAL_COND("1", "5 < 18"); - WEE_CHECK_EVAL_COND("1", "1 == 18 > 5"); - WEE_CHECK_EVAL_COND("1", "abc == abc"); - WEE_CHECK_EVAL_COND("1", "(26 > 5)"); - WEE_CHECK_EVAL_COND("1", "((26 > 5))"); - WEE_CHECK_EVAL_COND("1", "(5 < 26)"); - WEE_CHECK_EVAL_COND("1", "def > abc"); - WEE_CHECK_EVAL_COND("1", "1 && 1"); - WEE_CHECK_EVAL_COND("1", "abc && 1"); - WEE_CHECK_EVAL_COND("1", "0 || 1"); - WEE_CHECK_EVAL_COND("1", "0 || 0 || 1"); - WEE_CHECK_EVAL_COND("1", "1 || 1 && 0"); - WEE_CHECK_EVAL_COND("1", "0 || (1 && 1)"); - WEE_CHECK_EVAL_COND("1", "0 || (0 || (1 && 1))"); - WEE_CHECK_EVAL_COND("1", "1 && (0 || 1)"); - WEE_CHECK_EVAL_COND("1", "(0 || 1) && 1"); - WEE_CHECK_EVAL_COND("1", "((0 || 1) && 1) && 1"); - WEE_CHECK_EVAL_COND("1", "abcd =~ ^ABC"); - WEE_CHECK_EVAL_COND("1", "abcd =~ (?-i)^abc"); - WEE_CHECK_EVAL_COND("1", "(abcd) =~ (abcd)"); - WEE_CHECK_EVAL_COND("1", "(abcd) =~ \\(abcd\\)"); - WEE_CHECK_EVAL_COND("1", "((abcd)) =~ \\(\\(abcd\\)\\)"); - WEE_CHECK_EVAL_COND("1", "${test} == value"); - WEE_CHECK_EVAL_COND("1", "${test2} =="); - WEE_CHECK_EVAL_COND("1", "${buffer.number} == 1"); - WEE_CHECK_EVAL_COND("1", "${window.buffer.number} == 1"); + WEE_CHECK_EVAL("1", "1"); + WEE_CHECK_EVAL("1", "123"); + WEE_CHECK_EVAL("1", "abc"); + WEE_CHECK_EVAL("1", "2 == 2"); + WEE_CHECK_EVAL("1", "2 >= 1"); + WEE_CHECK_EVAL("1", "1 <= 2"); + WEE_CHECK_EVAL("1", "1 != 2"); + WEE_CHECK_EVAL("1", "18 > 5"); + WEE_CHECK_EVAL("1", "5 < 18"); + WEE_CHECK_EVAL("1", "1 == 18 > 5"); + WEE_CHECK_EVAL("1", "abc == abc"); + WEE_CHECK_EVAL("1", "(26 > 5)"); + WEE_CHECK_EVAL("1", "((26 > 5))"); + WEE_CHECK_EVAL("1", "(5 < 26)"); + WEE_CHECK_EVAL("1", "def > abc"); + WEE_CHECK_EVAL("1", "1 && 1"); + WEE_CHECK_EVAL("1", "abc && 1"); + WEE_CHECK_EVAL("1", "0 || 1"); + WEE_CHECK_EVAL("1", "0 || 0 || 1"); + WEE_CHECK_EVAL("1", "1 || 1 && 0"); + WEE_CHECK_EVAL("1", "0 || (1 && 1)"); + WEE_CHECK_EVAL("1", "0 || (0 || (1 && 1))"); + WEE_CHECK_EVAL("1", "1 && (0 || 1)"); + WEE_CHECK_EVAL("1", "(0 || 1) && 1"); + WEE_CHECK_EVAL("1", "((0 || 1) && 1) && 1"); + WEE_CHECK_EVAL("1", "abcd =~ ^ABC"); + WEE_CHECK_EVAL("1", "abcd =~ (?-i)^abc"); + WEE_CHECK_EVAL("1", "(abcd) =~ (abcd)"); + WEE_CHECK_EVAL("1", "(abcd) =~ \\(abcd\\)"); + WEE_CHECK_EVAL("1", "((abcd)) =~ \\(\\(abcd\\)\\)"); + WEE_CHECK_EVAL("1", "${test} == value"); + WEE_CHECK_EVAL("1", "${test2} =="); + WEE_CHECK_EVAL("1", "${buffer.number} == 1"); + WEE_CHECK_EVAL("1", "${window.buffer.number} == 1"); hashtable_free (extra_vars); hashtable_free (options); @@ -171,16 +170,20 @@ TEST(Eval, EvalCondition) TEST(Eval, EvalExpression) { - struct t_hashtable *extra_vars; + struct t_hashtable *pointers, *extra_vars, *options; char *value, str_value[256]; void *toto; + pointers = NULL; + extra_vars = hashtable_new (32, WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_STRING, NULL, NULL); - hashtable_set (extra_vars, "test", "value"); CHECK(extra_vars); + hashtable_set (extra_vars, "test", "value"); + + options = NULL; POINTERS_EQUAL(NULL, eval_expression (NULL, NULL, NULL, NULL)); @@ -228,3 +231,72 @@ TEST(Eval, EvalExpression) hashtable_free (extra_vars); } + +/* + * Tests functions: + * eval_expression (replace with regex) + */ + +TEST(Eval, EvalReplaceRegex) +{ + struct t_hashtable *pointers, *extra_vars, *options; + char *value; + regex_t regex; + + pointers = hashtable_new (32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_POINTER, + NULL, NULL); + CHECK(pointers); + + extra_vars = hashtable_new (32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, NULL); + CHECK(extra_vars); + hashtable_set (extra_vars, "test", "value"); + + options = hashtable_new (32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, NULL); + CHECK(options); + + /* add brackets around URLs (regex as string) */ + hashtable_remove (pointers, "regex"); + hashtable_set (options, "regex", "\\w+://\\S+"); + hashtable_set (options, "regex_replace", "[ ${re:0} ]"); + WEE_CHECK_EVAL("test: [ http://weechat.org ]", + "test: http://weechat.org"); + + /* add brackets around URLs (compiled regex) */ + LONGS_EQUAL(0, string_regcomp (®ex, "\\w+://\\S+", + REG_EXTENDED | REG_ICASE)); + hashtable_set (pointers, "regex", ®ex); + hashtable_remove (options, "regex"); + hashtable_set (options, "regex_replace", "[ ${re:0} ]"); + WEE_CHECK_EVAL("test: [ http://weechat.org ]", + "test: http://weechat.org"); + regfree (®ex); + + /* hide passwords (regex as string) */ + hashtable_remove (pointers, "regex"); + hashtable_set (options, "regex", "(password=)(\\S+)"); + hashtable_set (options, "regex_replace", "${re:1}${hide:*,${re:2}}"); + WEE_CHECK_EVAL("password=*** password=***", + "password=abc password=def"); + + /* hide passwords (compiled regex) */ + LONGS_EQUAL(0, string_regcomp (®ex, "(password=)(\\S+)", + REG_EXTENDED | REG_ICASE)); + hashtable_set (pointers, "regex", ®ex); + hashtable_remove (options, "regex"); + hashtable_set (options, "regex_replace", "${re:1}${hide:*,${re:2}}"); + WEE_CHECK_EVAL("password=*** password=***", + "password=abc password=def"); + regfree (®ex); + + hashtable_free (pointers); + hashtable_free (extra_vars); + hashtable_free (options); +}