2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2004 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
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 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 "@(#) $Id: SDL_main.c,v 1.1 2004-08-01 13:08:34 schaffner Exp $";
28 /* This file takes care of command line argument parsing, and stdio redirection
29 in the MacOS environment.
40 #if defined(__APPLE__) && defined(__MACH__)
41 #include <Carbon/Carbon.h>
42 #elif TARGET_API_MAC_CARBON
48 #include <Resources.h>
52 /* Include the SDL main definition header */
59 /* The standard output files */
60 #define STDOUT_FILE "stdout.txt"
61 #define STDERR_FILE "stderr.txt"
63 #if !defined(__MWERKS__) && !TARGET_API_MAC_CARBON
64 /* In MPW, the qd global has been removed from the libraries */
68 /* Structure for keeping prefs in 1 variable */
71 Str255 video_driver_name;
72 Boolean output_to_file;
75 /* See if the command key is held down at startup */
76 static Boolean CommandKeyIsDown(void)
82 if (((unsigned char *) theKeyMap)[6] & 0x80) {
88 /* Parse a command line buffer into arguments */
89 static int ParseCommandLine(char *cmdline, char **argv)
95 for ( bufp = cmdline; *bufp; ) {
96 /* Skip leading whitespace */
97 while ( isspace(*bufp) ) {
100 /* Skip over argument */
101 if ( *bufp == '"' ) {
110 while ( *bufp && (*bufp != '"') ) {
121 while ( *bufp && ! isspace(*bufp) ) {
138 /* Remove the output files if there was no output written */
139 static void cleanup_output(void)
144 /* Flush the output in case anything is queued */
148 /* See if the files have any output in them */
149 file = fopen(STDOUT_FILE, "rb");
151 empty = (fgetc(file) == EOF) ? 1 : 0;
157 file = fopen(STDERR_FILE, "rb");
159 empty = (fgetc(file) == EOF) ? 1 : 0;
167 static int getCurrentAppName (StrFileName name) {
169 ProcessSerialNumber process;
170 ProcessInfoRec process_info;
173 process.highLongOfPSN = 0;
174 process.lowLongOfPSN = kCurrentProcess;
175 process_info.processInfoLength = sizeof (process_info);
176 process_info.processName = NULL;
177 process_info.processAppSpec = &process_fsp;
179 if ( noErr != GetProcessInformation (&process, &process_info) )
182 memcpy (name, process_fsp.name, process_fsp.name[0] + 1);
186 static int getPrefsFile (FSSpec *prefs_fsp, int create) {
188 /* The prefs file name is the application name, possibly truncated, */
189 /* plus " Preferences */
191 #define SUFFIX " Preferences"
192 #define MAX_NAME 19 /* 31 - strlen (SUFFIX) */
194 short volume_ref_number;
196 StrFileName prefs_name;
197 StrFileName app_name;
199 /* Get Preferences folder - works with Multiple Users */
200 if ( noErr != FindFolder ( kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder,
201 &volume_ref_number, &directory_id) )
204 if ( ! getCurrentAppName (app_name) )
207 /* Truncate if name is too long */
208 if (app_name[0] > MAX_NAME )
209 app_name[0] = MAX_NAME;
211 memcpy (prefs_name + 1, app_name + 1, app_name[0]);
212 memcpy (prefs_name + app_name[0] + 1, SUFFIX, strlen (SUFFIX));
213 prefs_name[0] = app_name[0] + strlen (SUFFIX);
215 /* Make the file spec for prefs file */
216 if ( noErr != FSMakeFSSpec (volume_ref_number, directory_id, prefs_name, prefs_fsp) )
220 /* Create the prefs file */
221 memcpy (prefs_fsp->name, prefs_name, prefs_name[0] + 1);
222 prefs_fsp->parID = directory_id;
223 prefs_fsp->vRefNum = volume_ref_number;
225 FSpCreateResFile (prefs_fsp, '????', 'pref', 0);
227 if ( noErr != ResError () )
234 static int readPrefsResource (PrefsRecord *prefs) {
238 prefs_handle = Get1Resource( 'CLne', 128 );
240 if (prefs_handle != NULL) {
245 /* Get command line string */
246 memcpy (prefs->command_line, *prefs_handle, (*prefs_handle)[0]+1);
248 /* Get video driver name */
249 offset += (*prefs_handle)[0] + 1;
250 memcpy (prefs->video_driver_name, *prefs_handle + offset, (*prefs_handle)[offset] + 1);
252 /* Get save-to-file option (1 or 0) */
253 offset += (*prefs_handle)[offset] + 1;
254 prefs->output_to_file = (*prefs_handle)[offset];
256 ReleaseResource( prefs_handle );
258 return ResError() == noErr;
264 static int writePrefsResource (PrefsRecord *prefs, short resource_file) {
268 UseResFile (resource_file);
270 prefs_handle = Get1Resource ( 'CLne', 128 );
271 if (prefs_handle != NULL)
272 RemoveResource (prefs_handle);
274 prefs_handle = NewHandle ( prefs->command_line[0] + prefs->video_driver_name[0] + 4 );
275 if (prefs_handle != NULL) {
279 HLock (prefs_handle);
281 /* Command line text */
283 memcpy (*prefs_handle, prefs->command_line, prefs->command_line[0] + 1);
285 /* Video driver name */
286 offset += prefs->command_line[0] + 1;
287 memcpy (*prefs_handle + offset, prefs->video_driver_name, prefs->video_driver_name[0] + 1);
289 /* Output-to-file option */
290 offset += prefs->video_driver_name[0] + 1;
291 *( *((char**)prefs_handle) + offset) = (char)prefs->output_to_file;
292 *( *((char**)prefs_handle) + offset + 1) = 0;
294 AddResource (prefs_handle, 'CLne', 128, "\pCommand Line");
295 WriteResource (prefs_handle);
296 UpdateResFile (resource_file);
297 DisposeHandle (prefs_handle);
299 return ResError() == noErr;
305 static int readPreferences (PrefsRecord *prefs) {
310 /* Check for prefs file first */
311 if ( getPrefsFile (&prefs_fsp, 0) ) {
313 short prefs_resource;
315 prefs_resource = FSpOpenResFile (&prefs_fsp, fsRdPerm);
316 if ( prefs_resource == -1 ) /* this shouldn't happen, but... */
319 UseResFile (prefs_resource);
320 no_error = readPrefsResource (prefs);
321 CloseResFile (prefs_resource);
324 /* Fall back to application's resource fork (reading only, so this is safe) */
327 no_error = readPrefsResource (prefs);
333 static int writePreferences (PrefsRecord *prefs) {
338 /* Get prefs file, create if it doesn't exist */
339 if ( getPrefsFile (&prefs_fsp, 1) ) {
341 short prefs_resource;
343 prefs_resource = FSpOpenResFile (&prefs_fsp, fsRdWrPerm);
344 if (prefs_resource == -1)
346 no_error = writePrefsResource (prefs, prefs_resource);
347 CloseResFile (prefs_resource);
353 /* This is where execution begins */
354 int main(int argc, char *argv[])
357 #pragma unused(argc, argv)
359 #define DEFAULT_ARGS "\p" /* pascal string for default args */
360 #define DEFAULT_VIDEO_DRIVER "\ptoolbox" /* pascal string for default video driver name */
361 #define DEFAULT_OUTPUT_TO_FILE 1 /* 1 == output to file, 0 == no output */
363 #define VIDEO_ID_DRAWSPROCKET 1 /* these correspond to popup menu choices */
364 #define VIDEO_ID_TOOLBOX 2
366 PrefsRecord prefs = { DEFAULT_ARGS, DEFAULT_VIDEO_DRIVER, DEFAULT_OUTPUT_TO_FILE };
372 StrFileName appNameText;
373 int videodriver = VIDEO_ID_TOOLBOX;
374 int settingsChanged = 0;
378 /* Kyle's SDL command-line dialog code ... */
379 #if !TARGET_API_MAC_CARBON
380 InitGraf (&qd.thePort);
387 FlushEvents(everyEvent,0);
388 #if !TARGET_API_MAC_CARBON
394 /* Intialize SDL, and put up a dialog if we fail */
395 if ( SDL_Init (0) < 0 ) {
400 DialogPtr errorDialog;
406 errorDialog = GetNewDialog (1001, nil, (WindowPtr)-1);
407 DrawDialog (errorDialog);
409 GetDialogItem (errorDialog, kErr_Text, &dummyType, &dummyHandle, &dummyRect);
410 SetDialogItemText (dummyHandle, "\pError Initializing SDL");
412 SetPort (errorDialog);
414 ModalDialog (nil, &itemHit);
415 } while (itemHit != kErr_OK);
417 DisposeDialog (errorDialog);
420 atexit(cleanup_output);
424 /* Set up SDL's QuickDraw environment */
425 #if !TARGET_API_MAC_CARBON
426 SDL_InitQuickDraw(&qd);
429 if ( readPreferences (&prefs) ) {
431 if (memcmp (prefs.video_driver_name+1, "DSp", 3) == 0)
433 else if (memcmp (prefs.video_driver_name+1, "toolbox", 7) == 0)
437 if ( CommandKeyIsDown() ) {
445 DialogPtr commandDialog;
451 /* Assume that they will change settings, rather than do exhaustive check */
454 /* Create dialog and display it */
455 commandDialog = GetNewDialog (1000, nil, (WindowPtr)-1);
456 SetPortDialogPort (commandDialog);
459 GetDialogItem (commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
460 SetControlValue ((ControlHandle)dummyHandle, prefs.output_to_file );
462 GetDialogItem (commandDialog, kCL_Text, &dummyType, &dummyHandle, &dummyRect);
463 SetDialogItemText (dummyHandle, prefs.command_line);
465 GetDialogItem (commandDialog, kCL_Video, &dummyType, &dummyHandle, &dummyRect);
466 SetControlValue ((ControlRef)dummyHandle, videodriver);
468 SetDialogDefaultItem (commandDialog, kCL_OK);
469 SetDialogCancelItem (commandDialog, kCL_Cancel);
473 ModalDialog(nil, &itemHit); /* wait for user response */
475 /* Toggle command-line output checkbox */
476 if ( itemHit == kCL_File ) {
477 GetDialogItem(commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
478 SetControlValue((ControlHandle)dummyHandle, !GetControlValue((ControlHandle)dummyHandle) );
481 } while (itemHit != kCL_OK && itemHit != kCL_Cancel);
483 /* Get control values, even if they did not change */
484 GetDialogItem (commandDialog, kCL_Text, &dummyType, &dummyHandle, &dummyRect); /* MJS */
485 GetDialogItemText (dummyHandle, prefs.command_line);
487 GetDialogItem (commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
488 prefs.output_to_file = GetControlValue ((ControlHandle)dummyHandle);
490 GetDialogItem (commandDialog, kCL_Video, &dummyType, &dummyHandle, &dummyRect);
491 videodriver = GetControlValue ((ControlRef)dummyHandle);
493 DisposeDialog (commandDialog);
495 if (itemHit == kCL_Cancel ) {
500 /* Set pseudo-environment variables for video driver, update prefs */
501 switch ( videodriver ) {
502 case VIDEO_ID_DRAWSPROCKET:
503 putenv ("SDL_VIDEODRIVER=DSp");
504 memcpy (prefs.video_driver_name, "\pDSp", 4);
506 case VIDEO_ID_TOOLBOX:
507 putenv ("SDL_VIDEODRIVER=toolbox");
508 memcpy (prefs.video_driver_name, "\ptoolbox", 8);
511 /* Redirect standard I/O to files */
512 if ( prefs.output_to_file ) {
513 freopen (STDOUT_FILE, "w", stdout);
514 freopen (STDERR_FILE, "w", stderr);
520 if (settingsChanged) {
521 /* Save the prefs, even if they might not have changed (but probably did) */
522 if ( ! writePreferences (&prefs) )
523 fprintf (stderr, "WARNING: Could not save preferences!\n");
526 getCurrentAppName (appNameText); /* check for error here ? */
528 commandLine = (char*) malloc (appNameText[0] + prefs.command_line[0] + 2);
529 if ( commandLine == NULL ) {
533 /* Rather than rewrite ParseCommandLine method, let's replace */
534 /* any spaces in application name with underscores, */
535 /* so that the app name is only 1 argument */
536 for (i = 1; i < 1+appNameText[0]; i++)
537 if ( appNameText[i] == ' ' ) appNameText[i] = '_';
539 /* Copy app name & full command text to command-line C-string */
540 memcpy (commandLine, appNameText + 1, appNameText[0]);
541 commandLine[appNameText[0]] = ' ';
542 memcpy (commandLine + appNameText[0] + 1, prefs.command_line + 1, prefs.command_line[0]);
543 commandLine[ appNameText[0] + 1 + prefs.command_line[0] ] = '\0';
545 /* Parse C-string into argv and argc */
546 nargs = ParseCommandLine (commandLine, NULL);
547 args = (char **)malloc((nargs+1)*(sizeof *args));
548 if ( args == NULL ) {
551 ParseCommandLine (commandLine, args);
553 /* Run the main application code */
554 SDL_main(nargs, args);
558 /* Remove useless stdout.txt and stderr.txt */
561 /* Exit cleanly, calling atexit() functions */
564 /* Never reached, but keeps the compiler quiet */