2 * Copyright (c) 1997 Ben Harrison, and others
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.
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"
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"
35 * Available graphic modes
37 #define GRAPHICS_NONE 0
38 #define GRAPHICS_ORIGINAL 1
39 #define GRAPHICS_ADAM_BOLT 2
40 #define GRAPHICS_HENGBAND 3
43 * Some machines have a "main()" function in their "main-xxx.c" file,
44 * all the others use this file for their "main()" function.
49 * A hook for "quit()".
51 * Close down, then fall back into "quit()".
53 static void quit_hook(concptr s)
59 for (auto it = angband_terms.rbegin(); it != angband_terms.rend(); ++it) {
62 if (term == nullptr) {
72 * Set the stack size and overlay buffer (see main-286.c")
74 #ifdef PRIVATE_USER_PATH
77 * Create an ".angband/" directory in the users home directory.
79 * ToDo: Add error handling.
80 * ToDo: Only create the directories when actually writing files.
82 static void create_user_dir(void)
84 const auto &dirpath = path_parse(PRIVATE_USER_PATH).string();
85 mkdir(dirpath.data(), 0700);
87 char subdirpath[1024]{};
88 path_build(subdirpath, sizeof(subdirpath), dirpath, VARIANT_NAME);
89 mkdir(subdirpath, 0700);
92 #endif /* PRIVATE_USER_PATH */
95 * Initialize and verify the file paths, and the score file.
97 * Use the ANGBAND_PATH environment var if possible, else use
98 * DEFAULT_(LIB|VAR)_PATH, and in either case, branch off
101 * First, we'll look for the ANGBAND_PATH environment variable,
102 * and then look for the files in there. If that doesn't work,
103 * we'll try the DEFAULT_(LIB|VAR)_PATH constants. So be sure
104 * that one of these two things works...
106 * We must ensure that the path ends with "PATH_SEP" if needed,
107 * since the "init_file_paths()" function will simply append the
108 * relevant "sub-directory names" to the given path.
110 * Make sure that the path doesn't overflow the buffer. We have
111 * to leave enough space for the path separator, directory, and
114 static void init_stuff(void)
116 char libpath[1024], varpath[1024];
120 /* Get the environment variable */
121 tail = getenv("ANGBAND_PATH");
123 /* Use the angband_path, or a default */
124 strncpy(libpath, tail ? tail : DEFAULT_LIB_PATH, 511);
125 strncpy(varpath, tail ? tail : DEFAULT_VAR_PATH, 511);
127 /* Make sure they're terminated */
131 /* Hack -- Add a path separator (only if needed) */
132 if (!suffix(libpath, PATH_SEP)) {
133 strcat(libpath, PATH_SEP);
135 if (!suffix(varpath, PATH_SEP)) {
136 strcat(varpath, PATH_SEP);
140 init_file_paths(libpath, varpath);
144 * Handle a "-d<what>=<path>" option
146 * The "<what>" can be any string starting with the same letter as the
147 * name of a subdirectory of the "lib" folder (i.e. "i" or "info").
149 * The "<path>" can be any legal path for the given system, and should
150 * not end in any special path separator (i.e. "/tmp" or "~/.ang-info").
152 static void change_path(concptr info)
156 /* Find equal sign */
157 s = angband_strchr(info, '=');
159 /* Verify equal sign */
161 quit_fmt("Try '-d<what>=<path>' not '-d%s'", info);
165 switch (tolower(info[0])) {
167 string_free(ANGBAND_DIR_APEX);
168 ANGBAND_DIR_APEX = string_make(s + 1);
173 string_free(ANGBAND_DIR_FILE);
174 ANGBAND_DIR_FILE = string_make(s + 1);
179 string_free(ANGBAND_DIR_HELP);
180 ANGBAND_DIR_HELP = string_make(s + 1);
185 string_free(ANGBAND_DIR_INFO);
186 ANGBAND_DIR_INFO = string_make(s + 1);
191 string_free(ANGBAND_DIR_USER);
192 ANGBAND_DIR_USER = string_make(s + 1);
197 string_free(ANGBAND_DIR_XTRA);
198 ANGBAND_DIR_XTRA = string_make(s + 1);
203 string_free(ANGBAND_DIR_BONE);
204 ANGBAND_DIR_BONE = string_make(s + 1);
209 string_free(ANGBAND_DIR_DATA);
210 ANGBAND_DIR_DATA = string_make(s + 1);
215 string_free(ANGBAND_DIR_EDIT);
216 ANGBAND_DIR_EDIT = string_make(s + 1);
221 string_free(ANGBAND_DIR_SAVE);
222 ANGBAND_DIR_SAVE = string_make(s + 1);
227 string_free(ANGBAND_DIR_SCRIPT);
228 ANGBAND_DIR_SCRIPT = string_make(s + 1);
233 quit_fmt("Bad semantics in '-d%s'", info);
238 static void display_usage(const char *program)
240 /* Dump usage information */
241 printf("Usage: %s [options] [-- subopts]\n", program);
242 puts(" -n Start a new character");
243 puts(" -f Request fiddle mode");
244 puts(" -w Request wizard mode");
245 puts(" -b Request BGM mode");
246 puts(" -v Request sound mode");
247 puts(" -g Request graphics mode");
248 puts(" -o Request original keyset");
249 puts(" -r Request rogue-like keyset");
250 puts(" -M Request monochrome mode");
251 puts(" -s<num> Show <num> high scores");
252 puts(" -u<who> Use your <who> savefile");
253 puts(" -m<sys> Force 'main-<sys>.c' usage");
254 puts(" -d<def> Define a 'lib' dir sub-path");
255 puts(" --output-spoilers");
256 puts(" Output auto generated spoilers and exit");
260 puts(" -mx11 To use X11");
261 puts(" -- Sub options");
262 puts(" -- -d Set display name");
263 puts(" -- -o Request old 8x8 tile graphics");
264 puts(" -- -a Request Adam Bolt 16x16 tile graphics");
265 puts(" -- -b Request Bigtile graphics mode");
266 puts(" -- -s Turn off smoothscaling graphics");
267 puts(" -- -n# Number of terms to use");
272 puts(" -mgcu To use GCU (GNU Curses)");
273 puts(" -- Sub options");
274 puts(" -- -o old subwindow layout (no bigscreen)");
278 puts(" -mcap To use CAP (\"Termcap\" calls)");
281 /* Actually abort the process */
286 * @brief 2文字以上のコマンドライン引数 (オプション)を実行する
287 * @param opt コマンドライン引数
288 * @return Usageを表示する必要があるか否か
289 * @details v3.0.0 Alpha21時点では、スポイラー出力モードの判定及び実行を行う
291 static bool parse_long_opt(const char *opt)
293 if (strcmp(opt + 2, "output-spoilers") != 0) {
298 init_angband(p_ptr, true);
299 switch (output_all_spoilers()) {
300 case SpoilerOutputResultType::SUCCESSFUL:
301 puts("Successfully created a spoiler file.");
304 case SpoilerOutputResultType::FILE_OPEN_FAILED:
305 quit("Cannot create spoiler file.");
307 case SpoilerOutputResultType::FILE_CLOSE_FAILED:
308 quit("Cannot close spoiler file.");
318 * Simple "main" function for multiple platforms.
320 * Note the special "--" option which terminates the processing of
321 * standard options. All non-standard options (if any) are passed
322 * directly to the "init_xxx()" function.
324 int main(int argc, char *argv[])
329 bool new_game = false;
331 concptr mstr = nullptr;
334 /* Save the "program name" XXX XXX XXX */
339 /* Default permissions on files */
344 /* Get the file paths */
349 /* Get the user id (?) */
350 p_ptr->player_uid = getuid();
353 /* Mega-Hack -- Factor group id */
354 p_ptr->player_uid += (getgid() * 1000);
359 #ifdef _POSIX_SAVED_IDS
361 /* Save some info for later */
362 p_ptr->player_euid = geteuid();
363 p_ptr->player_egid = getegid();
371 /* Drop permissions */
376 /* Acquire the "user name" as a default player name */
377 user_name(p_ptr->name, p_ptr->player_uid);
379 #ifdef PRIVATE_USER_PATH
381 /* Create a directory for the users files. */
384 #endif /* PRIVATE_USER_PATH */
388 /* Process the command line arguments */
389 bool browsing_movie = false;
390 for (i = 1; args && (i < argc); i++) {
391 /* Require proper options */
392 if (argv[i][0] != '-') {
393 display_usage(argv[0]);
398 bool is_usage_needed = false;
399 switch (argv[i][1]) {
417 /* HACK - Graphics mode switches on the original tiles */
418 arg_graphics = GRAPHICS_ORIGINAL;
423 arg_force_roguelike = true;
428 arg_force_original = true;
433 show_score = atoi(&argv[i][2]);
434 if (show_score <= 0) {
442 is_usage_needed = true;
446 strcpy(p_ptr->name, &argv[i][2]);
451 is_usage_needed = true;
459 arg_monochrome = true;
464 change_path(&argv[i][2]);
469 is_usage_needed = true;
473 prepare_browse_movie_with_path_build(&argv[i][2]);
474 browsing_movie = true;
478 if (argv[i][2] == '\0') {
484 is_usage_needed = parse_long_opt(argv[i]);
489 is_usage_needed = true;
494 if (!is_usage_needed) {
498 display_usage(argv[0]);
501 /* Hack -- Forget standard args */
507 /* Process the player name */
508 process_player_name(p_ptr, true);
510 /* Install "quit" hook */
511 quit_aux = quit_hook;
514 /* Attempt to use the "main-x11.c" support */
515 if (!done && (!mstr || (streq(mstr, "x11")))) {
516 extern errr init_x11(int, char **);
517 if (0 == init_x11(argc, argv)) {
525 /* Attempt to use the "main-gcu.c" support */
526 if (!done && (!mstr || (streq(mstr, "gcu")))) {
527 extern errr init_gcu(int, char **);
528 if (0 == init_gcu(argc, argv)) {
536 /* Attempt to use the "main-cap.c" support */
537 if (!done && (!mstr || (streq(mstr, "cap")))) {
538 extern errr init_cap(int, char **);
539 if (0 == init_cap(argc, argv)) {
546 /* Make sure we have a display! */
548 quit("Unable to prepare any 'display module'!");
551 /* Hack -- If requested, display scores and quit */
552 if (show_score > 0) {
553 display_scores(0, show_score);
556 /* Catch nasty signals */
560 TermCenteredOffsetSetter tcos(MAIN_TERM_MIN_COLS, MAIN_TERM_MIN_ROWS);
563 init_angband(p_ptr, false);
565 /* Wait for response */
566 pause_line(MAIN_TERM_MIN_ROWS - 1);
570 play_game(p_ptr, new_game, browsing_movie);