OSDN Git Service

Merge remote-tracking branch 'remotes/origin/For2.2.2-Fix-Hourier' into For2.2.2...
[hengband/hengband.git] / src / main.c
1 /* File: main.c */
2
3 /*
4  * Copyright (c) 1997 Ben Harrison, and others
5  *
6  * This software may be copied and distributed for educational, research,
7  * and not for profit purposes provided that this copyright and statement
8  * are included in all such copies.
9  */
10
11 #include "system/angband.h"
12 #include "autopick/autopick-pref-processor.h"
13 #include "core/game-play.h"
14 #include "core/scores.h"
15 #include "game-option/runtime-arguments.h"
16 #include "io/chuukei.h"
17 #include "io/files-util.h"
18 #include "io/inet.h"
19 #include "io/signal-handlers.h"
20 #include "io/uid-checker.h"
21 #include "main/init.h"
22 #include "player/process-name.h"
23 #include "system/angband-version.h"
24 #include "system/system-variables.h"
25 #include "term/gameterm.h"
26 #include "term/term-color-types.h"
27
28 /*
29  * Available graphic modes
30  */
31 #define GRAPHICS_NONE       0
32 #define GRAPHICS_ORIGINAL   1
33 #define GRAPHICS_ADAM_BOLT  2
34 #define GRAPHICS_HENGBAND   3
35
36 /*
37  * Some machines have a "main()" function in their "main-xxx.c" file,
38  * all the others use this file for their "main()" function.
39  */
40
41
42 #if !defined(WINDOWS)
43
44 /*
45  * A hook for "quit()".
46  *
47  * Close down, then fall back into "quit()".
48  */
49 static void quit_hook(concptr s)
50 {
51         int j;
52
53         /* Unused */
54         (void)s;
55
56         /* Scan windows */
57         for (j = 8 - 1; j >= 0; j--)
58         {
59                 /* Unused */
60                 if (!angband_term[j]) continue;
61
62                 /* Nuke it */
63                 term_nuke(angband_term[j]);
64         }
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 /*
101  * Initialize and verify the file paths, and the score file.
102  *
103  * Use the ANGBAND_PATH environment var if possible, else use
104  * DEFAULT_PATH, and in either case, branch off 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_PATH constant.  So be sure that one of
109  * 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 path[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(path, tail ? tail : DEFAULT_PATH, 511);
130
131         /* Make sure it's terminated */
132         path[511] = '\0';
133
134         /* Hack -- Add a path separator (only if needed) */
135         if (!suffix(path, PATH_SEP)) strcat(path, PATH_SEP);
136
137         /* Initialize */
138         init_file_paths(path);
139 }
140
141
142
143 /*
144  * Handle a "-d<what>=<path>" option
145  *
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").
148  *
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").
151  */
152 static void change_path(concptr info)
153 {
154         concptr s;
155
156         /* Find equal sign */
157         s = angband_strchr(info, '=');
158
159         /* Verify equal sign */
160         if (!s) quit_fmt("Try '-d<what>=<path>' not '-d%s'", info);
161
162         /* Analyze */
163         switch (tolower(info[0]))
164         {
165                 case 'a':
166                 {
167                         string_free(ANGBAND_DIR_APEX);
168                         ANGBAND_DIR_APEX = string_make(s+1);
169                         break;
170                 }
171
172                 case 'f':
173                 {
174                         string_free(ANGBAND_DIR_FILE);
175                         ANGBAND_DIR_FILE = string_make(s+1);
176                         break;
177                 }
178
179                 case 'h':
180                 {
181                         string_free(ANGBAND_DIR_HELP);
182                         ANGBAND_DIR_HELP = string_make(s+1);
183                         break;
184                 }
185
186                 case 'i':
187                 {
188                         string_free(ANGBAND_DIR_INFO);
189                         ANGBAND_DIR_INFO = string_make(s+1);
190                         break;
191                 }
192
193                 case 'u':
194                 {
195                         string_free(ANGBAND_DIR_USER);
196                         ANGBAND_DIR_USER = string_make(s+1);
197                         break;
198                 }
199
200                 case 'x':
201                 {
202                         string_free(ANGBAND_DIR_XTRA);
203                         ANGBAND_DIR_XTRA = string_make(s+1);
204                         break;
205                 }
206
207                 case 'b':
208                 {
209                         string_free(ANGBAND_DIR_BONE);
210                         ANGBAND_DIR_BONE = string_make(s+1);
211                         break;
212                 }
213
214                 case 'd':
215                 {
216                         string_free(ANGBAND_DIR_DATA);
217                         ANGBAND_DIR_DATA = string_make(s+1);
218                         break;
219                 }
220
221                 case 'e':
222                 {
223                         string_free(ANGBAND_DIR_EDIT);
224                         ANGBAND_DIR_EDIT = string_make(s+1);
225                         break;
226                 }
227
228                 case 's':
229                 {
230                         string_free(ANGBAND_DIR_SAVE);
231                         ANGBAND_DIR_SAVE = string_make(s+1);
232                         break;
233                 }
234
235                 case 'z':
236                 {
237                         string_free(ANGBAND_DIR_SCRIPT);
238                         ANGBAND_DIR_SCRIPT = string_make(s+1);
239                         break;
240                 }
241
242                 default:
243                 {
244                         quit_fmt("Bad semantics in '-d%s'", info);
245                 }
246         }
247 }
248
249 static void display_usage(void)
250 {
251         /* Dump usage information */
252         puts("Usage: angband [options] [-- subopts]");
253         puts("  -n       Start a new character");
254         puts("  -f       Request fiddle mode");
255         puts("  -w       Request wizard mode");
256         puts("  -b       Request BGM mode");
257         puts("  -v       Request sound mode");
258         puts("  -g       Request graphics mode");
259         puts("  -o       Request original keyset");
260         puts("  -r       Request rogue-like keyset");
261         puts("  -M       Request monochrome mode");
262         puts("  -s<num>  Show <num> high scores");
263         puts("  -u<who>  Use your <who> savefile");
264         puts("  -m<sys>  Force 'main-<sys>.c' usage");
265         puts("  -d<def>  Define a 'lib' dir sub-path");
266         puts("");
267
268 #ifdef USE_X11
269         puts("  -mx11    To use X11");
270         puts("  --       Sub options");
271         puts("  -- -d    Set display name");
272         puts("  -- -o    Request old 8x8 tile graphics");
273         puts("  -- -a    Request Adam Bolt 16x16 tile graphics");
274         puts("  -- -b    Request Bigtile graphics mode");
275         puts("  -- -s    Turn off smoothscaling graphics");
276         puts("  -- -n#   Number of terms to use");
277         puts("");
278 #endif /* USE_X11 */
279
280 #ifdef USE_GCU
281         puts("  -mgcu    To use GCU (GNU Curses)");
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(NULL);
290 }
291
292
293 /*
294  * Simple "main" function for multiple platforms.
295  *
296  * Note the special "--" option which terminates the processing of
297  * standard options.  All non-standard options (if any) are passed
298  * directly to the "init_xxx()" function.
299  */
300 int main(int argc, char *argv[])
301 {
302         int i;
303
304         bool done = FALSE;
305         bool new_game = FALSE;
306         int show_score = 0;
307         concptr mstr = NULL;
308         bool args = TRUE;
309
310         /* Save the "program name" XXX XXX XXX */
311         argv0 = argv[0];
312
313 #ifdef SET_UID
314
315         /* Default permissions on files */
316         (void)umask(022);
317
318 #endif
319
320
321         /* Get the file paths */
322         init_stuff();
323
324
325 #ifdef SET_UID
326
327         /* Get the user id (?) */
328         p_ptr->player_uid = getuid();
329
330 #ifdef VMS
331         /* Mega-Hack -- Factor group id */
332         p_ptr->player_uid += (getgid() * 1000);
333 #endif
334
335 # ifdef SAFE_SETUID
336
337 #  ifdef _POSIX_SAVED_IDS
338
339         /* Save some info for later */
340         p_ptr->player_euid = geteuid();
341         p_ptr->player_egid = getegid();
342
343 #  endif
344
345 # endif
346
347 #endif
348
349
350         /* Drop permissions */
351         safe_setuid_drop();
352
353
354 #ifdef SET_UID
355
356         /* Acquire the "user name" as a default player name */
357         user_name(p_ptr->name, p_ptr->player_uid);
358
359 #ifdef PRIVATE_USER_PATH
360
361         /* Create a directory for the users files. */
362         create_user_dir();
363
364 #endif /* PRIVATE_USER_PATH */
365
366 #endif /* SET_UID */
367
368
369         /* Process the command line arguments */
370         for (i = 1; args && (i < argc); i++)
371         {
372                 /* Require proper options */
373                 if (argv[i][0] != '-')
374                 {
375                         display_usage();
376                         continue;
377                 }
378
379                 /* Analyze option */
380                 bool is_usage_needed = FALSE;
381                 switch (argv[i][1])
382                 {
383                         case 'N':
384                         case 'n':
385                         {
386                                 new_game = TRUE;
387                                 break;
388                         }
389                         case 'F':
390                         case 'f':
391                         {
392                                 arg_fiddle = TRUE;
393                                 break;
394                         }
395                         case 'W':
396                         case 'w':
397                         {
398                                 arg_wizard = TRUE;
399                                 break;
400                         }
401                         case 'B':
402                         case 'b':
403                         {
404                                 arg_music = TRUE;
405                                 break;
406                         }
407                         case 'V':
408                         case 'v':
409                         {
410                                 arg_sound = TRUE;
411                                 break;
412                         }
413                         case 'G':
414                         case 'g':
415                         {
416                                 /* HACK - Graphics mode switches on the original tiles */
417                                 arg_graphics = GRAPHICS_ORIGINAL;
418                                 break;
419                         }
420                         case 'R':
421                         case 'r':
422                         {
423                                 arg_force_roguelike = TRUE;
424                                 break;
425                         }
426                         case 'O':
427                         case 'o':
428                         {
429                                 arg_force_original = TRUE;
430                                 break;
431                         }
432                         case 'S':
433                         case 's':
434                         {
435                                 show_score = atoi(&argv[i][2]);
436                                 if (show_score <= 0) show_score = 10;
437                                 break;
438                         }
439                         case 'u':
440                         case 'U':
441                         {
442                                 if (!argv[i][2])
443                                 {
444                                         is_usage_needed = TRUE;
445                                         break;
446                                 }
447
448                                 strcpy(p_ptr->name, &argv[i][2]);
449                                 break;
450                         }
451                         case 'm':
452                         {
453                                 if (!argv[i][2])
454                                 {
455                                         is_usage_needed = TRUE;
456                                         break;
457                                 }
458
459                                 mstr = &argv[i][2];
460                                 break;
461                         }
462                         case 'M':
463                         {
464                                 arg_monochrome = TRUE;
465                                 break;
466                         }
467                         case 'd':
468                         case 'D':
469                         {
470                                 change_path(&argv[i][2]);
471                                 break;
472                         }
473 #ifdef CHUUKEI
474                         case 'p':
475                         case 'P':
476                         {
477                                 if (!argv[i][2])
478                                 {
479                                         is_usage_needed = TRUE;
480                                         break;
481                                 }
482
483                                 chuukei_server = TRUE;
484                                 if (connect_chuukei_server(&argv[i][2]) < 0) chuukei_server = FALSE;
485                                 break;
486                         }
487
488                         case 'c':
489                         case 'C':
490                         {
491                                 if (!argv[i][2])
492                                 {
493                                         is_usage_needed = TRUE;
494                                         break;
495                                 }
496
497                                 chuukei_client = TRUE;
498                                 connect_chuukei_server(&argv[i][2]);
499                                 break;
500                         }
501 #endif
502                         case 'x':
503                         {
504                                 if (!argv[i][2])
505                                 {
506                                         is_usage_needed = TRUE;
507                                         break;
508                                 }
509
510                                 prepare_browse_movie(&argv[i][2]);
511                                 break;
512                         }
513                         case '-':
514                         {
515                                 argv[i] = argv[0];
516                                 argc = argc - i;
517                                 argv = argv + i;
518                                 args = FALSE;
519                                 break;
520                         }
521                         default:
522                         {
523                                 is_usage_needed = TRUE;
524                                 break;
525                         }
526                 }
527
528                 if (!is_usage_needed) continue;
529
530                 display_usage();
531         }
532
533         /* Hack -- Forget standard args */
534         if (args)
535         {
536                 argc = 1;
537                 argv[1] = NULL;
538         }
539
540
541         /* Process the player name */
542         process_player_name(p_ptr,TRUE);
543
544
545
546         /* Install "quit" hook */
547         quit_aux = quit_hook;
548
549
550
551 #ifdef USE_XAW
552         /* Attempt to use the "main-xaw.c" support */
553         if (!done && (!mstr || (streq(mstr, "xaw"))))
554         {
555                 extern errr init_xaw(int, char**);
556                 if (0 == init_xaw(argc, argv))
557                 {
558                         ANGBAND_SYS = "xaw";
559                         done = TRUE;
560                 }
561         }
562 #endif
563
564 #ifdef USE_X11
565         /* Attempt to use the "main-x11.c" support */
566         if (!done && (!mstr || (streq(mstr, "x11"))))
567         {
568                 extern errr init_x11(int, char**);
569                 if (0 == init_x11(argc, argv))
570                 {
571                         ANGBAND_SYS = "x11";
572                         done = TRUE;
573                 }
574         }
575 #endif
576
577 #ifdef USE_GCU
578         /* Attempt to use the "main-gcu.c" support */
579         if (!done && (!mstr || (streq(mstr, "gcu"))))
580         {
581                 extern errr init_gcu(int, char**);
582                 if (0 == init_gcu(argc, argv))
583                 {
584                         ANGBAND_SYS = "gcu";
585                         done = TRUE;
586                 }
587         }
588 #endif
589
590 #ifdef USE_CAP
591         /* Attempt to use the "main-cap.c" support */
592         if (!done && (!mstr || (streq(mstr, "cap"))))
593         {
594                 extern errr init_cap(int, char**);
595                 if (0 == init_cap(argc, argv))
596                 {
597                         ANGBAND_SYS = "cap";
598                         done = TRUE;
599                 }
600         }
601 #endif
602
603         /* Make sure we have a display! */
604         if (!done) quit("Unable to prepare any 'display module'!");
605
606
607         /* Hack -- If requested, display scores and quit */
608         if (show_score > 0) display_scores(0, show_score);
609
610
611         /* Catch nasty signals */
612         signals_init();
613
614         /* Initialize */
615         init_angband(p_ptr, process_autopick_file_command);
616
617         /* Wait for response */
618         pause_line(23);
619
620         /* Play the game */
621         play_game(p_ptr, new_game);
622
623         /* Quit */
624         quit(NULL);
625
626         /* Exit */
627         return (0);
628 }
629
630 #endif