OSDN Git Service

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