src/SDL_log.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 02 Feb 2014 00:53:27 -0800
changeset 8149 681eb46b8ac4
parent 8093 b43765095a6f
child 8583 fb2933ca805f
permissions -rw-r--r--
Fixed bug 2374 - Update copyright for 2014...

Is it that time already??
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_internal.h"
    22 
    23 #if defined(__WIN32__)
    24 #include "core/windows/SDL_windows.h"
    25 #endif
    26 
    27 /* Simple log messages in SDL */
    28 
    29 #include "SDL_log.h"
    30 
    31 #if HAVE_STDIO_H
    32 #include <stdio.h>
    33 #endif
    34 
    35 #if defined(__ANDROID__)
    36 #include <android/log.h>
    37 #endif
    38 
    39 #define DEFAULT_PRIORITY                SDL_LOG_PRIORITY_CRITICAL
    40 #define DEFAULT_ASSERT_PRIORITY         SDL_LOG_PRIORITY_WARN
    41 #define DEFAULT_APPLICATION_PRIORITY    SDL_LOG_PRIORITY_INFO
    42 #define DEFAULT_TEST_PRIORITY           SDL_LOG_PRIORITY_VERBOSE
    43 
    44 /* Forward definition of error function */
    45 extern int SDL_SetError(const char *fmt, ...);
    46 
    47 typedef struct SDL_LogLevel
    48 {
    49     int category;
    50     SDL_LogPriority priority;
    51     struct SDL_LogLevel *next;
    52 } SDL_LogLevel;
    53 
    54 /* The default log output function */
    55 static void SDL_LogOutput(void *userdata,
    56                           int category, SDL_LogPriority priority,
    57                           const char *message);
    58 
    59 static SDL_LogLevel *SDL_loglevels;
    60 static SDL_LogPriority SDL_default_priority = DEFAULT_PRIORITY;
    61 static SDL_LogPriority SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
    62 static SDL_LogPriority SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
    63 static SDL_LogPriority SDL_test_priority = DEFAULT_TEST_PRIORITY;
    64 static SDL_LogOutputFunction SDL_log_function = SDL_LogOutput;
    65 static void *SDL_log_userdata = NULL;
    66 
    67 static const char *SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES] = {
    68     NULL,
    69     "VERBOSE",
    70     "DEBUG",
    71     "INFO",
    72     "WARN",
    73     "ERROR",
    74     "CRITICAL"
    75 };
    76 
    77 #ifdef __ANDROID__
    78 static const char *SDL_category_prefixes[SDL_LOG_CATEGORY_RESERVED1] = {
    79     "APP",
    80     "ERROR",
    81     "SYSTEM",
    82     "AUDIO",
    83     "VIDEO",
    84     "RENDER",
    85     "INPUT"
    86 };
    87 
    88 static int SDL_android_priority[SDL_NUM_LOG_PRIORITIES] = {
    89     ANDROID_LOG_UNKNOWN,
    90     ANDROID_LOG_VERBOSE,
    91     ANDROID_LOG_DEBUG,
    92     ANDROID_LOG_INFO,
    93     ANDROID_LOG_WARN,
    94     ANDROID_LOG_ERROR,
    95     ANDROID_LOG_FATAL
    96 };
    97 #endif /* __ANDROID__ */
    98 
    99 
   100 void
   101 SDL_LogSetAllPriority(SDL_LogPriority priority)
   102 {
   103     SDL_LogLevel *entry;
   104 
   105     for (entry = SDL_loglevels; entry; entry = entry->next) {
   106         entry->priority = priority;
   107     }
   108     SDL_default_priority = priority;
   109     SDL_assert_priority = priority;
   110     SDL_application_priority = priority;
   111 }
   112 
   113 void
   114 SDL_LogSetPriority(int category, SDL_LogPriority priority)
   115 {
   116     SDL_LogLevel *entry;
   117 
   118     for (entry = SDL_loglevels; entry; entry = entry->next) {
   119         if (entry->category == category) {
   120             entry->priority = priority;
   121             return;
   122         }
   123     }
   124 
   125     /* Create a new entry */
   126     entry = (SDL_LogLevel *)SDL_malloc(sizeof(*entry));
   127     if (entry) {
   128         entry->category = category;
   129         entry->priority = priority;
   130         entry->next = SDL_loglevels;
   131         SDL_loglevels = entry;
   132     }
   133 }
   134 
   135 SDL_LogPriority
   136 SDL_LogGetPriority(int category)
   137 {
   138     SDL_LogLevel *entry;
   139 
   140     for (entry = SDL_loglevels; entry; entry = entry->next) {
   141         if (entry->category == category) {
   142             return entry->priority;
   143         }
   144     }
   145 
   146     if (category == SDL_LOG_CATEGORY_TEST) {
   147         return SDL_test_priority;
   148     } else if (category == SDL_LOG_CATEGORY_APPLICATION) {
   149         return SDL_application_priority;
   150     } else if (category == SDL_LOG_CATEGORY_ASSERT) {
   151         return SDL_assert_priority;
   152     } else {
   153         return SDL_default_priority;
   154     }
   155 }
   156 
   157 void
   158 SDL_LogResetPriorities(void)
   159 {
   160     SDL_LogLevel *entry;
   161 
   162     while (SDL_loglevels) {
   163         entry = SDL_loglevels;
   164         SDL_loglevels = entry->next;
   165         SDL_free(entry);
   166     }
   167 
   168     SDL_default_priority = DEFAULT_PRIORITY;
   169     SDL_assert_priority = DEFAULT_ASSERT_PRIORITY;
   170     SDL_application_priority = DEFAULT_APPLICATION_PRIORITY;
   171     SDL_test_priority = DEFAULT_TEST_PRIORITY;
   172 }
   173 
   174 void
   175 SDL_Log(const char *fmt, ...)
   176 {
   177     va_list ap;
   178 
   179     va_start(ap, fmt);
   180     SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap);
   181     va_end(ap);
   182 }
   183 
   184 void
   185 SDL_LogVerbose(int category, const char *fmt, ...)
   186 {
   187     va_list ap;
   188 
   189     va_start(ap, fmt);
   190     SDL_LogMessageV(category, SDL_LOG_PRIORITY_VERBOSE, fmt, ap);
   191     va_end(ap);
   192 }
   193 
   194 void
   195 SDL_LogDebug(int category, const char *fmt, ...)
   196 {
   197     va_list ap;
   198 
   199     va_start(ap, fmt);
   200     SDL_LogMessageV(category, SDL_LOG_PRIORITY_DEBUG, fmt, ap);
   201     va_end(ap);
   202 }
   203 
   204 void
   205 SDL_LogInfo(int category, const char *fmt, ...)
   206 {
   207     va_list ap;
   208 
   209     va_start(ap, fmt);
   210     SDL_LogMessageV(category, SDL_LOG_PRIORITY_INFO, fmt, ap);
   211     va_end(ap);
   212 }
   213 
   214 void
   215 SDL_LogWarn(int category, const char *fmt, ...)
   216 {
   217     va_list ap;
   218 
   219     va_start(ap, fmt);
   220     SDL_LogMessageV(category, SDL_LOG_PRIORITY_WARN, fmt, ap);
   221     va_end(ap);
   222 }
   223 
   224 void
   225 SDL_LogError(int category, const char *fmt, ...)
   226 {
   227     va_list ap;
   228 
   229     va_start(ap, fmt);
   230     SDL_LogMessageV(category, SDL_LOG_PRIORITY_ERROR, fmt, ap);
   231     va_end(ap);
   232 }
   233 
   234 void
   235 SDL_LogCritical(int category, const char *fmt, ...)
   236 {
   237     va_list ap;
   238 
   239     va_start(ap, fmt);
   240     SDL_LogMessageV(category, SDL_LOG_PRIORITY_CRITICAL, fmt, ap);
   241     va_end(ap);
   242 }
   243 
   244 void
   245 SDL_LogMessage(int category, SDL_LogPriority priority, const char *fmt, ...)
   246 {
   247     va_list ap;
   248 
   249     va_start(ap, fmt);
   250     SDL_LogMessageV(category, priority, fmt, ap);
   251     va_end(ap);
   252 }
   253 
   254 #ifdef __ANDROID__
   255 static const char *
   256 GetCategoryPrefix(int category)
   257 {
   258     if (category < SDL_LOG_CATEGORY_RESERVED1) {
   259         return SDL_category_prefixes[category];
   260     }
   261     if (category < SDL_LOG_CATEGORY_CUSTOM) {
   262         return "RESERVED";
   263     }
   264     return "CUSTOM";
   265 }
   266 #endif /* __ANDROID__ */
   267 
   268 void
   269 SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va_list ap)
   270 {
   271     char *message;
   272     size_t len;
   273 
   274     /* Nothing to do if we don't have an output function */
   275     if (!SDL_log_function) {
   276         return;
   277     }
   278 
   279     /* Make sure we don't exceed array bounds */
   280     if ((int)priority < 0 || priority >= SDL_NUM_LOG_PRIORITIES) {
   281         return;
   282     }
   283 
   284     /* See if we want to do anything with this message */
   285     if (priority < SDL_LogGetPriority(category)) {
   286         return;
   287     }
   288 
   289     message = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
   290     if (!message) {
   291         return;
   292     }
   293 
   294     SDL_vsnprintf(message, SDL_MAX_LOG_MESSAGE, fmt, ap);
   295 
   296     /* Chop off final endline. */
   297     len = SDL_strlen(message);
   298     if ((len > 0) && (message[len-1] == '\n')) {
   299         message[--len] = '\0';
   300         if ((len > 0) && (message[len-1] == '\r')) {  /* catch "\r\n", too. */
   301             message[--len] = '\0';
   302         }
   303     }
   304 
   305     SDL_log_function(SDL_log_userdata, category, priority, message);
   306     SDL_stack_free(message);
   307 }
   308 
   309 #if defined(__WIN32__)
   310 /* Flag tracking the attachment of the console: 0=unattached, 1=attached, -1=error */
   311 static int consoleAttached = 0;
   312 
   313 /* Handle to stderr output of console. */
   314 static HANDLE stderrHandle = NULL;
   315 #endif
   316 
   317 static void
   318 SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
   319               const char *message)
   320 {
   321 #if defined(__WIN32__)
   322     /* Way too many allocations here, urgh */
   323     /* Note: One can't call SDL_SetError here, since that function itself logs. */
   324     {
   325         char *output;
   326         size_t length;
   327         LPTSTR tstr;
   328         BOOL attachResult;
   329         DWORD attachError;
   330         unsigned long charsWritten; 
   331 
   332         /* Maybe attach console and get stderr handle */
   333         if (consoleAttached == 0) {
   334             attachResult = AttachConsole(ATTACH_PARENT_PROCESS);
   335             if (!attachResult) {
   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 */
   345                         consoleAttached = 1;
   346                     } else {
   347                         OutputDebugString(TEXT("Error attaching console\r\n"));
   348                         consoleAttached = -1;
   349                     }
   350                 } else {
   351                     /* Newly attached */
   352                     consoleAttached = 1;
   353                 }
   354 			
   355                 if (consoleAttached == 1) {
   356                         stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
   357                 }
   358         }
   359 
   360         length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1;
   361         output = SDL_stack_alloc(char, length);
   362         SDL_snprintf(output, length, "%s: %s\r\n", SDL_priority_prefixes[priority], message);
   363         tstr = WIN_UTF8ToString(output);
   364         
   365         /* Output to debugger */
   366         OutputDebugString(tstr);
   367        
   368         /* Screen output to stderr, if console was attached. */
   369         if (consoleAttached == 1) {
   370                 if (!WriteConsole(stderrHandle, tstr, lstrlen(tstr), &charsWritten, NULL)) {
   371                     OutputDebugString(TEXT("Error calling WriteConsole\r\n"));
   372                 }
   373                 if (charsWritten == ERROR_NOT_ENOUGH_MEMORY) {
   374                     OutputDebugString(TEXT("Insufficient heap memory to write message\r\n"));
   375                 }
   376         }
   377 
   378         SDL_free(tstr);
   379         SDL_stack_free(output);
   380     }
   381 #elif defined(__ANDROID__)
   382     {
   383         char tag[32];
   384 
   385         SDL_snprintf(tag, SDL_arraysize(tag), "SDL/%s", GetCategoryPrefix(category));
   386         __android_log_write(SDL_android_priority[priority], tag, message);
   387     }
   388 #elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA)
   389     /* Technically we don't need SDL_VIDEO_DRIVER_COCOA, but that's where this function is defined for now.
   390     */
   391     extern void SDL_NSLog(const char *text);
   392     {
   393         char *text;
   394 
   395         text = SDL_stack_alloc(char, SDL_MAX_LOG_MESSAGE);
   396         if (text) {
   397             SDL_snprintf(text, SDL_MAX_LOG_MESSAGE, "%s: %s", SDL_priority_prefixes[priority], message);
   398             SDL_NSLog(text);
   399             SDL_stack_free(text);
   400             return;
   401         }
   402     }
   403 #elif defined(__PSP__)
   404     {
   405         FILE*        pFile;
   406         pFile = fopen ("SDL_Log.txt", "a");
   407         fprintf(pFile, "%s: %s\n", SDL_priority_prefixes[priority], message);
   408         fclose (pFile);
   409     }
   410 #endif
   411 #if HAVE_STDIO_H
   412     fprintf(stderr, "%s: %s\n", SDL_priority_prefixes[priority], message);
   413 #endif
   414 }
   415 
   416 void
   417 SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata)
   418 {
   419     if (callback) {
   420         *callback = SDL_log_function;
   421     }
   422     if (userdata) {
   423         *userdata = SDL_log_userdata;
   424     }
   425 }
   426 
   427 void
   428 SDL_LogSetOutputFunction(SDL_LogOutputFunction callback, void *userdata)
   429 {
   430     SDL_log_function = callback;
   431     SDL_log_userdata = userdata;
   432 }
   433 
   434 /* vi: set ts=4 sw=4 expandtab: */