OSDN Git Service

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