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 */
11 static void NDECL(whoami);
12 static void FDECL(process_options, (int, char **));
13 static void NDECL(byebye);
14 #ifndef SAVE_ON_FATAL_ERROR
16 # define vms_handler_type int
18 # define vms_handler_type unsigned int
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 */
25 static void NDECL(wd_message);
27 static boolean wiz_error_flag = FALSE;
40 #ifdef SECURE /* this should be the very first code executed */
42 fflush((FILE *)0); /* force stdio to init itself */
48 hname = vms_basename(hname); /* name used in 'usage' type messages */
52 choose_windows(DEFAULT_WINDOW_SYS);
54 #ifdef CHDIR /* otherwise no chdir() */
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)
62 dir = nh_getenv("NETHACKDIR");
63 if (!dir) dir = nh_getenv("HACKDIR");
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
74 if(*dir == '=' || *dir == ':') dir++;
75 if(!*dir && argc > 1) {
81 error("Flag -d must be followed by a directory name.");
87 * Now we know the directory containing 'record' and
90 if (!strncmp(argv[1], "-s", 2)) {
100 /* move to the playground directory; 'termcap' might be found there */
105 /* disable installed privs while loading nethack.cnf and termcap,
106 and also while initializing terminal [$assign("TT:")]. */
110 init_nhwindows(&argc, argv);
117 * It seems you really want to play.
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);
124 (void) signal(SIGHUP, (SIG_RET_TYPE) hangup);
126 process_options(argc, argv); /* command line options */
130 Strcpy(plname, "wizard");
133 if (!*plname || !strncmpi(plname, "games", 4) ||
134 !strcmpi(plname, "nethack"))
136 plnamesuffix(); /* strip suffix from name; calls askname() */
137 /* again if suffix was whole name */
138 /* accepts any suffix */
143 * check for multiple games under the same name
144 * (if !locknum) or check max nr of players (otherwise)
146 (void) signal(SIGQUIT,SIG_IGN);
147 (void) signal(SIGINT,SIG_IGN);
149 Sprintf(lock, "_%u%s", (unsigned)getuid(), plname);
153 Sprintf(lock, "_%u%s", (unsigned)getuid(), plname);
158 dlb_init(); /* must be before newgame() */
161 * Initialization of the boundaries of the mazes
162 * Both boundaries have to be even.
164 x_maze_max = COLNO-1;
167 y_maze_max = ROWNO-1;
172 * Initialize the vision system. This must be before mklev() on a
173 * new game or before a level restore on a saved game.
177 display_gamewindows();
179 if ((fd = restore_saved_game()) >= 0) {
181 /* Since wizard is actually flags.debug, restoring might
184 boolean remember_wiz_mode = wizard;
186 const char *fq_save = fqname(SAVEF, SAVEPREFIX, 1);
188 (void) chmod(fq_save,0); /* disallow parallel restores */
189 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
192 display_file(NEWS, FALSE);
193 iflags.news = FALSE; /* in case dorecover() fails */
196 pline("Restoring save file...");
197 mark_synch(); /* flush output */
201 if(!wizard && remember_wiz_mode) wizard = TRUE;
203 check_special_room(FALSE);
206 if (discover || wizard) {
207 if (yn("Do you want to keep the save file?") == 'n')
208 (void) delete_savefile();
210 (void) chmod(fq_save,FCMASK); /* back to readable */
232 process_options(argc, argv)
242 while(argc > 1 && argv[1][0] == '-'){
248 if(!strcmpi(nh_getenv("USER"), WIZARD_NAME)) {
252 /* otherwise fall thru to discover */
253 wiz_error_flag = TRUE;
266 (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
270 (void) strncpy(plname, argv[0], sizeof(plname)-1);
272 raw_print("Player name expected after -u");
276 if (!strncmpi(argv[0]+1, "IBM", 3))
277 switch_graphics(IBM_GRAPHICS);
281 if (!strncmpi(argv[0]+1, "DEC", 3))
282 switch_graphics(DEC_GRAPHICS);
284 case 'p': /* profession (role) */
286 if ((i = str2role(&argv[0][2])) >= 0)
288 } else if (argc > 1) {
291 if ((i = str2role(argv[0])) >= 0)
297 if ((i = str2race(&argv[0][2])) >= 0)
299 } else if (argc > 1) {
302 if ((i = str2race(argv[0])) >= 0)
310 if ((i = str2role(&argv[0][1])) >= 0) {
314 /* else raw_printf("Unknown option: %s", *argv); */
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;
333 static const char *defdir = ".";
335 static const char *defdir = HACKDIR;
337 if(dir == (const char *)0)
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. */
345 if(dir && chdir(dir) < 0) {
347 error("Cannot chdir to %s.", dir);
350 /* warn the player if we can't write the record file */
351 if (wr) check_recordfile(dir);
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.
371 if (!*plname && (s = nh_getenv("USER")))
372 (void) lcase(strncpy(plname, s, sizeof(plname)-1));
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>.
384 extern unsigned long dosh_pid, mail_pid;
385 extern unsigned long FDECL(sys$delprc,(unsigned long *,const genericptr_t));
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;
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)
399 (void) chdir(getenv("PATH"));
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. */
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 */
411 unsigned long condition = ((unsigned long *)sigargs)[1];
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)
419 # endif /*WIZARD && !BETA*/
420 # if defined(WIZARD) || defined(BETA)
421 abort(); /* enter the debugger */
422 # endif /*WIZARD || BETA*/
433 * Display VMS-specific help. Just show contents of the helpfile
434 * named by PORT_HELP.
436 display_file(PORT_HELP, TRUE);
438 #endif /* PORT_HELP */
444 if (wiz_error_flag) {
445 pline("Only user \"%s\" may access debug (wizard) mode.",
447 pline("Entering discovery mode instead.");
451 You("are in non-scoring discovery mode.");