OSDN Git Service

Initial revision
[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
13
14 /*
15  * Some machines have a "main()" function in their "main-xxx.c" file,
16  * all the others use this file for their "main()" function.
17  */
18
19
20 #if !defined(MACINTOSH) && !defined(WINDOWS) && !defined(ACORN)
21
22 #ifdef USE_SCRIPT
23
24 #include "Python.h"
25
26 #endif /* USE_SCRIPT */
27
28
29 /*
30  * A hook for "quit()".
31  *
32  * Close down, then fall back into "quit()".
33  */
34 static void quit_hook(cptr s)
35 {
36         int j;
37
38         /* Scan windows */
39         for (j = 8 - 1; j >= 0; j--)
40         {
41                 /* Unused */
42                 if (!angband_term[j]) continue;
43
44                 /* Nuke it */
45                 term_nuke(angband_term[j]);
46         }
47 }
48
49
50
51 /*
52  * Set the stack size (for the Amiga)
53  */
54 #ifdef AMIGA
55 # include <dos.h>
56 __near long __stack = 32768L;
57 #endif
58
59
60 /*
61  * Set the stack size and overlay buffer (see main-286.c")
62  */
63 #ifdef USE_286
64 # include <dos.h>
65 extern unsigned _stklen = 32768U;
66 extern unsigned _ovrbuffer = 0x1500;
67 #endif
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         /* Drop privs */
83         safe_setuid_drop();
84
85         /* Get an absolute path from the filename */
86         path_parse(dirpath, 1024, PRIVATE_USER_PATH);
87
88         /* Create the ~/.angband/ directory */
89         mkdir(dirpath, 0700);
90
91         /* Build the path to the variant-specific sub-directory */
92         path_build(subdirpath, 1024, dirpath, VERSION_NAME);
93
94         /* Create the directory */
95         mkdir(subdirpath, 0700);
96
97         /* Grab privs */
98         safe_setuid_grab();
99 }
100
101 #endif /* PRIVATE_USER_PATH */
102
103
104 /*
105  * Initialize and verify the file paths, and the score file.
106  *
107  * Use the ANGBAND_PATH environment var if possible, else use
108  * DEFAULT_PATH, and in either case, branch off appropriately.
109  *
110  * First, we'll look for the ANGBAND_PATH environment variable,
111  * and then look for the files in there.  If that doesn't work,
112  * we'll try the DEFAULT_PATH constant.  So be sure that one of
113  * these two things works...
114  *
115  * We must ensure that the path ends with "PATH_SEP" if needed,
116  * since the "init_file_paths()" function will simply append the
117  * relevant "sub-directory names" to the given path.
118  *
119  * Note that the "path" must be "Angband:" for the Amiga, and it
120  * is ignored for "VM/ESA", so I just combined the two.
121  *
122  * Make sure that the path doesn't overflow the buffer.  We have
123  * to leave enough space for the path separator, directory, and
124  * filenames.
125  */
126 static void init_stuff(void)
127 {
128         char path[1024];
129
130 #if defined(AMIGA) || defined(VM)
131
132         /* Hack -- prepare "path" */
133         strcpy(path, "Angband:");
134
135 #else /* AMIGA / VM */
136
137         cptr tail;
138
139         /* Get the environment variable */
140         tail = getenv("ANGBAND_PATH");
141
142         /* Use the angband_path, or a default */
143         strncpy(path, tail ? tail : DEFAULT_PATH, 511);
144
145         /* Make sure it's terminated */
146         path[511] = '\0';
147
148         /* Hack -- Add a path separator (only if needed) */
149         if (!suffix(path, PATH_SEP)) strcat(path, PATH_SEP);
150
151 #endif /* AMIGA / VM */
152
153         /* Initialize */
154         init_file_paths(path);
155 }
156
157
158
159 /*
160  * Handle a "-d<what>=<path>" option
161  *
162  * The "<what>" can be any string starting with the same letter as the
163  * name of a subdirectory of the "lib" folder (i.e. "i" or "info").
164  *
165  * The "<path>" can be any legal path for the given system, and should
166  * not end in any special path separator (i.e. "/tmp" or "~/.ang-info").
167  */
168 static void change_path(cptr info)
169 {
170         cptr s;
171
172         /* Find equal sign */
173         s = strchr(info, '=');
174
175         /* Verify equal sign */
176         if (!s) quit_fmt("Try '-d<what>=<path>' not '-d%s'", info);
177
178         /* Analyze */
179         switch (tolower(info[0]))
180         {
181                 case 'a':
182                 {
183                         string_free(ANGBAND_DIR_APEX);
184                         ANGBAND_DIR_APEX = string_make(s+1);
185                         break;
186                 }
187
188                 case 'f':
189                 {
190                         string_free(ANGBAND_DIR_FILE);
191                         ANGBAND_DIR_FILE = string_make(s+1);
192                         break;
193                 }
194
195                 case 'h':
196                 {
197                         string_free(ANGBAND_DIR_HELP);
198                         ANGBAND_DIR_HELP = string_make(s+1);
199                         break;
200                 }
201
202                 case 'i':
203                 {
204                         string_free(ANGBAND_DIR_INFO);
205                         ANGBAND_DIR_INFO = string_make(s+1);
206                         break;
207                 }
208
209                 case 'u':
210                 {
211                         string_free(ANGBAND_DIR_USER);
212                         ANGBAND_DIR_USER = string_make(s+1);
213                         break;
214                 }
215
216                 case 'x':
217                 {
218                         string_free(ANGBAND_DIR_XTRA);
219                         ANGBAND_DIR_XTRA = string_make(s+1);
220                         break;
221                 }
222
223 #ifdef VERIFY_SAVEFILE
224
225                 case 'b':
226                 case 'd':
227                 case 'e':
228                 case 's':
229                 {
230                         quit_fmt("Restricted option '-d%s'", info);
231                 }
232
233 #else /* VERIFY_SAVEFILE */
234
235                 case 'b':
236                 {
237                         string_free(ANGBAND_DIR_BONE);
238                         ANGBAND_DIR_BONE = string_make(s+1);
239                         break;
240                 }
241
242                 case 'd':
243                 {
244                         string_free(ANGBAND_DIR_DATA);
245                         ANGBAND_DIR_DATA = string_make(s+1);
246                         break;
247                 }
248
249                 case 'e':
250                 {
251                         string_free(ANGBAND_DIR_EDIT);
252                         ANGBAND_DIR_EDIT = string_make(s+1);
253                         break;
254                 }
255
256                 case 's':
257                 {
258                         string_free(ANGBAND_DIR_SAVE);
259                         ANGBAND_DIR_SAVE = string_make(s+1);
260                         break;
261                 }
262
263                 case 'z':
264                 {
265                         string_free(ANGBAND_DIR_SCRIPT);
266                         ANGBAND_DIR_SCRIPT = string_make(s+1);
267                         break;
268                 }
269
270 #endif /* VERIFY_SAVEFILE */
271
272                 default:
273                 {
274                         quit_fmt("Bad semantics in '-d%s'", info);
275                 }
276         }
277 }
278
279
280 /*
281  * Simple "main" function for multiple platforms.
282  *
283  * Note the special "--" option which terminates the processing of
284  * standard options.  All non-standard options (if any) are passed
285  * directly to the "init_xxx()" function.
286  */
287 int main(int argc, char *argv[])
288 {
289         int i;
290
291         bool done = FALSE;
292
293         bool new_game = FALSE;
294
295         int show_score = 0;
296
297         cptr mstr = NULL;
298
299         bool args = TRUE;
300
301
302         /* Save the "program name" XXX XXX XXX */
303         argv0 = argv[0];
304
305 #ifdef USE_286
306         /* Attempt to use XMS (or EMS) memory for swap space */
307         if (_OvrInitExt(0L, 0L))
308         {
309                 _OvrInitEms(0, 0, 64);
310         }
311 #endif
312
313
314 #ifdef SET_UID
315
316         /* Default permissions on files */
317         (void)umask(022);
318
319 # ifdef SECURE
320         /* Authenticate */
321         Authenticate();
322 # endif
323
324 #endif
325
326
327         /* Get the file paths */
328         init_stuff();
329
330
331 #ifdef SET_UID
332
333         /* Get the user id (?) */
334         player_uid = getuid();
335
336 #ifdef VMS
337         /* Mega-Hack -- Factor group id */
338         player_uid += (getgid() * 1000);
339 #endif
340
341 # ifdef SAFE_SETUID
342
343 #  ifdef _POSIX_SAVED_IDS
344
345         /* Save some info for later */
346         player_euid = geteuid();
347         player_egid = getegid();
348
349 #  endif
350
351 #  if 0 /* XXX XXX XXX */
352
353         /* Redundant setting necessary in case root is running the game */
354         /* If not root or game not setuid the following two calls do nothing */
355
356         if (setgid(getegid()) != 0)
357         {
358                 quit("setgid(): cannot set permissions correctly!");
359         }
360
361         if (setuid(geteuid()) != 0)
362         {
363                 quit("setuid(): cannot set permissions correctly!");
364         }
365
366 #  endif
367
368 # endif
369
370 #endif
371
372
373 #ifdef SET_UID
374
375         /* Initialize the "time" checker */
376         if (check_time_init() || check_time())
377         {
378                 quit("The gates to Angband are closed (bad time).");
379         }
380
381         /* Initialize the "load" checker */
382         if (check_load_init() || check_load())
383         {
384                 quit("The gates to Angband are closed (bad load).");
385         }
386
387         /* Acquire the "user name" as a default player name */
388 #ifdef ANGBAND_2_8_1
389         user_name(player_name, player_uid);
390 #else /* ANGBAND_2_8_1 */
391         user_name(op_ptr->full_name, player_uid);
392 #endif /* ANGBAND_2_8_1 */
393
394 #ifdef PRIVATE_USER_PATH
395
396         /* Create a directory for the users files. */
397         create_user_dir();
398
399 #endif /* PRIVATE_USER_PATH */
400
401 #endif /* SET_UID */
402
403
404         /* Process the command line arguments */
405         for (i = 1; args && (i < argc); i++)
406         {
407                 /* Require proper options */
408                 if (argv[i][0] != '-') goto usage;
409
410                 /* Analyze option */
411                 switch (argv[i][1])
412                 {
413                         case 'N':
414                         case 'n':
415                         {
416                                 new_game = TRUE;
417                                 break;
418                         }
419
420                         case 'F':
421                         case 'f':
422                         {
423                                 arg_fiddle = TRUE;
424                                 break;
425                         }
426
427                         case 'W':
428                         case 'w':
429                         {
430                                 arg_wizard = TRUE;
431                                 break;
432                         }
433
434                         case 'V':
435                         case 'v':
436                         {
437                                 arg_sound = TRUE;
438                                 break;
439                         }
440
441                         case 'G':
442                         case 'g':
443                         {
444                                 /* HACK - Graphics mode switches on the original tiles */
445                                 arg_graphics = GRAPHICS_ORIGINAL;
446                                 break;
447                         }
448
449                         case 'R':
450                         case 'r':
451                         {
452                                 arg_force_roguelike = TRUE;
453                                 break;
454                         }
455
456                         case 'O':
457                         case 'o':
458                         {
459                                 arg_force_original = TRUE;
460                                 break;
461                         }
462
463                         case 'S':
464                         case 's':
465                         {
466                                 show_score = atoi(&argv[i][2]);
467                                 if (show_score <= 0) show_score = 10;
468                                 break;
469                         }
470
471                         case 'u':
472                         case 'U':
473                         {
474                                 if (!argv[i][2]) goto usage;
475 #ifdef ANGBAND_2_8_1
476                                 strcpy(player_name, &argv[i][2]);
477 #else /* ANGBAND_2_8_1 */
478
479                                 /* Get the savefile name */
480                                 strncpy(op_ptr->full_name, &argv[i][2], 32);
481
482                                 /* Make sure it's terminated */
483                                 op_ptr->full_name[31] = '\0';
484
485 #endif /* ANGBAND_2_8_1 */
486                                 break;
487                         }
488
489                         case 'm':
490                         {
491                                 if (!argv[i][2]) goto usage;
492                                 mstr = &argv[i][2];
493                                 break;
494                         }
495
496                         case 'M':
497                         {
498                                 arg_monochrome = TRUE;
499                                 break;
500                         }
501
502                         case 'd':
503                         case 'D':
504                         {
505                                 change_path(&argv[i][2]);
506                                 break;
507                         }
508
509 #ifdef CHUUKEI
510                         case 'p':
511                         case 'P':
512                         {
513                                 if (!argv[i][2]) goto usage;
514                                 chuukei_server = TRUE;
515                                 if (connect_chuukei_server(&argv[i][2]) < 0) chuukei_server = FALSE;
516                                 break;
517                         }
518
519                         case 'c':
520                         case 'C':
521                         {
522                                 if (!argv[i][2]) goto usage;
523                                 chuukei_client = TRUE;
524                                 connect_chuukei_server(&argv[i][2]);
525                                 break;
526                         }
527 #endif
528
529                         case '-':
530                         {
531                                 argv[i] = argv[0];
532                                 argc = argc - i;
533                                 argv = argv + i;
534                                 args = FALSE;
535                                 break;
536                         }
537
538                         default:
539                         usage:
540                         {
541                                 /* Dump usage information */
542                                 puts("Usage: angband [options] [-- subopts]");
543                                 puts("  -n       Start a new character");
544                                 puts("  -f       Request fiddle mode");
545                                 puts("  -w       Request wizard mode");
546                                 puts("  -v       Request sound mode");
547                                 puts("  -g       Request graphics mode");
548                                 puts("  -o       Request original keyset");
549                                 puts("  -r       Request rogue-like keyset");
550                                 puts("  -M       Request monochrome mode");
551                                 puts("  -s<num>  Show <num> high scores");
552                                 puts("  -u<who>  Use your <who> savefile");
553                                 puts("  -m<sys>  Force 'main-<sys>.c' usage");
554                                 puts("  -d<def>  Define a 'lib' dir sub-path");
555
556                                 /* Actually abort the process */
557                                 quit(NULL);
558                         }
559                 }
560         }
561
562         /* Hack -- Forget standard args */
563         if (args)
564         {
565                 argc = 1;
566                 argv[1] = NULL;
567         }
568
569
570         /* Process the player name */
571         process_player_name(TRUE);
572
573
574
575         /* Install "quit" hook */
576         quit_aux = quit_hook;
577
578
579         /* Drop privs (so X11 will work correctly) */
580         safe_setuid_drop();
581
582
583 #ifdef USE_XAW
584         /* Attempt to use the "main-xaw.c" support */
585         if (!done && (!mstr || (streq(mstr, "xaw"))))
586         {
587                 extern errr init_xaw(int, char**);
588                 if (0 == init_xaw(argc, argv))
589                 {
590                         ANGBAND_SYS = "xaw";
591                         done = TRUE;
592                 }
593         }
594 #endif
595
596 #ifdef USE_X11
597         /* Attempt to use the "main-x11.c" support */
598         if (!done && (!mstr || (streq(mstr, "x11"))))
599         {
600                 extern errr init_x11(int, char**);
601                 if (0 == init_x11(argc, argv))
602                 {
603                         ANGBAND_SYS = "x11";
604                         done = TRUE;
605                 }
606         }
607 #endif
608
609 #ifdef USE_GCU
610         /* Attempt to use the "main-gcu.c" support */
611         if (!done && (!mstr || (streq(mstr, "gcu"))))
612         {
613                 extern errr init_gcu(int, char**);
614                 if (0 == init_gcu(argc, argv))
615                 {
616                         ANGBAND_SYS = "gcu";
617                         done = TRUE;
618                 }
619         }
620 #endif
621
622 #ifdef USE_CAP
623         /* Attempt to use the "main-cap.c" support */
624         if (!done && (!mstr || (streq(mstr, "cap"))))
625         {
626                 extern errr init_cap(int, char**);
627                 if (0 == init_cap(argc, argv))
628                 {
629                         ANGBAND_SYS = "cap";
630                         done = TRUE;
631                 }
632         }
633 #endif
634
635
636 #ifdef USE_DOS
637         /* Attempt to use the "main-dos.c" support */
638         if (!done && (!mstr || (streq(mstr, "dos"))))
639         {
640                 extern errr init_dos(void);
641                 if (0 == init_dos())
642                 {
643                         ANGBAND_SYS = "dos";
644                         done = TRUE;
645                 }
646         }
647 #endif
648
649 #ifdef USE_IBM
650         /* Attempt to use the "main-ibm.c" support */
651         if (!done && (!mstr || (streq(mstr, "ibm"))))
652         {
653                 extern errr init_ibm(void);
654                 if (0 == init_ibm())
655                 {
656                         ANGBAND_SYS = "ibm";
657                         done = TRUE;
658                 }
659         }
660 #endif
661
662
663 #ifdef USE_EMX
664         /* Attempt to use the "main-emx.c" support */
665         if (!done && (!mstr || (streq(mstr, "emx"))))
666         {
667                 extern errr init_emx(void);
668                 if (0 == init_emx())
669                 {
670                         ANGBAND_SYS = "emx";
671                         done = TRUE;
672                 }
673         }
674 #endif
675
676
677 #ifdef USE_SLA
678         /* Attempt to use the "main-sla.c" support */
679         if (!done && (!mstr || (streq(mstr, "sla"))))
680         {
681                 extern errr init_sla(void);
682                 if (0 == init_sla())
683                 {
684                         ANGBAND_SYS = "sla";
685                         done = TRUE;
686                 }
687         }
688 #endif
689
690
691 #ifdef USE_LSL
692         /* Attempt to use the "main-lsl.c" support */
693         if (!done && (!mstr || (streq(mstr, "lsl"))))
694         {
695                 extern errr init_lsl(void);
696                 if (0 == init_lsl())
697                 {
698                         ANGBAND_SYS = "lsl";
699                         done = TRUE;
700                 }
701         }
702 #endif
703
704
705 #ifdef USE_AMI
706         /* Attempt to use the "main-ami.c" support */
707         if (!done && (!mstr || (streq(mstr, "ami"))))
708         {
709                 extern errr init_ami(void);
710                 if (0 == init_ami())
711                 {
712                         ANGBAND_SYS = "ami";
713                         done = TRUE;
714                 }
715         }
716 #endif
717
718
719 #ifdef USE_VME
720         /* Attempt to use the "main-vme.c" support */
721         if (!done && (!mstr || (streq(mstr, "vme"))))
722         {
723                 extern errr init_vme(void);
724                 if (0 == init_vme())
725                 {
726                         ANGBAND_SYS = "vme";
727                         done = TRUE;
728                 }
729         }
730 #endif
731
732
733         /* Grab privs (dropped above for X11) */
734         safe_setuid_grab();
735
736
737         /* Make sure we have a display! */
738         if (!done) quit("Unable to prepare any 'display module'!");
739
740
741         /* Hack -- If requested, display scores and quit */
742         if (show_score > 0) display_scores(0, show_score);
743
744
745         /* Catch nasty signals */
746         signals_init();
747
748         /* Initialize */
749         init_angband();
750
751         /* Wait for response */
752         pause_line(23);
753
754         /* Play the game */
755         play_game(new_game);
756
757         /* Quit */
758         quit(NULL);
759
760         /* Exit */
761         return (0);
762 }
763
764 #endif
765
766
767