OSDN Git Service

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