OSDN Git Service

[update] Usage出力で実行プログラム名を表示する
[hengbandforosx/hengbandosx.git] / src / main.c
1 /*
2  * Copyright (c) 1997 Ben Harrison, and others
3  *
4  * This software may be copied and distributed for educational, research,
5  * and not for profit purposes provided that this copyright and statement
6  * are included in all such copies.
7  */
8
9 #include "autopick/autopick-pref-processor.h"
10 #include "core/asking-player.h"
11 #include "core/game-play.h"
12 #include "core/scores.h"
13 #include "game-option/runtime-arguments.h"
14 #include "io/files-util.h"
15 #include "io/inet.h"
16 #include "io/record-play-movie.h"
17 #include "io/signal-handlers.h"
18 #include "io/uid-checker.h"
19 #include "main/angband-initializer.h"
20 #include "player/process-name.h"
21 #include "system/angband-version.h"
22 #include "system/angband.h"
23 #include "system/system-variables.h"
24 #include "term/gameterm.h"
25 #include "term/term-color-types.h"
26 #include "util/angband-files.h"
27 #include "util/string-processor.h"
28 #include "wizard/wizard-spoiler.h"
29
30 /*
31  * Available graphic modes
32  */
33 #define GRAPHICS_NONE 0
34 #define GRAPHICS_ORIGINAL 1
35 #define GRAPHICS_ADAM_BOLT 2
36 #define GRAPHICS_HENGBAND 3
37
38 /*
39  * Some machines have a "main()" function in their "main-xxx.c" file,
40  * all the others use this file for their "main()" function.
41  */
42
43 #ifndef WINDOWS
44 /*
45  * A hook for "quit()".
46  *
47  * Close down, then fall back into "quit()".
48  */
49 static void quit_hook(concptr s)
50 {
51     int j;
52
53     /* Unused */
54     (void)s;
55
56     /* Scan windows */
57     for (j = 8 - 1; j >= 0; j--) {
58         /* Unused */
59         if (!angband_term[j])
60             continue;
61
62         /* Nuke it */
63         term_nuke(angband_term[j]);
64     }
65 }
66
67 /*
68  * Set the stack size and overlay buffer (see main-286.c")
69  */
70 #ifdef PRIVATE_USER_PATH
71
72 /*
73  * Create an ".angband/" directory in the users home directory.
74  *
75  * ToDo: Add error handling.
76  * ToDo: Only create the directories when actually writing files.
77  */
78 static void create_user_dir(void)
79 {
80     char dirpath[1024];
81     char subdirpath[1024];
82
83     /* Get an absolute path from the filename */
84     path_parse(dirpath, 1024, PRIVATE_USER_PATH);
85
86     /* Create the ~/.angband/ directory */
87     mkdir(dirpath, 0700);
88
89     /* Build the path to the variant-specific sub-directory */
90     path_build(subdirpath, sizeof(subdirpath), dirpath, VERSION_NAME);
91
92     /* Create the directory */
93     mkdir(subdirpath, 0700);
94 }
95
96 #endif /* PRIVATE_USER_PATH */
97
98 /*
99  * Initialize and verify the file paths, and the score file.
100  *
101  * Use the ANGBAND_PATH environment var if possible, else use
102  * DEFAULT_(LIB|VAR)_PATH, and in either case, branch off
103  * appropriately.
104  *
105  * First, we'll look for the ANGBAND_PATH environment variable,
106  * and then look for the files in there.  If that doesn't work,
107  * we'll try the DEFAULT_(LIB|VAR)_PATH constants.  So be sure
108  * that one of these two things works...
109  *
110  * We must ensure that the path ends with "PATH_SEP" if needed,
111  * since the "init_file_paths()" function will simply append the
112  * relevant "sub-directory names" to the given path.
113  *
114  * Make sure that the path doesn't overflow the buffer.  We have
115  * to leave enough space for the path separator, directory, and
116  * filenames.
117  */
118 static void init_stuff(void)
119 {
120     char libpath[1024], varpath[1024];
121
122     concptr tail;
123
124     /* Get the environment variable */
125     tail = getenv("ANGBAND_PATH");
126
127     /* Use the angband_path, or a default */
128     strncpy(libpath, tail ? tail : DEFAULT_LIB_PATH, 511);
129     strncpy(varpath, tail ? tail : DEFAULT_VAR_PATH, 511);
130
131     /* Make sure they're terminated */
132     libpath[511] = '\0';
133     varpath[511] = '\0';
134
135     /* Hack -- Add a path separator (only if needed) */
136     if (!suffix(libpath, PATH_SEP))
137         strcat(libpath, PATH_SEP);
138     if (!suffix(varpath, PATH_SEP))
139         strcat(varpath, PATH_SEP);
140
141     /* Initialize */
142     init_file_paths(libpath, varpath);
143 }
144
145 /*
146  * Handle a "-d<what>=<path>" option
147  *
148  * The "<what>" can be any string starting with the same letter as the
149  * name of a subdirectory of the "lib" folder (i.e. "i" or "info").
150  *
151  * The "<path>" can be any legal path for the given system, and should
152  * not end in any special path separator (i.e. "/tmp" or "~/.ang-info").
153  */
154 static void change_path(concptr info)
155 {
156     concptr s;
157
158     /* Find equal sign */
159     s = angband_strchr(info, '=');
160
161     /* Verify equal sign */
162     if (!s)
163         quit_fmt("Try '-d<what>=<path>' not '-d%s'", info);
164
165     /* Analyze */
166     switch (tolower(info[0])) {
167     case 'a': {
168         string_free(ANGBAND_DIR_APEX);
169         ANGBAND_DIR_APEX = string_make(s + 1);
170         break;
171     }
172
173     case 'f': {
174         string_free(ANGBAND_DIR_FILE);
175         ANGBAND_DIR_FILE = string_make(s + 1);
176         break;
177     }
178
179     case 'h': {
180         string_free(ANGBAND_DIR_HELP);
181         ANGBAND_DIR_HELP = string_make(s + 1);
182         break;
183     }
184
185     case 'i': {
186         string_free(ANGBAND_DIR_INFO);
187         ANGBAND_DIR_INFO = string_make(s + 1);
188         break;
189     }
190
191     case 'u': {
192         string_free(ANGBAND_DIR_USER);
193         ANGBAND_DIR_USER = string_make(s + 1);
194         break;
195     }
196
197     case 'x': {
198         string_free(ANGBAND_DIR_XTRA);
199         ANGBAND_DIR_XTRA = string_make(s + 1);
200         break;
201     }
202
203     case 'b': {
204         string_free(ANGBAND_DIR_BONE);
205         ANGBAND_DIR_BONE = string_make(s + 1);
206         break;
207     }
208
209     case 'd': {
210         string_free(ANGBAND_DIR_DATA);
211         ANGBAND_DIR_DATA = string_make(s + 1);
212         break;
213     }
214
215     case 'e': {
216         string_free(ANGBAND_DIR_EDIT);
217         ANGBAND_DIR_EDIT = string_make(s + 1);
218         break;
219     }
220
221     case 's': {
222         string_free(ANGBAND_DIR_SAVE);
223         ANGBAND_DIR_SAVE = string_make(s + 1);
224         break;
225     }
226
227     case 'z': {
228         string_free(ANGBAND_DIR_SCRIPT);
229         ANGBAND_DIR_SCRIPT = string_make(s + 1);
230         break;
231     }
232
233     default: {
234         quit_fmt("Bad semantics in '-d%s'", info);
235     }
236     }
237 }
238
239 static void display_usage(const char* program)
240 {
241     /* Dump usage information */
242     printf("Usage: %s [options] [-- subopts]\n", program);
243     puts("  -n       Start a new character");
244     puts("  -f       Request fiddle mode");
245     puts("  -w       Request wizard mode");
246     puts("  -b       Request BGM mode");
247     puts("  -v       Request sound mode");
248     puts("  -g       Request graphics mode");
249     puts("  -o       Request original keyset");
250     puts("  -r       Request rogue-like keyset");
251     puts("  -M       Request monochrome mode");
252     puts("  -s<num>  Show <num> high scores");
253     puts("  -u<who>  Use your <who> savefile");
254     puts("  -m<sys>  Force 'main-<sys>.c' usage");
255     puts("  -d<def>  Define a 'lib' dir sub-path");
256     puts("  --output-spoilers");
257     puts("           Output auto generated spoilers and exit");
258     puts("");
259
260 #ifdef USE_X11
261     puts("  -mx11    To use X11");
262     puts("  --       Sub options");
263     puts("  -- -d    Set display name");
264     puts("  -- -o    Request old 8x8 tile graphics");
265     puts("  -- -a    Request Adam Bolt 16x16 tile graphics");
266     puts("  -- -b    Request Bigtile graphics mode");
267     puts("  -- -s    Turn off smoothscaling graphics");
268     puts("  -- -n#   Number of terms to use");
269     puts("");
270 #endif /* USE_X11 */
271
272 #ifdef USE_GCU
273     puts("  -mgcu    To use GCU (GNU Curses)");
274 #endif /* USE_GCU */
275
276 #ifdef USE_CAP
277     puts("  -mcap    To use CAP (\"Termcap\" calls)");
278 #endif /* USE_CAP */
279
280     /* Actually abort the process */
281     quit(NULL);
282 }
283
284 static bool parse_long_opt(const char *opt)
285 {
286     bool is_usage_needed = TRUE;
287
288     if (strcmp(opt + 2, "output-spoilers") == 0) {
289         init_stuff();
290         init_angband(p_ptr, process_autopick_file_command, TRUE);
291         switch (output_all_spoilers()) {
292         case SPOILER_OUTPUT_SUCCESS:
293             puts("Successfully created a spiler file.");
294             quit(NULL);
295             break;
296         case SPOILER_OUTPUT_FAIL_FOPEN:
297             quit("Cannot create spoiler file.");
298             break;
299         case SPOILER_OUTPUT_FAIL_FCLOSE:
300             quit("Cannot close spoiler file.");
301             break;
302         default:
303             break;
304         }
305         is_usage_needed = FALSE;
306     }
307
308     return is_usage_needed;
309 }
310
311 /*
312  * Simple "main" function for multiple platforms.
313  *
314  * Note the special "--" option which terminates the processing of
315  * standard options.  All non-standard options (if any) are passed
316  * directly to the "init_xxx()" function.
317  */
318 int main(int argc, char *argv[])
319 {
320     int i;
321
322     bool done = FALSE;
323     bool new_game = FALSE;
324     int show_score = 0;
325     concptr mstr = NULL;
326     bool args = TRUE;
327
328     /* Save the "program name" XXX XXX XXX */
329     argv0 = argv[0];
330
331 #ifdef SET_UID
332
333     /* Default permissions on files */
334     (void)umask(022);
335
336 #endif
337
338     /* Get the file paths */
339     init_stuff();
340
341 #ifdef SET_UID
342
343     /* Get the user id (?) */
344     p_ptr->player_uid = getuid();
345
346 #ifdef VMS
347     /* Mega-Hack -- Factor group id */
348     p_ptr->player_uid += (getgid() * 1000);
349 #endif
350
351 #ifdef SAFE_SETUID
352
353 #ifdef _POSIX_SAVED_IDS
354
355     /* Save some info for later */
356     p_ptr->player_euid = geteuid();
357     p_ptr->player_egid = getegid();
358
359 #endif
360
361 #endif
362
363 #endif
364
365     /* Drop permissions */
366     safe_setuid_drop();
367
368 #ifdef SET_UID
369
370     /* Acquire the "user name" as a default player name */
371     user_name(p_ptr->name, p_ptr->player_uid);
372
373 #ifdef PRIVATE_USER_PATH
374
375     /* Create a directory for the users files. */
376     create_user_dir();
377
378 #endif /* PRIVATE_USER_PATH */
379
380 #endif /* SET_UID */
381
382     /* Process the command line arguments */
383     bool browsing_movie = FALSE;
384     for (i = 1; args && (i < argc); i++) {
385         /* Require proper options */
386         if (argv[i][0] != '-') {
387             display_usage(argv[0]);
388             continue;
389         }
390
391         /* Analyze option */
392         bool is_usage_needed = FALSE;
393         switch (argv[i][1]) {
394         case 'N':
395         case 'n': {
396             new_game = TRUE;
397             break;
398         }
399         case 'F':
400         case 'f': {
401             arg_fiddle = TRUE;
402             break;
403         }
404         case 'W':
405         case 'w': {
406             arg_wizard = TRUE;
407             break;
408         }
409         case 'B':
410         case 'b': {
411             arg_music = TRUE;
412             break;
413         }
414         case 'V':
415         case 'v': {
416             arg_sound = TRUE;
417             break;
418         }
419         case 'G':
420         case 'g': {
421             /* HACK - Graphics mode switches on the original tiles */
422             arg_graphics = GRAPHICS_ORIGINAL;
423             break;
424         }
425         case 'R':
426         case 'r': {
427             arg_force_roguelike = TRUE;
428             break;
429         }
430         case 'O':
431         case 'o': {
432             arg_force_original = TRUE;
433             break;
434         }
435         case 'S':
436         case 's': {
437             show_score = atoi(&argv[i][2]);
438             if (show_score <= 0)
439                 show_score = 10;
440             break;
441         }
442         case 'u':
443         case 'U': {
444             if (!argv[i][2]) {
445                 is_usage_needed = TRUE;
446                 break;
447             }
448
449             strcpy(p_ptr->name, &argv[i][2]);
450             break;
451         }
452         case 'm': {
453             if (!argv[i][2]) {
454                 is_usage_needed = TRUE;
455                 break;
456             }
457
458             mstr = &argv[i][2];
459             break;
460         }
461         case 'M': {
462             arg_monochrome = TRUE;
463             break;
464         }
465         case 'd':
466         case 'D': {
467             change_path(&argv[i][2]);
468             break;
469         }
470         case 'x': {
471             if (!argv[i][2]) {
472                 is_usage_needed = TRUE;
473                 break;
474             }
475
476             prepare_browse_movie_with_path_build(&argv[i][2]);
477             browsing_movie = TRUE;
478             break;
479         }
480         case '-': {
481             if (argv[i][2] == '\0') {
482                 argv[i] = argv[0];
483                 argc = argc - i;
484                 argv = argv + i;
485                 args = FALSE;
486             } else {
487                 is_usage_needed = parse_long_opt(argv[i]);
488             }
489             break;
490         }
491         default: {
492             is_usage_needed = TRUE;
493             break;
494         }
495         }
496
497         if (!is_usage_needed)
498             continue;
499
500         display_usage(argv[0]);
501     }
502
503     /* Hack -- Forget standard args */
504     if (args) {
505         argc = 1;
506         argv[1] = NULL;
507     }
508
509     /* Process the player name */
510     process_player_name(p_ptr, TRUE);
511
512     /* Install "quit" hook */
513     quit_aux = quit_hook;
514
515 #ifdef USE_XAW
516     /* Attempt to use the "main-xaw.c" support */
517     if (!done && (!mstr || (streq(mstr, "xaw")))) {
518         extern errr init_xaw(int, char **);
519         if (0 == init_xaw(argc, argv)) {
520             ANGBAND_SYS = "xaw";
521             done = TRUE;
522         }
523     }
524 #endif
525
526 #ifdef USE_X11
527     /* Attempt to use the "main-x11.c" support */
528     if (!done && (!mstr || (streq(mstr, "x11")))) {
529         extern errr init_x11(int, char **);
530         if (0 == init_x11(argc, argv)) {
531             ANGBAND_SYS = "x11";
532             done = TRUE;
533         }
534     }
535 #endif
536
537 #ifdef USE_GCU
538     /* Attempt to use the "main-gcu.c" support */
539     if (!done && (!mstr || (streq(mstr, "gcu")))) {
540         extern errr init_gcu(int, char **);
541         if (0 == init_gcu(argc, argv)) {
542             ANGBAND_SYS = "gcu";
543             done = TRUE;
544         }
545     }
546 #endif
547
548 #ifdef USE_CAP
549     /* Attempt to use the "main-cap.c" support */
550     if (!done && (!mstr || (streq(mstr, "cap")))) {
551         extern errr init_cap(int, char **);
552         if (0 == init_cap(argc, argv)) {
553             ANGBAND_SYS = "cap";
554             done = TRUE;
555         }
556     }
557 #endif
558
559     /* Make sure we have a display! */
560     if (!done)
561         quit("Unable to prepare any 'display module'!");
562
563     /* Hack -- If requested, display scores and quit */
564     if (show_score > 0)
565         display_scores(0, show_score);
566
567     /* Catch nasty signals */
568     signals_init();
569
570     /* Initialize */
571     init_angband(p_ptr, process_autopick_file_command, FALSE);
572
573     /* Wait for response */
574     pause_line(23);
575
576     /* Play the game */
577     play_game(p_ptr, new_game, browsing_movie);
578
579     /* Quit */
580     quit(NULL);
581
582     /* Exit */
583     return (0);
584 }
585
586 #endif