Commit | Line | Data |
---|---|---|
ef79bbde P |
1 | /* |
2 | SDL - Simple DirectMedia Layer | |
3 | Copyright (C) 1997-2010 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_error.h" | |
27 | #include "SDL_error_c.h" | |
28 | ||
29 | /* Routine to get the thread-specific error variable */ | |
30 | #if SDL_THREADS_DISABLED | |
31 | /* !!! FIXME: what does this comment mean? Victim of Search and Replace? */ | |
32 | /* The SDL_arraysize(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 | void | |
53 | SDL_SetError(const char *fmt, ...) | |
54 | { | |
55 | va_list ap; | |
56 | SDL_error *error; | |
57 | ||
58 | /* Copy in the key, mark error as valid */ | |
59 | error = SDL_GetErrBuf(); | |
60 | error->error = 1; | |
61 | SDL_strlcpy((char *) error->key, fmt, sizeof(error->key)); | |
62 | ||
63 | va_start(ap, fmt); | |
64 | error->argc = 0; | |
65 | while (*fmt) { | |
66 | if (*fmt++ == '%') { | |
67 | while (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) { | |
68 | ++fmt; | |
69 | } | |
70 | switch (*fmt++) { | |
71 | case 0: /* Malformed format string.. */ | |
72 | --fmt; | |
73 | break; | |
74 | case 'c': | |
75 | case 'i': | |
76 | case 'd': | |
77 | case 'u': | |
78 | case 'o': | |
79 | case 'x': | |
80 | case 'X': | |
81 | error->args[error->argc++].value_i = va_arg(ap, int); | |
82 | break; | |
83 | case 'f': | |
84 | error->args[error->argc++].value_f = va_arg(ap, double); | |
85 | break; | |
86 | case 'p': | |
87 | error->args[error->argc++].value_ptr = va_arg(ap, void *); | |
88 | break; | |
89 | case 's': | |
90 | { | |
91 | int i = error->argc; | |
92 | const char *str = va_arg(ap, const char *); | |
93 | if (str == NULL) | |
94 | str = "(null)"; | |
95 | SDL_strlcpy((char *) error->args[i].buf, str, | |
96 | ERR_MAX_STRLEN); | |
97 | error->argc++; | |
98 | } | |
99 | break; | |
100 | default: | |
101 | break; | |
102 | } | |
103 | if (error->argc >= ERR_MAX_ARGS) { | |
104 | break; | |
105 | } | |
106 | } | |
107 | } | |
108 | va_end(ap); | |
109 | ||
110 | /* If we are in debug mode, print out an error message */ | |
111 | #ifdef DEBUG_ERROR | |
112 | fprintf(stderr, "SDL_SetError: %s\n", SDL_GetError()); | |
113 | #endif | |
114 | } | |
115 | ||
116 | /* This function has a bit more overhead than most error functions | |
117 | so that it supports internationalization and thread-safe errors. | |
118 | */ | |
119 | static char * | |
120 | SDL_GetErrorMsg(char *errstr, unsigned int maxlen) | |
121 | { | |
122 | SDL_error *error; | |
123 | ||
124 | /* Clear the error string */ | |
125 | *errstr = '\0'; | |
126 | --maxlen; | |
127 | ||
128 | /* Get the thread-safe error, and print it out */ | |
129 | error = SDL_GetErrBuf(); | |
130 | if (error->error) { | |
131 | const char *fmt; | |
132 | char *msg = errstr; | |
133 | int len; | |
134 | int argi; | |
135 | ||
136 | fmt = SDL_LookupString(error->key); | |
137 | argi = 0; | |
138 | while (*fmt && (maxlen > 0)) { | |
139 | if (*fmt == '%') { | |
140 | char tmp[32], *spot = tmp; | |
141 | *spot++ = *fmt++; | |
142 | while ((*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) | |
143 | && spot < (tmp + SDL_arraysize(tmp) - 2)) { | |
144 | *spot++ = *fmt++; | |
145 | } | |
146 | *spot++ = *fmt++; | |
147 | *spot++ = '\0'; | |
148 | switch (spot[-2]) { | |
149 | case '%': | |
150 | *msg++ = '%'; | |
151 | maxlen -= 1; | |
152 | break; | |
153 | case 'c': | |
154 | case 'i': | |
155 | case 'd': | |
156 | case 'u': | |
157 | case 'o': | |
158 | case 'x': | |
159 | case 'X': | |
160 | len = | |
161 | SDL_snprintf(msg, maxlen, tmp, | |
162 | error->args[argi++].value_i); | |
163 | msg += len; | |
164 | maxlen -= len; | |
165 | break; | |
166 | case 'f': | |
167 | len = | |
168 | SDL_snprintf(msg, maxlen, tmp, | |
169 | error->args[argi++].value_f); | |
170 | msg += len; | |
171 | maxlen -= len; | |
172 | break; | |
173 | case 'p': | |
174 | len = | |
175 | SDL_snprintf(msg, maxlen, tmp, | |
176 | error->args[argi++].value_ptr); | |
177 | msg += len; | |
178 | maxlen -= len; | |
179 | break; | |
180 | case 's': | |
181 | len = | |
182 | SDL_snprintf(msg, maxlen, tmp, | |
183 | SDL_LookupString(error->args[argi++]. | |
184 | buf)); | |
185 | msg += len; | |
186 | maxlen -= len; | |
187 | break; | |
188 | } | |
189 | } else { | |
190 | *msg++ = *fmt++; | |
191 | maxlen -= 1; | |
192 | } | |
193 | } | |
194 | *msg = 0; /* NULL terminate the string */ | |
195 | } | |
196 | return (errstr); | |
197 | } | |
198 | ||
199 | /* Available for backwards compatibility */ | |
200 | char * | |
201 | SDL_GetError(void) | |
202 | { | |
203 | static char errmsg[SDL_ERRBUFIZE]; | |
204 | ||
205 | return ((char *) SDL_GetErrorMsg(errmsg, SDL_ERRBUFIZE)); | |
206 | } | |
207 | ||
208 | void | |
209 | SDL_ClearError(void) | |
210 | { | |
211 | SDL_error *error; | |
212 | ||
213 | error = SDL_GetErrBuf(); | |
214 | error->error = 0; | |
215 | } | |
216 | ||
217 | /* Very common errors go here */ | |
218 | void | |
219 | SDL_Error(SDL_errorcode code) | |
220 | { | |
221 | switch (code) { | |
222 | case SDL_ENOMEM: | |
223 | SDL_SetError("Out of memory"); | |
224 | break; | |
225 | case SDL_EFREAD: | |
226 | SDL_SetError("Error reading from datastream"); | |
227 | break; | |
228 | case SDL_EFWRITE: | |
229 | SDL_SetError("Error writing to datastream"); | |
230 | break; | |
231 | case SDL_EFSEEK: | |
232 | SDL_SetError("Error seeking in datastream"); | |
233 | break; | |
234 | case SDL_UNSUPPORTED: | |
235 | SDL_SetError("That operation is not supported"); | |
236 | break; | |
237 | default: | |
238 | SDL_SetError("Unknown SDL error"); | |
239 | break; | |
240 | } | |
241 | } | |
242 | ||
243 | #ifdef TEST_ERROR | |
244 | int | |
245 | main(int argc, char *argv[]) | |
246 | { | |
247 | char buffer[BUFSIZ + 1]; | |
248 | ||
249 | SDL_SetError("Hi there!"); | |
250 | printf("Error 1: %s\n", SDL_GetError()); | |
251 | SDL_ClearError(); | |
252 | SDL_memset(buffer, '1', BUFSIZ); | |
253 | buffer[BUFSIZ] = 0; | |
254 | SDL_SetError("This is the error: %s (%f)", buffer, 1.0); | |
255 | printf("Error 2: %s\n", SDL_GetError()); | |
256 | exit(0); | |
257 | } | |
258 | #endif | |
259 | /* vi: set ts=4 sw=4 expandtab: */ |