OSDN Git Service

Initial Import
[nethackexpress/trunk.git] / sys / vms / vmsmain.c
1 /*      SCCS Id: @(#)vmsmain.c  3.4     2003/10/16      */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4 /* main.c - VMS NetHack */
5
6 #include "hack.h"
7 #include "dlb.h"
8
9 #include <signal.h>
10
11 static void NDECL(whoami);
12 static void FDECL(process_options, (int, char **));
13 static void NDECL(byebye);
14 #ifndef SAVE_ON_FATAL_ERROR
15 # ifndef __DECC
16 #  define vms_handler_type int
17 # else
18 #  define vms_handler_type unsigned int
19 # endif
20 extern void FDECL(VAXC$ESTABLISH, (vms_handler_type (*)(genericptr_t,genericptr_t)));
21 static vms_handler_type FDECL(vms_handler, (genericptr_t,genericptr_t));
22 #include <ssdef.h>      /* system service status codes */
23 #endif
24
25 static void NDECL(wd_message);
26 #ifdef WIZARD
27 static boolean wiz_error_flag = FALSE;
28 #endif
29
30 int
31 main(argc,argv)
32 int argc;
33 char *argv[];
34 {
35         register int fd;
36 #ifdef CHDIR
37         register char *dir;
38 #endif
39
40 #ifdef SECURE   /* this should be the very first code executed */
41         privoff();
42         fflush((FILE *)0);      /* force stdio to init itself */
43         privon();
44 #endif
45
46         atexit(byebye);
47         hname = argv[0];
48         hname = vms_basename(hname);    /* name used in 'usage' type messages */
49         hackpid = getpid();
50         (void) umask(0);
51
52         choose_windows(DEFAULT_WINDOW_SYS);
53
54 #ifdef CHDIR                    /* otherwise no chdir() */
55         /*
56          * See if we must change directory to the playground.
57          * (Perhaps hack is installed with privs and playground is
58          *  inaccessible for the player.)
59          * The logical name HACKDIR is overridden by a
60          *  -d command line option (must be the first option given)
61          */
62         dir = nh_getenv("NETHACKDIR");
63         if (!dir) dir = nh_getenv("HACKDIR");
64 #endif
65         if(argc > 1) {
66 #ifdef CHDIR
67             if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') {
68                 /* avoid matching "-dec" for DECgraphics; since the man page
69                  * says -d directory, hope nobody's using -desomething_else
70                  */
71                 argc--;
72                 argv++;
73                 dir = argv[0]+2;
74                 if(*dir == '=' || *dir == ':') dir++;
75                 if(!*dir && argc > 1) {
76                         argc--;
77                         argv++;
78                         dir = argv[0];
79                 }
80                 if(!*dir)
81                     error("Flag -d must be followed by a directory name.");
82             }
83             if (argc > 1)
84 #endif /* CHDIR */
85
86             /*
87              * Now we know the directory containing 'record' and
88              * may do a prscore().
89              */
90             if (!strncmp(argv[1], "-s", 2)) {
91 #ifdef CHDIR
92                 chdirx(dir, FALSE);
93 #endif
94                 prscore(argc, argv);
95                 exit(EXIT_SUCCESS);
96             }
97         }
98
99 #ifdef CHDIR
100         /* move to the playground directory; 'termcap' might be found there */
101         chdirx(dir, TRUE);
102 #endif
103
104 #ifdef SECURE
105         /* disable installed privs while loading nethack.cnf and termcap,
106            and also while initializing terminal [$assign("TT:")]. */
107         privoff();
108 #endif
109         initoptions();
110         init_nhwindows(&argc, argv);
111         whoami();
112 #ifdef SECURE
113         privon();
114 #endif
115
116         /*
117          * It seems you really want to play.
118          */
119         u.uhp = 1;      /* prevent RIP on early quits */
120 #ifndef SAVE_ON_FATAL_ERROR
121         /* used to clear hangup stuff while still giving standard traceback */
122         VAXC$ESTABLISH(vms_handler);
123 #endif
124         (void) signal(SIGHUP, (SIG_RET_TYPE) hangup);
125
126         process_options(argc, argv);    /* command line options */
127
128 #ifdef WIZARD
129         if (wizard)
130                 Strcpy(plname, "wizard");
131         else
132 #endif
133         if (!*plname || !strncmpi(plname, "games", 4) ||
134             !strcmpi(plname, "nethack"))
135                 askname();
136         plnamesuffix();         /* strip suffix from name; calls askname() */
137                                 /* again if suffix was whole name */
138                                 /* accepts any suffix */
139 #ifdef WIZARD
140         if(!wizard) {
141 #endif
142                 /*
143                  * check for multiple games under the same name
144                  * (if !locknum) or check max nr of players (otherwise)
145                  */
146                 (void) signal(SIGQUIT,SIG_IGN);
147                 (void) signal(SIGINT,SIG_IGN);
148                 if(!locknum)
149                         Sprintf(lock, "_%u%s", (unsigned)getuid(), plname);
150                 getlock();
151 #ifdef WIZARD
152         } else {
153                 Sprintf(lock, "_%u%s", (unsigned)getuid(), plname);
154                 getlock();
155         }
156 #endif /* WIZARD */
157
158         dlb_init();     /* must be before newgame() */
159
160         /*
161          * Initialization of the boundaries of the mazes
162          * Both boundaries have to be even.
163          */
164         x_maze_max = COLNO-1;
165         if (x_maze_max % 2)
166                 x_maze_max--;
167         y_maze_max = ROWNO-1;
168         if (y_maze_max % 2)
169                 y_maze_max--;
170
171         /*
172          *  Initialize the vision system.  This must be before mklev() on a
173          *  new game or before a level restore on a saved game.
174          */
175         vision_init();
176
177         display_gamewindows();
178
179         if ((fd = restore_saved_game()) >= 0) {
180 #ifdef WIZARD
181                 /* Since wizard is actually flags.debug, restoring might
182                  * overwrite it.
183                  */
184                 boolean remember_wiz_mode = wizard;
185 #endif
186                 const char *fq_save = fqname(SAVEF, SAVEPREFIX, 1);
187
188                 (void) chmod(fq_save,0);        /* disallow parallel restores */
189                 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
190 #ifdef NEWS
191                 if(iflags.news) {
192                     display_file(NEWS, FALSE);
193                     iflags.news = FALSE; /* in case dorecover() fails */
194                 }
195 #endif
196                 pline("Restoring save file...");
197                 mark_synch();   /* flush output */
198                 if(!dorecover(fd))
199                         goto not_recovered;
200 #ifdef WIZARD
201                 if(!wizard && remember_wiz_mode) wizard = TRUE;
202 #endif
203                 check_special_room(FALSE);
204                 wd_message();
205
206                 if (discover || wizard) {
207                         if (yn("Do you want to keep the save file?") == 'n')
208                             (void) delete_savefile();
209                         else
210                             (void) chmod(fq_save,FCMASK); /* back to readable */
211                 }
212
213                 flags.move = 0;
214         } else {
215 not_recovered:
216                 player_selection();
217                 newgame();
218                 wd_message();
219
220                 flags.move = 0;
221                 set_wear();
222                 (void) pickup(1);
223         }
224
225         moveloop();
226         exit(EXIT_SUCCESS);
227         /*NOTREACHED*/
228         return(0);
229 }
230
231 static void
232 process_options(argc, argv)
233 int argc;
234 char *argv[];
235 {
236         int i;
237
238
239         /*
240          * Process options.
241          */
242         while(argc > 1 && argv[1][0] == '-'){
243                 argv++;
244                 argc--;
245                 switch(argv[0][1]){
246                 case 'D':
247 #ifdef WIZARD
248                         if(!strcmpi(nh_getenv("USER"), WIZARD_NAME)) {
249                                 wizard = TRUE;
250                                 break;
251                         }
252                         /* otherwise fall thru to discover */
253                         wiz_error_flag = TRUE;
254 #endif /* WIZARD */
255                 case 'X':
256                 case 'x':
257                         discover = TRUE;
258                         break;
259 #ifdef NEWS
260                 case 'n':
261                         iflags.news = FALSE;
262                         break;
263 #endif
264                 case 'u':
265                         if(argv[0][2])
266                           (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
267                         else if(argc > 1) {
268                           argc--;
269                           argv++;
270                           (void) strncpy(plname, argv[0], sizeof(plname)-1);
271                         } else
272                                 raw_print("Player name expected after -u");
273                         break;
274                 case 'I':
275                 case 'i':
276                         if (!strncmpi(argv[0]+1, "IBM", 3))
277                                 switch_graphics(IBM_GRAPHICS);
278                         break;
279             /*  case 'D': */
280                 case 'd':
281                         if (!strncmpi(argv[0]+1, "DEC", 3))
282                                 switch_graphics(DEC_GRAPHICS);
283                         break;
284                 case 'p': /* profession (role) */
285                         if (argv[0][2]) {
286                             if ((i = str2role(&argv[0][2])) >= 0)
287                                 flags.initrole = i;
288                         } else if (argc > 1) {
289                                 argc--;
290                                 argv++;
291                             if ((i = str2role(argv[0])) >= 0)
292                                 flags.initrole = i;
293                         }
294                         break;
295                 case 'r': /* race */
296                         if (argv[0][2]) {
297                             if ((i = str2race(&argv[0][2])) >= 0)
298                                 flags.initrace = i;
299                         } else if (argc > 1) {
300                                 argc--;
301                                 argv++;
302                             if ((i = str2race(argv[0])) >= 0)
303                                 flags.initrace = i;
304                         }
305                         break;
306                 case '@':
307                         flags.randomall = 1;
308                         break;
309                 default:
310                         if ((i = str2role(&argv[0][1])) >= 0) {
311                             flags.initrole = i;
312                                 break;
313                         }
314                         /* else raw_printf("Unknown option: %s", *argv); */
315                 }
316         }
317
318         if(argc > 1)
319                 locknum = atoi(argv[1]);
320 #ifdef MAX_NR_OF_PLAYERS
321         if(!locknum || locknum > MAX_NR_OF_PLAYERS)
322                 locknum = MAX_NR_OF_PLAYERS;
323 #endif
324 }
325
326 #ifdef CHDIR
327 void
328 chdirx(dir, wr)
329 const char *dir;
330 boolean wr;
331 {
332 # ifndef HACKDIR
333         static const char *defdir = ".";
334 # else
335         static const char *defdir = HACKDIR;
336
337         if(dir == (const char *)0)
338                 dir = defdir;
339         else if (wr && !same_dir(HACKDIR, dir))
340                 /* If we're playing anywhere other than HACKDIR, turn off any
341                    privs we may have been installed with. */
342                 privoff();
343 # endif
344
345         if(dir && chdir(dir) < 0) {
346                 perror(dir);
347                 error("Cannot chdir to %s.", dir);
348         }
349
350         /* warn the player if we can't write the record file */
351         if (wr) check_recordfile(dir);
352
353         defdir = dir;
354 }
355 #endif /* CHDIR */
356
357 static void
358 whoami()
359 {
360         /*
361          * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS
362          *                      2. Use lowercase of $USER  (if 1. fails)
363          * The resulting name is overridden by command line options.
364          * If everything fails, or if the resulting name is some generic
365          * account like "games" then eventually we'll ask him.
366          * Note that we trust the user here; it is possible to play under
367          * somebody else's name.
368          */
369         register char *s;
370
371         if (!*plname && (s = nh_getenv("USER")))
372                 (void) lcase(strncpy(plname, s, sizeof(plname)-1));
373 }
374
375 static void
376 byebye()
377 {
378     /*  Different versions of both VAX C and GNU C use different return types
379         for signal functions.  Return type 'int' along with the explicit casts
380         below satisfy the most combinations of compiler vs <signal.h>.
381      */
382     int (*hup)();
383 #ifdef SHELL
384     extern unsigned long dosh_pid, mail_pid;
385     extern unsigned long FDECL(sys$delprc,(unsigned long *,const genericptr_t));
386
387     /* clean up any subprocess we've spawned that may still be hanging around */
388     if (dosh_pid) (void) sys$delprc(&dosh_pid, 0), dosh_pid = 0;
389     if (mail_pid) (void) sys$delprc(&mail_pid, 0), mail_pid = 0;
390 #endif
391
392     /* SIGHUP doesn't seem to do anything on VMS, so we fudge it here... */
393     hup = (int(*)()) signal(SIGHUP, SIG_IGN);
394     if (!program_state.exiting++ &&
395         hup != (int(*)()) SIG_DFL && hup != (int(*)()) SIG_IGN)
396         (void) (*hup)();
397
398 #ifdef CHDIR
399     (void) chdir(getenv("PATH"));
400 #endif
401 }
402
403 #ifndef SAVE_ON_FATAL_ERROR
404 /* Condition handler to prevent byebye's hangup simulation
405    from saving the game after a fatal error has occurred.  */
406 /*ARGSUSED*/
407 static vms_handler_type         /* should be `unsigned long', but the -*/
408 vms_handler(sigargs, mechargs)  /*+ prototype in <signal.h> is screwed */
409 genericptr_t sigargs, mechargs; /* [0] is argc, [1..argc] are the real args */
410 {
411     unsigned long condition = ((unsigned long *)sigargs)[1];
412
413     if (condition == SS$_ACCVIO         /* access violation */
414      || (condition >= SS$_ASTFLT && condition <= SS$_TBIT)
415      || (condition >= SS$_ARTRES && condition <= SS$_INHCHME)) {
416         program_state.done_hup = TRUE;  /* pretend hangup has been attempted */
417 # if defined(WIZARD) && !defined(BETA)
418         if (wizard)
419 # endif /*WIZARD && !BETA*/
420 # if defined(WIZARD) ||  defined(BETA)
421             abort();    /* enter the debugger */
422 # endif /*WIZARD || BETA*/
423     }
424     return SS$_RESIGNAL;
425 }
426 #endif
427
428 #ifdef PORT_HELP
429 void
430 port_help()
431 {
432         /*
433          * Display VMS-specific help.   Just show contents of the helpfile
434          * named by PORT_HELP.
435          */
436         display_file(PORT_HELP, TRUE);
437 }
438 #endif /* PORT_HELP */
439
440 static void
441 wd_message()
442 {
443 #ifdef WIZARD
444         if (wiz_error_flag) {
445                 pline("Only user \"%s\" may access debug (wizard) mode.",
446                         WIZARD_NAME);
447                 pline("Entering discovery mode instead.");
448         } else
449 #endif
450         if (discover)
451                 You("are in non-scoring discovery mode.");
452 }
453
454 /*vmsmain.c*/