OSDN Git Service

[Fix] 属性への免疫を唱えた時のメッセージ
[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/record-play-movie.h"
15 #include "io/signal-handlers.h"
16 #include "io/uid-checker.h"
17 #include "main-unix/unix-user-ids.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     auto done = false;
253     auto new_game = false;
254     auto show_score = 0;
255     concptr mstr = nullptr;
256     auto args = true;
257     argv0 = argv[0];
258
259 #ifdef SET_UID
260     /* Default permissions on files */
261     (void)umask(022);
262 #endif
263
264     init_stuff();
265     auto &ids = UnixUserIds::get_instance();
266 #ifdef SET_UID
267     ids.set_user_id(getuid());
268 #ifdef VMS
269     ids.mod_user_id(getgid() * 1000);
270 #endif
271
272 #if defined(SAFE_SETUID) && defined(_POSIX_SAVED_IDS)
273     ids.set_effective_user_id(geteuid());
274     ids.set_effective_group_id(getegid());
275 #endif
276
277 #endif /* SET_UID */
278
279     safe_setuid_drop();
280 #ifdef SET_UID
281     user_name(p_ptr->name, ids.get_user_id());
282 #ifdef PRIVATE_USER_PATH
283     create_user_dir();
284 #endif /* PRIVATE_USER_PATH */
285 #endif /* SET_UID */
286
287     auto browsing_movie = false;
288     for (auto i = 1; args && (i < argc); i++) {
289         if (argv[i][0] != '-') {
290             display_usage(argv[0]);
291             continue;
292         }
293
294         auto is_usage_needed = false;
295         switch (argv[i][1]) {
296         case 'N':
297         case 'n':
298             new_game = true;
299             break;
300         case 'B':
301         case 'b':
302             arg_music = true;
303             break;
304         case 'V':
305         case 'v':
306             arg_sound = true;
307             break;
308         case 'G':
309         case 'g':
310             arg_graphics = GRAPHICS_ORIGINAL;
311             break;
312         case 'R':
313         case 'r':
314             arg_force_roguelike = true;
315             break;
316         case 'O':
317         case 'o':
318             arg_force_original = true;
319             break;
320         case 'S':
321         case 's':
322             show_score = atoi(&argv[i][2]);
323             if (show_score <= 0) {
324                 show_score = 10;
325             }
326
327             break;
328         case 'u':
329         case 'U':
330             if (!argv[i][2]) {
331                 is_usage_needed = true;
332                 break;
333             }
334
335             strcpy(p_ptr->name, &argv[i][2]);
336             break;
337         case 'm':
338             if (!argv[i][2]) {
339                 is_usage_needed = true;
340                 break;
341             }
342
343             mstr = &argv[i][2];
344             break;
345         case 'M':
346             arg_monochrome = true;
347             break;
348         case 'd':
349         case 'D':
350             change_path(&argv[i][2]);
351             break;
352         case 'x':
353             if (!argv[i][2]) {
354                 is_usage_needed = true;
355                 break;
356             }
357
358             prepare_browse_movie_with_path_build(&argv[i][2]);
359             browsing_movie = true;
360             break;
361         case '-':
362             if (argv[i][2] == '\0') {
363                 argv[i] = argv[0];
364                 argc = argc - i;
365                 argv = argv + i;
366                 args = false;
367             } else {
368                 is_usage_needed = parse_long_opt(argv[i]);
369             }
370
371             break;
372         default:
373             is_usage_needed = true;
374             break;
375         }
376
377         if (!is_usage_needed) {
378             continue;
379         }
380
381         display_usage(argv[0]);
382     }
383
384     if (args) {
385         argc = 1;
386         argv[1] = nullptr;
387     }
388
389     process_player_name(p_ptr, true);
390     quit_aux = quit_hook;
391
392 #ifdef USE_X11
393     if (!done && (!mstr || (streq(mstr, "x11")))) {
394         extern errr init_x11(int, char **);
395         if (0 == init_x11(argc, argv)) {
396             ANGBAND_SYS = "x11";
397             done = true;
398         }
399     }
400 #endif
401
402 #ifdef USE_GCU
403     if (!done && (!mstr || (streq(mstr, "gcu")))) {
404         extern errr init_gcu(int, char **);
405         if (0 == init_gcu(argc, argv)) {
406             ANGBAND_SYS = "gcu";
407             done = true;
408         }
409     }
410 #endif
411
412 #ifdef USE_CAP
413     if (!done && (!mstr || (streq(mstr, "cap")))) {
414         extern errr init_cap(int, char **);
415         if (0 == init_cap(argc, argv)) {
416             ANGBAND_SYS = "cap";
417             done = true;
418         }
419     }
420 #endif
421
422     if (!done) {
423         quit("Unable to prepare any 'display module'!");
424     }
425
426     if (show_score > 0) {
427         display_scores(0, show_score);
428     }
429
430     signals_init();
431
432     {
433         TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, MAIN_TERM_MIN_ROWS);
434         init_angband(p_ptr, false);
435         pause_line(MAIN_TERM_MIN_ROWS - 1);
436     }
437
438     play_game(p_ptr, new_game, browsing_movie);
439     quit(nullptr);
440     return 0;
441 }
442
443 #endif