Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/SDL_log.c
9902 views
1
/*
2
Simple DirectMedia Layer
3
Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
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(SDL_PLATFORM_WINDOWS)
24
#include "core/windows/SDL_windows.h"
25
#endif
26
27
// Simple log messages in SDL
28
29
#include "SDL_log_c.h"
30
31
#ifdef HAVE_STDIO_H
32
#include <stdio.h>
33
#endif
34
35
#ifdef SDL_PLATFORM_ANDROID
36
#include <android/log.h>
37
#endif
38
39
#include "stdlib/SDL_vacopy.h"
40
41
// The size of the stack buffer to use for rendering log messages.
42
#define SDL_MAX_LOG_MESSAGE_STACK 256
43
44
#define DEFAULT_CATEGORY -1
45
46
typedef struct SDL_LogLevel
47
{
48
int category;
49
SDL_LogPriority priority;
50
struct SDL_LogLevel *next;
51
} SDL_LogLevel;
52
53
54
// The default log output function
55
static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority, const char *message);
56
57
static void CleanupLogPriorities(void);
58
static void CleanupLogPrefixes(void);
59
60
static SDL_InitState SDL_log_init;
61
static SDL_Mutex *SDL_log_lock;
62
static SDL_Mutex *SDL_log_function_lock;
63
static SDL_LogLevel *SDL_loglevels SDL_GUARDED_BY(SDL_log_lock);
64
static SDL_LogPriority SDL_log_priorities[SDL_LOG_CATEGORY_CUSTOM] SDL_GUARDED_BY(SDL_log_lock);
65
static SDL_LogPriority SDL_log_default_priority SDL_GUARDED_BY(SDL_log_lock);
66
static SDL_LogOutputFunction SDL_log_function SDL_GUARDED_BY(SDL_log_function_lock) = SDL_LogOutput;
67
static void *SDL_log_userdata SDL_GUARDED_BY(SDL_log_function_lock) = NULL;
68
69
#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
70
#pragma GCC diagnostic push
71
#pragma GCC diagnostic ignored "-Wunused-variable"
72
#endif
73
74
// If this list changes, update the documentation for SDL_HINT_LOGGING
75
static const char * const SDL_priority_names[] = {
76
NULL,
77
"TRACE",
78
"VERBOSE",
79
"DEBUG",
80
"INFO",
81
"WARN",
82
"ERROR",
83
"CRITICAL"
84
};
85
SDL_COMPILE_TIME_ASSERT(priority_names, SDL_arraysize(SDL_priority_names) == SDL_LOG_PRIORITY_COUNT);
86
87
// This is guarded by SDL_log_function_lock because it's the logging function that calls GetLogPriorityPrefix()
88
static char *SDL_priority_prefixes[SDL_LOG_PRIORITY_COUNT] SDL_GUARDED_BY(SDL_log_function_lock);
89
90
// If this list changes, update the documentation for SDL_HINT_LOGGING
91
static const char * const SDL_category_names[] = {
92
"APP",
93
"ERROR",
94
"ASSERT",
95
"SYSTEM",
96
"AUDIO",
97
"VIDEO",
98
"RENDER",
99
"INPUT",
100
"TEST",
101
"GPU"
102
};
103
SDL_COMPILE_TIME_ASSERT(category_names, SDL_arraysize(SDL_category_names) == SDL_LOG_CATEGORY_RESERVED2);
104
105
#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
106
#pragma GCC diagnostic pop
107
#endif
108
109
#ifdef SDL_PLATFORM_ANDROID
110
static int SDL_android_priority[] = {
111
ANDROID_LOG_UNKNOWN,
112
ANDROID_LOG_VERBOSE,
113
ANDROID_LOG_VERBOSE,
114
ANDROID_LOG_DEBUG,
115
ANDROID_LOG_INFO,
116
ANDROID_LOG_WARN,
117
ANDROID_LOG_ERROR,
118
ANDROID_LOG_FATAL
119
};
120
SDL_COMPILE_TIME_ASSERT(android_priority, SDL_arraysize(SDL_android_priority) == SDL_LOG_PRIORITY_COUNT);
121
#endif // SDL_PLATFORM_ANDROID
122
123
static void SDLCALL SDL_LoggingChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
124
{
125
SDL_ResetLogPriorities();
126
}
127
128
void SDL_InitLog(void)
129
{
130
if (!SDL_ShouldInit(&SDL_log_init)) {
131
return;
132
}
133
134
// If these fail we'll continue without them.
135
SDL_log_lock = SDL_CreateMutex();
136
SDL_log_function_lock = SDL_CreateMutex();
137
138
SDL_AddHintCallback(SDL_HINT_LOGGING, SDL_LoggingChanged, NULL);
139
140
SDL_SetInitialized(&SDL_log_init, true);
141
}
142
143
void SDL_QuitLog(void)
144
{
145
if (!SDL_ShouldQuit(&SDL_log_init)) {
146
return;
147
}
148
149
SDL_RemoveHintCallback(SDL_HINT_LOGGING, SDL_LoggingChanged, NULL);
150
151
CleanupLogPriorities();
152
CleanupLogPrefixes();
153
154
if (SDL_log_lock) {
155
SDL_DestroyMutex(SDL_log_lock);
156
SDL_log_lock = NULL;
157
}
158
if (SDL_log_function_lock) {
159
SDL_DestroyMutex(SDL_log_function_lock);
160
SDL_log_function_lock = NULL;
161
}
162
163
SDL_SetInitialized(&SDL_log_init, false);
164
}
165
166
static void SDL_CheckInitLog(void)
167
{
168
int status = SDL_GetAtomicInt(&SDL_log_init.status);
169
if (status == SDL_INIT_STATUS_INITIALIZED ||
170
(status == SDL_INIT_STATUS_INITIALIZING && SDL_log_init.thread == SDL_GetCurrentThreadID())) {
171
return;
172
}
173
174
SDL_InitLog();
175
}
176
177
static void CleanupLogPriorities(void)
178
{
179
while (SDL_loglevels) {
180
SDL_LogLevel *entry = SDL_loglevels;
181
SDL_loglevels = entry->next;
182
SDL_free(entry);
183
}
184
}
185
186
void SDL_SetLogPriorities(SDL_LogPriority priority)
187
{
188
SDL_CheckInitLog();
189
190
SDL_LockMutex(SDL_log_lock);
191
{
192
CleanupLogPriorities();
193
194
SDL_log_default_priority = priority;
195
for (int i = 0; i < SDL_arraysize(SDL_log_priorities); ++i) {
196
SDL_log_priorities[i] = priority;
197
}
198
}
199
SDL_UnlockMutex(SDL_log_lock);
200
}
201
202
void SDL_SetLogPriority(int category, SDL_LogPriority priority)
203
{
204
SDL_LogLevel *entry;
205
206
SDL_CheckInitLog();
207
208
SDL_LockMutex(SDL_log_lock);
209
{
210
if (category >= 0 && category < SDL_arraysize(SDL_log_priorities)) {
211
SDL_log_priorities[category] = priority;
212
} else {
213
for (entry = SDL_loglevels; entry; entry = entry->next) {
214
if (entry->category == category) {
215
entry->priority = priority;
216
break;
217
}
218
}
219
220
if (!entry) {
221
entry = (SDL_LogLevel *)SDL_malloc(sizeof(*entry));
222
if (entry) {
223
entry->category = category;
224
entry->priority = priority;
225
entry->next = SDL_loglevels;
226
SDL_loglevels = entry;
227
}
228
}
229
}
230
}
231
SDL_UnlockMutex(SDL_log_lock);
232
}
233
234
SDL_LogPriority SDL_GetLogPriority(int category)
235
{
236
SDL_LogLevel *entry;
237
SDL_LogPriority priority = SDL_LOG_PRIORITY_INVALID;
238
239
SDL_CheckInitLog();
240
241
// Bypass the lock for known categories
242
// Technically if the priority was set on a different CPU the value might not
243
// be visible on this CPU for a while, but in practice it's fast enough that
244
// this performance improvement is worthwhile.
245
if (category >= 0 && category < SDL_arraysize(SDL_log_priorities)) {
246
return SDL_log_priorities[category];
247
}
248
249
SDL_LockMutex(SDL_log_lock);
250
{
251
if (category >= 0 && category < SDL_arraysize(SDL_log_priorities)) {
252
priority = SDL_log_priorities[category];
253
} else {
254
for (entry = SDL_loglevels; entry; entry = entry->next) {
255
if (entry->category == category) {
256
priority = entry->priority;
257
break;
258
}
259
}
260
if (priority == SDL_LOG_PRIORITY_INVALID) {
261
priority = SDL_log_default_priority;
262
}
263
}
264
}
265
SDL_UnlockMutex(SDL_log_lock);
266
267
return priority;
268
}
269
270
static bool ParseLogCategory(const char *string, size_t length, int *category)
271
{
272
int i;
273
274
if (SDL_isdigit(*string)) {
275
*category = SDL_atoi(string);
276
return true;
277
}
278
279
if (*string == '*') {
280
*category = DEFAULT_CATEGORY;
281
return true;
282
}
283
284
for (i = 0; i < SDL_arraysize(SDL_category_names); ++i) {
285
if (SDL_strncasecmp(string, SDL_category_names[i], length) == 0) {
286
*category = i;
287
return true;
288
}
289
}
290
return false;
291
}
292
293
static bool ParseLogPriority(const char *string, size_t length, SDL_LogPriority *priority)
294
{
295
int i;
296
297
if (SDL_isdigit(*string)) {
298
i = SDL_atoi(string);
299
if (i == 0) {
300
// 0 has a special meaning of "disable this category"
301
*priority = SDL_LOG_PRIORITY_COUNT;
302
return true;
303
}
304
if (i > SDL_LOG_PRIORITY_INVALID && i < SDL_LOG_PRIORITY_COUNT) {
305
*priority = (SDL_LogPriority)i;
306
return true;
307
}
308
return false;
309
}
310
311
if (SDL_strncasecmp(string, "quiet", length) == 0) {
312
*priority = SDL_LOG_PRIORITY_COUNT;
313
return true;
314
}
315
316
for (i = SDL_LOG_PRIORITY_INVALID + 1; i < SDL_LOG_PRIORITY_COUNT; ++i) {
317
if (SDL_strncasecmp(string, SDL_priority_names[i], length) == 0) {
318
*priority = (SDL_LogPriority)i;
319
return true;
320
}
321
}
322
return false;
323
}
324
325
static void ParseLogPriorities(const char *hint)
326
{
327
const char *name, *next;
328
int category = DEFAULT_CATEGORY;
329
SDL_LogPriority priority = SDL_LOG_PRIORITY_INVALID;
330
331
if (SDL_strchr(hint, '=') == NULL) {
332
if (ParseLogPriority(hint, SDL_strlen(hint), &priority)) {
333
SDL_SetLogPriorities(priority);
334
}
335
return;
336
}
337
338
for (name = hint; name; name = next) {
339
const char *sep = SDL_strchr(name, '=');
340
if (!sep) {
341
break;
342
}
343
next = SDL_strchr(sep, ',');
344
if (next) {
345
++next;
346
}
347
348
if (ParseLogCategory(name, (sep - name), &category)) {
349
const char *value = sep + 1;
350
size_t len;
351
if (next) {
352
len = (next - value - 1);
353
} else {
354
len = SDL_strlen(value);
355
}
356
if (ParseLogPriority(value, len, &priority)) {
357
if (category == DEFAULT_CATEGORY) {
358
for (int i = 0; i < SDL_arraysize(SDL_log_priorities); ++i) {
359
if (SDL_log_priorities[i] == SDL_LOG_PRIORITY_INVALID) {
360
SDL_log_priorities[i] = priority;
361
}
362
}
363
SDL_log_default_priority = priority;
364
} else {
365
SDL_SetLogPriority(category, priority);
366
}
367
}
368
}
369
}
370
}
371
372
void SDL_ResetLogPriorities(void)
373
{
374
SDL_CheckInitLog();
375
376
SDL_LockMutex(SDL_log_lock);
377
{
378
CleanupLogPriorities();
379
380
SDL_log_default_priority = SDL_LOG_PRIORITY_INVALID;
381
for (int i = 0; i < SDL_arraysize(SDL_log_priorities); ++i) {
382
SDL_log_priorities[i] = SDL_LOG_PRIORITY_INVALID;
383
}
384
385
const char *hint = SDL_GetHint(SDL_HINT_LOGGING);
386
if (hint) {
387
ParseLogPriorities(hint);
388
}
389
390
if (SDL_log_default_priority == SDL_LOG_PRIORITY_INVALID) {
391
SDL_log_default_priority = SDL_LOG_PRIORITY_ERROR;
392
}
393
for (int i = 0; i < SDL_arraysize(SDL_log_priorities); ++i) {
394
if (SDL_log_priorities[i] != SDL_LOG_PRIORITY_INVALID) {
395
continue;
396
}
397
398
switch (i) {
399
case SDL_LOG_CATEGORY_APPLICATION:
400
SDL_log_priorities[i] = SDL_LOG_PRIORITY_INFO;
401
break;
402
case SDL_LOG_CATEGORY_ASSERT:
403
SDL_log_priorities[i] = SDL_LOG_PRIORITY_WARN;
404
break;
405
case SDL_LOG_CATEGORY_TEST:
406
SDL_log_priorities[i] = SDL_LOG_PRIORITY_VERBOSE;
407
break;
408
default:
409
SDL_log_priorities[i] = SDL_LOG_PRIORITY_ERROR;
410
break;
411
}
412
}
413
}
414
SDL_UnlockMutex(SDL_log_lock);
415
}
416
417
static void CleanupLogPrefixes(void)
418
{
419
for (int i = 0; i < SDL_arraysize(SDL_priority_prefixes); ++i) {
420
if (SDL_priority_prefixes[i]) {
421
SDL_free(SDL_priority_prefixes[i]);
422
SDL_priority_prefixes[i] = NULL;
423
}
424
}
425
}
426
427
static const char *GetLogPriorityPrefix(SDL_LogPriority priority)
428
{
429
if (priority <= SDL_LOG_PRIORITY_INVALID || priority >= SDL_LOG_PRIORITY_COUNT) {
430
return "";
431
}
432
433
if (SDL_priority_prefixes[priority]) {
434
return SDL_priority_prefixes[priority];
435
}
436
437
switch (priority) {
438
case SDL_LOG_PRIORITY_WARN:
439
return "WARNING: ";
440
case SDL_LOG_PRIORITY_ERROR:
441
return "ERROR: ";
442
case SDL_LOG_PRIORITY_CRITICAL:
443
return "ERROR: ";
444
default:
445
return "";
446
}
447
}
448
449
bool SDL_SetLogPriorityPrefix(SDL_LogPriority priority, const char *prefix)
450
{
451
char *prefix_copy;
452
453
if (priority <= SDL_LOG_PRIORITY_INVALID || priority >= SDL_LOG_PRIORITY_COUNT) {
454
return SDL_InvalidParamError("priority");
455
}
456
457
if (!prefix || !*prefix) {
458
prefix_copy = SDL_strdup("");
459
} else {
460
prefix_copy = SDL_strdup(prefix);
461
}
462
if (!prefix_copy) {
463
return false;
464
}
465
466
SDL_LockMutex(SDL_log_function_lock);
467
{
468
if (SDL_priority_prefixes[priority]) {
469
SDL_free(SDL_priority_prefixes[priority]);
470
}
471
SDL_priority_prefixes[priority] = prefix_copy;
472
}
473
SDL_UnlockMutex(SDL_log_function_lock);
474
475
return true;
476
}
477
478
void SDL_Log(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
479
{
480
va_list ap;
481
482
va_start(ap, fmt);
483
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, ap);
484
va_end(ap);
485
}
486
487
void SDL_LogTrace(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
488
{
489
va_list ap;
490
491
va_start(ap, fmt);
492
SDL_LogMessageV(category, SDL_LOG_PRIORITY_TRACE, fmt, ap);
493
va_end(ap);
494
}
495
496
void SDL_LogVerbose(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
497
{
498
va_list ap;
499
500
va_start(ap, fmt);
501
SDL_LogMessageV(category, SDL_LOG_PRIORITY_VERBOSE, fmt, ap);
502
va_end(ap);
503
}
504
505
void SDL_LogDebug(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
506
{
507
va_list ap;
508
509
va_start(ap, fmt);
510
SDL_LogMessageV(category, SDL_LOG_PRIORITY_DEBUG, fmt, ap);
511
va_end(ap);
512
}
513
514
void SDL_LogInfo(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
515
{
516
va_list ap;
517
518
va_start(ap, fmt);
519
SDL_LogMessageV(category, SDL_LOG_PRIORITY_INFO, fmt, ap);
520
va_end(ap);
521
}
522
523
void SDL_LogWarn(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
524
{
525
va_list ap;
526
527
va_start(ap, fmt);
528
SDL_LogMessageV(category, SDL_LOG_PRIORITY_WARN, fmt, ap);
529
va_end(ap);
530
}
531
532
void SDL_LogError(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
533
{
534
va_list ap;
535
536
va_start(ap, fmt);
537
SDL_LogMessageV(category, SDL_LOG_PRIORITY_ERROR, fmt, ap);
538
va_end(ap);
539
}
540
541
void SDL_LogCritical(int category, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
542
{
543
va_list ap;
544
545
va_start(ap, fmt);
546
SDL_LogMessageV(category, SDL_LOG_PRIORITY_CRITICAL, fmt, ap);
547
va_end(ap);
548
}
549
550
void SDL_LogMessage(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
551
{
552
va_list ap;
553
554
va_start(ap, fmt);
555
SDL_LogMessageV(category, priority, fmt, ap);
556
va_end(ap);
557
}
558
559
#ifdef SDL_PLATFORM_ANDROID
560
static const char *GetCategoryPrefix(int category)
561
{
562
if (category < SDL_LOG_CATEGORY_RESERVED2) {
563
return SDL_category_names[category];
564
}
565
if (category < SDL_LOG_CATEGORY_CUSTOM) {
566
return "RESERVED";
567
}
568
return "CUSTOM";
569
}
570
#endif // SDL_PLATFORM_ANDROID
571
572
void SDL_LogMessageV(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap)
573
{
574
char *message = NULL;
575
char stack_buf[SDL_MAX_LOG_MESSAGE_STACK];
576
size_t len_plus_term;
577
int len;
578
va_list aq;
579
580
// Nothing to do if we don't have an output function
581
if (!SDL_log_function) {
582
return;
583
}
584
585
// See if we want to do anything with this message
586
if (priority < SDL_GetLogPriority(category)) {
587
return;
588
}
589
590
// Render into stack buffer
591
va_copy(aq, ap);
592
len = SDL_vsnprintf(stack_buf, sizeof(stack_buf), fmt, aq);
593
va_end(aq);
594
595
if (len < 0) {
596
return;
597
}
598
599
// If message truncated, allocate and re-render
600
if (len >= sizeof(stack_buf) && SDL_size_add_check_overflow(len, 1, &len_plus_term)) {
601
// Allocate exactly what we need, including the zero-terminator
602
message = (char *)SDL_malloc(len_plus_term);
603
if (!message) {
604
return;
605
}
606
va_copy(aq, ap);
607
len = SDL_vsnprintf(message, len_plus_term, fmt, aq);
608
va_end(aq);
609
} else {
610
message = stack_buf;
611
}
612
613
// Chop off final endline.
614
if ((len > 0) && (message[len - 1] == '\n')) {
615
message[--len] = '\0';
616
if ((len > 0) && (message[len - 1] == '\r')) { // catch "\r\n", too.
617
message[--len] = '\0';
618
}
619
}
620
621
SDL_LockMutex(SDL_log_function_lock);
622
{
623
SDL_log_function(SDL_log_userdata, category, priority, message);
624
}
625
SDL_UnlockMutex(SDL_log_function_lock);
626
627
// Free only if dynamically allocated
628
if (message != stack_buf) {
629
SDL_free(message);
630
}
631
}
632
633
#if defined(SDL_PLATFORM_WIN32) && !defined(SDL_PLATFORM_GDK)
634
enum {
635
CONSOLE_UNATTACHED = 0,
636
CONSOLE_ATTACHED_CONSOLE = 1,
637
CONSOLE_ATTACHED_FILE = 2,
638
CONSOLE_ATTACHED_ERROR = -1,
639
} consoleAttached = CONSOLE_UNATTACHED;
640
641
// Handle to stderr output of console.
642
static HANDLE stderrHandle = NULL;
643
#endif
644
645
static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
646
const char *message)
647
{
648
#if defined(SDL_PLATFORM_WINDOWS)
649
// Way too many allocations here, urgh
650
// Note: One can't call SDL_SetError here, since that function itself logs.
651
{
652
char *output;
653
size_t length;
654
LPTSTR tstr;
655
bool isstack;
656
657
#if !defined(SDL_PLATFORM_GDK)
658
BOOL attachResult;
659
DWORD attachError;
660
DWORD consoleMode;
661
DWORD charsWritten;
662
663
// Maybe attach console and get stderr handle
664
if (consoleAttached == CONSOLE_UNATTACHED) {
665
attachResult = AttachConsole(ATTACH_PARENT_PROCESS);
666
if (!attachResult) {
667
attachError = GetLastError();
668
if (attachError == ERROR_INVALID_HANDLE) {
669
// This is expected when running from Visual Studio
670
// OutputDebugString(TEXT("Parent process has no console\r\n"));
671
consoleAttached = CONSOLE_ATTACHED_ERROR;
672
} else if (attachError == ERROR_GEN_FAILURE) {
673
OutputDebugString(TEXT("Could not attach to console of parent process\r\n"));
674
consoleAttached = CONSOLE_ATTACHED_ERROR;
675
} else if (attachError == ERROR_ACCESS_DENIED) {
676
// Already attached
677
consoleAttached = CONSOLE_ATTACHED_CONSOLE;
678
} else {
679
OutputDebugString(TEXT("Error attaching console\r\n"));
680
consoleAttached = CONSOLE_ATTACHED_ERROR;
681
}
682
} else {
683
// Newly attached
684
consoleAttached = CONSOLE_ATTACHED_CONSOLE;
685
}
686
687
if (consoleAttached == CONSOLE_ATTACHED_CONSOLE) {
688
stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
689
690
if (GetConsoleMode(stderrHandle, &consoleMode) == 0) {
691
// WriteConsole fails if the output is redirected to a file. Must use WriteFile instead.
692
consoleAttached = CONSOLE_ATTACHED_FILE;
693
}
694
}
695
}
696
#endif // !defined(SDL_PLATFORM_GDK)
697
length = SDL_strlen(GetLogPriorityPrefix(priority)) + SDL_strlen(message) + 1 + 1 + 1;
698
output = SDL_small_alloc(char, length, &isstack);
699
if (!output) {
700
return;
701
}
702
(void)SDL_snprintf(output, length, "%s%s\r\n", GetLogPriorityPrefix(priority), message);
703
tstr = WIN_UTF8ToString(output);
704
705
// Output to debugger
706
OutputDebugString(tstr);
707
708
#if !defined(SDL_PLATFORM_GDK)
709
// Screen output to stderr, if console was attached.
710
if (consoleAttached == CONSOLE_ATTACHED_CONSOLE) {
711
if (!WriteConsole(stderrHandle, tstr, (DWORD)SDL_tcslen(tstr), &charsWritten, NULL)) {
712
OutputDebugString(TEXT("Error calling WriteConsole\r\n"));
713
if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
714
OutputDebugString(TEXT("Insufficient heap memory to write message\r\n"));
715
}
716
}
717
718
} else if (consoleAttached == CONSOLE_ATTACHED_FILE) {
719
if (!WriteFile(stderrHandle, output, (DWORD)SDL_strlen(output), &charsWritten, NULL)) {
720
OutputDebugString(TEXT("Error calling WriteFile\r\n"));
721
}
722
}
723
#endif // !defined(SDL_PLATFORM_GDK)
724
725
SDL_free(tstr);
726
SDL_small_free(output, isstack);
727
}
728
#elif defined(SDL_PLATFORM_ANDROID)
729
{
730
char tag[32];
731
732
SDL_snprintf(tag, SDL_arraysize(tag), "SDL/%s", GetCategoryPrefix(category));
733
__android_log_write(SDL_android_priority[priority], tag, message);
734
}
735
#elif defined(SDL_PLATFORM_APPLE) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT))
736
/* Technically we don't need Cocoa/UIKit, but that's where this function is defined for now.
737
*/
738
extern void SDL_NSLog(const char *prefix, const char *text);
739
{
740
SDL_NSLog(GetLogPriorityPrefix(priority), message);
741
return;
742
}
743
#elif defined(SDL_PLATFORM_PSP) || defined(SDL_PLATFORM_PS2)
744
{
745
FILE *pFile;
746
pFile = fopen("SDL_Log.txt", "a");
747
if (pFile) {
748
(void)fprintf(pFile, "%s%s\n", GetLogPriorityPrefix(priority), message);
749
(void)fclose(pFile);
750
}
751
}
752
#elif defined(SDL_PLATFORM_VITA)
753
{
754
FILE *pFile;
755
pFile = fopen("ux0:/data/SDL_Log.txt", "a");
756
if (pFile) {
757
(void)fprintf(pFile, "%s%s\n", GetLogPriorityPrefix(priority), message);
758
(void)fclose(pFile);
759
}
760
}
761
#elif defined(SDL_PLATFORM_3DS)
762
{
763
FILE *pFile;
764
pFile = fopen("sdmc:/3ds/SDL_Log.txt", "a");
765
if (pFile) {
766
(void)fprintf(pFile, "%s%s\n", GetLogPriorityPrefix(priority), message);
767
(void)fclose(pFile);
768
}
769
}
770
#endif
771
#if defined(HAVE_STDIO_H) && \
772
!(defined(SDL_PLATFORM_APPLE) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT))) && \
773
!(defined(SDL_PLATFORM_WIN32))
774
(void)fprintf(stderr, "%s%s\n", GetLogPriorityPrefix(priority), message);
775
#endif
776
}
777
778
SDL_LogOutputFunction SDL_GetDefaultLogOutputFunction(void)
779
{
780
return SDL_LogOutput;
781
}
782
783
void SDL_GetLogOutputFunction(SDL_LogOutputFunction *callback, void **userdata)
784
{
785
SDL_LockMutex(SDL_log_function_lock);
786
{
787
if (callback) {
788
*callback = SDL_log_function;
789
}
790
if (userdata) {
791
*userdata = SDL_log_userdata;
792
}
793
}
794
SDL_UnlockMutex(SDL_log_function_lock);
795
}
796
797
void SDL_SetLogOutputFunction(SDL_LogOutputFunction callback, void *userdata)
798
{
799
SDL_LockMutex(SDL_log_function_lock);
800
{
801
SDL_log_function = callback;
802
SDL_log_userdata = userdata;
803
}
804
SDL_UnlockMutex(SDL_log_function_lock);
805
}
806
807