OSDN Git Service

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