printf-hook-builtin: Support Windows console colors using TTY escape codes
authorMartin Willi <martin@revosec.ch>
Tue, 15 Oct 2013 13:45:11 +0000 (15:45 +0200)
committerMartin Willi <martin@revosec.ch>
Wed, 4 Jun 2014 13:52:57 +0000 (15:52 +0200)
src/libstrongswan/utils/printf_hook/printf_hook_builtin.c
src/libstrongswan/utils/utils.c

index c79d4b8..466c673 100644 (file)
@@ -1104,6 +1104,128 @@ int builtin_vprintf(const char *format, va_list ap)
        return builtin_vfprintf(stdout, format, ap);
 }
 
+#ifdef WIN32
+/**
+ * Set TTY color on Windows consoles
+ */
+static void set_console_color(HANDLE handle, int color)
+{
+       CONSOLE_SCREEN_BUFFER_INFO info;
+       struct {
+               /* escape code */
+               int color;
+               /* windows console color combination */
+               WORD attributes;
+       } maps[] = {
+               { 30,   0                                                                                                                       },
+               { 31,   FOREGROUND_RED                                                                                          },
+               { 32,   FOREGROUND_GREEN                                                                                        },
+               { 33,   FOREGROUND_GREEN | FOREGROUND_RED                                                       },
+               { 34,   FOREGROUND_BLUE | FOREGROUND_INTENSITY                                          },
+               { 35,   FOREGROUND_RED | FOREGROUND_BLUE                                                        },
+               { 36,   FOREGROUND_GREEN | FOREGROUND_BLUE                                                      },
+               { 37,   FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED                     },
+               { 39,   FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED                     },
+               { 40,   0                                                                                                                       },
+               { 41,   BACKGROUND_RED                                                                                          },
+               { 42,   BACKGROUND_GREEN                                                                                        },
+               { 43,   BACKGROUND_GREEN | BACKGROUND_RED                                                       },
+               { 44,   BACKGROUND_BLUE                                                                                         },
+               { 45,   BACKGROUND_RED | BACKGROUND_BLUE                                                        },
+               { 46,   BACKGROUND_GREEN | BACKGROUND_BLUE                                                      },
+               { 47,   BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED                     },
+               { 49,   0                                                                                                                       },
+       };
+       int i;
+
+       if (GetConsoleScreenBufferInfo(handle, &info))
+       {
+               if (color < 40)
+               {
+                       info.wAttributes &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN |
+                                                                 FOREGROUND_RED | FOREGROUND_INTENSITY);
+               }
+               else
+               {
+                       info.wAttributes &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN |
+                                                                 BACKGROUND_RED | BACKGROUND_INTENSITY);
+               }
+               for (i = 0; i < countof(maps); i++)
+               {
+                       if (maps[i].color == color)
+                       {
+                               info.wAttributes |= maps[i].attributes;
+                               SetConsoleTextAttribute(handle, info.wAttributes);
+                               break;
+                       }
+               }
+       }
+}
+
+int builtin_vfprintf(FILE *stream, const char *format, va_list ap)
+{
+       char buf[PRINTF_BUF_LEN], *pos, *stop;
+       HANDLE handle;
+       int len, total;
+       DWORD clen, mode;
+
+       total = len = builtin_vsnprintf(buf, sizeof(buf), format, ap);
+       switch (fileno(stream))
+       {
+               case 1:
+                       handle = GetStdHandle(STD_OUTPUT_HANDLE);
+                       break;
+               case 2:
+                       handle = GetStdHandle(STD_ERROR_HANDLE);
+                       break;
+               default:
+                       handle = INVALID_HANDLE_VALUE;
+                       break;
+       }
+       /* GetConsoleMode fails if output redirected */
+       if (handle == INVALID_HANDLE_VALUE || !GetConsoleMode(handle, &mode))
+       {
+               return fwrite(buf, 1, len, stream);
+       }
+       while (len)
+       {
+               pos = &buf[total - len];
+               if (len > 4)
+               {
+                       if (pos[0] == '\e' && pos[1] == '[' && pos[4] == 'm')
+                       {
+                               if (isdigit(pos[3]))
+                               {
+                                       if (pos[2] == '3' || pos[2] == '4')
+                                       {
+                                               set_console_color(handle,
+                                                                       (pos[2] - '0') * 10 + pos[3] - '0');
+                                               len -= 5;
+                                               continue;
+                                       }
+                               }
+                       }
+               }
+               stop = memchr(pos + 1, '\e', len);
+               if (stop)
+               {
+                       clen = stop - pos;
+               }
+               else
+               {
+                       clen = len;
+               }
+               if (clen && !WriteConsole(handle, pos, clen, &clen, NULL))
+               {
+                       break;
+               }
+               len -= clen;
+       }
+       return total - len;
+}
+
+#else /* !WIN32 */
+
 int builtin_vfprintf(FILE *stream, const char *format, va_list ap)
 {
        char buf[PRINTF_BUF_LEN];
@@ -1113,6 +1235,8 @@ int builtin_vfprintf(FILE *stream, const char *format, va_list ap)
        return fwrite(buf, 1, len, stream);
 }
 
+#endif /* !WIN32 */
+
 int builtin_vsprintf(char *str, const char *format, va_list ap)
 {
        return builtin_vsnprintf(str, ~(size_t)0, format, ap);
index 03c7b4f..7cca845 100644 (file)
@@ -363,6 +363,9 @@ char* tty_escape_get(int fd, tty_escape_t escape)
                case TTY_BOLD:
                case TTY_UNDERLINE:
                case TTY_BLINKING:
+#ifdef WIN32
+                       return "";
+#endif
                case TTY_FG_BLACK:
                case TTY_FG_RED:
                case TTY_FG_GREEN:
@@ -382,7 +385,7 @@ char* tty_escape_get(int fd, tty_escape_t escape)
                case TTY_BG_WHITE:
                case TTY_BG_DEF:
                        return enum_to_name(tty_color_names, escape);
-               /* warn if a excape code is missing */
+               /* warn if a escape code is missing */
        }
        return "";
 }