From 2f3e0cb18e933309584efeb6d28680bc795bae3f Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Sun, 11 Apr 2021 15:52:05 +0100 Subject: [PATCH] SDL1: Backport SDL2 logging 1. Backports SDL2 logging. 2. Adds a `--verbose` flag. 3. As an example, adds logging priority and category to a few log calls. --- CMakeLists.txt | 12 ++- Source/diablo.cpp | 7 ++ Source/mpqapi.cpp | 4 +- SourceS/console.cpp | 78 ++++++++++++++ SourceS/console.h | 34 +------ SourceS/sdl2_to_1_2_backports.cpp | 162 ++++++++++++++++++++++++++++++ SourceS/sdl2_to_1_2_backports.h | 41 ++++++-- SourceX/miniwin/misc_msg.cpp | 2 +- 8 files changed, 295 insertions(+), 45 deletions(-) create mode 100644 SourceS/console.cpp create mode 100644 SourceS/sdl2_to_1_2_backports.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 754fcbe84..7f04310e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -211,8 +211,14 @@ add_library(PKWare STATIC 3rdParty/PKWare/explode.cpp 3rdParty/PKWare/implode.cpp) -add_library(SourceS STATIC - SourceS/paths.cpp) +set(SourceS_SRCS + SourceS/console.cpp + SourceS/paths.cpp +) +if(USE_SDL1) + list(APPEND SourceS_SRCS SourceS/sdl2_to_1_2_backports.cpp) +endif() +add_library(SourceS STATIC ${SourceS_SRCS}) add_library(devilution STATIC Source/appfat.cpp @@ -358,7 +364,7 @@ if(SWITCH) SourceX/platform/switch/docking.cpp) set(BIN_TARGET devilutionx.elf) endif() - + if(VITA) list(APPEND devilutionx_SRCS SourceX/platform/vita/keyboard.cpp) diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 686b5144a..262be9e1c 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -104,6 +104,7 @@ extern void plrctrls_after_game_logic(); printInConsole(" %-20s %-30s\n", "-n", "Skip startup videos"); printInConsole(" %-20s %-30s\n", "-f", "Display frames per second"); printInConsole(" %-20s %-30s\n", "-x", "Run in windowed mode"); + printInConsole(" %-20s %-30s\n", "--verbose", "Enable verbose logging"); printInConsole(" %-20s %-30s\n", "--spawn", "Force spawn mode even if diabdat.mpq is found"); printInConsole("\nHellfire options:\n"); printInConsole(" %-20s %-30s\n", "--diablo", "Force diablo mode even if hellfire.mpq is found"); @@ -159,6 +160,8 @@ static void diablo_parse_flags(int argc, char **argv) gbNestArt = true; } else if (strcasecmp("--vanilla", argv[i]) == 0) { gbVanilla = true; + } else if (strcasecmp("--verbose", argv[i]) == 0) { + SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE); #ifdef _DEBUG } else if (strcasecmp("-^", argv[i]) == 0) { debug_mode_key_inverted_v = true; @@ -639,6 +642,10 @@ void diablo_quit(int exitStatus) int DiabloMain(int argc, char **argv) { +#ifdef _DEBUG + SDL_LogSetAllPriority(SDL_LOG_PRIORITY_DEBUG); +#endif + diablo_parse_flags(argc, argv); LoadOptions(); diablo_init(); diff --git a/Source/mpqapi.cpp b/Source/mpqapi.cpp index b1cddf10c..8e882bd21 100644 --- a/Source/mpqapi.cpp +++ b/Source/mpqapi.cpp @@ -156,10 +156,10 @@ private: const char *error_message = std::strerror(errno); if (error_message == NULL) error_message = ""; - SDL_Log(fmt_with_error.c_str(), args..., error_message); + SDL_LogError(SDL_LOG_CATEGORY_SYSTEM, fmt_with_error.c_str(), args..., error_message); #ifdef _DEBUG } else { - SDL_Log(fmt, args...); + SDL_LogVerbose(SDL_LOG_CATEGORY_SYSTEM, fmt, args...); #endif } return !s_->fail(); diff --git a/SourceS/console.cpp b/SourceS/console.cpp new file mode 100644 index 000000000..62ead8dfd --- /dev/null +++ b/SourceS/console.cpp @@ -0,0 +1,78 @@ +#include "./console.h" + +#if defined(_WIN64) || defined(_WIN32) +#include +#include + +// Suppress definitions of `min` and `max` macros by : +#define NOMINMAX 1 +#define WIN32_LEAN_AND_MEAN +#include + +namespace devilution { + +namespace { + +HANDLE GetStderrHandle() +{ + static HANDLE handle = NULL; + if (handle == NULL) { + if (AttachConsole(ATTACH_PARENT_PROCESS)) { + handle = GetStdHandle(STD_ERROR_HANDLE); + } + } + return handle; +} + +} // namespace + +void printInConsole(const char *fmt, ...) +{ + HANDLE handle = GetStderrHandle(); + if (handle == NULL) + return; + + char message[4096]; + va_list ap; + va_start(ap, fmt); + std::vsnprintf(message, sizeof(message), fmt, ap); + va_end(ap); + + WriteConsole(handle, message, strlen(message), NULL, NULL); +} + +void printInConsoleV(const char *fmt, va_list ap) +{ + HANDLE handle = GetStderrHandle(); + if (handle == NULL) + return; + + char message[4096]; + std::vsnprintf(message, sizeof(message), fmt, ap); + + if (handle == NULL) + return; + WriteConsole(handle, message, strlen(message), NULL, NULL); +} + +} // namespace devilution +#else +#include + +namespace devilution { + +void printInConsole(const char *fmt, ...) +{ + std::va_list ap; + va_start(ap, fmt); + std::vfprintf(stderr, fmt, ap); + va_end(ap); +} + +void printInConsoleV(const char *fmt, std::va_list ap) +{ + std::vfprintf(stderr, fmt, ap); +} + +} // namespace devilution +#endif diff --git a/SourceS/console.h b/SourceS/console.h index 31583ad19..aaad797a8 100644 --- a/SourceS/console.h +++ b/SourceS/console.h @@ -1,39 +1,13 @@ #pragma once -#if defined(_WIN64) || defined(_WIN32) -#include "../defs.h" +#include +#include -// Suppress definitions of `min` and `max` macros by : -#define NOMINMAX 1 -#define WIN32_LEAN_AND_MEAN -#include +#include "../defs.h" namespace devilution { void printInConsole(const char *fmt, ...) DVL_PRINTF_ATTRIBUTE(1, 2); - -inline void printInConsole(const char *fmt, ...) -{ - static HANDLE stderrHandle = NULL; - if (stderrHandle == NULL) { - if (AttachConsole(ATTACH_PARENT_PROCESS)) { - stderrHandle = GetStdHandle(STD_ERROR_HANDLE); - } - } - - if (stderrHandle == NULL) - return; - - char message[256]; - va_list ap; - va_start(ap, fmt); - vsprintf(message, fmt, ap); - va_end(ap); - - WriteConsole(stderrHandle, message, strlen(message), NULL, NULL); -} +void printInConsoleV(const char *fmt, std::va_list ap) DVL_PRINTF_ATTRIBUTE(1, 0); } // namespace devilution -#else -#define printInConsole printf -#endif diff --git a/SourceS/sdl2_to_1_2_backports.cpp b/SourceS/sdl2_to_1_2_backports.cpp new file mode 100644 index 000000000..8de234422 --- /dev/null +++ b/SourceS/sdl2_to_1_2_backports.cpp @@ -0,0 +1,162 @@ +#include "./sdl2_to_1_2_backports.h" + +#include + +#include "./console.h" + +#define DEFAULT_PRIORITY SDL_LOG_PRIORITY_CRITICAL +#define DEFAULT_ASSERT_PRIORITY SDL_LOG_PRIORITY_WARN +#define DEFAULT_APPLICATION_PRIORITY SDL_LOG_PRIORITY_INFO +#define DEFAULT_TEST_PRIORITY SDL_LOG_PRIORITY_VERBOSE + +namespace { + +// We use the same names of these structs as the SDL2 implementation: +// NOLINTNEXTLINE(readability-identifier-naming) +struct SDL_LogLevel { + int category; + SDL_LogPriority priority; + SDL_LogLevel *next; +}; + +SDL_LogLevel *SDL_loglevels; // NOLINT(readability-identifier-naming) +SDL_LogPriority SDL_default_priority = DEFAULT_PRIORITY; // NOLINT(readability-identifier-naming) +SDL_LogPriority SDL_assert_priority = DEFAULT_ASSERT_PRIORITY; // NOLINT(readability-identifier-naming) +SDL_LogPriority SDL_application_priority = DEFAULT_APPLICATION_PRIORITY; // NOLINT(readability-identifier-naming) +SDL_LogPriority SDL_test_priority = DEFAULT_TEST_PRIORITY; // NOLINT(readability-identifier-naming) + +// NOLINTNEXTLINE(readability-identifier-naming) +const char *const SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES] = { + nullptr, + "VERBOSE", + "DEBUG", + "INFO", + "WARN", + "ERROR", + "CRITICAL" +}; + +} // namespace + +void SDL_LogSetAllPriority(SDL_LogPriority priority) +{ + for (SDL_LogLevel *entry = SDL_loglevels; entry != nullptr; entry = entry->next) { + entry->priority = priority; + } + SDL_default_priority = priority; + SDL_assert_priority = priority; + SDL_application_priority = priority; +} + +void SDL_LogSetPriority(int category, SDL_LogPriority priority) +{ + SDL_LogLevel *entry; + for (entry = SDL_loglevels; entry != nullptr; entry = entry->next) { + if (entry->category == category) { + entry->priority = priority; + return; + } + } + + entry = static_cast(SDL_malloc(sizeof(*entry))); + if (entry != nullptr) { + entry->category = category; + entry->priority = priority; + entry->next = SDL_loglevels; + SDL_loglevels = entry; + } +} + +SDL_LogPriority SDL_LogGetPriority(int category) +{ + for (SDL_LogLevel *entry = SDL_loglevels; entry != nullptr; entry = entry->next) { + if (entry->category == category) { + return entry->priority; + } + } + + switch (category) { + case SDL_LOG_CATEGORY_TEST: + return SDL_test_priority; + case SDL_LOG_CATEGORY_APPLICATION: + return SDL_application_priority; + case SDL_LOG_CATEGORY_ASSERT: + return SDL_assert_priority; + default: + return SDL_default_priority; + } +} + +void SDL_Log(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap); + va_end(ap); +} + +void SDL_LogVerbose(int category, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + SDL_LogMessageV(category, SDL_LOG_PRIORITY_VERBOSE, fmt, ap); + va_end(ap); +} + +void SDL_LogDebug(int category, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + SDL_LogMessageV(category, SDL_LOG_PRIORITY_DEBUG, fmt, ap); + va_end(ap); +} + +void SDL_LogInfo(int category, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + SDL_LogMessageV(category, SDL_LOG_PRIORITY_INFO, fmt, ap); + va_end(ap); +} + +void SDL_LogWarn(int category, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + SDL_LogMessageV(category, SDL_LOG_PRIORITY_WARN, fmt, ap); + va_end(ap); +} + +void SDL_LogError(int category, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + SDL_LogMessageV(category, SDL_LOG_PRIORITY_ERROR, fmt, ap); + va_end(ap); +} + +void SDL_LogCritical(int category, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + SDL_LogMessageV(category, SDL_LOG_PRIORITY_CRITICAL, fmt, ap); + va_end(ap); +} + +void SDL_LogMessage(int category, SDL_LogPriority priority, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + SDL_LogMessageV(category, priority, fmt, ap); + va_end(ap); +} + +void SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list ap) +{ + if (static_cast(priority) < 0 || priority >= SDL_NUM_LOG_PRIORITIES || priority < SDL_LogGetPriority(category)) + return; + + ::devilution::printInConsole("%s: ", SDL_priority_prefixes[priority]); + ::devilution::printInConsoleV(fmt, ap); + ::devilution::printInConsole("\n"); +} diff --git a/SourceS/sdl2_to_1_2_backports.h b/SourceS/sdl2_to_1_2_backports.h index 225deb220..16dc95172 100644 --- a/SourceS/sdl2_to_1_2_backports.h +++ b/SourceS/sdl2_to_1_2_backports.h @@ -55,18 +55,41 @@ #define SDL_JoystickID Sint32 #define SDL_JoystickNameForIndex SDL_JoystickName -void SDL_Log(const char *fmt, ...) DVL_PRINTF_ATTRIBUTE(1, 2); +enum SDL_LogCategory { + SDL_LOG_CATEGORY_APPLICATION, + SDL_LOG_CATEGORY_ERROR, + SDL_LOG_CATEGORY_ASSERT, + SDL_LOG_CATEGORY_SYSTEM, + SDL_LOG_CATEGORY_AUDIO, + SDL_LOG_CATEGORY_VIDEO, + SDL_LOG_CATEGORY_RENDER, + SDL_LOG_CATEGORY_INPUT, + SDL_LOG_CATEGORY_TEST, +}; -inline void SDL_Log(const char *fmt, ...) +enum SDL_LogPriority { - char message[256]; - va_list ap; - va_start(ap, fmt); - vsprintf(message, fmt, ap); - va_end(ap); + SDL_LOG_PRIORITY_VERBOSE = 1, + SDL_LOG_PRIORITY_DEBUG, + SDL_LOG_PRIORITY_INFO, + SDL_LOG_PRIORITY_WARN, + SDL_LOG_PRIORITY_ERROR, + SDL_LOG_PRIORITY_CRITICAL, + SDL_NUM_LOG_PRIORITIES +}; - printInConsole("INFO: %s\n", message); -} +void SDL_Log(const char *fmt, ...) DVL_PRINTF_ATTRIBUTE(1, 2); +void SDL_LogVerbose(int category, const char *fmt, ...) DVL_PRINTF_ATTRIBUTE(2, 3); +void SDL_LogDebug(int category, const char *fmt, ...) DVL_PRINTF_ATTRIBUTE(2, 3); +void SDL_LogInfo(int category, const char *fmt, ...) DVL_PRINTF_ATTRIBUTE(2, 3); +void SDL_LogWarn(int category, const char *fmt, ...) DVL_PRINTF_ATTRIBUTE(2, 3); +void SDL_LogError(int category, const char *fmt, ...) DVL_PRINTF_ATTRIBUTE(2, 3); +void SDL_LogCritical(int category, const char *fmt, ...) DVL_PRINTF_ATTRIBUTE(2, 3); +void SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list ap) DVL_PRINTF_ATTRIBUTE(3, 0); + +void SDL_LogSetAllPriority(SDL_LogPriority priority); +void SDL_LogSetPriority(int category, SDL_LogPriority priority); +SDL_LogPriority SDL_LogGetPriority(int category); inline void SDL_StartTextInput() { diff --git a/SourceX/miniwin/misc_msg.cpp b/SourceX/miniwin/misc_msg.cpp index 9702d3399..b65f83d40 100644 --- a/SourceX/miniwin/misc_msg.cpp +++ b/SourceX/miniwin/misc_msg.cpp @@ -264,7 +264,7 @@ bool false_avail(const char *name, int value) { #ifndef __vita__ // Logging on Vita is slow due slow IO, so disable spamming unhandled events to log - SDL_Log("Unhandled SDL event: %s %d", name, value); + SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "Unhandled SDL event: %s %d", name, value); #endif return true; }