1 |
/* |
2 |
SDL - Simple DirectMedia Layer |
3 |
Copyright (C) 1997-2011 Sam Lantinga |
4 |
|
5 |
This library is free software; you can redistribute it and/or |
6 |
modify it under the terms of the GNU Lesser General Public |
7 |
License as published by the Free Software Foundation; either |
8 |
version 2.1 of the License, or (at your option) any later version. |
9 |
|
10 |
This library is distributed in the hope that it will be useful, |
11 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 |
Lesser General Public License for more details. |
14 |
|
15 |
You should have received a copy of the GNU Lesser General Public |
16 |
License along with this library; if not, write to the Free Software |
17 |
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
18 |
|
19 |
Sam Lantinga |
20 |
slouken@libsdl.org |
21 |
*/ |
22 |
#include "SDL_config.h" |
23 |
|
24 |
/* Simple error handling in SDL */ |
25 |
|
26 |
#include "SDL_log.h" |
27 |
#include "SDL_error.h" |
28 |
#include "SDL_error_c.h" |
29 |
|
30 |
|
31 |
/* Routine to get the thread-specific error variable */ |
32 |
#if SDL_THREADS_DISABLED |
33 |
/* The default (non-thread-safe) global error variable */ |
34 |
static SDL_error SDL_global_error; |
35 |
#define SDL_GetErrBuf() (&SDL_global_error) |
36 |
#else |
37 |
extern SDL_error *SDL_GetErrBuf(void); |
38 |
#endif /* SDL_THREADS_DISABLED */ |
39 |
|
40 |
#define SDL_ERRBUFIZE 1024 |
41 |
|
42 |
/* Private functions */ |
43 |
|
44 |
static const char * |
45 |
SDL_LookupString(const char *key) |
46 |
{ |
47 |
/* FIXME: Add code to lookup key in language string hash-table */ |
48 |
return key; |
49 |
} |
50 |
|
51 |
/* Public functions */ |
52 |
|
53 |
void |
54 |
SDL_SetError(const char *fmt, ...) |
55 |
{ |
56 |
va_list ap; |
57 |
SDL_error *error; |
58 |
|
59 |
/* Copy in the key, mark error as valid */ |
60 |
error = SDL_GetErrBuf(); |
61 |
error->error = 1; |
62 |
SDL_strlcpy((char *) error->key, fmt, sizeof(error->key)); |
63 |
|
64 |
va_start(ap, fmt); |
65 |
error->argc = 0; |
66 |
while (*fmt) { |
67 |
if (*fmt++ == '%') { |
68 |
while (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) { |
69 |
++fmt; |
70 |
} |
71 |
switch (*fmt++) { |
72 |
case 0: /* Malformed format string.. */ |
73 |
--fmt; |
74 |
break; |
75 |
case 'c': |
76 |
case 'i': |
77 |
case 'd': |
78 |
case 'u': |
79 |
case 'o': |
80 |
case 'x': |
81 |
case 'X': |
82 |
error->args[error->argc++].value_i = va_arg(ap, int); |
83 |
break; |
84 |
case 'f': |
85 |
error->args[error->argc++].value_f = va_arg(ap, double); |
86 |
break; |
87 |
case 'p': |
88 |
error->args[error->argc++].value_ptr = va_arg(ap, void *); |
89 |
break; |
90 |
case 's': |
91 |
{ |
92 |
int i = error->argc; |
93 |
const char *str = va_arg(ap, const char *); |
94 |
if (str == NULL) |
95 |
str = "(null)"; |
96 |
SDL_strlcpy((char *) error->args[i].buf, str, |
97 |
ERR_MAX_STRLEN); |
98 |
error->argc++; |
99 |
} |
100 |
break; |
101 |
default: |
102 |
break; |
103 |
} |
104 |
if (error->argc >= ERR_MAX_ARGS) { |
105 |
break; |
106 |
} |
107 |
} |
108 |
} |
109 |
va_end(ap); |
110 |
|
111 |
/* If we are in debug mode, print out an error message */ |
112 |
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "%s", SDL_GetError()); |
113 |
} |
114 |
|
115 |
/* This function has a bit more overhead than most error functions |
116 |
so that it supports internationalization and thread-safe errors. |
117 |
*/ |
118 |
static char * |
119 |
SDL_GetErrorMsg(char *errstr, unsigned int maxlen) |
120 |
{ |
121 |
SDL_error *error; |
122 |
|
123 |
/* Clear the error string */ |
124 |
*errstr = '\0'; |
125 |
--maxlen; |
126 |
|
127 |
/* Get the thread-safe error, and print it out */ |
128 |
error = SDL_GetErrBuf(); |
129 |
if (error->error) { |
130 |
const char *fmt; |
131 |
char *msg = errstr; |
132 |
int len; |
133 |
int argi; |
134 |
|
135 |
fmt = SDL_LookupString(error->key); |
136 |
argi = 0; |
137 |
while (*fmt && (maxlen > 0)) { |
138 |
if (*fmt == '%') { |
139 |
char tmp[32], *spot = tmp; |
140 |
*spot++ = *fmt++; |
141 |
while ((*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) |
142 |
&& spot < (tmp + SDL_arraysize(tmp) - 2)) { |
143 |
*spot++ = *fmt++; |
144 |
} |
145 |
*spot++ = *fmt++; |
146 |
*spot++ = '\0'; |
147 |
switch (spot[-2]) { |
148 |
case '%': |
149 |
*msg++ = '%'; |
150 |
maxlen -= 1; |
151 |
break; |
152 |
case 'c': |
153 |
case 'i': |
154 |
case 'd': |
155 |
case 'u': |
156 |
case 'o': |
157 |
case 'x': |
158 |
case 'X': |
159 |
len = |
160 |
SDL_snprintf(msg, maxlen, tmp, |
161 |
error->args[argi++].value_i); |
162 |
msg += len; |
163 |
maxlen -= len; |
164 |
break; |
165 |
case 'f': |
166 |
len = |
167 |
SDL_snprintf(msg, maxlen, tmp, |
168 |
error->args[argi++].value_f); |
169 |
msg += len; |
170 |
maxlen -= len; |
171 |
break; |
172 |
case 'p': |
173 |
len = |
174 |
SDL_snprintf(msg, maxlen, tmp, |
175 |
error->args[argi++].value_ptr); |
176 |
msg += len; |
177 |
maxlen -= len; |
178 |
break; |
179 |
case 's': |
180 |
len = |
181 |
SDL_snprintf(msg, maxlen, tmp, |
182 |
SDL_LookupString(error->args[argi++]. |
183 |
buf)); |
184 |
msg += len; |
185 |
maxlen -= len; |
186 |
break; |
187 |
} |
188 |
} else { |
189 |
*msg++ = *fmt++; |
190 |
maxlen -= 1; |
191 |
} |
192 |
} |
193 |
*msg = 0; /* NULL terminate the string */ |
194 |
} |
195 |
return (errstr); |
196 |
} |
197 |
|
198 |
/* Available for backwards compatibility */ |
199 |
const char * |
200 |
SDL_GetError(void) |
201 |
{ |
202 |
static char errmsg[SDL_ERRBUFIZE]; |
203 |
|
204 |
return SDL_GetErrorMsg(errmsg, SDL_ERRBUFIZE); |
205 |
} |
206 |
|
207 |
void |
208 |
SDL_ClearError(void) |
209 |
{ |
210 |
SDL_error *error; |
211 |
|
212 |
error = SDL_GetErrBuf(); |
213 |
error->error = 0; |
214 |
} |
215 |
|
216 |
/* Very common errors go here */ |
217 |
void |
218 |
SDL_Error(SDL_errorcode code) |
219 |
{ |
220 |
switch (code) { |
221 |
case SDL_ENOMEM: |
222 |
SDL_SetError("Out of memory"); |
223 |
break; |
224 |
case SDL_EFREAD: |
225 |
SDL_SetError("Error reading from datastream"); |
226 |
break; |
227 |
case SDL_EFWRITE: |
228 |
SDL_SetError("Error writing to datastream"); |
229 |
break; |
230 |
case SDL_EFSEEK: |
231 |
SDL_SetError("Error seeking in datastream"); |
232 |
break; |
233 |
case SDL_UNSUPPORTED: |
234 |
SDL_SetError("That operation is not supported"); |
235 |
break; |
236 |
default: |
237 |
SDL_SetError("Unknown SDL error"); |
238 |
break; |
239 |
} |
240 |
} |
241 |
|
242 |
#ifdef TEST_ERROR |
243 |
int |
244 |
main(int argc, char *argv[]) |
245 |
{ |
246 |
char buffer[BUFSIZ + 1]; |
247 |
|
248 |
SDL_SetError("Hi there!"); |
249 |
printf("Error 1: %s\n", SDL_GetError()); |
250 |
SDL_ClearError(); |
251 |
SDL_memset(buffer, '1', BUFSIZ); |
252 |
buffer[BUFSIZ] = 0; |
253 |
SDL_SetError("This is the error: %s (%f)", buffer, 1.0); |
254 |
printf("Error 2: %s\n", SDL_GetError()); |
255 |
exit(0); |
256 |
} |
257 |
#endif |
258 |
|
259 |
/* vi: set ts=4 sw=4 expandtab: */ |