diff -au xrootconsole-0.6.orig/main.c xrootconsole-0.6/main.c
--- xrootconsole-0.6.orig/main.c	2004-02-20 23:31:53.000000000 +0100
+++ xrootconsole-0.6/main.c	2009-04-02 23:11:01.000000000 +0200
@@ -67,6 +67,7 @@
 "  -c COLUMNS       split window into number of text columns (default 1)\n" \
 "  --solid          make background a solid color, not shaded-transparent\n" \
 "  --topdown        insert lines at the top and scroll the rest down\n" \
+"  --bottomup       start inserting lines at the bottom\n" \
 "  --wrap           wrap long lines, instead of cutting them off\n" \
 "  -h or --help     a familiar-looking help screen\n" \
 "  -v or --version  displays the version number\n" \
@@ -89,6 +90,62 @@
 #define DEFAULT_TOPDOWN  False
 #define DEFAULT_SOLID    False
 
+// implementing ANSI colors
+// ref: http://en.wikipedia.org/wiki/ANSI_escape_code
+//
+// todo: allow customizing color table from cmd line ?
+// todo: background alpha instead of AND 
+//   ... complex need several cases dep on BPP
+// todo: background update when image changes
+//   ... need to poll on background, heavy process ?
+//
+// usage tail -f /var/log/messages | ccze -A | xrootconsole
+
+#define ESC_SEQ_START       0x10000
+#define ESC_SEQ_CONT        0x20000
+#define ESC_SEQ_DATA_MASK   0xFFFF
+
+
+#define REND_DEFAULT        0
+#define REND_FG_COLOR_MASK  0x0007
+#define REND_FG_SET_COLOR   0x0008
+#define REND_FG_FULLCOLOR_MASK  (REND_FG_COLOR_MASK | REND_FG_SET_COLOR)
+#define REND_FG_COLOR(c)    (REND_FG_SET_COLOR + ((c) & REND_FG_COLOR_MASK))
+#define REND_FG_COLOR_GET(r) (r & REND_FG_COLOR_MASK)
+#define REND_BG_COLOR_MASK  0x0070
+#define REND_BG_SET_COLOR   0x0080
+#define REND_BG_FULLCOLOR_MASK  (REND_BG_COLOR_MASK | REND_BG_SET_COLOR)
+#define REND_BG_COLOR(c)    (REND_BG_SET_COLOR + (((c)<<4) & REND_BG_COLOR_MASK))
+#define REND_BG_COLOR_GET(r) ((r & REND_BG_COLOR_MASK)>>4)
+
+#define REND_BOLD           0x0100  // used as fg high intensity
+#define REND_BLINK          0x0200  // used as bg high intensity
+#define REND_ULINE          0x0400
+#define REND_RVIDEO         0x0800
+
+static const char *def_colorName[] =
+{
+/* low-intensity colors */
+    "Black",            /* 0: black             (#000000) */
+    "Red3",             /* 1: red               (#CD0000) */
+    "Green3",           /* 2: green             (#00CD00) */
+//  "Yellow3",          /* 3: yellow            (#CDCD00) */
+    "#AB5700",          /* 3: brown actually (EGA/DOS ANSY.SYS compatible) */
+    "Blue3",            /* 4: blue              (#0000CD) */
+    "Magenta3",         /* 5: magenta           (#CD00CD) */
+    "Cyan3",            /* 6: cyan              (#00CDCD) */
+    "AntiqueWhite",     /* 7: white             (#FAEBD7) */
+/* high-intensity colors */
+    "Grey25",           /* 8: bright black      (#404040) */
+    "Red",              /* 9: bright red        (#FF0000) */
+    "Green",            /* 10: bright green     (#00FF00) */
+    "Yellow",           /* 11: bright yellow    (#FFFF00) */
+    "Blue",             /* 12: bright blue      (#0000FF) */
+    "Magenta",          /* 13: bright magenta   (#FF00FF) */
+    "Cyan",             /* 14: bright cyan      (#00FFFF) */
+    "White",            /* 15: bright white     (#FFFFFF) */
+};
+
 
 typedef struct {
     const char* fg;
@@ -123,16 +180,23 @@
     int nlines;           /* number of lines to keep in memory */
     int intercolgap;      /* width between two columns */
     XSetWindowAttributes swa;
+    unsigned long colortable[16];
+    unsigned long fgcolor;
+    unsigned long bgcolor;
 } WindowSettings;
 
 typedef struct {
     const char* console;   /* name of the console file */
     int fd;                /* file descriptor of the console file */
     char* text;            /* circular buffer to store the characters */
+    short* rend;           /* circular buffer to store the rendition options */
     int pos;               /* where the actual first line in text is */
+    int escapeseq;         /* we are in an escape sequence */
+    short currend;         /* current renditions options */
 } ConsoleSettings;
 
 
+
 /*
  * put
  */
@@ -142,37 +206,221 @@
     static int x = 0, y = 0;
   
     while (*s != '\0') {
-        switch (*s) {
-        case '\n':
-            x = 0;
-            if (io->topdown) {
-                cs->pos = (cs->pos + ws->nlines - 1) % ws->nlines;
-                memset(cs->text + cs->pos * ws->colwidth, ' ', ws->colwidth);
-            } 
-            else if (y == ws->nlines - 1) {
-                memset(cs->text + cs->pos * ws->colwidth, ' ', ws->colwidth);
-                cs->pos = (cs->pos + 1) % ws->nlines;
+        // For escape sequence we assume we got only supported commands
+        // ie COLOR only
+        // really entering : ESC[ ?
+        if (ESC_SEQ_START==cs->escapeseq) {
+            if (*s == '[') {
+                // yes, continue with escape seq
+                cs->escapeseq = ESC_SEQ_CONT;
+            }
+            else {
+                // no fall back to normal string processing
+                cs->escapeseq = False;
             }
-            else y++;
-            break;
-      
-        case '\t':
-            x = (x / 8 + 1) * 8;
-            if (x >= ws->cols && io->wrap) put("\n",io,ws,cs);
-            break;
-      
-        default:
-            if (*s >= ' ' && x < ws->colwidth) {
-                cs->text[x + ((y + cs->pos) % ws->nlines) * ws->colwidth] = *s;
-                if (++x == ws->colwidth && io->wrap) put("\n",io,ws,cs);
+        }
+
+        // inside an escape sequence ?
+        if (cs->escapeseq) {
+            switch (*s) {
+                case '[':
+                    break; // already treated
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                    cs->escapeseq = ESC_SEQ_CONT | ((cs->escapeseq & ESC_SEQ_DATA_MASK) * 10 + *s - '0');
+                    break;
+                case 'm':
+                    switch(cs->escapeseq & ESC_SEQ_DATA_MASK) {
+                        case 0:
+                            cs->currend = REND_DEFAULT;
+                            break;
+                        case 1:
+                            cs->currend |= REND_BOLD;
+                            break;
+                        case 4:
+                            cs->currend |= REND_ULINE;
+                            break;
+                        case 5:
+                            cs->currend |= REND_BLINK;
+                            break;
+                        case 7:
+                            cs->currend |= REND_RVIDEO;
+                            break;
+                        case 22:
+                            cs->currend &= ~REND_BOLD;
+                            break;
+                        case 24:
+                            cs->currend &= ~REND_ULINE;
+                            break;
+                        case 25:
+                            cs->currend &= ~REND_BLINK;
+                            break;
+                        case 27:
+                            cs->currend &= ~REND_RVIDEO;
+                            break;
+
+                        case 30:
+                        case 31:        /* set fg color */
+                        case 32:
+                        case 33:
+                        case 34:
+                        case 35:
+                        case 36:
+                        case 37:
+                            cs->currend = (cs->currend & ~REND_FG_FULLCOLOR_MASK)
+                                | REND_FG_COLOR((cs->escapeseq & ESC_SEQ_DATA_MASK)-30);
+                            break;
+                        case 39:        /* default fg */
+                            cs->currend = cs->currend & ~REND_FG_FULLCOLOR_MASK;
+                            break;
+
+                        case 40:
+                        case 41:        /* set bg color */
+                        case 42:
+                        case 43:
+                        case 44:
+                        case 45:
+                        case 46:
+                        case 47:
+                            cs->currend = (cs->currend & ~REND_BG_FULLCOLOR_MASK)
+                                | REND_BG_COLOR((cs->escapeseq & ESC_SEQ_DATA_MASK)-40);
+                            break;
+                        case 49:        /* default bg */
+                            cs->currend = cs->currend & ~REND_BG_FULLCOLOR_MASK;
+                            break;
+                    }
+                default:
+                   cs->escapeseq = False;
+            }
+        }
+        else {
+            switch (*s) {
+            case '\n':
+                if (io->topdown) {
+                    cs->pos = (cs->pos + ws->nlines - 1) % ws->nlines;
+                    memset(cs->text + cs->pos * ws->colwidth, ' ', ws->colwidth);
+                    for(x = 0; x < ws->colwidth; x++) {
+                        cs->rend[cs->pos * ws->colwidth + x] = cs->currend;
+                    }
+                } 
+                else if (y == ws->nlines - 1) {
+                    memset(cs->text + cs->pos * ws->colwidth, ' ', ws->colwidth);
+                    for(x = 0; x < ws->colwidth; x++) {
+                        cs->rend[cs->pos * ws->colwidth + x] = cs->currend;
+                    }
+                    cs->pos = (cs->pos + 1) % ws->nlines;
+                }
+                else y++;
+                x = 0;
+                break;
+          
+            case '\t':
+                x = (x / 8 + 1) * 8;
+                if (x >= ws->cols && io->wrap && *(s+1)!='\n') put("\n",io,ws,cs);
+                break;
+
+            case '\033': // esc
+                // enter escape sequence start mode
+                cs->escapeseq = ESC_SEQ_START;
+                break;
+          
+            default:
+                if (*s >= ' ' && x < ws->colwidth) {
+                    cs->text[x + ((y + cs->pos) % ws->nlines) * ws->colwidth] = *s;
+                    cs->rend[x + ((y + cs->pos) % ws->nlines) * ws->colwidth] = cs->currend;
+                    if (++x == ws->colwidth && io->wrap && *(s+1)!='\n') put("\n",io,ws,cs);
+                }
+                break;
             }
-            break;
         }
     
         s++;
     }
 }
 
+void draw_textline(InitOptions *io, WindowSettings *ws, ConsoleSettings *cs, int x, int y, int offset, int length)
+{
+    XGCValues values;
+    int len;
+    short rend = REND_DEFAULT;
+
+    while (length > 0) {
+        rend = cs->rend[offset];
+        len = 1;
+        // search longer segment with same color;
+        while ((cs->rend[offset+len] == rend) && (len < length)) len ++;
+
+        if (rend & REND_FG_SET_COLOR) {
+            values.foreground = ws->colortable[REND_FG_COLOR_GET(rend) + ((rend & REND_BOLD)?8:0) ];
+        }
+        else {
+            values.foreground = ws->fgcolor;
+        }
+
+        //printf("len:%3d rend: %04x\n",len, rend);
+
+        if (rend & (REND_BG_SET_COLOR | REND_RVIDEO) ) {
+            if (rend & REND_RVIDEO) {
+                values.background = values.foreground;
+                if (rend & REND_BG_SET_COLOR) {
+                    values.foreground = ws->colortable[REND_BG_COLOR_GET(rend) + ((rend & REND_BLINK)?8:0) ];
+                }
+                else {
+                    if (io->solid == True) {
+                        values.foreground = ws->bgcolor;
+                    }
+                    else {
+                        // transparent mode use AND so it make bg darker
+                        // just make the letters black, could be too dark,
+                        // but probably more readable
+                        values.foreground = ws->colortable[0];
+                    }
+                }
+            }
+            else {
+                values.background = ws->colortable[REND_BG_COLOR_GET(rend) + ((rend & REND_BLINK)?8:0) ];
+            }
+            XChangeGC(ws->dpy, ws->foregc, GCForeground | GCBackground, &values);
+            XDrawImageString(ws->dpy, ws->buf, ws->foregc, 
+                    x,
+                    y, 
+                    cs->text + offset, 
+                    len);
+        }
+        else {
+            XChangeGC(ws->dpy, ws->foregc, GCForeground, &values);
+            XDrawString(ws->dpy, ws->buf, ws->foregc, 
+                    x,
+                    y, 
+                    cs->text + offset, 
+                    len);
+        }
+        if (rend & REND_BOLD) {
+            XDrawString(ws->dpy, ws->buf, ws->foregc, 
+                    x+1,
+                    y, 
+                    cs->text + offset, 
+                    len);
+        }
+        length -= len;
+        offset += len;
+        x += len * ws->fn->min_bounds.width; /* can be error !!!! */
+    }
+
+    // restore rendering options
+    if(rend != REND_DEFAULT) {
+        values.foreground = ws->fgcolor;
+        XChangeGC(ws->dpy, ws->foregc, GCForeground, &values);
+    }
+}
 
 /*
  * write the text in the pixmap
@@ -189,10 +437,10 @@
     /* write the string */
     for (i = ws->rows; i>0; --i) {
         for (j = 0; j < io->tc; ++j) {
-            XDrawString(ws->dpy, ws->buf, ws->foregc, 
+            draw_textline(io, ws, cs, 
                 j * (ws->colwidth * ws->fn->max_bounds.width + ws->intercolgap),
                 rowp, 
-                cs->text + ((rowc + j*(ws->rows)) % ws->nlines)*(ws->colwidth), 
+                ((rowc + j*(ws->rows)) % ws->nlines)*(ws->colwidth), 
                 ws->colwidth);   
         }
         rowp += ws->fn->ascent + ws->fn->descent;
@@ -242,6 +490,8 @@
             io->wrap = True;
         else if (!strcmp(*argv, "--topdown"))
             io->topdown = True;
+        else if (!strcmp(*argv, "--bottomup"))
+            io->topdown = -1234;
         else if (!strcmp(*argv, "--version") || !strcmp(*argv, "-v")) {
             fprintf(stderr, "xrootconsole %s\n", XROOTCONSOLE_VERSION);
             exit(EXIT_SUCCESS);
@@ -276,6 +526,8 @@
     if (cs->console == NULL) exit(EXIT_SUCCESS);
     close(cs->fd);
     cs->fd = -1;
+    cs->escapeseq = False;
+    cs->currend = REND_DEFAULT;
 }
 
 void init_console(const char *console, 
@@ -290,9 +542,14 @@
        extra one is for the line being read. */
     cs->text = (char*)malloc(colwidth * nlines);
     memset(cs->text, ' ', colwidth * nlines);
+    /* Create rendering info array */
+    cs->rend = (short*)malloc(colwidth * nlines * sizeof(short));
+    memset(cs->rend, 0, colwidth * nlines * sizeof(short));
     cs->pos = 0;
     if (cs->console == NULL) cs->fd = 0;      /* STDIN special case, */
     else cs->fd = open_console(cs->console);  /* or open normal file */
+    cs->escapeseq = False;
+    cs->currend = REND_DEFAULT;
 }
   
 
@@ -305,7 +562,7 @@
         unsigned int count;
 
         if (XQueryTree(display, DefaultRootWindow (display), &unused, &unused,
-		      &windows, &count)) {
+              &windows, &count)) {
             int i;
 
             for (i=0; i<count; i++) {
@@ -416,9 +673,20 @@
     ws->buf = XCreatePixmap(ws->dpy, ws->win, ws->width, ws->height,
             DefaultDepth(ws->dpy, DefaultScreen(ws->dpy)));
 
+    /* build colortable */
+    ws->fgcolor = load_color(io->fg, ws->dpy);
+    ws->bgcolor = load_color(io->bg, ws->dpy);
+    {
+        int i;
+        for(i = 0; i < 16; i ++)
+        {
+            ws->colortable[i] = load_color(def_colorName[i], ws->dpy);
+            
+        }
+    }
     /* Create the foreground GC */
     values.font = ws->fn->fid;
-    values.foreground = load_color(io->fg, ws->dpy);
+    values.foreground = ws->fgcolor;
     values.graphics_exposures = 0;
     ws->foregc = XCreateGC(ws->dpy, ws->win, 
            GCFont | GCForeground | GCGraphicsExposures, 
@@ -426,7 +694,7 @@
      
     /* initialize the background pixmap */
     values.background = values.foreground;
-    values.foreground = load_color(io->bg, ws->dpy);
+    values.foreground = ws->bgcolor;
     if (io->solid == True) {
 
         XLowerWindow(ws->dpy, ws->win);
@@ -492,6 +760,13 @@
   
     maxfd = (cs->fd > Xfd ? cs->fd : Xfd) + 1;
 
+    if (io->topdown == -1234) {
+        int i;
+        io->topdown = False;
+        for (i=0; i < ws->nlines; i++)
+            put("\n", io, ws, cs);
+    }
+
     while (1) {
 
         while ((XPending(ws->dpy) > 0) && 
