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
23 /* This file takes care of command line argument parsing, and stdio redirection
24 in the MacOS environment.
35 #if defined(__APPLE__) && defined(__MACH__)
36 #include <Carbon/Carbon.h>
37 #elif TARGET_API_MAC_CARBON
43 #include <Resources.h>
47 /* Include the SDL main definition header */
54 /* The standard output files */
55 #define STDOUT_FILE "stdout.txt"
56 #define STDERR_FILE "stderr.txt"
58 #if !defined(__MWERKS__) && !TARGET_API_MAC_CARBON
59 /* In MPW, the qd global has been removed from the libraries */
63 /* Structure for keeping prefs in 1 variable */
66 Str255 video_driver_name;
67 Boolean output_to_file;
70 /* See if the command key is held down at startup */
71 static Boolean CommandKeyIsDown(void)
77 if (((unsigned char *) theKeyMap)[6] & 0x80) {
83 /* Parse a command line buffer into arguments */
84 static int ParseCommandLine(char *cmdline, char **argv)
90 for ( bufp = cmdline; *bufp; ) {
91 /* Skip leading whitespace */
92 while ( isspace(*bufp) ) {
95 /* Skip over argument */
105 while ( *bufp && (*bufp != '"') ) {
116 while ( *bufp && ! isspace(*bufp) ) {
133 /* Remove the output files if there was no output written */
134 static void cleanup_output(void)
139 /* Flush the output in case anything is queued */
143 /* See if the files have any output in them */
144 file = fopen(STDOUT_FILE, "rb");
146 empty = (fgetc(file) == EOF) ? 1 : 0;
152 file = fopen(STDERR_FILE, "rb");
154 empty = (fgetc(file) == EOF) ? 1 : 0;
162 static int getCurrentAppName (StrFileName name) {
164 ProcessSerialNumber process;
165 ProcessInfoRec process_info;
168 process.highLongOfPSN = 0;
169 process.lowLongOfPSN = kCurrentProcess;
170 process_info.processInfoLength = sizeof (process_info);
171 process_info.processName = NULL;
172 process_info.processAppSpec = &process_fsp;
174 if ( noErr != GetProcessInformation (&process, &process_info) )
177 memcpy (name, process_fsp.name, process_fsp.name[0] + 1);
181 static int getPrefsFile (FSSpec *prefs_fsp, int create) {
183 /* The prefs file name is the application name, possibly truncated, */
184 /* plus " Preferences */
186 #define SUFFIX " Preferences"
187 #define MAX_NAME 19 /* 31 - strlen (SUFFIX) */
189 short volume_ref_number;
191 StrFileName prefs_name;
192 StrFileName app_name;
194 /* Get Preferences folder - works with Multiple Users */
195 if ( noErr != FindFolder ( kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder,
196 &volume_ref_number, &directory_id) )
199 if ( ! getCurrentAppName (app_name) )
202 /* Truncate if name is too long */
203 if (app_name[0] > MAX_NAME )
204 app_name[0] = MAX_NAME;
206 memcpy (prefs_name + 1, app_name + 1, app_name[0]);
207 memcpy (prefs_name + app_name[0] + 1, SUFFIX, strlen (SUFFIX));
208 prefs_name[0] = app_name[0] + strlen (SUFFIX);
210 /* Make the file spec for prefs file */
211 if ( noErr != FSMakeFSSpec (volume_ref_number, directory_id, prefs_name, prefs_fsp) )
215 /* Create the prefs file */
216 memcpy (prefs_fsp->name, prefs_name, prefs_name[0] + 1);
217 prefs_fsp->parID = directory_id;
218 prefs_fsp->vRefNum = volume_ref_number;
220 FSpCreateResFile (prefs_fsp, '????', 'pref', 0);
222 if ( noErr != ResError () )
229 static int readPrefsResource (PrefsRecord *prefs) {
233 prefs_handle = Get1Resource( 'CLne', 128 );
235 if (prefs_handle != NULL) {
240 /* Get command line string */
241 memcpy (prefs->command_line, *prefs_handle, (*prefs_handle)[0]+1);
243 /* Get video driver name */
244 offset += (*prefs_handle)[0] + 1;
245 memcpy (prefs->video_driver_name, *prefs_handle + offset, (*prefs_handle)[offset] + 1);
247 /* Get save-to-file option (1 or 0) */
248 offset += (*prefs_handle)[offset] + 1;
249 prefs->output_to_file = (*prefs_handle)[offset];
251 ReleaseResource( prefs_handle );
253 return ResError() == noErr;
259 static int writePrefsResource (PrefsRecord *prefs, short resource_file) {
263 UseResFile (resource_file);
265 prefs_handle = Get1Resource ( 'CLne', 128 );
266 if (prefs_handle != NULL)
267 RemoveResource (prefs_handle);
269 prefs_handle = NewHandle ( prefs->command_line[0] + prefs->video_driver_name[0] + 4 );
270 if (prefs_handle != NULL) {
274 HLock (prefs_handle);
276 /* Command line text */
278 memcpy (*prefs_handle, prefs->command_line, prefs->command_line[0] + 1);
280 /* Video driver name */
281 offset += prefs->command_line[0] + 1;
282 memcpy (*prefs_handle + offset, prefs->video_driver_name, prefs->video_driver_name[0] + 1);
284 /* Output-to-file option */
285 offset += prefs->video_driver_name[0] + 1;
286 *( *((char**)prefs_handle) + offset) = (char)prefs->output_to_file;
287 *( *((char**)prefs_handle) + offset + 1) = 0;
289 AddResource (prefs_handle, 'CLne', 128, "\pCommand Line");
290 WriteResource (prefs_handle);
291 UpdateResFile (resource_file);
292 DisposeHandle (prefs_handle);
294 return ResError() == noErr;
300 static int readPreferences (PrefsRecord *prefs) {
305 /* Check for prefs file first */
306 if ( getPrefsFile (&prefs_fsp, 0) ) {
308 short prefs_resource;
310 prefs_resource = FSpOpenResFile (&prefs_fsp, fsRdPerm);
311 if ( prefs_resource == -1 ) /* this shouldn't happen, but... */
314 UseResFile (prefs_resource);
315 no_error = readPrefsResource (prefs);
316 CloseResFile (prefs_resource);
319 /* Fall back to application's resource fork (reading only, so this is safe) */
322 no_error = readPrefsResource (prefs);
328 static int writePreferences (PrefsRecord *prefs) {
333 /* Get prefs file, create if it doesn't exist */
334 if ( getPrefsFile (&prefs_fsp, 1) ) {
336 short prefs_resource;
338 prefs_resource = FSpOpenResFile (&prefs_fsp, fsRdWrPerm);
339 if (prefs_resource == -1)
341 no_error = writePrefsResource (prefs, prefs_resource);
342 CloseResFile (prefs_resource);
348 /* This is where execution begins */
349 int main(int argc, char *argv[])
352 #pragma unused(argc, argv)
354 #define DEFAULT_ARGS "\p" /* pascal string for default args */
355 #define DEFAULT_VIDEO_DRIVER "\ptoolbox" /* pascal string for default video driver name */
356 #define DEFAULT_OUTPUT_TO_FILE 1 /* 1 == output to file, 0 == no output */
358 #define VIDEO_ID_DRAWSPROCKET 1 /* these correspond to popup menu choices */
359 #define VIDEO_ID_TOOLBOX 2
361 PrefsRecord prefs = { DEFAULT_ARGS, DEFAULT_VIDEO_DRIVER, DEFAULT_OUTPUT_TO_FILE };
367 StrFileName appNameText;
368 int videodriver = VIDEO_ID_TOOLBOX;
369 int settingsChanged = 0;
373 /* Kyle's SDL command-line dialog code ... */
374 #if !TARGET_API_MAC_CARBON
375 InitGraf (&qd.thePort);
382 FlushEvents(everyEvent,0);
383 #if !TARGET_API_MAC_CARBON
389 /* Intialize SDL, and put up a dialog if we fail */
390 if ( SDL_Init (0) < 0 ) {
395 DialogPtr errorDialog;
401 errorDialog = GetNewDialog (1001, nil, (WindowPtr)-1);
402 DrawDialog (errorDialog);
404 GetDialogItem (errorDialog, kErr_Text, &dummyType, &dummyHandle, &dummyRect);
405 SetDialogItemText (dummyHandle, "\pError Initializing SDL");
407 SetPort (errorDialog);
409 ModalDialog (nil, &itemHit);
410 } while (itemHit != kErr_OK);
412 DisposeDialog (errorDialog);
415 atexit(cleanup_output);
419 /* Set up SDL's QuickDraw environment */
420 #if !TARGET_API_MAC_CARBON
421 SDL_InitQuickDraw(&qd);
424 if ( readPreferences (&prefs) ) {
426 if (memcmp (prefs.video_driver_name+1, "DSp", 3) == 0)
428 else if (memcmp (prefs.video_driver_name+1, "toolbox", 7) == 0)
432 if ( CommandKeyIsDown() ) {
440 DialogPtr commandDialog;
446 /* Assume that they will change settings, rather than do exhaustive check */
449 /* Create dialog and display it */
450 commandDialog = GetNewDialog (1000, nil, (WindowPtr)-1);
451 SetPortDialogPort (commandDialog);
454 GetDialogItem (commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
455 SetControlValue ((ControlHandle)dummyHandle, prefs.output_to_file );
457 GetDialogItem (commandDialog, kCL_Text, &dummyType, &dummyHandle, &dummyRect);
458 SetDialogItemText (dummyHandle, prefs.command_line);
460 GetDialogItem (commandDialog, kCL_Video, &dummyType, &dummyHandle, &dummyRect);
461 SetControlValue ((ControlRef)dummyHandle, videodriver);
463 SetDialogDefaultItem (commandDialog, kCL_OK);
464 SetDialogCancelItem (commandDialog, kCL_Cancel);
468 ModalDialog(nil, &itemHit); /* wait for user response */
470 /* Toggle command-line output checkbox */
471 if ( itemHit == kCL_File ) {
472 GetDialogItem(commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
473 SetControlValue((ControlHandle)dummyHandle, !GetControlValue((ControlHandle)dummyHandle) );
476 } while (itemHit != kCL_OK && itemHit != kCL_Cancel);
478 /* Get control values, even if they did not change */
479 GetDialogItem (commandDialog, kCL_Text, &dummyType, &dummyHandle, &dummyRect); /* MJS */
480 GetDialogItemText (dummyHandle, prefs.command_line);
482 GetDialogItem (commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
483 prefs.output_to_file = GetControlValue ((ControlHandle)dummyHandle);
485 GetDialogItem (commandDialog, kCL_Video, &dummyType, &dummyHandle, &dummyRect);
486 videodriver = GetControlValue ((ControlRef)dummyHandle);
488 DisposeDialog (commandDialog);
490 if (itemHit == kCL_Cancel ) {
495 /* Set pseudo-environment variables for video driver, update prefs */
496 switch ( videodriver ) {
497 case VIDEO_ID_DRAWSPROCKET:
498 putenv ("SDL_VIDEODRIVER=DSp");
499 memcpy (prefs.video_driver_name, "\pDSp", 4);
501 case VIDEO_ID_TOOLBOX:
502 putenv ("SDL_VIDEODRIVER=toolbox");
503 memcpy (prefs.video_driver_name, "\ptoolbox", 8);
506 /* Redirect standard I/O to files */
507 if ( prefs.output_to_file ) {
508 freopen (STDOUT_FILE, "w", stdout);
509 freopen (STDERR_FILE, "w", stderr);
515 if (settingsChanged) {
516 /* Save the prefs, even if they might not have changed (but probably did) */
517 if ( ! writePreferences (&prefs) )
518 fprintf (stderr, "WARNING: Could not save preferences!\n");
521 getCurrentAppName (appNameText); /* check for error here ? */
523 commandLine = (char*) malloc (appNameText[0] + prefs.command_line[0] + 2);
524 if ( commandLine == NULL ) {
528 /* Rather than rewrite ParseCommandLine method, let's replace */
529 /* any spaces in application name with underscores, */
530 /* so that the app name is only 1 argument */
531 for (i = 1; i < 1+appNameText[0]; i++)
532 if ( appNameText[i] == ' ' ) appNameText[i] = '_';
534 /* Copy app name & full command text to command-line C-string */
535 memcpy (commandLine, appNameText + 1, appNameText[0]);
536 commandLine[appNameText[0]] = ' ';
537 memcpy (commandLine + appNameText[0] + 1, prefs.command_line + 1, prefs.command_line[0]);
538 commandLine[ appNameText[0] + 1 + prefs.command_line[0] ] = '\0';
540 /* Parse C-string into argv and argc */
541 nargs = ParseCommandLine (commandLine, NULL);
542 args = (char **)malloc((nargs+1)*(sizeof *args));
543 if ( args == NULL ) {
546 ParseCommandLine (commandLine, args);
548 /* Run the main application code */
549 SDL_main(nargs, args);
553 /* Remove useless stdout.txt and stderr.txt */
556 /* Exit cleanly, calling atexit() functions */
559 /* Never reached, but keeps the compiler quiet */