/*
	xterm 256 color code parser by Igor van den Hoven

	No restrictions on use. 02/11/2009
*/

/*
	Use <aaa> to <fff> for RGB foreground colors and for RGB background
	colors yse <AAA> to <FFF>.

	Use <g00> to <g23> for grayscale foreground colors and <G00> to <G23>
	for grayscale background colors.

	With xterm256 disabled ASCII colors are emulated.
*/

/*
	Syntax:  <xyz>  with x, y, z being parameters

	Parameter 'x': ASCII code

	0 - Reset all colors and codes to default
	1 - Bold
	2 - Dim
	4 - Underscore
	5 - Blink
	7 - Reverse
	8 - Skip (use previous code)

	Parameter 'y':  Foreground color
	Parameter 'z':  Background color

	0 - Black                5 - Magenta
	1 - Red                  6 - Cyan
	2 - Green                7 - White
	3 - Yellow               8 - Skip
	4 - Blue                 9 - Default
*/

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define BUFFER_SIZE 10000


void substitute_color(char *string, char *result, int xterm256)
{
	char buffer[BUFFER_SIZE], *pti, *pto;
	int cnt;

	pti = string;
	pto = string != result ? result : buffer;

	while (*pti)
	{
		switch (*pti)
		{
			case '<':
				if (isdigit(pti[1]) && isdigit(pti[2]) && isdigit(pti[3]) && pti[4] == '>')
				{
					if (pti[1] != '8' || pti[2] != '8' || pti[3] != '8')
					{
						*pto++ = '\033';
						*pto++ = '[';

						switch (pti[1])
						{
							case '2':
								*pto++ = '2';
								*pto++ = '2';
								*pto++ = ';';
								break;
							case '8':
								break;
							default:
								*pto++ = pti[1];
								*pto++ = ';';
						}
						switch (pti[2])
						{
							case '8':
								break;
							default:
								*pto++ = '3';
								*pto++ = pti[2];
								*pto++ = ';';
								break;
						}
						switch (pti[3])
						{
							case '8':
								break;
							default:
								*pto++ = '4';
								*pto++ = pti[3];
								*pto++ = ';';
								break;
						}
						pto--;
						*pto++ = 'm';
					}
					pti += 5;
				}
				else if (pti[1] >= 'a' && pti[1] <= 'f' && pti[2] >= 'a' && pti[2] <= 'f' && pti[3] >= 'a' && pti[3] <= 'f' && pti[4] == '>')
				{
					if (xterm256)
					{
						*pto++ = '\033';
						*pto++ = '[';
						*pto++ = '3';
						*pto++ = '8';
						*pto++ = ';';
						*pto++ = '5';
						*pto++ = ';';
						cnt = 16 + (pti[1] - 'a') * 36 + (pti[2] - 'a') * 6 + (pti[3] - 'a');
						*pto++ = '0' + cnt / 100;
						*pto++ = '0' + cnt % 100 / 10;
						*pto++ = '0' + cnt % 10;
						*pto++ = 'm';
					}
					else
					{
						*pto++ = '\033';
						*pto++ = '[';
						cnt = pti[1] - 'a' + pti[2] - 'a' + pti[3] - 'a';
						*pto++ = '0' + ((pti[1] > 'd' || pti[2] > 'd' || pti[3] > 'd'));
						*pto++ = ';';
						*pto++ = '3';
						*pto++ = '0' + (cnt && pti[1] >= pti[2] ? pti[1] >= pti[3] : 0) + (cnt && pti[2] >= pti[1] ? pti[2] >= pti[3] : 0) * 2 + (cnt && pti[3] >= pti[2] ? pti[3] >= pti[1] : 0) * 4;
						*pto++ = 'm';
					}
					pti += 5;
							
						
				}
				else if (pti[1] >= 'A' && pti[1] <= 'F' && pti[2] >= 'A' && pti[2] <= 'F' && pti[3] >= 'A' && pti[3] <= 'F' && pti[4] == '>')
				{
					if (xterm256)
					{
						*pto++ = '\033';
						*pto++ = '[';
						*pto++ = '4';
						*pto++ = '8';
						*pto++ = ';';
						*pto++ = '5';
						*pto++ = ';';
						cnt = 16 + (pti[1] - 'A') * 36 + (pti[2] - 'A') * 6 + (pti[3] - 'A');
						*pto++ = '0' + cnt / 100;
						*pto++ = '0' + cnt % 100 / 10;
						*pto++ = '0' + cnt % 10;
						*pto++ = 'm';
					}
					else
					{
						*pto++ = '\033';
						*pto++ = '[';
						cnt = pti[1] - 'A' + pti[2] - 'A' + pti[3] - 'A';
						if (pti[1] > 'D' || pti[2] > 'D' || pti[3] > 'D')
						{
							*pto++ = '1';
							*pto++ = '0';
						}
						else
						{
							*pto++ = '4';
						}
						*pto++ = '0' + (cnt && pti[1] >= pti[2] ? pti[1] >= pti[3] : 0) + (cnt && pti[2] >= pti[1] ? pti[2] >= pti[3] : 0) * 2 + (cnt && pti[3] >= pti[2] ? pti[3] >= pti[1] : 0) * 4;
						*pto++ = 'm';
					}
					pti += 5;
				}
				else if (pti[1] == 'g' && isdigit(pti[2]) && isdigit(pti[3]) && pti[4] == '>')
				{
					if (xterm256)
					{
						*pto++ = '\033';
						*pto++ = '[';
						*pto++ = '3';
						*pto++ = '8';
						*pto++ = ';';
						*pto++ = '5';
						*pto++ = ';';
						cnt = 232 + (pti[2] - '0') * 10 + (pti[3] - '0');
						*pto++ = '0' + cnt / 100;
						*pto++ = '0' + cnt % 100 / 10;
						*pto++ = '0' + cnt % 10;
						*pto++ = 'm';
					}
					else
					{
						*pto++ = '\033';
						*pto++ = '[';
						cnt = (pti[2] - '0') * 10 + (pti[3] - '0');
						*pto++ = '0' + (cnt / 6 != 2);
						*pto++ = ';';
						*pto++ = '3';
						*pto++ = '0' + (cnt / 12 ? 7 : 0);
						*pto++ = 'm';
					}
					pti += 5;
				}
				else if (pti[1] == 'G' && isdigit(pti[2]) && isdigit(pti[3]) && pti[4] == '>')
				{
					if (xterm256)
					{
						*pto++ = '\033';
						*pto++ = '[';
						*pto++ = '4';
						*pto++ = '8';
						*pto++ = ';';
						*pto++ = '5';
						*pto++ = ';';
						cnt = 232 + (pti[2] - '0') * 10 + (pti[3] - '0');
						*pto++ = '0' + cnt / 100;
						*pto++ = '0' + cnt % 100 / 10;
						*pto++ = '0' + cnt % 10;
						*pto++ = 'm';
					}
					else
					{
						*pto++ = '\033';
						*pto++ = '[';
						cnt = (pti[2] - '0') * 10 + (pti[3] - '0');
						if (cnt / 6 == 2)
						{
							*pto++ = '4';
						}
						else
						{
							*pto++ = '1';
							*pto++ = '0';
						}
						*pto++ = '0' + (cnt / 12 ? 7 : 0);
						*pto++ = 'm';
					}
					pti += 5;
				}
				else
				{
					*pto++ = *pti++;
				}
				break;

			default:
				*pto++ = *pti++;
				break;
		}
	}
	*pto = 0;

	if (string == result)
	{
		strcpy(result, buffer);
	}
	return;
}

/*
	Compile for an example display of xterm 256 colors
*/

int main(int argc, char **argv)
{
	char buf[BUFFER_SIZE], tmp[BUFFER_SIZE], out[BUFFER_SIZE];
	int x, y, z;

	/*
		Foreground
	*/

	buf[0] = 0;

	for (x = 'a' ; x <= 'f' ; x++)
	{
		for (y = 'a' ; y <= 'f' ; y++)
		{
			for (z = 'a' ; z <= 'f' ; z++)
			{
				sprintf(tmp, "<%c%c%c><<880>%c%c%c> ", x, y, z, x, y, z);
				strcat(buf, tmp);
			}
			strcat(buf, "\n");
		}
	}

	substitute_color(buf, out, 1);
	printf("%s\n", out);

	substitute_color(buf, out, 0);
	printf("%s\n", out);

	buf[0] = 0;

	for (x = 0 ; x < 24 ; x++)
	{
		sprintf(tmp, "<g%02d>%02d<088> ", x, x);
		strcat(buf, tmp);
	}

	substitute_color(buf, out, 1);
	printf("%s\n", out);

	substitute_color(buf, out, 0);
	printf("%s\n", out);

	/*
		Background
	*/

	buf[0] = 0;

	for (x = 'A' ; x <= 'F' ; x++)
	{
		for (y = 'A' ; y <= 'F' ; y++)
		{
			for (z = 'A' ; z <= 'F' ; z++)
			{
				sprintf(tmp, "<%c%c%c><<878>%c%c%c><880> ", x, y, z, x, y, z);
				strcat(buf, tmp);
			}
			strcat(buf, "\n");
		}
	}

	substitute_color(buf, out, 1);
	printf("%s\n", out);

	substitute_color(buf, out, 0);
	printf("%s\n", out);


	buf[0] = 0;

	for (x = 0 ; x < 24 ; x++)
	{
		sprintf(tmp, "<G%02d>%02d<088> ", x, x);
		strcat(buf, tmp);
	}

	substitute_color(buf, out, 1);
	printf("%s\n", out);

	substitute_color(buf, out, 0);
	printf("%s\n", out);

	return 0;
}
