summaryrefslogtreecommitdiff
path: root/src/plugins/irc
diff options
context:
space:
mode:
authorSebastien Helleu <flashcode@flashtux.org>2014-03-15 11:12:49 +0100
committerSebastien Helleu <flashcode@flashtux.org>2014-03-15 11:12:49 +0100
commitd3c85c920c367d23820d58e448dfec30873a488c (patch)
tree73f334aaf413e882eab7f8160696c01585efb387 /src/plugins/irc
parente38f437ad739967c5e8e5388ff47d38fb88b2a9f (diff)
downloadweechat-d3c85c920c367d23820d58e448dfec30873a488c.zip
irc: add modifier "irc_color_decode_ansi"
Diffstat (limited to 'src/plugins/irc')
-rw-r--r--src/plugins/irc/irc-color.c380
-rw-r--r--src/plugins/irc/irc-color.h11
-rw-r--r--src/plugins/irc/irc.c3
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;
}