OSDN Git Service

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