OSDN Git Service

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