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
UnEscapeQuotes(char * arg)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 */
ParseCommandLine(char * cmdline,char ** argv)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 */
ShowError(const char * title,const char * 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 */
OutOfMemory(void)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... */
cleanup(void)156 static void cleanup(void)
157 {
158 SDL_Quit();
159 }
160
161 /* Remove the output files if there was no output written */
cleanup_output(void)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 */
redirect_output(void)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] */
console_main(int argc,char * argv[])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
WinMain(HINSTANCE hInst,HINSTANCE hPrev,LPWSTR szCmdLine,int sw)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