loperIRCLogBot/src/libircclient-1.9/src/colors.c

389 lines
8.4 KiB
C

/*
* 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 <ctype.h>
#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);
}