SDL_log.c
Go to the documentation of this file.
/*
Simple DirectMedia Layer
Copyright (C) 1997-2016 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(__WIN32__) || defined(__WINRT__)
#include "core/windows/SDL_windows.h"
#endif
/* Simple log messages in SDL */
#include "SDL_error.h"
#include "SDL_log.h"
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#if defined(__ANDROID__)
#include <android/log.h>
#endif
#define DEFAULT_PRIORITY SDL_LOG_PRIORITY_CRITICAL
#define DEFAULT_ASSERT_PRIORITY SDL_LOG_PRIORITY_WARN
#define DEFAULT_APPLICATION_PRIORITY SDL_LOG_PRIORITY_INFO
#define DEFAULT_TEST_PRIORITY SDL_LOG_PRIORITY_VERBOSE
typedef struct SDL_LogLevel
{
int category;
SDL_LogPriority priority;
struct SDL_LogLevel *next;
} SDL_LogLevel;
/* The default log output function */
static void SDL_LogOutput(void *userdata,
int category, SDL_LogPriority priority,
const char *message);
static SDL_LogLevel *SDL_loglevels;
static SDL_LogPriority SDL_default_priority = DEFAULT_PRIORITY;
static SDL_LogPriority SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
static SDL_LogPriority SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
static SDL_LogPriority SDL_test_priority = DEFAULT_TEST_PRIORITY;
static SDL_LogOutputFunction SDL_log_function = SDL_LogOutput;
static void *SDL_log_userdata = NULL;
static const char *SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES] = {
NULL,
"VERBOSE",
"DEBUG",
"INFO",
"WARN",
"ERROR",
"CRITICAL"
};
#ifdef __ANDROID__
static const char *SDL_category_prefixes[SDL_LOG_CATEGORY_RESERVED1] = {
"APP",
"ERROR",
"SYSTEM",
"AUDIO",
"VIDEO",
"RENDER",
"INPUT"
};
static int SDL_android_priority[SDL_NUM_LOG_PRIORITIES] = {
ANDROID_LOG_UNKNOWN,
ANDROID_LOG_VERBOSE,
ANDROID_LOG_DEBUG,
ANDROID_LOG_INFO,
ANDROID_LOG_WARN,
ANDROID_LOG_ERROR,
ANDROID_LOG_FATAL
};
#endif /* __ANDROID__ */
void
SDL_LogSetAllPriority(SDL_LogPriority priority)
{
SDL_LogLevel *entry;
for (entry = SDL_loglevels; entry; entry = entry->next) {
entry->priority = priority;
}
SDL_default_priority = priority;
SDL_assert_priority = priority;
SDL_application_priority = priority;
}
void
SDL_LogSetPriority(int category, SDL_LogPriority priority)
{
SDL_LogLevel *entry;
for (entry = SDL_loglevels; entry; entry = entry->next) {
if (entry->category == category) {
entry->priority = priority;
return;
}
}
/* Create a new entry */
entry = (SDL_LogLevel *)SDL_malloc(sizeof(*entry));
if (entry) {
entry->category = category;
entry->priority = priority;
entry->next = SDL_loglevels;
SDL_loglevels = entry;
}
}
SDL_LogPriority
SDL_LogGetPriority(int category)
{
SDL_LogLevel *entry;
for (entry = SDL_loglevels; entry; entry = entry->next) {
if (entry->category == category) {
return entry->priority;
}
}
if (category == SDL_LOG_CATEGORY_TEST) {
return SDL_test_priority;
} else if (category == SDL_LOG_CATEGORY_APPLICATION) {
return SDL_application_priority;
} else if (category == SDL_LOG_CATEGORY_ASSERT) {
return SDL_assert_priority;
} else {
return SDL_default_priority;
}
}
void
SDL_LogResetPriorities(void)
{
SDL_LogLevel *entry;
while (SDL_loglevels) {
entry = SDL_loglevels;
SDL_loglevels = entry->next;
SDL_free(entry);
}
SDL_default_priority = DEFAULT_PRIORITY;
SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
SDL_test_priority = DEFAULT_TEST_PRIORITY;
}
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_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 __ANDROID__
static const char *
GetCategoryPrefix(int category)
{
if (category < SDL_LOG_CATEGORY_RESERVED1) {
return SDL_category_prefixes[category];
}
if (category < SDL_LOG_CATEGORY_CUSTOM) {
return "RESERVED";
}
return "CUSTOM";
}
#endif /* __ANDROID__ */
void
SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list ap)
{
char *message;
size_t len;
/* Nothing to do if we don't have an output function */
if (!SDL_log_function) {
return;
}
/* Make sure we don't exceed array bounds */
if ((int)priority < 0 || priority >= SDL_NUM_LOG_PRIORITIES) {
return;
}
/* See if we want to do anything with this message */
if (priority < SDL_LogGetPriority(category)) {
return;
}
message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
if (!message) {
return;
}
SDL_vsnprintf(message, SDL_MAX_LOG_MESSAGE, fmt, ap);
/* Chop off final endline. */
len = SDL_strlen(message);
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_log_function(SDL_log_userdata, category, priority, message);
SDL_stack_free(message);
}
#if defined(__WIN32__)
/* Flag tracking the attachment of the console: 0=unattached, 1=attached, -1=error */
static int consoleAttached = 0;
/* Handle to stderr output of console. */
static HANDLE stderrHandle = NULL;
#endif
static void
SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
const char *message)
{
#if defined(__WIN32__) || defined(__WINRT__)
/* 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;
#ifndef __WINRT__
BOOL attachResult;
DWORD attachError;
unsigned long charsWritten;
/* Maybe attach console and get stderr handle */
if (consoleAttached == 0) {
attachResult = AttachConsole(ATTACH_PARENT_PROCESS);
if (!attachResult) {
attachError = GetLastError();
if (attachError == ERROR_INVALID_HANDLE) {
OutputDebugString(TEXT("Parent process has no console\r\n"));
consoleAttached = -1;
} else if (attachError == ERROR_GEN_FAILURE) {
OutputDebugString(TEXT("Could not attach to console of parent process\r\n"));
consoleAttached = -1;
} else if (attachError == ERROR_ACCESS_DENIED) {
/* Already attached */
consoleAttached = 1;
} else {
OutputDebugString(TEXT("Error attaching console\r\n"));
consoleAttached = -1;
}
} else {
/* Newly attached */
consoleAttached = 1;
}
if (consoleAttached == 1) {
stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
}
}
#endif /* ifndef __WINRT__ */
length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1;
output = SDL_stack_alloc(char, length);
SDL_snprintf(output, length, "%s: %s\r\n", SDL_priority_prefixes[priority], message);
tstr = WIN_UTF8ToString(output);
/* Output to debugger */
OutputDebugString(tstr);
#ifndef __WINRT__
/* Screen output to stderr, if console was attached. */
if (consoleAttached == 1) {
if (!WriteConsole(stderrHandle, tstr, lstrlen(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"));
}
}
}
#endif /* ifndef __WINRT__ */
SDL_free(tstr);
SDL_stack_free(output);
}
#elif defined(__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(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA)
/* Technically we don't need SDL_VIDEO_DRIVER_COCOA, but that's where this function is defined for now.
*/
extern void SDL_NSLog(const char *text);
{
char *text;
text = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
if (text) {
SDL_snprintf(text, SDL_MAX_LOG_MESSAGE, "%s: %s", SDL_priority_prefixes[priority], message);
SDL_NSLog(text);
SDL_stack_free(text);
return;
}
}
#elif defined(__PSP__)
{
FILE* pFile;
pFile = fopen ("SDL_Log.txt", "a");
fprintf(pFile, "%s: %s\n", SDL_priority_prefixes[priority], message);
fclose (pFile);
}
#endif
#if HAVE_STDIO_H
fprintf(stderr, "%s: %s\n", SDL_priority_prefixes[priority], message);
#if __NACL__
fflush(stderr);
#endif
#endif
}
void
SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata)
{
if (callback) {
*callback = SDL_log_function;
}
if (userdata) {
*userdata = SDL_log_userdata;
}
}
void
SDL_LogSetOutputFunction(SDL_LogOutputFunction callback, void *userdata)
{
SDL_log_function = callback;
SDL_log_userdata = userdata;
}
/* vi: set ts=4 sw=4 expandtab: */
DEFAULT_APPLICATION_PRIORITY
#define DEFAULT_APPLICATION_PRIORITY
Definition: SDL_log.c:42
SDL_LogDebug
void SDL_LogDebug(int category, SDL_PRINTF_FORMAT_STRING const char *fmt,...)
Log a message with SDL_LOG_PRIORITY_DEBUG.
Definition: SDL_log.c:193
SDL_LOG_PRIORITY_ERROR
Definition: SDL_log.h:108
SDL_MAX_LOG_MESSAGE
#define SDL_MAX_LOG_MESSAGE
The maximum size of a log message.
Definition: SDL_log.h:54
WIN_UTF8ToString
#define WIN_UTF8ToString(S)
Definition: SDL_windows.h:46
SDL_test_priority
static SDL_LogPriority SDL_test_priority
Definition: SDL_log.c:61
SDL_LogCritical
void SDL_LogCritical(int category, SDL_PRINTF_FORMAT_STRING const char *fmt,...)
Log a message with SDL_LOG_PRIORITY_CRITICAL.
Definition: SDL_log.c:233
SDL_loglevels
static SDL_LogLevel * SDL_loglevels
Definition: SDL_log.c:57
SDL_log.h
message
GLuint GLsizei const GLchar * message
Definition: SDL_opengl_glext.h:2483
DEFAULT_ASSERT_PRIORITY
#define DEFAULT_ASSERT_PRIORITY
Definition: SDL_log.c:41
SDL_LOG_CATEGORY_CUSTOM
Definition: SDL_log.h:96
SDL_internal.h
SDL_priority_prefixes
static const char * SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES]
Definition: SDL_log.c:65
SDL_LogSetAllPriority
void SDL_LogSetAllPriority(SDL_LogPriority priority)
Set the priority of all log categories.
Definition: SDL_log.c:99
SDL_LogLevel::priority
SDL_LogPriority priority
Definition: SDL_log.c:48
SDL_LOG_PRIORITY_DEBUG
Definition: SDL_log.h:105
SDL_LOG_PRIORITY_VERBOSE
Definition: SDL_log.h:104
len
GLenum GLsizei len
Definition: SDL_opengl_glext.h:2926
SDL_windows.h
SDL_LogWarn
void SDL_LogWarn(int category, SDL_PRINTF_FORMAT_STRING const char *fmt,...)
Log a message with SDL_LOG_PRIORITY_WARN.
Definition: SDL_log.c:213
SDL_LogVerbose
void SDL_LogVerbose(int category, SDL_PRINTF_FORMAT_STRING const char *fmt,...)
Log a message with SDL_LOG_PRIORITY_VERBOSE.
Definition: SDL_log.c:183
SDL_LogResetPriorities
void SDL_LogResetPriorities(void)
Reset all priorities to default.
Definition: SDL_log.c:156
SDL_LOG_PRIORITY_CRITICAL
Definition: SDL_log.h:109
SDL_vsnprintf
#define SDL_vsnprintf
Definition: SDL_dynapi_overrides.h:427
SDL_LOG_CATEGORY_RESERVED1
Definition: SDL_log.h:77
SDL_log_function
static SDL_LogOutputFunction SDL_log_function
Definition: SDL_log.c:62
SDL_NUM_LOG_PRIORITIES
Definition: SDL_log.h:110
SDL_Log
void SDL_Log(SDL_PRINTF_FORMAT_STRING const char *fmt,...)
Log a message with SDL_LOG_CATEGORY_APPLICATION and SDL_LOG_PRIORITY_INFO.
Definition: SDL_log.c:173
SDL_assert_priority
static SDL_LogPriority SDL_assert_priority
Definition: SDL_log.c:59
SDL_default_priority
static SDL_LogPriority SDL_default_priority
Definition: SDL_log.c:58
SDL_stack_alloc
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:326
SDL_free
void SDL_free(void *mem)
sort_controllers.output
output
Definition: sort_controllers.py:10
SDL_LogLevel::category
int category
Definition: SDL_log.c:47
SDL_LogLevel::next
struct SDL_LogLevel * next
Definition: SDL_log.c:49
SDL_LogSetOutputFunction
void SDL_LogSetOutputFunction(SDL_LogOutputFunction callback, void *userdata)
This function allows you to replace the default log output function with one of your own...
Definition: SDL_log.c:434
SDL_LOG_CATEGORY_ASSERT
Definition: SDL_log.h:68
callback
static Uint32 callback(Uint32 interval, void *param)
Definition: testtimer.c:34
SDL_LogLevel
Definition: SDL_log.c:45
SDL_LogMessageV
void SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list ap)
Log a message with the specified category and priority.
Definition: SDL_log.c:267
SDL_LOG_PRIORITY_INFO
Definition: SDL_log.h:106
SDL_LogGetPriority
SDL_LogPriority SDL_LogGetPriority(int category)
Get the priority of a particular log category.
Definition: SDL_log.c:134
SDL_LogPriority
SDL_LogPriority
The predefined log priorities.
Definition: SDL_log.h:102
SDL_log_userdata
static void * SDL_log_userdata
Definition: SDL_log.c:63
SDL_LOG_CATEGORY_TEST
Definition: SDL_log.h:74
SDL_LogGetOutputFunction
void SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata)
Get the current log output function.
Definition: SDL_log.c:423
NULL
#define NULL
Definition: begin_code.h:143
text
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:34
SDL_strlen
#define SDL_strlen
Definition: SDL_dynapi_overrides.h:399
SDL_LogError
void SDL_LogError(int category, SDL_PRINTF_FORMAT_STRING const char *fmt,...)
Log a message with SDL_LOG_PRIORITY_ERROR.
Definition: SDL_log.c:223
SDL_LOG_PRIORITY_WARN
Definition: SDL_log.h:107
SDL_LogOutputFunction
void(* SDL_LogOutputFunction)(void *userdata, int category, SDL_LogPriority priority, const char *message)
The prototype for the log output function.
Definition: SDL_log.h:189
SDL_snprintf
#define SDL_snprintf
Definition: SDL_dynapi_overrides.h:46
SDL_arraysize
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
DEFAULT_PRIORITY
#define DEFAULT_PRIORITY
Definition: SDL_log.c:40
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:380
SDL_LogInfo
void SDL_LogInfo(int category, SDL_PRINTF_FORMAT_STRING const char *fmt,...)
Log a message with SDL_LOG_PRIORITY_INFO.
Definition: SDL_log.c:203
SDL_application_priority
static SDL_LogPriority SDL_application_priority
Definition: SDL_log.c:60
SDL_stack_free
#define SDL_stack_free(data)
Definition: SDL_stdinc.h:327
SDL_PRINTF_FORMAT_STRING
#define SDL_PRINTF_FORMAT_STRING
Definition: SDL_stdinc.h:250
SDL_LogSetPriority
void SDL_LogSetPriority(int category, SDL_LogPriority priority)
Set the priority of a particular log category.
Definition: SDL_log.c:112
length
GLuint GLsizei GLsizei * length
Definition: SDL_opengl_glext.h:669
DEFAULT_TEST_PRIORITY
#define DEFAULT_TEST_PRIORITY
Definition: SDL_log.c:43
SDL_LogMessage
void SDL_LogMessage(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt,...)
Log a message with the specified category and priority.
Definition: SDL_log.c:243
SDL_LogOutput
static void SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority, const char *message)
Definition: SDL_log.c:316
SDL_error.h
SDL_LOG_CATEGORY_APPLICATION
Definition: SDL_log.h:66