OSDN Git Service

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