2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
21 #include "./SDL_internal.h"
23 #if defined(__WIN32__) || defined(__WINRT__)
24 #include "core/windows/SDL_windows.h"
27 /* Simple log messages in SDL */
29 #include "SDL_error.h"
36 #if defined(__ANDROID__)
37 #include <android/log.h>
44 #if defined(__TIZEN__)
45 #include <dlog/dlog.h>
49 #define LOG_TAG "SDL_LOG"
55 #define DEFAULT_PRIORITY SDL_LOG_PRIORITY_CRITICAL
56 #define DEFAULT_ASSERT_PRIORITY SDL_LOG_PRIORITY_WARN
57 #define DEFAULT_APPLICATION_PRIORITY SDL_LOG_PRIORITY_INFO
58 #define DEFAULT_TEST_PRIORITY SDL_LOG_PRIORITY_VERBOSE
60 typedef struct SDL_LogLevel
63 SDL_LogPriority priority;
64 struct SDL_LogLevel *next;
67 /* The default log output function */
68 static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority, const char *message);
70 static SDL_LogLevel *SDL_loglevels;
71 static SDL_LogPriority SDL_default_priority = DEFAULT_PRIORITY;
72 static SDL_LogPriority SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
73 static SDL_LogPriority SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
74 static SDL_LogPriority SDL_test_priority = DEFAULT_TEST_PRIORITY;
75 static SDL_LogOutputFunction SDL_log_function = SDL_LogOutput;
76 static void *SDL_log_userdata = NULL;
78 static const char *SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES] = {
88 #if defined(__TIZEN__)
89 static const int SDL_dlog_debug_priority[SDL_NUM_LOG_PRIORITIES] = {
101 static const char *SDL_category_prefixes[SDL_LOG_CATEGORY_RESERVED1] = {
111 static int SDL_android_priority[SDL_NUM_LOG_PRIORITIES] = {
120 #endif /* __ANDROID__ */
124 SDL_LogSetAllPriority(SDL_LogPriority priority)
128 for (entry = SDL_loglevels; entry; entry = entry->next) {
129 entry->priority = priority;
131 SDL_default_priority = priority;
132 SDL_assert_priority = priority;
133 SDL_application_priority = priority;
137 SDL_LogSetPriority(int category, SDL_LogPriority priority)
141 for (entry = SDL_loglevels; entry; entry = entry->next) {
142 if (entry->category == category) {
143 entry->priority = priority;
148 /* Create a new entry */
149 entry = (SDL_LogLevel *)SDL_malloc(sizeof(*entry));
151 entry->category = category;
152 entry->priority = priority;
153 entry->next = SDL_loglevels;
154 SDL_loglevels = entry;
159 SDL_LogGetPriority(int category)
163 for (entry = SDL_loglevels; entry; entry = entry->next) {
164 if (entry->category == category) {
165 return entry->priority;
169 if (category == SDL_LOG_CATEGORY_TEST) {
170 return SDL_test_priority;
171 } else if (category == SDL_LOG_CATEGORY_APPLICATION) {
172 return SDL_application_priority;
173 } else if (category == SDL_LOG_CATEGORY_ASSERT) {
174 return SDL_assert_priority;
176 return SDL_default_priority;
181 SDL_LogResetPriorities(void)
185 while (SDL_loglevels) {
186 entry = SDL_loglevels;
187 SDL_loglevels = entry->next;
191 SDL_default_priority = DEFAULT_PRIORITY;
192 SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
193 SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
194 SDL_test_priority = DEFAULT_TEST_PRIORITY;
198 SDL_Log(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
203 SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap);
208 SDL_LogVerbose(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
213 SDL_LogMessageV(category, SDL_LOG_PRIORITY_VERBOSE, fmt, ap);
218 SDL_LogDebug(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
223 SDL_LogMessageV(category, SDL_LOG_PRIORITY_DEBUG, fmt, ap);
228 SDL_LogInfo(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
233 SDL_LogMessageV(category, SDL_LOG_PRIORITY_INFO, fmt, ap);
238 SDL_LogWarn(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
243 SDL_LogMessageV(category, SDL_LOG_PRIORITY_WARN, fmt, ap);
248 SDL_LogError(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
253 SDL_LogMessageV(category, SDL_LOG_PRIORITY_ERROR, fmt, ap);
258 SDL_LogCritical(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
263 SDL_LogMessageV(category, SDL_LOG_PRIORITY_CRITICAL, fmt, ap);
268 SDL_LogMessage(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
273 SDL_LogMessageV(category, priority, fmt, ap);
279 GetCategoryPrefix(int category)
281 if (category < SDL_LOG_CATEGORY_RESERVED1) {
282 return SDL_category_prefixes[category];
284 if (category < SDL_LOG_CATEGORY_CUSTOM) {
289 #endif /* __ANDROID__ */
292 SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list ap)
297 /* Nothing to do if we don't have an output function */
298 if (!SDL_log_function) {
302 /* Make sure we don't exceed array bounds */
303 if ((int)priority < 0 || priority >= SDL_NUM_LOG_PRIORITIES) {
307 /* See if we want to do anything with this message */
308 if (priority < SDL_LogGetPriority(category)) {
312 /* !!! FIXME: why not just "char message[SDL_MAX_LOG_MESSAGE];" ? */
313 message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
318 SDL_vsnprintf(message, SDL_MAX_LOG_MESSAGE, fmt, ap);
320 /* Chop off final endline. */
321 len = SDL_strlen(message);
322 if ((len > 0) && (message[len-1] == '\n')) {
323 message[--len] = '\0';
324 if ((len > 0) && (message[len-1] == '\r')) { /* catch "\r\n", too. */
325 message[--len] = '\0';
329 SDL_log_function(SDL_log_userdata, category, priority, message);
330 SDL_stack_free(message);
333 #if defined(__WIN32__) && !defined(HAVE_STDIO_H) && !defined(__WINRT__)
334 /* Flag tracking the attachment of the console: 0=unattached, 1=attached to a console, 2=attached to a file, -1=error */
335 static int consoleAttached = 0;
337 /* Handle to stderr output of console. */
338 static HANDLE stderrHandle = NULL;
342 #if defined(__TIZEN__)
344 SDL_PrintDlog(int priority, char *format, ...)
348 if (priority >= SDL_NUM_LOG_PRIORITIES)
351 va_start(ap, format);
352 dlog_vprint(SDL_dlog_debug_priority[priority], LOG_TAG, format, ap);
358 SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
361 #if defined(__WIN32__) || defined(__WINRT__)
362 /* Way too many allocations here, urgh */
363 /* Note: One can't call SDL_SetError here, since that function itself logs. */
370 #if !defined(HAVE_STDIO_H) && !defined(__WINRT__)
373 unsigned long charsWritten;
376 /* Maybe attach console and get stderr handle */
377 if (consoleAttached == 0) {
378 attachResult = AttachConsole(ATTACH_PARENT_PROCESS);
380 attachError = GetLastError();
381 if (attachError == ERROR_INVALID_HANDLE) {
382 /* This is expected when running from Visual Studio */
383 /*OutputDebugString(TEXT("Parent process has no console\r\n"));*/
384 consoleAttached = -1;
385 } else if (attachError == ERROR_GEN_FAILURE) {
386 OutputDebugString(TEXT("Could not attach to console of parent process\r\n"));
387 consoleAttached = -1;
388 } else if (attachError == ERROR_ACCESS_DENIED) {
389 /* Already attached */
392 OutputDebugString(TEXT("Error attaching console\r\n"));
393 consoleAttached = -1;
400 if (consoleAttached == 1) {
401 stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
403 if (GetConsoleMode(stderrHandle, &consoleMode) == 0) {
404 /* WriteConsole fails if the output is redirected to a file. Must use WriteFile instead. */
409 #endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) */
411 length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1;
412 output = SDL_small_alloc(char, length, &isstack);
413 SDL_snprintf(output, length, "%s: %s\r\n", SDL_priority_prefixes[priority], message);
414 tstr = WIN_UTF8ToString(output);
416 /* Output to debugger */
417 OutputDebugString(tstr);
419 #if !defined(HAVE_STDIO_H) && !defined(__WINRT__)
420 /* Screen output to stderr, if console was attached. */
421 if (consoleAttached == 1) {
422 if (!WriteConsole(stderrHandle, tstr, lstrlen(tstr), &charsWritten, NULL)) {
423 OutputDebugString(TEXT("Error calling WriteConsole\r\n"));
424 if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
425 OutputDebugString(TEXT("Insufficient heap memory to write message\r\n"));
429 } else if (consoleAttached == 2) {
430 if (!WriteFile(stderrHandle, output, lstrlenA(output), &charsWritten, NULL)) {
431 OutputDebugString(TEXT("Error calling WriteFile\r\n"));
434 #endif /* !defined(HAVE_STDIO_H) && !defined(__WINRT__) */
437 SDL_small_free(output, isstack);
439 #elif defined(__ANDROID__)
443 SDL_snprintf(tag, SDL_arraysize(tag), "SDL/%s", GetCategoryPrefix(category));
444 __android_log_write(SDL_android_priority[priority], tag, message);
446 #elif defined(__APPLE__) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT))
447 /* Technically we don't need Cocoa/UIKit, but that's where this function is defined for now.
449 extern void SDL_NSLog(const char *text);
452 /* !!! FIXME: why not just "char text[SDL_MAX_LOG_MESSAGE];" ? */
453 text = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
455 SDL_snprintf(text, SDL_MAX_LOG_MESSAGE, "%s: %s", SDL_priority_prefixes[priority], message);
457 SDL_stack_free(text);
461 #elif defined(__PSP__)
464 pFile = fopen ("SDL_Log.txt", "a");
465 fprintf(pFile, "%s: %s\n", SDL_priority_prefixes[priority], message);
468 #elif defined(__TIZEN__)
470 SDL_PrintDlog(priority, "%s: %s", SDL_priority_prefixes[priority], message);
474 fprintf(stderr, "%s: %s\n", SDL_priority_prefixes[priority], message);
482 SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata)
485 *callback = SDL_log_function;
488 *userdata = SDL_log_userdata;
493 SDL_LogSetOutputFunction(SDL_LogOutputFunction callback, void *userdata)
495 SDL_log_function = callback;
496 SDL_log_userdata = userdata;
499 /* vi: set ts=4 sw=4 expandtab: */