From 5c57804a97bda18a5383279161e9163e89fe8054 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 3 Dec 2019 23:32:12 -0500 Subject: [PATCH] fix self-recover prompting on windows the prompting on Windows wasn't working correctly if a prior game had crashed and the self-recover feature was trying to kick in. This impacts tty, curses, and mswin (GUI). --- doc/fixes36.3 | 1 + include/extern.h | 8 +- sys/winnt/Makefile.msc | 2 +- sys/winnt/nttty.c | 28 ++++- sys/winnt/windmain.c | 239 +++++++++++++++++++++++++++++++---------- win/share/safeproc.c | 2 +- 6 files changed, 216 insertions(+), 64 deletions(-) diff --git a/doc/fixes36.3 b/doc/fixes36.3 index baf32548d..d0b52cd5d 100644 --- a/doc/fixes36.3 +++ b/doc/fixes36.3 @@ -327,6 +327,7 @@ windows: fix --showpaths output for the data file which relies on being constructed programmatically to incorporate the version suffix windows+tty: add code to make keypad support for swap_yz behave (currently commented out in include/ntconf.h) +windows: fix self-recover user prompting (tty, curses, mswin) Platform- and/or Interface-Specific Fixes or Features diff --git a/include/extern.h b/include/extern.h index 88f71fed9..0ac10abee 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1823,15 +1823,17 @@ E char *FDECL(dowhatdoes_core, (CHAR_P, char *)); E int NDECL(dohelp); E int NDECL(dohistory); -/* ### pcmain.c ### */ +/* ### xxmain.c ### */ #if defined(MICRO) || defined(WIN32) #ifdef CHDIR E void FDECL(chdirx, (char *, BOOLEAN_P)); #endif /* CHDIR */ E boolean NDECL(authorize_wizard_mode); - #endif /* MICRO || WIN32 */ +#if defined(WIN32) +E int NDECL(getlock); +#endif /* ### pcsys.c ### */ @@ -1869,10 +1871,10 @@ E void FDECL(msleep, (unsigned)); #if defined(MICRO) E void FDECL(regularize, (char *)); -#endif /* MICRO */ #if defined(PC_LOCKING) E void NDECL(getlock); #endif +#endif /* MICRO */ /* ### pickup.c ### */ diff --git a/sys/winnt/Makefile.msc b/sys/winnt/Makefile.msc index 8e0da5bd4..550c71fc0 100644 --- a/sys/winnt/Makefile.msc +++ b/sys/winnt/Makefile.msc @@ -73,7 +73,7 @@ DEBUGINFO = Y # of your PDCurses C files. # #ADD_CURSES=Y -#PDCURSES_TOP=..\..\pdcurses +#PDCURSES_TOP=..\lib\pdcurses # #============================================================================== # This marks the end of the BUILD DECISIONS section. diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 9c96ae8a4..2760b5493 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -680,13 +680,37 @@ cl_end() void raw_clear_screen() { - buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0); + if (WINDOWPORT("tty")) { + cell_t * back = console.back_buffer; + cell_t * front = console.front_buffer; + COORD pos; + DWORD unused; + + for (pos.Y = 0; pos.Y < console.height; pos.Y++) { + for (pos.X = 0; pos.X < console.width; pos.X++) { + WriteConsoleOutputAttribute(console.hConOut, &back->attribute, + 1, pos, &unused); + front->attribute = back->attribute; + if (console.has_unicode) { + WriteConsoleOutputCharacterW(console.hConOut, + &back->character, 1, pos, &unused); + } else { + char ch = (char)back->character; + WriteConsoleOutputCharacterA(console.hConOut, &ch, 1, pos, + &unused); + } + *front = *back; + back++; + front++; + } + } + } } void clear_screen() { - raw_clear_screen(); + buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0); home(); } diff --git a/sys/winnt/windmain.c b/sys/winnt/windmain.c index 5fba32d74..332d363dd 100644 --- a/sys/winnt/windmain.c +++ b/sys/winnt/windmain.c @@ -39,6 +39,13 @@ extern void NDECL(backsp); extern void NDECL(clear_screen); #undef E +#ifdef _MSC_VER +#ifdef kbhit +#undef kbhit +#endif +#include +#endif + #ifdef PC_LOCKING static int NDECL(eraseoldlocks); #endif @@ -50,6 +57,8 @@ char FDECL(windows_yn_function, (const char *, const char *, CHAR_P)); static void FDECL(windows_getlin, (const char *, char *)); extern int NDECL(windows_console_custom_nhgetch); void NDECL(safe_routines); +int NDECL(tty_self_recover_prompt); +int NDECL(other_self_recover_prompt); char orgdir[PATHLEN]; boolean getreturn_enabled; @@ -460,7 +469,8 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ fnamebuf, encodedfnamebuf, BUFSZ); Sprintf(lock, "%s", encodedfnamebuf); /* regularize(lock); */ /* we encode now, rather than substitute */ - getlock(); + if (getlock() == 0) + nethack_exit(EXIT_SUCCESS); /* Set up level 0 file to keep the game state. */ @@ -997,15 +1007,16 @@ eraseoldlocks() return (1); /* success! */ } -void +int getlock() { - register int fd, c, ci, ct, ern; + register int fd, ern, prompt_result = 0; int fcmask = FCMASK; char tbuf[BUFSZ]; const char *fq_lock; #define OOPS_BUFSZ 512 char oops[OOPS_BUFSZ]; + boolean istty = WINDOWPORT("tty"); /* we ignore QUIT and INT at this point */ if (!lock_file(HLOCK, LOCKPREFIX, 10)) { @@ -1050,56 +1061,41 @@ getlock() (void) nhclose(fd); - if (iflags.window_inited || WINDOWPORT("curses")) { -#ifdef SELF_RECOVER - c = yn("There are files from a game in progress under your name. " - "Recover?"); -#else - pline("There is already a game in progress under your name."); - pline("You may be able to use \"recover %s\" to get it back.\n", - tbuf); - c = yn("Do you want to destroy the old game?"); -#endif - } else { - c = 'n'; - ct = 0; -#ifdef SELF_RECOVER - raw_print("There are files from a game in progress under your name. " - "Recover? [yn]"); -#else - raw_print("\nThere is already a game in progress under your name.\n"); - raw_print("If this is unexpected, you may be able to use \n"); - raw_print("\"recover %s\" to get it back.", tbuf); - raw_print("\nDo you want to destroy the old game? [yn] "); -#endif - while ((ci = nhgetch()) != '\n') { - if (ct > 0) { - raw_print("\b \b"); - ct = 0; - c = 'n'; - } - if (ci == 'y' || ci == 'n' || ci == 'Y' || ci == 'N') { - ct = 1; - c = ci; - } - } - } - if (c == 'y' || c == 'Y') -#ifndef SELF_RECOVER - if (eraseoldlocks()) { - if (WINDOWPORT("tty")) - clear_screen(); /* display gets fouled up otherwise */ - goto gotlock; - } else { - unlock_file(HLOCK); -#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) - chdirx(orgdir, 0); -#endif - raw_print("Couldn't destroy old game."); - } -#else /*SELF_RECOVER*/ + if (WINDOWPORT("tty")) + prompt_result = tty_self_recover_prompt(); + else + prompt_result = other_self_recover_prompt(); + /* + * prompt_result == 1 means recover old game. + * prompt_result == -1 means willfully destroy the old game. + * prompt_result == 0 should just exit. + */ + Sprintf(oops, "You chose to %s.", + (prompt_result == -1) + ? "destroy the old game and start a new one" + : (prompt_result == 1) + ? "recover the old game" + : "not start a new game"); + if (istty) + clear_screen(); + pline(oops); + if (prompt_result == 1) { /* recover */ if (recover_savefile()) { - if (WINDOWPORT("tty")) +#if 0 + if (istty) + clear_screen(); /* display gets fouled up otherwise */ +#endif + goto gotlock; + } else { + unlock_file(HLOCK); +#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) + chdirx(orgdir, 0); +#endif + raw_print("Couldn't recover the old game."); + } + } else if (prompt_result < 0) { /* destroy old game */ + if (eraseoldlocks()) { + if (istty) clear_screen(); /* display gets fouled up otherwise */ goto gotlock; } else { @@ -1107,16 +1103,15 @@ getlock() #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); #endif - raw_print("Couldn't recover old game."); + raw_print("Couldn't destroy the old game."); + return 0; } -#endif /*SELF_RECOVER*/ - else { + } else { unlock_file(HLOCK); #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); #endif - Sprintf(oops, "%s", "Cannot start a new game."); - raw_print(oops); + return 0; } gotlock: @@ -1147,6 +1142,7 @@ gotlock: error("cannot close lock (%s)", fq_lock); } } + return 1; } #endif /* PC_LOCKING */ @@ -1187,4 +1183,133 @@ const char * b_path; return FALSE; } +/* + * returns: + * 1 if game should be recovered + * -1 if old game should be destroyed, allowing new game to proceed. + */ +int +tty_self_recover_prompt() +{ + register int c, ci, ct, pl, retval = 0; + /* for saving/replacing functions, if needed */ + struct window_procs saved_procs = {0}; + + pl = 1; + c = 'n'; + ct = 0; + saved_procs = windowprocs; + safe_routines(); + raw_print("\n"); + raw_print("\n"); + raw_print("\n"); + raw_print("\n"); + raw_print("\n"); + raw_print("There are files from a game in progress under your name. "); + raw_print("Recover? [yn] "); + + tty_ask_again: + + while ((ci = nhgetch()) && !(ci == '\n' || ci == 13)) { + if (ct > 0) { + /* invalid answer */ + raw_print("\b \b"); + ct = 0; + c = 'n'; + } + if (ci == 'y' || ci == 'n' || ci == 'Y' || ci == 'N') { + ct = 1; + c = ci; +#ifdef _MSC_VER + _putch(ci); +#endif + } + } + + if (pl == 1 && (c == 'n' || c == 'N')) { + /* no to recover */ + raw_print("\n\nAre you sure you wish to destroy the old game rather than try to\n"); + raw_print("recover it? [yn] "); + c = 'n'; + ct = 0; + pl = 2; + goto tty_ask_again; + } + + if (pl == 2 && (c == 'n' || c == 'N')) { + /* no to destruction of old game */ + retval = 0; + } else { + /* only yes answers get here */ + if (pl == 2) + retval = -1; /* yes, do destroy the old game anyway */ + else + retval = 1; /* yes, do recover the old game */ + } + if (saved_procs.name[0]) { + windowprocs = saved_procs; + raw_clear_screen(); + } + return retval; +} + +int +other_self_recover_prompt() +{ + register int c, ci, ct, pl, retval = 0; + boolean ismswin = WINDOWPORT("mswin"), + iscurses = WINDOWPORT("curses"); + + pl = 1; + c = 'n'; + ct = 0; + if (iflags.window_inited || WINDOWPORT("curses")) { + c = yn("There are files from a game in progress under your name. " + "Recover?"); + } else { + c = 'n'; + ct = 0; + raw_print("There are files from a game in progress under your name. " + "Recover? [yn]"); + } + + other_ask_again: + + if (!ismswin && !iscurses) { + while ((ci = nhgetch()) && !(ci == '\n' || ci == 13)) { + if (ct > 0) { + /* invalid answer */ + raw_print("\b \b"); + ct = 0; + c = 'n'; + } + if (ci == 'y' || ci == 'n' || ci == 'Y' || ci == 'N') { + ct = 1; + c = ci; + } + } + } + if (pl == 1 && (c == 'n' || c == 'N')) { + /* no to recover */ + c = yn("Are you sure you wish to destroy the old game, rather than try to " + "recover it? [yn] "); + pl = 2; + if (!ismswin && !iscurses) { + c = 'n'; + ct = 0; + goto other_ask_again; + } + } + if (pl == 2 && (c == 'n' || c == 'N')) { + /* no to destruction of old game */ + retval = 0; + } else { + /* only yes answers get here */ + if (pl == 2) + retval = -1; /* yes, do destroy the old game anyway */ + else + retval = 1; /* yes, do recover the old game */ + } + return retval; +} /*windmain.c*/ diff --git a/win/share/safeproc.c b/win/share/safeproc.c index b0f75220a..28896c9c2 100644 --- a/win/share/safeproc.c +++ b/win/share/safeproc.c @@ -538,7 +538,7 @@ stdio_raw_print(str) const char *str; { if (str) - fprintf(stdout, "%s\n", str); + fprintf(stdout, "%s", str); return; }