Mercurial > sdl-ios-xcode
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:74212992fb08 |
---|---|
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$"; | |
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) | |
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) | |
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) | |
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) { | |
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) { | |
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) { | |
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) { | |
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, (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 } |