/* * Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or (at your * option) any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include #define LIBIRC_COLORPARSER_BOLD (1<<1) #define LIBIRC_COLORPARSER_UNDERLINE (1<<2) #define LIBIRC_COLORPARSER_REVERSE (1<<3) #define LIBIRC_COLORPARSER_COLOR (1<<4) #define LIBIRC_COLORPARSER_MAXCOLORS 15 static const char * color_replacement_table[] = { "WHITE", "BLACK", "DARKBLUE", "DARKGREEN", "RED", "BROWN", "PURPLE", "OLIVE", "YELLOW", "GREEN", "TEAL", "CYAN", "BLUE", "MAGENTA", "DARKGRAY", "LIGHTGRAY", 0 }; static inline void libirc_colorparser_addorcat (char ** destline, unsigned int * destlen, const char * str) { unsigned int len = strlen(str); if ( *destline ) { strcpy (*destline, str); *destline += len; } else *destlen += len; } static void libirc_colorparser_applymask (unsigned int * mask, char ** destline, unsigned int * destlen, unsigned int bitmask, const char * start, const char * end) { if ( (*mask & bitmask) != 0 ) { *mask &= ~bitmask; libirc_colorparser_addorcat (destline, destlen, end); } else { *mask |= bitmask; libirc_colorparser_addorcat (destline, destlen, start); } } static void libirc_colorparser_applycolor (unsigned int * mask, char ** destline, unsigned int * destlen, unsigned int colorid, unsigned int bgcolorid) { const char * end = "[/COLOR]"; char startbuf[64]; if ( bgcolorid != 0 ) sprintf (startbuf, "[COLOR=%s/%s]", color_replacement_table[colorid], color_replacement_table[bgcolorid]); else sprintf (startbuf, "[COLOR=%s]", color_replacement_table[colorid]); if ( (*mask & LIBIRC_COLORPARSER_COLOR) != 0 ) libirc_colorparser_addorcat (destline, destlen, end); *mask |= LIBIRC_COLORPARSER_COLOR; libirc_colorparser_addorcat (destline, destlen, startbuf); } static void libirc_colorparser_closetags (unsigned int * mask, char ** destline, unsigned int * destlen) { if ( *mask & LIBIRC_COLORPARSER_BOLD ) libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_BOLD, 0, "[/B]"); if ( *mask & LIBIRC_COLORPARSER_UNDERLINE ) libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_UNDERLINE, 0, "[/U]"); if ( *mask & LIBIRC_COLORPARSER_REVERSE ) libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_REVERSE, 0, "[/I]"); if ( *mask & LIBIRC_COLORPARSER_COLOR ) libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_COLOR, 0, "[/COLOR]"); } /* * IRC to [code] color conversion. Or strip. */ static char * libirc_colorparser_irc2code (const char * source, int strip) { unsigned int mask = 0, destlen = 0; char * destline = 0, *d = 0; const char *p; int current_bg = 0; /* * There will be two passes. First pass calculates the total length of * the destination string. The second pass allocates memory for the string, * and fills it. */ while ( destline == 0 ) // destline will be set after the 2nd pass { if ( destlen > 0 ) { // This is the 2nd pass; allocate memory. if ( (destline = malloc (destlen)) == 0 ) return 0; d = destline; } for ( p = source; *p; p++ ) { switch (*p) { case 0x02: // bold if ( strip ) continue; libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_BOLD, "[B]", "[/B]"); break; case 0x1F: // underline if ( strip ) continue; libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_UNDERLINE, "[U]", "[/U]"); break; case 0x16: // reverse if ( strip ) continue; libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_REVERSE, "[I]", "[/I]"); break; case 0x0F: // reset colors if ( strip ) continue; libirc_colorparser_closetags (&mask, &d, &destlen); break; case 0x03: // set color if ( isdigit (p[1]) ) { // Parse int bgcolor = -1, color = p[1] - 0x30; p++; if ( isdigit (p[1]) ) { color = color * 10 + (p[1] - 0x30); p++; } // If there is a comma, search for the following // background color if ( p[1] == ',' && isdigit (p[2]) ) { bgcolor = p[2] - 0x30; p += 2; if ( isdigit (p[1]) ) { bgcolor = bgcolor * 10 + (p[1] - 0x30); p++; } } // Check for range if ( color <= LIBIRC_COLORPARSER_MAXCOLORS && bgcolor <= LIBIRC_COLORPARSER_MAXCOLORS ) { if ( strip ) continue; if ( bgcolor != -1 ) current_bg = bgcolor; libirc_colorparser_applycolor (&mask, &d, &destlen, color, current_bg); } } break; default: if ( destline ) *d++ = *p; else destlen++; break; } } // Close all the opened tags libirc_colorparser_closetags (&mask, &d, &destlen); destlen++; // for 0-terminator } *d = '\0'; return destline; } static int libirc_colorparser_colorlookup (const char * color) { int i; for ( i = 0; color_replacement_table[i]; i++ ) if ( !strcmp (color, color_replacement_table[i]) ) return i; return -1; } /* * [code] to IRC color conversion. */ char * irc_color_convert_to_mirc (const char * source) { unsigned int destlen = 0; char * destline = 0, *d = 0; const char *p1, *p2, *cur; /* * There will be two passes. First pass calculates the total length of * the destination string. The second pass allocates memory for the string, * and fills it. */ while ( destline == 0 ) // destline will be set after the 2nd pass { if ( destlen > 0 ) { // This is the 2nd pass; allocate memory. if ( (destline = malloc (destlen)) == 0 ) return 0; d = destline; } cur = source; while ( (p1 = strchr (cur, '[')) != 0 ) { const char * replacedval = 0; p2 = 0; // Check if the closing bracket is available after p1 // and the tag length is suitable if ( p1[1] != '\0' && (p2 = strchr (p1, ']')) != 0 && (p2 - p1) > 1 && (p2 - p1) < 31 ) { // Get the tag char tagbuf[32]; int taglen = p2 - p1 - 1; memcpy (tagbuf, p1 + 1, taglen); tagbuf[taglen] = '\0'; if ( !strcmp (tagbuf, "/COLOR") ) replacedval = "\x0F"; else if ( strstr (tagbuf, "COLOR=") == tagbuf ) { int color, bgcolor = -2; char * bcol; bcol = strchr (tagbuf + 6, '/'); if ( bcol ) { *bcol++ = '\0'; bgcolor = libirc_colorparser_colorlookup (bcol); } color = libirc_colorparser_colorlookup (tagbuf + 6); if ( color != -1 && bgcolor == -2 ) { sprintf (tagbuf, "\x03%02d", color); replacedval = tagbuf; } else if ( color != -1 && bgcolor >= 0 ) { sprintf (tagbuf, "\x03%02d,%02d", color, bgcolor); replacedval = tagbuf; } } else if ( !strcmp (tagbuf, "B") || !strcmp (tagbuf, "/B") ) replacedval = "\x02"; else if ( !strcmp (tagbuf, "U") || !strcmp (tagbuf, "/U") ) replacedval = "\x1F"; else if ( !strcmp (tagbuf, "I") || !strcmp (tagbuf, "/I") ) replacedval = "\x16"; } if ( replacedval ) { // add a part before the tag int partlen = p1 - cur; if ( destline ) { memcpy (d, cur, partlen); d += partlen; } else destlen += partlen; // Add the replacement libirc_colorparser_addorcat (&d, &destlen, replacedval); // And move the pointer cur = p2 + 1; } else { // add a whole part before the end tag int partlen; if ( !p2 ) p2 = cur + strlen(cur); partlen = p2 - cur + 1; if ( destline ) { memcpy (d, cur, partlen); d += partlen; } else destlen += partlen; // And move the pointer cur = p2 + 1; } } // Add the rest of string libirc_colorparser_addorcat (&d, &destlen, cur); destlen++; // for 0-terminator } *d = '\0'; return destline; } char * irc_color_strip_from_mirc (const char * message) { return libirc_colorparser_irc2code (message, 1); } char * irc_color_convert_from_mirc (const char * message) { return libirc_colorparser_irc2code (message, 0); }