/*
xterm 256 color code parser by Igor van den Hoven
v1.0 02/11/2009
v1.4 06/24/2011 v1.4.2 06/30/2011
This code is placed in the public domain.
*/
/*
For xterm 256 color foreground colors use:
<aaa> to <fff> for RGB foreground colors
<g00> to <g23> for grayscale foreground colors
For xterm 256 color background colors use:
<AAA> to <FFF> for RGB background colors
<G00> to <G23> for grayscale background colors
Background color support is commented out by default
With 256 colors disabled colors are converted to 16 color ANSI.
*/
/*
For 32 color codes use:
^a - dark azure ^A - azure
^b - dark blue ^B - blue
^c - dark cyan ^C - cyan
^e - dark ebony ^E - ebony
^g - dark green ^G - green
^j - dark jade ^J - jade
^l - dark lime ^L - lime
^m - dark magenta ^M - magenta
^o - dark orange ^O - orange
^p - dark pink ^P - pink
^r - dark red ^R - red
^s - dark silver ^S - silver
^t - dark tan ^T - tan
^v - dark violet ^V - violet
^w - dark white ^W - white
^y - dark yellow ^Y - yellow
With 256 colors disabled colors are converted to 16 color ANSI.
*/
#include <stdio.h>
#include <string.h>
/*
256 to 16 color conversion table
*/
char *ansi_colors[256] =
{
"\e =
{
"\e[22;30m", "\e[22;31m", "\e[22;32m", "\e[22;33m", "\e[22;34m", "\e[22;35m", "\e[22;36m", "\e[22;37m",
"\e[1;30m", "\e[1;31m", "\e[1;32m", "\e[1;33m", "\e[1;34m", "\e[1;35m", "\e[1;36m", "\e[1;37m",
"\e[22;30m", "\e[22;34m", "\e[22;34m", "\e[22;34m", "\e[1;34m", "\e[1;34m",
"\e[22;32m", "\e[22;36m", "\e[22;36m", "\e[22;34m", "\e[1;34m", "\e[1;34m",
"\e[22;32m", "\e[22;36m", "\e[22;36m", "\e[22;36m", "\e[1;34m", "\e[1;34m",
"\e[22;32m", "\e[22;32m", "\e[22;36m", "\e[22;36m", "\e[22;36m", "\e[1;36m",
"\e[1;32m", "\e[1;32m", "\e[1;32m", "\e[22;36m", "\e[1;36m", "\e[1;36m",
"\e[1;32m", "\e[1;32m", "\e[1;32m", "\e[1;36m", "\e[1;36m", "\e[1;36m",
"\e[22;31m", "\e[22;35m", "\e[22;35m", "\e[22;34m", "\e[1;34m", "\e[1;34m",
"\e[22;33m", "\e[1;30m", "\e[22;34m", "\e[22;34m", "\e[1;34m", "\e[1;34m",
"\e[22;33m", "\e[22;32m", "\e[22;36m", "\e[22;36m", "\e[1;34m", "\e[1;34m",
"\e[22;32m", "\e[22;32m", "\e[22;36m", "\e[22;36m", "\e[22;36m", "\e[1;36m",
"\e[1;32m", "\e[1;32m", "\e[1;32m", "\e[22;36m", "\e[1;36m", "\e[1;36m",
"\e[1;32m", "\e[1;32m", "\e[1;32m", "\e[1;36m", "\e[1;36m", "\e[1;36m",
"\e[22;31m", "\e[22;35m", "\e[22;35m", "\e[22;35m", "\e[1;34m", "\e[1;34m",
"\e[22;33m", "\e[22;31m", "\e[22;35m", "\e[22;35m", "\e[1;34m", "\e[1;34m",
"\e[22;33m", "\e[22;33m", "\e[22;37m", "\e[22;34m", "\e[1;34m", "\e[1;34m",
"\e[22;33m", "\e[22;33m", "\e[22;32m", "\e[22;36m", "\e[22;36m", "\e[1;34m",
"\e[1;32m", "\e[1;32m", "\e[1;32m", "\e[22;36m", "\e[1;36m", "\e[1;36m",
"\e[1;32m", "\e[1;32m", "\e[1;32m", "\e[1;32m", "\e[1;36m", "\e[1;36m",
"\e[22;31m", "\e[22;31m", "\e[22;35m", "\e[22;35m", "\e[22;35m", "\e[1;35m",
"\e[22;31m", "\e[22;31m", "\e[22;35m", "\e[22;35m", "\e[22;35m", "\e[1;35m",
"\e[22;33m", "\e[22;33m", "\e[22;31m", "\e[22;35m", "\e[22;35m", "\e[1;34m",
"\e[22;33m", "\e[22;33m", "\e[22;33m", "\e[22;37m", "\e[1;34m", "\e[1;34m",
"\e[22;33m", "\e[22;33m", "\e[22;33m", "\e[1;32m", "\e[1;36m", "\e[1;36m",
"\e[1;33m", "\e[1;33m", "\e[1;32m", "\e[1;32m", "\e[1;36m", "\e[1;36m",
"\e[1;31m", "\e[1;31m", "\e[1;31m", "\e[22;35m", "\e[1;35m", "\e[1;35m",
"\e[1;31m", "\e[1;31m", "\e[1;31m", "\e[22;35m", "\e[1;35m", "\e[1;35m",
"\e[1;31m", "\e[1;31m", "\e[1;31m", "\e[22;35m", "\e[1;35m", "\e[1;35m",
"\e[22;33m", "\e[22;33m", "\e[22;33m", "\e[1;31m", "\e[1;35m", "\e[1;35m",
"\e[1;33m", "\e[1;33m", "\e[1;33m", "\e[1;33m", "\e[1;37m", "\e[1;37m",
"\e[1;33m", "\e[1;33m", "\e[1;33m", "\e[1;33m", "\e[1;37m", "\e[1;37m",
"\e[1;31m", "\e[1;31m", "\e[1;31m", "\e[1;35m", "\e[1;35m", "\e[1;35m",
"\e[1;31m", "\e[1;31m", "\e[1;31m", "\e[1;35m", "\e[1;35m", "\e[1;35m",
"\e[1;31m", "\e[1;31m", "\e[1;31m", "\e[1;31m", "\e[1;35m", "\e[1;35m",
"\e[1;33m", "\e[1;33m", "\e[1;31m", "\e[1;31m", "\e[1;35m", "\e[1;35m",
"\e[1;33m", "\e[1;33m", "\e[1;33m", "\e[1;33m", "\e[1;37m", "\e[1;37m",
"\e[1;33m", "\e[1;33m", "\e[1;33m", "\e[1;33m", "\e[1;37m", "\e[1;37m",
"\e[1;30m", "\e[1;30m", "\e[1;30m", "\e[1;30m", "\e[1;30m", "\e[1;30m",
"\e[1;30m", "\e[1;30m", "\e[1;30m", "\e[1;30m", "\e[1;30m", "\e[1;30m",
"\e[22;37m", "\e[22;37m", "\e[22;37m", "\e[22;37m", "\e[22;37m", "\e[22;37m",
"\e[1;37m", "\e[1;37m", "\e[1;37m", "\e[1;37m", "\e[1;37m", "\e[1;37m"
};
/*
32 to 256 color conversion table
*/
char *alphabet_colors_dark[26] =
{
"<abd>", "<aad>", "<add>", "", "<g04>", "", "<ada>", "", "", "<adb>", "", "<bda>", "<dad>",
"", "<dba>", "<dab>", "", "<daa>", "<ccc>", "<cba>", "", "<bad>", "<ddd>", "", "<dda>", ""
};
char *alphabet_colors_bold[26] =
{
"<acf>", "<aaf>", "<aff>", "", "<bbb>", "", "<afa>", "", "", "<afc>", "", "<cfa>", "<faf>",
"", "<fca>", "<fac>", "", "<faa>", "<eee>", "<eda>", "", "<caf>", "<fff>", "", "<ffa>", ""
};
// Make sure that the output buffer remains at least 4 times larger than the user input buffer.
// colors should either be 0 for no colors, 16 for ansi colors, or 256 for xterm 256 colors.
int substitute_color(char *input, char *output, int colors)
{
char *pti, *pto, old[6] = { 0 };
pti = input;
pto = output;
while (*pti)
{
switch (*pti)
{
case '^':
if (isalpha(pti[1]))
{
if (pti[2] == '^' && isalpha(pti[3]))
{
pti += 2;
continue;
}
if (strncmp(old, pti, 2) && colors)
{
if (pti[1] >= 'a' && pti[1] <= 'z')
{
pto += substitute_color(alphabet_colors_dark[pti[1] - 'a'], pto, colors);
}
else
{
pto += substitute_color(alphabet_colors_bold[pti[1] - 'A'], pto, colors);
}
}
pti += sprintf(old, "%c%c", pti[0], pti[1]);
}
else
{
if (pti[1] == '^')
{
pti++;
}
*pto++ = *pti++;
}
break;
case '<':
if (pti[1] >= 'a' && pti[1] <= 'f' && pti[2] >= 'a' && pti[2] <= 'f' && pti[3] >= 'a' && pti[3] <= 'f' && pti[4] == '>')
{
if (strncmp(old, pti, 5) && colors)
{
if (colors == 256)
{
pto += sprintf(pto, "\033[38;5;%dm", 16 + (pti[1] - 'a') * 36 + (pti[2] - 'a') * 6 + (pti[3] - 'a'));
}
else
{
pto += substitute_color(ansi_colors[16 + (pti[1] - 'a') * 36 + (pti[2] - 'a') * 6 + (pti[3] - 'a')], pto, colors);
}
}
pti += sprintf(old, "<%c%c%c>", pti[1], pti[2], pti[3]);
}
/*
else if (pti[1] >= 'A' && pti[1] <= 'F' && pti[2] >= 'A' && pti[2] <= 'F' && pti[3] >= 'A' && pti[3] <= 'F' && pti[4] == '>')
{
if (colors == 256)
{
pto += sprintf(pto, "\033[48;5;%dm", 16 + (pti[1] - 'A') * 36 + (pti[2] - 'A') * 6 + (pti[3] - 'A'));
}
else if (colors)
{
pto += sprintf(pto, "\033[4%dm", (pti[1] && pti[1] >= pti[2] ? pti[1] >= pti[3] : 0) + (pti[2] && pti[2] >= pti[1] ? pti[2] >= pti[3] : 0) * 2 + (pti[3] && pti[3] >= pti[2] ? pti[3] >= pti[1] : 0) * 4);
}
pti += 5;
}
*/
else if (pti[1] == 'g' && isdigit((int) pti[2]) && isdigit((int) pti[3]) && (pti[2] - '0') * 10 + (pti[3] - '0') >= 0 && (pti[2] - '0') * 10 + (pti[3] - '0') < 24 && pti[4] == '>')
{
if (strncmp(old, pti, 5) && colors)
{
if (colors == 256)
{
pto += sprintf(pto, "\033[38;5;%dm", 232 + (pti[2] - '0') * 10 + (pti[3] - '0'));
}
else
{
pto += substitute_color(ansi_colors[232 + (pti[2] - '0') * 10 + (pti[3] - '0')], pto, colors);
}
}
pti += sprintf(old, "<%c%c%c>", pti[1], pti[2], pti[3]);
}
/*
else if (pti[1] == 'G' && isdigit((int) pti[2]) && isdigit((int) pti[3]) && (pti[2] - '0') * 10 + (pti[3] - '0') >= 0 && (pti[2] - '0') * 10 + (pti[3] - '0') < 24 && pti[4] == '>')
{
if (colors == 256)
{
pto += sprintf(pto, "\033[48;5;%dm", 232 + (pti[2] - '0') * 10 + (pti[3] - '0'));
}
else if (colors)
{
pto += sprintf(pto, "\033[4%dm", ((pti[2] - '0') * 10 + (pti[3] - '0')) / 12 ? 7 : 0);
}
pti += 5;
}
*/
else
{
*pto++ = *pti++;
}
break;
default:
*pto++ = *pti++;
break;
}
}
*pto = 0;
return pto - output;
}
[/code]
/*
strip unneccessary color changes from string
string is modified in place
st - state
lc - last color value
cc - current color
d1 - first digit
rp - read pointer
wp - write pointer
esc - escape character
*/
char *strip_colors(char *s,size_t sz) {
enum {normal, escaped, digits} st=normal;
char lc=0,cc,d1,*rp=s,*wp=s,esc=046;
while (*rp && rp != s+sz) {
switch (st) {
case normal:
if (*rp==esc) st=escaped;
else *wp++=*rp;
break;
case escaped:
if (*rp>=0x30 && *rp<=0x39) {d1 = *rp; st=digits;}
else {*wp++=esc;*wp++=*rp;st=normal;}
break;
case digits:
if (*rp>=0x30 && *rp<=0x39) {
cc = ((d1-0x30)*10)+(*rp-0x30);
if (lc != cc) {lc=cc;*wp++=esc;*wp++=d1;*wp++=*rp;}
} else {
cc = (d1-0x30);
if (lc != cc) {lc=cc;*wp++=esc;*wp++=d1;}
*wp++=*rp;
}
st=normal;
}
rp++;
}
*wp=0;
return s;
}
case digits:
if (*rp>=0x30 && *rp<=0x39) {
cc = ((d1-0x30)*10)+(*rp-0x30);
if (lc != cc) {lc=cc;*wp++=esc;*wp++=d1;*wp++=*rp;}
st=normal;
} else {
cc = (d1-0x30);
if (lc != cc) {lc=cc;*wp++=esc;*wp++=d1;}
if (*rp==esc) st=escaped;
else {*wp++=*rp; st=normal;}
}
Should be easy to go from the end of the string to the start and remove duplicated colors
something like that:
previouscolor = none
from end of string to beginning {
color = detect(color)
if (previsouscolor == color)
remove(previsoucolor)
if (isAdjacentColor) //cause having two colors in a rowmeans only the last one will be used
remove(color)
else
previouscolor = color
}
and thats it, algorthm should work fine, not easy to code as it imply to go back and forth in the string, but the logic of it is easier to read this way.
I could not make scandum snippet works and Tyche seems have problem as well.
I am not a fan of coding myself those things as I usually fuck up something (string replacement that can still be freed once done is nightmarish)
But at least I will be able to understand the code I did ;p