e14743d1 |
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 == '\\' ) ) { |
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 | HINSTANCE 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 | } |