Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | pmbaty | 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 | } |