diff src/main/macos/SDL_main.c @ 0:74212992fb08

Initial revision
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:45:43 +0000
parents
children e8157fcb3114
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/macos/SDL_main.c	Thu Apr 26 16:45:43 2001 +0000
@@ -0,0 +1,562 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@devolution.com
+*/
+
+#ifdef SAVE_RCSID
+static char rcsid =
+ "@(#) $Id$";
+#endif
+
+/* This file takes care of command line argument parsing, and stdio redirection
+   in the MacOS environment.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>	
+#if TARGET_API_MAC_CARBON
+#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
+
+/* The standard output files */
+#define STDOUT_FILE	"stdout.txt"
+#define STDERR_FILE	"stderr.txt"
+
+#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);
+}
+
+/* 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 ( 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 && ! 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);
+		}
+	}
+}
+
+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;
+    
+    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;
+        
+    memcpy (prefs_name + 1, app_name + 1, app_name[0]);    
+    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 */
+            memcpy (prefs_fsp->name, prefs_name, prefs_name[0] + 1);
+            prefs_fsp->parID   = directory_id;
+            prefs_fsp->vRefNum = volume_ref_number;
+                
+            FSpCreateResFile (prefs_fsp, '????', 'pref', 0);
+            
+            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 */	
+		memcpy (prefs->command_line, *prefs_handle, (*prefs_handle)[0]+1);
+
+		/* Get video driver name */
+		offset += (*prefs_handle)[0] + 1;	
+		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;
+        memcpy (*prefs_handle, prefs->command_line, prefs->command_line[0] + 1);
+        
+        /* Video driver name */
+        offset += prefs->command_line[0] + 1;
+        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[])
+{
+
+#pragma unused(argc, argv)
+	
+#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 }; 
+	
+	int     nargs;
+	char   **args;
+	char   *commandLine;
+	
+	StrFileName  appNameText;
+	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);
+		DrawDialog (errorDialog);
+		
+		GetDialogItem (errorDialog, kErr_Text, &dummyType, &dummyHandle, &dummyRect);
+		SetDialogItemText (dummyHandle, "\pError Initializing SDL");
+		
+		SetPort (errorDialog);
+		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 (memcmp (prefs.video_driver_name+1, "DSp", 3) == 0)
+            videodriver = 1;
+        else if (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;
+
+        /* Assume that they will change settings, rather than do exhaustive check */
+        settingsChanged = 1;
+        
+        /* Create dialog and display it */
+        commandDialog = GetNewDialog (1000, nil, (DialogPtr)-1);
+        SetPort (commandDialog);
+            
+        /* Setup controls */
+        GetDialogItem   (commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
+        SetControlValue ((ControlHandle)dummyHandle, prefs.output_to_file );
+
+        GetDialogItem     (commandDialog, kCL_Text, &dummyType, &dummyHandle, &dummyRect);
+        SetDialogItemText (dummyHandle, prefs.command_line);
+
+        GetDialogItem   (commandDialog, kCL_Video, &dummyType, &dummyHandle, &dummyRect);
+        SetControlValue ((ControlRef)dummyHandle, videodriver);
+
+        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 ) {
+        		GetDialogItem(commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
+        		SetControlValue((ControlHandle)dummyHandle, !GetControlValue((ControlHandle)dummyHandle) );
+        	}
+
+        } 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);
+
+        GetDialogItem (commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
+        prefs.output_to_file = GetControlValue ((ControlHandle)dummyHandle);
+
+        GetDialogItem (commandDialog, kCL_Video, &dummyType, &dummyHandle, &dummyRect);
+        videodriver = GetControlValue ((ControlRef)dummyHandle);
+
+        DisposeDialog (commandDialog);
+
+        if (itemHit == kCL_Cancel ) {
+        	exit (0);
+        }
+	}
+    
+    /* Set pseudo-environment variables for video driver, update prefs */
+	switch ( videodriver ) {
+	   case VIDEO_ID_DRAWSPROCKET: 
+	      putenv ("SDL_VIDEODRIVER=DSp");
+	      memcpy (prefs.video_driver_name, "\pDSp", 4);
+	      break;
+	   case VIDEO_ID_TOOLBOX:
+	      putenv ("SDL_VIDEODRIVER=toolbox");
+	      memcpy (prefs.video_driver_name, "\ptoolbox", 8);
+	      break;
+	}
+
+    /* 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);
+	}
+   
+    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");
+    }
+   
+    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 */      
+    memcpy (commandLine, appNameText + 1, appNameText[0]);
+    commandLine[appNameText[0]] = ' ';
+    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 ();
+   	
+	/* Exit cleanly, calling atexit() functions */
+	exit (0);    
+
+	/* Never reached, but keeps the compiler quiet */
+	return (0);
+}