OSDN Git Service

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