SDL 2.0
SDL_error.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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 */
33static SDL_error SDL_global_error;
34#define SDL_GetErrBuf() (&SDL_global_error)
35#else
36extern SDL_error *SDL_GetErrBuf(void);
37#endif /* SDL_THREADS_DISABLED */
38
39#define SDL_ERRBUFIZE 1024
40
41/* Private functions */
42
43static const char *
45{
46 /* FIXME: Add code to lookup key in language string hash-table */
47 return key;
48}
49
50/* Public functions */
51
52static char *SDL_GetErrorMsg(char *errstr, int maxlen);
53
54int
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': case 'x': case 'X':
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));
134 }
135 return -1;
136}
137
138/* Available for backwards compatibility */
139const char *
141{
142 static char errmsg[SDL_ERRBUFIZE];
143
144 return SDL_GetErrorMsg(errmsg, SDL_ERRBUFIZE);
145}
146
147void
149{
150 SDL_error *error;
151
152 error = SDL_GetErrBuf();
153 error->error = 0;
154}
155
156/* Very common errors go here */
157int
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
177int
178main(int argc, char *argv[])
179{
180 char buffer[BUFSIZ + 1];
181
182 SDL_SetError("Hi there!");
183 printf("Error 1: %s\n", SDL_GetError());
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*/
205static char *
206SDL_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': case 'x': case 'X':
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_memset
#define SDL_LogGetPriority
#define SDL_strlcpy
#define SDL_LogDebug
#define SDL_snprintf
#define SDL_ERRBUFIZE
Definition: SDL_error.c:39
SDL_error * SDL_GetErrBuf(void)
Definition: SDL_thread.c:206
static const char * SDL_LookupString(const char *key)
Definition: SDL_error.c:44
const char * SDL_GetError(void)
Definition: SDL_error.c:140
static char * SDL_GetErrorMsg(char *errstr, int maxlen)
Definition: SDL_error.c:206
int SDL_Error(SDL_errorcode code)
Definition: SDL_error.c:158
int SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt,...)
Definition: SDL_error.c:55
void SDL_ClearError(void)
Definition: SDL_error.c:148
SDL_errorcode
Definition: SDL_error.h:56
@ SDL_EFSEEK
Definition: SDL_error.h:60
@ SDL_EFWRITE
Definition: SDL_error.h:59
@ SDL_UNSUPPORTED
Definition: SDL_error.h:61
@ SDL_EFREAD
Definition: SDL_error.h:58
@ SDL_ENOMEM
Definition: SDL_error.h:57
#define ERR_MAX_ARGS
Definition: SDL_error_c.h:31
#define ERR_MAX_STRLEN
Definition: SDL_error_c.h:30
@ SDL_LOG_PRIORITY_DEBUG
Definition: SDL_log.h:105
@ SDL_LOG_CATEGORY_ERROR
Definition: SDL_log.h:67
#define main
Definition: SDL_main.h:109
GLenum GLsizei len
GLuint buffer
GLenum GLuint GLenum GLsizei const GLchar * buf
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
#define SDL_PRINTF_FORMAT_STRING
Definition: SDL_stdinc.h:300
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
#define NULL
Definition: begin_code.h:167
GLuint64 key
Definition: gl2ext.h:2192
int value_i
Definition: SDL_error_c.h:53
long value_l
Definition: SDL_error_c.h:54
void * value_ptr
Definition: SDL_error_c.h:49
char key[ERR_MAX_STRLEN]
Definition: SDL_error_c.h:43
char buf[ERR_MAX_STRLEN]
Definition: SDL_error_c.h:56
union SDL_error::@35 args[ERR_MAX_ARGS]
double value_f
Definition: SDL_error_c.h:55