VVVVVV/desktop_version/src/Vlogging.c

288 lines
6.2 KiB
C

#include "Vlogging.h"
#include <stdarg.h>
#include <stdio.h>
#ifdef __ANDROID__
// forward to SDL logging on Android, since stdout/stderr are /dev/null
#define VLOG_USE_SDL 1
#endif
#ifdef VLOG_USE_SDL
# include <SDL_log.h>
#elif defined(_WIN32)
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#elif defined(__unix__) || defined(__APPLE__)
# include <unistd.h>
#endif
#define COLOR(EXPR) (color_enabled && color_supported ? EXPR : "")
#define Color_RESET COLOR("\x1b[0m")
#define Color_BOLD COLOR("\x1b[1m")
#define Color_BOLD_YELLOW COLOR("\x1b[1;33m")
#define Color_BOLD_RED COLOR("\x1b[1;31m")
#define Color_BOLD_GRAY COLOR("\x1b[1;90m")
#ifdef __ANDROID__
const int color_supported = 0;
#else
static int color_supported = 0;
#endif
static int output_enabled = 1;
static int color_enabled = 1;
static int debug_enabled = 0;
static int info_enabled = 1;
static int warn_enabled = 1;
static int error_enabled = 1;
static void check_color_support(void);
void vlog_init(void)
{
#ifdef VLOG_USE_SDL
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_VERBOSE);
#endif
check_color_support();
}
void vlog_toggle_output(const int enable_output)
{
output_enabled = enable_output;
}
void vlog_toggle_color(const int enable_color)
{
color_enabled = enable_color;
}
void vlog_toggle_debug(const int enable_debug)
{
debug_enabled = enable_debug;
}
void vlog_toggle_info(const int enable_info)
{
info_enabled = enable_info;
}
void vlog_toggle_warn(const int enable_warn)
{
warn_enabled = enable_warn;
}
void vlog_toggle_error(const int enable_error)
{
error_enabled = enable_error;
}
SDL_PRINTF_VARARG_FUNC(1) void vlog_debug(const char* text, ...)
{
va_list list;
if (!output_enabled || !debug_enabled)
{
return;
}
#ifdef VLOG_USE_SDL
va_start(list, text);
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, text, list);
va_end(list);
#else
printf(Color_BOLD_GRAY);
printf("[DEBUG]");
printf(Color_RESET);
printf(" ");
va_start(list, text);
vprintf(text, list);
va_end(list);
putchar('\n');
#endif
}
SDL_PRINTF_VARARG_FUNC(1) void vlog_info(const char* text, ...)
{
va_list list;
if (!output_enabled || !info_enabled)
{
return;
}
#ifdef VLOG_USE_SDL
va_start(list, text);
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, text, list);
va_end(list);
#else
printf(Color_BOLD);
printf("[INFO]");
printf(Color_RESET);
printf(" ");
va_start(list, text);
vprintf(text, list);
va_end(list);
putchar('\n');
#endif
}
SDL_PRINTF_VARARG_FUNC(1) void vlog_warn(const char* text, ...)
{
va_list list;
if (!output_enabled || !warn_enabled)
{
return;
}
#ifdef VLOG_USE_SDL
va_start(list, text);
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, text, list);
va_end(list);
#else
fprintf(stderr, Color_BOLD_YELLOW);
fprintf(stderr, "[WARN]");
fprintf(stderr, Color_RESET);
fprintf(stderr, " ");
va_start(list, text);
vfprintf(stderr, text, list);
va_end(list);
fputc('\n', stderr);
#endif
}
SDL_PRINTF_VARARG_FUNC(1) void vlog_error(const char* text, ...)
{
va_list list;
if (!output_enabled || !error_enabled)
{
return;
}
#ifdef VLOG_USE_SDL
va_start(list, text);
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, text, list);
va_end(list);
#else
fprintf(stderr, Color_BOLD_RED);
fprintf(stderr, "[ERROR]");
fprintf(stderr, Color_RESET);
fprintf(stderr, " ");
va_start(list, text);
vfprintf(stderr, text, list);
va_end(list);
fputc('\n', stderr);
#endif
}
#ifdef _WIN32
void vlog_open_console(void)
{
static int run_once = 0;
if (run_once)
{
return;
}
run_once = 1;
const BOOL success = AllocConsole();
if (!success)
{
/* Debug, not error, because it might not be an error.
* (E.g. there is already an attached console.) */
vlog_debug(
"Could not open console: AllocConsole() failed with %d",
GetLastError()
);
return;
}
const FILE* handle = freopen("CON", "w", stdout);
if (handle == NULL)
{
vlog_error("Could not redirect STDOUT to console.");
}
handle = freopen("CON", "w", stderr);
if (handle == NULL)
{
vlog_error("Could not redirect STDERR to console.");
}
check_color_support();
if (!SetConsoleOutputCP(CP_UTF8))
{
vlog_warn(
"Could not set code page for console output to UTF-8: "
"SetConsoleOutputCP() failed with %d",
GetLastError()
);
}
}
#endif /* _WIN32 */
static void check_color_support(void)
{
#ifdef _WIN32
/* VT100 colors are supported since Windows 10 build 16257,
* but it's not enabled by default. So we have to set it. */
const HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
if (hStdout == INVALID_HANDLE_VALUE)
{
vlog_error(
"Could not set color support: GetStdHandle() failed with %d",
GetLastError()
);
return;
}
const HANDLE hStderr = GetStdHandle(STD_ERROR_HANDLE);
if (hStderr == INVALID_HANDLE_VALUE)
{
vlog_error(
"Could not enable color support: GetStdHandle() failed with %d",
GetLastError()
);
return;
}
/* Older VS releases don't have this defined yet */
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif
const BOOL success = SetConsoleMode(
hStdout, ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING
);
if (!success)
{
/* Debug, not error, because it might not be an error.
* (E.g. this version of Windows doesn't support VT100 colors.) */
vlog_debug(
"Could not enable color support: SetConsoleMode() failed with %d",
GetLastError()
);
return;
}
color_supported = 1;
#elif (defined(__unix__) || defined(__APPLE__)) && !defined(VLOG_USE_SDL)
if (isatty(STDOUT_FILENO) && isatty(STDERR_FILENO))
{
color_supported = 1;
}
#endif
}