From 11a49e35ce89943098835ba6d5b3f1252c2d6b8c Mon Sep 17 00:00:00 2001 From: Laurent Mazet Date: Fri, 24 Feb 2023 09:36:24 +0100 Subject: [PATCH] add color support for windows console --- calc.c | 2 +- color.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ color.h | 41 ++++++++++++++++++++++++ debug.h | 24 +++++---------- 4 files changed, 145 insertions(+), 18 deletions(-) create mode 100644 color.c create mode 100644 color.h diff --git a/calc.c b/calc.c index cd5defb..1432acc 100644 --- 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 #include diff --git a/color.c b/color.c new file mode 100644 index 0000000..2af7572 --- /dev/null +++ b/color.c @@ -0,0 +1,96 @@ +#ifdef _WIN32 +#include +#else +#include +#include +#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 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 01f4ea3..46442d4 100644 --- a/debug.h +++ b/debug.h @@ -1,6 +1,8 @@ #ifndef __DEBUG_H__ #define __DEBUG_H__ +#include "color.h" + /* constants */ #define DEBUG 3 @@ -8,29 +10,17 @@ #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 */ -- 2.30.2