watch: interpret ANSI color code sequences

A patch from Debian.

Bug-Debian: http://bugs.debian.org/129334
Backported-by: Sami Kerola <kerolasa@iki.fi>
This commit is contained in:
Craig Small 2010-03-01 06:17:11 +00:00 committed by Craig Small
parent db552d38bc
commit 39a2f5d717
2 changed files with 96 additions and 4 deletions

View File

@ -1,4 +1,4 @@
.TH WATCH 1 "2009 May 11" " " "Linux User's Manual" .TH WATCH 1 "2010 Mar 01" " " "Linux User's Manual"
.SH NAME .SH NAME
watch \- execute a program periodically, showing output fullscreen watch \- execute a program periodically, showing output fullscreen
.SH SYNOPSIS .SH SYNOPSIS
@ -8,6 +8,7 @@ watch \- execute a program periodically, showing output fullscreen
.RB [ \-n .RB [ \-n
.IR seconds ] .IR seconds ]
.RB [ \-\-beep ] .RB [ \-\-beep ]
.RB [ \-\-color ]
.RB [ \-\-differences[=\fIcumulative\fP]] .RB [ \-\-differences[=\fIcumulative\fP]]
.RB [ \-\-errexit ] .RB [ \-\-errexit ]
.RB [ \-\-exec ] .RB [ \-\-exec ]
@ -57,6 +58,10 @@ or
options, which will cause options, which will cause
.B watch .B watch
to exit if the return value from the program is non-zero. to exit if the return value from the program is non-zero.
.PP
By default \fBwatch\fR will normally not pass escape characters, however
if you use the \fI\-\-c\fR or \fI\-\-color\fR option, then
\fBwatch\fR will interpret ANSI color sequences for the foreground.
.SH NOTE .SH NOTE
Note that Note that

93
watch.c
View File

@ -32,6 +32,7 @@
#endif #endif
static struct option longopts[] = { static struct option longopts[] = {
{"color", no_argument, 0, 'c' },
{"differences", optional_argument, 0, 'd'}, {"differences", optional_argument, 0, 'd'},
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"interval", required_argument, 0, 'n'}, {"interval", required_argument, 0, 'n'},
@ -44,7 +45,7 @@ static struct option longopts[] = {
}; };
static char usage[] = static char usage[] =
"Usage: %s [-bdhntvx] [--beep] [--differences[=cumulative]] [--exec] [--help] [--interval=<n>] [--no-title] [--version] <command>\n"; "Usage: %s [-bdhntvx] [--beep] [--color] [--differences[=cumulative]] [--exec] [--help] [--interval=<n>] [--no-title] [--version] <command>\n";
static char *progname; static char *progname;
@ -55,6 +56,74 @@ static int first_screen = 1;
static int show_title = 2; // number of lines used, 2 or 0 static int show_title = 2; // number of lines used, 2 or 0
#define min(x,y) ((x) > (y) ? (y) : (x)) #define min(x,y) ((x) > (y) ? (y) : (x))
#define MAX_ANSIBUF 10
static void init_ansi_colors(void)
{
int i;
short ncurses_colors[] = {
COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE,
COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE };
for (i=0; i< 8; i++)
init_pair(i+1, ncurses_colors[i], -1);
}
static void set_ansi_attribute(const int attrib)
{
switch (attrib)
{
case -1:
return;
case 0:
standend();
return;
case 1:
attrset(A_BOLD);
return;
}
if (attrib >= 30 && attrib <= 37) {
color_set(attrib-29,NULL);
return;
}
}
static void process_ansi(FILE *fp)
{
int i,c, num1, num2;
char buf[MAX_ANSIBUF];
char *nextnum;
c= getc(fp);
if (c != '[') {
ungetc(c, fp);
return;
}
for(i=0; i<MAX_ANSIBUF; i++)
{
c = getc(fp);
if (c == 'm') //COLOUR SEQUENCE ENDS in 'm'
{
buf[i] = '\0';
break;
}
if (c < '0' && c > '9' && c != ';')
{
while(--i >= 0)
ungetc(buf[i],fp);
return;
}
buf[i] = (char)c;
}
num1 = strtol(buf, &nextnum, 10);
if (nextnum != buf && nextnum[0] != '\0')
num2 = strtol(nextnum+1, NULL, 10);
else
num2 = -1;
set_ansi_attribute(num1);
set_ansi_attribute(num2);
}
static void do_usage(void) NORETURN; static void do_usage(void) NORETURN;
static void do_usage(void) static void do_usage(void)
@ -145,6 +214,7 @@ main(int argc, char *argv[])
option_differences_cumulative = 0, option_differences_cumulative = 0,
option_exec = 0, option_exec = 0,
option_beep = 0, option_beep = 0,
option_color = 0,
option_errexit = 0, option_errexit = 0,
option_help = 0, option_version = 0; option_help = 0, option_version = 0;
double interval = 2; double interval = 2;
@ -158,12 +228,15 @@ main(int argc, char *argv[])
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
progname = argv[0]; progname = argv[0];
while ((optc = getopt_long(argc, argv, "+bed::hn:vtx", longopts, (int *) 0)) while ((optc = getopt_long(argc, argv, "+bced::hn:vtx", longopts, (int *) 0))
!= EOF) { != EOF) {
switch (optc) { switch (optc) {
case 'b': case 'b':
option_beep = 1; option_beep = 1;
break; break;
case 'c':
option_color = 1;
break;
case 'd': case 'd':
option_differences = 1; option_differences = 1;
if (optarg) if (optarg)
@ -251,6 +324,14 @@ main(int argc, char *argv[])
/* Set up tty for curses use. */ /* Set up tty for curses use. */
curses_started = 1; curses_started = 1;
initscr(); initscr();
if (option_color) {
if (has_colors()) {
start_color();
use_default_colors();
init_ansi_colors();
} else
option_color = 0;
}
nonl(); nonl();
noecho(); noecho();
cbreak(); cbreak();
@ -350,7 +431,13 @@ main(int argc, char *argv[])
c = getc(p); c = getc(p);
while (c != EOF && !isprint(c) while (c != EOF && !isprint(c)
&& c != '\n' && c != '\n'
&& c != '\t'); && c != '\t'
&& (c != L'\033' || option_color != 1));
if (c == L'\033' && option_color == 1) {
x--;
process_ansi(p);
continue;
}
if (c == '\n') if (c == '\n')
if (!oldeolseen && x == 0) { if (!oldeolseen && x == 0) {
x = -1; x = -1;