src/main/macos/SDL_main.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. CommandKeyIsDown
  2. ParseCommandLine
  3. cleanup_output
  4. getCurrentAppName
  5. getPrefsFile
  6. readPrefsResource
  7. writePrefsResource
  8. readPreferences
  9. writePreferences
  10. main

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

/* [<][>][^][v][top][bottom][index][help] */