SDL  2.0
SDL_log.c
Go to the documentation of this file.
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__)
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;
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 
61 static void *SDL_log_userdata = NULL;
62 
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
98 {
99  SDL_LogLevel *entry;
100 
101  for (entry = SDL_loglevels; entry; entry = entry->next) {
102  entry->priority = priority;
103  }
107 }
108 
109 void
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 
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 
143  return SDL_test_priority;
144  } else if (category == SDL_LOG_CATEGORY_APPLICATION) {
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
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 
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);
177  va_end(ap);
178 }
179 
180 void
182 {
183  va_list ap;
184 
185  va_start(ap, fmt);
187  va_end(ap);
188 }
189 
190 void
192 {
193  va_list ap;
194 
195  va_start(ap, fmt);
197  va_end(ap);
198 }
199 
200 void
202 {
203  va_list ap;
204 
205  va_start(ap, fmt);
207  va_end(ap);
208 }
209 
210 void
212 {
213  va_list ap;
214 
215  va_start(ap, fmt);
217  va_end(ap);
218 }
219 
220 void
222 {
223  va_list ap;
224 
225  va_start(ap, fmt);
227  va_end(ap);
228 }
229 
230 void
232 {
233  va_list ap;
234 
235  va_start(ap, fmt);
237  va_end(ap);
238 }
239 
240 void
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 {
255  return SDL_category_prefixes[category];
256  }
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 */
282  return;
283  }
284 
285  /* !!! FIXME: why not just "char message[SDL_MAX_LOG_MESSAGE];" ? */
287  if (!message) {
288  return;
289  }
290 
292 
293  /* Chop off final endline. */
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 
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
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 
369  output = SDL_small_alloc(char, length, &isstack);
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];" ? */
411  if (text) {
413  SDL_NSLog(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
436 {
437  if (callback) {
439  }
440  if (userdata) {
441  *userdata = SDL_log_userdata;
442  }
443 }
444 
445 void
447 {
449  SDL_log_userdata = userdata;
450 }
451 
452 /* vi: set ts=4 sw=4 expandtab: */
SDL_LogSetAllPriority
void SDL_LogSetAllPriority(SDL_LogPriority priority)
Set the priority of all log categories.
Definition: SDL_log.c:97
SDL_small_free
#define SDL_small_free(ptr, isstack)
Definition: SDL_internal.h:40
WIN_UTF8ToString
#define WIN_UTF8ToString(S)
Definition: SDL_windows.h:47
SDL_PRINTF_FORMAT_STRING
#define SDL_PRINTF_FORMAT_STRING
Definition: SDL_stdinc.h:300
SDL_LOG_PRIORITY_CRITICAL
@ SDL_LOG_PRIORITY_CRITICAL
Definition: SDL_log.h:109
DEFAULT_APPLICATION_PRIORITY
#define DEFAULT_APPLICATION_PRIORITY
Definition: SDL_log.c:42
SDL_LOG_CATEGORY_CUSTOM
@ SDL_LOG_CATEGORY_CUSTOM
Definition: SDL_log.h:96
DEFAULT_ASSERT_PRIORITY
#define DEFAULT_ASSERT_PRIORITY
Definition: SDL_log.c:41
NULL
#define NULL
Definition: begin_code.h:167
message
GLuint GLsizei const GLchar * message
Definition: SDL_opengl_glext.h:2486
SDL_LogGetPriority
SDL_LogPriority SDL_LogGetPriority(int category)
Get the priority of a particular log category.
Definition: SDL_log.c:132
SDL_error.h
SDL_application_priority
static SDL_LogPriority SDL_application_priority
Definition: SDL_log.c:58
SDL_log.h
SDL_LogLevel::priority
SDL_LogPriority priority
Definition: SDL_log.c:48
DEFAULT_PRIORITY
#define DEFAULT_PRIORITY
Definition: SDL_log.c:40
SDLCALL
#define SDLCALL
Definition: SDL_internal.h:49
callback
static Uint32 callback(Uint32 interval, void *param)
Definition: testtimer.c:34
SDL_LOG_PRIORITY_DEBUG
@ SDL_LOG_PRIORITY_DEBUG
Definition: SDL_log.h:105
SDL_LOG_PRIORITY_WARN
@ SDL_LOG_PRIORITY_WARN
Definition: SDL_log.h:107
SDL_small_alloc
#define SDL_small_alloc(type, count, pisstack)
Definition: SDL_internal.h:39
length
GLuint GLsizei GLsizei * length
Definition: SDL_opengl_glext.h:672
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:265
SDL_stack_alloc
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:354
SDL_NUM_LOG_PRIORITIES
@ SDL_NUM_LOG_PRIORITIES
Definition: SDL_log.h:110
SDL_LOG_CATEGORY_TEST
@ SDL_LOG_CATEGORY_TEST
Definition: SDL_log.h:74
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:241
SDL_LOG_CATEGORY_ASSERT
@ SDL_LOG_CATEGORY_ASSERT
Definition: SDL_log.h:68
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
len
GLenum GLsizei len
Definition: SDL_opengl_glext.h:2929
SDL_LogResetPriorities
void SDL_LogResetPriorities(void)
Reset all priorities to default.
Definition: SDL_log.c:154
SDL_LogLevel::next
struct SDL_LogLevel * next
Definition: SDL_log.c:49
DEFAULT_TEST_PRIORITY
#define DEFAULT_TEST_PRIORITY
Definition: SDL_log.c:43
SDL_LogOutput
static void SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority, const char *message)
Definition: SDL_log.c:315
SDL_internal.h
SDL_LogLevel
Definition: SDL_log.c:45
SDL_LOG_CATEGORY_APPLICATION
@ SDL_LOG_CATEGORY_APPLICATION
Definition: SDL_log.h:66
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
SDL_vsnprintf
#define SDL_vsnprintf
Definition: SDL_dynapi_overrides.h:421
SDL_priority_prefixes
static const char * SDL_priority_prefixes[SDL_NUM_LOG_PRIORITIES]
Definition: SDL_log.c:63
text
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:47
SDL_LOG_PRIORITY_ERROR
@ SDL_LOG_PRIORITY_ERROR
Definition: SDL_log.h:108
SDL_assert_priority
static SDL_LogPriority SDL_assert_priority
Definition: SDL_log.c:57
SDL_LogGetOutputFunction
void SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata)
Get the current log output function.
Definition: SDL_log.c:435
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:201
SDL_loglevels
static SDL_LogLevel * SDL_loglevels
Definition: SDL_log.c:55
SDL_default_priority
static SDL_LogPriority SDL_default_priority
Definition: SDL_log.c:56
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:181
SDL_arraysize
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
SDL_LOG_PRIORITY_INFO
@ SDL_LOG_PRIORITY_INFO
Definition: SDL_log.h:106
SDL_stack_free
#define SDL_stack_free(data)
Definition: SDL_stdinc.h:355
sort_controllers.output
output
Definition: sort_controllers.py:10
SDL_snprintf
#define SDL_snprintf
Definition: SDL_dynapi_overrides.h:40
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:191
SDL_log_userdata
static void * SDL_log_userdata
Definition: SDL_log.c:61
SDL_LOG_PRIORITY_VERBOSE
@ SDL_LOG_PRIORITY_VERBOSE
Definition: SDL_log.h:104
SDL_log_function
static SDL_LogOutputFunction SDL_log_function
Definition: SDL_log.c:60
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:221
SDL_LogLevel::category
int category
Definition: SDL_log.c:47
SDL_strlen
#define SDL_strlen
Definition: SDL_dynapi_overrides.h:393
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:446
SDL_LOG_CATEGORY_RESERVED1
@ SDL_LOG_CATEGORY_RESERVED1
Definition: SDL_log.h:77
SDL_windows.h
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:374
SDL_test_priority
static SDL_LogPriority SDL_test_priority
Definition: SDL_log.c:59
SDL_MAX_LOG_MESSAGE
#define SDL_MAX_LOG_MESSAGE
The maximum size of a log message.
Definition: SDL_log.h:54
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:211
SDL_LogPriority
SDL_LogPriority
The predefined log priorities.
Definition: SDL_log.h:102
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:231
SDL_LogSetPriority
void SDL_LogSetPriority(int category, SDL_LogPriority priority)
Set the priority of a particular log category.
Definition: SDL_log.c:110
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:161
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:171