#include "std_include.hpp" #include "logger.hpp" #include namespace { #ifdef _WIN32 #define COLOR(win, posix, web) win using color_type = WORD; #elif defined(__EMSCRIPTEN__) && !defined(MOMO_EMSCRIPTEN_SUPPORT_NODEJS) #define COLOR(win, posix, web) web using color_type = const char*; #else #define COLOR(win, posix, web) posix using color_type = const char*; #endif color_type get_reset_color() { return COLOR(7, "\033[0m", ""); } color_type get_color_type(const color c) { using enum color; switch (c) { case black: return COLOR(0x8, "\033[0;90m", ""); case red: return COLOR(0xC, "\033[0;91m", ""); case green: return COLOR(0xA, "\033[0;92m", ""); case yellow: return COLOR(0xE, "\033[0;93m", ""); case blue: return COLOR(0x9, "\033[0;94m", ""); case cyan: return COLOR(0xB, "\033[0;96m", ""); case pink: return COLOR(0xD, "\033[0;95m", ""); case white: return COLOR(0xF, "\033[0;97m", ""); case dark_gray: return COLOR(0x8, "\033[0;90m", ""); case gray: default: return get_reset_color(); } } #ifdef _WIN32 HANDLE get_console_handle() { return GetStdHandle(STD_OUTPUT_HANDLE); } #endif void set_color(const color_type color) { #ifdef _WIN32 SetConsoleTextAttribute(get_console_handle(), color); #else printf("%s", color); #endif } void reset_color() { (void)fflush(stdout); set_color(get_reset_color()); (void)fflush(stdout); } int format_internal(const char* message, std::span buffer, va_list* ap) { return vsnprintf(buffer.data(), buffer.size(), message, *ap); } std::string_view format(const char* message, std::string& reserve_buffer, va_list* ap1, va_list* ap2) { thread_local std::array buffer{}; auto count = format_internal(message, buffer, ap1); if (count < 0) { return {}; } if (static_cast(count) < buffer.size()) { return {buffer.data(), static_cast(count)}; } reserve_buffer.resize(count + 1); count = format_internal(message, reserve_buffer, ap2); if (count < 0) { return {}; } return {reserve_buffer.data(), std::min(static_cast(count), reserve_buffer.size() - 1)}; } #define format_to_string(msg, str) \ std::string buf{}; \ va_list ap1; \ va_list ap2; \ va_start(ap1, msg); \ va_start(ap2, msg); \ const auto str = format(msg, buf, &ap1, &ap2); \ va_end(ap2); \ va_end(ap1) void print_colored(const std::string_view& line, const color_type base_color) { const auto _ = utils::finally(&reset_color); set_color(base_color); (void)fwrite(line.data(), 1, line.size(), stdout); } } void logger::print_message(const color c, const std::string_view message, const bool force) const { if (!force && this->disable_output_) { return; } print_colored(message, get_color_type(c)); } void logger::print(const color c, const std::string_view message) { this->print_message(c, message); } // NOLINTNEXTLINE(cert-dcl50-cpp) void logger::print(const color c, const char* message, ...) { format_to_string(message, data); this->print_message(c, data); } // NOLINTNEXTLINE(cert-dcl50-cpp) void logger::force_print(const color c, const char* message, ...) { format_to_string(message, data); this->print_message(c, data, true); } // NOLINTNEXTLINE(cert-dcl50-cpp) void logger::info(const char* message, ...) const { format_to_string(message, data); this->print_message(color::cyan, data); } // NOLINTNEXTLINE(cert-dcl50-cpp) void logger::warn(const char* message, ...) const { format_to_string(message, data); this->print_message(color::yellow, data); } // NOLINTNEXTLINE(cert-dcl50-cpp) void logger::error(const char* message, ...) const { format_to_string(message, data); this->print_message(color::red, data, true); } // NOLINTNEXTLINE(cert-dcl50-cpp) void logger::success(const char* message, ...) const { format_to_string(message, data); this->print_message(color::green, data); } // NOLINTNEXTLINE(cert-dcl50-cpp) void logger::log(const char* message, ...) const { format_to_string(message, data); this->print_message(color::gray, data); }