From a2c094cf1c564076ef17df28a695bec05d5ff162 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 22 May 2023 17:27:30 +0200 Subject: [PATCH 1/4] Make Console::SetWindowsConsoleColor() control flow more obvious and more like Console::PrintVT100ColorCode(). Doesn't change anything (ex. readability) as equality to Console_Normal (0) implies that all conditions now transferred into the else{} are false. --- lib/base/console.cpp | 113 ++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 56 deletions(-) diff --git a/lib/base/console.cpp b/lib/base/console.cpp index 99a5fad3d..034aa5730 100644 --- a/lib/base/console.cpp +++ b/lib/base/console.cpp @@ -138,66 +138,67 @@ void Console::SetWindowsConsoleColor(std::ostream& fp, int color) WORD attrs = 0; - if (color == Console_Normal) + if (color == Console_Normal) { attrs = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + } else { + switch (color & 0xff) { + case Console_ForegroundBlack: + attrs |= 0; + break; + case Console_ForegroundRed: + attrs |= FOREGROUND_RED; + break; + case Console_ForegroundGreen: + attrs |= FOREGROUND_GREEN; + break; + case Console_ForegroundYellow: + attrs |= FOREGROUND_RED | FOREGROUND_GREEN; + break; + case Console_ForegroundBlue: + attrs |= FOREGROUND_BLUE; + break; + case Console_ForegroundMagenta: + attrs |= FOREGROUND_RED | FOREGROUND_BLUE; + break; + case Console_ForegroundCyan: + attrs |= FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + case Console_ForegroundWhite: + attrs |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + } - switch (color & 0xff) { - case Console_ForegroundBlack: - attrs |= 0; - break; - case Console_ForegroundRed: - attrs |= FOREGROUND_RED; - break; - case Console_ForegroundGreen: - attrs |= FOREGROUND_GREEN; - break; - case Console_ForegroundYellow: - attrs |= FOREGROUND_RED | FOREGROUND_GREEN; - break; - case Console_ForegroundBlue: - attrs |= FOREGROUND_BLUE; - break; - case Console_ForegroundMagenta: - attrs |= FOREGROUND_RED | FOREGROUND_BLUE; - break; - case Console_ForegroundCyan: - attrs |= FOREGROUND_GREEN | FOREGROUND_BLUE; - break; - case Console_ForegroundWhite: - attrs |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; - break; + switch (color & 0xff00) { + case Console_BackgroundBlack: + attrs |= 0; + break; + case Console_BackgroundRed: + attrs |= BACKGROUND_RED; + break; + case Console_BackgroundGreen: + attrs |= BACKGROUND_GREEN; + break; + case Console_BackgroundYellow: + attrs |= BACKGROUND_RED | BACKGROUND_GREEN; + break; + case Console_BackgroundBlue: + attrs |= BACKGROUND_BLUE; + break; + case Console_BackgroundMagenta: + attrs |= BACKGROUND_RED | BACKGROUND_BLUE; + break; + case Console_BackgroundCyan: + attrs |= BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + case Console_BackgroundWhite: + attrs |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + } + + if (color & Console_Bold) + attrs |= FOREGROUND_INTENSITY; } - switch (color & 0xff00) { - case Console_BackgroundBlack: - attrs |= 0; - break; - case Console_BackgroundRed: - attrs |= BACKGROUND_RED; - break; - case Console_BackgroundGreen: - attrs |= BACKGROUND_GREEN; - break; - case Console_BackgroundYellow: - attrs |= BACKGROUND_RED | BACKGROUND_GREEN; - break; - case Console_BackgroundBlue: - attrs |= BACKGROUND_BLUE; - break; - case Console_BackgroundMagenta: - attrs |= BACKGROUND_RED | BACKGROUND_BLUE; - break; - case Console_BackgroundCyan: - attrs |= BACKGROUND_GREEN | BACKGROUND_BLUE; - break; - case Console_BackgroundWhite: - attrs |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; - break; - } - - if (color & Console_Bold) - attrs |= FOREGROUND_INTENSITY; - SetConsoleTextAttribute(hConsole, attrs); } #endif /* _WIN32 */ From 3687c94e6071c8624fa99f0ea8cfea52bded80bd Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 22 May 2023 18:00:05 +0200 Subject: [PATCH 2/4] Console::SetWindowsConsoleColor(): correct behavior on Console_Normal Capture initial character attributes, which don't have to be white text on black, and set them. They may be also e.g. black text on red. --- lib/base/console.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/base/console.cpp b/lib/base/console.cpp index 034aa5730..89687231d 100644 --- a/lib/base/console.cpp +++ b/lib/base/console.cpp @@ -1,5 +1,6 @@ /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ +#include "base/atomic.hpp" #include "base/console.hpp" #include "base/initialize.hpp" #include @@ -121,25 +122,36 @@ void Console::PrintVT100ColorCode(std::ostream& fp, int color) fp << "\33[1m"; } #else /* _WIN32 */ +static Atomic l_StdoutInitTextAttrs (-1), l_StderrInitTextAttrs (-1); + void Console::SetWindowsConsoleColor(std::ostream& fp, int color) { CONSOLE_SCREEN_BUFFER_INFO consoleInfo; HANDLE hConsole; + Atomic* initConsoleTextAttrs; - if (&fp == &std::cout) + if (&fp == &std::cout) { hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - else if (&fp == &std::cerr) + initConsoleTextAttrs = &l_StdoutInitTextAttrs; + } else if (&fp == &std::cerr) { hConsole = GetStdHandle(STD_ERROR_HANDLE); - else + initConsoleTextAttrs = &l_StderrInitTextAttrs; + } else { return; + } if (!GetConsoleScreenBufferInfo(hConsole, &consoleInfo)) return; + { + WORD uninitialised = -1; + (void)initConsoleTextAttrs->compare_exchange_strong(uninitialised, consoleInfo.wAttributes); + } + WORD attrs = 0; if (color == Console_Normal) { - attrs = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + attrs = initConsoleTextAttrs->load(); } else { switch (color & 0xff) { case Console_ForegroundBlack: From e007651a32e36763c4f84bd98d02a83ac97532b1 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 22 May 2023 18:30:17 +0200 Subject: [PATCH 3/4] Console::SetWindowsConsoleColor(): preserve all kinds of character attributes not explicitly set just like on *nix. Unlike the latter on Windows one can only override the whole bitmask at once. So we have to forward all non-overridden kinds of bits form current to desired state ourselves. --- lib/base/console.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/base/console.cpp b/lib/base/console.cpp index 89687231d..91caf55ad 100644 --- a/lib/base/console.cpp +++ b/lib/base/console.cpp @@ -178,6 +178,8 @@ void Console::SetWindowsConsoleColor(std::ostream& fp, int color) case Console_ForegroundWhite: attrs |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break; + default: + attrs |= consoleInfo.wAttributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); } switch (color & 0xff00) { @@ -205,10 +207,16 @@ void Console::SetWindowsConsoleColor(std::ostream& fp, int color) case Console_BackgroundWhite: attrs |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break; + default: + attrs |= consoleInfo.wAttributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE); } if (color & Console_Bold) attrs |= FOREGROUND_INTENSITY; + else + attrs |= consoleInfo.wAttributes & FOREGROUND_INTENSITY; + + attrs |= consoleInfo.wAttributes & BACKGROUND_INTENSITY; } SetConsoleTextAttribute(hConsole, attrs); From 7e534da55b5710f11c6be2815d9d96f3dbc57e8c Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 22 May 2023 18:36:28 +0200 Subject: [PATCH 4/4] Console::SetWindowsConsoleColor(): link to bitmask docs --- lib/base/console.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/base/console.cpp b/lib/base/console.cpp index 91caf55ad..7208019ae 100644 --- a/lib/base/console.cpp +++ b/lib/base/console.cpp @@ -143,6 +143,9 @@ void Console::SetWindowsConsoleColor(std::ostream& fp, int color) if (!GetConsoleScreenBufferInfo(hConsole, &consoleInfo)) return; + // On CONSOLE_SCREEN_BUFFER_INFO#wAttributes, FOREGROUND_* and BACKGROUND_* read + // https://learn.microsoft.com/en-us/windows/console/console-screen-buffers#character-attributes + { WORD uninitialised = -1; (void)initConsoleTextAttrs->compare_exchange_strong(uninitialised, consoleInfo.wAttributes);