2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 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 SDL_LogOutput(void *userdata,
69 int category, SDL_LogPriority priority,
72 static SDL_LogLevel *SDL_loglevels;
73 static SDL_LogPriority SDL_default_priority = DEFAULT_PRIORITY;
74 static SDL_LogPriority SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
75 static SDL_LogPriority SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
76 static SDL_LogPriority SDL_test_priority = DEFAULT_TEST_PRIORITY;
77 static SDL_LogOutputFunction SDL_log_function = SDL_LogOutput;
78 static void *SDL_log_userdata = NULL;
80 static const char *SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES] = {
90 #if defined(__TIZEN__)
91 static const int SDL_dlog_debug_priority[SDL_NUM_LOG_PRIORITIES] = {
103 static const char *SDL_category_prefixes[SDL_LOG_CATEGORY_RESERVED1] = {
113 static int SDL_android_priority[SDL_NUM_LOG_PRIORITIES] = {
122 #endif /* __ANDROID__ */
126 SDL_LogSetAllPriority(SDL_LogPriority priority)
130 for (entry = SDL_loglevels; entry; entry = entry->next) {
131 entry->priority = priority;
133 SDL_default_priority = priority;
134 SDL_assert_priority = priority;
135 SDL_application_priority = priority;
139 SDL_LogSetPriority(int category, SDL_LogPriority priority)
143 for (entry = SDL_loglevels; entry; entry = entry->next) {
144 if (entry->category == category) {
145 entry->priority = priority;
150 /* Create a new entry */
151 entry = (SDL_LogLevel *)SDL_malloc(sizeof(*entry));
153 entry->category = category;
154 entry->priority = priority;
155 entry->next = SDL_loglevels;
156 SDL_loglevels = entry;
161 SDL_LogGetPriority(int category)
165 for (entry = SDL_loglevels; entry; entry = entry->next) {
166 if (entry->category == category) {
167 return entry->priority;
171 if (category == SDL_LOG_CATEGORY_TEST) {
172 return SDL_test_priority;
173 } else if (category == SDL_LOG_CATEGORY_APPLICATION) {
174 return SDL_application_priority;
175 } else if (category == SDL_LOG_CATEGORY_ASSERT) {
176 return SDL_assert_priority;
178 return SDL_default_priority;
183 SDL_LogResetPriorities(void)
187 while (SDL_loglevels) {
188 entry = SDL_loglevels;
189 SDL_loglevels = entry->next;
193 SDL_default_priority = DEFAULT_PRIORITY;
194 SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
195 SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
196 SDL_test_priority = DEFAULT_TEST_PRIORITY;
200 SDL_Log(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
205 SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap);
210 SDL_LogVerbose(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
215 SDL_LogMessageV(category, SDL_LOG_PRIORITY_VERBOSE, fmt, ap);
220 SDL_LogDebug(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
225 SDL_LogMessageV(category, SDL_LOG_PRIORITY_DEBUG, fmt, ap);
230 SDL_LogInfo(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
235 SDL_LogMessageV(category, SDL_LOG_PRIORITY_INFO, fmt, ap);
240 SDL_LogWarn(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
245 SDL_LogMessageV(category, SDL_LOG_PRIORITY_WARN, fmt, ap);
250 SDL_LogError(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
255 SDL_LogMessageV(category, SDL_LOG_PRIORITY_ERROR, fmt, ap);
260 SDL_LogCritical(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
265 SDL_LogMessageV(category, SDL_LOG_PRIORITY_CRITICAL, fmt, ap);
270 SDL_LogMessage(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
275 SDL_LogMessageV(category, priority, fmt, ap);
281 GetCategoryPrefix(int category)
283 if (category < SDL_LOG_CATEGORY_RESERVED1) {
284 return SDL_category_prefixes[category];
286 if (category < SDL_LOG_CATEGORY_CUSTOM) {
291 #endif /* __ANDROID__ */
294 SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list ap)
299 /* Nothing to do if we don't have an output function */
300 if (!SDL_log_function) {
304 /* Make sure we don't exceed array bounds */
305 if ((int)priority < 0 || priority >= SDL_NUM_LOG_PRIORITIES) {
309 /* See if we want to do anything with this message */
310 if (priority < SDL_LogGetPriority(category)) {
314 message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
319 SDL_vsnprintf(message, SDL_MAX_LOG_MESSAGE, fmt, ap);
321 /* Chop off final endline. */
322 len = SDL_strlen(message);
323 if ((len > 0) && (message[len-1] == '\n')) {
324 message[--len] = '\0';
325 if ((len > 0) && (message[len-1] == '\r')) { /* catch "\r\n", too. */
326 message[--len] = '\0';
330 SDL_log_function(SDL_log_userdata, category, priority, message);
331 SDL_stack_free(message);
334 #if defined(__WIN32__)
335 /* Flag tracking the attachment of the console: 0=unattached, 1=attached, -1=error */
336 static int consoleAttached = 0;
338 /* Handle to stderr output of console. */
339 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. */
372 unsigned long charsWritten;
374 /* Maybe attach console and get stderr handle */
375 if (consoleAttached == 0) {
376 attachResult = AttachConsole(ATTACH_PARENT_PROCESS);
378 attachError = GetLastError();
379 if (attachError == ERROR_INVALID_HANDLE) {
380 OutputDebugString(TEXT("Parent process has no console\r\n"));
381 consoleAttached = -1;
382 } else if (attachError == ERROR_GEN_FAILURE) {
383 OutputDebugString(TEXT("Could not attach to console of parent process\r\n"));
384 consoleAttached = -1;
385 } else if (attachError == ERROR_ACCESS_DENIED) {
386 /* Already attached */
389 OutputDebugString(TEXT("Error attaching console\r\n"));
390 consoleAttached = -1;
397 if (consoleAttached == 1) {
398 stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
401 #endif /* ifndef __WINRT__ */
403 length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1;
404 output = SDL_stack_alloc(char, length);
405 SDL_snprintf(output, length, "%s: %s\r\n", SDL_priority_prefixes[priority], message);
406 tstr = WIN_UTF8ToString(output);
408 /* Output to debugger */
409 OutputDebugString(tstr);
412 /* Screen output to stderr, if console was attached. */
413 if (consoleAttached == 1) {
414 if (!WriteConsole(stderrHandle, tstr, lstrlen(tstr), &charsWritten, NULL)) {
415 OutputDebugString(TEXT("Error calling WriteConsole\r\n"));
416 if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
417 OutputDebugString(TEXT("Insufficient heap memory to write message\r\n"));
421 #endif /* ifndef __WINRT__ */
424 SDL_stack_free(output);
426 #elif defined(__ANDROID__)
430 SDL_snprintf(tag, SDL_arraysize(tag), "SDL/%s", GetCategoryPrefix(category));
431 __android_log_write(SDL_android_priority[priority], tag, message);
433 #elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA)
434 /* Technically we don't need SDL_VIDEO_DRIVER_COCOA, but that's where this function is defined for now.
436 extern void SDL_NSLog(const char *text);
440 text = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
442 SDL_snprintf(text, SDL_MAX_LOG_MESSAGE, "%s: %s", SDL_priority_prefixes[priority], message);
444 SDL_stack_free(text);
448 #elif defined(__PSP__)
451 pFile = fopen ("SDL_Log.txt", "a");
452 fprintf(pFile, "%s: %s\n", SDL_priority_prefixes[priority], message);
455 #elif defined(__TIZEN__)
457 SDL_PrintDlog(priority, "%s: %s", SDL_priority_prefixes[priority], message);
461 fprintf(stderr, "%s: %s\n", SDL_priority_prefixes[priority], message);
469 SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata)
472 *callback = SDL_log_function;
475 *userdata = SDL_log_userdata;
480 SDL_LogSetOutputFunction(SDL_LogOutputFunction callback, void *userdata)
482 SDL_log_function = callback;
483 SDL_log_userdata = userdata;
486 /* vi: set ts=4 sw=4 expandtab: */