Mercurial > sdl-ios-xcode
view src/main/macos/SDL_main.c @ 1895:c121d94672cb
SDL 1.2 is moving to a branch, and SDL 1.3 is becoming the head.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 10 Jul 2006 21:04:37 +0000 |
parents | 7a610f25c12f |
children |
line wrap: on
line source
/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2006 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); } /* vi: set ts=4 sw=4 expandtab: */