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
67
static Boolean
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
83
static int
ParseCommandLine(char *cmdline, char **argv)
84
{
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
char *bufp;
int argc;
argc = 0;
for (bufp = cmdline; *bufp;) {
/* Skip leading whitespace */
while (SDL_isspace(*bufp)) {
++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 */
while (*bufp && !SDL_isspace(*bufp)) {
++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
134
static void
cleanup_output(void)
135
{
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
FILE *file;
int empty;
/* Flush the output in case anything is queued */
fclose(stdout);
fclose(stderr);
/* See if the files have any output in them */
file = fopen(STDOUT_FILE, "rb");
if (file) {
empty = (fgetc(file) == EOF) ? 1 : 0;
fclose(file);
if (empty) {
remove(STDOUT_FILE);
}
}
file = fopen(STDERR_FILE, "rb");
if (file) {
empty = (fgetc(file) == EOF) ? 1 : 0;
fclose(file);
if (empty) {
remove(STDERR_FILE);
}
}
160
161
}
162
163
#endif //!(defined(__APPLE__) && defined(__MACH__))
164
165
166
167
static int
getCurrentAppName(StrFileName name)
{
168
ProcessSerialNumber process;
169
170
171
ProcessInfoRec process_info;
FSSpec process_fsp;
172
process.highLongOfPSN = 0;
173
174
175
process.lowLongOfPSN = kCurrentProcess;
process_info.processInfoLength = sizeof(process_info);
process_info.processName = NULL;
176
process_info.processAppSpec = &process_fsp;
177
178
179
180
if (noErr != GetProcessInformation(&process, &process_info))
return 0;
181
SDL_memcpy(name, process_fsp.name, process_fsp.name[0] + 1);
182
183
184
return 1;
}
185
186
187
static int
getPrefsFile(FSSpec * prefs_fsp, int create)
{
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
202
203
204
205
206
207
208
if (noErr !=
FindFolder(kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder,
&volume_ref_number, &directory_id))
exit(-1);
if (!getCurrentAppName(app_name))
exit(-1);
209
/* Truncate if name is too long */
210
if (app_name[0] > MAX_NAME)
211
app_name[0] = MAX_NAME;
212
213
214
215
216
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);
217
/* Make the file spec for prefs file */
218
219
220
221
if (noErr !=
FSMakeFSSpec(volume_ref_number, directory_id, prefs_name, prefs_fsp))
{
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
230
231
FSpCreateResFile(prefs_fsp, 0x3f3f3f3f, 'pref', 0); // '????' parsed as trigraph
if (noErr != ResError())
232
233
return 0;
}
234
}
235
236
237
return 1;
}
238
239
240
241
static int
readPrefsResource(PrefsRecord * prefs)
{
242
Handle prefs_handle;
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
prefs_handle = Get1Resource('CLne', 128);
if (prefs_handle != NULL) {
int offset = 0;
// int j = 0;
HLock(prefs_handle);
/* Get command line string */
SDL_memcpy(prefs->command_line, *prefs_handle,
(*prefs_handle)[0] + 1);
/* Get video driver name */
offset += (*prefs_handle)[0] + 1;
SDL_memcpy(prefs->video_driver_name, *prefs_handle + offset,
(*prefs_handle)[offset] + 1);
/* Get save-to-file option (1 or 0) */
offset += (*prefs_handle)[offset] + 1;
prefs->output_to_file = (*prefs_handle)[offset];
ReleaseResource(prefs_handle);
267
268
269
270
271
272
return ResError() == noErr;
}
return 0;
}
273
274
275
static int
writePrefsResource(PrefsRecord * prefs, short resource_file)
{
276
277
Handle prefs_handle;
278
279
280
281
UseResFile(resource_file);
prefs_handle = Get1Resource('CLne', 128);
282
if (prefs_handle != NULL)
283
284
285
286
RemoveResource(prefs_handle);
prefs_handle =
NewHandle(prefs->command_line[0] + prefs->video_driver_name[0] + 4);
287
if (prefs_handle != NULL) {
288
289
int offset;
290
291
292
HLock(prefs_handle);
293
294
/* Command line text */
offset = 0;
295
296
297
SDL_memcpy(*prefs_handle, prefs->command_line,
prefs->command_line[0] + 1);
298
299
/* Video driver name */
offset += prefs->command_line[0] + 1;
300
301
302
SDL_memcpy(*prefs_handle + offset, prefs->video_driver_name,
prefs->video_driver_name[0] + 1);
303
304
/* Output-to-file option */
offset += prefs->video_driver_name[0] + 1;
305
306
307
308
309
310
311
312
*(*((char **) prefs_handle) + offset) = (char) prefs->output_to_file;
*(*((char **) prefs_handle) + offset + 1) = 0;
AddResource(prefs_handle, 'CLne', 128, "\pCommand Line");
WriteResource(prefs_handle);
UpdateResFile(resource_file);
DisposeHandle(prefs_handle);
313
314
return ResError() == noErr;
}
315
316
317
318
return 0;
}
319
320
321
static int
readPreferences(PrefsRecord * prefs)
{
322
323
int no_error = 1;
324
325
326
FSSpec prefs_fsp;
/* Check for prefs file first */
327
328
329
330
331
332
if (getPrefsFile(&prefs_fsp, 0)) {
short prefs_resource;
prefs_resource = FSpOpenResFile(&prefs_fsp, fsRdPerm);
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
344
no_error = readPrefsResource(prefs);
}
345
346
347
348
return no_error;
}
349
350
351
352
353
static int
writePreferences(PrefsRecord * prefs)
{
int no_error = 1;
354
FSSpec prefs_fsp;
355
356
/* Get prefs file, create if it doesn't exist */
357
358
359
360
361
if (getPrefsFile(&prefs_fsp, 1)) {
short prefs_resource;
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
373
int
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
int videodriver = VIDEO_ID_TOOLBOX;
int settingsChanged = 0;
399
400
401
402
long i;
/* 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
419
/* Intialize SDL, and put up a dialog if we fail */
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
430
431
432
433
434
435
436
437
438
short dummyType;
Rect dummyRect;
Handle dummyHandle;
short itemHit;
errorDialog = GetNewDialog(1001, nil, (WindowPtr) - 1);
if (errorDialog == NULL)
return -1;
DrawDialog(errorDialog);
GetDialogItem(errorDialog, kErr_Text, &dummyType, &dummyHandle,
&dummyRect);
SetDialogItemText(dummyHandle, "\pError Initializing SDL");
439
#if TARGET_API_MAC_CARBON
440
SetPort(GetDialogPort(errorDialog));
441
#else
442
SetPort(errorDialog);
443
#endif
444
445
446
447
448
449
450
451
452
453
do {
ModalDialog(nil, &itemHit);
}
while (itemHit != kErr_OK);
DisposeDialog(errorDialog);
exit(-1);
}
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
462
463
if (readPreferences(&prefs)) {
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
491
492
493
494
495
496
commandDialog = GetNewDialog(1000, nil, (WindowPtr) - 1);
#if TARGET_API_MAC_CARBON
SetPort(GetDialogPort(commandDialog));
#else
SetPort(commandDialog);
#endif
497
/* Setup controls */
498
#if TARGET_API_MAC_CARBON
499
GetDialogItemAsControl(commandDialog, kCL_File, &control);
500
501
502
503
504
SetControlValue(control, prefs.output_to_file);
#else
GetDialogItem(commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
SetControlValue((ControlHandle) dummyHandle, prefs.output_to_file);
#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
GetDialogItemAsControl(commandDialog, kCL_Video, &control);
512
513
514
515
516
517
SetControlValue(control, videodriver);
#else
GetDialogItem(commandDialog, kCL_Video, &dummyType, &dummyHandle,
&dummyRect);
SetControlValue((ControlRef) dummyHandle, videodriver);
#endif
518
519
520
SetDialogDefaultItem(commandDialog, kCL_OK);
SetDialogCancelItem(commandDialog, kCL_Cancel);
521
522
do {
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
ModalDialog(nil, &itemHit); /* wait for user response */
/* Toggle command-line output checkbox */
if (itemHit == kCL_File) {
#if TARGET_API_MAC_CARBON
GetDialogItemAsControl(commandDialog, kCL_File, &control);
SetControlValue(control, !GetControlValue(control));
#else
GetDialogItem(commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
SetControlValue((ControlHandle) dummyHandle,
!GetControlValue((ControlHandle)
dummyHandle));
#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
550
551
552
#else
GetDialogItem(commandDialog, kCL_File, &dummyType, &dummyHandle, &dummyRect); /* MJS */
prefs.output_to_file = GetControlValue((ControlHandle) dummyHandle);
#endif
553
554
#if TARGET_API_MAC_CARBON
555
556
GetDialogItemAsControl(commandDialog, kCL_Video, &control);
videodriver = GetControlValue(control);
557
558
559
560
561
#else
GetDialogItem(commandDialog, kCL_Video, &dummyType, &dummyHandle,
&dummyRect);
videodriver = GetControlValue((ControlRef) dummyHandle);
#endif
562
563
DisposeDialog(commandDialog);
564
565
566
if (itemHit == kCL_Cancel) {
exit(0);
567
}
568
569
}
570
/* Set pseudo-environment variables for video driver, update prefs */
571
572
573
574
575
576
577
578
579
580
switch (videodriver) {
case VIDEO_ID_DRAWSPROCKET:
SDL_putenv("SDL_VIDEODRIVER=DSp");
SDL_memcpy(prefs.video_driver_name, "\pDSp", 4);
break;
case VIDEO_ID_TOOLBOX:
SDL_putenv("SDL_VIDEODRIVER=toolbox");
SDL_memcpy(prefs.video_driver_name, "\ptoolbox", 8);
break;
}
581
582
#if !(defined(__APPLE__) && defined(__MACH__))
583
/* Redirect standard I/O to files */
584
585
586
587
588
589
590
if (prefs.output_to_file) {
freopen(STDOUT_FILE, "w", stdout);
freopen(STDERR_FILE, "w", stderr);
} else {
fclose(stdout);
fclose(stderr);
}
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
603
604
commandLine = (char *) malloc(appNameText[0] + prefs.command_line[0] + 2);
if (commandLine == NULL) {
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
619
SDL_memcpy(commandLine + appNameText[0] + 1, prefs.command_line + 1,
prefs.command_line[0]);
commandLine[appNameText[0] + 1 + prefs.command_line[0]] = '\0';
620
621
/* Parse C-string into argv and argc */
622
623
624
625
626
627
628
629
630
631
632
633
634
635
nargs = ParseCommandLine(commandLine, NULL);
args = (char **) malloc((nargs + 1) * (sizeof *args));
if (args == NULL) {
exit(-1);
}
ParseCommandLine(commandLine, args);
/* Run the main application code */
SDL_main(nargs, args);
free(args);
free(commandLine);
/* Remove useless stdout.txt and stderr.txt */
cleanup_output();
636
#else // defined(__APPLE__) && defined(__MACH__)
637
SDL_main(argc, argv);
638
#endif
639
640
641
642
643
644
/* Exit cleanly, calling atexit() functions */
exit(0);
/* Never reached, but keeps the compiler quiet */
return (0);
645
}
646
647
/* vi: set ts=4 sw=4 expandtab: */