Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997-2004 Sam Lantinga
  4.  
  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.
  9.  
  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.
  14.  
  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
  18.  
  19.     Sam Lantinga
  20.     slouken@libsdl.org
  21. */
  22.  
  23. #ifdef SAVE_RCSID
  24. static char rcsid =
  25.  "@(#) $Id: SDL_main.c,v 1.1.1.1 2006/03/17 19:54:28 zicodxx Exp $";
  26. #endif
  27.  
  28. /* This file takes care of command line argument parsing, and stdio redirection
  29.    in the MacOS environment.
  30.  */
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <ctype.h>
  36. #if defined(__APPLE__) && defined(__MACH__)
  37. #include <Carbon/Carbon.h>
  38. #elif TARGET_API_MAC_CARBON
  39. #include <Carbon.h>
  40. #else
  41. #include <Dialogs.h>
  42. #include <Fonts.h>
  43. #include <Events.h>
  44. #include <Resources.h>
  45. #include <Folders.h>
  46. #endif
  47.  
  48. /* Include the SDL main definition header */
  49. #include <SDL.h>
  50. #include "SDL_main.h"
  51. #ifdef main
  52. #undef main
  53. #endif
  54.  
  55. /* The standard output files */
  56. #define STDOUT_FILE     "stdout.txt"
  57. #define STDERR_FILE     "stderr.txt"
  58.  
  59. #if !defined(__MWERKS__) && !TARGET_API_MAC_CARBON
  60.         /* In MPW, the qd global has been removed from the libraries */
  61.         QDGlobals qd;
  62. #endif
  63.  
  64. /* Structure for keeping prefs in 1 variable */
  65. typedef struct {
  66.     Str255  command_line;
  67.     Str255  video_driver_name;
  68.     Boolean output_to_file;
  69. }  PrefsRecord;
  70.  
  71. /* See if the command key is held down at startup */
  72. static Boolean CommandKeyIsDown(void)
  73. {
  74.         KeyMap  theKeyMap;
  75.  
  76.         GetKeys(theKeyMap);
  77.  
  78.         if (((unsigned char *) theKeyMap)[6] & 0x80) {
  79.                 return(true);
  80.         }
  81.         return(false);
  82. }
  83.  
  84. /* Parse a command line buffer into arguments */
  85. static int ParseCommandLine(char *cmdline, char **argv)
  86. {
  87.         char *bufp;
  88.         int argc;
  89.  
  90.         argc = 0;
  91.         for ( bufp = cmdline; *bufp; ) {
  92.                 /* Skip leading whitespace */
  93.                 while ( isspace(*bufp) ) {
  94.                         ++bufp;
  95.                 }
  96.                 /* Skip over argument */
  97.                 if ( *bufp == '"' ) {
  98.                         ++bufp;
  99.                         if ( *bufp ) {
  100.                                 if ( argv ) {
  101.                                         argv[argc] = bufp;
  102.                                 }
  103.                                 ++argc;
  104.                         }
  105.                         /* Skip over word */
  106.                         while ( *bufp && (*bufp != '"') ) {
  107.                                 ++bufp;
  108.                         }
  109.                 } else {
  110.                         if ( *bufp ) {
  111.                                 if ( argv ) {
  112.                                         argv[argc] = bufp;
  113.                                 }
  114.                                 ++argc;
  115.                         }
  116.                         /* Skip over word */
  117.                         while ( *bufp && ! isspace(*bufp) ) {
  118.                                 ++bufp;
  119.                         }
  120.                 }
  121.                 if ( *bufp ) {
  122.                         if ( argv ) {
  123.                                 *bufp = '\0';
  124.                         }
  125.                         ++bufp;
  126.                 }
  127.         }
  128.         if ( argv ) {
  129.                 argv[argc] = NULL;
  130.         }
  131.         return(argc);
  132. }
  133.  
  134. /* Remove the output files if there was no output written */
  135. static void cleanup_output(void)
  136. {
  137.         FILE *file;
  138.         int empty;
  139.  
  140.         /* Flush the output in case anything is queued */
  141.         fclose(stdout);
  142.         fclose(stderr);
  143.  
  144.         /* See if the files have any output in them */
  145.         file = fopen(STDOUT_FILE, "rb");
  146.         if ( file ) {
  147.                 empty = (fgetc(file) == EOF) ? 1 : 0;
  148.                 fclose(file);
  149.                 if ( empty ) {
  150.                         remove(STDOUT_FILE);
  151.                 }
  152.         }
  153.         file = fopen(STDERR_FILE, "rb");
  154.         if ( file ) {
  155.                 empty = (fgetc(file) == EOF) ? 1 : 0;
  156.                 fclose(file);
  157.                 if ( empty ) {
  158.                         remove(STDERR_FILE);
  159.                 }
  160.         }
  161. }
  162.  
  163. static int getCurrentAppName (StrFileName name) {
  164.        
  165.     ProcessSerialNumber process;
  166.     ProcessInfoRec      process_info;
  167.     FSSpec              process_fsp;
  168.    
  169.     process.highLongOfPSN = 0;
  170.     process.lowLongOfPSN  = kCurrentProcess;
  171.     process_info.processInfoLength = sizeof (process_info);
  172.     process_info.processName    = NULL;
  173.     process_info.processAppSpec = &process_fsp;
  174.    
  175.     if ( noErr != GetProcessInformation (&process, &process_info) )
  176.        return 0;
  177.    
  178.     memcpy (name, process_fsp.name, process_fsp.name[0] + 1);
  179.     return 1;
  180. }
  181.  
  182. static int getPrefsFile (FSSpec *prefs_fsp, int create) {
  183.  
  184.     /* The prefs file name is the application name, possibly truncated, */
  185.     /* plus " Preferences */
  186.    
  187.     #define  SUFFIX   " Preferences"
  188.     #define  MAX_NAME 19             /* 31 - strlen (SUFFIX) */
  189.    
  190.     short  volume_ref_number;
  191.     long   directory_id;
  192.     StrFileName  prefs_name;
  193.     StrFileName  app_name;
  194.    
  195.     /* Get Preferences folder - works with Multiple Users */
  196.     if ( noErr != FindFolder ( kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder,
  197.                                &volume_ref_number, &directory_id) )
  198.         exit (-1);
  199.    
  200.     if ( ! getCurrentAppName (app_name) )
  201.         exit (-1);
  202.    
  203.     /* Truncate if name is too long */
  204.     if (app_name[0] > MAX_NAME )
  205.         app_name[0] = MAX_NAME;
  206.        
  207.     memcpy (prefs_name + 1, app_name + 1, app_name[0]);    
  208.     memcpy (prefs_name + app_name[0] + 1, SUFFIX, strlen (SUFFIX));
  209.     prefs_name[0] = app_name[0] + strlen (SUFFIX);
  210.    
  211.     /* Make the file spec for prefs file */
  212.     if ( noErr != FSMakeFSSpec (volume_ref_number, directory_id, prefs_name, prefs_fsp) )
  213.         if ( !create )
  214.             return 0;
  215.         else {
  216.             /* Create the prefs file */
  217.             memcpy (prefs_fsp->name, prefs_name, prefs_name[0] + 1);
  218.             prefs_fsp->parID   = directory_id;
  219.             prefs_fsp->vRefNum = volume_ref_number;
  220.                
  221.             FSpCreateResFile (prefs_fsp, '????', 'pref', 0);
  222.            
  223.             if ( noErr != ResError () )
  224.                 return 0;
  225.         }
  226.      
  227.     return 1;
  228. }
  229.  
  230. static int readPrefsResource (PrefsRecord *prefs) {
  231.    
  232.     Handle prefs_handle;
  233.    
  234.     prefs_handle = Get1Resource( 'CLne', 128 );
  235.  
  236.         if (prefs_handle != NULL) {
  237.                 int offset = 0;
  238.                
  239.                 HLock(prefs_handle);
  240.                
  241.                 /* Get command line string */  
  242.                 memcpy (prefs->command_line, *prefs_handle, (*prefs_handle)[0]+1);
  243.  
  244.                 /* Get video driver name */
  245.                 offset += (*prefs_handle)[0] + 1;      
  246.                 memcpy (prefs->video_driver_name, *prefs_handle + offset, (*prefs_handle)[offset] + 1);        
  247.                
  248.                 /* Get save-to-file option (1 or 0) */
  249.                 offset += (*prefs_handle)[offset] + 1;
  250.                 prefs->output_to_file = (*prefs_handle)[offset];
  251.                
  252.                 ReleaseResource( prefs_handle );
  253.    
  254.         return ResError() == noErr;
  255.     }
  256.  
  257.     return 0;
  258. }
  259.  
  260. static int writePrefsResource (PrefsRecord *prefs, short resource_file) {
  261.  
  262.     Handle prefs_handle;
  263.    
  264.     UseResFile (resource_file);
  265.    
  266.     prefs_handle = Get1Resource ( 'CLne', 128 );
  267.     if (prefs_handle != NULL)
  268.         RemoveResource (prefs_handle);
  269.    
  270.     prefs_handle = NewHandle ( prefs->command_line[0] + prefs->video_driver_name[0] + 4 );
  271.     if (prefs_handle != NULL) {
  272.    
  273.         int offset;
  274.        
  275.         HLock (prefs_handle);
  276.        
  277.         /* Command line text */
  278.         offset = 0;
  279.         memcpy (*prefs_handle, prefs->command_line, prefs->command_line[0] + 1);
  280.        
  281.         /* Video driver name */
  282.         offset += prefs->command_line[0] + 1;
  283.         memcpy (*prefs_handle + offset, prefs->video_driver_name, prefs->video_driver_name[0] + 1);
  284.        
  285.         /* Output-to-file option */
  286.         offset += prefs->video_driver_name[0] + 1;
  287.         *( *((char**)prefs_handle) + offset)     = (char)prefs->output_to_file;
  288.         *( *((char**)prefs_handle) + offset + 1) = 0;
  289.              
  290.         AddResource   (prefs_handle, 'CLne', 128, "\pCommand Line");
  291.         WriteResource (prefs_handle);
  292.         UpdateResFile (resource_file);
  293.         DisposeHandle (prefs_handle);
  294.        
  295.         return ResError() == noErr;
  296.     }
  297.    
  298.     return 0;
  299. }
  300.  
  301. static int readPreferences (PrefsRecord *prefs) {
  302.  
  303.     int    no_error = 1;
  304.     FSSpec prefs_fsp;
  305.  
  306.     /* Check for prefs file first */
  307.     if ( getPrefsFile (&prefs_fsp, 0) ) {
  308.    
  309.         short  prefs_resource;
  310.        
  311.         prefs_resource = FSpOpenResFile (&prefs_fsp, fsRdPerm);
  312.         if ( prefs_resource == -1 ) /* this shouldn't happen, but... */
  313.             return 0;
  314.    
  315.         UseResFile   (prefs_resource);
  316.         no_error = readPrefsResource (prefs);    
  317.         CloseResFile (prefs_resource);
  318.     }
  319.    
  320.     /* Fall back to application's resource fork (reading only, so this is safe) */
  321.     else {
  322.    
  323.           no_error = readPrefsResource (prefs);
  324.      }
  325.  
  326.     return no_error;
  327. }
  328.  
  329. static int writePreferences (PrefsRecord *prefs) {
  330.    
  331.     int    no_error = 1;
  332.     FSSpec prefs_fsp;
  333.    
  334.     /* Get prefs file, create if it doesn't exist */
  335.     if ( getPrefsFile (&prefs_fsp, 1) ) {
  336.    
  337.         short  prefs_resource;
  338.        
  339.         prefs_resource = FSpOpenResFile (&prefs_fsp, fsRdWrPerm);
  340.         if (prefs_resource == -1)
  341.             return 0;
  342.         no_error = writePrefsResource (prefs, prefs_resource);
  343.         CloseResFile (prefs_resource);
  344.     }
  345.    
  346.     return no_error;
  347. }
  348.  
  349. /* This is where execution begins */
  350. int main(int argc, char *argv[])
  351. {
  352.  
  353. #pragma unused(argc, argv)
  354.        
  355. #define DEFAULT_ARGS "\p"                /* pascal string for default args */
  356. #define DEFAULT_VIDEO_DRIVER "\ptoolbox" /* pascal string for default video driver name */     
  357. #define DEFAULT_OUTPUT_TO_FILE 1         /* 1 == output to file, 0 == no output */
  358.  
  359. #define VIDEO_ID_DRAWSPROCKET 1          /* these correspond to popup menu choices */
  360. #define VIDEO_ID_TOOLBOX      2
  361.  
  362.     PrefsRecord prefs = { DEFAULT_ARGS, DEFAULT_VIDEO_DRIVER, DEFAULT_OUTPUT_TO_FILE };
  363.        
  364.         int     nargs;
  365.         char   **args;
  366.         char   *commandLine;
  367.        
  368.         StrFileName  appNameText;
  369.         int     videodriver     = VIDEO_ID_TOOLBOX;
  370.     int     settingsChanged = 0;
  371.    
  372.     long        i;
  373.  
  374.         /* Kyle's SDL command-line dialog code ... */
  375. #if !TARGET_API_MAC_CARBON
  376.         InitGraf    (&qd.thePort);
  377.         InitFonts   ();
  378.         InitWindows ();
  379.         InitMenus   ();
  380.         InitDialogs (nil);
  381. #endif
  382.         InitCursor ();
  383.         FlushEvents(everyEvent,0);
  384. #if !TARGET_API_MAC_CARBON
  385.         MaxApplZone ();
  386. #endif
  387.         MoreMasters ();
  388.         MoreMasters ();
  389. #if 0
  390.         /* Intialize SDL, and put up a dialog if we fail */
  391.         if ( SDL_Init (0) < 0 ) {
  392.  
  393. #define kErr_OK         1
  394. #define kErr_Text       2
  395.  
  396.         DialogPtr errorDialog;
  397.         short     dummyType;
  398.         Rect      dummyRect;
  399.             Handle    dummyHandle;
  400.             short     itemHit;
  401.        
  402.                 errorDialog = GetNewDialog (1001, nil, (WindowPtr)-1);
  403.                 DrawDialog (errorDialog);
  404.                
  405.                 GetDialogItem (errorDialog, kErr_Text, &dummyType, &dummyHandle, &dummyRect);
  406.                 SetDialogItemText (dummyHandle, "\pError Initializing SDL");
  407.                
  408.                 SetPort (errorDialog);
  409.                 do {
  410.                         ModalDialog (nil, &itemHit);
  411.                 } while (itemHit != kErr_OK);
  412.                
  413.                 DisposeDialog (errorDialog);
  414.                 exit (-1);
  415.         }
  416.         atexit(cleanup_output);
  417.         atexit(SDL_Quit);
  418. #endif
  419.  
  420. /* Set up SDL's QuickDraw environment  */
  421. #if !TARGET_API_MAC_CARBON
  422.         SDL_InitQuickDraw(&qd);
  423. #endif
  424.  
  425.          if ( readPreferences (&prefs) ) {
  426.                
  427.         if (memcmp (prefs.video_driver_name+1, "DSp", 3) == 0)
  428.             videodriver = 1;
  429.         else if (memcmp (prefs.video_driver_name+1, "toolbox", 7) == 0)
  430.             videodriver = 2;
  431.          }
  432.                
  433.         if ( CommandKeyIsDown() ) {
  434.  
  435. #define kCL_OK          1
  436. #define kCL_Cancel      2
  437. #define kCL_Text        3
  438. #define kCL_File        4
  439. #define kCL_Video   6
  440.        
  441.         DialogPtr commandDialog;
  442.         short     dummyType;
  443.         Rect      dummyRect;
  444.         Handle    dummyHandle;
  445.         short     itemHit;
  446.  
  447.         /* Assume that they will change settings, rather than do exhaustive check */
  448.         settingsChanged = 1;
  449.        
  450.         /* Create dialog and display it */
  451.         commandDialog = GetNewDialog (1000, nil, (WindowPtr)-1);
  452.         SetPortDialogPort (commandDialog);
  453.            
  454.         /* Setup controls */
  455.         GetDialogItem   (commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
  456.         SetControlValue ((ControlHandle)dummyHandle, prefs.output_to_file );
  457.  
  458.         GetDialogItem     (commandDialog, kCL_Text, &dummyType, &dummyHandle, &dummyRect);
  459.         SetDialogItemText (dummyHandle, prefs.command_line);
  460.  
  461.         GetDialogItem   (commandDialog, kCL_Video, &dummyType, &dummyHandle, &dummyRect);
  462.         SetControlValue ((ControlRef)dummyHandle, videodriver);
  463.  
  464.         SetDialogDefaultItem (commandDialog, kCL_OK);
  465.         SetDialogCancelItem  (commandDialog, kCL_Cancel);
  466.  
  467.         do {
  468.                        
  469.                 ModalDialog(nil, &itemHit); /* wait for user response */
  470.            
  471.             /* Toggle command-line output checkbox */  
  472.                 if ( itemHit == kCL_File ) {
  473.                         GetDialogItem(commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
  474.                         SetControlValue((ControlHandle)dummyHandle, !GetControlValue((ControlHandle)dummyHandle) );
  475.                 }
  476.  
  477.         } while (itemHit != kCL_OK && itemHit != kCL_Cancel);
  478.  
  479.         /* Get control values, even if they did not change */
  480.         GetDialogItem     (commandDialog, kCL_Text, &dummyType, &dummyHandle, &dummyRect); /* MJS */
  481.         GetDialogItemText (dummyHandle, prefs.command_line);
  482.  
  483.         GetDialogItem (commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
  484.         prefs.output_to_file = GetControlValue ((ControlHandle)dummyHandle);
  485.  
  486.         GetDialogItem (commandDialog, kCL_Video, &dummyType, &dummyHandle, &dummyRect);
  487.         videodriver = GetControlValue ((ControlRef)dummyHandle);
  488.  
  489.         DisposeDialog (commandDialog);
  490.  
  491.         if (itemHit == kCL_Cancel ) {
  492.                 exit (0);
  493.         }
  494.         }
  495.    
  496.     /* Set pseudo-environment variables for video driver, update prefs */
  497.         switch ( videodriver ) {
  498.            case VIDEO_ID_DRAWSPROCKET:
  499.               SDL_putenv ("SDL_VIDEODRIVER=DSp");
  500.               memcpy (prefs.video_driver_name, "\pDSp", 4);
  501.               break;
  502.            case VIDEO_ID_TOOLBOX:
  503.               SDL_putenv ("SDL_VIDEODRIVER=toolbox");
  504.               memcpy (prefs.video_driver_name, "\ptoolbox", 8);
  505.               break;
  506.         }
  507.     /* Redirect standard I/O to files */
  508.         if ( prefs.output_to_file ) {
  509.                 freopen (STDOUT_FILE, "w", stdout);
  510.                 freopen (STDERR_FILE, "w", stderr);
  511.         } else {
  512.                 fclose (stdout);
  513.                 fclose (stderr);
  514.         }
  515.    
  516.     if (settingsChanged) {
  517.         /* Save the prefs, even if they might not have changed (but probably did) */
  518.         if ( ! writePreferences (&prefs) )
  519.             fprintf (stderr, "WARNING: Could not save preferences!\n");
  520.     }
  521.    
  522.     getCurrentAppName (appNameText); /* check for error here ? */
  523.  
  524.     commandLine = (char*) malloc (appNameText[0] + prefs.command_line[0] + 2);
  525.     if ( commandLine == NULL ) {
  526.        exit(-1);
  527.     }
  528.  
  529.     /* Rather than rewrite ParseCommandLine method, let's replace  */
  530.     /* any spaces in application name with underscores,            */
  531.     /* so that the app name is only 1 argument                     */  
  532.     for (i = 1; i < 1+appNameText[0]; i++)
  533.         if ( appNameText[i] == ' ' ) appNameText[i] = '_';
  534.  
  535.     /* Copy app name & full command text to command-line C-string */      
  536.     memcpy (commandLine, appNameText + 1, appNameText[0]);
  537.     commandLine[appNameText[0]] = ' ';
  538.     memcpy (commandLine + appNameText[0] + 1, prefs.command_line + 1, prefs.command_line[0]);
  539.     commandLine[ appNameText[0] + 1 + prefs.command_line[0] ] = '\0';
  540.  
  541.     /* Parse C-string into argv and argc */
  542.     nargs = ParseCommandLine (commandLine, NULL);
  543.     args = (char **)malloc((nargs+1)*(sizeof *args));
  544.     if ( args == NULL ) {
  545.                 exit(-1);
  546.         }
  547.         ParseCommandLine (commandLine, args);
  548.        
  549.         /* Run the main application code */
  550.         SDL_main(nargs, args);
  551.         free (args);
  552.         free (commandLine);
  553.    
  554.         /* Remove useless stdout.txt and stderr.txt */
  555.         cleanup_output ();
  556.        
  557.         /* Exit cleanly, calling atexit() functions */
  558.         exit (0);    
  559.  
  560.         /* Never reached, but keeps the compiler quiet */
  561.         return (0);
  562. }
  563.