365 lines
12 KiB
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: <ESC>[{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>
|
|
<ESC>[{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 <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);
|
|
}
|
|
</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 <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);
|
|
}
|
|
</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 © 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 ============================================================-->
|