| /* |
| SDL - Simple DirectMedia Layer |
| Copyright (C) 1997-2012 Sam Lantinga |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 of the License, or (at your option) any later version. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with this library; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| |
| Sam Lantinga |
| slouken@libsdl.org |
| */ |
| |
| /* This file takes care of command line argument parsing, and stdio redirection |
| in the MacOS environment. (stdio/stderr is *not* directed for Mach-O builds) |
| */ |
| |
| #if defined(__APPLE__) && defined(__MACH__) |
| #include <Carbon/Carbon.h> |
| #elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335) |
| #include <Carbon.h> |
| #else |
| #include <Dialogs.h> |
| #include <Fonts.h> |
| #include <Events.h> |
| #include <Resources.h> |
| #include <Folders.h> |
| #endif |
| |
| /* Include the SDL main definition header */ |
| #include "SDL.h" |
| #include "SDL_main.h" |
| #ifdef main |
| #undef main |
| #endif |
| |
| #if !(defined(__APPLE__) && defined(__MACH__)) |
| /* The standard output files */ |
| #define STDOUT_FILE "stdout.txt" |
| #define STDERR_FILE "stderr.txt" |
| #endif |
| |
| #if !defined(__MWERKS__) && !TARGET_API_MAC_CARBON |
| /* In MPW, the qd global has been removed from the libraries */ |
| QDGlobals qd; |
| #endif |
| |
| /* Structure for keeping prefs in 1 variable */ |
| typedef struct { |
| Str255 command_line; |
| Str255 video_driver_name; |
| Boolean output_to_file; |
| } PrefsRecord; |
| |
| /* See if the command key is held down at startup */ |
| static Boolean CommandKeyIsDown(void) |
| { |
| KeyMap theKeyMap; |
| |
| GetKeys(theKeyMap); |
| |
| if (((unsigned char *) theKeyMap)[6] & 0x80) { |
| return(true); |
| } |
| return(false); |
| } |
| |
| #if !(defined(__APPLE__) && defined(__MACH__)) |
| |
| /* Parse a command line buffer into arguments */ |
| static int ParseCommandLine(char *cmdline, char **argv) |
| { |
| char *bufp; |
| int argc; |
| |
| argc = 0; |
| for ( bufp = cmdline; *bufp; ) { |
| /* Skip leading whitespace */ |
| while ( SDL_isspace(*bufp) ) { |
| ++bufp; |
| } |
| /* Skip over argument */ |
| if ( *bufp == '"' ) { |
| ++bufp; |
| if ( *bufp ) { |
| if ( argv ) { |
| argv[argc] = bufp; |
| } |
| ++argc; |
| } |
| /* Skip over word */ |
| while ( *bufp && (*bufp != '"') ) { |
| ++bufp; |
| } |
| } else { |
| if ( *bufp ) { |
| if ( argv ) { |
| argv[argc] = bufp; |
| } |
| ++argc; |
| } |
| /* Skip over word */ |
| while ( *bufp && ! SDL_isspace(*bufp) ) { |
| ++bufp; |
| } |
| } |
| if ( *bufp ) { |
| if ( argv ) { |
| *bufp = '\0'; |
| } |
| ++bufp; |
| } |
| } |
| if ( argv ) { |
| argv[argc] = NULL; |
| } |
| return(argc); |
| } |
| |
| /* Remove the output files if there was no output written */ |
| static void cleanup_output(void) |
| { |
| FILE *file; |
| int empty; |
| |
| /* Flush the output in case anything is queued */ |
| fclose(stdout); |
| fclose(stderr); |
| |
| /* See if the files have any output in them */ |
| file = fopen(STDOUT_FILE, "rb"); |
| if ( file ) { |
| empty = (fgetc(file) == EOF) ? 1 : 0; |
| fclose(file); |
| if ( empty ) { |
| remove(STDOUT_FILE); |
| } |
| } |
| file = fopen(STDERR_FILE, "rb"); |
| if ( file ) { |
| empty = (fgetc(file) == EOF) ? 1 : 0; |
| fclose(file); |
| if ( empty ) { |
| remove(STDERR_FILE); |
| } |
| } |
| } |
| |
| #endif //!(defined(__APPLE__) && defined(__MACH__)) |
| |
| static int getCurrentAppName (StrFileName name) { |
| |
| ProcessSerialNumber process; |
| ProcessInfoRec process_info; |
| FSSpec process_fsp; |
| |
| process.highLongOfPSN = 0; |
| process.lowLongOfPSN = kCurrentProcess; |
| process_info.processInfoLength = sizeof (process_info); |
| process_info.processName = NULL; |
| process_info.processAppSpec = &process_fsp; |
| |
| if ( noErr != GetProcessInformation (&process, &process_info) ) |
| return 0; |
| |
| SDL_memcpy(name, process_fsp.name, process_fsp.name[0] + 1); |
| return 1; |
| } |
| |
| static int getPrefsFile (FSSpec *prefs_fsp, int create) { |
| |
| /* The prefs file name is the application name, possibly truncated, */ |
| /* plus " Preferences */ |
| |
| #define SUFFIX " Preferences" |
| #define MAX_NAME 19 /* 31 - strlen (SUFFIX) */ |
| |
| short volume_ref_number; |
| long directory_id; |
| StrFileName prefs_name; |
| StrFileName app_name; |
| |
| /* Get Preferences folder - works with Multiple Users */ |
| if ( noErr != FindFolder ( kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder, |
| &volume_ref_number, &directory_id) ) |
| exit (-1); |
| |
| if ( ! getCurrentAppName (app_name) ) |
| exit (-1); |
| |
| /* Truncate if name is too long */ |
| if (app_name[0] > MAX_NAME ) |
| app_name[0] = MAX_NAME; |
| |
| SDL_memcpy(prefs_name + 1, app_name + 1, app_name[0]); |
| SDL_memcpy(prefs_name + app_name[0] + 1, SUFFIX, strlen (SUFFIX)); |
| prefs_name[0] = app_name[0] + strlen (SUFFIX); |
| |
| /* Make the file spec for prefs file */ |
| if ( noErr != FSMakeFSSpec (volume_ref_number, directory_id, prefs_name, prefs_fsp) ) { |
| if ( !create ) |
| return 0; |
| else { |
| /* Create the prefs file */ |
| SDL_memcpy(prefs_fsp->name, prefs_name, prefs_name[0] + 1); |
| prefs_fsp->parID = directory_id; |
| prefs_fsp->vRefNum = volume_ref_number; |
| |
| FSpCreateResFile (prefs_fsp, 0x3f3f3f3f, 'pref', 0); // '????' parsed as trigraph |
| |
| if ( noErr != ResError () ) |
| return 0; |
| } |
| } |
| return 1; |
| } |
| |
| static int readPrefsResource (PrefsRecord *prefs) { |
| |
| Handle prefs_handle; |
| |
| prefs_handle = Get1Resource( 'CLne', 128 ); |
| |
| if (prefs_handle != NULL) { |
| int offset = 0; |
| // int j = 0; |
| |
| HLock(prefs_handle); |
| |
| /* Get command line string */ |
| SDL_memcpy(prefs->command_line, *prefs_handle, (*prefs_handle)[0]+1); |
| |
| /* Get video driver name */ |
| offset += (*prefs_handle)[0] + 1; |
| SDL_memcpy(prefs->video_driver_name, *prefs_handle + offset, (*prefs_handle)[offset] + 1); |
| |
| /* Get save-to-file option (1 or 0) */ |
| offset += (*prefs_handle)[offset] + 1; |
| prefs->output_to_file = (*prefs_handle)[offset]; |
| |
| ReleaseResource( prefs_handle ); |
| |
| return ResError() == noErr; |
| } |
| |
| return 0; |
| } |
| |
| static int writePrefsResource (PrefsRecord *prefs, short resource_file) { |
| |
| Handle prefs_handle; |
| |
| UseResFile (resource_file); |
| |
| prefs_handle = Get1Resource ( 'CLne', 128 ); |
| if (prefs_handle != NULL) |
| RemoveResource (prefs_handle); |
| |
| prefs_handle = NewHandle ( prefs->command_line[0] + prefs->video_driver_name[0] + 4 ); |
| if (prefs_handle != NULL) { |
| |
| int offset; |
| |
| HLock (prefs_handle); |
| |
| /* Command line text */ |
| offset = 0; |
| SDL_memcpy(*prefs_handle, prefs->command_line, prefs->command_line[0] + 1); |
| |
| /* Video driver name */ |
| offset += prefs->command_line[0] + 1; |
| SDL_memcpy(*prefs_handle + offset, prefs->video_driver_name, prefs->video_driver_name[0] + 1); |
| |
| /* Output-to-file option */ |
| offset += prefs->video_driver_name[0] + 1; |
| *( *((char**)prefs_handle) + offset) = (char)prefs->output_to_file; |
| *( *((char**)prefs_handle) + offset + 1) = 0; |
| |
| AddResource (prefs_handle, 'CLne', 128, "\pCommand Line"); |
| WriteResource (prefs_handle); |
| UpdateResFile (resource_file); |
| DisposeHandle (prefs_handle); |
| |
| return ResError() == noErr; |
| } |
| |
| return 0; |
| } |
| |
| static int readPreferences (PrefsRecord *prefs) { |
| |
| int no_error = 1; |
| FSSpec prefs_fsp; |
| |
| /* Check for prefs file first */ |
| if ( getPrefsFile (&prefs_fsp, 0) ) { |
| |
| short prefs_resource; |
| |
| prefs_resource = FSpOpenResFile (&prefs_fsp, fsRdPerm); |
| if ( prefs_resource == -1 ) /* this shouldn't happen, but... */ |
| return 0; |
| |
| UseResFile (prefs_resource); |
| no_error = readPrefsResource (prefs); |
| CloseResFile (prefs_resource); |
| } |
| |
| /* Fall back to application's resource fork (reading only, so this is safe) */ |
| else { |
| |
| no_error = readPrefsResource (prefs); |
| } |
| |
| return no_error; |
| } |
| |
| static int writePreferences (PrefsRecord *prefs) { |
| |
| int no_error = 1; |
| FSSpec prefs_fsp; |
| |
| /* Get prefs file, create if it doesn't exist */ |
| if ( getPrefsFile (&prefs_fsp, 1) ) { |
| |
| short prefs_resource; |
| |
| prefs_resource = FSpOpenResFile (&prefs_fsp, fsRdWrPerm); |
| if (prefs_resource == -1) |
| return 0; |
| no_error = writePrefsResource (prefs, prefs_resource); |
| CloseResFile (prefs_resource); |
| } |
| |
| return no_error; |
| } |
| |
| /* This is where execution begins */ |
| int main(int argc, char *argv[]) |
| { |
| |
| #if !(defined(__APPLE__) && defined(__MACH__)) |
| #pragma unused(argc, argv) |
| #endif |
| |
| #define DEFAULT_ARGS "\p" /* pascal string for default args */ |
| #define DEFAULT_VIDEO_DRIVER "\ptoolbox" /* pascal string for default video driver name */ |
| #define DEFAULT_OUTPUT_TO_FILE 1 /* 1 == output to file, 0 == no output */ |
| |
| #define VIDEO_ID_DRAWSPROCKET 1 /* these correspond to popup menu choices */ |
| #define VIDEO_ID_TOOLBOX 2 |
| |
| PrefsRecord prefs = { DEFAULT_ARGS, DEFAULT_VIDEO_DRIVER, DEFAULT_OUTPUT_TO_FILE }; |
| |
| #if !(defined(__APPLE__) && defined(__MACH__)) |
| int nargs; |
| char **args; |
| char *commandLine; |
| |
| StrFileName appNameText; |
| #endif |
| int videodriver = VIDEO_ID_TOOLBOX; |
| int settingsChanged = 0; |
| |
| long i; |
| |
| /* Kyle's SDL command-line dialog code ... */ |
| #if !TARGET_API_MAC_CARBON |
| InitGraf (&qd.thePort); |
| InitFonts (); |
| InitWindows (); |
| InitMenus (); |
| InitDialogs (nil); |
| #endif |
| InitCursor (); |
| FlushEvents(everyEvent,0); |
| #if !TARGET_API_MAC_CARBON |
| MaxApplZone (); |
| #endif |
| MoreMasters (); |
| MoreMasters (); |
| #if 0 |
| /* Intialize SDL, and put up a dialog if we fail */ |
| if ( SDL_Init (0) < 0 ) { |
| |
| #define kErr_OK 1 |
| #define kErr_Text 2 |
| |
| DialogPtr errorDialog; |
| short dummyType; |
| Rect dummyRect; |
| Handle dummyHandle; |
| short itemHit; |
| |
| errorDialog = GetNewDialog (1001, nil, (WindowPtr)-1); |
| if (errorDialog == NULL) |
| return -1; |
| DrawDialog (errorDialog); |
| |
| GetDialogItem (errorDialog, kErr_Text, &dummyType, &dummyHandle, &dummyRect); |
| SetDialogItemText (dummyHandle, "\pError Initializing SDL"); |
| |
| #if TARGET_API_MAC_CARBON |
| SetPort (GetDialogPort(errorDialog)); |
| #else |
| SetPort (errorDialog); |
| #endif |
| do { |
| ModalDialog (nil, &itemHit); |
| } while (itemHit != kErr_OK); |
| |
| DisposeDialog (errorDialog); |
| exit (-1); |
| } |
| atexit(cleanup_output); |
| atexit(SDL_Quit); |
| #endif |
| |
| /* Set up SDL's QuickDraw environment */ |
| #if !TARGET_API_MAC_CARBON |
| SDL_InitQuickDraw(&qd); |
| #endif |
| |
| if ( readPreferences (&prefs) ) { |
| |
| if (SDL_memcmp(prefs.video_driver_name+1, "DSp", 3) == 0) |
| videodriver = 1; |
| else if (SDL_memcmp(prefs.video_driver_name+1, "toolbox", 7) == 0) |
| videodriver = 2; |
| } |
| |
| if ( CommandKeyIsDown() ) { |
| |
| #define kCL_OK 1 |
| #define kCL_Cancel 2 |
| #define kCL_Text 3 |
| #define kCL_File 4 |
| #define kCL_Video 6 |
| |
| DialogPtr commandDialog; |
| short dummyType; |
| Rect dummyRect; |
| Handle dummyHandle; |
| short itemHit; |
| #if TARGET_API_MAC_CARBON |
| ControlRef control; |
| #endif |
| |
| /* Assume that they will change settings, rather than do exhaustive check */ |
| settingsChanged = 1; |
| |
| /* Create dialog and display it */ |
| commandDialog = GetNewDialog (1000, nil, (WindowPtr)-1); |
| #if TARGET_API_MAC_CARBON |
| SetPort ( GetDialogPort(commandDialog) ); |
| #else |
| SetPort (commandDialog); |
| #endif |
| |
| /* Setup controls */ |
| #if TARGET_API_MAC_CARBON |
| GetDialogItemAsControl(commandDialog, kCL_File, &control); |
| SetControlValue (control, prefs.output_to_file); |
| #else |
| GetDialogItem (commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */ |
| SetControlValue ((ControlHandle)dummyHandle, prefs.output_to_file ); |
| #endif |
| |
| GetDialogItem (commandDialog, kCL_Text, &dummyType, &dummyHandle, &dummyRect); |
| SetDialogItemText (dummyHandle, prefs.command_line); |
| |
| #if TARGET_API_MAC_CARBON |
| GetDialogItemAsControl(commandDialog, kCL_Video, &control); |
| SetControlValue (control, videodriver); |
| #else |
| GetDialogItem (commandDialog, kCL_Video, &dummyType, &dummyHandle, &dummyRect); |
| SetControlValue ((ControlRef)dummyHandle, videodriver); |
| #endif |
| |
| SetDialogDefaultItem (commandDialog, kCL_OK); |
| SetDialogCancelItem (commandDialog, kCL_Cancel); |
| |
| do { |
| |
| ModalDialog(nil, &itemHit); /* wait for user response */ |
| |
| /* Toggle command-line output checkbox */ |
| if ( itemHit == kCL_File ) { |
| #if TARGET_API_MAC_CARBON |
| GetDialogItemAsControl(commandDialog, kCL_File, &control); |
| SetControlValue (control, !GetControlValue(control)); |
| #else |
| GetDialogItem(commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */ |
| SetControlValue((ControlHandle)dummyHandle, !GetControlValue((ControlHandle)dummyHandle) ); |
| #endif |
| } |
| |
| } while (itemHit != kCL_OK && itemHit != kCL_Cancel); |
| |
| /* Get control values, even if they did not change */ |
| GetDialogItem (commandDialog, kCL_Text, &dummyType, &dummyHandle, &dummyRect); /* MJS */ |
| GetDialogItemText (dummyHandle, prefs.command_line); |
| |
| #if TARGET_API_MAC_CARBON |
| GetDialogItemAsControl(commandDialog, kCL_File, &control); |
| prefs.output_to_file = GetControlValue(control); |
| #else |
| GetDialogItem (commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */ |
| prefs.output_to_file = GetControlValue ((ControlHandle)dummyHandle); |
| #endif |
| |
| #if TARGET_API_MAC_CARBON |
| GetDialogItemAsControl(commandDialog, kCL_Video, &control); |
| videodriver = GetControlValue(control); |
| #else |
| GetDialogItem (commandDialog, kCL_Video, &dummyType, &dummyHandle, &dummyRect); |
| videodriver = GetControlValue ((ControlRef)dummyHandle); |
| #endif |
| |
| DisposeDialog (commandDialog); |
| |
| if (itemHit == kCL_Cancel ) { |
| exit (0); |
| } |
| } |
| |
| /* Set pseudo-environment variables for video driver, update prefs */ |
| switch ( videodriver ) { |
| case VIDEO_ID_DRAWSPROCKET: |
| SDL_putenv("SDL_VIDEODRIVER=DSp"); |
| SDL_memcpy(prefs.video_driver_name, "\pDSp", 4); |
| break; |
| case VIDEO_ID_TOOLBOX: |
| SDL_putenv("SDL_VIDEODRIVER=toolbox"); |
| SDL_memcpy(prefs.video_driver_name, "\ptoolbox", 8); |
| break; |
| } |
| |
| #if !(defined(__APPLE__) && defined(__MACH__)) |
| /* Redirect standard I/O to files */ |
| if ( prefs.output_to_file ) { |
| freopen (STDOUT_FILE, "w", stdout); |
| freopen (STDERR_FILE, "w", stderr); |
| } else { |
| fclose (stdout); |
| fclose (stderr); |
| } |
| #endif |
| |
| if (settingsChanged) { |
| /* Save the prefs, even if they might not have changed (but probably did) */ |
| if ( ! writePreferences (&prefs) ) |
| fprintf (stderr, "WARNING: Could not save preferences!\n"); |
| } |
| |
| #if !(defined(__APPLE__) && defined(__MACH__)) |
| appNameText[0] = 0; |
| getCurrentAppName (appNameText); /* check for error here ? */ |
| |
| commandLine = (char*) malloc (appNameText[0] + prefs.command_line[0] + 2); |
| if ( commandLine == NULL ) { |
| exit(-1); |
| } |
| |
| /* Rather than rewrite ParseCommandLine method, let's replace */ |
| /* any spaces in application name with underscores, */ |
| /* so that the app name is only 1 argument */ |
| for (i = 1; i < 1+appNameText[0]; i++) |
| if ( appNameText[i] == ' ' ) appNameText[i] = '_'; |
| |
| /* Copy app name & full command text to command-line C-string */ |
| SDL_memcpy(commandLine, appNameText + 1, appNameText[0]); |
| commandLine[appNameText[0]] = ' '; |
| SDL_memcpy(commandLine + appNameText[0] + 1, prefs.command_line + 1, prefs.command_line[0]); |
| commandLine[ appNameText[0] + 1 + prefs.command_line[0] ] = '\0'; |
| |
| /* Parse C-string into argv and argc */ |
| nargs = ParseCommandLine (commandLine, NULL); |
| args = (char **)malloc((nargs+1)*(sizeof *args)); |
| if ( args == NULL ) { |
| exit(-1); |
| } |
| ParseCommandLine (commandLine, args); |
| |
| /* Run the main application code */ |
| SDL_main(nargs, args); |
| free (args); |
| free (commandLine); |
| |
| /* Remove useless stdout.txt and stderr.txt */ |
| cleanup_output (); |
| #else // defined(__APPLE__) && defined(__MACH__) |
| SDL_main(argc, argv); |
| #endif |
| |
| /* Exit cleanly, calling atexit() functions */ |
| exit (0); |
| |
| /* Never reached, but keeps the compiler quiet */ |
| return (0); |
| } |