OSDN Git Service

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