cmenu: better implementation of vga->ansi
authorPierre-Alexandre Meyer <pierre@mouraf.org>
Fri, 21 Aug 2009 06:00:25 +0000 (23:00 -0700)
committerPierre-Alexandre Meyer <pierre@mouraf.org>
Tue, 1 Sep 2009 18:43:37 +0000 (11:43 -0700)
hpa suggested a better implementation, that also fixes some color
issues and invalid ANSI codes. Thanks hpa!

Signed-off-by: Pierre-Alexandre Meyer <pierre@mouraf.org>
com32/cmenu/libmenu/com32io.c

index 8a44a77..330bcb9 100644 (file)
@@ -29,27 +29,46 @@ static unsigned int bit_reverse(unsigned int code, int len)
 
 void cprint_vga2ansi(char chr, char attr)
 {
-       /* The VGA attribute looks like: X B B B I F F F */
-       unsigned int ansi_attr;
-
-       /* Bit reverse Background/Foreground */
-       ansi_attr = bit_reverse(attr, 7);
-
-       /* Blinking attribute? */
-       if (! (ansi_attr & 0x80))
-               printf(CSI "%d;3%d;4%dm%c", ansi_attr & 0x8,
-                                           ansi_attr & 0x70,
-                                           ansi_attr & 0x7, chr);
-       else {
-               if (ansi_attr & 0x8)
-                       printf(CSI "%d;4;3%d;4%dm%c", ansi_attr & 0x8,
-                                                     ansi_attr & 0x70,
-                                                     ansi_attr & 0x7, chr);
-               else
-                       printf(CSI "%d;3%d;4%dm%c", ansi_attr & 0x8,
-                                                   ansi_attr & 0x70,
-                                                   ansi_attr & 0x7, chr);
+       static const char ansi_char[8] = "04261537";
+       static uint8_t last_attr = 0x07;
+       char buf[16], *p;
+
+       if (attr != last_attr) {
+               p = buf;
+               *p++ = '\033';
+               *p++ = '[';
+
+               if (last_attr & ~attr & 0x88) {
+                       *p++ = '0';
+                       *p++ = ';';
+               }
+               if (attr & 0x08) {
+                       *p++ = '1';
+                       *p++ = ';';
+               }
+               if (attr & 0x80) {
+                       *p++ = '4';
+                       *p++ = ';';
+               }
+               if ((attr ^ last_attr) & 0x07) {
+                       *p++ = '3';
+                       *p++ = ansi_char[attr & 7];
+                       *p++ = ';';
+               }
+               if ((attr ^ last_attr) & 0x70) {
+                       *p++ = '4';
+                       *p++ = ansi_char[(attr >> 4) & 7];
+                       *p++ = ';';
+               }
+               p[-1] = 'm';    /* We'll have generated at least one semicolon */
+               p[0] = '\0';
+
+               last_attr = attr;
+
+               fputs(buf, stdout);
        }
+
+       putchar(chr);
 }
 
 /* Print character and attribute at cursor */