OSDN Git Service

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