sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_log.c (13091B)


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