1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 08:47:17 +01:00
SqMod/external/LibIRC/colors.c
Sandu Liviu Catalin bedf03c9cd Implemented the IRC library.
Fixed a bug in the Routine system that caused crashes when constructed with only the first three arguments because it wasn't attached.
Implemented a gentle release of functions to not release them if the reference count is 1.
Adjusted the Routine and Command system to not be necessary to include them in the module core.
Moved the INI and XML libraries into their own namespace.
Various other modifications and fixes.
2016-02-23 05:23:56 +02:00

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);
}