diff options
Diffstat (limited to 'src/plugins/irc')
-rw-r--r-- | src/plugins/irc/irc-color.c | 380 | ||||
-rw-r--r-- | src/plugins/irc/irc-color.h | 11 | ||||
-rw-r--r-- | src/plugins/irc/irc.c | 3 |
3 files changed, 392 insertions, 2 deletions
diff --git a/src/plugins/irc/irc-color.c b/src/plugins/irc/irc-color.c index 69b0381eb..bd1895b1f 100644 --- a/src/plugins/irc/irc-color.c +++ b/src/plugins/irc/irc-color.c @@ -23,6 +23,7 @@ #include <stdio.h> #include <string.h> #include <ctype.h> +#include <regex.h> #include "../weechat-plugin.h" #include "irc.h" @@ -45,9 +46,29 @@ char *irc_color_to_weechat[IRC_NUM_COLORS] = /* 11 */ "lightcyan", /* 12 */ "lightblue", /* 13 */ "lightmagenta", - /* 14 */ "gray", - /* 15 */ "white" + /* 14 */ "darkgray", + /* 15 */ "gray" }; +char irc_color_term2irc[IRC_COLOR_TERM2IRC_NUM_COLORS] = +{ /* term > IRC */ + 1, /* 0 1 (black) */ + 5, /* 1 5 (red) */ + 3, /* 2 3 (green) */ + 7, /* 3 7 (brown) */ + 2, /* 4 2 (blue) */ + 6, /* 5 6 (magenta) */ + 10, /* 6 10 (cyan) */ + 15, /* 7 15 (gray) */ + 14, /* 8 14 (darkgray) */ + 4, /* 9 4 (lightred) */ + 9, /* 10 9 (lightgreen) */ + 8, /* 11 8 (yellow) */ + 12, /* 12 12 (lightblue) */ + 13, /* 13 13 (lightmagenta) */ + 11, /* 14 11 (lightcyan) */ + 0, /* 15 0 (white) */ +}; +regex_t *irc_color_regex_ansi = NULL; /* @@ -362,6 +383,343 @@ irc_color_encode (const char *string, int keep_colors) } /* + * Converts a RGB color to IRC color. + * + * Returns a IRC color number (between 0 and 15), -1 if error. + */ + +int +irc_color_convert_rgb2irc (int rgb) +{ + char str_color[64], *error; + const char *info_color; + long number; + + snprintf (str_color, sizeof (str_color), + "%d,%d", + rgb, + IRC_COLOR_TERM2IRC_NUM_COLORS); + + info_color = weechat_info_get ("color_rgb2term", str_color); + if (!info_color || !info_color[0]) + return -1; + + error = NULL; + number = strtol (info_color, &error, 10); + if (!error || error[0] + || (number < 0) || (number >= IRC_COLOR_TERM2IRC_NUM_COLORS)) + { + return -1; + } + + return irc_color_term2irc[number]; +} + +/* + * Converts a terminal color to IRC color. + * + * Returns a IRC color number (between 0 and 15), -1 if error. + */ + +int +irc_color_convert_term2irc (int color) +{ + char str_color[64], *error; + const char *info_color; + long number; + + snprintf (str_color, sizeof (str_color), "%d", color); + + info_color = weechat_info_get ("color_term2rgb", str_color); + if (!info_color || !info_color[0]) + return -1; + + error = NULL; + number = strtol (info_color, &error, 10); + if (!error || error[0] || (number < 0) || (number > 0xFFFFFF)) + return -1; + + return irc_color_convert_rgb2irc (number); +} + +/* + * Replaces ANSI colors by IRC colors (or removes them). + * + * This callback is called by irc_color_decode_ansi, it must not be called + * directly. + */ + +char * +irc_color_decode_ansi_cb (void *data, const char *text) +{ + struct t_irc_color_ansi_state *ansi_state; + char *text2, **items, *output, str_color[128]; + int i, length, num_items, value, color; + + ansi_state = (struct t_irc_color_ansi_state *)data; + + /* if we don't keep colors of if text is empty, just return empty string */ + if (!ansi_state->keep_colors || !text || !text[0]) + return strdup (""); + + /* only sequences ending with 'm' are used, the others are discarded */ + length = strlen (text); + if (text[length - 1] != 'm') + return strdup (""); + + /* sequence "\33[m" resets color */ + if (length < 4) + return strdup (weechat_color ("reset")); + + text2 = NULL; + items = NULL; + output = NULL; + + /* extract text between "\33[" and "m" */ + text2 = weechat_strndup (text + 2, length - 3); + if (!text2) + goto end; + + items = weechat_string_split (text2, ";", 0, 0, &num_items); + if (!items) + goto end; + + output = malloc ((32 * num_items) + 1); + if (!output) + goto end; + output[0] = '\0'; + + for (i = 0; i < num_items; i++) + { + value = atoi (items[i]); + switch (value) + { + case 0: /* reset */ + strcat (output, IRC_COLOR_RESET_STR); + ansi_state->bold = 0; + ansi_state->underline = 0; + ansi_state->italic = 0; + break; + case 1: /* bold */ + if (!ansi_state->bold) + { + strcat (output, IRC_COLOR_BOLD_STR); + ansi_state->bold = 1; + } + break; + case 2: /* remove bold */ + case 21: + case 22: + if (ansi_state->bold) + { + strcat (output, IRC_COLOR_BOLD_STR); + ansi_state->bold = 0; + } + break; + case 3: /* italic */ + if (!ansi_state->italic) + { + strcat (output, IRC_COLOR_ITALIC_STR); + ansi_state->italic = 1; + } + break; + case 4: /* underline */ + if (!ansi_state->underline) + { + strcat (output, IRC_COLOR_UNDERLINE_STR); + ansi_state->underline = 1; + } + break; + case 23: /* remove italic */ + if (ansi_state->italic) + { + strcat (output, IRC_COLOR_ITALIC_STR); + ansi_state->italic = 0; + } + break; + case 24: /* remove underline */ + if (ansi_state->underline) + { + strcat (output, IRC_COLOR_UNDERLINE_STR); + ansi_state->underline = 0; + } + break; + case 30: /* text color */ + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + snprintf (str_color, sizeof (str_color), + "%c%02d", + IRC_COLOR_COLOR_CHAR, + irc_color_term2irc[value - 30]); + strcat (output, str_color); + break; + case 38: /* text color */ + if (i + 1 < num_items) + { + switch (atoi (items[i + 1])) + { + case 2: /* RGB color */ + if (i + 4 < num_items) + { + color = irc_color_convert_rgb2irc ( + (atoi (items[i + 2]) << 16) | + (atoi (items[i + 3]) << 8) | + atoi (items[i + 4])); + if (color >= 0) + { + snprintf (str_color, sizeof (str_color), + "%c%02d", + IRC_COLOR_COLOR_CHAR, + color); + strcat (output, str_color); + } + i += 4; + } + break; + case 5: /* terminal color (0-255) */ + if (i + 2 < num_items) + { + color = irc_color_convert_term2irc (atoi (items[i + 2])); + if (color >= 0) + { + snprintf (str_color, sizeof (str_color), + "%c%02d", + IRC_COLOR_COLOR_CHAR, + color); + strcat (output, str_color); + } + i += 2; + } + break; + } + } + break; + case 39: /* default text color */ + snprintf (str_color, sizeof (str_color), + "%c15", + IRC_COLOR_COLOR_CHAR); + strcat (output, str_color); + break; + case 40: /* background color */ + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + snprintf (str_color, sizeof (str_color), + "%c,%02d", + IRC_COLOR_COLOR_CHAR, + irc_color_term2irc[value - 40]); + strcat (output, str_color); + break; + case 48: /* background color */ + if (i + 1 < num_items) + { + switch (atoi (items[i + 1])) + { + case 2: /* RGB color */ + if (i + 4 < num_items) + { + color = irc_color_convert_rgb2irc ( + (atoi (items[i + 2]) << 16) | + (atoi (items[i + 3]) << 8) | + atoi (items[i + 4])); + if (color >= 0) + { + snprintf (str_color, sizeof (str_color), + "%c,%02d", + IRC_COLOR_COLOR_CHAR, + color); + strcat (output, str_color); + } + i += 4; + } + break; + case 5: /* terminal color (0-255) */ + if (i + 2 < num_items) + { + color = irc_color_convert_term2irc (atoi (items[i + 2])); + if (color >= 0) + { + snprintf (str_color, sizeof (str_color), + "%c,%02d", + IRC_COLOR_COLOR_CHAR, + color); + strcat (output, str_color); + } + i += 2; + } + break; + } + } + break; + case 49: /* default background color */ + snprintf (str_color, sizeof (str_color), + "%c,01", + IRC_COLOR_COLOR_CHAR); + strcat (output, str_color); + break; + } + } + +end: + if (items) + weechat_string_free_split (items); + if (text2) + free (text2); + + return (output) ? output : strdup (""); +} + +/* + * Replaces ANSI colors by IRC colors. + * + * If keep_colors == 0: removes any color/style in message otherwise keeps + * colors. + * + * Note: result must be freed after use. + */ + +char * +irc_color_decode_ansi (const char *string, int keep_colors) +{ + struct t_irc_color_ansi_state ansi_state; + + /* allocate/compile regex if needed (first call) */ + if (!irc_color_regex_ansi) + { + irc_color_regex_ansi = malloc (sizeof (*irc_color_regex_ansi)); + if (!irc_color_regex_ansi) + return NULL; + if (weechat_string_regcomp (irc_color_regex_ansi, + weechat_info_get ("color_ansi_regex", NULL), + REG_EXTENDED) != 0) + { + free (irc_color_regex_ansi); + irc_color_regex_ansi = NULL; + return NULL; + } + } + + ansi_state.keep_colors = keep_colors; + ansi_state.bold = 0; + ansi_state.underline = 0; + ansi_state.italic = 0; + + return weechat_string_replace_regex (string, irc_color_regex_ansi, + "$0", '$', + &irc_color_decode_ansi_cb, + &ansi_state); +} + +/* * Callback for modifiers "irc_color_decode" and "irc_color_encode". * * This modifier can be used by other plugins to decode/encode IRC colors in @@ -385,6 +743,9 @@ irc_color_modifier_cb (void *data, const char *modifier, if (strcmp (modifier, "irc_color_encode") == 0) return irc_color_encode (string, keep_colors); + if (strcmp (modifier, "irc_color_decode_ansi") == 0) + return irc_color_decode_ansi (string, keep_colors); + /* unknown modifier */ return NULL; } @@ -403,3 +764,18 @@ irc_color_for_tags (const char *color) return weechat_string_replace (color, ",", ":"); } + +/* + * Ends IRC colors. + */ + +void +irc_color_end () +{ + if (irc_color_regex_ansi) + { + regfree (irc_color_regex_ansi); + free (irc_color_regex_ansi); + irc_color_regex_ansi = NULL; + } +} diff --git a/src/plugins/irc/irc-color.h b/src/plugins/irc/irc-color.h index 0224bd11d..5136d7690 100644 --- a/src/plugins/irc/irc-color.h +++ b/src/plugins/irc/irc-color.h @@ -59,6 +59,8 @@ #define IRC_COLOR_UNDERLINE_CHAR '\x1F' /* underlined text */ #define IRC_COLOR_UNDERLINE_STR "\x1F" /* [1F]...[1F] */ +#define IRC_COLOR_TERM2IRC_NUM_COLORS 16 + /* macros for WeeChat core and IRC colors */ #define IRC_COLOR_BAR_FG weechat_color("bar_fg") @@ -92,11 +94,20 @@ #define IRC_COLOR_ITEM_LAG_COUNTING weechat_color(weechat_config_string(irc_config_color_item_lag_counting)) #define IRC_COLOR_ITEM_LAG_FINISHED weechat_color(weechat_config_string(irc_config_color_item_lag_finished)) +struct t_irc_color_ansi_state +{ + char keep_colors; + char bold; + char underline; + char italic; +}; + extern char *irc_color_decode (const char *string, int keep_colors); extern char *irc_color_encode (const char *string, int keep_colors); extern char *irc_color_modifier_cb (void *data, const char *modifier, const char *modifier_data, const char *string); extern char *irc_color_for_tags (const char *color); +extern void irc_color_end (); #endif /* __WEECHAT_IRC_COLOR_H */ diff --git a/src/plugins/irc/irc.c b/src/plugins/irc/irc.c index 2b341b99f..6c807ddaf 100644 --- a/src/plugins/irc/irc.c +++ b/src/plugins/irc/irc.c @@ -189,6 +189,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) /* modifiers */ weechat_hook_modifier ("irc_color_decode", &irc_color_modifier_cb, NULL); weechat_hook_modifier ("irc_color_encode", &irc_color_modifier_cb, NULL); + weechat_hook_modifier ("irc_color_decode_ansi", &irc_color_modifier_cb, NULL); /* hook completions */ irc_completion_init (); @@ -281,5 +282,7 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) irc_redirect_end (); + irc_color_end (); + return WEECHAT_RC_OK; } |