SDL-1.2.14
[sdl_omap.git] / src / main / macos / SDL_main.c
CommitLineData
e14743d1 1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 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
23/* This file takes care of command line argument parsing, and stdio redirection
24 in the MacOS environment. (stdio/stderr is *not* directed for Mach-O builds)
25 */
26
27#if defined(__APPLE__) && defined(__MACH__)
28#include <Carbon/Carbon.h>
29#elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
30#include <Carbon.h>
31#else
32#include <Dialogs.h>
33#include <Fonts.h>
34#include <Events.h>
35#include <Resources.h>
36#include <Folders.h>
37#endif
38
39/* Include the SDL main definition header */
40#include "SDL.h"
41#include "SDL_main.h"
42#ifdef main
43#undef main
44#endif
45
46#if !(defined(__APPLE__) && defined(__MACH__))
47/* The standard output files */
48#define STDOUT_FILE "stdout.txt"
49#define STDERR_FILE "stderr.txt"
50#endif
51
52#if !defined(__MWERKS__) && !TARGET_API_MAC_CARBON
53 /* In MPW, the qd global has been removed from the libraries */
54 QDGlobals qd;
55#endif
56
57/* Structure for keeping prefs in 1 variable */
58typedef struct {
59 Str255 command_line;
60 Str255 video_driver_name;
61 Boolean output_to_file;
62} PrefsRecord;
63
64/* See if the command key is held down at startup */
65static Boolean CommandKeyIsDown(void)
66{
67 KeyMap theKeyMap;
68
69 GetKeys(theKeyMap);
70
71 if (((unsigned char *) theKeyMap)[6] & 0x80) {
72 return(true);
73 }
74 return(false);
75}
76
77#if !(defined(__APPLE__) && defined(__MACH__))
78
79/* Parse a command line buffer into arguments */
80static int ParseCommandLine(char *cmdline, char **argv)
81{
82 char *bufp;
83 int argc;
84
85 argc = 0;
86 for ( bufp = cmdline; *bufp; ) {
87 /* Skip leading whitespace */
88 while ( SDL_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 != '"') ) {
102 ++bufp;
103 }
104 } else {
105 if ( *bufp ) {
106 if ( argv ) {
107 argv[argc] = bufp;
108 }
109 ++argc;
110 }
111 /* Skip over word */
112 while ( *bufp && ! SDL_isspace(*bufp) ) {
113 ++bufp;
114 }
115 }
116 if ( *bufp ) {
117 if ( argv ) {
118 *bufp = '\0';
119 }
120 ++bufp;
121 }
122 }
123 if ( argv ) {
124 argv[argc] = NULL;
125 }
126 return(argc);
127}
128
129/* Remove the output files if there was no output written */
130static void cleanup_output(void)
131{
132 FILE *file;
133 int empty;
134
135 /* Flush the output in case anything is queued */
136 fclose(stdout);
137 fclose(stderr);
138
139 /* See if the files have any output in them */
140 file = fopen(STDOUT_FILE, "rb");
141 if ( file ) {
142 empty = (fgetc(file) == EOF) ? 1 : 0;
143 fclose(file);
144 if ( empty ) {
145 remove(STDOUT_FILE);
146 }
147 }
148 file = fopen(STDERR_FILE, "rb");
149 if ( file ) {
150 empty = (fgetc(file) == EOF) ? 1 : 0;
151 fclose(file);
152 if ( empty ) {
153 remove(STDERR_FILE);
154 }
155 }
156}
157
158#endif //!(defined(__APPLE__) && defined(__MACH__))
159
160static int getCurrentAppName (StrFileName name) {
161
162 ProcessSerialNumber process;
163 ProcessInfoRec process_info;
164 FSSpec process_fsp;
165
166 process.highLongOfPSN = 0;
167 process.lowLongOfPSN = kCurrentProcess;
168 process_info.processInfoLength = sizeof (process_info);
169 process_info.processName = NULL;
170 process_info.processAppSpec = &process_fsp;
171
172 if ( noErr != GetProcessInformation (&process, &process_info) )
173 return 0;
174
175 SDL_memcpy(name, process_fsp.name, process_fsp.name[0] + 1);
176 return 1;
177}
178
179static int getPrefsFile (FSSpec *prefs_fsp, int create) {
180
181 /* The prefs file name is the application name, possibly truncated, */
182 /* plus " Preferences */
183
184 #define SUFFIX " Preferences"
185 #define MAX_NAME 19 /* 31 - strlen (SUFFIX) */
186
187 short volume_ref_number;
188 long directory_id;
189 StrFileName prefs_name;
190 StrFileName app_name;
191
192 /* Get Preferences folder - works with Multiple Users */
193 if ( noErr != FindFolder ( kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder,
194 &volume_ref_number, &directory_id) )
195 exit (-1);
196
197 if ( ! getCurrentAppName (app_name) )
198 exit (-1);
199
200 /* Truncate if name is too long */
201 if (app_name[0] > MAX_NAME )
202 app_name[0] = MAX_NAME;
203
204 SDL_memcpy(prefs_name + 1, app_name + 1, app_name[0]);
205 SDL_memcpy(prefs_name + app_name[0] + 1, SUFFIX, strlen (SUFFIX));
206 prefs_name[0] = app_name[0] + strlen (SUFFIX);
207
208 /* Make the file spec for prefs file */
209 if ( noErr != FSMakeFSSpec (volume_ref_number, directory_id, prefs_name, prefs_fsp) ) {
210 if ( !create )
211 return 0;
212 else {
213 /* Create the prefs file */
214 SDL_memcpy(prefs_fsp->name, prefs_name, prefs_name[0] + 1);
215 prefs_fsp->parID = directory_id;
216 prefs_fsp->vRefNum = volume_ref_number;
217
218 FSpCreateResFile (prefs_fsp, 0x3f3f3f3f, 'pref', 0); // '????' parsed as trigraph
219
220 if ( noErr != ResError () )
221 return 0;
222 }
223 }
224 return 1;
225}
226
227static int readPrefsResource (PrefsRecord *prefs) {
228
229 Handle prefs_handle;
230
231 prefs_handle = Get1Resource( 'CLne', 128 );
232
233 if (prefs_handle != NULL) {
234 int offset = 0;
235// int j = 0;
236
237 HLock(prefs_handle);
238
239 /* Get command line string */
240 SDL_memcpy(prefs->command_line, *prefs_handle, (*prefs_handle)[0]+1);
241
242 /* Get video driver name */
243 offset += (*prefs_handle)[0] + 1;
244 SDL_memcpy(prefs->video_driver_name, *prefs_handle + offset, (*prefs_handle)[offset] + 1);
245
246 /* Get save-to-file option (1 or 0) */
247 offset += (*prefs_handle)[offset] + 1;
248 prefs->output_to_file = (*prefs_handle)[offset];
249
250 ReleaseResource( prefs_handle );
251
252 return ResError() == noErr;
253 }
254
255 return 0;
256}
257
258static int writePrefsResource (PrefsRecord *prefs, short resource_file) {
259
260 Handle prefs_handle;
261
262 UseResFile (resource_file);
263
264 prefs_handle = Get1Resource ( 'CLne', 128 );
265 if (prefs_handle != NULL)
266 RemoveResource (prefs_handle);
267
268 prefs_handle = NewHandle ( prefs->command_line[0] + prefs->video_driver_name[0] + 4 );
269 if (prefs_handle != NULL) {
270
271 int offset;
272
273 HLock (prefs_handle);
274
275 /* Command line text */
276 offset = 0;
277 SDL_memcpy(*prefs_handle, prefs->command_line, prefs->command_line[0] + 1);
278
279 /* Video driver name */
280 offset += prefs->command_line[0] + 1;
281 SDL_memcpy(*prefs_handle + offset, prefs->video_driver_name, prefs->video_driver_name[0] + 1);
282
283 /* Output-to-file option */
284 offset += prefs->video_driver_name[0] + 1;
285 *( *((char**)prefs_handle) + offset) = (char)prefs->output_to_file;
286 *( *((char**)prefs_handle) + offset + 1) = 0;
287
288 AddResource (prefs_handle, 'CLne', 128, "\pCommand Line");
289 WriteResource (prefs_handle);
290 UpdateResFile (resource_file);
291 DisposeHandle (prefs_handle);
292
293 return ResError() == noErr;
294 }
295
296 return 0;
297}
298
299static int readPreferences (PrefsRecord *prefs) {
300
301 int no_error = 1;
302 FSSpec prefs_fsp;
303
304 /* Check for prefs file first */
305 if ( getPrefsFile (&prefs_fsp, 0) ) {
306
307 short prefs_resource;
308
309 prefs_resource = FSpOpenResFile (&prefs_fsp, fsRdPerm);
310 if ( prefs_resource == -1 ) /* this shouldn't happen, but... */
311 return 0;
312
313 UseResFile (prefs_resource);
314 no_error = readPrefsResource (prefs);
315 CloseResFile (prefs_resource);
316 }
317
318 /* Fall back to application's resource fork (reading only, so this is safe) */
319 else {
320
321 no_error = readPrefsResource (prefs);
322 }
323
324 return no_error;
325}
326
327static int writePreferences (PrefsRecord *prefs) {
328
329 int no_error = 1;
330 FSSpec prefs_fsp;
331
332 /* Get prefs file, create if it doesn't exist */
333 if ( getPrefsFile (&prefs_fsp, 1) ) {
334
335 short prefs_resource;
336
337 prefs_resource = FSpOpenResFile (&prefs_fsp, fsRdWrPerm);
338 if (prefs_resource == -1)
339 return 0;
340 no_error = writePrefsResource (prefs, prefs_resource);
341 CloseResFile (prefs_resource);
342 }
343
344 return no_error;
345}
346
347/* This is where execution begins */
348int main(int argc, char *argv[])
349{
350
351#if !(defined(__APPLE__) && defined(__MACH__))
352#pragma unused(argc, argv)
353#endif
354
355#define DEFAULT_ARGS "\p" /* pascal string for default args */
356#define DEFAULT_VIDEO_DRIVER "\ptoolbox" /* pascal string for default video driver name */
357#define DEFAULT_OUTPUT_TO_FILE 1 /* 1 == output to file, 0 == no output */
358
359#define VIDEO_ID_DRAWSPROCKET 1 /* these correspond to popup menu choices */
360#define VIDEO_ID_TOOLBOX 2
361
362 PrefsRecord prefs = { DEFAULT_ARGS, DEFAULT_VIDEO_DRIVER, DEFAULT_OUTPUT_TO_FILE };
363
364#if !(defined(__APPLE__) && defined(__MACH__))
365 int nargs;
366 char **args;
367 char *commandLine;
368
369 StrFileName appNameText;
370#endif
371 int videodriver = VIDEO_ID_TOOLBOX;
372 int settingsChanged = 0;
373
374 long i;
375
376 /* Kyle's SDL command-line dialog code ... */
377#if !TARGET_API_MAC_CARBON
378 InitGraf (&qd.thePort);
379 InitFonts ();
380 InitWindows ();
381 InitMenus ();
382 InitDialogs (nil);
383#endif
384 InitCursor ();
385 FlushEvents(everyEvent,0);
386#if !TARGET_API_MAC_CARBON
387 MaxApplZone ();
388#endif
389 MoreMasters ();
390 MoreMasters ();
391#if 0
392 /* Intialize SDL, and put up a dialog if we fail */
393 if ( SDL_Init (0) < 0 ) {
394
395#define kErr_OK 1
396#define kErr_Text 2
397
398 DialogPtr errorDialog;
399 short dummyType;
400 Rect dummyRect;
401 Handle dummyHandle;
402 short itemHit;
403
404 errorDialog = GetNewDialog (1001, nil, (WindowPtr)-1);
405 if (errorDialog == NULL)
406 return -1;
407 DrawDialog (errorDialog);
408
409 GetDialogItem (errorDialog, kErr_Text, &dummyType, &dummyHandle, &dummyRect);
410 SetDialogItemText (dummyHandle, "\pError Initializing SDL");
411
412#if TARGET_API_MAC_CARBON
413 SetPort (GetDialogPort(errorDialog));
414#else
415 SetPort (errorDialog);
416#endif
417 do {
418 ModalDialog (nil, &itemHit);
419 } while (itemHit != kErr_OK);
420
421 DisposeDialog (errorDialog);
422 exit (-1);
423 }
424 atexit(cleanup_output);
425 atexit(SDL_Quit);
426#endif
427
428/* Set up SDL's QuickDraw environment */
429#if !TARGET_API_MAC_CARBON
430 SDL_InitQuickDraw(&qd);
431#endif
432
433 if ( readPreferences (&prefs) ) {
434
435 if (SDL_memcmp(prefs.video_driver_name+1, "DSp", 3) == 0)
436 videodriver = 1;
437 else if (SDL_memcmp(prefs.video_driver_name+1, "toolbox", 7) == 0)
438 videodriver = 2;
439 }
440
441 if ( CommandKeyIsDown() ) {
442
443#define kCL_OK 1
444#define kCL_Cancel 2
445#define kCL_Text 3
446#define kCL_File 4
447#define kCL_Video 6
448
449 DialogPtr commandDialog;
450 short dummyType;
451 Rect dummyRect;
452 Handle dummyHandle;
453 short itemHit;
454 #if TARGET_API_MAC_CARBON
455 ControlRef control;
456 #endif
457
458 /* Assume that they will change settings, rather than do exhaustive check */
459 settingsChanged = 1;
460
461 /* Create dialog and display it */
462 commandDialog = GetNewDialog (1000, nil, (WindowPtr)-1);
463 #if TARGET_API_MAC_CARBON
464 SetPort ( GetDialogPort(commandDialog) );
465 #else
466 SetPort (commandDialog);
467 #endif
468
469 /* Setup controls */
470 #if TARGET_API_MAC_CARBON
471 GetDialogItemAsControl(commandDialog, kCL_File, &control);
472 SetControlValue (control, prefs.output_to_file);
473 #else
474 GetDialogItem (commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
475 SetControlValue ((ControlHandle)dummyHandle, prefs.output_to_file );
476 #endif
477
478 GetDialogItem (commandDialog, kCL_Text, &dummyType, &dummyHandle, &dummyRect);
479 SetDialogItemText (dummyHandle, prefs.command_line);
480
481 #if TARGET_API_MAC_CARBON
482 GetDialogItemAsControl(commandDialog, kCL_Video, &control);
483 SetControlValue (control, videodriver);
484 #else
485 GetDialogItem (commandDialog, kCL_Video, &dummyType, &dummyHandle, &dummyRect);
486 SetControlValue ((ControlRef)dummyHandle, videodriver);
487 #endif
488
489 SetDialogDefaultItem (commandDialog, kCL_OK);
490 SetDialogCancelItem (commandDialog, kCL_Cancel);
491
492 do {
493
494 ModalDialog(nil, &itemHit); /* wait for user response */
495
496 /* Toggle command-line output checkbox */
497 if ( itemHit == kCL_File ) {
498 #if TARGET_API_MAC_CARBON
499 GetDialogItemAsControl(commandDialog, kCL_File, &control);
500 SetControlValue (control, !GetControlValue(control));
501 #else
502 GetDialogItem(commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
503 SetControlValue((ControlHandle)dummyHandle, !GetControlValue((ControlHandle)dummyHandle) );
504 #endif
505 }
506
507 } while (itemHit != kCL_OK && itemHit != kCL_Cancel);
508
509 /* Get control values, even if they did not change */
510 GetDialogItem (commandDialog, kCL_Text, &dummyType, &dummyHandle, &dummyRect); /* MJS */
511 GetDialogItemText (dummyHandle, prefs.command_line);
512
513 #if TARGET_API_MAC_CARBON
514 GetDialogItemAsControl(commandDialog, kCL_File, &control);
515 prefs.output_to_file = GetControlValue(control);
516 #else
517 GetDialogItem (commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
518 prefs.output_to_file = GetControlValue ((ControlHandle)dummyHandle);
519 #endif
520
521 #if TARGET_API_MAC_CARBON
522 GetDialogItemAsControl(commandDialog, kCL_Video, &control);
523 videodriver = GetControlValue(control);
524 #else
525 GetDialogItem (commandDialog, kCL_Video, &dummyType, &dummyHandle, &dummyRect);
526 videodriver = GetControlValue ((ControlRef)dummyHandle);
527 #endif
528
529 DisposeDialog (commandDialog);
530
531 if (itemHit == kCL_Cancel ) {
532 exit (0);
533 }
534 }
535
536 /* Set pseudo-environment variables for video driver, update prefs */
537 switch ( videodriver ) {
538 case VIDEO_ID_DRAWSPROCKET:
539 SDL_putenv("SDL_VIDEODRIVER=DSp");
540 SDL_memcpy(prefs.video_driver_name, "\pDSp", 4);
541 break;
542 case VIDEO_ID_TOOLBOX:
543 SDL_putenv("SDL_VIDEODRIVER=toolbox");
544 SDL_memcpy(prefs.video_driver_name, "\ptoolbox", 8);
545 break;
546 }
547
548#if !(defined(__APPLE__) && defined(__MACH__))
549 /* Redirect standard I/O to files */
550 if ( prefs.output_to_file ) {
551 freopen (STDOUT_FILE, "w", stdout);
552 freopen (STDERR_FILE, "w", stderr);
553 } else {
554 fclose (stdout);
555 fclose (stderr);
556 }
557#endif
558
559 if (settingsChanged) {
560 /* Save the prefs, even if they might not have changed (but probably did) */
561 if ( ! writePreferences (&prefs) )
562 fprintf (stderr, "WARNING: Could not save preferences!\n");
563 }
564
565#if !(defined(__APPLE__) && defined(__MACH__))
566 appNameText[0] = 0;
567 getCurrentAppName (appNameText); /* check for error here ? */
568
569 commandLine = (char*) malloc (appNameText[0] + prefs.command_line[0] + 2);
570 if ( commandLine == NULL ) {
571 exit(-1);
572 }
573
574 /* Rather than rewrite ParseCommandLine method, let's replace */
575 /* any spaces in application name with underscores, */
576 /* so that the app name is only 1 argument */
577 for (i = 1; i < 1+appNameText[0]; i++)
578 if ( appNameText[i] == ' ' ) appNameText[i] = '_';
579
580 /* Copy app name & full command text to command-line C-string */
581 SDL_memcpy(commandLine, appNameText + 1, appNameText[0]);
582 commandLine[appNameText[0]] = ' ';
583 SDL_memcpy(commandLine + appNameText[0] + 1, prefs.command_line + 1, prefs.command_line[0]);
584 commandLine[ appNameText[0] + 1 + prefs.command_line[0] ] = '\0';
585
586 /* Parse C-string into argv and argc */
587 nargs = ParseCommandLine (commandLine, NULL);
588 args = (char **)malloc((nargs+1)*(sizeof *args));
589 if ( args == NULL ) {
590 exit(-1);
591 }
592 ParseCommandLine (commandLine, args);
593
594 /* Run the main application code */
595 SDL_main(nargs, args);
596 free (args);
597 free (commandLine);
598
599 /* Remove useless stdout.txt and stderr.txt */
600 cleanup_output ();
601#else // defined(__APPLE__) && defined(__MACH__)
602 SDL_main(argc, argv);
603#endif
604
605 /* Exit cleanly, calling atexit() functions */
606 exit (0);
607
608 /* Never reached, but keeps the compiler quiet */
609 return (0);
610}