From f0d817cf39987e7b7548863c86beac29440ab7c6 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Wed, 12 Jul 2023 02:04:57 +0100 Subject: [PATCH] Remove rang and use fmtlib for printing coloured messages. This supports more platforms (e.g. Haiku) and is actually still maintained unlike the former. All of this code should really be cleaned up for release (maybe by adding something like Anope's LOG_CONSOLE) but for now I've just replaced it with the fmtlib equivalent. --- src/configreader.cpp | 5 +- src/coremods/core_dns.cpp | 1 - src/inspircd.cpp | 75 +++--- src/modulemanager.cpp | 17 +- src/modules.cpp | 18 +- src/socketengine.cpp | 9 +- vendor/README.md | 10 - vendor/rang/LICENSE | 24 -- vendor/rang/rang.hpp | 502 -------------------------------------- vendor/update.toml | 7 - 10 files changed, 68 insertions(+), 600 deletions(-) delete mode 100644 vendor/rang/LICENSE delete mode 100644 vendor/rang/rang.hpp diff --git a/src/configreader.cpp b/src/configreader.cpp index 1c418eae7..e71c22f59 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -31,7 +31,6 @@ #include -#include #ifndef _WIN32 # include #endif @@ -507,9 +506,11 @@ void ServerConfig::Apply(ServerConfig* old, const std::string& useruid) getline(errstr, line, '\n'); if (line.empty()) continue; + // On startup, print out to console (still attached at this point) if (!old) - std::cout << line << std::endl; + fmt::println(line); + // If a user is rehashing, tell them directly if (user) user->WriteRemoteNotice(INSP_FORMAT("*** {}", line)); diff --git a/src/coremods/core_dns.cpp b/src/coremods/core_dns.cpp index 3ad672676..6eba7573d 100644 --- a/src/coremods/core_dns.cpp +++ b/src/coremods/core_dns.cpp @@ -24,7 +24,6 @@ #include "modules/dns.h" #include "modules/stats.h" -#include #include #ifdef _WIN32 diff --git a/src/inspircd.cpp b/src/inspircd.cpp index f6fdcaabf..6d0ed4163 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -36,8 +36,8 @@ #include #include +#include #include -#include #include "inspircd.h" #include "exitcodes.h" @@ -48,6 +48,7 @@ # include # include # include +# include #else # define STDIN_FILENO 0 # define STDOUT_FILENO 1 @@ -77,21 +78,21 @@ namespace if (getegid() != 0 && geteuid() != 0) return; - std::cout << rang::style::bold << rang::fg::red << "Warning!" << rang::style::reset << " You have started as root. Running as root is generally not required" << std::endl - << "and may allow an attacker to gain access to your system if they find a way to" << std::endl - << "exploit your IRC server." << std::endl - << std::endl; + fmt::println("{} You have started as root. Running as root is generally not required", fmt::styled("Warning!", fmt::emphasis::bold | fmt::fg(fmt::terminal_color::red))); + fmt::println("and may allow an attacker to gain access to your system if they find a way to"); + fmt::println("exploit your IRC server."); + fmt::println(""); if (isatty(fileno(stdout))) { - std::cout << "InspIRCd will start in 30 seconds. If you are sure that you need to run as root" << std::endl - << "then you can pass the " << rang::style::bold << "--runasroot" << rang::style::reset << " option to disable this wait." << std::endl; + fmt::println("InspIRCd will start in 30 seconds. If you are sure that you need to run as root"); + fmt::println("then you can pass the {} option to disable this wait.", fmt::styled("--runasroot", fmt::emphasis::bold)); sleep(30); } else { - std::cout << "If you are sure that you need to run as root then you can pass the " << rang::style::bold << "--runasroot" << rang::style::reset << std::endl - << "option to disable this error." << std::endl; - ServerInstance->Exit(EXIT_STATUS_ROOT); + fmt::println("If you are sure that you need to run as root then you can pass the {}", fmt::styled("--runasroot", fmt::emphasis::bold)); + fmt::println("option to disable this error."); + ServerInstance->Exit(EXIT_STATUS_ROOT); } #endif } @@ -235,7 +236,7 @@ namespace if (childpid < 0) { ServerInstance->Logs.Error("STARTUP", "fork() failed: {}", strerror(errno)); - std::cout << rang::style::bold << rang::fg::red << "Error:" << rang::style::reset << " unable to fork into background: " << strerror(errno); + fmt::println("{} unable to fork into background: {}", fmt::styled("Error:", fmt::emphasis::bold | fmt::fg(fmt::terminal_color::red)), strerror(errno)); ServerInstance->Exit(EXIT_STATUS_FORK); } else if (childpid > 0) @@ -316,7 +317,7 @@ namespace auto result = cli.parse({ServerInstance->Config->CommandLine.argc, ServerInstance->Config->CommandLine.argv}); if (!result) { - std::cerr << rang::style::bold << rang::fg::red << "Error: " << rang::style::reset << result.message() << '.' << std::endl; + fmt::println(stderr, "{} {}", fmt::styled("Error:", fmt::emphasis::bold | fmt::fg(fmt::terminal_color::red)), result.message()); ServerInstance->Exit(EXIT_STATUS_ARGV); } @@ -328,7 +329,7 @@ namespace if (do_version) { - std::cout << INSPIRCD_VERSION << std::endl; + fmt::println(INSPIRCD_VERSION); ServerInstance->Exit(EXIT_STATUS_NOERROR); } @@ -373,24 +374,24 @@ namespace if (!pl.empty()) { - std::cout << rang::style::bold << rang::fg::red << "Warning!" << rang::style::reset << " Some of your listener" << (pl.size() == 1 ? "s" : "") << " failed to bind:" << std::endl - << std::endl; + fmt::println("{} Some of your listeners failed to bind:", fmt::styled("Warning!", fmt::emphasis::bold | fmt::fg(fmt::terminal_color::red))); + fmt::println(""); for (const auto& fp : pl) { - std::cout << " "; + fmt::print(" "); if (fp.sa.family() != AF_UNSPEC) - std::cout << rang::style::bold << fp.sa.str() << rang::style::reset << ": "; + fmt::print("{}: ", fmt::styled(fp.sa.str(), fmt::emphasis::bold)); - std::cout << fp.error << '.' << std::endl - << " " << "Created from tag at " << fp.tag->source.str() << std::endl - << std::endl; + fmt::println("{}.", fp.error); + fmt::println("Created from tag at {}", fp.tag->source.str()); + fmt::println(""); } - std::cout << rang::style::bold << "Hints:" << rang::style::reset << std::endl - << "- For TCP/IP listeners try using a public IP address in instead" << std::endl - << " of * or leaving it blank." << std::endl - << "- For UNIX socket listeners try enabling to replace old sockets." << std::endl; + fmt::print(fmt::text_style(fmt::emphasis::bold), "Hints:"); + fmt::println("- For TCP/IP listeners try using a public IP address in instead"); + fmt::println(" of * or leaving it blank."); + fmt::println("- For UNIX socket listeners try enabling to replace old sockets."); } } @@ -454,7 +455,7 @@ void InspIRCd::WritePID() } else { - std::cout << "Failed to write PID-file '" << pidfile << "', exiting." << std::endl; + fmt::println("Failed to write PID-file '{}', exiting.", pidfile); this->Logs.Error("STARTUP", "Failed to write PID-file '{}', exiting.", pidfile); Exit(EXIT_STATUS_PID); } @@ -489,9 +490,9 @@ InspIRCd::InspIRCd(int argc, char** argv) Modules.AddServices(provs, sizeof(provs)/sizeof(provs[0])); } - std::cout << rang::style::bold << rang::fg::green << "InspIRCd - Internet Relay Chat Daemon" << rang::style::reset << std::endl - << "See " << rang::style::bold << rang::fg::green << "/INFO" << rang::style::reset << " for contributors & authors" << std::endl - << std::endl; + fmt::println("{}", fmt::styled("InspIRCd - Internet Relay Chat Daemon", fmt::emphasis::bold | fmt::fg(fmt::terminal_color::green))); + fmt::println("See {} for contributors & authors", fmt::styled("/INFO", fmt::emphasis::bold | fmt::fg(fmt::terminal_color::green))); + fmt::println(""); Logs.RegisterServices(); if (Config->CommandLine.forcedebug) @@ -500,7 +501,8 @@ InspIRCd::InspIRCd(int argc, char** argv) if (!FindConfigFile(ConfigFileName)) { this->Logs.Error("STARTUP", "Unable to open config file {}", ConfigFileName); - std::cout << "ERROR: Cannot open config file: " << ConfigFileName << std::endl << "Exiting..." << std::endl; + fmt::println("ERROR: Cannot open config file: {}", ConfigFileName); + fmt::println("Exiting..."); Exit(EXIT_STATUS_CONFIG); } @@ -510,7 +512,7 @@ InspIRCd::InspIRCd(int argc, char** argv) if (!Config->CommandLine.nofork) ForkIntoBackground(); - std::cout << "InspIRCd Process ID: " << rang::style::bold << rang::fg::green << getpid() << rang::style::reset << std::endl; + fmt::println("InspIRCd Process ID: {}", fmt::styled(getpid(), fmt::emphasis::bold | fmt::fg(fmt::terminal_color::green))); /* During startup we read the configuration now, not in * a separate thread @@ -525,7 +527,8 @@ InspIRCd::InspIRCd(int argc, char** argv) } catch (const CoreException& ex) { - std::cout << "ERROR: Cannot open log files: " << ex.GetReason() << std::endl << "Exiting..." << std::endl; + fmt::println("ERROR: Cannot open log files: {}", ex.GetReason()); + fmt::println("Exiting..."); Exit(EXIT_STATUS_LOG); } @@ -542,7 +545,7 @@ InspIRCd::InspIRCd(int argc, char** argv) // This is needed as all new XLines are marked pending until ApplyLines() is called this->XLines->ApplyLines(); - std::cout << std::endl; + fmt::println(""); TryBindPorts(); @@ -555,18 +558,20 @@ InspIRCd::InspIRCd(int argc, char** argv) } catch (const CoreException& ex) { - std::cout << "ERROR: Cannot open log files: " << ex.GetReason() << std::endl << "Exiting..." << std::endl; + fmt::println("ERROR: Cannot open log files: {}", ex.GetReason()); + fmt::println("Exiting..."); Exit(EXIT_STATUS_LOG); } - std::cout << "InspIRCd is now running as '" << Config->ServerName << "'[" << Config->ServerId << "] with " << SocketEngine::GetMaxFds() << " max open sockets" << std::endl; + fmt::println("InspIRCd is now running as '{}'[{}] with {} max open sockets", + Config->ServerName, Config->ServerId, SocketEngine::GetMaxFds()); #ifndef _WIN32 if (!Config->CommandLine.nofork) { if (kill(getppid(), SIGTERM) == -1) { - std::cout << "Error killing parent process: " << strerror(errno) << std::endl; + fmt::println("Error killing parent process: {}", strerror(errno)); Logs.Warning("STARTUP", "Error killing parent process: {}", strerror(errno)); } } diff --git a/src/modulemanager.cpp b/src/modulemanager.cpp index 2c0b27527..b0ac5f711 100644 --- a/src/modulemanager.cpp +++ b/src/modulemanager.cpp @@ -23,9 +23,8 @@ #include -#include -#include +#include #include "inspircd.h" #include "dynamic.h" @@ -128,7 +127,8 @@ bool ModuleManager::Load(const std::string& modname, bool defer) /* We must load the modules AFTER initializing the socket engine, now */ void ModuleManager::LoadCoreModules(std::map& servicemap) { - std::cout << "Loading core modules " << std::flush; + fmt::print("Loading core modules "); + fflush(stdout); try { @@ -141,21 +141,24 @@ void ModuleManager::LoadCoreModules(std::map& servicem if (!InspIRCd::Match(name, "core_*" DLL_EXTENSION)) continue; - std::cout << "." << std::flush; + fmt::print("."); + fflush(stdout); this->NewServices = &servicemap[name]; if (!Load(name, true)) { - std::cout << std::endl << "[" << rang::style::bold << rang::fg::red << "*" << rang::style::reset << "] " << this->LastError() << std::endl << std::endl; + fmt::println(""); + fmt::println("[{}] {}", fmt::styled("*", fmt::emphasis::bold | fmt::fg(fmt::terminal_color::red)), LastError()); + fmt::println(""); ServerInstance->Exit(EXIT_STATUS_MODULE); } } } catch (const std::filesystem::filesystem_error& err) { - std::cout << "failed: " << err.what() << std::endl; + fmt::println("failed: {}", err.what()); ServerInstance->Exit(EXIT_STATUS_MODULE); } - std::cout << std::endl; + fmt::println(""); } diff --git a/src/modules.cpp b/src/modules.cpp index 74d8acf08..13c73cb28 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -30,9 +30,7 @@ */ -#include - -#include +#include #include "inspircd.h" #include "exitcodes.h" @@ -536,10 +534,12 @@ void ModuleManager::LoadAll() continue; this->NewServices = &servicemap[name]; - std::cout << "[" << rang::style::bold << rang::fg::green << "*" << rang::style::reset << "] Loading module:\t" << rang::style::bold << rang::fg::green << name << rang::style::reset << std::endl; + fmt::println("[{}] Loading module:\t{}", fmt::styled("*", fmt::emphasis::bold | fmt::fg(fmt::terminal_color::green)), name); if (!this->Load(name, true)) { - std::cout << std::endl << "[" << rang::style::bold << rang::fg::red << "*" << rang::style::reset << "] " << this->LastError() << std::endl << std::endl; + fmt::println(""); + fmt::println("[{}] {}", fmt::styled("*", fmt::emphasis::bold | fmt::fg(fmt::terminal_color::red)), LastError()); + fmt::println(""); ServerInstance->Exit(EXIT_STATUS_MODULE); } } @@ -558,7 +558,9 @@ void ModuleManager::LoadAll() { LastModuleError = "Unable to initialize " + modname + ": " + modexcept.GetReason(); ServerInstance->Logs.Error("MODULE", LastModuleError); - std::cout << std::endl << "[" << rang::style::bold << rang::fg::red << "*" << rang::style::reset << "] " << LastModuleError << std::endl << std::endl; + fmt::println(""); + fmt::println("[{}] {}", fmt::styled("*", fmt::emphasis::bold | fmt::fg(fmt::terminal_color::red)), LastModuleError); + fmt::println(""); ServerInstance->Exit(EXIT_STATUS_MODULE); } } @@ -580,7 +582,9 @@ void ModuleManager::LoadAll() { LastModuleError = "Unable to read the configuration for " + modname + ": " + modexcept.GetReason(); ServerInstance->Logs.Error("MODULE", LastModuleError); - std::cout << std::endl << "[" << rang::style::bold << rang::fg::red << "*" << rang::style::reset << "] " << LastModuleError << std::endl << std::endl; + fmt::println(""); + fmt::println("[{}] {}", fmt::styled("*", fmt::emphasis::bold | fmt::fg(fmt::terminal_color::red)), LastModuleError); + fmt::println(""); ServerInstance->Exit(EXIT_STATUS_CONFIG); } } diff --git a/src/socketengine.cpp b/src/socketengine.cpp index 9a42e856d..c760b1a12 100644 --- a/src/socketengine.cpp +++ b/src/socketengine.cpp @@ -26,15 +26,14 @@ */ -#include - -#include - #ifndef _WIN32 # include # include +# include #endif +#include + #include "inspircd.h" #include "exitcodes.h" @@ -71,7 +70,7 @@ void EventHandler::OnEventHandlerError(int errornum) void SocketEngine::InitError() { - std::cerr << rang::style::bold << rang::fg::red << "FATAL ERROR!" << rang::style::reset << " Socket engine initialization failed. " << strerror(errno) << '.' << std::endl; + fmt::println(stderr, "{} Socket engine initialization failed. {}.", fmt::styled("FATAL ERROR!", fmt::emphasis::bold | fmt::fg(fmt::terminal_color::red)), strerror(errno)); InspIRCd::QuickExit(EXIT_STATUS_SOCKETENGINE); } diff --git a/vendor/README.md b/vendor/README.md index e2a2a2118..b8b3c7876 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -52,16 +52,6 @@ This directory contains vendored dependencies that are shipped with InspIRCd to **Website** — [https://openwall.info/wiki/people/solar/software/public-domain-source-code/md5](https://openwall.info/wiki/people/solar/software/public-domain-source-code/md5) -## rang - -**Author** — Abhinav Gauniyal - -**License** — Unlicense - -**Version** — v3.2 - -**Website** — [https://github.com/agauniyal/rang/](https://github.com/agauniyal/rang/) - ## sha2 **Author** — [Olivier Gay](mailto:olivier.gay@a3.epfl.ch) diff --git a/vendor/rang/LICENSE b/vendor/rang/LICENSE deleted file mode 100644 index cf1ab25da..000000000 --- a/vendor/rang/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/vendor/rang/rang.hpp b/vendor/rang/rang.hpp deleted file mode 100644 index 831eda4c5..000000000 --- a/vendor/rang/rang.hpp +++ /dev/null @@ -1,502 +0,0 @@ -#ifndef RANG_DOT_HPP -#define RANG_DOT_HPP - -#if defined(__unix__) || defined(__unix) || defined(__linux__) -#define OS_LINUX -#elif defined(WIN32) || defined(_WIN32) || defined(_WIN64) -#define OS_WIN -#elif defined(__APPLE__) || defined(__MACH__) -#define OS_MAC -#else -#error Unknown Platform -#endif - -#if defined(OS_LINUX) || defined(OS_MAC) -#include - -#elif defined(OS_WIN) - -#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600) -#error \ - "Please include rang.hpp before any windows system headers or set _WIN32_WINNT at least to _WIN32_WINNT_VISTA" -#elif !defined(_WIN32_WINNT) -#define _WIN32_WINNT _WIN32_WINNT_VISTA -#endif - -#include -#include -#include - -// Only defined in windows 10 onwards, redefining in lower windows since it -// doesn't gets used in lower versions -// https://docs.microsoft.com/en-us/windows/console/getconsolemode -#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING -#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 -#endif - -#endif - -#include -#include -#include -#include -#include - -namespace rang { - -/* For better compability with most of terminals do not use any style settings - * except of reset, bold and reversed. - * Note that on Windows terminals bold style is same as fgB color. - */ -enum class style { - reset = 0, - bold = 1, - dim = 2, - italic = 3, - underline = 4, - blink = 5, - rblink = 6, - reversed = 7, - conceal = 8, - crossed = 9 -}; - -enum class fg { - black = 30, - red = 31, - green = 32, - yellow = 33, - blue = 34, - magenta = 35, - cyan = 36, - gray = 37, - reset = 39 -}; - -enum class bg { - black = 40, - red = 41, - green = 42, - yellow = 43, - blue = 44, - magenta = 45, - cyan = 46, - gray = 47, - reset = 49 -}; - -enum class fgB { - black = 90, - red = 91, - green = 92, - yellow = 93, - blue = 94, - magenta = 95, - cyan = 96, - gray = 97 -}; - -enum class bgB { - black = 100, - red = 101, - green = 102, - yellow = 103, - blue = 104, - magenta = 105, - cyan = 106, - gray = 107 -}; - -enum class control { // Behaviour of rang function calls - Off = 0, // toggle off rang style/color calls - Auto = 1, // (Default) autodect terminal and colorize if needed - Force = 2 // force ansi color output to non terminal streams -}; -// Use rang::setControlMode to set rang control mode - -enum class winTerm { // Windows Terminal Mode - Auto = 0, // (Default) automatically detects wheter Ansi or Native API - Ansi = 1, // Force use Ansi API - Native = 2 // Force use Native API -}; -// Use rang::setWinTermMode to explicitly set terminal API for Windows -// Calling rang::setWinTermMode have no effect on other OS - -namespace rang_implementation { - - inline std::atomic &controlMode() noexcept - { - static std::atomic value(control::Auto); - return value; - } - - inline std::atomic &winTermMode() noexcept - { - static std::atomic termMode(winTerm::Auto); - return termMode; - } - - inline bool supportsColor() noexcept - { -#if defined(OS_LINUX) || defined(OS_MAC) - - static const bool result = [] { - const char *Terms[] - = { "ansi", "color", "console", "cygwin", "gnome", - "konsole", "kterm", "linux", "msys", "putty", - "rxvt", "screen", "vt100", "xterm" }; - - const char *env_p = std::getenv("TERM"); - if (env_p == nullptr) { - return false; - } - return std::any_of(std::begin(Terms), std::end(Terms), - [&](const char *term) { - return std::strstr(env_p, term) != nullptr; - }); - }(); - -#elif defined(OS_WIN) - // All windows versions support colors through native console methods - static constexpr bool result = true; -#endif - return result; - } - -#ifdef OS_WIN - - - inline bool isMsysPty(int fd) noexcept - { - // Dynamic load for binary compability with old Windows - const auto ptrGetFileInformationByHandleEx - = reinterpret_cast( - GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), - "GetFileInformationByHandleEx")); - if (!ptrGetFileInformationByHandleEx) { - return false; - } - - HANDLE h = reinterpret_cast(_get_osfhandle(fd)); - if (h == INVALID_HANDLE_VALUE) { - return false; - } - - // Check that it's a pipe: - if (GetFileType(h) != FILE_TYPE_PIPE) { - return false; - } - - // POD type is binary compatible with FILE_NAME_INFO from WinBase.h - // It have the same alignment and used to avoid UB in caller code - struct MY_FILE_NAME_INFO { - DWORD FileNameLength; - WCHAR FileName[MAX_PATH]; - }; - - auto pNameInfo = std::unique_ptr( - new (std::nothrow) MY_FILE_NAME_INFO()); - if (!pNameInfo) { - return false; - } - - // Check pipe name is template of - // {"cygwin-","msys-"}XXXXXXXXXXXXXXX-ptyX-XX - if (!ptrGetFileInformationByHandleEx(h, FileNameInfo, pNameInfo.get(), - sizeof(MY_FILE_NAME_INFO))) { - return false; - } - std::wstring name(pNameInfo->FileName, pNameInfo->FileNameLength / sizeof(WCHAR)); - if ((name.find(L"msys-") == std::wstring::npos - && name.find(L"cygwin-") == std::wstring::npos) - || name.find(L"-pty") == std::wstring::npos) { - return false; - } - - return true; - } - -#endif - - inline bool isTerminal(const std::streambuf *osbuf) noexcept - { - using std::cerr; - using std::clog; - using std::cout; -#if defined(OS_LINUX) || defined(OS_MAC) - if (osbuf == cout.rdbuf()) { - static const bool cout_term = isatty(fileno(stdout)) != 0; - return cout_term; - } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { - static const bool cerr_term = isatty(fileno(stderr)) != 0; - return cerr_term; - } -#elif defined(OS_WIN) - if (osbuf == cout.rdbuf()) { - static const bool cout_term - = (_isatty(_fileno(stdout)) || isMsysPty(_fileno(stdout))); - return cout_term; - } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { - static const bool cerr_term - = (_isatty(_fileno(stderr)) || isMsysPty(_fileno(stderr))); - return cerr_term; - } -#endif - return false; - } - - template - using enableStd = typename std::enable_if< - std::is_same::value || std::is_same::value - || std::is_same::value || std::is_same::value - || std::is_same::value, - std::ostream &>::type; - - -#ifdef OS_WIN - - struct SGR { // Select Graphic Rendition parameters for Windows console - BYTE fgColor; // foreground color (0-15) lower 3 rgb bits + intense bit - BYTE bgColor; // background color (0-15) lower 3 rgb bits + intense bit - BYTE bold; // emulated as FOREGROUND_INTENSITY bit - BYTE underline; // emulated as BACKGROUND_INTENSITY bit - BOOLEAN inverse; // swap foreground/bold & background/underline - BOOLEAN conceal; // set foreground/bold to background/underline - }; - - enum class AttrColor : BYTE { // Color attributes for console screen buffer - black = 0, - red = 4, - green = 2, - yellow = 6, - blue = 1, - magenta = 5, - cyan = 3, - gray = 7 - }; - - inline HANDLE getConsoleHandle(const std::streambuf *osbuf) noexcept - { - if (osbuf == std::cout.rdbuf()) { - static const HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); - return hStdout; - } else if (osbuf == std::cerr.rdbuf() || osbuf == std::clog.rdbuf()) { - static const HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE); - return hStderr; - } - return INVALID_HANDLE_VALUE; - } - - inline bool setWinTermAnsiColors(const std::streambuf *osbuf) noexcept - { - HANDLE h = getConsoleHandle(osbuf); - if (h == INVALID_HANDLE_VALUE) { - return false; - } - DWORD dwMode = 0; - if (!GetConsoleMode(h, &dwMode)) { - return false; - } - dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - if (!SetConsoleMode(h, dwMode)) { - return false; - } - return true; - } - - inline bool supportsAnsi(const std::streambuf *osbuf) noexcept - { - using std::cerr; - using std::clog; - using std::cout; - if (osbuf == cout.rdbuf()) { - static const bool cout_ansi - = (isMsysPty(_fileno(stdout)) || setWinTermAnsiColors(osbuf)); - return cout_ansi; - } else if (osbuf == cerr.rdbuf() || osbuf == clog.rdbuf()) { - static const bool cerr_ansi - = (isMsysPty(_fileno(stderr)) || setWinTermAnsiColors(osbuf)); - return cerr_ansi; - } - return false; - } - - inline const SGR &defaultState() noexcept - { - static const SGR defaultSgr = []() -> SGR { - CONSOLE_SCREEN_BUFFER_INFO info; - WORD attrib = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), - &info) - || GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), - &info)) { - attrib = info.wAttributes; - } - SGR sgr = { 0, 0, 0, 0, FALSE, FALSE }; - sgr.fgColor = attrib & 0x0F; - sgr.bgColor = (attrib & 0xF0) >> 4; - return sgr; - }(); - return defaultSgr; - } - - inline BYTE ansi2attr(BYTE rgb) noexcept - { - static const AttrColor rev[8] - = { AttrColor::black, AttrColor::red, AttrColor::green, - AttrColor::yellow, AttrColor::blue, AttrColor::magenta, - AttrColor::cyan, AttrColor::gray }; - return static_cast(rev[rgb]); - } - - inline void setWinSGR(rang::bg col, SGR &state) noexcept - { - if (col != rang::bg::reset) { - state.bgColor = ansi2attr(static_cast(col) - 40); - } else { - state.bgColor = defaultState().bgColor; - } - } - - inline void setWinSGR(rang::fg col, SGR &state) noexcept - { - if (col != rang::fg::reset) { - state.fgColor = ansi2attr(static_cast(col) - 30); - } else { - state.fgColor = defaultState().fgColor; - } - } - - inline void setWinSGR(rang::bgB col, SGR &state) noexcept - { - state.bgColor = (BACKGROUND_INTENSITY >> 4) - | ansi2attr(static_cast(col) - 100); - } - - inline void setWinSGR(rang::fgB col, SGR &state) noexcept - { - state.fgColor - = FOREGROUND_INTENSITY | ansi2attr(static_cast(col) - 90); - } - - inline void setWinSGR(rang::style style, SGR &state) noexcept - { - switch (style) { - case rang::style::reset: state = defaultState(); break; - case rang::style::bold: state.bold = FOREGROUND_INTENSITY; break; - case rang::style::underline: - case rang::style::blink: - state.underline = BACKGROUND_INTENSITY; - break; - case rang::style::reversed: state.inverse = TRUE; break; - case rang::style::conceal: state.conceal = TRUE; break; - default: break; - } - } - - inline SGR ¤t_state() noexcept - { - static SGR state = defaultState(); - return state; - } - - inline WORD SGR2Attr(const SGR &state) noexcept - { - WORD attrib = 0; - if (state.conceal) { - if (state.inverse) { - attrib = (state.fgColor << 4) | state.fgColor; - if (state.bold) - attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; - } else { - attrib = (state.bgColor << 4) | state.bgColor; - if (state.underline) - attrib |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; - } - } else if (state.inverse) { - attrib = (state.fgColor << 4) | state.bgColor; - if (state.bold) attrib |= BACKGROUND_INTENSITY; - if (state.underline) attrib |= FOREGROUND_INTENSITY; - } else { - attrib = state.fgColor | (state.bgColor << 4) | state.bold - | state.underline; - } - return attrib; - } - - template - inline void setWinColorAnsi(std::ostream &os, T const value) - { - os << "\033[" << static_cast(value) << "m"; - } - - template - inline void setWinColorNative(std::ostream &os, T const value) - { - const HANDLE h = getConsoleHandle(os.rdbuf()); - if (h != INVALID_HANDLE_VALUE) { - setWinSGR(value, current_state()); - // Out all buffered text to console with previous settings: - os.flush(); - SetConsoleTextAttribute(h, SGR2Attr(current_state())); - } - } - - template - inline enableStd setColor(std::ostream &os, T const value) - { - if (winTermMode() == winTerm::Auto) { - if (supportsAnsi(os.rdbuf())) { - setWinColorAnsi(os, value); - } else { - setWinColorNative(os, value); - } - } else if (winTermMode() == winTerm::Ansi) { - setWinColorAnsi(os, value); - } else { - setWinColorNative(os, value); - } - return os; - } -#else - template - inline enableStd setColor(std::ostream &os, T const value) - { - return os << "\033[" << static_cast(value) << "m"; - } -#endif -} // namespace rang_implementation - -template -inline rang_implementation::enableStd operator<<(std::ostream &os, - const T value) -{ - const control option = rang_implementation::controlMode(); - switch (option) { - case control::Auto: - return rang_implementation::supportsColor() - && rang_implementation::isTerminal(os.rdbuf()) - ? rang_implementation::setColor(os, value) - : os; - case control::Force: return rang_implementation::setColor(os, value); - default: return os; - } -} - -inline void setWinTermMode(const rang::winTerm value) noexcept -{ - rang_implementation::winTermMode() = value; -} - -inline void setControlMode(const control value) noexcept -{ - rang_implementation::controlMode() = value; -} - -} // namespace rang - -#undef OS_LINUX -#undef OS_WIN -#undef OS_MAC - -#endif /* ifndef RANG_DOT_HPP */ diff --git a/vendor/update.toml b/vendor/update.toml index 45656c6d1..700ea0472 100644 --- a/vendor/update.toml +++ b/vendor/update.toml @@ -39,13 +39,6 @@ tarball = "https://www.openwall.com/blists/blists-2.0.tar.gz" version = "v2.0" website = "https://openwall.info/wiki/people/solar/software/public-domain-source-code/md5" -[rang] -author = "Abhinav Gauniyal" -depth = 1 -files = "{include/rang.hpp,LICENSE}" -git = "https://github.com/agauniyal/rang/" -license = "Unlicense" - [sha2] author = "Olivier Gay" email = "olivier.gay@a3.epfl.ch"