]> icculus.org git repositories - btb/d2x.git/blob - arch/carbon/SDL_main.c
use the orientation parameter of g3_draw_bitmap
[btb/d2x.git] / arch / carbon / SDL_main.c
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 /* This file takes care of command line argument parsing, and stdio redirection
24    in the MacOS environment.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "conf.h"
29 #endif
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #if defined(__APPLE__) && defined(__MACH__)
36 #include <Carbon/Carbon.h>
37 #elif TARGET_API_MAC_CARBON
38 #include <Carbon.h>
39 #else
40 #include <Dialogs.h>
41 #include <Fonts.h>
42 #include <Events.h>
43 #include <Resources.h>
44 #include <Folders.h>
45 #endif
46
47 /* Include the SDL main definition header */
48 #include "SDL.h"
49 #include "SDL_main.h"
50 #ifdef main
51 #undef main
52 #endif
53
54 /* The standard output files */
55 #define STDOUT_FILE     "stdout.txt"
56 #define STDERR_FILE     "stderr.txt"
57
58 #if !defined(__MWERKS__) && !TARGET_API_MAC_CARBON
59         /* In MPW, the qd global has been removed from the libraries */
60         QDGlobals qd;
61 #endif
62
63 /* Structure for keeping prefs in 1 variable */
64 typedef struct {
65     Str255  command_line;
66     Str255  video_driver_name;
67     Boolean output_to_file;
68 }  PrefsRecord;
69
70 /* See if the command key is held down at startup */
71 static Boolean CommandKeyIsDown(void)
72 {
73         KeyMap  theKeyMap;
74
75         GetKeys(theKeyMap);
76
77         if (((unsigned char *) theKeyMap)[6] & 0x80) {
78                 return(true);
79         }
80         return(false);
81 }
82
83 /* Parse a command line buffer into arguments */
84 static int ParseCommandLine(char *cmdline, char **argv)
85 {
86         char *bufp;
87         int argc;
88
89         argc = 0;
90         for ( bufp = cmdline; *bufp; ) {
91                 /* Skip leading whitespace */
92                 while ( isspace(*bufp) ) {
93                         ++bufp;
94                 }
95                 /* Skip over argument */
96                 if ( *bufp == '"' ) {
97                         ++bufp;
98                         if ( *bufp ) {
99                                 if ( argv ) {
100                                         argv[argc] = bufp;
101                                 }
102                                 ++argc;
103                         }
104                         /* Skip over word */
105                         while ( *bufp && (*bufp != '"') ) {
106                                 ++bufp;
107                         }
108                 } else {
109                         if ( *bufp ) {
110                                 if ( argv ) {
111                                         argv[argc] = bufp;
112                                 }
113                                 ++argc;
114                         }
115                         /* Skip over word */
116                         while ( *bufp && ! isspace(*bufp) ) {
117                                 ++bufp;
118                         }
119                 }
120                 if ( *bufp ) {
121                         if ( argv ) {
122                                 *bufp = '\0';
123                         }
124                         ++bufp;
125                 }
126         }
127         if ( argv ) {
128                 argv[argc] = NULL;
129         }
130         return(argc);
131 }
132
133 /* Remove the output files if there was no output written */
134 static void cleanup_output(void)
135 {
136         FILE *file;
137         int empty;
138
139         /* Flush the output in case anything is queued */
140         fclose(stdout);
141         fclose(stderr);
142
143         /* See if the files have any output in them */
144         file = fopen(STDOUT_FILE, "rb");
145         if ( file ) {
146                 empty = (fgetc(file) == EOF) ? 1 : 0;
147                 fclose(file);
148                 if ( empty ) {
149                         remove(STDOUT_FILE);
150                 }
151         }
152         file = fopen(STDERR_FILE, "rb");
153         if ( file ) {
154                 empty = (fgetc(file) == EOF) ? 1 : 0;
155                 fclose(file);
156                 if ( empty ) {
157                         remove(STDERR_FILE);
158                 }
159         }
160 }
161
162 static int getCurrentAppName (StrFileName name) {
163         
164     ProcessSerialNumber process;
165     ProcessInfoRec      process_info;
166     FSSpec              process_fsp;
167     
168     process.highLongOfPSN = 0;
169     process.lowLongOfPSN  = kCurrentProcess;
170     process_info.processInfoLength = sizeof (process_info);
171     process_info.processName    = NULL;
172     process_info.processAppSpec = &process_fsp;
173     
174     if ( noErr != GetProcessInformation (&process, &process_info) )
175        return 0;
176     
177     memcpy (name, process_fsp.name, process_fsp.name[0] + 1);
178     return 1;
179 }
180
181 static int getPrefsFile (FSSpec *prefs_fsp, int create) {
182
183     /* The prefs file name is the application name, possibly truncated, */
184     /* plus " Preferences */
185     
186     #define  SUFFIX   " Preferences"
187     #define  MAX_NAME 19             /* 31 - strlen (SUFFIX) */
188     
189     short  volume_ref_number;
190     long   directory_id;
191     StrFileName  prefs_name;
192     StrFileName  app_name;
193     
194     /* Get Preferences folder - works with Multiple Users */
195     if ( noErr != FindFolder ( kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder,
196                                &volume_ref_number, &directory_id) )
197         exit (-1);
198     
199     if ( ! getCurrentAppName (app_name) )
200         exit (-1);
201     
202     /* Truncate if name is too long */
203     if (app_name[0] > MAX_NAME )
204         app_name[0] = MAX_NAME;
205         
206     memcpy (prefs_name + 1, app_name + 1, app_name[0]);    
207     memcpy (prefs_name + app_name[0] + 1, SUFFIX, strlen (SUFFIX));
208     prefs_name[0] = app_name[0] + strlen (SUFFIX);
209    
210     /* Make the file spec for prefs file */
211     if ( noErr != FSMakeFSSpec (volume_ref_number, directory_id, prefs_name, prefs_fsp) )
212         if ( !create )
213             return 0;
214         else {
215             /* Create the prefs file */
216             memcpy (prefs_fsp->name, prefs_name, prefs_name[0] + 1);
217             prefs_fsp->parID   = directory_id;
218             prefs_fsp->vRefNum = volume_ref_number;
219                 
220             FSpCreateResFile (prefs_fsp, '????', 'pref', 0);
221             
222             if ( noErr != ResError () )
223                 return 0;
224         }
225       
226     return 1;
227 }
228
229 static int readPrefsResource (PrefsRecord *prefs) {
230     
231     Handle prefs_handle;
232     
233     prefs_handle = Get1Resource( 'CLne', 128 );
234
235         if (prefs_handle != NULL) {
236                 int offset = 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) {
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) {
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) {
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[])
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, (WindowPtr)-1);
451         SetPortDialogPort (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     /* Redirect standard I/O to files */
507         if ( prefs.output_to_file ) {
508                 freopen (STDOUT_FILE, "w", stdout);
509                 freopen (STDERR_FILE, "w", stderr);
510         } else {
511                 fclose (stdout);
512                 fclose (stderr);
513         }
514    
515     if (settingsChanged) {
516         /* Save the prefs, even if they might not have changed (but probably did) */
517         if ( ! writePreferences (&prefs) )
518             fprintf (stderr, "WARNING: Could not save preferences!\n");
519     }
520    
521     getCurrentAppName (appNameText); /* check for error here ? */
522
523     commandLine = (char*) malloc (appNameText[0] + prefs.command_line[0] + 2);
524     if ( commandLine == NULL ) {
525        exit(-1);
526     }
527
528     /* Rather than rewrite ParseCommandLine method, let's replace  */
529     /* any spaces in application name with underscores,            */
530     /* so that the app name is only 1 argument                     */   
531     for (i = 1; i < 1+appNameText[0]; i++)
532         if ( appNameText[i] == ' ' ) appNameText[i] = '_';
533
534     /* Copy app name & full command text to command-line C-string */      
535     memcpy (commandLine, appNameText + 1, appNameText[0]);
536     commandLine[appNameText[0]] = ' ';
537     memcpy (commandLine + appNameText[0] + 1, prefs.command_line + 1, prefs.command_line[0]);
538     commandLine[ appNameText[0] + 1 + prefs.command_line[0] ] = '\0';
539
540     /* Parse C-string into argv and argc */
541     nargs = ParseCommandLine (commandLine, NULL);
542     args = (char **)malloc((nargs+1)*(sizeof *args));
543     if ( args == NULL ) {
544                 exit(-1);
545         }
546         ParseCommandLine (commandLine, args);
547         
548         /* Run the main application code */
549         SDL_main(nargs, args);
550         free (args);
551         free (commandLine);
552    
553         /* Remove useless stdout.txt and stderr.txt */
554         cleanup_output ();
555         
556         /* Exit cleanly, calling atexit() functions */
557         exit (0);    
558
559         /* Never reached, but keeps the compiler quiet */
560         return (0);
561 }