old-www/LDP/LG/issue65/padala.html

365 lines
12 KiB
HTML

<!--startcut ==============================================-->
<!-- *** BEGIN HTML header *** -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML><HEAD>
<title>So You Like Color !!! (The mysterious ^[[ characters) LG #65</title>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
ALINK="#FF0000">
<!-- *** END HTML header *** -->
<CENTER>
<A HREF="http://www.linuxgazette.com/">
<H1><IMG ALT="LINUX GAZETTE" SRC="../gx/lglogo.png"
WIDTH="600" HEIGHT="124" border="0"></H1></A>
<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="okopnik.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue65/padala.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../faq/index.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="puryear.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
<P>
</CENTER>
<!--endcut ============================================================-->
<H4 ALIGN="center">
"Linux Gazette...<I>making Linux just a little more fun!</I>"
</H4>
<P> <HR> <P>
<!--===================================================================-->
<center>
<H1><font color="maroon">So You Like Color !!!<BR>
(The mysterious ^[[ characters)</font></H1>
<H4>By <a href="mailto:p_padala@yahoo.com">Pradeep Padala</a></H4>
</center>
<P> <HR> <P>
<!-- END header -->
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...
</P>
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.
</P>
<H3> Terminal Codes </H3>
<P>
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.
</P>
Type this on your console.
<PRE>
echo "^[[0;31;40mIn Color"
</PRE>
<P>
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
</P>
<PRE>
echo "^[[0;37;40m"
</PRE>
<P>
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..
</P>
<H3> The Color Code: &nbsp;&nbsp;&nbsp;&nbsp;&lt;ESC&gt;[{attr};{fg};{bg}m </H3>
<P>
I'll explain the escape sequence to produce colors. The sequence to be printed
or echoed to the terminal is
<PRE>
&lt;ESC&gt;[{attr};{fg};{bg}m
</PRE>
<P>
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.
</P>
<P>
{attr} is one of following
<PRE>
0 Reset All Attributes (return to normal mode)
1 Bright (Usually turns on BOLD)
2 Dim
3 Underline
5 Blink
7 Reverse
8 Hidden
</PRE>
{fg} is one of the following
<PRE>
30 Black
31 Red
32 Green
33 Yellow
34 Blue
35 Magenta
36 Cyan
37 White
</PRE>
{bg} is one of the following
<PRE>
40 Black
41 Red
42 Green
43 Yellow
44 Blue
45 Magenta
46 Cyan
47 White
</PRE>
<P>
So to get a blinking line with Blue foreground and Green background, the combination to be used should
be
<PRE>
echo "^[[5;34;42mIn color"
</PRE>
which actually is very ugly. :-) Revert back with
<PRE>
echo "^[0;37;40m"
</PRE>
<H3> With printf() </H3>
<P>
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 <CODE>textcolor()</CODE> which does this
automatically. You can use it in your programs along with the #define constants.
The text version of this program is <A HREF=misc/padala/color.c.txt> here </A>
</P>
<H3><CODE>textcolor()</CODE> </H3>
<TABLE BGCOLOR="#C5C5C5" WIDTH=450>
<TR> <TD>
<PRE>
#include &lt;stdio.h&gt;
#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);
}
</PRE>
</TD>
</TABLE>
<P>
The <CODE>textcolor()</CODE> is modeled against the Turbo C API function. You
call the function to set the color and then print with a <CODE>sprintf()</CODE>
(a function used in Turbo C to produce console output in color).
</P>
<H3> A Demo of colors</H3>
<TABLE BGCOLOR="#C5C5C5" WIDTH=450>
<TR> <TD>
<PRE>
#include &lt;stdio.h&gt;
#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 &lt; n_options; ++i)
printf("%d.%s\n", i, array[i]);
printf("%s", title);
scanf("%d", &amp;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);
}
</PRE>
</TD>
</TABLE>
<P> 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 <A HREF=misc/padala/demo.c.txt> here </A>.
</P>
<H3> The Catch </H3>
<P>
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.
</P>
<P>
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.
</P>
<H3> With tput </H3>
<P>
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.
</P>
<PRE>
tput setf 4 # tput setf {fg color number}
tput setb 2 # tput setb {bg color number}
</PRE>
<P>
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.
<P> These are the color numbers to be passed as arguments to "tput setf" and
"tput setb".
</P>
<PRE>
0 Black
1 Red
2 Green
3 Yellow
4 Blue
5 Magenta
6 Cyan
7 White
</PRE>
<P>
Have fun !!!
</P>
<H3> References </H3>
<UL>
<LI>The <A HREF=http://www.linuxdoc.org/HOWTO/Text-Terminal-HOWTO.html>
Text-Terminal-HOWTO </A> </LI>
<LI>Man pages for <A HREF=http://linux.ctyme.com/man/man2488.htm>tput</A>
and <A HREF=http://linux.ctyme.com/man/man2346.htm> terminfo<A>. </LI>
</UL>
<!-- *** BEGIN copyright *** -->
<P> <hr> <!-- P -->
<H5 ALIGN=center>
Copyright &copy; 2001, Pradeep Padala.<BR>
Copying license <A HREF="../copying.html">http://www.linuxgazette.com/copying.html</A><BR>
Published in Issue 65 of <i>Linux Gazette</i>, April 2001</H5>
<!-- *** END copyright *** -->
<!--startcut ==========================================================-->
<HR><P>
<CENTER>
<!-- *** BEGIN navbar *** -->
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="okopnik.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue65/padala.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../faq/index.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="puryear.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
<!-- *** END navbar *** -->
</CENTER>
</BODY></HTML>
<!--endcut ============================================================-->