add color support for windows console
authorLaurent Mazet <mazet@softndesign.org>
Fri, 24 Feb 2023 08:36:24 +0000 (09:36 +0100)
committerLaurent Mazet <mazet@softndesign.org>
Fri, 24 Feb 2023 08:36:24 +0000 (09:36 +0100)
calc.c
color.c [new file with mode: 0644]
color.h [new file with mode: 0644]
debug.h

diff --git a/calc.c b/calc.c
index cd5defb646aaf2c99ff7ff6fc323857219d03612..1432acc275fb7c496e29b3b024da4db6783364df 100644 (file)
--- a/calc.c
+++ b/calc.c
@@ -1,6 +1,6 @@
 /* depend: */
 /* cflags: */
-/* linker: alloc.o argument.o debug.o element.o format.o parser.o program.o stack.o storage.o tabular.o workspace.o -lm -lreadline */
+/* linker: alloc.o argument.o color.o debug.o element.o format.o parser.o program.o stack.o storage.o tabular.o workspace.o -lm -lreadline */
 
 #include <malloc.h>
 #include <stddef.h>
diff --git a/color.c b/color.c
new file mode 100644 (file)
index 0000000..2af7572
--- /dev/null
+++ b/color.c
@@ -0,0 +1,96 @@
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#include <stdio.h>
+#endif
+
+#include "color.h"
+
+#ifdef _WIN32 /* Windows */
+
+void color_set (FILE *fid, color_e color)
+{
+    /* save default configuration */
+    static WORD init = 0;
+    if (init == 0) {
+        CONSOLE_SCREEN_BUFFER_INFO info;
+        GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
+        init = info.attr;
+    }
+
+    /* default attribute */
+    WORD attr = 0;
+
+    /* define foreground color */
+    if (FG_DEFAULT == (color & FG_MASK)) {
+        attr |= init & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
+    } else {
+        attr |= (color & FG_BRIGHT) ? FOREGROUND_INTENSITY : 0;
+        switch (color & FG_MASK) {
+            case FG_RED:     attr |= FOREGROUND_RED; break;
+            case FG_GREEN:   attr |= FOREGROUND_GREEN; break;
+            case FG_BLUE:    attr |= FOREGROUND_BLUE; break;
+            case FG_YELLOW:  attr |= FOREGROUND_RED | FOREGROUND_GREEN; break;
+            case FG_MAGENTA: attr |= FOREGROUND_RED | FOREGROUND_BLUE; break;
+            case FG_CYAN:    attr |= FOREGROUND_GREEN | FOREGROUND_BLUE; break;
+            case FG_WHITE:   attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
+        }
+    }
+
+    /* define background color */
+    if (BG_DEFAULT == (color & BG_MASK)) {
+        attr |= init & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
+    } else {
+        attr |= (color & BG_BRIGHT) ? BACKGROUND_INTENSITY : 0;
+        switch (color&BG_MASK) {
+            case BG_RED:     attr |= BACKGROUND_RED; break;
+            case BG_GREEN:   attr |= BACKGROUND_GREEN; break;
+            case BG_BLUE:    attr |= BACKGROUND_BLUE; break;
+            case BG_YELLOW:  attr |= BACKGROUND_RED | BACKGROUND_GREEN; break;
+            case BG_MAGENTA: attr |= BACKGROUND_RED | BACKGROUND_BLUE; break;
+            case BG_CYAN:    attr |= BACKGROUND_GREEN | BACKGROUND_BLUE; break;
+            case BG_WHITE:   attr |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
+        }
+    }
+
+    /* define underline state */
+    if (color & UNDERLINE) {
+        attr |= COMMON_LVB_UNDERSCORE;
+    }
+
+    /* set text attribute */
+    SetConsoleTextAttribute (GetStdHandle ((fid == stdout) ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE), attr);
+}
+
+#else /* Linux */
+
+void color_set (FILE *fid, color_e color)
+{
+    /* check if it's a terminal */
+    if (!isatty (fileno (fid))) {
+        return;
+    }
+
+    /* default color */
+    fprintf (fid, "\033[m");
+
+    /* set foreground color */
+    if (FG_DEFAULT != (color & FG_MASK)) {
+        fprintf (fid, "\033[%dm", 29 + (color & FG_MASK) + ((color & FG_BRIGHT) ? 60 : 0));
+    }
+
+    /* set background color */
+    if (BG_DEFAULT != (color & BG_MASK)) {
+        fprintf (fid, "\033[%dm", 39 + ((color & BG_MASK ) >> 8) + ((color & BG_BRIGHT) ? 60 : 0));
+    }
+
+    /* set underline state */
+    if (color & UNDERLINE) {
+        fprintf (fid, "\033[4m");
+    }
+}
+
+#endif /* _WIN32 */
+
+/* vim: set ts=4 sw=4 et: */
diff --git a/color.h b/color.h
new file mode 100644 (file)
index 0000000..6a2e8dc
--- /dev/null
+++ b/color.h
@@ -0,0 +1,41 @@
+#ifndef __COLOR_H__
+#define __COLOR_H__
+
+#include "stdio.h"
+
+typedef enum {
+    FG_DEFAULT    = 0x00,
+    FG_BLACK      = 0x01,
+    FG_RED        = 0x02,
+    FG_GREEN      = 0x03,
+    FG_YELLOW     = 0x04,
+    FG_BLUE       = 0x05,
+    FG_MAGENTA    = 0x06,
+    FG_CYAN       = 0x07,
+    FG_WHITE      = 0x08,
+    FG_BRIGHT     = 0x80,
+    FG_MASK       = 0x7F,
+
+    BG_DEFAULT    = 0x0000,
+    BG_BLACK      = 0x0100,
+    BG_RED        = 0x0200,
+    BG_GREEN      = 0x0300,
+    BG_YELLOW     = 0x0400,
+    BG_BLUE       = 0x0500,
+    BG_MAGENTA    = 0x0600,
+    BG_CYAN       = 0x0700,
+    BG_WHITE      = 0x0800,
+    BG_BRIGHT     = 0x8000,
+    BG_MASK       = 0x7F00,
+
+    UNDERLINE     = 0x10000,
+
+    COLOR_DEFAULT = FG_DEFAULT | BG_DEFAULT
+} color_e;
+
+/* Set text color, COLOR_DEFAULT will revert to default setting */
+void color_set (FILE *fid, color_e color);
+
+#endif /* __COLOR_H__ */
+
+/* vim: set ts=4 sw=4 et: */
diff --git a/debug.h b/debug.h
index 01f4ea3dc1adc1c7fb703b91ea98dc5ba202aab9..46442d4bb6ac9b8132acd3a088b6314960069f5a 100644 (file)
--- a/debug.h
+++ b/debug.h
@@ -1,6 +1,8 @@
 #ifndef __DEBUG_H__
 #define __DEBUG_H__
 
+#include "color.h"
+
 /* constants */
 
 #define DEBUG   3
 #define WARNING 1
 #define ERROR   0
 
-/* colors */
-
-#define COLOR_BLACK   30
-#define COLOR_RED     31
-#define COLOR_GREEN   32
-#define COLOR_YELLOW  33
-#define COLOR_BLUE    34
-#define COLOR_MAGENTA 35
-#define COLOR_CYAN    36
-#define COLOR_WHITE   37
-#define COLOR_DEFAULT 39
-
 /* macros */
 
 #define VERBOSE(level, statement...) \
     do { if (level <= verbose) { CHANGE_COLOR(level); statement; CHANGE_COLOR(-1); } } while(0)
 
 #define CHANGE_COLOR(level) \
-    fprintf ((level == ERROR) ? stderr : stdout, \
-             "\1\033[%dm\1", (level == ERROR) ? COLOR_RED : \
-                             (level == WARNING) ? COLOR_YELLOW : \
-                             (level == INFO) ? COLOR_BLUE : \
-                             (level == DEBUG) ? COLOR_GREEN : COLOR_DEFAULT)
+    color_set ((level == ERROR) ? stderr : stdout, \
+               (level == ERROR) ? FG_RED : \
+               (level == WARNING) ? FG_YELLOW : \
+               (level == INFO) ? FG_BLUE : \
+               (level == DEBUG) ? FG_GREEN : COLOR_DEFAULT)
 
 /* vim: set ts=4 sw=4 et: */
 /* gobal variables */