1 /* NetHack 3.6 vmsmain.c $NHDT-Date: 1449801742 2015/12/11 02:42:22 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.32 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2011. */
4 /* NetHack may be freely redistributed. See license for details. */
5 /* main.c - VMS NetHack */
12 static void NDECL(whoami);
13 static void FDECL(process_options, (int, char **));
14 static void NDECL(byebye);
15 #ifndef SAVE_ON_FATAL_ERROR
17 #define vms_handler_type int
19 #define vms_handler_type unsigned int
21 extern void FDECL(VAXC$ESTABLISH,
22 (vms_handler_type (*) (genericptr_t, genericptr_t)));
23 static vms_handler_type FDECL(vms_handler, (genericptr_t, genericptr_t));
24 #include <ssdef.h> /* system service status codes */
27 static void NDECL(wd_message);
28 static boolean wiz_error_flag = FALSE;
39 boolean resuming = FALSE; /* assume new game */
41 #ifdef SECURE /* this should be the very first code executed */
43 fflush((FILE *) 0); /* force stdio to init itself */
51 hname = vms_basename(hname); /* name used in 'usage' type messages */
55 choose_windows(DEFAULT_WINDOW_SYS);
57 #ifdef CHDIR /* otherwise no chdir() */
59 * See if we must change directory to the playground.
60 * (Perhaps hack is installed with privs and playground is
61 * inaccessible for the player.)
62 * The logical name HACKDIR is overridden by a
63 * -d command line option (must be the first option given)
65 dir = nh_getenv("NETHACKDIR");
67 dir = nh_getenv("HACKDIR");
71 if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') {
72 /* avoid matching "-dec" for DECgraphics; since the man page
73 * says -d directory, hope nobody's using -desomething_else
78 if (*dir == '=' || *dir == ':')
80 if (!*dir && argc > 1) {
86 error("Flag -d must be followed by a directory name.");
92 * Now we know the directory containing 'record' and
95 if (!strncmp(argv[1], "-s", 2)) {
108 /* move to the playground directory; 'termcap' might be found there */
113 /* disable installed privs while loading nethack.cnf and termcap,
114 and also while initializing terminal [$assign("TT:")]. */
118 init_nhwindows(&argc, argv);
125 * It seems you really want to play.
127 u.uhp = 1; /* prevent RIP on early quits */
128 #ifndef SAVE_ON_FATAL_ERROR
129 /* used to clear hangup stuff while still giving standard traceback */
130 VAXC$ESTABLISH(vms_handler);
132 sethanguphandler(hangup);
134 process_options(argc, argv); /* command line options */
136 /* wizard mode access is deferred until here */
137 set_playmode(); /* sets plname to "wizard" for wizard mode */
138 /* strip role,race,&c suffix; calls askname() if plname[] is empty
139 or holds a generic user name like "player" or "games" */
143 /* use character name rather than lock letter for file names */
146 /* suppress interrupts while processing lock file */
147 (void) signal(SIGQUIT, SIG_IGN);
148 (void) signal(SIGINT, SIG_IGN);
151 * getlock() complains and quits if there is already a game
152 * in progress for current character name (when locknum == 0)
153 * or if there are too many active games (when locknum > 0).
154 * When proceeding, it creates an empty <lockname>.0 file to
155 * designate the current game.
156 * getlock() constructs <lockname> based on the character
157 * name (for !locknum) or on first available of alock, block,
158 * clock, &c not currently in use in the playground directory
163 dlb_init(); /* must be before newgame() */
166 * Initialize the vision system. This must be before mklev() on a
167 * new game or before a level restore on a saved game.
171 display_gamewindows();
174 * First, try to find and restore a save file for specified character.
175 * We'll return here if new game player_selection() renames the hero.
178 if ((fd = restore_saved_game()) >= 0) {
179 const char *fq_save = fqname(SAVEF, SAVEPREFIX, 1);
181 (void) chmod(fq_save, 0); /* disallow parallel restores */
182 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
185 display_file(NEWS, FALSE);
186 iflags.news = FALSE; /* in case dorecover() fails */
189 pline("Restoring save file...");
190 mark_synch(); /* flush output */
192 resuming = TRUE; /* not starting new game */
194 if (discover || wizard) {
195 if (yn("Do you want to keep the save file?") == 'n')
196 (void) delete_savefile();
198 (void) chmod(fq_save, FCMASK); /* back to readable */
204 /* new game: start by choosing role, race, etc;
205 player might change the hero's name while doing that,
206 in which case we try to restore under the new name
207 and skip selection this time if that didn't succeed */
208 if (!iflags.renameinprogress) {
210 if (iflags.renameinprogress) {
211 /* player has renamed the hero while selecting role;
212 if locking alphabetically, the existing lock file
213 can still be used; otherwise, discard current one
214 and create another for the new character name */
216 delete_levelfile(0); /* remove empty lock file */
219 goto attempt_restore;
233 process_options(argc, argv)
242 while (argc > 1 && argv[1][0] == '-') {
245 switch (argv[0][1]) {
247 wizard = TRUE, discover = FALSE;
251 discover = TRUE, wizard = FALSE;
260 (void) strncpy(plname, argv[0] + 2, sizeof(plname) - 1);
264 (void) strncpy(plname, argv[0], sizeof(plname) - 1);
266 raw_print("Player name expected after -u");
270 if (!strncmpi(argv[0] + 1, "IBM", 3)) {
271 load_symset("IBMGraphics", PRIMARY);
272 load_symset("RogueIBM", ROGUESET);
273 switch_symbols(TRUE);
278 if (!strncmpi(argv[0] + 1, "DEC", 3)) {
279 load_symset("DECGraphics", PRIMARY);
280 switch_symbols(TRUE);
283 case 'p': /* profession (role) */
285 if ((i = str2role(&argv[0][2])) >= 0)
287 } else if (argc > 1) {
290 if ((i = str2role(argv[0])) >= 0)
296 if ((i = str2race(&argv[0][2])) >= 0)
298 } else if (argc > 1) {
301 if ((i = str2race(argv[0])) >= 0)
309 if ((i = str2role(&argv[0][1])) >= 0) {
313 /* else raw_printf("Unknown option: %s", *argv); */
318 locknum = atoi(argv[1]);
319 #ifdef MAX_NR_OF_PLAYERS
320 if (!locknum || locknum > MAX_NR_OF_PLAYERS)
321 locknum = MAX_NR_OF_PLAYERS;
332 static const char *defdir = ".";
334 static const char *defdir = HACKDIR;
336 if (dir == (const char *) 0)
338 else if (wr && !same_dir(HACKDIR, dir))
339 /* If we're playing anywhere other than HACKDIR, turn off any
340 privs we may have been installed with. */
344 if (dir && chdir(dir) < 0) {
346 error("Cannot chdir to %s.", dir);
349 /* warn the player if we can't write the record file */
351 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 void FDECL((*hup), (int) );
380 extern unsigned long dosh_pid, mail_pid;
381 extern unsigned long FDECL(sys$delprc,
382 (unsigned long *, const genericptr_t));
384 /* clean up any subprocess we've spawned that may still be hanging around
387 (void) sys$delprc(&dosh_pid, (genericptr_t) 0), dosh_pid = 0;
389 (void) sys$delprc(&mail_pid, (genericptr_t) 0), mail_pid = 0;
392 /* SIGHUP doesn't seem to do anything on VMS, so we fudge it here... */
393 hup = (void FDECL((*), (int) )) signal(SIGHUP, SIG_IGN);
394 if (!program_state.exiting++ && hup != (void FDECL((*), (int) )) SIG_DFL
395 && hup != (void FDECL((*), (int) )) SIG_IGN) {
400 (void) chdir(getenv("PATH"));
404 #ifndef SAVE_ON_FATAL_ERROR
405 /* Condition handler to prevent byebye's hangup simulation
406 from saving the game after a fatal error has occurred. */
408 static vms_handler_type /* should be `unsigned long', but the -*/
409 vms_handler(sigargs, mechargs) /*+ prototype in <signal.h> is screwed */
410 genericptr_t sigargs, mechargs; /* [0] is argc, [1..argc] are the real args */
412 unsigned long condition = ((unsigned long *) sigargs)[1];
414 if (condition == SS$_ACCVIO /* access violation */
415 || (condition >= SS$_ASTFLT && condition <= SS$_TBIT)
416 || (condition >= SS$_ARTRES && condition <= SS$_INHCHME)) {
417 program_state.done_hup = TRUE; /* pretend hangup has been attempted */
421 abort(); /* enter the debugger */
428 sethanguphandler(handler)
429 void FDECL((*handler), (int));
431 (void) signal(SIGHUP, (SIG_RET_TYPE) handler);
439 * Display VMS-specific help. Just show contents of the helpfile
440 * named by PORT_HELP.
442 display_file(PORT_HELP, TRUE);
444 #endif /* PORT_HELP */
446 /* validate wizard mode if player has requested access to it */
448 authorize_wizard_mode()
450 if (!strcmpi(nh_getenv("USER"), WIZARD_NAME))
452 wiz_error_flag = TRUE; /* not being allowed into wizard mode */
459 if (wiz_error_flag) {
460 pline("Only user \"%s\" may access debug (wizard) mode.",
462 pline("Entering explore/discovery mode instead.");
463 wizard = 0, discover = 1; /* (paranoia) */
465 You("are in non-scoring explore/discovery mode.");
472 unsigned long pid = (unsigned long) getpid();
474 seed = (unsigned long) getnow(); /* time((TIME_type) 0) */
475 /* Quick dirty band-aid to prevent PRNG prediction */