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>
40 #define DEFAULT_PRIORITY SDL_LOG_PRIORITY_CRITICAL
41 #define DEFAULT_ASSERT_PRIORITY SDL_LOG_PRIORITY_WARN
42 #define DEFAULT_APPLICATION_PRIORITY SDL_LOG_PRIORITY_INFO
43 #define DEFAULT_TEST_PRIORITY SDL_LOG_PRIORITY_VERBOSE
45 typedef struct SDL_LogLevel
48 SDL_LogPriority priority;
49 struct SDL_LogLevel *next;
52 /* The default log output function */
53 static void SDL_LogOutput(void *userdata,
54 int category, SDL_LogPriority priority,
57 static SDL_LogLevel *SDL_loglevels;
58 static SDL_LogPriority SDL_default_priority = DEFAULT_PRIORITY;
59 static SDL_LogPriority SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
60 static SDL_LogPriority SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
61 static SDL_LogPriority SDL_test_priority = DEFAULT_TEST_PRIORITY;
62 static SDL_LogOutputFunction SDL_log_function = SDL_LogOutput;
63 static void *SDL_log_userdata = NULL;
65 static const char *SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES] = {
76 static const char *SDL_category_prefixes[SDL_LOG_CATEGORY_RESERVED1] = {
86 static int SDL_android_priority[SDL_NUM_LOG_PRIORITIES] = {
95 #endif /* __ANDROID__ */
99 SDL_LogSetAllPriority(SDL_LogPriority priority)
103 for (entry = SDL_loglevels; entry; entry = entry->next) {
104 entry->priority = priority;
106 SDL_default_priority = priority;
107 SDL_assert_priority = priority;
108 SDL_application_priority = priority;
112 SDL_LogSetPriority(int category, SDL_LogPriority priority)
116 for (entry = SDL_loglevels; entry; entry = entry->next) {
117 if (entry->category == category) {
118 entry->priority = priority;
123 /* Create a new entry */
124 entry = (SDL_LogLevel *)SDL_malloc(sizeof(*entry));
126 entry->category = category;
127 entry->priority = priority;
128 entry->next = SDL_loglevels;
129 SDL_loglevels = entry;
134 SDL_LogGetPriority(int category)
138 for (entry = SDL_loglevels; entry; entry = entry->next) {
139 if (entry->category == category) {
140 return entry->priority;
144 if (category == SDL_LOG_CATEGORY_TEST) {
145 return SDL_test_priority;
146 } else if (category == SDL_LOG_CATEGORY_APPLICATION) {
147 return SDL_application_priority;
148 } else if (category == SDL_LOG_CATEGORY_ASSERT) {
149 return SDL_assert_priority;
151 return SDL_default_priority;
156 SDL_LogResetPriorities(void)
160 while (SDL_loglevels) {
161 entry = SDL_loglevels;
162 SDL_loglevels = entry->next;
166 SDL_default_priority = DEFAULT_PRIORITY;
167 SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
168 SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
169 SDL_test_priority = DEFAULT_TEST_PRIORITY;
173 SDL_Log(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
178 SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap);
183 SDL_LogVerbose(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
188 SDL_LogMessageV(category, SDL_LOG_PRIORITY_VERBOSE, fmt, ap);
193 SDL_LogDebug(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
198 SDL_LogMessageV(category, SDL_LOG_PRIORITY_DEBUG, fmt, ap);
203 SDL_LogInfo(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
208 SDL_LogMessageV(category, SDL_LOG_PRIORITY_INFO, fmt, ap);
213 SDL_LogWarn(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
218 SDL_LogMessageV(category, SDL_LOG_PRIORITY_WARN, fmt, ap);
223 SDL_LogError(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
228 SDL_LogMessageV(category, SDL_LOG_PRIORITY_ERROR, fmt, ap);
233 SDL_LogCritical(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
238 SDL_LogMessageV(category, SDL_LOG_PRIORITY_CRITICAL, fmt, ap);
243 SDL_LogMessage(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
248 SDL_LogMessageV(category, priority, fmt, ap);
254 GetCategoryPrefix(int category)
256 if (category < SDL_LOG_CATEGORY_RESERVED1) {
257 return SDL_category_prefixes[category];
259 if (category < SDL_LOG_CATEGORY_CUSTOM) {
264 #endif /* __ANDROID__ */
267 SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list ap)
272 /* Nothing to do if we don't have an output function */
273 if (!SDL_log_function) {
277 /* Make sure we don't exceed array bounds */
278 if ((int)priority < 0 || priority >= SDL_NUM_LOG_PRIORITIES) {
282 /* See if we want to do anything with this message */
283 if (priority < SDL_LogGetPriority(category)) {
287 message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
292 SDL_vsnprintf(message, SDL_MAX_LOG_MESSAGE, fmt, ap);
294 /* Chop off final endline. */
295 len = SDL_strlen(message);
296 if ((len > 0) && (message[len-1] == '\n')) {
297 message[--len] = '\0';
298 if ((len > 0) && (message[len-1] == '\r')) { /* catch "\r\n", too. */
299 message[--len] = '\0';
303 SDL_log_function(SDL_log_userdata, category, priority, message);
304 SDL_stack_free(message);
307 #if defined(__WIN32__)
308 /* Flag tracking the attachment of the console: 0=unattached, 1=attached, -1=error */
309 static int consoleAttached = 0;
311 /* Handle to stderr output of console. */
312 static HANDLE stderrHandle = NULL;
316 SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
319 #if defined(__WIN32__) || defined(__WINRT__)
320 /* Way too many allocations here, urgh */
321 /* Note: One can't call SDL_SetError here, since that function itself logs. */
330 unsigned long charsWritten;
332 /* Maybe attach console and get stderr handle */
333 if (consoleAttached == 0) {
334 attachResult = AttachConsole(ATTACH_PARENT_PROCESS);
336 attachError = GetLastError();
337 if (attachError == ERROR_INVALID_HANDLE) {
338 OutputDebugString(TEXT("Parent process has no console\r\n"));
339 consoleAttached = -1;
340 } else if (attachError == ERROR_GEN_FAILURE) {
341 OutputDebugString(TEXT("Could not attach to console of parent process\r\n"));
342 consoleAttached = -1;
343 } else if (attachError == ERROR_ACCESS_DENIED) {
344 /* Already attached */
347 OutputDebugString(TEXT("Error attaching console\r\n"));
348 consoleAttached = -1;
355 if (consoleAttached == 1) {
356 stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
359 #endif /* ifndef __WINRT__ */
361 length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1;
362 output = SDL_stack_alloc(char, length);
363 SDL_snprintf(output, length, "%s: %s\r\n", SDL_priority_prefixes[priority], message);
364 tstr = WIN_UTF8ToString(output);
366 /* Output to debugger */
367 OutputDebugString(tstr);
370 /* Screen output to stderr, if console was attached. */
371 if (consoleAttached == 1) {
372 if (!WriteConsole(stderrHandle, tstr, lstrlen(tstr), &charsWritten, NULL)) {
373 OutputDebugString(TEXT("Error calling WriteConsole\r\n"));
374 if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
375 OutputDebugString(TEXT("Insufficient heap memory to write message\r\n"));
379 #endif /* ifndef __WINRT__ */
382 SDL_stack_free(output);
384 #elif defined(__ANDROID__)
388 SDL_snprintf(tag, SDL_arraysize(tag), "SDL/%s", GetCategoryPrefix(category));
389 __android_log_write(SDL_android_priority[priority], tag, message);
391 #elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA)
392 /* Technically we don't need SDL_VIDEO_DRIVER_COCOA, but that's where this function is defined for now.
394 extern void SDL_NSLog(const char *text);
398 text = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
400 SDL_snprintf(text, SDL_MAX_LOG_MESSAGE, "%s: %s", SDL_priority_prefixes[priority], message);
402 SDL_stack_free(text);
406 #elif defined(__PSP__)
409 pFile = fopen ("SDL_Log.txt", "a");
410 fprintf(pFile, "%s: %s\n", SDL_priority_prefixes[priority], message);
415 fprintf(stderr, "%s: %s\n", SDL_priority_prefixes[priority], message);
423 SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata)
426 *callback = SDL_log_function;
429 *userdata = SDL_log_userdata;
434 SDL_LogSetOutputFunction(SDL_LogOutputFunction callback, void *userdata)
436 SDL_log_function = callback;
437 SDL_log_userdata = userdata;
440 /* vi: set ts=4 sw=4 expandtab: */