]> granicus.if.org Git - procps-ng/commitdiff
watch: interpret ANSI color code sequences
authorCraig Small <csmall@debian.org>
Mon, 1 Mar 2010 06:17:11 +0000 (06:17 +0000)
committerCraig Small <csmall@enc.com.au>
Mon, 19 Dec 2011 10:56:02 +0000 (21:56 +1100)
A patch from Debian.

Bug-Debian: http://bugs.debian.org/129334
Backported-by: Sami Kerola <kerolasa@iki.fi>
watch.1
watch.c

diff --git a/watch.1 b/watch.1
index 802ab8412dd9baaa0ca6436b547ede52b7f4c9d2..cbfa3b328b59014a35f93debb972df7826ff4a40 100644 (file)
--- a/watch.1
+++ b/watch.1
@@ -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
 watch \- execute a program periodically, showing output fullscreen
 .SH SYNOPSIS
@@ -8,6 +8,7 @@ watch \- execute a program periodically, showing output fullscreen
 .RB [ \-n
 .IR seconds ]
 .RB [ \-\-beep ]
+.RB [ \-\-color ]
 .RB [ \-\-differences[=\fIcumulative\fP]]
 .RB [ \-\-errexit ]
 .RB [ \-\-exec ]
@@ -57,6 +58,10 @@ or
 options, which will cause
 .B watch
 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
 Note that
diff --git a/watch.c b/watch.c
index 25f8964f225d80485162cce525c397c339bbc9d6..bfd15e68a986f6bfb5ffcc20cc223326aae583e2 100644 (file)
--- a/watch.c
+++ b/watch.c
@@ -32,6 +32,7 @@
 #endif
 
 static struct option longopts[] = {
+  {"color", no_argument, 0, 'c' },
        {"differences", optional_argument, 0, 'd'},
        {"help", no_argument, 0, 'h'},
        {"interval", required_argument, 0, 'n'},
@@ -44,7 +45,7 @@ static struct option longopts[] = {
 };
 
 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;
 
@@ -55,6 +56,74 @@ static int first_screen = 1;
 static int show_title = 2;  // number of lines used, 2 or 0
 
 #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)
@@ -145,6 +214,7 @@ main(int argc, char *argv[])
            option_differences_cumulative = 0,
                        option_exec = 0,
                        option_beep = 0,
+      option_color = 0,
         option_errexit = 0,
            option_help = 0, option_version = 0;
        double interval = 2;
@@ -158,12 +228,15 @@ main(int argc, char *argv[])
        setlocale(LC_ALL, "");
        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) {
                switch (optc) {
                case 'b':
                        option_beep = 1;
                        break;
+    case 'c':
+      option_color = 1;
+      break;
                case 'd':
                        option_differences = 1;
                        if (optarg)
@@ -251,6 +324,14 @@ main(int argc, char *argv[])
        /* Set up tty for curses use.  */
        curses_started = 1;
        initscr();
+  if (option_color) {
+    if (has_colors()) {
+      start_color();
+      use_default_colors();
+      init_ansi_colors();
+    } else
+      option_color = 0;
+  }
        nonl();
        noecho();
        cbreak();
@@ -350,7 +431,13 @@ main(int argc, char *argv[])
                                                        c = getc(p);
                                                while (c != EOF && !isprint(c)
                                                       && 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 (!oldeolseen && x == 0) {
                                                        x = -1;