1 /* SCCS Id: @(#)unixmain.c 3.4 1997/01/22 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* main.c - Unix NetHack */
17 #if !defined(_BULL_SOURCE) && !defined(__sgi) && !defined(_M_UNIX)
18 # if !defined(SUNOS4) && !(defined(ULTRIX) && defined(__GNUC__))
19 # if defined(POSIX_TYPES) || defined(SVR4) || defined(HPUX)
20 extern struct passwd *FDECL(getpwuid,(uid_t));
22 extern struct passwd *FDECL(getpwuid,(int));
26 extern struct passwd *FDECL(getpwnam,(const char *));
28 static void FDECL(chdirx, (const char *,BOOLEAN_P));
30 static boolean NDECL(whoami);
31 static void FDECL(process_options, (int, char **));
34 extern void NDECL(check_sco_console);
35 extern void NDECL(init_sco_cons);
38 extern void NDECL(check_linux_console);
39 extern void NDECL(init_linux_cons);
42 static void NDECL(wd_message);
44 static boolean wiz_error_flag = FALSE;
56 boolean exact_username;
58 #if defined(__APPLE__)
59 /* special hack to change working directory to a resource fork when
60 running from finder --sam */
61 #define MAC_PATH_VALUE ".app/Contents/MacOS/"
62 char mac_cwd[1024], *mac_exe = argv[0], *mac_tmp;
63 int arg0_len = strlen(mac_exe), mac_tmp_len, mac_lhs_len=0;
64 getcwd(mac_cwd, 1024);
65 if(mac_exe[0] == '/' && !strcmp(mac_cwd, "/")) {
66 if((mac_exe = strrchr(mac_exe, '/')))
70 mac_tmp_len = (strlen(mac_exe) * 2) + strlen(MAC_PATH_VALUE);
71 if(mac_tmp_len <= arg0_len) {
72 mac_tmp = malloc(mac_tmp_len + 1);
73 sprintf(mac_tmp, "%s%s%s", mac_exe, MAC_PATH_VALUE, mac_exe);
74 if(!strcmp(argv[0] + (arg0_len - mac_tmp_len), mac_tmp)) {
75 mac_lhs_len = (arg0_len - mac_tmp_len) + strlen(mac_exe) + 5;
76 if(mac_lhs_len > mac_tmp_len - 1)
77 mac_tmp = realloc(mac_tmp, mac_lhs_len);
78 strncpy(mac_tmp, argv[0], mac_lhs_len);
79 mac_tmp[mac_lhs_len] = '\0';
89 (void) umask(0777 & ~FCMASK);
91 choose_windows(DEFAULT_WINDOW_SYS);
93 #ifdef CHDIR /* otherwise no chdir() */
95 * See if we must change directory to the playground.
96 * (Perhaps hack runs suid and playground is inaccessible
98 * The environment variable HACKDIR is overridden by a
99 * -d command line option (must be the first option given)
101 dir = nh_getenv("NETHACKDIR");
102 if (!dir) dir = nh_getenv("HACKDIR");
106 if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') {
107 /* avoid matching "-dec" for DECgraphics; since the man page
108 * says -d directory, hope nobody's using -desomething_else
113 if(*dir == '=' || *dir == ':') dir++;
114 if(!*dir && argc > 1) {
120 error("Flag -d must be followed by a directory name.");
126 * Now we know the directory containing 'record' and
127 * may do a prscore(). Exclude `-style' - it's a Qt option.
129 if (!strncmp(argv[1], "-s", 2) && strncmp(argv[1], "-style", 6)) {
139 * Change directories before we initialize the window system so
140 * we can find the tile file.
150 check_linux_console();
153 init_nhwindows(&argc,argv);
154 exact_username = whoami();
163 * It seems you really want to play.
165 u.uhp = 1; /* prevent RIP on early quits */
166 (void) signal(SIGHUP, (SIG_RET_TYPE) hangup);
168 (void) signal(SIGXCPU, (SIG_RET_TYPE) hangup);
171 process_options(argc, argv); /* command line options */
174 if(!(catmore = nh_getenv("HACKPAGER")) && !(catmore = nh_getenv("PAGER")))
182 Strcpy(plname, "wizard");
185 if(!*plname || !strncmp(plname, "player", 4)
186 || !strncmp(plname, "games", 4)) {
188 } else if (exact_username) {
189 /* guard against user names with hyphens in them */
190 int len = strlen(plname);
191 /* append the current role, if any, so that last dash is ours */
192 if (++len < sizeof plname)
193 (void)strncat(strcat(plname, "-"),
194 pl_character, sizeof plname - len - 1);
196 plnamesuffix(); /* strip suffix from name; calls askname() */
197 /* again if suffix was whole name */
198 /* accepts any suffix */
203 * check for multiple games under the same name
204 * (if !locknum) or check max nr of players (otherwise)
206 (void) signal(SIGQUIT,SIG_IGN);
207 (void) signal(SIGINT,SIG_IGN);
209 Sprintf(lock, "%d%s", (int)getuid(), plname);
213 Sprintf(lock, "%d%s", (int)getuid(), plname);
218 dlb_init(); /* must be before newgame() */
221 * Initialization of the boundaries of the mazes
222 * Both boundaries have to be even.
224 x_maze_max = COLNO-1;
227 y_maze_max = ROWNO-1;
232 * Initialize the vision system. This must be before mklev() on a
233 * new game or before a level restore on a saved game.
237 display_gamewindows();
239 if ((fd = restore_saved_game()) >= 0) {
241 /* Since wizard is actually flags.debug, restoring might
244 boolean remember_wiz_mode = wizard;
246 const char *fq_save = fqname(SAVEF, SAVEPREFIX, 1);
248 (void) chmod(fq_save,0); /* disallow parallel restores */
249 (void) signal(SIGINT, (SIG_RET_TYPE) done1);
252 display_file(NEWS, FALSE);
253 iflags.news = FALSE; /* in case dorecover() fails */
256 pline("Restoring save file...");
257 mark_synch(); /* flush output */
261 if(!wizard && remember_wiz_mode) wizard = TRUE;
263 check_special_room(FALSE);
266 if (discover || wizard) {
267 if(yn("Do you want to keep the save file?") == 'n')
268 (void) delete_savefile();
270 (void) chmod(fq_save,FCMASK); /* back to readable */
293 process_options(argc, argv)
303 while(argc > 1 && argv[1][0] == '-'){
312 struct passwd *pw = (struct passwd *)0;
318 if (pw && (pw->pw_uid != uid)) pw = 0;
321 user = nh_getenv("USER");
324 if (pw && (pw->pw_uid != uid)) pw = 0;
330 if (pw && !strcmp(pw->pw_name,WIZARD)) {
335 /* otherwise fall thru to discover */
336 wiz_error_flag = TRUE;
348 (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
352 (void) strncpy(plname, argv[0], sizeof(plname)-1);
354 raw_print("Player name expected after -u");
358 if (!strncmpi(argv[0]+1, "IBM", 3))
359 switch_graphics(IBM_GRAPHICS);
363 if (!strncmpi(argv[0]+1, "DEC", 3))
364 switch_graphics(DEC_GRAPHICS);
366 case 'p': /* profession (role) */
368 if ((i = str2role(&argv[0][2])) >= 0)
370 } else if (argc > 1) {
373 if ((i = str2role(argv[0])) >= 0)
379 if ((i = str2race(&argv[0][2])) >= 0)
381 } else if (argc > 1) {
384 if ((i = str2race(argv[0])) >= 0)
392 if ((i = str2role(&argv[0][1])) >= 0) {
396 /* else raw_printf("Unknown option: %s", *argv); */
401 locknum = atoi(argv[1]);
402 #ifdef MAX_NR_OF_PLAYERS
403 if(!locknum || locknum > MAX_NR_OF_PLAYERS)
404 locknum = MAX_NR_OF_PLAYERS;
414 if (dir /* User specified directory? */
416 && strcmp(dir, HACKDIR) /* and not the default? */
420 (void) setgid(getgid());
421 (void) setuid(getuid()); /* Ron Wessels */
424 /* non-default data files is a sign that scores may not be
425 * compatible, or perhaps that a binary not fitting this
426 * system's layout is being used.
428 # ifdef VAR_PLAYGROUND
429 int len = strlen(VAR_PLAYGROUND);
431 fqn_prefix[SCOREPREFIX] = (char *)alloc(len+2);
432 Strcpy(fqn_prefix[SCOREPREFIX], VAR_PLAYGROUND);
433 if (fqn_prefix[SCOREPREFIX][len-1] != '/') {
434 fqn_prefix[SCOREPREFIX][len] = '/';
435 fqn_prefix[SCOREPREFIX][len+1] = '\0';
441 if (dir == (const char *)0)
445 if (dir && chdir(dir) < 0) {
447 error("Cannot chdir to %s.", dir);
450 /* warn the player if we can't write the record file */
451 /* perhaps we should also test whether . is writable */
452 /* unfortunately the access system-call is worthless */
454 # ifdef VAR_PLAYGROUND
455 fqn_prefix[LEVELPREFIX] = fqn_prefix[SCOREPREFIX];
456 fqn_prefix[SAVEPREFIX] = fqn_prefix[SCOREPREFIX];
457 fqn_prefix[BONESPREFIX] = fqn_prefix[SCOREPREFIX];
458 fqn_prefix[LOCKPREFIX] = fqn_prefix[SCOREPREFIX];
459 fqn_prefix[TROUBLEPREFIX] = fqn_prefix[SCOREPREFIX];
461 check_recordfile(dir);
469 * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS
470 * 2. Use $USER or $LOGNAME (if 1. fails)
471 * 3. Use getlogin() (if 2. fails)
472 * The resulting name is overridden by command line options.
473 * If everything fails, or if the resulting name is some generic
474 * account like "games", "play", "player", "hack" then eventually
476 * Note that we trust the user here; it is possible to play under
477 * somebody else's name.
481 if (*plname) return FALSE;
482 if(/* !*plname && */ (s = nh_getenv("USER")))
483 (void) strncpy(plname, s, sizeof(plname)-1);
484 if(!*plname && (s = nh_getenv("LOGNAME")))
485 (void) strncpy(plname, s, sizeof(plname)-1);
486 if(!*plname && (s = getlogin()))
487 (void) strncpy(plname, s, sizeof(plname)-1);
496 * Display unix-specific help. Just show contents of the helpfile
497 * named by PORT_HELP.
499 display_file(PORT_HELP, TRUE);
507 if (wiz_error_flag) {
508 pline("Only user \"%s\" may access debug (wizard) mode.",
514 pline("Entering discovery mode instead.");
518 You("are in non-scoring discovery mode.");
522 * Add a slash to any name not ending in /. There must
533 ptr = name + (strlen(name) - 1);