1 /* 2 SDL_main.c, placed in the public domain by Sam Lantinga 4/13/98 3 4 The WinMain function -- calls your program's main() function 5 */ 6 7 #include <stdio.h> 8 #include <stdlib.h> 9 10 #define WIN32_LEAN_AND_MEAN 11 #include <windows.h> 12 13 #ifdef _WIN32_WCE 14 # define DIR_SEPERATOR TEXT("\\") 15 # undef _getcwd 16 # define _getcwd(str,len) wcscpy(str,TEXT("")) 17 # define setbuf(f,b) 18 # define setvbuf(w,x,y,z) 19 # define fopen _wfopen 20 # define freopen _wfreopen 21 # define remove(x) DeleteFile(x) 22 #else 23 # define DIR_SEPERATOR TEXT("/") 24 # include <direct.h> 25 #endif 26 27 /* Include the SDL main definition header */ 28 #include "SDL.h" 29 #include "SDL_main.h" 30 31 #ifdef main 32 # ifndef _WIN32_WCE_EMULATION 33 # undef main 34 # endif /* _WIN32_WCE_EMULATION */ 35 #endif /* main */ 36 37 /* The standard output files */ 38 #define STDOUT_FILE TEXT("stdout.txt") 39 #define STDERR_FILE TEXT("stderr.txt") 40 41 /* Set a variable to tell if the stdio redirect has been enabled. */ 42 static int stdioRedirectEnabled = 0; 43 44 #ifdef _WIN32_WCE 45 static wchar_t stdoutPath[MAX_PATH]; 46 static wchar_t stderrPath[MAX_PATH]; 47 #else 48 static char stdoutPath[MAX_PATH]; 49 static char stderrPath[MAX_PATH]; 50 #endif 51 52 #if defined(_WIN32_WCE) && _WIN32_WCE < 300 53 /* seems to be undefined in Win CE although in online help */ 54 #define isspace(a) (((CHAR)a == ' ') || ((CHAR)a == '\t')) 55 #endif /* _WIN32_WCE < 300 */ 56 57 static void UnEscapeQuotes( char *arg ) 58 { 59 char *last = NULL; 60 61 while( *arg ) { 62 if( *arg == '"' && *last == '\\' ) { 63 char *c_curr = arg; 64 char *c_last = last; 65 66 while( *c_curr ) { 67 *c_last = *c_curr; 68 c_last = c_curr; 69 c_curr++; 70 } 71 *c_last = '\0'; 72 } 73 last = arg; 74 arg++; 75 } 76 } 77 78 /* Parse a command line buffer into arguments */ 79 static int ParseCommandLine(char *cmdline, char **argv) 80 { 81 char *bufp; 82 char *lastp = NULL; 83 int argc, last_argc; 84 85 argc = last_argc = 0; 86 for ( bufp = cmdline; *bufp; ) { 87 /* Skip leading whitespace */ 88 while ( isspace(*bufp) ) { 89 ++bufp; 90 } 91 /* Skip over argument */ 92 if ( *bufp == '"' ) { 93 ++bufp; 94 if ( *bufp ) { 95 if ( argv ) { 96 argv[argc] = bufp; 97 } 98 ++argc; 99 } 100 /* Skip over word */ 101 while ( *bufp && ( *bufp != '"' || (lastp && *lastp == '\\') ) ) { 102 lastp = bufp; 103 ++bufp; 104 } 105 } else { 106 if ( *bufp ) { 107 if ( argv ) { 108 argv[argc] = bufp; 109 } 110 ++argc; 111 } 112 /* Skip over word */ 113 while ( *bufp && ! isspace(*bufp) ) { 114 ++bufp; 115 } 116 } 117 if ( *bufp ) { 118 if ( argv ) { 119 *bufp = '\0'; 120 } 121 ++bufp; 122 } 123 124 /* Strip out \ from \" sequences */ 125 if( argv && last_argc != argc ) { 126 UnEscapeQuotes( argv[last_argc] ); 127 } 128 last_argc = argc; 129 } 130 if ( argv ) { 131 argv[argc] = NULL; 132 } 133 return(argc); 134 } 135 136 /* Show an error message */ 137 static void ShowError(const char *title, const char *message) 138 { 139 /* If USE_MESSAGEBOX is defined, you need to link with user32.lib */ 140 #ifdef USE_MESSAGEBOX 141 MessageBox(NULL, message, title, MB_ICONEXCLAMATION|MB_OK); 142 #else 143 fprintf(stderr, "%s: %s\n", title, message); 144 #endif 145 } 146 147 /* Pop up an out of memory message, returns to Windows */ 148 static BOOL OutOfMemory(void) 149 { 150 ShowError("Fatal Error", "Out of memory - aborting"); 151 return FALSE; 152 } 153 154 /* SDL_Quit() shouldn't be used with atexit() directly because 155 calling conventions may differ... */ 156 static void cleanup(void) 157 { 158 SDL_Quit(); 159 } 160 161 /* Remove the output files if there was no output written */ 162 static void cleanup_output(void) { 163 FILE *file; 164 int empty; 165 166 /* Flush the output in case anything is queued */ 167 fclose(stdout); 168 fclose(stderr); 169 170 /* Without redirection we're done */ 171 if (!stdioRedirectEnabled) { 172 return; 173 } 174 175 /* See if the files have any output in them */ 176 if ( stdoutPath[0] ) { 177 file = fopen(stdoutPath, TEXT("rb")); 178 if ( file ) { 179 empty = (fgetc(file) == EOF) ? 1 : 0; 180 fclose(file); 181 if ( empty ) { 182 remove(stdoutPath); 183 } 184 } 185 } 186 if ( stderrPath[0] ) { 187 file = fopen(stderrPath, TEXT("rb")); 188 if ( file ) { 189 empty = (fgetc(file) == EOF) ? 1 : 0; 190 fclose(file); 191 if ( empty ) { 192 remove(stderrPath); 193 } 194 } 195 } 196 } 197 198 /* Redirect the output (stdout and stderr) to a file */ 199 static void redirect_output(void) 200 { 201 DWORD pathlen; 202 #ifdef _WIN32_WCE 203 wchar_t path[MAX_PATH]; 204 #else 205 char path[MAX_PATH]; 206 #endif 207 FILE *newfp; 208 209 pathlen = GetModuleFileName(NULL, path, SDL_arraysize(path)); 210 while ( pathlen > 0 && path[pathlen] != '\\' ) { 211 --pathlen; 212 } 213 path[pathlen] = '\0'; 214 215 #ifdef _WIN32_WCE 216 wcsncpy( stdoutPath, path, SDL_arraysize(stdoutPath) ); 217 wcsncat( stdoutPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) ); 218 #else 219 SDL_strlcpy( stdoutPath, path, SDL_arraysize(stdoutPath) ); 220 SDL_strlcat( stdoutPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) ); 221 #endif 222 223 /* Redirect standard input and standard output */ 224 newfp = freopen(stdoutPath, TEXT("w"), stdout); 225 226 #ifndef _WIN32_WCE 227 if ( newfp == NULL ) { /* This happens on NT */ 228 #if !defined(stdout) 229 stdout = fopen(stdoutPath, TEXT("w")); 230 #else 231 newfp = fopen(stdoutPath, TEXT("w")); 232 if ( newfp ) { 233 *stdout = *newfp; 234 } 235 #endif 236 } 237 #endif /* _WIN32_WCE */ 238 239 #ifdef _WIN32_WCE 240 wcsncpy( stderrPath, path, SDL_arraysize(stdoutPath) ); 241 wcsncat( stderrPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) ); 242 #else 243 SDL_strlcpy( stderrPath, path, SDL_arraysize(stderrPath) ); 244 SDL_strlcat( stderrPath, DIR_SEPERATOR STDERR_FILE, SDL_arraysize(stderrPath) ); 245 #endif 246 247 newfp = freopen(stderrPath, TEXT("w"), stderr); 248 #ifndef _WIN32_WCE 249 if ( newfp == NULL ) { /* This happens on NT */ 250 #if !defined(stderr) 251 stderr = fopen(stderrPath, TEXT("w")); 252 #else 253 newfp = fopen(stderrPath, TEXT("w")); 254 if ( newfp ) { 255 *stderr = *newfp; 256 } 257 #endif 258 } 259 #endif /* _WIN32_WCE */ 260 261 setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* Line buffered */ 262 setbuf(stderr, NULL); /* No buffering */ 263 stdioRedirectEnabled = 1; 264 } 265 266 #if defined(_MSC_VER) && !defined(_WIN32_WCE) 267 /* The VC++ compiler needs main defined */ 268 #define console_main main 269 #endif 270 271 /* This is where execution begins [console apps] */ 272 int console_main(int argc, char *argv[]) 273 { 274 size_t n; 275 char *bufp, *appname; 276 int status; 277 278 /* Get the class name from argv[0] */ 279 appname = argv[0]; 280 if ( (bufp=SDL_strrchr(argv[0], '\\')) != NULL ) { 281 appname = bufp+1; 282 } else 283 if ( (bufp=SDL_strrchr(argv[0], '/')) != NULL ) { 284 appname = bufp+1; 285 } 286 287 if ( (bufp=SDL_strrchr(appname, '.')) == NULL ) 288 n = SDL_strlen(appname); 289 else 290 n = (bufp-appname); 291 292 bufp = SDL_stack_alloc(char, n+1); 293 if ( bufp == NULL ) { 294 return OutOfMemory(); 295 } 296 SDL_strlcpy(bufp, appname, n+1); 297 appname = bufp; 298 299 /* Load SDL dynamic link library */ 300 if ( SDL_Init(SDL_INIT_NOPARACHUTE) < 0 ) { 301 ShowError("WinMain() error", SDL_GetError()); 302 return(FALSE); 303 } 304 atexit(cleanup_output); 305 atexit(cleanup); 306 307 /* Sam: 308 We still need to pass in the application handle so that 309 DirectInput will initialize properly when SDL_RegisterApp() 310 is called later in the video initialization. 311 */ 312 SDL_SetModuleHandle(GetModuleHandle(NULL)); 313 314 /* Run the application main() code */ 315 status = SDL_main(argc, argv); 316 317 /* Exit cleanly, calling atexit() functions */ 318 exit(status); 319 320 /* Hush little compiler, don't you cry... */ 321 return 0; 322 } 323 324 /* This is where execution begins [windowed apps] */ 325 #ifdef _WIN32_WCE 326 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPWSTR szCmdLine, int sw) 327 #else 328 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) 329 #endif 330 { 331 HMODULE handle; 332 char **argv; 333 int argc; 334 char *cmdline; 335 char *env_str; 336 #ifdef _WIN32_WCE 337 wchar_t *bufp; 338 int nLen; 339 #else 340 char *bufp; 341 size_t nLen; 342 #endif 343 344 /* Start up DDHELP.EXE before opening any files, so DDHELP doesn't 345 keep them open. This is a hack.. hopefully it will be fixed 346 someday. DDHELP.EXE starts up the first time DDRAW.DLL is loaded. 347 */ 348 handle = LoadLibrary(TEXT("DDRAW.DLL")); 349 if ( handle != NULL ) { 350 FreeLibrary(handle); 351 } 352 353 /* Check for stdio redirect settings and do the redirection */ 354 if ((env_str = SDL_getenv("SDL_STDIO_REDIRECT"))) { 355 if (SDL_atoi(env_str)) { 356 redirect_output(); 357 } 358 } 359 #ifndef NO_STDIO_REDIRECT 360 else { 361 redirect_output(); 362 } 363 #endif 364 365 #ifdef _WIN32_WCE 366 nLen = wcslen(szCmdLine)+128+1; 367 bufp = SDL_stack_alloc(wchar_t, nLen*2); 368 wcscpy (bufp, TEXT("\"")); 369 GetModuleFileName(NULL, bufp+1, 128-3); 370 wcscpy (bufp+wcslen(bufp), TEXT("\" ")); 371 wcsncpy(bufp+wcslen(bufp), szCmdLine,nLen-wcslen(bufp)); 372 nLen = wcslen(bufp)+1; 373 cmdline = SDL_stack_alloc(char, nLen); 374 if ( cmdline == NULL ) { 375 return OutOfMemory(); 376 } 377 WideCharToMultiByte(CP_ACP, 0, bufp, -1, cmdline, nLen, NULL, NULL); 378 #else 379 /* Grab the command line */ 380 bufp = GetCommandLine(); 381 nLen = SDL_strlen(bufp)+1; 382 cmdline = SDL_stack_alloc(char, nLen); 383 if ( cmdline == NULL ) { 384 return OutOfMemory(); 385 } 386 SDL_strlcpy(cmdline, bufp, nLen); 387 #endif 388 389 /* Parse it into argv and argc */ 390 argc = ParseCommandLine(cmdline, NULL); 391 argv = SDL_stack_alloc(char*, argc+1); 392 if ( argv == NULL ) { 393 return OutOfMemory(); 394 } 395 ParseCommandLine(cmdline, argv); 396 397 /* Run the main program (after a little SDL initialization) */ 398 console_main(argc, argv); 399 400 /* Hush little compiler, don't you cry... */ 401 return 0; 402 } 403