SDL  2.0
SDL_error.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 /* Simple error handling in SDL */
24 
25 #include "SDL_log.h"
26 #include "SDL_error.h"
27 #include "SDL_error_c.h"
28 
29 
30 /* Routine to get the thread-specific error variable */
31 #if SDL_THREADS_DISABLED
32 /* The default (non-thread-safe) global error variable */
33 static SDL_error SDL_global_error;
34 #define SDL_GetErrBuf() (&SDL_global_error)
35 #else
36 extern SDL_error *SDL_GetErrBuf(void);
37 #endif /* SDL_THREADS_DISABLED */
38 
39 #define SDL_ERRBUFIZE 1024
40 
41 /* Private functions */
42 
43 static const char *
44 SDL_LookupString(const char *key)
45 {
46  /* FIXME: Add code to lookup key in language string hash-table */
47  return key;
48 }
49 
50 /* Public functions */
51 
52 static char *SDL_GetErrorMsg(char *errstr, int maxlen);
53 
54 int
56 {
57  va_list ap;
58  SDL_error *error;
59 
60  /* Ignore call if invalid format pointer was passed */
61  if (fmt == NULL) return -1;
62 
63  /* Copy in the key, mark error as valid */
64  error = SDL_GetErrBuf();
65  error->error = 1;
66  SDL_strlcpy((char *) error->key, fmt, sizeof(error->key));
67 
68  va_start(ap, fmt);
69  error->argc = 0;
70  while (*fmt) {
71  if (*fmt++ == '%') {
72  while (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) {
73  ++fmt;
74  }
75  switch (*fmt++) {
76  case 0: /* Malformed format string.. */
77  --fmt;
78  break;
79  case 'l':
80  switch (*fmt++) {
81  case 0: /* Malformed format string.. */
82  --fmt;
83  break;
84  case 'i': case 'd': case 'u':
85  error->args[error->argc++].value_l = va_arg(ap, long);
86  break;
87  }
88  break;
89  case 'c':
90  case 'i':
91  case 'd':
92  case 'u':
93  case 'o':
94  case 'x':
95  case 'X':
96  error->args[error->argc++].value_i = va_arg(ap, int);
97  break;
98  case 'f':
99  error->args[error->argc++].value_f = va_arg(ap, double);
100  break;
101  case 'p':
102  error->args[error->argc++].value_ptr = va_arg(ap, void *);
103  break;
104  case 's':
105  {
106  int i = error->argc;
107  const char *str = va_arg(ap, const char *);
108  if (str == NULL)
109  str = "(null)";
110  SDL_strlcpy((char *) error->args[i].buf, str,
112  error->argc++;
113  }
114  break;
115  default:
116  break;
117  }
118  if (error->argc >= ERR_MAX_ARGS) {
119  break;
120  }
121  }
122  }
123  va_end(ap);
124 
126  /* If we are in debug mode, print out an error message
127  * Avoid stomping on the static buffer in GetError, just
128  * in case this is called while processing a ShowMessageBox to
129  * show an error already in that static buffer.
130  */
131  char errmsg[SDL_ERRBUFIZE];
132  SDL_GetErrorMsg(errmsg, sizeof(errmsg));
133  SDL_LogDebug(SDL_LOG_CATEGORY_ERROR, "%s", errmsg);
134  }
135  return -1;
136 }
137 
138 /* Available for backwards compatibility */
139 const char *
141 {
142  static char errmsg[SDL_ERRBUFIZE];
143 
144  return SDL_GetErrorMsg(errmsg, SDL_ERRBUFIZE);
145 }
146 
147 void
149 {
150  SDL_error *error;
151 
152  error = SDL_GetErrBuf();
153  error->error = 0;
154 }
155 
156 /* Very common errors go here */
157 int
159 {
160  switch (code) {
161  case SDL_ENOMEM:
162  return SDL_SetError("Out of memory");
163  case SDL_EFREAD:
164  return SDL_SetError("Error reading from datastream");
165  case SDL_EFWRITE:
166  return SDL_SetError("Error writing to datastream");
167  case SDL_EFSEEK:
168  return SDL_SetError("Error seeking in datastream");
169  case SDL_UNSUPPORTED:
170  return SDL_SetError("That operation is not supported");
171  default:
172  return SDL_SetError("Unknown SDL error");
173  }
174 }
175 
176 #ifdef TEST_ERROR
177 int
178 main(int argc, char *argv[])
179 {
180  char buffer[BUFSIZ + 1];
181 
182  SDL_SetError("Hi there!");
183  printf("Error 1: %s\n", SDL_GetError());
184  SDL_ClearError();
185  SDL_memset(buffer, '1', BUFSIZ);
186  buffer[BUFSIZ] = 0;
187  SDL_SetError("This is the error: %s (%f)", buffer, 1.0);
188  printf("Error 2: %s\n", SDL_GetError());
189  exit(0);
190 }
191 #endif
192 
193 
194 /* keep this at the end of the file so it works with GCC builds that don't
195  support "#pragma GCC diagnostic push" ... we'll just leave the warning
196  disabled after this. */
197 /* this pragma arrived in GCC 4.2 and causes a warning on older GCCs! Sigh. */
198 #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 2))))
199 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
200 #endif
201 
202 /* This function has a bit more overhead than most error functions
203  so that it supports internationalization and thread-safe errors.
204 */
205 static char *
206 SDL_GetErrorMsg(char *errstr, int maxlen)
207 {
208  SDL_error *error;
209 
210  /* Clear the error string */
211  *errstr = '\0';
212  --maxlen;
213 
214  /* Get the thread-safe error, and print it out */
215  error = SDL_GetErrBuf();
216  if (error->error) {
217  const char *fmt;
218  char *msg = errstr;
219  int len;
220  int argi;
221 
222  fmt = SDL_LookupString(error->key);
223  argi = 0;
224  while (*fmt && (maxlen > 0)) {
225  if (*fmt == '%') {
226  char tmp[32], *spot = tmp;
227  *spot++ = *fmt++;
228  while ((*fmt == '.' || (*fmt >= '0' && *fmt <= '9'))
229  && spot < (tmp + SDL_arraysize(tmp) - 2)) {
230  *spot++ = *fmt++;
231  }
232  if (*fmt == 'l') {
233  *spot++ = *fmt++;
234  *spot++ = *fmt++;
235  *spot++ = '\0';
236  switch (spot[-2]) {
237  case 'i': case 'd': case 'u':
238  len = SDL_snprintf(msg, maxlen, tmp,
239  error->args[argi++].value_l);
240  if (len > 0) {
241  msg += len;
242  maxlen -= len;
243  }
244  break;
245  }
246  continue;
247  }
248  *spot++ = *fmt++;
249  *spot++ = '\0';
250  switch (spot[-2]) {
251  case '%':
252  *msg++ = '%';
253  maxlen -= 1;
254  break;
255  case 'c':
256  case 'i':
257  case 'd':
258  case 'u':
259  case 'o':
260  case 'x':
261  case 'X':
262  len =
263  SDL_snprintf(msg, maxlen, tmp,
264  error->args[argi++].value_i);
265  if (len > 0) {
266  msg += len;
267  maxlen -= len;
268  }
269  break;
270 
271  case 'f':
272  len =
273  SDL_snprintf(msg, maxlen, tmp,
274  error->args[argi++].value_f);
275  if (len > 0) {
276  msg += len;
277  maxlen -= len;
278  }
279  break;
280 
281  case 'p':
282  len =
283  SDL_snprintf(msg, maxlen, tmp,
284  error->args[argi++].value_ptr);
285  if (len > 0) {
286  msg += len;
287  maxlen -= len;
288  }
289  break;
290 
291  case 's':
292  len =
293  SDL_snprintf(msg, maxlen, tmp,
294  SDL_LookupString(error->args[argi++].
295  buf));
296  if (len > 0) {
297  msg += len;
298  maxlen -= len;
299  }
300  break;
301 
302  }
303  } else {
304  *msg++ = *fmt++;
305  maxlen -= 1;
306  }
307  }
308 
309  /* slide back if we've overshot the end of our buffer. */
310  if (maxlen < 0) {
311  msg -= (-maxlen) + 1;
312  }
313 
314  *msg = 0; /* NULL terminate the string */
315  }
316  return (errstr);
317 }
318 
319 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_strlcpy
#define SDL_ERRBUFIZE
Definition: SDL_error.c:39
SDL_errorcode
Definition: SDL_error.h:55
union SDL_error::@29 args[ERR_MAX_ARGS]
double value_f
Definition: SDL_error_c.h:55
#define SDL_LogGetPriority
int SDL_Error(SDL_errorcode code)
Definition: SDL_error.c:158
static const char * SDL_LookupString(const char *key)
Definition: SDL_error.c:44
SDL_error * SDL_GetErrBuf(void)
Definition: SDL_thread.c:206
GLenum GLsizei len
#define ERR_MAX_STRLEN
Definition: SDL_error_c.h:30
const char * SDL_GetError(void)
Definition: SDL_error.c:140
#define SDL_LogDebug
GLuint64 key
Definition: gl2ext.h:2192
GLenum GLuint GLenum GLsizei const GLchar * buf
#define ERR_MAX_ARGS
Definition: SDL_error_c.h:31
char key[ERR_MAX_STRLEN]
Definition: SDL_error_c.h:43
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
int SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt,...)
Definition: SDL_error.c:55
#define NULL
Definition: begin_code.h:164
GLuint buffer
long value_l
Definition: SDL_error_c.h:54
char buf[ERR_MAX_STRLEN]
Definition: SDL_error_c.h:56
#define SDL_snprintf
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
void * value_ptr
Definition: SDL_error_c.h:49
#define main
Definition: SDL_main.h:111
int value_i
Definition: SDL_error_c.h:53
#define SDL_PRINTF_FORMAT_STRING
Definition: SDL_stdinc.h:278
void SDL_ClearError(void)
Definition: SDL_error.c:148
#define SDL_memset
static char * SDL_GetErrorMsg(char *errstr, int maxlen)
Definition: SDL_error.c:206