1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 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 (at) 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 /* The SDL_arraysize(The ),default (non-thread-safe) global error variable */ 32 static SDL_error SDL_global_error; 33 #define SDL_GetErrBuf() (&SDL_global_error) 34 #else 35 extern SDL_error *SDL_GetErrBuf(void); 36 #endif /* SDL_THREADS_DISABLED */ 37 38 #define SDL_ERRBUFIZE 1024 39 40 /* Private functions */ 41 42 static const char *SDL_LookupString(const char *key) 43 { 44 /* FIXME: Add code to lookup key in language string hash-table */ 45 return key; 46 } 47 48 /* Public functions */ 49 50 void SDL_SetError (const char *fmt, ...) 51 { 52 va_list ap; 53 SDL_error *error; 54 55 /* Copy in the key, mark error as valid */ 56 error = SDL_GetErrBuf(); 57 error->error = 1; 58 SDL_strlcpy((char *)error->key, fmt, sizeof(error->key)); 59 60 va_start(ap, fmt); 61 error->argc = 0; 62 while ( *fmt ) { 63 if ( *fmt++ == '%' ) { 64 while ( *fmt == '.' || (*fmt >= '0' && *fmt <= '9') ) { 65 ++fmt; 66 } 67 switch (*fmt++) { 68 case 0: /* Malformed format string.. */ 69 --fmt; 70 break; 71 case 'c': 72 case 'i': 73 case 'd': 74 case 'u': 75 case 'o': 76 case 'x': 77 case 'X': 78 error->args[error->argc++].value_i = 79 va_arg(ap, int); 80 break; 81 case 'f': 82 error->args[error->argc++].value_f = 83 va_arg(ap, double); 84 break; 85 case 'p': 86 error->args[error->argc++].value_ptr = 87 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, ERR_MAX_STRLEN); 96 error->argc++; 97 } 98 break; 99 default: 100 break; 101 } 102 if ( error->argc >= ERR_MAX_ARGS ) { 103 break; 104 } 105 } 106 } 107 va_end(ap); 108 109 /* If we are in debug mode, print out an error message */ 110 #ifdef DEBUG_ERROR 111 fprintf(stderr, "SDL_SetError: %s\n", SDL_GetError()); 112 #endif 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 char *SDL_GetErrorMsg(char *errstr, unsigned int maxlen) 119 { 120 SDL_error *error; 121 122 /* Clear the error string */ 123 *errstr = '\0'; --maxlen; 124 125 /* Get the thread-safe error, and print it out */ 126 error = SDL_GetErrBuf(); 127 if ( error->error ) { 128 const char *fmt; 129 char *msg = errstr; 130 int len; 131 int argi; 132 133 fmt = SDL_LookupString(error->key); 134 argi = 0; 135 while ( *fmt && (maxlen > 0) ) { 136 if ( *fmt == '%' ) { 137 char tmp[32], *spot = tmp; 138 *spot++ = *fmt++; 139 while ( (*fmt == '.' || (*fmt >= '0' && *fmt <= '9')) && spot < (tmp+SDL_arraysize(tmp)-2) ) { 140 *spot++ = *fmt++; 141 } 142 *spot++ = *fmt++; 143 *spot++ = '\0'; 144 switch (spot[-2]) { 145 case '%': 146 *msg++ = '%'; 147 maxlen -= 1; 148 break; 149 case 'c': 150 case 'i': 151 case 'd': 152 case 'u': 153 case 'o': 154 case 'x': 155 case 'X': 156 len = SDL_snprintf(msg, maxlen, tmp, error->args[argi++].value_i); 157 msg += len; 158 maxlen -= len; 159 break; 160 case 'f': 161 len = SDL_snprintf(msg, maxlen, tmp, error->args[argi++].value_f); 162 msg += len; 163 maxlen -= len; 164 break; 165 case 'p': 166 len = SDL_snprintf(msg, maxlen, tmp, error->args[argi++].value_ptr); 167 msg += len; 168 maxlen -= len; 169 break; 170 case 's': 171 len = SDL_snprintf(msg, maxlen, tmp, SDL_LookupString(error->args[argi++].buf)); 172 msg += len; 173 maxlen -= len; 174 break; 175 } 176 } else { 177 *msg++ = *fmt++; 178 maxlen -= 1; 179 } 180 } 181 *msg = 0; /* NULL terminate the string */ 182 } 183 return(errstr); 184 } 185 186 /* Available for backwards compatibility */ 187 char *SDL_GetError (void) 188 { 189 static char errmsg[SDL_ERRBUFIZE]; 190 191 return((char *)SDL_GetErrorMsg(errmsg, SDL_ERRBUFIZE)); 192 } 193 194 void SDL_ClearError(void) 195 { 196 SDL_error *error; 197 198 error = SDL_GetErrBuf(); 199 error->error = 0; 200 } 201 202 /* Very common errors go here */ 203 void SDL_Error(SDL_errorcode code) 204 { 205 switch (code) { 206 case SDL_ENOMEM: 207 SDL_SetError("Out of memory"); 208 break; 209 case SDL_EFREAD: 210 SDL_SetError("Error reading from datastream"); 211 break; 212 case SDL_EFWRITE: 213 SDL_SetError("Error writing to datastream"); 214 break; 215 case SDL_EFSEEK: 216 SDL_SetError("Error seeking in datastream"); 217 break; 218 default: 219 SDL_SetError("Unknown SDL error"); 220 break; 221 } 222 } 223 224 #ifdef TEST_ERROR 225 int main(int argc, char *argv[]) 226 { 227 char buffer[BUFSIZ+1]; 228 229 SDL_SetError("Hi there!"); 230 printf("Error 1: %s\n", SDL_GetError()); 231 SDL_ClearError(); 232 SDL_memset(buffer, '1', BUFSIZ); 233 buffer[BUFSIZ] = 0; 234 SDL_SetError("This is the error: %s (%f)", buffer, 1.0); 235 printf("Error 2: %s\n", SDL_GetError()); 236 exit(0); 237 } 238 #endif 239