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; }