From: nhmall Date: Sat, 8 Dec 2018 22:56:20 +0000 (-0500) Subject: Windows startup modifications X-Git-Tag: nmake-explicit-path~55^2~3^2~12 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dc1e2da35995ac8a8a008cbcbd7b66e60ded5e9b;p=nethack Windows startup modifications Changes to be committed: modified: include/winprocs.h modified: src/options.c modified: sys/share/pcmain.c new file: sys/share/safeproc.c modified: sys/winnt/Makefile.msc modified: sys/winnt/stubs.c new file: sys/winnt/windmain.c modified: sys/winnt/winnt.c modified: win/win32/vs2017/NetHack.vcxproj modified: win/win32/vs2017/NetHackW.vcxproj modified: win/win32/winhack.c Because multiple window ports are supported on Windows now, even in the same executable and selectable via config file in some cases, some adjustments became necessary. There will likely be some further refining of this over the next day or two. List of changes: Move Windows startup from sys/share/pcmain.c and into its own sys/winnt/windmain.c so that it can be modified to fix some current breakage, and allow altering the order of some things. There is startup processing code that is common to all of the Windows WindowPorts, but that startup processing code needs to have no dependency on any one of those WindowPorts. Yet, during startup processing, some of the initialization routines can end up calling NetHack functions that expect an active Window port underneath, and if there isn't one, routines like pline, impossible, panic can end up invoking null function pointers. Place a new file sys/share/safeproc.c, in which a complete window port is available for early startup processing purposes. It's WindowPort name field is set to "safe-startup" just for reference. The prototypes in include/winprocs.h require that SAFEPROCS be Usage: windowprocs = get_safe_procs(0); initializes a set of winprocs function pointers that ensure none of the function pointers are left null, but that's all it does. windowprocs = get_safe_procs(1); initializes a set of winprocs functions pointers that ensure none of the function pointers are left null, but also provides some basic output and input functionality using nothing other than C stdio routines (no platform or OS specific code). The conditional code related to WIN32 has been removed from sys/share/pcmain.c The code common to all of the Windows WindowPorts calls get_safe_procs() almost immediately to ensure that there is a set of WindowPort winprocs available. --- diff --git a/include/winprocs.h b/include/winprocs.h index ddfef409d..85ece4a7d 100644 --- a/include/winprocs.h +++ b/include/winprocs.h @@ -375,4 +375,77 @@ struct chain_procs { }; #endif /* WINCHAIN */ +#ifdef SAFEPROCS +/* + * window port routines available in sys/share/safeproc.c + */ +extern struct window_procs *FDECL(get_safe_procs, (int)); +extern void FDECL(safe_init_nhwindows, (int *, char **)); +extern void NDECL(safe_player_selection); +extern void NDECL(safe_askname); +extern void NDECL(safe_get_nh_event); +extern void FDECL(safe_exit_nhwindows, (const char *)); +extern void FDECL(safe_suspend_nhwindows, (const char *)); +extern void NDECL(safe_resume_nhwindows); +extern winid FDECL(safe_create_nhwindow, (int)); +extern void FDECL(safe_clear_nhwindow, (winid)); +extern void FDECL(safe_display_nhwindow, (winid, BOOLEAN_P)); +extern void FDECL(safe_destroy_nhwindow, (winid)); +extern void FDECL(safe_curs, (winid, int, int)); +extern void FDECL(safe_putstr, (winid, int, const char *)); +extern void FDECL(safe_putmixed, (winid, int, const char *)); +extern void FDECL(safe_display_file, (const char *, BOOLEAN_P)); +extern void FDECL(safe_start_menu, (winid)); +extern void FDECL(safe_add_menu, (winid, int, const ANY_P *, CHAR_P, CHAR_P, + int, const char *, BOOLEAN_P)); +extern void FDECL(safe_end_menu, (winid, const char *)); +extern int FDECL(safe_select_menu, (winid, int, MENU_ITEM_P **)); +extern char FDECL(safe_message_menu, (CHAR_P, int, const char *)); +extern void NDECL(safe_update_inventory); +extern void NDECL(safe_mark_synch); +extern void NDECL(safe_wait_synch); +#ifdef CLIPPING +extern void FDECL(safe_cliparound, (int, int)); +#endif +#ifdef POSITIONBAR +extern void FDECL(safe_update_positionbar, (char *)); +#endif +extern void FDECL(safe_print_glyph, (winid, XCHAR_P, XCHAR_P, int, int)); +extern void FDECL(safe_raw_print, (const char *)); +extern void FDECL(safe_raw_print_bold, (const char *)); +extern int NDECL(safe_nhgetch); +extern int FDECL(safe_nh_poskey, (int *, int *, int *)); +extern void NDECL(safe_nhbell); +extern int NDECL(safe_doprev_message); +extern char FDECL(safe_yn_function, (const char *, const char *, CHAR_P)); +extern void FDECL(safe_getlin, (const char *, char *)); +extern int NDECL(safe_get_ext_cmd); +extern void FDECL(safe_number_pad, (int)); +extern void NDECL(safe_delay_output); +#ifdef CHANGE_COLOR +extern void FDECL(safe_change_color, (int, long, int)); +#ifdef MAC +extern void FDECL(safe_change_background, (int)); +extern short FDECL(safe_set_font_name, (winid, char *)); +#endif +extern char *NDECL(safe_get_color_string); +#endif +extern void NDECL(safe_start_screen); +extern void NDECL(safe_end_screen); +extern void FDECL(safe_outrip, (winid, int, time_t)); +extern void FDECL(safe_preference_update, (const char *)); +extern char *FDECL(safe_getmsghistory, (BOOLEAN_P)); +extern void FDECL(safe_putmsghistory, (const char *, BOOLEAN_P)); +extern void NDECL(safe_status_init); +extern void NDECL(safe_status_finish); +extern void FDECL(safe_status_enablefield, + (int, const char *, const char *, BOOLEAN_P)); +extern void FDECL(safe_status_update, (int, genericptr_t, int, int, int, unsigned long *)); +extern boolean NDECL(safe_can_suspend); +extern void FDECL(stdio_raw_print, (const char *)); +extern void FDECL(stdio_raw_print_bold, (const char *)); +extern void NDECL(stdio_wait_synch); +extern int NDECL(stdio_nhgetch); +#endif /* SAFEPROCS */ #endif /* WINPROCS_H */ + diff --git a/src/options.c b/src/options.c index b3595a6ad..9dafa31bf 100644 --- a/src/options.c +++ b/src/options.c @@ -873,11 +873,16 @@ initoptions_finish() * A multi-interface binary might only support status highlighting * for some of the interfaces; check whether we asked for it but are * using one which doesn't. + * + * Option processing can take place before a user-decided WindowPort + * is even initialized, so check for that too. */ - if (iflags.hilite_delta && !wc2_supported("statushilites")) { - raw_printf("Status highlighting not supported for %s interface.", - windowprocs.name); - iflags.hilite_delta = 0; + if (!WINDOWPORT("safe-startup")) { + if (iflags.hilite_delta && !wc2_supported("statushilites")) { + raw_printf("Status highlighting not supported for %s interface.", + windowprocs.name); + iflags.hilite_delta = 0; + } } #endif return; diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index 8651ae8fe..1f67b0efb 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -3,11 +3,7 @@ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ -/* main.c - MSDOS, OS/2, ST, Amiga, and Windows NetHack */ - -#ifdef WIN32 -#include "win32api.h" /* for GetModuleFileName */ -#endif +/* main.c - MSDOS, OS/2, ST, Amiga NetHack */ #include "hack.h" #include "dlb.h" @@ -47,29 +43,12 @@ void NDECL(preserve_icon); STATIC_DCL void FDECL(process_options, (int argc, char **argv)); STATIC_DCL void NDECL(nhusage); -#if defined(MICRO) || defined(WIN32) || defined(OS2) +#if defined(MICRO) || defined(OS2) extern void FDECL(nethack_exit, (int)); #else #define nethack_exit exit #endif -#ifdef WIN32 -extern boolean getreturn_enabled; /* from sys/share/pcsys.c */ -extern int redirect_stdout; /* from sys/share/pcsys.c */ -extern int GUILaunched; -char *NDECL(exename); -char default_window_sys[] = "mswin"; -#ifndef WIN32CON -HANDLE hStdOut; -boolean NDECL(fakeconsole); -void NDECL(freefakeconsole); -#endif -#endif - -#if defined(MSWIN_GRAPHICS) -extern void NDECL(mswin_destroy_reg); -#endif - #ifdef EXEPATH STATIC_DCL char *FDECL(exepath, (char *)); #endif @@ -78,7 +57,7 @@ int FDECL(main, (int, char **)); extern boolean FDECL(pcmain, (int, char **)); -#if defined(__BORLANDC__) && !defined(_WIN32) +#if defined(__BORLANDC__) void NDECL(startup); unsigned _stklen = STKSIZ; #endif @@ -98,21 +77,8 @@ char *argv[]; { boolean resuming; - nethack_enter(argc, argv); - sys_early_init(); -#if defined(WIN32) && defined(TTY_GRAPHICS) - Strcpy(default_window_sys, "tty"); -#else -#if defined(CURSES_GRAPHICS) - Strcpy(default_window_sys, "curses"); -#endif -#endif - resuming = pcmain(argc, argv); -#ifdef LAN_FEATURES - init_lan_features(); -#endif moveloop(resuming); nethack_exit(EXIT_SUCCESS); /*NOTREACHED*/ @@ -126,14 +92,10 @@ char *argv[]; { register int fd; register char *dir; -#if defined(WIN32) || defined(MSDOS) +#if defined(MSDOS) char *envp = NULL; char *sptr = NULL; #endif -#if defined(WIN32) - char fnamebuf[BUFSZ], encodedfnamebuf[BUFSZ]; - boolean save_getreturn_status = getreturn_enabled; -#endif #ifdef NOCWD_ASSUMPTIONS char failbuf[BUFSZ]; #endif @@ -162,7 +124,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ # endif #endif -#if defined(__BORLANDC__) && !defined(_WIN32) +#if defined(__BORLANDC__) startup(); #endif @@ -175,15 +137,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ #endif hname = "NetHack"; /* used for syntax messages */ -#ifndef WIN32 choose_windows(DEFAULT_WINDOW_SYS); -#else - choose_windows(default_window_sys); - if (argc >= 1 - && !strcmpi(default_window_sys, "mswin") - && strstri(argv[0], "nethackw.exe")) - iflags.windowtype_locked = TRUE; -#endif #if !defined(AMIGA) && !defined(GNUDOS) /* Save current directory and make sure it gets restored when @@ -243,7 +197,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ for (prefcnt = 1; prefcnt < PREFIX_COUNT; prefcnt++) fqn_prefix[prefcnt] = fqn_prefix[0]; -#if defined(WIN32) || defined(MSDOS) +#if defined(MSDOS) /* sysconf should be searched for in this location */ envp = nh_getenv("COMMONPROGRAMFILES"); if (envp) { @@ -317,14 +271,6 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ chdirx(HACKDIR, 1); #endif ami_wininit_data(); -#endif -#ifdef WIN32 - save_getreturn_status = getreturn_enabled; -#ifdef TTY_GRAPHICS - raw_clear_screen(); -#endif - getreturn_enabled = TRUE; - check_recordfile((char *) 0); #endif initoptions(); @@ -355,13 +301,6 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ argv++; } -#ifdef WIN32 - if (argcheck(argc, argv, ARG_WINDOWS) == 1) { - argc--; - argv++; - } -#endif - if (argc > 1 && !strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else @@ -381,36 +320,11 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ Strcpy(hackdir, dir); } if (argc > 1) { -#if defined(WIN32) && !defined(WIN32CON) - int sfd = 0; - boolean tmpconsole = FALSE; - hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); -#endif /* * Now we know the directory containing 'record' and * may do a prscore(). */ if (!strncmp(argv[1], "-s", 2)) { -#if defined(WIN32) && !defined(WIN32CON) - -#if 0 - if (!hStdOut) { - tmpconsole = fakeconsole(); - } -#endif - /* - * Check to see if we're redirecting to a file. - */ - sfd = (int) _fileno(stdout); - redirect_stdout = (sfd >= 0) ? !isatty(sfd) : 0; - - if (!redirect_stdout && !hStdOut) { - raw_printf( - "-s is not supported for the Graphical Interface\n"); - nethack_exit(EXIT_SUCCESS); - } -#endif - #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(hackdir, 0); #endif @@ -418,47 +332,16 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ initoptions(); #endif prscore(argc, argv); -#if defined(WIN32) && !defined(WIN32CON) - if (tmpconsole) { - getreturn("to exit"); - freefakeconsole(); - tmpconsole = FALSE; - } -#endif nethack_exit(EXIT_SUCCESS); } -#ifdef MSWIN_GRAPHICS - if (!strncmpi(argv[1], "-clearreg", 6)) { /* clear registry */ - mswin_destroy_reg(); - nethack_exit(EXIT_SUCCESS); - } -#endif /* Don't initialize the window system just to print usage */ if (!strncmp(argv[1], "-?", 2) || !strncmp(argv[1], "/?", 2)) { -#if 0 - if (!hStdOut) { - GUILaunched = 0; - tmpconsole = fakeconsole(); - } -#endif nhusage(); - -#if defined(WIN32) && !defined(WIN32CON) - if (tmpconsole) { - getreturn("to exit"); - freefakeconsole(); - tmpconsole = FALSE; - } -#endif nethack_exit(EXIT_SUCCESS); } } } - -#ifdef WIN32 - getreturn_enabled = save_getreturn_status; -#endif /* * It seems you really want to play. */ @@ -472,11 +355,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ "\"%s\".%s", copyright_banner_line(1), copyright_banner_line(2), copyright_banner_line(3), copyright_banner_line(4), DLBFILE, -#ifdef WIN32 - "\nAre you perhaps trying to run NetHack within a zip utility?"); -#else ""); -#endif error("dlb_init failure."); } @@ -490,41 +369,22 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ chdirx(hackdir, 1); #endif -#if defined(MSDOS) || defined(WIN32) +#if defined(MSDOS) /* In 3.6.0, several ports process options before they init * the window port. This allows settings that impact window * ports to be specified or read from the sys or user config files. */ process_options(argc, argv); -#ifdef WIN32 - /* - if (WINDOWPORT("mswin")) - NHWinMainInit(); - else - */ -#ifdef TTY_GRAPHICS - if (WINDOWPORT("tty")) { - iflags.use_background_glyph = FALSE; - nttty_open(1); - } else { - iflags.use_background_glyph = TRUE; - } -#endif /* TTY_GRAPHICS */ -#endif /* WIN32 */ -#endif /* MSDOS || WIN32 */ +#endif /* MSDOS */ -#if defined(MSDOS) || defined(WIN32) +#if defined(MSDOS) init_nhwindows(&argc, argv); #else init_nhwindows(&argc, argv); process_options(argc, argv); #endif -#if defined(WIN32) && defined(TTY_GRAPHICS) - toggle_mouse_support(); /* must come after process_options */ -#endif - #ifdef MFLOPPY set_lock_and_bones(); #ifndef AMIGA @@ -561,19 +421,8 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ * overwritten without confirmation when a user starts up * another game with the same player name. */ -#if defined(WIN32) - /* Obtain the name of the logged on user and incorporate - * it into the name. */ - Sprintf(fnamebuf, "%s-%s", get_username(0), plname); - (void) fname_encode( - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.", '%', - fnamebuf, encodedfnamebuf, BUFSZ); - Sprintf(lock, "%s", encodedfnamebuf); - /* regularize(lock); */ /* we encode now, rather than substitute */ -#else Strcpy(lock, plname); regularize(lock); -#endif getlock(); #else /* What follows is !PC_LOCKING */ #ifdef AMIGA /* We'll put the bones & levels in the user specified directory \ @@ -599,11 +448,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ if (fd < 0) { raw_print("Cannot create lock file"); } else { -#ifdef WIN32 - hackpid = GetCurrentProcessId(); -#else hackpid = 1; -#endif write(fd, (genericptr_t) &hackpid, sizeof(hackpid)); nhclose(fd); } @@ -618,10 +463,6 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ vision_init(); display_gamewindows(); -#ifdef WIN32 - getreturn_enabled = TRUE; -#endif - /* * First, try to find and restore a save file for specified character. * We'll return here if new game player_selection() renames the hero. @@ -799,18 +640,6 @@ char *argv[]; case 'l': bigscreen = -1; break; -#endif -#ifdef WIN32 - case 'w': /* windowtype */ -#ifdef TTY_GRAPHICS - if (strncmpi(&argv[0][2], "tty", 3)) { - nttty_open(1); - } -#endif - config_error_init(FALSE, "command line", FALSE); - choose_windows(&argv[0][2]); - config_error_done(); - break; #endif case '@': flags.randomall = 1; @@ -904,14 +733,14 @@ boolean wr; #endif /* CHDIR */ #ifdef PORT_HELP -#if defined(MSDOS) || defined(WIN32) +#if defined(MSDOS) void port_help() { /* display port specific help file */ display_file(PORT_HELP, 1); } -#endif /* MSDOS || WIN32 */ +#endif /* MSDOS */ #endif /* PORT_HELP */ /* validate wizard mode if player has requested access to it */ @@ -930,71 +759,6 @@ authorize_wizard_mode() #define PATH_SEPARATOR '\\' #endif -#if defined(WIN32) && !defined(WIN32CON) -static char exenamebuf[PATHLEN]; -extern HANDLE hConIn; -extern HANDLE hConOut; -boolean has_fakeconsole; - -char * -exename() -{ - int bsize = PATHLEN; - char *tmp = exenamebuf, *tmp2; - -#ifdef UNICODE - { - TCHAR wbuf[PATHLEN * 4]; - GetModuleFileName((HANDLE) 0, wbuf, PATHLEN * 4); - WideCharToMultiByte(CP_ACP, 0, wbuf, -1, tmp, bsize, NULL, NULL); - } -#else - *(tmp + GetModuleFileName((HANDLE) 0, tmp, bsize)) = '\0'; -#endif - tmp2 = strrchr(tmp, PATH_SEPARATOR); - if (tmp2) - *tmp2 = '\0'; - tmp2++; - return tmp2; -} - -boolean -fakeconsole(void) -{ - if (!hStdOut) { - HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); - HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); - - if (!hStdOut && !hStdIn) { - /* Bool rval; */ - AllocConsole(); - AttachConsole(GetCurrentProcessId()); - /* rval = SetStdHandle(STD_OUTPUT_HANDLE, hWrite); */ - freopen("CON", "w", stdout); - freopen("CON", "r", stdin); - } - has_fakeconsole = TRUE; - } - - /* Obtain handles for the standard Console I/O devices */ - hConIn = GetStdHandle(STD_INPUT_HANDLE); - hConOut = GetStdHandle(STD_OUTPUT_HANDLE); -#if 0 - if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE)) { - /* Unable to set control handler */ - cmode = 0; /* just to have a statement to break on for debugger */ - } -#endif - return has_fakeconsole; -} -void freefakeconsole() -{ - if (has_fakeconsole) { - FreeConsole(); - } -} -#endif - #define EXEPATHBUFSZ 256 char exepathbuf[EXEPATHBUFSZ]; @@ -1009,19 +773,7 @@ char *str; return (char *) 0; bsize = EXEPATHBUFSZ; tmp = exepathbuf; -#ifndef WIN32 Strcpy(tmp, str); -#else -#ifdef UNICODE - { - TCHAR wbuf[BUFSZ]; - GetModuleFileName((HANDLE) 0, wbuf, BUFSZ); - WideCharToMultiByte(CP_ACP, 0, wbuf, -1, tmp, bsize, NULL, NULL); - } -#else - *(tmp + GetModuleFileName((HANDLE) 0, tmp, bsize)) = '\0'; -#endif -#endif tmp2 = strrchr(tmp, PATH_SEPARATOR); if (tmp2) *tmp2 = '\0'; diff --git a/sys/share/safeproc.c b/sys/share/safeproc.c new file mode 100644 index 000000000..b3b991a7c --- /dev/null +++ b/sys/share/safeproc.c @@ -0,0 +1,550 @@ +/* NetHack 3.6 safeproc.c */ +/* Copyright (c) Michael Allison, 2018 */ +/* NetHack may be freely redistributed. See license for details. */ + +#include "hack.h" +#include + +/* + * *********************************************************** + * This is a complete WindowPort implementation that can be + * assigned to the windowproc function pointers very early + * in the startup initialization, perhaps immediately even. + * It requires only the following call: + * windowprocs = get_safe_procs(0); + * + * The game startup can trigger functions in other modules + * that make assumptions on a WindowPort being available + * and bad things can happen if any function pointers are + * null at that time. + * + * Some ports prior to 3.6.2 made attempts to early init + * various pieces of one of their WindowPorts, but that + * caused conflicts if that particular WindowPort wasn't + * the one that the user ended up selecting in their + * config file later. The WindowPort interfaced was designed + * to allow multiple WindowPorts to be linked into the same + * game binary. + * + * The base functions established by a call to get_safe_procs() + * accomplish the goal of preventing crashes, but not much + * else. + * + * There are also a few additional functions provided in here + * that can be selected optionally to provide some startup + * functionality for getting messages out to the user about + * issues that are being experienced during startup in + * general or during options parsing. The ones in here are + * deliberately free from any platforms or OS specific code. + * Please leave them using stdio C routines as much as + * possible. That isn't to say you can't do fancier functions + * prior to initialization of the primary WindowPort, but you + * can provide those platform-specific functions elsewhere, + * and assign them the same way that these more generic versions + * are assigned. + * + * The additional platform-independent, but more functional + * routines provided in here should be assigned after the + * windowprocs = get_safe_procs() + * call. Here's a list of them: + * + * + * + * + * *********************************************************** + */ + +struct window_procs safe_procs = { + "safe-startup", 0L, 0L, + safe_init_nhwindows, safe_player_selection, safe_askname, safe_get_nh_event, + safe_exit_nhwindows, safe_suspend_nhwindows, safe_resume_nhwindows, + safe_create_nhwindow, safe_clear_nhwindow, safe_display_nhwindow, + safe_destroy_nhwindow, safe_curs, safe_putstr, genl_putmixed, + safe_display_file, safe_start_menu, safe_add_menu, safe_end_menu, + safe_select_menu, safe_message_menu, safe_update_inventory, safe_mark_synch, + safe_wait_synch, +#ifdef CLIPPING + safe_cliparound, +#endif +#ifdef POSITIONBAR + safe_update_positionbar, +#endif + safe_print_glyph, safe_raw_print, safe_raw_print_bold, safe_nhgetch, + safe_nh_poskey, safe_nhbell, safe_doprev_message, safe_yn_function, + safe_getlin, safe_get_ext_cmd, safe_number_pad, safe_delay_output, +#ifdef CHANGE_COLOR /* the Mac uses a palette device */ + safe_change_color, +#ifdef MAC + safe_change_background, set_safe_font_name, +#endif + safe_get_color_string, +#endif + safe_start_screen, safe_end_screen, genl_outrip, + safe_preference_update, + safe_getmsghistory, safe_putmsghistory, + safe_status_init, + safe_status_finish, safe_status_enablefield, +#ifdef STATUS_HILITES + safe_status_update, +#else + safe_status_update, +#endif + safe_can_suspend, +}; + +struct window_procs * +get_safe_procs(optn) +int optn; +{ + if (optn) { + /* include the slightly more functional stdc versions */ + safe_procs.win_raw_print = stdio_raw_print; + safe_procs.win_raw_print_bold = stdio_raw_print_bold; + safe_procs.win_nhgetch = stdio_nhgetch; + safe_procs.win_wait_synch = stdio_wait_synch; + } + return &safe_procs; +} + +/*ARGSUSED*/ +void +safe_init_nhwindows(argcp, argv) +int *argcp UNUSED; +char **argv UNUSED; +{ + return; +} + +void +safe_player_selection() +{ + return; +} + +void +safe_askname() +{ + return; +} + +void +safe_get_nh_event() +{ + return; +} + +void +safe_suspend_nhwindows(str) +const char *str; +{ + return; +} + +void +safe_resume_nhwindows() +{ + return; +} + +void +safe_exit_nhwindows(str) +const char *str; +{ + return; +} + +winid +safe_create_nhwindow(type) +int type; +{ + return WIN_ERR; +} + +void +safe_clear_nhwindow(window) +winid window; +{ + return; +} + +/*ARGSUSED*/ +void +safe_display_nhwindow(window, blocking) +winid window; +boolean blocking; +{ + return; +} + +void +safe_dismiss_nhwindow(window) +winid window; +{ + return; +} + +void +safe_destroy_nhwindow(window) +winid window; +{ + return; +} + +void +safe_curs(window, x, y) +winid window; +int x, y; +{ + return; +} + +void +safe_putstr(window, attr, str) +winid window; +int attr; +const char *str; +{ + return; +} + +void +safe_display_file(fname, complain) +const char *fname; +boolean complain; +{ + return; +} + +void +safe_start_menu(window) +winid window; +{ + return; +} + +/*ARGSUSED*/ +/* + * Add a menu item to the beginning of the menu list. This list is reversed + * later. + */ +void +safe_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected) +winid window; /* window to use, must be of type NHW_MENU */ +int glyph UNUSED; /* glyph to display with item (not used) */ +const anything *identifier; /* what to return if selected */ +char ch; /* keyboard accelerator (0 = pick our own) */ +char gch; /* group accelerator (0 = no group) */ +int attr; /* attribute for string (like safe_putstr()) */ +const char *str; /* menu string */ +boolean preselected; /* item is marked as selected */ +{ + return; +} + +/* + * End a menu in this window, window must a type NHW_MENU. + */ +void +safe_end_menu(window, prompt) +winid window; /* menu to use */ +const char *prompt; /* prompt to for menu */ +{ + return; +} + +int +safe_select_menu(window, how, menu_list) +winid window; +int how; +menu_item **menu_list; +{ + return 0; +} + +/* special hack for treating top line --More-- as a one item menu */ +char +safe_message_menu(let, how, mesg) +char let; +int how; +const char *mesg; +{ + return '\033'; +} + +void +safe_update_inventory() +{ + return; +} + +void +safe_mark_synch() +{ +} + +void +safe_wait_synch() +{ +} + +#ifdef CLIPPING +void +safe_cliparound(x, y) +int x, y; +{ +} +#endif /* CLIPPING */ + +/* + * safe_print_glyph + * + * Print the glyph to the output device. Don't flush the output device. + */ +void +safe_print_glyph(window, x, y, glyph, bkglyph) +winid window; +xchar x, y; +int glyph; +int bkglyph UNUSED; +{ + return; +} + +void +safe_raw_print(str) +const char *str; +{ + return; +} + +void +safe_raw_print_bold(str) +const char *str; +{ + return; +} + +int +safe_nhgetch() +{ + return '\033'; +} + +/* + * return a key, or 0, in which case a mouse button was pressed + * mouse events should be returned as character postitions in the map window. + * Since normal tty's don't have mice, just return a key. + */ +/*ARGSUSED*/ +int +safe_nh_poskey(x, y, mod) +int *x, *y, *mod; +{ + return '\033'; +} + +void +win_safe_init(dir) +int dir; +{ + return; +} + +#ifdef POSITIONBAR +void +safe_update_positionbar(posbar) +char *posbar; +{ + return; +} +#endif /* POSITIONBAR */ + +/* + * safe_status_init() + * -- initialize the port-specific data structures. + */ +void +safe_status_init() +{ + return; +} + +void +safe_can_suspend() +{ + return; +} + +void +safe_nhbell() +{ + return; +} + +int +safe_doprev_message() +{ + return 0; +} + +char +safe_yn_function(query, resp, def) +const char *query; +const char *resp; +char def; +{ + return '\033'; +} + +/*ARGSUSED*/ +static void +safe_getlin(prompt, outbuf) +const char *prompt UNUSED; +char *outbuf; +{ + Strcpy(outbuf, "\033"); +} + +int +safe_get_ext_cmd() +{ + return '\033'; +} + +void +safe_number_pad(mode) +int mode; +{ + return; +} + +void +safe_delay_output() +{ + return; +} + +void +safe_start_screen() +{ + return; +} + +void +safe_end_screen() +{ + return; +} + +void +safe_outrip(tmpwin, how, when) +winid tmpwin; +int how; +time_t when; +{ + return; +} + +/*ARGSUSED*/ +void +safe_preference_update(pref) +const char *pref UNUSED; +{ + return; +} + +char * +safe_getmsghistory(init) +boolean init UNUSED; +{ + return (char *) 0; +} + +void +safe_putmsghistory(msg, is_restoring) +const char *msg; +boolean is_restoring; +{ +} + +void +safe_status_finish() +{ +} + +void +safe_status_enablefield(fieldidx, nm, fmt, enable) +int fieldidx; +const char *nm; +const char *fmt; +boolean enable; +{ +} + +#ifdef STATUS_HILITES +/* call once for each field, then call with BL_FLUSH to output the result */ +void +safe_status_update(idx, ptr, chg, percent, color, colormasks) +int idx; +genericptr_t ptr; +int chg UNUSED, percent UNUSED, color UNUSED; +unsigned long *colormasks UNUSED; +{ +} +#endif /* STATUS_HILITES */ + +/************************************************************** + * These are some optionally selectable routines that add + * some base functionality over the safe_* versions above. + * The safe_* versions are primarily designed to ensure that + * there are no null function pointers remaining at early + * game startup/initialization time. + * + * The slightly more functional versions in here should be kept + * free of platform-specific code or OS-specific code. If you + * want to use versions that involve platform-specific or + * OS-specific code, go right ahead but use your own replacement + * version of the functions in a platform-specific or + * OS-specific source file, not in here. + ***************************************************************/ + +/* Add to your code: windowprocs.win_raw_print = stdio_wait_synch; */ +void +stdio_wait_synch() +{ + char valid[] = {' ', '\n', '\r', '\033', '\0'}; + + fprintf(stdout, "--More--"); + (void) fflush(stdout); + while (!index(valid, stdio_nhgetch())) + ; +} + +/* Add to your code: windowprocs.win_raw_print = stdio_raw_print; */ +void +stdio_raw_print(str) +const char *str; +{ + if (str) + fprintf(stdout, "%s\n", str); + return; +} + +/* Add to your code: windowprocs.win_raw_print_bold = stdio_raw_print_bold; */ +void +stdio_raw_print_bold(str) +const char *str; +{ + stdio_raw_print(str); + return; +} + +/* Add to your code: windowprocs.win_nhgetch = stdio_nhgetch; */ +int +stdio_nhgetch() +{ + return getchar(); +} + + +/* safeprocs.c */ diff --git a/sys/winnt/Makefile.msc b/sys/winnt/Makefile.msc index 3bc520282..e8b4e22d3 100644 --- a/sys/winnt/Makefile.msc +++ b/sys/winnt/Makefile.msc @@ -215,7 +215,7 @@ VOBJ06 = $(O)dothrow.o $(O)drawing.o $(O)dungeon.o $(O)eat.o VOBJ07 = $(O)end.o $(O)engrave.o $(O)exper.o $(O)explode.o VOBJ08 = $(O)extralev.o $(O)files.o $(O)fountain.o $(O)hack.o VOBJ09 = $(O)hacklib.o $(O)invent.o $(O)light.o $(O)lock.o -VOBJ10 = $(O)mail.o $(O)pcmain.o $(O)makemon.o $(O)mapglyph.o $(O)mcastu.o +VOBJ10 = $(O)mail.o $(O)makemon.o $(O)mapglyph.o $(O)mcastu.o VOBJ11 = $(O)mhitm.o $(O)mhitu.o $(O)minion.o $(O)mklev.o VOBJ12 = $(O)mkmap.o $(O)mkmaze.o $(O)mkobj.o $(O)mkroom.o VOBJ13 = $(O)mon.o $(O)mondata.o $(O)monmove.o $(O)monst.o @@ -233,7 +233,7 @@ VOBJ24 = $(O)track.o $(O)trap.o $(O)u_init.o $(O)uhitm.o VOBJ25 = $(O)vault.o $(O)vis_tab.o $(O)vision.o $(O)weapon.o VOBJ26 = $(O)were.o $(O)wield.o $(O)windows.o $(O)wizard.o VOBJ27 = $(O)worm.o $(O)worn.o $(O)write.o $(O)zap.o -VOBJ28 = $(O)win10.o +VOBJ28 = $(O)win10.o $(O)safeproc.o $(O)windmain.o DLBOBJ = $(O)dlb.o @@ -535,7 +535,7 @@ INCLDIR= /I..\include /I..\sys\winnt # Util builds #========================================== -cflagsBuild = $(cflags) $(INCLDIR) $(WINPFLAG) $(DLBFLG) +cflagsBuild = $(cflags) $(INCLDIR) $(WINPFLAG) $(DLBFLG) -DSAFEPROCS lflagsBuild = $(lflags) $(conlibs) $(MACHINE) #========================================== @@ -1461,7 +1461,7 @@ $(O)guistub.o: $(HACK_H) $(MSWSYS)\stubs.c # $(O)winhack.o: $(HACK_H) $(MSWIN)\winhack.c - @$(cc) $(cflagsBuild) -I$(MSWSYS) -I$(MSWIN) -Fo$@ $(MSWIN)\winhack.c + @$(cc) $(cflagsBuild) -DSAFEPROCS -I$(MSWSYS) -I$(MSWIN) -Fo$@ $(MSWIN)\winhack.c #if you aren't linking in the full tty then #include the following stub for proper linkage. @@ -1511,9 +1511,9 @@ $(O)\curswins.c: $(WCURSES)\curswins.c $(WCURSES)\curswins.h $(INCL)\wincurs.h $(O)tos.o: ..\sys\atari\tos.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(cflagsBuild) -Fo$@ ..\sys\atari\tos.c -$(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h \ - $(MSWSYS)\win32api.h - @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\pcmain.c +$(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h +$(O)safeprocs.o: ..\sys\share\safeprocs.c $(HACK_H) $(MSWSYS)\win32api.h + @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\safeprocs.c $(O)pcsys.o: ..\sys\share\pcsys.c $(HACK_H) @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\pcsys.c $(O)pctty.o: ..\sys\share\pctty.c $(HACK_H) diff --git a/sys/winnt/stubs.c b/sys/winnt/stubs.c index 3e7fa4c20..af10a7fc0 100644 --- a/sys/winnt/stubs.c +++ b/sys/winnt/stubs.c @@ -96,13 +96,11 @@ clear_screen() return; } -#ifdef TTY_GRAPHICS void backsp() { return; } -#endif int has_color(int color) diff --git a/sys/winnt/windmain.c b/sys/winnt/windmain.c new file mode 100644 index 000000000..9768a8e6f --- /dev/null +++ b/sys/winnt/windmain.c @@ -0,0 +1,757 @@ +/* NetHack 3.6 windmain.c $NHDT-Date: 1543465755 2018/11/29 04:29:15 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.101 $ */ +/* Copyright (c) Derek S. Ray, 2015. */ +/* NetHack may be freely redistributed. See license for details. */ + +/* main.c - Windows */ + +#include "win32api.h" /* for GetModuleFileName */ +#include "hack.h" +#include "dlb.h" +#include +#include + +#if !defined(SAFEPROCS) +#error You must #define SAFEPROCS to build windmain.c +#endif + +#define E extern +static void FDECL(process_options, (int argc, char **argv)); +static void NDECL(nhusage); +static char *FDECL(exepath, (char *)); +char *NDECL(exename); +boolean NDECL(fakeconsole); +void NDECL(freefakeconsole); +E void FDECL(nethack_exit, (int)); +#if defined(MSWIN_GRAPHICS) +E void NDECL(mswin_destroy_reg); +#endif +#undef E + +int NDECL(windows_nhgetch); +void NDECL(windows_nhbell); +int FDECL(windows_nh_poskey, (int *, int *, int *)); +void FDECL(windows_raw_print, (const char *)); +char FDECL(windows_yn_function, (const char *, const char *, CHAR_P)); +void FDECL(windows_getlin, (const char *, char *)); + +char orgdir[PATHLEN]; +extern boolean getreturn_enabled; /* from sys/share/pcsys.c */ +extern int redirect_stdout; /* from sys/share/pcsys.c */ +extern int GUILaunched; +HANDLE hStdOut; +#if defined(MSWIN_GRAPHICS) +char default_window_sys[] = "mswin"; +#endif + +/* + * __MINGW32__ Note + * If the graphics version is built, we don't need a main; it is skipped + * to help MinGW decide which entry point to choose. If both main and + * WinMain exist, the resulting executable won't work correctly. + */ +int +#ifndef __MINGW32__ +main(argc, argv) +#else +mingw_main(argc, argv) +#endif +int argc; +char *argv[]; +{ + boolean save_getreturn_status = getreturn_enabled; + boolean resuming = FALSE; /* assume new game */ + register int fd; + register char *dir; + char *envp = NULL; + char *sptr = NULL; + char fnamebuf[BUFSZ], encodedfnamebuf[BUFSZ]; + char failbuf[BUFSZ]; + + /* + * Get a set of valid safe windowport function + * pointers during early startup initialization. + */ + if (!WINDOWPORT("safe-startup")) + windowprocs = *get_safe_procs(1); + sys_early_init(); +#ifdef _MSC_VER +# ifdef DEBUG + /* set these appropriately for VS debugging */ + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); + _CrtSetReportMode(_CRT_ERROR, + _CRTDBG_MODE_DEBUG); /* | _CRTDBG_MODE_FILE);*/ + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); +/*| _CRTDBG_MODE_FILE | _CRTDBG_MODE_WNDW);*/ +/* use STDERR by default +_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); +_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ +/* Heap Debugging + _CrtSetDbgFlag( _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) + | _CRTDBG_ALLOC_MEM_DF + | _CRTDBG_CHECK_ALWAYS_DF + | _CRTDBG_CHECK_CRT_DF + | _CRTDBG_DELAY_FREE_MEM_DF + | _CRTDBG_LEAK_CHECK_DF); + _CrtSetBreakAlloc(1423); +*/ +# endif +#endif + + hname = "NetHack"; /* used for syntax messages */ + /* Save current directory and make sure it gets restored when + * the game is exited. + */ + if (getcwd(orgdir, sizeof orgdir) == (char *) 0) + error("NetHack: current directory path too long"); + dir = nh_getenv("NETHACKDIR"); + if (dir == (char *) 0) + dir = nh_getenv("HACKDIR"); + if (dir == (char *) 0) + dir = exepath(argv[0]); +#ifdef _MSC_VER + if (IsDebuggerPresent()) { + static char exepath[_MAX_PATH]; + /* check if we're running under the debugger so we can get to the right folder anyway */ + if (dir != (char *)0) { + char *top = (char *)0; + + if (strlen(dir) < (_MAX_PATH - 1)) + strcpy(exepath, dir); + top = strstr(exepath, "\\build\\.\\Debug"); + if (!top) top = strstr(exepath, "\\build\\.\\Release"); + if (top) { + *top = '\0'; + if (strlen(exepath) < (_MAX_PATH - (strlen("\\binary\\") + 1))) { + Strcat(exepath, "\\binary\\"); + if (strlen(exepath) < (PATHLEN - 1)) { + dir = exepath; + } + } + } + } + } +#endif + if (dir != (char *)0) { + int prefcnt; + int fd; + boolean have_syscf = FALSE; + + (void) strncpy(hackdir, dir, PATHLEN - 1); + hackdir[PATHLEN - 1] = '\0'; + fqn_prefix[0] = (char *) alloc(strlen(hackdir) + 2); + Strcpy(fqn_prefix[0], hackdir); + append_slash(fqn_prefix[0]); + for (prefcnt = 1; prefcnt < PREFIX_COUNT; prefcnt++) + fqn_prefix[prefcnt] = fqn_prefix[0]; + /* sysconf should be searched for in this location */ + envp = nh_getenv("COMMONPROGRAMFILES"); + if (envp) { + if ((sptr = index(envp, ';')) != 0) + *sptr = '\0'; + if (strlen(envp) > 0) { + fqn_prefix[SYSCONFPREFIX] = + (char *) alloc(strlen(envp) + 10); + Strcpy(fqn_prefix[SYSCONFPREFIX], envp); + append_slash(fqn_prefix[SYSCONFPREFIX]); + Strcat(fqn_prefix[SYSCONFPREFIX], "NetHack\\"); + } + } + + /* okay so we have the overriding and definitive locaton + for sysconf, but only in the event that there is not a + sysconf file there (for whatever reason), check a secondary + location rather than abort. */ + + /* Is there a SYSCF_FILE there? */ + fd = open(fqname(SYSCF_FILE, SYSCONFPREFIX, 0), O_RDONLY); + if (fd >= 0) { + /* readable */ + close(fd); + have_syscf = TRUE; + } + + if (!have_syscf) { + /* No SYSCF_FILE where there should be one, and + without an installer, a user may not be able + to place one there. So, let's try somewhere else... */ + fqn_prefix[SYSCONFPREFIX] = fqn_prefix[0]; + + /* Is there a SYSCF_FILE there? */ + fd = open(fqname(SYSCF_FILE, SYSCONFPREFIX, 0), O_RDONLY); + if (fd >= 0) { + /* readable */ + close(fd); + have_syscf = TRUE; + } + } + + /* user's home directory should default to this - unless + * overridden */ + envp = nh_getenv("USERPROFILE"); + if (envp) { + if ((sptr = index(envp, ';')) != 0) + *sptr = '\0'; + if (strlen(envp) > 0) { + fqn_prefix[CONFIGPREFIX] = + (char *) alloc(strlen(envp) + 2); + Strcpy(fqn_prefix[CONFIGPREFIX], envp); + append_slash(fqn_prefix[CONFIGPREFIX]); + } + } + } + save_getreturn_status = getreturn_enabled; + getreturn_enabled = TRUE; + check_recordfile((char *) 0); + initoptions(); + if (!validate_prefix_locations(failbuf)) { + raw_printf("Some invalid directory locations were specified:\n\t%s\n", + failbuf); + nethack_exit(EXIT_FAILURE); + } + if (!hackdir[0]) + Strcpy(hackdir, orgdir); + if (argc > 1) { + if (argcheck(argc, argv, ARG_VERSION) == 2) + nethack_exit(EXIT_SUCCESS); + + if (argcheck(argc, argv, ARG_DEBUG) == 1) { + argc--; + argv++; + } + if (argcheck(argc, argv, ARG_WINDOWS) == 1) { + argc--; + argv++; + } + if (argc > 1 && !strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { + /* avoid matching "-dec" for DECgraphics; since the man page + * says -d directory, hope nobody's using -desomething_else + */ + argc--; + argv++; + dir = argv[0] + 2; + if (*dir == '=' || *dir == ':') + dir++; + if (!*dir && argc > 1) { + argc--; + argv++; + dir = argv[0]; + } + if (!*dir) + error("Flag -d must be followed by a directory name."); + Strcpy(hackdir, dir); + } + if (argc > 1) { +#if !defined(TTY_GRAPHICS) + int sfd = 0; + boolean tmpconsole = FALSE; + hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); +#endif + /* + * Now we know the directory containing 'record' and + * may do a prscore(). + */ + if (!strncmp(argv[1], "-s", 2)) { +#if !defined(TTY_GRAPHICS) + /* + * Check to see if we're redirecting to a file. + */ + sfd = (int) _fileno(stdout); + redirect_stdout = (sfd >= 0) ? !isatty(sfd) : 0; + + if (!redirect_stdout && !hStdOut) { + raw_printf( + "-s is not supported for the Graphical Interface\n"); + nethack_exit(EXIT_SUCCESS); + } +#endif +#ifdef SYSCF + initoptions(); +#endif + prscore(argc, argv); + +#if !defined(TTY_GRAPHICS) + if (tmpconsole) { + getreturn("to exit"); + freefakeconsole(); + tmpconsole = FALSE; + } +#endif + nethack_exit(EXIT_SUCCESS); + } + +#if defined(MSWIN_GRAPHICS) + if (!strncmpi(argv[1], "-clearreg", 6)) { /* clear registry */ + mswin_destroy_reg(); + nethack_exit(EXIT_SUCCESS); + } +#endif + /* Don't initialize the window system just to print usage */ + if (!strncmp(argv[1], "-?", 2) || !strncmp(argv[1], "/?", 2)) { + nhusage(); + +#if !defined(TTY_GRAPHICS) + if (tmpconsole) { + getreturn("to exit"); + freefakeconsole(); + tmpconsole = FALSE; + } +#endif + nethack_exit(EXIT_SUCCESS); + } + } + } + getreturn_enabled = save_getreturn_status; + +/* + * It seems you really want to play. + */ + /* In 3.6.0, several ports process options before they init + * the window port. This allows settings that impact window + * ports to be specified or read from the sys or user config files. + */ + process_options(argc, argv); + + if (argc >= 1 + && !strcmpi(default_window_sys, "mswin") + && strstri(argv[0], "nethackw.exe")) + iflags.windowtype_locked = TRUE; + +#if defined(TTY_GRAPHICS) + if (!iflags.windowtype_locked) + Strcpy(default_window_sys, "tty"); +#else +#if defined(CURSES_GRAPHICS) + if (!iflags.windowtype_locked) + Strcpy(default_window_sys, "curses"); +#endif +#endif + choose_windows(default_window_sys); + if (!dlb_init()) { + pline( + "%s\n%s\n%s\n%s\n\nNetHack was unable to open the required file " + "\"%s\".%s", + copyright_banner_line(1), copyright_banner_line(2), + copyright_banner_line(3), copyright_banner_line(4), DLBFILE, + "\nAre you perhaps trying to run NetHack within a zip utility?"); + error("dlb_init failure."); + } + + u.uhp = 1; /* prevent RIP on early quits */ + u.ux = 0; /* prevent flush_screen() */ + + nethack_enter(argc, argv); + iflags.use_background_glyph = FALSE; + if (WINDOWPORT("mswin")) + iflags.use_background_glyph = TRUE; + if (WINDOWPORT("tty")) + nttty_open(1); + + init_nhwindows(&argc, argv); + + if (WINDOWPORT("tty")) + toggle_mouse_support(); + + /* strip role,race,&c suffix; calls askname() if plname[] is empty + or holds a generic user name like "player" or "games" */ + plnamesuffix(); + set_playmode(); /* sets plname to "wizard" for wizard mode */ + /* until the getlock code is resolved, override askname()'s + setting of renameallowed; when False, player_selection() + won't resent renaming as an option */ + iflags.renameallowed = FALSE; + /* Obtain the name of the logged on user and incorporate + * it into the name. */ + Sprintf(fnamebuf, "%s-%s", get_username(0), plname); + (void) fname_encode( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.", '%', + fnamebuf, encodedfnamebuf, BUFSZ); + Sprintf(lock, "%s", encodedfnamebuf); + /* regularize(lock); */ /* we encode now, rather than substitute */ + getlock(); + + /* Set up level 0 file to keep the game state. + */ + fd = create_levelfile(0, (char *) 0); + if (fd < 0) { + raw_print("Cannot create lock file"); + } else { + hackpid = GetCurrentProcessId(); + write(fd, (genericptr_t) &hackpid, sizeof(hackpid)); + nhclose(fd); + } + /* + * Initialize the vision system. This must be before mklev() on a + * new game or before a level restore on a saved game. + */ + vision_init(); + display_gamewindows(); + getreturn_enabled = TRUE; + /* + * First, try to find and restore a save file for specified character. + * We'll return here if new game player_selection() renames the hero. + */ +attempt_restore: + if ((fd = restore_saved_game()) >= 0) { +#ifdef NEWS + if (iflags.news) { + display_file(NEWS, FALSE); + iflags.news = FALSE; + } +#endif + pline("Restoring save file..."); + mark_synch(); /* flush output */ + if (dorecover(fd)) { + resuming = TRUE; /* not starting new game */ + if (discover) + You("are in non-scoring discovery mode."); + if (discover || wizard) { + if (yn("Do you want to keep the save file?") == 'n') + (void) delete_savefile(); + else { + nh_compress(fqname(SAVEF, SAVEPREFIX, 0)); + } + } + } + } + + if (!resuming) { + /* new game: start by choosing role, race, etc; + player might change the hero's name while doing that, + in which case we try to restore under the new name + and skip selection this time if that didn't succeed */ + if (!iflags.renameinprogress) { + player_selection(); + if (iflags.renameinprogress) { + /* player has renamed the hero while selecting role; + discard current lock file and create another for + the new character name */ + goto attempt_restore; + } + } + newgame(); + if (discover) + You("are in non-scoring discovery mode."); + } + moveloop(resuming); + nethack_exit(EXIT_SUCCESS); + /*NOTREACHED*/ + return 0; +} + +STATIC_OVL void +process_options(argc, argv) +int argc; +char *argv[]; +{ + int i; + + /* + * Process options. + */ + while (argc > 1 && argv[1][0] == '-') { + argv++; + argc--; + switch (argv[0][1]) { + case 'a': + if (argv[0][2]) { + if ((i = str2align(&argv[0][2])) >= 0) + flags.initalign = i; + } else if (argc > 1) { + argc--; + argv++; + if ((i = str2align(argv[0])) >= 0) + flags.initalign = i; + } + break; + case 'D': + wizard = TRUE, discover = FALSE; + break; + case 'X': + discover = TRUE, wizard = FALSE; + break; +#ifdef NEWS + case 'n': + iflags.news = FALSE; + break; +#endif + case 'u': + if (argv[0][2]) + (void) strncpy(plname, argv[0] + 2, sizeof(plname) - 1); + else if (argc > 1) { + argc--; + argv++; + (void) strncpy(plname, argv[0], sizeof(plname) - 1); + } else + raw_print("Player name expected after -u"); + break; + case 'g': + if (argv[0][2]) { + if ((i = str2gend(&argv[0][2])) >= 0) + flags.initgend = i; + } else if (argc > 1) { + argc--; + argv++; + if ((i = str2gend(argv[0])) >= 0) + flags.initgend = i; + } + break; + case 'p': /* profession (role) */ + if (argv[0][2]) { + if ((i = str2role(&argv[0][2])) >= 0) + flags.initrole = i; + } else if (argc > 1) { + argc--; + argv++; + if ((i = str2role(argv[0])) >= 0) + flags.initrole = i; + } + break; + case 'r': /* race */ + if (argv[0][2]) { + if ((i = str2race(&argv[0][2])) >= 0) + flags.initrace = i; + } else if (argc > 1) { + argc--; + argv++; + if ((i = str2race(argv[0])) >= 0) + flags.initrace = i; + } + break; +#if 0 + case 'w': /* windowtype */ +#if defined(TTY_GRAPHICS) + if (!strncmpi(&argv[0][2], "tty", 3)) { + nttty_open(1); + } +#endif + config_error_init(FALSE, "command line", FALSE); + choose_windows(&argv[0][2]); + config_error_done(); + break; +#endif + case '@': + flags.randomall = 1; + break; + default: + if ((i = str2role(&argv[0][1])) >= 0) { + flags.initrole = i; + break; + } else + raw_printf("\nUnknown switch: %s", argv[0]); + /* FALL THROUGH */ + case '?': + nhusage(); + nethack_exit(EXIT_SUCCESS); + } + } +} + +STATIC_OVL void +nhusage() +{ + char buf1[BUFSZ], buf2[BUFSZ], *bufptr; + + buf1[0] = '\0'; + bufptr = buf1; + +#define ADD_USAGE(s) \ + if ((strlen(buf1) + strlen(s)) < (BUFSZ - 1)) \ + Strcat(bufptr, s); + + /* -role still works for those cases which aren't already taken, but + * is deprecated and will not be listed here. + */ + (void) Sprintf(buf2, "\nUsage:\n%s [-d dir] -s [-r race] [-p profession] " + "[maxrank] [name]...\n or", + hname); + ADD_USAGE(buf2); + + (void) Sprintf( + buf2, "\n%s [-d dir] [-u name] [-r race] [-p profession] [-[DX]]", + hname); + ADD_USAGE(buf2); +#ifdef NEWS + ADD_USAGE(" [-n]"); +#endif + if (!iflags.window_inited) + raw_printf("%s\n", buf1); + else + (void) printf("%s\n", buf1); +#undef ADD_USAGE +} + +#ifdef PORT_HELP +void +port_help() +{ + /* display port specific help file */ + display_file(PORT_HELP, 1); +} +#endif /* PORT_HELP */ + +/* validate wizard mode if player has requested access to it */ +boolean +authorize_wizard_mode() +{ + if (!strcmp(plname, WIZARD_NAME)) + return TRUE; + return FALSE; +} + +#define PATH_SEPARATOR '\\' + +#if defined(WIN32) && !defined(WIN32CON) +static char exenamebuf[PATHLEN]; +extern HANDLE hConIn; +extern HANDLE hConOut; +boolean has_fakeconsole; + +char * +exename() +{ + int bsize = PATHLEN; + char *tmp = exenamebuf, *tmp2; + +#ifdef UNICODE + { + TCHAR wbuf[PATHLEN * 4]; + GetModuleFileName((HANDLE) 0, wbuf, PATHLEN * 4); + WideCharToMultiByte(CP_ACP, 0, wbuf, -1, tmp, bsize, NULL, NULL); + } +#else + *(tmp + GetModuleFileName((HANDLE) 0, tmp, bsize)) = '\0'; +#endif + tmp2 = strrchr(tmp, PATH_SEPARATOR); + if (tmp2) + *tmp2 = '\0'; + tmp2++; + return tmp2; +} + +boolean +fakeconsole(void) +{ + if (!hStdOut) { + HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); + + if (!hStdOut && !hStdIn) { + /* Bool rval; */ + AllocConsole(); + AttachConsole(GetCurrentProcessId()); + /* rval = SetStdHandle(STD_OUTPUT_HANDLE, hWrite); */ + freopen("CON", "w", stdout); + freopen("CON", "r", stdin); + } + has_fakeconsole = TRUE; + } + + /* Obtain handles for the standard Console I/O devices */ + hConIn = GetStdHandle(STD_INPUT_HANDLE); + hConOut = GetStdHandle(STD_OUTPUT_HANDLE); +#if 0 + if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE)) { + /* Unable to set control handler */ + cmode = 0; /* just to have a statement to break on for debugger */ + } +#endif + return has_fakeconsole; +} +void freefakeconsole() +{ + if (has_fakeconsole) { + FreeConsole(); + } +} +#endif + +#define EXEPATHBUFSZ 256 +char exepathbuf[EXEPATHBUFSZ]; + +char * +exepath(str) +char *str; +{ + char *tmp, *tmp2; + int bsize; + + if (!str) + return (char *) 0; + bsize = EXEPATHBUFSZ; + tmp = exepathbuf; +#ifdef UNICODE + { + TCHAR wbuf[BUFSZ]; + GetModuleFileName((HANDLE) 0, wbuf, BUFSZ); + WideCharToMultiByte(CP_ACP, 0, wbuf, -1, tmp, bsize, NULL, NULL); + } +#else + *(tmp + GetModuleFileName((HANDLE) 0, tmp, bsize)) = '\0'; +#endif + tmp2 = strrchr(tmp, PATH_SEPARATOR); + if (tmp2) + *tmp2 = '\0'; + return tmp; +} + +/*ARGSUSED*/ +void +windows_raw_print(str) +const char *str; +{ + if (str) + fprintf(stdout, "%s\n", str); + windows_nhgetch(); + return; +} + +/*ARGSUSED*/ +void +windows_raw_print_bold(str) +const char *str; +{ + windows_raw_print(str); + return; +} + +int +windows_nhgetch() +{ + return getchar(); +} + + +void +windows_nhbell() +{ + return; +} + +/*ARGSUSED*/ +int +windows_nh_poskey(x, y, mod) +int *x, *y, *mod; +{ + return '\033'; +} + +/*ARGSUSED*/ +char +windows_yn_function(query, resp, def) +const char *query; +const char *resp; +char def; +{ + return '\033'; +} + +/*ARGSUSED*/ +static void +windows_getlin(prompt, outbuf) +const char *prompt UNUSED; +char *outbuf; +{ + Strcpy(outbuf, "\033"); +} + +/*pcmain.c*/ diff --git a/sys/winnt/winnt.c b/sys/winnt/winnt.c index 0be1da094..f5121bddc 100644 --- a/sys/winnt/winnt.c +++ b/sys/winnt/winnt.c @@ -47,6 +47,9 @@ WIN32_FIND_DATA ffd; typedef HWND(WINAPI *GETCONSOLEWINDOW)(); static HWND GetConsoleHandle(void); static HWND GetConsoleHwnd(void); +#if !defined(TTY_GRAPHICS) +extern void NDECL(backsp); +#endif /* The function pointer nt_kbhit contains a kbhit() equivalent * which varies depending on which window port is active. diff --git a/win/win32/vs2017/NetHack.vcxproj b/win/win32/vs2017/NetHack.vcxproj index e51474a65..84daa8434 100644 --- a/win/win32/vs2017/NetHack.vcxproj +++ b/win/win32/vs2017/NetHack.vcxproj @@ -151,15 +151,16 @@ - + GUISTUB;%(PreprocessorDefinitions) + @@ -254,4 +255,4 @@ - \ No newline at end of file + diff --git a/win/win32/vs2017/NetHackW.vcxproj b/win/win32/vs2017/NetHackW.vcxproj index af28761da..c54c8e9f5 100644 --- a/win/win32/vs2017/NetHackW.vcxproj +++ b/win/win32/vs2017/NetHackW.vcxproj @@ -146,14 +146,15 @@ - + TTYSTUB; + @@ -200,4 +201,4 @@ - \ No newline at end of file + diff --git a/win/win32/winhack.c b/win/win32/winhack.c index 9dcbb4e4b..6796a5ce6 100644 --- a/win/win32/winhack.c +++ b/win/win32/winhack.c @@ -15,6 +15,10 @@ #include "mhmain.h" #include "mhmap.h" +#if !defined(SAFEPROCS) +#error You must #define SAFEPROCS to build winhack.c +#endif + /* Borland and MinGW redefine "boolean" in shlwapi.h, so just use the little bit we need */ typedef struct _DLLVERSIONINFO { @@ -66,7 +70,7 @@ NHWinApp _nethack_app; #endif // Foward declarations of functions included in this code module: -extern boolean FDECL(pcmain, (int, char **)); +extern boolean FDECL(main, (int, char **)); static void __cdecl mswin_moveloop(void *); #define MAX_CMDLINE_PARAM 255 @@ -82,24 +86,44 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, TCHAR *p; TCHAR wbuf[BUFSZ]; char buf[BUFSZ]; + DWORD major, minor; - boolean resuming; /* OSVERSIONINFO osvi; */ UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); UNREFERENCED_PARAMETER(nCmdShow); - /* We must initialize state sufficiently to support calls to panic */ + /* + * Get a set of valid safe windowport function + * pointers during early startup initialization. + * + * When get_safe_procs is called with 0 as the param, + * non-functional, but safe function pointers are set + * for all windowport routines. + * + * When get_safe_procs is called with 1 as the param, + * raw_print, raw_print_bold, and wait_synch, and nhgetch + * are set to use C stdio routines via stdio_raw_print, + * stdio_raw_print_bold, stdio_wait_synch, and + * stdio_nhgetch. + */ + windowprocs = *get_safe_procs(0); + + /* + * Now we are going to override a couple + * of the windowprocs functions so that + * error messages are handled in a suitable + * way for the graphical version. + */ windowprocs.win_raw_print = mswin_raw_print; windowprocs.win_raw_print_bold = mswin_raw_print_bold; windowprocs.win_wait_synch = mswin_wait_synch; win10_init(); - sys_early_init(); - /* init applicatio structure */ + /* init application structure */ _nethack_app.hApp = hInstance; _nethack_app.hAccelTable = LoadAccelerators(hInstance, (LPCTSTR) IDC_NETHACKW); @@ -209,10 +233,9 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, } free(savefile); } - resuming = pcmain(argc, argv); - - moveloop(resuming); + /* let main do the argument processing */ + (void) main(argc, argv); return 0; }