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