ALINK="#FF0000">

LINUX GAZETTE

[ Prev ][ Table of Contents ][ Front Page ][ Talkback ][ FAQ ][ Next ]

"Linux Gazette...making Linux just a little more fun!"


So You Like Color !!!
(The mysterious ^[[ characters)

By Pradeep Padala


Have you ever redirected the output of a curses program with colors and wondered what those mysterious ^[[ are? Did you ever try to produce colors with a printf without using curses? If the answer to either of these questions is yes, read on...

This article attempts to explain those mysterious characters that one finds in the output of a curses program which produces colors. Later on, we extend the concept to produce colors with a mere printf.

Terminal Codes

In the olden days of teletype terminals, terminals were away from computers and were connected to them through serial cables. The terminals could be configured by sending a series of bytes to each of them. All the capabilities of terminals could be accessed through these series of bytes which are usually called escape sequences because they start with an escape(0x1B) character. Even today with vt100 emulation, we can send escape sequences to the emulator and it will have the same effect on the terminal window. Hence, in order to print color, we merely echo a control code.

Type this on your console.
	echo "^[[0;31;40mIn Color"

The first character is an escape character, which looks like two characters ^ and [. To be able to print that you have to press CTRL+V and then the ESC key. All the others are normal printable characters. You see the string "In Color" in red. It stays that way and to revert back type this

	echo "^[[0;37;40m"

As you can see it's pretty easy to set color and reset it back. There are a myriad of escape sequences with which you can do a lot of things like moving the cursor, resetting the terminal etc..

The Color Code:     <ESC>[{attr};{fg};{bg}m

I'll explain the escape sequence to produce colors. The sequence to be printed or echoed to the terminal is

	<ESC>[{attr};{fg};{bg}m

The first character is ESC which has to be printed by pressing CTRL+V and then ESC on the Linux console or in xterm, konsole, kvt, etc. ("CTRL+V ESC" is also the way to embed an escape character in a document in vim.) Then {attr}, {fg}, {bg} have to be replaced with the correct value to get the corresponding effect. attr is the attribute like blinking or underlined etc.. fg and bg are foreground and background colors respectively. You don't have to put braces around the number. Just writing the number will suffice.

{attr} is one of following

	0	Reset All Attributes (return to normal mode)
	1	Bright (Usually turns on BOLD)
	2 	Dim
	3	Underline
	5	Blink
	7 	Reverse
	8	Hidden
{fg} is one of the following
	30	Black
	31	Red
	32	Green
	33	Yellow
	34	Blue
	35	Magenta
	36	Cyan
	37	White
{bg} is one of the following
	40	Black
	41	Red
	42	Green
	43	Yellow
	44	Blue
	45	Magenta
	46	Cyan
	47	White

So to get a blinking line with Blue foreground and Green background, the combination to be used should be

	
echo "^[[5;34;42mIn color"
which actually is very ugly. :-) Revert back with
echo "^[0;37;40m"

With printf()

What if you want to use this functionality in a C program? Simple! Before you printf something print this escape sequence to produce it in the desired color. I have written a small routine textcolor() which does this automatically. You can use it in your programs along with the #define constants. The text version of this program is here

textcolor()

#include <stdio.h>

#define RESET		0
#define BRIGHT 		1
#define DIM		2
#define UNDERLINE 	3
#define BLINK		4
#define REVERSE		7
#define HIDDEN		8

#define BLACK 		0
#define RED		1
#define GREEN		2
#define YELLOW		3
#define BLUE		4
#define MAGENTA		5
#define CYAN		6
#define	WHITE		7

void textcolor(int attr, int fg, int bg);
int main()
{	textcolor(BRIGHT, RED, BLACK);	
	printf("In color\n");
	textcolor(RESET, WHITE, BLACK);	
	return 0;
}

void textcolor(int attr, int fg, int bg)
{	char command[13];

	/* Command is the control command to the terminal */
	sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40);
	printf("%s", command);
}

The textcolor() is modeled against the Turbo C API function. You call the function to set the color and then print with a sprintf() (a function used in Turbo C to produce console output in color).

A Demo of colors

#include <stdio.h>

#define RESET		0
#define BRIGHT 		1
#define DIM		2
#define UNDERLINE 	3
#define BLINK		4
#define REVERSE		7
#define HIDDEN		8

#define BLACK 		0
#define RED		1
#define GREEN		2
#define YELLOW		3
#define BLUE		4
#define MAGENTA		5
#define CYAN		6
#define	WHITE		7

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))

char *attrs[] = {"NORMAL", "BRIGHT", "DIM", "UNDERLINE", "BLINK",
		 "REVERSE", "HIDDEN", "EXIT"};
char *colors[] = {"BLACK", "RED", "GREEN", "YELLOW", "BLUE", "MAGENTA",
		 "CYAN", "WHITE", "EXIT"};
void textcolor(int attr, int fg, int bg);
int print_menu(char *array[], int n_options, char *title);
int main()
{	int attr, fg, bg;
	int attr_size, colors_size;
	
	attr_size = ARRAY_SIZE(attrs);
	colors_size = ARRAY_SIZE(colors);
	while(1)
	{	printf("\n");
		attr = print_menu(attrs, attr_size, "Choose the attr you want:");
		if(attr == attr_size - 1)
			break;
		fg = print_menu(colors, colors_size, "Choose the foreground you want:");
		if(attr == colors_size - 1)
			break;
		bg = print_menu(colors, colors_size, "Choose the background you want:");
		if(attr == colors_size - 1)
			break;
		printf("\n");
		textcolor(attr, fg, bg);	
		printf("This is what you get if you use the combination %s attribute %s foreground and %s
 background", attrs[attr], colors[fg], colors[bg]);
		textcolor(RESET, WHITE, BLACK);
		system("clear");
	}
	return 0;
}

int print_menu(char *array[], int n_options, char *title)
{	int choice, i;
	for(i = 0;i < n_options; ++i)
		printf("%d.%s\n", i, array[i]);
	printf("%s", title);
	scanf("%d", &choice);
	return choice;
}		
void textcolor(int attr, int fg, int bg)
{	char command[13];

	/* Command is the control command to the terminal */
	sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40);
	printf("%s", command);
}

This program asks the user to play with attributes and colors and shows a string in that color. I usually use it to find out the best combination of colors for my GUIs. Text version of above program is here .

The Catch

Then what's the catch? If producing color is so easy, why do people waste their time writing huge programs in curses, which in turn query terminfo in a complex way? As we know, there are many terminals with very few capabilities and terminals which don't recognize these escape codes or need different codes to achieve the same effect. So if you want a portable program which would run on any terminal with the same (or reduced) functionality, you should use curses. Curses uses terminfo to find the correct codes to accomplish the task in style. Terminfo is a big database which contains information about the various functionalities of different terminals.

But if you just want to write a simple program which produces color on a Linux console or xterm window, you can just use the escape sequences above to do it easily. The Linux console mostly emulates vt100, so it recognizes these escape sequences.

With tput

But there is a way to query the terminfo database and do the work. tput is the command which queries the database and executes the functionality you specify. The two capabilities setf and setb are useful to set foreground and background colors. Use this to set foreground color to red and background color to green.

	tput setf 4	# tput setf {fg color number}
	tput setb 2	# tput setb {bg color number}

This can be used in shell scripts where you want. See the tput manual page for additional capabilities of tput. The terminfo manpages contain a lot of information regarding terminal capabilities - how to get and set their values and more. There are two terminfo manpages. "man 5 terminfo" describes the terminfo database. "man 3ncurses terminfo" describes the C functions that use the database.

These are the color numbers to be passed as arguments to "tput setf" and "tput setb".

	0	Black
	1	Red
	2	Green
	3	Yellow
	4	Blue
	5	Magenta
	6	Cyan
	7	White

Have fun !!!

References


Copyright © 2001, Pradeep Padala.
Copying license
http://www.linuxgazette.net/copying.html
Published in Issue 65 of Linux Gazette, April 2001

[ Prev ][ Table of Contents ][ Front Page ][ Talkback ][ FAQ ][ Next ]