OSDN Git Service

Merge branch 'develop' into macos-develop
[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-unix/unix-user-ids.h"
19 #include "main/angband-initializer.h"
20 #include "player/process-name.h"
21 #include "system/angband-version.h"
22 #include "system/angband.h"
23 #include "system/player-type-definition.h"
24 #include "system/system-variables.h"
25 #include "term/gameterm.h"
26 #include "term/term-color-types.h"
27 #include "util/angband-files.h"
28 #include "util/string-processor.h"
29 #include "view/display-scores.h"
30 #include "wizard/spoiler-util.h"
31 #include "wizard/wizard-spoiler.h"
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 #if !defined(WINDOWS) && !defined(MACH_O_COCOA)
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 static void init_stuff()
72 {
73     char libpath[1024]{};
74     const auto tail = getenv("ANGBAND_PATH");
75     strncpy(libpath, tail ? tail : DEFAULT_LIB_PATH, 511);
76     if (!suffix(libpath, PATH_SEP)) {
77         strcat(libpath, PATH_SEP);
78     }
79
80     init_file_paths(libpath, libpath);
81 }
82
83 /*
84  * Handle a "-d<what>=<path>" option
85  *
86  * The "<what>" can be any string starting with the same letter as the
87  * name of a subdirectory of the "lib" folder (i.e. "i" or "info").
88  *
89  * The "<path>" can be any legal path for the given system, and should
90  * not end in any special path separator (i.e. "/tmp" or "~/.ang-info").
91  */
92 static void change_path(concptr info)
93 {
94     const auto s = angband_strchr(info, '=');
95
96     /* Verify equal sign */
97     if (!s) {
98         quit_fmt("Try '-d<what>=<path>' not '-d%s'", info);
99     }
100
101     switch (tolower(info[0])) {
102     case 'a':
103         ANGBAND_DIR_APEX = s + 1;
104         break;
105     case 'f':
106         ANGBAND_DIR_FILE = s + 1;
107         break;
108     case 'h':
109         ANGBAND_DIR_HELP = s + 1;
110         break;
111     case 'i':
112         ANGBAND_DIR_INFO = s + 1;
113         break;
114     case 'u':
115         ANGBAND_DIR_USER = s + 1;
116         break;
117     case 'x':
118         ANGBAND_DIR_XTRA = s + 1;
119         break;
120     case 'b':
121         ANGBAND_DIR_BONE = s + 1;
122         break;
123     case 'd':
124         ANGBAND_DIR_DATA = s + 1;
125         break;
126     case 'e':
127         ANGBAND_DIR_EDIT = s + 1;
128         break;
129     case 's':
130         ANGBAND_DIR_SAVE = s + 1;
131         break;
132     case 'z':
133         ANGBAND_DIR_SCRIPT = s + 1;
134         break;
135     default:
136         quit_fmt("Bad semantics in '-d%s'", info);
137     }
138 }
139
140 static void display_usage(const char *program)
141 {
142     /* Dump usage information */
143     printf("Usage: %s [options] [-- subopts]\n", program);
144     puts("  -n       Start a new character");
145     puts("  -f       Request fiddle mode");
146     puts("  -w       Request wizard mode");
147     puts("  -b       Request BGM mode");
148     puts("  -v       Request sound mode");
149     puts("  -g       Request graphics mode");
150     puts("  -o       Request original keyset");
151     puts("  -r       Request rogue-like keyset");
152     puts("  -M       Request monochrome mode");
153     puts("  -s<num>  Show <num> high scores");
154     puts("  -u<who>  Use your <who> savefile");
155     puts("  -m<sys>  Force 'main-<sys>.c' usage");
156     puts("  -d<def>  Define a 'lib' dir sub-path");
157     puts("  --output-spoilers");
158     puts("           Output auto generated spoilers and exit");
159     puts("");
160
161 #ifdef USE_X11
162     puts("  -mx11    To use X11");
163     puts("  --       Sub options");
164     puts("  -- -d    Set display name");
165     puts("  -- -o    Request old 8x8 tile graphics");
166     puts("  -- -a    Request Adam Bolt 16x16 tile graphics");
167     puts("  -- -b    Request Bigtile graphics mode");
168     puts("  -- -s    Turn off smoothscaling graphics");
169     puts("  -- -n#   Number of terms to use");
170     puts("");
171 #endif /* USE_X11 */
172
173 #ifdef USE_GCU
174     puts("  -mgcu    To use GCU (GNU Curses)");
175     puts("  --       Sub options");
176     puts("  -- -o    old subwindow layout (no bigscreen)");
177 #endif /* USE_GCU */
178
179 #ifdef USE_CAP
180     puts("  -mcap    To use CAP (\"Termcap\" calls)");
181 #endif /* USE_CAP */
182
183     /* Actually abort the process */
184     quit(nullptr);
185 }
186
187 /*
188  * @brief 2文字以上のコマンドライン引数 (オプション)を実行する
189  * @param opt コマンドライン引数
190  * @return Usageを表示する必要があるか否か
191  * @details v3.0.0 Alpha21時点では、スポイラー出力モードの判定及び実行を行う
192  */
193 static bool parse_long_opt(const char *opt)
194 {
195     if (strcmp(opt + 2, "output-spoilers") != 0) {
196         return true;
197     }
198
199     init_stuff();
200     init_angband(p_ptr, true);
201     switch (output_all_spoilers()) {
202     case SpoilerOutputResultType::SUCCESSFUL:
203         puts("Successfully created a spoiler file.");
204         quit(nullptr);
205         break;
206     case SpoilerOutputResultType::FILE_OPEN_FAILED:
207         quit("Cannot create spoiler file.");
208         break;
209     case SpoilerOutputResultType::FILE_CLOSE_FAILED:
210         quit("Cannot close spoiler file.");
211         break;
212     default:
213         break;
214     }
215
216     return false;
217 }
218
219 /*
220  * Simple "main" function for multiple platforms.
221  *
222  * Note the special "--" option which terminates the processing of
223  * standard options.  All non-standard options (if any) are passed
224  * directly to the "init_xxx()" function.
225  */
226 int main(int argc, char *argv[])
227 {
228     auto done = false;
229     auto new_game = false;
230     auto show_score = 0;
231     concptr mstr = nullptr;
232     auto args = true;
233     argv0 = argv[0];
234
235 #ifdef SET_UID
236     /* Default permissions on files */
237     (void)umask(022);
238 #endif
239
240     init_stuff();
241     auto &ids = UnixUserIds::get_instance();
242 #ifdef SET_UID
243     ids.set_user_id(getuid());
244 #ifdef VMS
245     ids.mod_user_id(getgid() * 1000);
246 #endif
247
248 #if defined(SAFE_SETUID) && defined(_POSIX_SAVED_IDS)
249     ids.set_effective_user_id(geteuid());
250     ids.set_effective_group_id(getegid());
251 #endif
252
253 #endif /* SET_UID */
254
255     safe_setuid_drop();
256 #ifdef SET_UID
257     user_name(p_ptr->name, ids.get_user_id());
258 #ifdef PRIVATE_USER_PATH
259     /* Create a directory for the user's files; handled by init.c. */
260     create_needed_dirs();
261 #endif /* PRIVATE_USER_PATH */
262 #endif /* SET_UID */
263
264     auto browsing_movie = false;
265     for (auto i = 1; args && (i < argc); i++) {
266         if (argv[i][0] != '-') {
267             display_usage(argv[0]);
268             continue;
269         }
270
271         auto is_usage_needed = false;
272         switch (argv[i][1]) {
273         case 'N':
274         case 'n':
275             new_game = true;
276             break;
277         case 'B':
278         case 'b':
279             arg_music = true;
280             break;
281         case 'V':
282         case 'v':
283             arg_sound = true;
284             break;
285         case 'G':
286         case 'g':
287             arg_graphics = GRAPHICS_ORIGINAL;
288             break;
289         case 'R':
290         case 'r':
291             arg_force_roguelike = true;
292             break;
293         case 'O':
294         case 'o':
295             arg_force_original = true;
296             break;
297         case 'S':
298         case 's':
299             show_score = atoi(&argv[i][2]);
300             if (show_score <= 0) {
301                 show_score = 10;
302             }
303
304             break;
305         case 'u':
306         case 'U':
307             if (!argv[i][2]) {
308                 is_usage_needed = true;
309                 break;
310             }
311
312             strcpy(p_ptr->name, &argv[i][2]);
313             break;
314         case 'm':
315             if (!argv[i][2]) {
316                 is_usage_needed = true;
317                 break;
318             }
319
320             mstr = &argv[i][2];
321             break;
322         case 'M':
323             arg_monochrome = true;
324             break;
325         case 'd':
326         case 'D':
327             change_path(&argv[i][2]);
328             break;
329         case 'x':
330             if (!argv[i][2]) {
331                 is_usage_needed = true;
332                 break;
333             }
334
335             prepare_browse_movie_with_path_build(&argv[i][2]);
336             browsing_movie = true;
337             break;
338         case '-':
339             if (argv[i][2] == '\0') {
340                 argv[i] = argv[0];
341                 argc = argc - i;
342                 argv = argv + i;
343                 args = false;
344             } else {
345                 is_usage_needed = parse_long_opt(argv[i]);
346             }
347
348             break;
349         default:
350             is_usage_needed = true;
351             break;
352         }
353
354         if (!is_usage_needed) {
355             continue;
356         }
357
358         display_usage(argv[0]);
359     }
360
361     if (args) {
362         argc = 1;
363         argv[1] = nullptr;
364     }
365
366     process_player_name(p_ptr, true);
367     quit_aux = quit_hook;
368
369 #ifdef USE_X11
370     if (!done && (!mstr || (streq(mstr, "x11")))) {
371         extern errr init_x11(int, char **);
372         if (0 == init_x11(argc, argv)) {
373             ANGBAND_SYS = "x11";
374             done = true;
375         }
376     }
377 #endif
378
379 #ifdef USE_GCU
380     if (!done && (!mstr || (streq(mstr, "gcu")))) {
381         extern errr init_gcu(int, char **);
382         if (0 == init_gcu(argc, argv)) {
383             ANGBAND_SYS = "gcu";
384             done = true;
385         }
386     }
387 #endif
388
389 #ifdef USE_CAP
390     if (!done && (!mstr || (streq(mstr, "cap")))) {
391         extern errr init_cap(int, char **);
392         if (0 == init_cap(argc, argv)) {
393             ANGBAND_SYS = "cap";
394             done = true;
395         }
396     }
397 #endif
398
399     if (!done) {
400         quit("Unable to prepare any 'display module'!");
401     }
402
403     if (show_score > 0) {
404         display_scores(0, show_score);
405     }
406
407     signals_init();
408
409     {
410         TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, MAIN_TERM_MIN_ROWS);
411         init_angband(p_ptr, false);
412         pause_line(MAIN_TERM_MIN_ROWS - 1);
413     }
414
415     play_game(p_ptr, new_game, browsing_movie);
416     quit(nullptr);
417     return 0;
418 }
419
420 #endif