From 082cbe519bd14453fc4669758a81ff8d9ed6baca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Helleu?= Date: Wed, 1 Nov 2023 13:21:06 +0100 Subject: irc: add support of RGB colors in messages (issue #2025) This is made using standard color code '\x04' followed by text color (RGB as hexadecimal) and optional background (RGB as hexadecimal). --- src/plugins/irc/irc-color.c | 349 +++++++++++++++++++++++++++++++++----------- 1 file changed, 264 insertions(+), 85 deletions(-) (limited to 'src/plugins/irc/irc-color.c') diff --git a/src/plugins/irc/irc-color.c b/src/plugins/irc/irc-color.c index 012cfa5cd..b110fcfbc 100644 --- a/src/plugins/irc/irc-color.c +++ b/src/plugins/irc/irc-color.c @@ -83,6 +83,121 @@ char irc_color_term2irc[IRC_COLOR_TERM2IRC_NUM_COLORS] = regex_t *irc_color_regex_ansi = NULL; +/* + * Converts a RGB color to terminal color. + * + * Returns a terminal color (between 0 and 255), -1 if error. + */ + +int +irc_color_convert_rgb2term (long rgb) +{ + char str_color[64], *info_color, *error; + long number; + + if (rgb < 0) + return -1; + + snprintf (str_color, sizeof (str_color), "%ld", rgb); + + info_color = weechat_info_get ("color_rgb2term", str_color); + if (!info_color || !info_color[0]) + { + if (info_color) + free (info_color); + return -1; + } + + error = NULL; + number = strtol (info_color, &error, 10); + if (!error || error[0]) + { + free (info_color); + return -1; + } + + free (info_color); + + return (int)number; +} + +/* + * Converts a RGB color to IRC color. + * + * Returns a IRC color number (between 0 and 15), -1 if error. + */ + +int +irc_color_convert_rgb2irc (long rgb) +{ + char str_color[64], *error, *info_color; + long number; + + if (rgb < 0) + return -1; + + snprintf (str_color, sizeof (str_color), + "%ld,%d", + rgb, + IRC_COLOR_TERM2IRC_NUM_COLORS); + + info_color = weechat_info_get ("color_rgb2term", str_color); + if (!info_color || !info_color[0]) + { + if (info_color) + free (info_color); + return -1; + } + + error = NULL; + number = strtol (info_color, &error, 10); + if (!error || error[0] + || (number < 0) || (number >= IRC_COLOR_TERM2IRC_NUM_COLORS)) + { + free (info_color); + return -1; + } + + free (info_color); + + 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, *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]) + { + if (info_color) + free (info_color); + return -1; + } + + error = NULL; + number = strtol (info_color, &error, 10); + if (!error || error[0] || (number < 0) || (number > 0xFFFFFF)) + { + free (info_color); + return -1; + } + + free (info_color); + + return irc_color_convert_rgb2irc (number); +} + /* * Replaces IRC colors by WeeChat colors. * @@ -95,11 +210,12 @@ regex_t *irc_color_regex_ansi = NULL; char * irc_color_decode (const char *string, int keep_colors) { - char **out; - char str_fg[3], str_bg[3], str_color[128], str_key[128], str_to_add[128]; + char **out, *error; + char str_fg[16], str_bg[16], str_color[128], str_key[128], str_to_add[128]; const char *remapped_color; unsigned char *ptr_string; - int length, fg, bg, bold, reverse, italic, underline, rc; + int length, fg, bg, bold, reverse, italic, underline, color_number; + long fg_rgb, bg_rgb; if (!string) return NULL; @@ -211,19 +327,21 @@ irc_color_decode (const char *string, int keep_colors) bg = -1; if (str_fg[0]) { - rc = sscanf (str_fg, "%d", &fg); - if ((rc != EOF) && (rc >= 1)) - { + error = NULL; + fg = (int)strtol (str_fg, &error, 10); + if (error && !error[0]) fg %= IRC_NUM_COLORS; - } + else + fg = -1; } if (str_bg[0]) { - rc = sscanf (str_bg, "%d", &bg); - if ((rc != EOF) && (rc >= 1)) - { + error = NULL; + bg = (int)strtol (str_bg, &error, 10); + if (error && !error[0]) bg %= IRC_NUM_COLORS; - } + else + bg = -1; } /* search "fg,bg" in hashtable of remapped colors */ snprintf (str_key, sizeof (str_key), "%d,%d", fg, bg); @@ -253,6 +371,94 @@ irc_color_decode (const char *string, int keep_colors) } } break; + case IRC_COLOR_HEX_COLOR_CHAR: + ptr_string++; + str_fg[0] = '\0'; + str_bg[0] = '\0'; + if (isxdigit (ptr_string[0])) + { + /* foreground */ + length = 1; + while (isxdigit (ptr_string[length])) + { + length++; + if (length == 6) + break; + } + memcpy (str_fg, ptr_string, length); + str_fg[length] = '\0'; + ptr_string += length; + } + if ((ptr_string[0] == ',') && (isxdigit (ptr_string[1]))) + { + /* background */ + ptr_string++; + length = 1; + while (isxdigit (ptr_string[length])) + { + length++; + if (length == 6) + break; + } + memcpy (str_bg, ptr_string, length); + str_bg[length] = '\0'; + ptr_string += length; + } + if (keep_colors) + { + if (str_fg[0] || str_bg[0]) + { + fg_rgb = -1; + bg_rgb = -1; + if (str_fg[0]) + { + error = NULL; + fg_rgb = strtol (str_fg, &error, 16); + if (!error || error[0]) + fg_rgb = -1; + } + if (str_bg[0]) + { + error = NULL; + bg_rgb = strtol (str_bg, &error, 16); + if (!error || error[0]) + bg_rgb = -1; + } + str_fg[0] = '\0'; + str_bg[0] = '\0'; + if (fg_rgb >= 0) + { + color_number = irc_color_convert_rgb2term (fg_rgb); + if (color_number >= 0) + { + snprintf (str_fg, sizeof (str_fg), + "%d", color_number); + } + } + if (bg_rgb >= 0) + { + color_number = irc_color_convert_rgb2term (bg_rgb); + if (color_number >= 0) + { + snprintf (str_bg, sizeof (str_bg), + "%d", color_number); + } + } + snprintf (str_color, sizeof (str_color), + "|%s%s%s", + str_fg, + (str_bg[0]) ? "," : "", + str_bg); + snprintf (str_to_add, sizeof (str_to_add), "%s", + weechat_color (str_color)); + } + else + { + snprintf (str_to_add, sizeof (str_to_add), "%s", + weechat_color ("resetcolor")); + } + } + break; default: /* * we are not on an IRC color code, just copy the UTF-8 char @@ -364,6 +570,53 @@ irc_color_encode (const char *string, int keep_colors) } } break; + case 0x04: /* ^D */ + if (keep_colors) + weechat_string_dyn_concat (out, IRC_COLOR_HEX_COLOR_STR, -1); + ptr_string++; + if (isxdigit (ptr_string[0])) + { + /* foreground */ + length = 1; + while (isxdigit (ptr_string[length])) + { + length++; + if (length == 6) + break; + } + if (keep_colors) + { + weechat_string_dyn_concat (out, + (const char *)ptr_string, + length); + } + ptr_string += length; + } + if (ptr_string[0] == ',') + { + /* background */ + if (keep_colors) + weechat_string_dyn_concat (out, ",", -1); + ptr_string++; + if (isxdigit (ptr_string[0])) + { + length = 1; + while (isxdigit (ptr_string[length])) + { + length++; + if (length == 6) + break; + } + if (keep_colors) + { + weechat_string_dyn_concat (out, + (const char *)ptr_string, + length); + } + ptr_string += length; + } + } + break; case 0x0F: /* ^O */ if (keep_colors) weechat_string_dyn_concat (out, IRC_COLOR_RESET_STR, -1); @@ -398,80 +651,6 @@ irc_color_encode (const char *string, int keep_colors) return weechat_string_dyn_free (out, 0); } -/* - * 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, *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]) - { - if (info_color) - free (info_color); - return -1; - } - - error = NULL; - number = strtol (info_color, &error, 10); - if (!error || error[0] - || (number < 0) || (number >= IRC_COLOR_TERM2IRC_NUM_COLORS)) - { - free (info_color); - return -1; - } - - free (info_color); - - 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, *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]) - { - if (info_color) - free (info_color); - return -1; - } - - error = NULL; - number = strtol (info_color, &error, 10); - if (!error || error[0] || (number < 0) || (number > 0xFFFFFF)) - { - free (info_color); - return -1; - } - - free (info_color); - - return irc_color_convert_rgb2irc (number); -} - /* * Replaces ANSI colors by IRC colors (or removes them). * -- cgit v1.2.3