Replace consolecolors with a vendored library.

This library supports much more than consolecolors including the
Windows 8 console API.
This commit is contained in:
Sadie Powell 2022-01-26 13:12:32 +00:00
parent 4fd71323d3
commit ec46f6acda
12 changed files with 551 additions and 223 deletions

View File

@ -1,172 +0,0 @@
/*
* InspIRCd -- Internet Relay Chat Daemon
*
* Copyright (C) 2019 linuxdaemon <linuxdaemon.irc@gmail.com>
* Copyright (C) 2013, 2019, 2021 Sadie Powell <sadie@witchery.services>
* Copyright (C) 2012 ChrisTX <xpipe@hotmail.de>
*
* This file is part of InspIRCd. InspIRCd is free software: you can
* redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstdio>
#include <ostream>
#ifdef _WIN32
# include <iostream>
# include <io.h>
# define isatty(x) _isatty((x))
# define fileno(x) _fileno((x))
extern WindowsStream StandardError;
extern WindowsStream StandardOutput;
#else
# include <unistd.h>
#endif
namespace
{
inline bool CanUseColors()
{
#ifdef INSPIRCD_DISABLE_COLORS
return false;
#else
return isatty(fileno(stdout));
#endif
}
#ifdef _WIN32
inline WindowsStream& GetStreamHandle(std::ostream& os)
{
if (os.rdbuf() == std::cerr.rdbuf())
return StandardError;
if (os.rdbuf() == std::cout.rdbuf())
return StandardOutput;
// This will never happen.
throw std::invalid_argument("Tried to write color codes to a stream other than stdout or stderr!");
}
#endif
}
#ifdef _WIN32
#include <windows.h>
inline std::ostream& con_green(std::ostream& stream)
{
if (CanUseColors())
{
const WindowsStream& ws = GetStreamHandle(stream);
SetConsoleTextAttribute(ws.Handle, FOREGROUND_GREEN | FOREGROUND_INTENSITY | ws.BackgroundColor);
}
return stream;
}
inline std::ostream& con_red(std::ostream& stream)
{
if (CanUseColors())
{
const WindowsStream& ws = GetStreamHandle(stream);
SetConsoleTextAttribute(ws.Handle, FOREGROUND_RED | FOREGROUND_INTENSITY | ws.BackgroundColor);
}
return stream;
}
inline std::ostream& con_white(std::ostream& stream)
{
if (CanUseColors())
{
const WindowsStream& ws = GetStreamHandle(stream);
SetConsoleTextAttribute(ws.Handle, FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN | ws.BackgroundColor);
}
return stream;
}
inline std::ostream& con_white_bright(std::ostream& stream)
{
if (CanUseColors())
{
const WindowsStream& ws = GetStreamHandle(stream);
SetConsoleTextAttribute(ws.Handle, FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY | ws.BackgroundColor);
}
return stream;
}
inline std::ostream& con_bright(std::ostream& stream)
{
if (CanUseColors())
{
const WindowsStream& ws = GetStreamHandle(stream);
SetConsoleTextAttribute(ws.Handle, FOREGROUND_INTENSITY | ws.BackgroundColor);
}
return stream;
}
inline std::ostream& con_reset(std::ostream& stream)
{
if (CanUseColors())
{
const WindowsStream& ws = GetStreamHandle(stream);
SetConsoleTextAttribute(ws.Handle, ws.ForegroundColor);
}
return stream;
}
#else
inline std::ostream& con_green(std::ostream& stream)
{
if (!CanUseColors())
return stream;
return stream << "\033[1;32m";
}
inline std::ostream& con_red(std::ostream& stream)
{
if (!CanUseColors())
return stream;
return stream << "\033[1;31m";
}
inline std::ostream& con_white(std::ostream& stream)
{
if (!CanUseColors())
return stream;
return stream << "\033[0m";
}
inline std::ostream& con_white_bright(std::ostream& stream)
{
if (!CanUseColors())
return stream;
return stream << "\033[1m";
}
inline std::ostream& con_bright(std::ostream& stream)
{
if (!CanUseColors())
return stream;
return stream << "\033[1m";
}
inline std::ostream& con_reset(std::ostream& stream)
{
if (!CanUseColors())
return stream;
return stream << "\033[0m";
}
#endif

View File

@ -45,7 +45,7 @@ SYSTEM = @SYSTEM_NAME@
SOURCEPATH = @SOURCE_DIR@
BUILDPATH ?= $(SOURCEPATH)/build/@COMPILER_NAME@-@COMPILER_VERSION@
SOCKETENGINE = @SOCKETENGINE@
CORECXXFLAGS = -fPIC -fvisibility=hidden -fvisibility-inlines-hidden -pipe -I"$(SOURCEPATH)/include" -Wall -Wextra -Wfatal-errors -Wformat=2 -Wmissing-format-attribute -Woverloaded-virtual -Wpedantic -Wno-format-nonliteral -Wno-unused-parameter
CORECXXFLAGS = -fPIC -fvisibility=hidden -fvisibility-inlines-hidden -pipe -I"$(SOURCEPATH)/include" -I"$(SOURCEPATH)/vendor" -Wall -Wextra -Wfatal-errors -Wformat=2 -Wmissing-format-attribute -Woverloaded-virtual -Wpedantic -Wno-format-nonliteral -Wno-unused-parameter
LDLIBS = @COMPILER_EXTRA_LDLIBS@
CORELDFLAGS = -fPIE -L.
PICLDFLAGS = -fPIC -shared

View File

@ -37,18 +37,14 @@
#include <iostream>
#include "inspircd.h"
#include "consolecolors.h"
#include "exitcodes.h"
#include "xline.h"
// Needs to be included after inspircd.h to avoid reincluding winsock.
#include <rang/rang.hpp>
#ifdef _WIN32
# include <ya_getopt.h>
// Manages formatting lines written to stderr on Windows.
WindowsStream StandardError(STD_ERROR_HANDLE);
// Manages formatting lines written to stdout on Windows.
WindowsStream StandardOutput(STD_OUTPUT_HANDLE);
#else
# include <getopt.h>
# include <grp.h>
@ -78,19 +74,19 @@ namespace
if (getegid() != 0 && geteuid() != 0)
return;
std::cout << con_red << "Warning!" << con_reset << " You have started as root. Running as root is generally not required" << std::endl
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;
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 " << con_bright << "--runasroot" << con_reset << " option to disable this wait." << std::endl;
<< "then you can pass the " << rang::style::bold << "--runasroot" << rang::style::reset << " option to disable this wait." << std::endl;
sleep(30);
}
else
{
std::cout << "If you are sure that you need to run as root then you can pass the " << con_bright << "--runasroot" << con_reset << std::endl
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);
}
@ -236,7 +232,7 @@ namespace
if (childpid < 0)
{
ServerInstance->Logs.Log("STARTUP", LOG_DEFAULT, "fork() failed: %s", strerror(errno));
std::cout << con_red << "Error:" << con_reset << " unable to fork into background: " << strerror(errno);
std::cout << rang::style::bold << rang::fg::red << "Error:" << rang::style::reset << " unable to fork into background: " << strerror(errno);
ServerInstance->Exit(EXIT_STATUS_FORK);
}
else if (childpid > 0)
@ -310,8 +306,8 @@ namespace
default:
// An unknown option was specified.
std::cout << con_red << "Error:" << con_reset << " unknown option '" << argv[optind-1] << "'." << std::endl
<< con_bright << "Usage: " << con_reset << argv[0] << " [--config <file>] [--debug] [--nofork] [--nolog]" << std::endl
std::cout << rang::style::bold << rang::fg::red << "Error:" << rang::style::reset << " unknown option '" << argv[optind-1] << "'." << std::endl
<< rang::style::bold << "Usage: " << rang::style::reset << argv[0] << " [--config <file>] [--debug] [--nofork] [--nolog]" << std::endl
<< std::string(strlen(argv[0]) + 8, ' ') << "[--nopid] [--runasroot] [--version]" << std::endl;
ServerInstance->Exit(EXIT_STATUS_ARGV);
}
@ -362,17 +358,17 @@ namespace
if (!pl.empty())
{
std::cout << con_red << "Warning!" << con_reset << " Some of your listener" << (pl.size() == 1 ? "s" : "") << " failed to bind:" << std::endl
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;
for (const auto& fp : pl)
{
std::cout << " " << con_bright << fp.sa.str() << con_reset << ": " << strerror(fp.error) << '.' << std::endl
std::cout << " " << rang::style::bold << fp.sa.str() << rang::style::reset << ": " << strerror(fp.error) << '.' << std::endl
<< " " << "Created from <bind> tag at " << fp.tag->source.str() << std::endl
<< std::endl;
}
std::cout << con_bright << "Hints:" << con_reset << std::endl
std::cout << rang::style::bold << "Hints:" << rang::style::reset << std::endl
<< "- For TCP/IP listeners try using a public IP address in <bind:address> instead" << std::endl
<< " of * or leaving it blank." << std::endl
<< "- For UNIX socket listeners try enabling <bind:rewrite> to replace old sockets." << std::endl;
@ -482,8 +478,8 @@ InspIRCd::InspIRCd(int argc, char** argv)
Modules.AddServices(provs, sizeof(provs)/sizeof(provs[0]));
}
std::cout << con_green << "InspIRCd - Internet Relay Chat Daemon" << con_reset << std::endl
<< "See " << con_green << "/INFO" << con_reset << " for contributors & authors" << std::endl
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;
if (Config->cmdline.forcedebug)
@ -507,7 +503,7 @@ InspIRCd::InspIRCd(int argc, char** argv)
if (!Config->cmdline.nofork)
ForkIntoBackground();
std::cout << "InspIRCd Process ID: " << con_green << getpid() << con_reset << std::endl;
std::cout << "InspIRCd Process ID: " << rang::style::bold << rang::fg::green << getpid() << rang::style::reset << std::endl;
/* During startup we read the configuration now, not in
* a separate thread

View File

@ -27,9 +27,11 @@
#include <iostream>
#include "inspircd.h"
#include "consolecolors.h"
#include "exitcodes.h"
// Needs to be included after inspircd.h to avoid reincluding winsock.
#include <rang/rang.hpp>
bool ModuleManager::Load(const std::string& modname, bool defer)
{
/* Don't allow people to specify paths for modules, it doesn't work as expected */
@ -147,7 +149,7 @@ void ModuleManager::LoadCoreModules(std::map<std::string, ServiceList>& servicem
if (!Load(name, true))
{
ServerInstance->Logs.Log("MODULE", LOG_DEFAULT, this->LastError());
std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << this->LastError() << std::endl << std::endl;
std::cout << std::endl << "[" << rang::style::bold << rang::fg::red << "*" << rang::style::reset << "] " << this->LastError() << std::endl << std::endl;
ServerInstance->Exit(EXIT_STATUS_MODULE);
}
}

View File

@ -34,9 +34,11 @@
#include <iostream>
#include "inspircd.h"
#include "consolecolors.h"
#include "exitcodes.h"
// Needs to be included after inspircd.h to avoid reincluding winsock.
#include <rang/rang.hpp>
static insp::intrusive_list<dynamic_reference_base>* dynrefs = NULL;
void dynamic_reference_base::reset_all()
@ -516,11 +518,11 @@ void ModuleManager::LoadAll()
continue;
this->NewServices = &servicemap[name];
std::cout << "[" << con_green << "*" << con_reset << "] Loading module:\t" << con_green << name << con_reset << std::endl;
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;
if (!this->Load(name, true))
{
ServerInstance->Logs.Log("MODULE", LOG_DEFAULT, this->LastError());
std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << this->LastError() << std::endl << std::endl;
std::cout << std::endl << "[" << rang::style::bold << rang::fg::red << "*" << rang::style::reset << "] " << this->LastError() << std::endl << std::endl;
ServerInstance->Exit(EXIT_STATUS_MODULE);
}
}
@ -539,7 +541,7 @@ void ModuleManager::LoadAll()
{
LastModuleError = "Unable to initialize " + modname + ": " + modexcept.GetReason();
ServerInstance->Logs.Log("MODULE", LOG_DEFAULT, LastModuleError);
std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << LastModuleError << std::endl << std::endl;
std::cout << std::endl << "[" << rang::style::bold << rang::fg::red << "*" << rang::style::reset << "] " << LastModuleError << std::endl << std::endl;
ServerInstance->Exit(EXIT_STATUS_MODULE);
}
}
@ -561,7 +563,7 @@ void ModuleManager::LoadAll()
{
LastModuleError = "Unable to read the configuration for " + modname + ": " + modexcept.GetReason();
ServerInstance->Logs.Log("MODULE", LOG_DEFAULT, LastModuleError);
std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << LastModuleError << std::endl << std::endl;
std::cout << std::endl << "[" << rang::style::bold << rang::fg::red << "*" << rang::style::reset << "] " << LastModuleError << std::endl << std::endl;
ServerInstance->Exit(EXIT_STATUS_CONFIG);
}
}

View File

@ -29,9 +29,11 @@
#include <iostream>
#include "inspircd.h"
#include "consolecolors.h"
#include "exitcodes.h"
// Needs to be included after inspircd.h to avoid reincluding winsock.
#include <rang/rang.hpp>
/** Reference table, contains all current handlers
**/
std::vector<EventHandler*> SocketEngine::ref;
@ -71,7 +73,7 @@ void EventHandler::OnEventHandlerError(int errornum)
void SocketEngine::InitError()
{
std::cerr << con_red << "FATAL ERROR!" << con_reset << " Socket engine initialization failed. " << strerror(errno) << '.' << std::endl;
std::cerr << rang::style::bold << rang::fg::red << "FATAL ERROR!" << rang::style::reset << " Socket engine initialization failed. " << strerror(errno) << '.' << std::endl;
exit(EXIT_STATUS_SOCKETENGINE);
}

10
vendor/README.md vendored
View File

@ -22,6 +22,16 @@ This directory contains vendored dependencies that are shipped with InspIRCd to
**Website** &mdash; [https://github.com/nodejs/http-parser](https://github.com/nodejs/http-parser)
## rang
**Author** &mdash; Abhinav Gauniyal
**License** &mdash; Unlicense
**Version** &mdash; v3.2
**Website** &mdash; [https://github.com/agauniyal/rang/](https://github.com/agauniyal/rang/)
## sha2
**Author** &mdash; [Olivier Gay](mailto:olivier.gay@a3.epfl.ch)

502
vendor/rang/rang.hpp vendored Normal file
View File

@ -0,0 +1,502 @@
#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 <unistd.h>
#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 <windows.h>
#include <io.h>
#include <memory>
// 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 <algorithm>
#include <atomic>
#include <cstdlib>
#include <cstring>
#include <iostream>
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<control> &controlMode() noexcept
{
static std::atomic<control> value(control::Auto);
return value;
}
inline std::atomic<winTerm> &winTermMode() noexcept
{
static std::atomic<winTerm> 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<decltype(&GetFileInformationByHandleEx)>(
GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
"GetFileInformationByHandleEx"));
if (!ptrGetFileInformationByHandleEx) {
return false;
}
HANDLE h = reinterpret_cast<HANDLE>(_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<MY_FILE_NAME_INFO>(
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 <typename T>
using enableStd = typename std::enable_if<
std::is_same<T, rang::style>::value || std::is_same<T, rang::fg>::value
|| std::is_same<T, rang::bg>::value || std::is_same<T, rang::fgB>::value
|| std::is_same<T, rang::bgB>::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<BYTE>(rev[rgb]);
}
inline void setWinSGR(rang::bg col, SGR &state) noexcept
{
if (col != rang::bg::reset) {
state.bgColor = ansi2attr(static_cast<BYTE>(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<BYTE>(col) - 30);
} else {
state.fgColor = defaultState().fgColor;
}
}
inline void setWinSGR(rang::bgB col, SGR &state) noexcept
{
state.bgColor = (BACKGROUND_INTENSITY >> 4)
| ansi2attr(static_cast<BYTE>(col) - 100);
}
inline void setWinSGR(rang::fgB col, SGR &state) noexcept
{
state.fgColor
= FOREGROUND_INTENSITY | ansi2attr(static_cast<BYTE>(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 &current_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 <typename T>
inline void setWinColorAnsi(std::ostream &os, T const value)
{
os << "\033[" << static_cast<int>(value) << "m";
}
template <typename T>
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 <typename T>
inline enableStd<T> 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 <typename T>
inline enableStd<T> setColor(std::ostream &os, T const value)
{
return os << "\033[" << static_cast<int>(value) << "m";
}
#endif
} // namespace rang_implementation
template <typename T>
inline rang_implementation::enableStd<T> 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 */

7
vendor/update.toml vendored
View File

@ -13,6 +13,13 @@ files = "http_parser.[ch]"
git = "https://github.com/nodejs/http-parser"
license = "MIT License"
[rang]
author = "Abhinav Gauniyal"
depth = 1
files = "include/rang.hpp"
git = "https://github.com/agauniyal/rang/"
license = "Unlicense"
[sha2]
author = "Olivier Gay"
email = "olivier.gay@a3.epfl.ch"

View File

@ -60,7 +60,7 @@ foreach(INSPIRCD_VENDOR ${INSPIRCD_VENDORS})
endif()
endforeach()
include_directories("${INSPIRCD_BASE}/win" "${INSPIRCD_BASE}/include")
include_directories("${INSPIRCD_BASE}/win" "${INSPIRCD_BASE}/include" "${INSPIRCD_BASE}/vendor")
include_directories(${EXTRA_INCLUDES})
link_directories(${EXTRA_LIBS})

View File

@ -55,16 +55,3 @@ DWORD CWin32Exception::GetErrorCode()
{
return dwErrorCode;
}
WindowsStream::WindowsStream(DWORD handle)
: BackgroundColor(0)
, ForegroundColor(FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN)
{
this->Handle = GetStdHandle(handle);
CONSOLE_SCREEN_BUFFER_INFO bufinf;
if (GetConsoleScreenBufferInfo(this->Handle, &bufinf))
{
this->BackgroundColor = bufinf.wAttributes & 0x00F0;
this->ForegroundColor = bufinf.wAttributes & 0x00FF;
}
}

View File

@ -190,11 +190,3 @@ struct sockaddr_un final
ADDRESS_FAMILY sun_family;
char sun_path[6];
};
struct WindowsStream final
{
WORD BackgroundColor;
WORD ForegroundColor;
HANDLE Handle;
WindowsStream(DWORD handle);
};