123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801 |
- /*
- Simple DirectMedia Layer
- Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
- #include "SDL_internal.h"
- #if defined(SDL_PLATFORM_WINDOWS)
- #include "core/windows/SDL_windows.h"
- #endif
- // Simple log messages in SDL
- #include "SDL_log_c.h"
- #ifdef HAVE_STDIO_H
- #include <stdio.h>
- #endif
- #ifdef SDL_PLATFORM_ANDROID
- #include <android/log.h>
- #endif
- #include "stdlib/SDL_vacopy.h"
- // The size of the stack buffer to use for rendering log messages.
- #define SDL_MAX_LOG_MESSAGE_STACK 256
- #define DEFAULT_CATEGORY -1
- typedef struct SDL_LogLevel
- {
- int category;
- SDL_LogPriority priority;
- struct SDL_LogLevel *next;
- } SDL_LogLevel;
- // The default log output function
- static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority, const char *message);
- static void CleanupLogPriorities(void);
- static void CleanupLogPrefixes(void);
- static SDL_AtomicInt SDL_log_initializing;
- static SDL_AtomicInt SDL_log_initialized;
- static SDL_Mutex *SDL_log_lock;
- static SDL_Mutex *SDL_log_function_lock;
- static SDL_LogLevel *SDL_loglevels SDL_GUARDED_BY(SDL_log_lock);
- static SDL_LogPriority SDL_log_priorities[SDL_LOG_CATEGORY_CUSTOM] SDL_GUARDED_BY(SDL_log_lock);
- static SDL_LogPriority SDL_log_default_priority SDL_GUARDED_BY(SDL_log_lock);
- static SDL_LogOutputFunction SDL_log_function SDL_GUARDED_BY(SDL_log_function_lock) = SDL_LogOutput;
- static void *SDL_log_userdata SDL_GUARDED_BY(SDL_log_function_lock) = NULL;
- #ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-variable"
- #endif
- // If this list changes, update the documentation for SDL_HINT_LOGGING
- static const char * const SDL_priority_names[] = {
- NULL,
- "TRACE",
- "VERBOSE",
- "DEBUG",
- "INFO",
- "WARN",
- "ERROR",
- "CRITICAL"
- };
- SDL_COMPILE_TIME_ASSERT(priority_names, SDL_arraysize(SDL_priority_names) == SDL_LOG_PRIORITY_COUNT);
- // This is guarded by SDL_log_function_lock because it's the logging function that calls GetLogPriorityPrefix()
- static char *SDL_priority_prefixes[SDL_LOG_PRIORITY_COUNT] SDL_GUARDED_BY(SDL_log_function_lock);
- // If this list changes, update the documentation for SDL_HINT_LOGGING
- static const char * const SDL_category_names[] = {
- "APP",
- "ERROR",
- "ASSERT",
- "SYSTEM",
- "AUDIO",
- "VIDEO",
- "RENDER",
- "INPUT",
- "TEST",
- "GPU"
- };
- SDL_COMPILE_TIME_ASSERT(category_names, SDL_arraysize(SDL_category_names) == SDL_LOG_CATEGORY_RESERVED2);
- #ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
- #pragma GCC diagnostic pop
- #endif
- #ifdef SDL_PLATFORM_ANDROID
- static int SDL_android_priority[] = {
- ANDROID_LOG_UNKNOWN,
- ANDROID_LOG_VERBOSE,
- ANDROID_LOG_VERBOSE,
- ANDROID_LOG_DEBUG,
- ANDROID_LOG_INFO,
- ANDROID_LOG_WARN,
- ANDROID_LOG_ERROR,
- ANDROID_LOG_FATAL
- };
- SDL_COMPILE_TIME_ASSERT(android_priority, SDL_arraysize(SDL_android_priority) == SDL_LOG_PRIORITY_COUNT);
- #endif // SDL_PLATFORM_ANDROID
- static void SDLCALL SDL_LoggingChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
- {
- SDL_ResetLogPriorities();
- }
- void SDL_InitLog(void)
- {
- if (SDL_AtomicGet(&SDL_log_initialized)) {
- return;
- }
- // Do a little tap dance to make sure only one thread initializes logging
- if (!SDL_AtomicCompareAndSwap(&SDL_log_initializing, false, true)) {
- // Wait for the other thread to complete initialization
- while (!SDL_AtomicGet(&SDL_log_initialized)) {
- SDL_Delay(1);
- }
- return;
- }
- // If these fail we'll continue without them.
- SDL_log_lock = SDL_CreateMutex();
- SDL_log_function_lock = SDL_CreateMutex();
- SDL_AddHintCallback(SDL_HINT_LOGGING, SDL_LoggingChanged, NULL);
- SDL_AtomicSet(&SDL_log_initializing, false);
- SDL_AtomicSet(&SDL_log_initialized, true);
- }
- void SDL_QuitLog(void)
- {
- SDL_RemoveHintCallback(SDL_HINT_LOGGING, SDL_LoggingChanged, NULL);
- CleanupLogPriorities();
- CleanupLogPrefixes();
- if (SDL_log_lock) {
- SDL_DestroyMutex(SDL_log_lock);
- SDL_log_lock = NULL;
- }
- if (SDL_log_function_lock) {
- SDL_DestroyMutex(SDL_log_function_lock);
- SDL_log_function_lock = NULL;
- }
- SDL_AtomicSet(&SDL_log_initialized, false);
- }
- static void SDL_CheckInitLog()
- {
- if (!SDL_AtomicGet(&SDL_log_initialized) &&
- !SDL_AtomicGet(&SDL_log_initializing)) {
- SDL_InitLog();
- }
- }
- static void CleanupLogPriorities(void)
- {
- while (SDL_loglevels) {
- SDL_LogLevel *entry = SDL_loglevels;
- SDL_loglevels = entry->next;
- SDL_free(entry);
- }
- }
- void SDL_SetLogPriorities(SDL_LogPriority priority)
- {
- SDL_CheckInitLog();
- SDL_LockMutex(SDL_log_lock);
- {
- CleanupLogPriorities();
- SDL_log_default_priority = priority;
- for (int i = 0; i < SDL_arraysize(SDL_log_priorities); ++i) {
- SDL_log_priorities[i] = priority;
- }
- }
- SDL_UnlockMutex(SDL_log_lock);
- }
- void SDL_SetLogPriority(int category, SDL_LogPriority priority)
- {
- SDL_LogLevel *entry;
- SDL_CheckInitLog();
- SDL_LockMutex(SDL_log_lock);
- {
- if (category >= 0 && category < SDL_arraysize(SDL_log_priorities)) {
- SDL_log_priorities[category] = priority;
- } else {
- for (entry = SDL_loglevels; entry; entry = entry->next) {
- if (entry->category == category) {
- entry->priority = priority;
- break;
- }
- }
- if (!entry) {
- entry = (SDL_LogLevel *)SDL_malloc(sizeof(*entry));
- if (entry) {
- entry->category = category;
- entry->priority = priority;
- entry->next = SDL_loglevels;
- SDL_loglevels = entry;
- }
- }
- }
- }
- SDL_UnlockMutex(SDL_log_lock);
- }
- SDL_LogPriority SDL_GetLogPriority(int category)
- {
- SDL_LogLevel *entry;
- SDL_LogPriority priority = SDL_LOG_PRIORITY_INVALID;
- SDL_CheckInitLog();
- // Bypass the lock for known categories
- // Technically if the priority was set on a different CPU the value might not
- // be visible on this CPU for a while, but in practice it's fast enough that
- // this performance improvement is worthwhile.
- if (category >= 0 && category < SDL_arraysize(SDL_log_priorities)) {
- return SDL_log_priorities[category];
- }
- SDL_LockMutex(SDL_log_lock);
- {
- if (category >= 0 && category < SDL_arraysize(SDL_log_priorities)) {
- priority = SDL_log_priorities[category];
- } else {
- for (entry = SDL_loglevels; entry; entry = entry->next) {
- if (entry->category == category) {
- priority = entry->priority;
- break;
- }
- }
- if (priority == SDL_LOG_PRIORITY_INVALID) {
- priority = SDL_log_default_priority;
- }
- }
- }
- SDL_UnlockMutex(SDL_log_lock);
- return priority;
- }
- static bool ParseLogCategory(const char *string, size_t length, int *category)
- {
- int i;
- if (SDL_isdigit(*string)) {
- *category = SDL_atoi(string);
- return true;
- }
- if (*string == '*') {
- *category = DEFAULT_CATEGORY;
- return true;
- }
- for (i = 0; i < SDL_arraysize(SDL_category_names); ++i) {
- if (SDL_strncasecmp(string, SDL_category_names[i], length) == 0) {
- *category = i;
- return true;
- }
- }
- return false;
- }
- static bool ParseLogPriority(const char *string, size_t length, SDL_LogPriority *priority)
- {
- int i;
- if (SDL_isdigit(*string)) {
- i = SDL_atoi(string);
- if (i == 0) {
- // 0 has a special meaning of "disable this category"
- *priority = SDL_LOG_PRIORITY_COUNT;
- return true;
- }
- if (i > SDL_LOG_PRIORITY_INVALID && i < SDL_LOG_PRIORITY_COUNT) {
- *priority = (SDL_LogPriority)i;
- return true;
- }
- return false;
- }
- if (SDL_strncasecmp(string, "quiet", length) == 0) {
- *priority = SDL_LOG_PRIORITY_COUNT;
- return true;
- }
- for (i = SDL_LOG_PRIORITY_INVALID + 1; i < SDL_LOG_PRIORITY_COUNT; ++i) {
- if (SDL_strncasecmp(string, SDL_priority_names[i], length) == 0) {
- *priority = (SDL_LogPriority)i;
- return true;
- }
- }
- return false;
- }
- static void ParseLogPriorities(const char *hint)
- {
- const char *name, *next;
- int category = DEFAULT_CATEGORY;
- SDL_LogPriority priority = SDL_LOG_PRIORITY_INVALID;
- if (SDL_strchr(hint, '=') == NULL) {
- if (ParseLogPriority(hint, SDL_strlen(hint), &priority)) {
- SDL_SetLogPriorities(priority);
- }
- return;
- }
- for (name = hint; name; name = next) {
- const char *sep = SDL_strchr(name, '=');
- if (!sep) {
- break;
- }
- next = SDL_strchr(sep, ',');
- if (next) {
- ++next;
- }
- if (ParseLogCategory(name, (sep - name), &category)) {
- const char *value = sep + 1;
- size_t len;
- if (next) {
- len = (next - value - 1);
- } else {
- len = SDL_strlen(value);
- }
- if (ParseLogPriority(value, len, &priority)) {
- if (category == DEFAULT_CATEGORY) {
- for (int i = 0; i < SDL_arraysize(SDL_log_priorities); ++i) {
- if (SDL_log_priorities[i] == SDL_LOG_PRIORITY_INVALID) {
- SDL_log_priorities[i] = priority;
- }
- }
- SDL_log_default_priority = priority;
- } else {
- SDL_SetLogPriority(category, priority);
- }
- }
- }
- }
- }
- void SDL_ResetLogPriorities(void)
- {
- SDL_CheckInitLog();
- SDL_LockMutex(SDL_log_lock);
- {
- CleanupLogPriorities();
- SDL_log_default_priority = SDL_LOG_PRIORITY_INVALID;
- for (int i = 0; i < SDL_arraysize(SDL_log_priorities); ++i) {
- SDL_log_priorities[i] = SDL_LOG_PRIORITY_INVALID;
- }
- const char *hint = SDL_GetHint(SDL_HINT_LOGGING);
- if (hint) {
- ParseLogPriorities(hint);
- }
- if (SDL_log_default_priority == SDL_LOG_PRIORITY_INVALID) {
- SDL_log_default_priority = SDL_LOG_PRIORITY_ERROR;
- }
- for (int i = 0; i < SDL_arraysize(SDL_log_priorities); ++i) {
- if (SDL_log_priorities[i] != SDL_LOG_PRIORITY_INVALID) {
- continue;
- }
- switch (i) {
- case SDL_LOG_CATEGORY_APPLICATION:
- SDL_log_priorities[i] = SDL_LOG_PRIORITY_INFO;
- break;
- case SDL_LOG_CATEGORY_ASSERT:
- SDL_log_priorities[i] = SDL_LOG_PRIORITY_WARN;
- break;
- case SDL_LOG_CATEGORY_TEST:
- SDL_log_priorities[i] = SDL_LOG_PRIORITY_VERBOSE;
- break;
- default:
- SDL_log_priorities[i] = SDL_LOG_PRIORITY_ERROR;
- break;
- }
- }
- }
- SDL_UnlockMutex(SDL_log_lock);
- }
- static void CleanupLogPrefixes(void)
- {
- for (int i = 0; i < SDL_arraysize(SDL_priority_prefixes); ++i) {
- if (SDL_priority_prefixes[i]) {
- SDL_free(SDL_priority_prefixes[i]);
- SDL_priority_prefixes[i] = NULL;
- }
- }
- }
- static const char *GetLogPriorityPrefix(SDL_LogPriority priority)
- {
- if (priority <= SDL_LOG_PRIORITY_INVALID || priority >= SDL_LOG_PRIORITY_COUNT) {
- return "";
- }
- if (SDL_priority_prefixes[priority]) {
- return SDL_priority_prefixes[priority];
- }
- switch (priority) {
- case SDL_LOG_PRIORITY_WARN:
- return "WARNING: ";
- case SDL_LOG_PRIORITY_ERROR:
- return "ERROR: ";
- case SDL_LOG_PRIORITY_CRITICAL:
- return "ERROR: ";
- default:
- return "";
- }
- }
- SDL_bool SDL_SetLogPriorityPrefix(SDL_LogPriority priority, const char *prefix)
- {
- char *prefix_copy;
- if (priority <= SDL_LOG_PRIORITY_INVALID || priority >= SDL_LOG_PRIORITY_COUNT) {
- return SDL_InvalidParamError("priority");
- }
- if (!prefix || !*prefix) {
- prefix_copy = SDL_strdup("");
- } else {
- prefix_copy = SDL_strdup(prefix);
- }
- if (!prefix_copy) {
- return false;
- }
- SDL_LockMutex(SDL_log_function_lock);
- {
- if (SDL_priority_prefixes[priority]) {
- SDL_free(SDL_priority_prefixes[priority]);
- }
- SDL_priority_prefixes[priority] = prefix_copy;
- }
- SDL_UnlockMutex(SDL_log_function_lock);
- return true;
- }
- void SDL_Log(SDL_PRINTF_FORMAT_STRING 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_LogTrace(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- SDL_LogMessageV(category, SDL_LOG_PRIORITY_TRACE, fmt, ap);
- va_end(ap);
- }
- void SDL_LogVerbose(int category, SDL_PRINTF_FORMAT_STRING 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, SDL_PRINTF_FORMAT_STRING 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, SDL_PRINTF_FORMAT_STRING 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, SDL_PRINTF_FORMAT_STRING 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, SDL_PRINTF_FORMAT_STRING 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, SDL_PRINTF_FORMAT_STRING 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, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
- {
- va_list ap;
- va_start(ap, fmt);
- SDL_LogMessageV(category, priority, fmt, ap);
- va_end(ap);
- }
- #ifdef SDL_PLATFORM_ANDROID
- static const char *GetCategoryPrefix(int category)
- {
- if (category < SDL_LOG_CATEGORY_RESERVED2) {
- return SDL_category_names[category];
- }
- if (category < SDL_LOG_CATEGORY_CUSTOM) {
- return "RESERVED";
- }
- return "CUSTOM";
- }
- #endif // SDL_PLATFORM_ANDROID
- void SDL_LogMessageV(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap)
- {
- char *message = NULL;
- char stack_buf[SDL_MAX_LOG_MESSAGE_STACK];
- size_t len_plus_term;
- int len;
- va_list aq;
- // Nothing to do if we don't have an output function
- if (!SDL_log_function) {
- return;
- }
- // See if we want to do anything with this message
- if (priority < SDL_GetLogPriority(category)) {
- return;
- }
- // Render into stack buffer
- va_copy(aq, ap);
- len = SDL_vsnprintf(stack_buf, sizeof(stack_buf), fmt, aq);
- va_end(aq);
- if (len < 0) {
- return;
- }
- // If message truncated, allocate and re-render
- if (len >= sizeof(stack_buf) && SDL_size_add_check_overflow(len, 1, &len_plus_term)) {
- // Allocate exactly what we need, including the zero-terminator
- message = (char *)SDL_malloc(len_plus_term);
- if (!message) {
- return;
- }
- va_copy(aq, ap);
- len = SDL_vsnprintf(message, len_plus_term, fmt, aq);
- va_end(aq);
- } else {
- message = stack_buf;
- }
- // Chop off final endline.
- if ((len > 0) && (message[len - 1] == '\n')) {
- message[--len] = '\0';
- if ((len > 0) && (message[len - 1] == '\r')) { // catch "\r\n", too.
- message[--len] = '\0';
- }
- }
- SDL_LockMutex(SDL_log_function_lock);
- {
- SDL_log_function(SDL_log_userdata, category, priority, message);
- }
- SDL_UnlockMutex(SDL_log_function_lock);
- // Free only if dynamically allocated
- if (message != stack_buf) {
- SDL_free(message);
- }
- }
- #if defined(SDL_PLATFORM_WIN32) && !defined(SDL_PLATFORM_GDK)
- enum {
- CONSOLE_UNATTACHED = 0,
- CONSOLE_ATTACHED_CONSOLE = 1,
- CONSOLE_ATTACHED_FILE = 2,
- CONSOLE_ATTACHED_ERROR = -1,
- } consoleAttached = CONSOLE_UNATTACHED;
- // Handle to stderr output of console.
- static HANDLE stderrHandle = NULL;
- #endif
- static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
- const char *message)
- {
- #if defined(SDL_PLATFORM_WINDOWS)
- // Way too many allocations here, urgh
- // Note: One can't call SDL_SetError here, since that function itself logs.
- {
- char *output;
- size_t length;
- LPTSTR tstr;
- bool isstack;
- #if !defined(SDL_PLATFORM_GDK)
- BOOL attachResult;
- DWORD attachError;
- DWORD consoleMode;
- DWORD charsWritten;
- // Maybe attach console and get stderr handle
- if (consoleAttached == CONSOLE_UNATTACHED) {
- attachResult = AttachConsole(ATTACH_PARENT_PROCESS);
- if (!attachResult) {
- attachError = GetLastError();
- if (attachError == ERROR_INVALID_HANDLE) {
- // This is expected when running from Visual Studio
- // OutputDebugString(TEXT("Parent process has no console\r\n"));
- consoleAttached = CONSOLE_ATTACHED_ERROR;
- } else if (attachError == ERROR_GEN_FAILURE) {
- OutputDebugString(TEXT("Could not attach to console of parent process\r\n"));
- consoleAttached = CONSOLE_ATTACHED_ERROR;
- } else if (attachError == ERROR_ACCESS_DENIED) {
- // Already attached
- consoleAttached = CONSOLE_ATTACHED_CONSOLE;
- } else {
- OutputDebugString(TEXT("Error attaching console\r\n"));
- consoleAttached = CONSOLE_ATTACHED_ERROR;
- }
- } else {
- // Newly attached
- consoleAttached = CONSOLE_ATTACHED_CONSOLE;
- }
- if (consoleAttached == CONSOLE_ATTACHED_CONSOLE) {
- stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
- if (GetConsoleMode(stderrHandle, &consoleMode) == 0) {
- // WriteConsole fails if the output is redirected to a file. Must use WriteFile instead.
- consoleAttached = CONSOLE_ATTACHED_FILE;
- }
- }
- }
- #endif // !defined(SDL_PLATFORM_GDK)
- length = SDL_strlen(GetLogPriorityPrefix(priority)) + SDL_strlen(message) + 1 + 1 + 1;
- output = SDL_small_alloc(char, length, &isstack);
- (void)SDL_snprintf(output, length, "%s%s\r\n", GetLogPriorityPrefix(priority), message);
- tstr = WIN_UTF8ToString(output);
- // Output to debugger
- OutputDebugString(tstr);
- #if !defined(SDL_PLATFORM_GDK)
- // Screen output to stderr, if console was attached.
- if (consoleAttached == CONSOLE_ATTACHED_CONSOLE) {
- if (!WriteConsole(stderrHandle, tstr, (DWORD)SDL_tcslen(tstr), &charsWritten, NULL)) {
- OutputDebugString(TEXT("Error calling WriteConsole\r\n"));
- if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
- OutputDebugString(TEXT("Insufficient heap memory to write message\r\n"));
- }
- }
- } else if (consoleAttached == CONSOLE_ATTACHED_FILE) {
- if (!WriteFile(stderrHandle, output, (DWORD)SDL_strlen(output), &charsWritten, NULL)) {
- OutputDebugString(TEXT("Error calling WriteFile\r\n"));
- }
- }
- #endif // !defined(SDL_PLATFORM_GDK)
- SDL_free(tstr);
- SDL_small_free(output, isstack);
- }
- #elif defined(SDL_PLATFORM_ANDROID)
- {
- char tag[32];
- SDL_snprintf(tag, SDL_arraysize(tag), "SDL/%s", GetCategoryPrefix(category));
- __android_log_write(SDL_android_priority[priority], tag, message);
- }
- #elif defined(SDL_PLATFORM_APPLE) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT))
- /* Technically we don't need Cocoa/UIKit, but that's where this function is defined for now.
- */
- extern void SDL_NSLog(const char *prefix, const char *text);
- {
- SDL_NSLog(GetLogPriorityPrefix(priority), message);
- return;
- }
- #elif defined(SDL_PLATFORM_PSP) || defined(SDL_PLATFORM_PS2)
- {
- FILE *pFile;
- pFile = fopen("SDL_Log.txt", "a");
- if (pFile) {
- (void)fprintf(pFile, "%s%s\n", GetLogPriorityPrefix(priority), message);
- (void)fclose(pFile);
- }
- }
- #elif defined(SDL_PLATFORM_VITA)
- {
- FILE *pFile;
- pFile = fopen("ux0:/data/SDL_Log.txt", "a");
- if (pFile) {
- (void)fprintf(pFile, "%s%s\n", GetLogPriorityPrefix(priority), message);
- (void)fclose(pFile);
- }
- }
- #elif defined(SDL_PLATFORM_3DS)
- {
- FILE *pFile;
- pFile = fopen("sdmc:/3ds/SDL_Log.txt", "a");
- if (pFile) {
- (void)fprintf(pFile, "%s%s\n", GetLogPriorityPrefix(priority), message);
- (void)fclose(pFile);
- }
- }
- #endif
- #if defined(HAVE_STDIO_H) && \
- !(defined(SDL_PLATFORM_APPLE) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT))) && \
- !(defined(SDL_PLATFORM_WIN32))
- (void)fprintf(stderr, "%s%s\n", GetLogPriorityPrefix(priority), message);
- #endif
- }
- void SDL_GetLogOutputFunction(SDL_LogOutputFunction *callback, void **userdata)
- {
- SDL_LockMutex(SDL_log_function_lock);
- {
- if (callback) {
- *callback = SDL_log_function;
- }
- if (userdata) {
- *userdata = SDL_log_userdata;
- }
- }
- SDL_UnlockMutex(SDL_log_function_lock);
- }
- void SDL_SetLogOutputFunction(SDL_LogOutputFunction callback, void *userdata)
- {
- SDL_LockMutex(SDL_log_function_lock);
- {
- SDL_log_function = callback;
- SDL_log_userdata = userdata;
- }
- SDL_UnlockMutex(SDL_log_function_lock);
- }
|