src/SDL_log.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 30 Oct 2012 12:30:02 -0700
changeset 6616 4f272256d172
parent 6138 4c64952a58fb
child 6717 2acd95060548
child 8337 4a67a3cca43d
permissions -rw-r--r--
Added an assert log category, and NSLog support on Mac OS X and iOS
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     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.
     8 
     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:
    12 
    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.
    20 */
    21 #include "SDL_config.h"
    22 
    23 /* Simple log messages in SDL */
    24 
    25 #include "SDL_log.h"
    26 
    27 #if HAVE_STDIO_H
    28 #include <stdio.h>
    29 #endif
    30 
    31 #if defined(__WIN32__)
    32 #include "core/windows/SDL_windows.h"
    33 #elif defined(__ANDROID__)
    34 #include <android/log.h>
    35 #endif
    36 
    37 #define DEFAULT_PRIORITY                SDL_LOG_PRIORITY_CRITICAL
    38 #define DEFAULT_ASSERT_PRIORITY         SDL_LOG_PRIORITY_WARN
    39 #define DEFAULT_APPLICATION_PRIORITY    SDL_LOG_PRIORITY_INFO
    40 
    41 typedef struct SDL_LogLevel
    42 {
    43     int category;
    44     SDL_LogPriority priority;
    45     struct SDL_LogLevel *next;
    46 } SDL_LogLevel;
    47 
    48 /* The default log output function */
    49 static void SDL_LogOutput(void *userdata,
    50                           int category, SDL_LogPriority priority,
    51                           const char *message);
    52 
    53 static SDL_LogLevel *SDL_loglevels;
    54 static SDL_LogPriority SDL_default_priority = DEFAULT_PRIORITY;
    55 static SDL_LogPriority SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
    56 static SDL_LogPriority SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
    57 static SDL_LogOutputFunction SDL_log_function = SDL_LogOutput;
    58 static void *SDL_log_userdata = NULL;
    59 
    60 static const char *SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES] = {
    61     NULL,
    62     "VERBOSE",
    63     "DEBUG",
    64     "INFO",
    65     "WARN",
    66     "ERROR",
    67     "CRITICAL"
    68 };
    69 
    70 #ifdef __ANDROID__
    71 static const char *SDL_category_prefixes[SDL_LOG_CATEGORY_RESERVED1] = {
    72     "APP",
    73     "ERROR",
    74     "SYSTEM",
    75     "AUDIO",
    76     "VIDEO",
    77     "RENDER",
    78     "INPUT"
    79 };
    80 
    81 static int SDL_android_priority[SDL_NUM_LOG_PRIORITIES] = {
    82     ANDROID_LOG_VERBOSE,
    83     ANDROID_LOG_DEBUG,
    84     ANDROID_LOG_INFO,
    85     ANDROID_LOG_WARN,
    86     ANDROID_LOG_ERROR,
    87     ANDROID_LOG_FATAL
    88 };
    89 #endif /* __ANDROID__ */
    90 
    91 
    92 void
    93 SDL_LogSetAllPriority(SDL_LogPriority priority)
    94 {
    95     SDL_LogLevel *entry;
    96 
    97     for (entry = SDL_loglevels; entry; entry = entry->next) {
    98         entry->priority = priority;
    99     }
   100     SDL_default_priority = priority;
   101     SDL_assert_priority = priority;
   102     SDL_application_priority = priority;
   103 }
   104 
   105 void
   106 SDL_LogSetPriority(int category, SDL_LogPriority priority)
   107 {
   108     SDL_LogLevel *entry;
   109 
   110     for (entry = SDL_loglevels; entry; entry = entry->next) {
   111         if (entry->category == category) {
   112             entry->priority = priority;
   113             return;
   114         }
   115     }
   116 
   117     /* Create a new entry */
   118     entry = (SDL_LogLevel *)SDL_malloc(sizeof(*entry));
   119     if (entry) {
   120         entry->category = category;
   121         entry->priority = priority;
   122         entry->next = SDL_loglevels;
   123         SDL_loglevels = entry;
   124     }
   125 }
   126 
   127 SDL_LogPriority
   128 SDL_LogGetPriority(int category)
   129 {
   130     SDL_LogLevel *entry;
   131 
   132     for (entry = SDL_loglevels; entry; entry = entry->next) {
   133         if (entry->category == category) {
   134             return entry->priority;
   135         }
   136     }
   137 
   138     if (category == SDL_LOG_CATEGORY_APPLICATION) {
   139         return SDL_application_priority;
   140     } else if (category == SDL_LOG_CATEGORY_ASSERT) {
   141         return SDL_assert_priority;
   142     } else {
   143         return SDL_default_priority;
   144     }
   145 }
   146 
   147 void
   148 SDL_LogResetPriorities(void)
   149 {
   150     SDL_LogLevel *entry;
   151 
   152     while (SDL_loglevels) {
   153         entry = SDL_loglevels;
   154         SDL_loglevels = entry->next;
   155         SDL_free(entry);
   156     }
   157 
   158     SDL_default_priority = DEFAULT_PRIORITY;
   159     SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
   160     SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
   161 }
   162 
   163 void
   164 SDL_Log(const char *fmt, ...)
   165 {
   166     va_list ap;
   167 
   168     va_start(ap, fmt);
   169     SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap);
   170     va_end(ap);
   171 }
   172 
   173 void
   174 SDL_LogVerbose(int category, const char *fmt, ...)
   175 {
   176     va_list ap;
   177 
   178     va_start(ap, fmt);
   179     SDL_LogMessageV(category, SDL_LOG_PRIORITY_VERBOSE, fmt, ap);
   180     va_end(ap);
   181 }
   182 
   183 void
   184 SDL_LogDebug(int category, const char *fmt, ...)
   185 {
   186     va_list ap;
   187 
   188     va_start(ap, fmt);
   189     SDL_LogMessageV(category, SDL_LOG_PRIORITY_DEBUG, fmt, ap);
   190     va_end(ap);
   191 }
   192 
   193 void
   194 SDL_LogInfo(int category, const char *fmt, ...)
   195 {
   196     va_list ap;
   197 
   198     va_start(ap, fmt);
   199     SDL_LogMessageV(category, SDL_LOG_PRIORITY_INFO, fmt, ap);
   200     va_end(ap);
   201 }
   202 
   203 void
   204 SDL_LogWarn(int category, const char *fmt, ...)
   205 {
   206     va_list ap;
   207 
   208     va_start(ap, fmt);
   209     SDL_LogMessageV(category, SDL_LOG_PRIORITY_WARN, fmt, ap);
   210     va_end(ap);
   211 }
   212 
   213 void
   214 SDL_LogError(int category, const char *fmt, ...)
   215 {
   216     va_list ap;
   217 
   218     va_start(ap, fmt);
   219     SDL_LogMessageV(category, SDL_LOG_PRIORITY_ERROR, fmt, ap);
   220     va_end(ap);
   221 }
   222 
   223 void
   224 SDL_LogCritical(int category, const char *fmt, ...)
   225 {
   226     va_list ap;
   227 
   228     va_start(ap, fmt);
   229     SDL_LogMessageV(category, SDL_LOG_PRIORITY_CRITICAL, fmt, ap);
   230     va_end(ap);
   231 }
   232 
   233 void
   234 SDL_LogMessage(int category, SDL_LogPriority priority, const char *fmt, ...)
   235 {
   236     va_list ap;
   237 
   238     va_start(ap, fmt);
   239     SDL_LogMessageV(category, priority, fmt, ap);
   240     va_end(ap);
   241 }
   242 
   243 #ifdef __ANDROID__
   244 static const char *
   245 GetCategoryPrefix(int category)
   246 {
   247     if (category < SDL_LOG_CATEGORY_RESERVED1) {
   248         return SDL_category_prefixes[category];
   249     }
   250     if (category < SDL_LOG_CATEGORY_CUSTOM) {
   251         return "RESERVED";
   252     }
   253     return "CUSTOM";
   254 }
   255 #endif /* __ANDROID__ */
   256 
   257 void
   258 SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list ap)
   259 {
   260     char *message;
   261 
   262     /* Nothing to do if we don't have an output function */
   263     if (!SDL_log_function) {
   264         return;
   265     }
   266 
   267     /* Make sure we don't exceed array bounds */
   268     if ((int)priority < 0 || priority >= SDL_NUM_LOG_PRIORITIES) {
   269         return;
   270     }
   271 
   272     /* See if we want to do anything with this message */
   273     if (priority < SDL_LogGetPriority(category)) {
   274         return;
   275     }
   276 
   277     message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
   278     if (!message) {
   279         return;
   280     }
   281     SDL_vsnprintf(message, SDL_MAX_LOG_MESSAGE, fmt, ap);
   282     SDL_log_function(SDL_log_userdata, category, priority, message);
   283     SDL_stack_free(message);
   284 }
   285 
   286 static void
   287 SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
   288               const char *message)
   289 {
   290 #if defined(__WIN32__)
   291     /* Way too many allocations here, urgh */
   292     {
   293         char *output;
   294         size_t length;
   295         LPTSTR tstr;
   296 
   297         length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1;
   298         output = SDL_stack_alloc(char, length);
   299         SDL_snprintf(output, length, "%s: %s", SDL_priority_prefixes[priority], message);
   300         tstr = WIN_UTF8ToString(output);
   301         OutputDebugString(tstr);
   302         SDL_free(tstr);
   303         SDL_stack_free(output);
   304     }
   305 #elif defined(__ANDROID__)
   306     {
   307         char tag[32];
   308 
   309         SDL_snprintf(tag, SDL_arraysize(tag), "SDL/%s", GetCategoryPrefix(category));
   310         __android_log_write(SDL_android_priority[priority], tag, message);
   311     }
   312 #elif defined(__APPLE__)
   313     extern void SDL_NSLog(const char *text);
   314     {
   315         char *text;
   316 
   317         text = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
   318         if (text) {
   319             SDL_snprintf(text, SDL_MAX_LOG_MESSAGE, "%s: %s", SDL_priority_prefixes[priority], message);
   320             SDL_NSLog(text);
   321             SDL_stack_free(text);
   322             return;
   323         }
   324     }
   325 #endif
   326 #if HAVE_STDIO_H
   327     fprintf(stderr, "%s: %s\n", SDL_priority_prefixes[priority], message);
   328 #endif
   329 }
   330 
   331 void
   332 SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata)
   333 {
   334     if (callback) {
   335         *callback = SDL_log_function;
   336     }
   337     if (userdata) {
   338         *userdata = SDL_log_userdata;
   339     }
   340 }
   341 
   342 void
   343 SDL_LogSetOutputFunction(SDL_LogOutputFunction callback, void *userdata)
   344 {
   345     SDL_log_function = callback;
   346     SDL_log_userdata = userdata;
   347 }
   348 
   349 /* vi: set ts=4 sw=4 expandtab: */