From 7da9fbce1aed84ac9b02d8c4f7363ca02429d238 Mon Sep 17 00:00:00 2001 From: zelgadis Date: Tue, 28 Jul 2009 07:19:25 +0000 Subject: Backport r10443: generalized way of dealing with "disconnect at --more--" hacks. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/branches/stone_soup-0.5@10444 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/acr.cc | 11 ++++++++++ crawl-ref/source/cio.cc | 9 ++++++++ crawl-ref/source/directn.cc | 26 +++++++++++++++++++++++ crawl-ref/source/effects.cc | 13 +++++++++++- crawl-ref/source/libunix.cc | 52 +++++++++++++++++++++++++++++++++++++++------ crawl-ref/source/libunix.h | 4 ++++ crawl-ref/source/message.cc | 2 +- crawl-ref/source/spells3.cc | 12 +++++++++++ crawl-ref/source/stuff.cc | 18 +++++++++++++--- crawl-ref/source/view.cc | 10 +++++++++ 10 files changed, 145 insertions(+), 12 deletions(-) diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 9318b863ee..58acce1cdd 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -878,6 +878,11 @@ static void _center_cursor() // static void _input() { +#if defined(USE_UNIX_SIGNALS) && defined(SIGHUP_SAVE) && defined(USE_CURSES) + if (crawl_state.seen_hups) + sighup_save_and_exit(); +#endif + crawl_state.clear_mon_acting(); religion_turn_start(); @@ -1022,6 +1027,11 @@ static void _input() #endif const command_type cmd = _get_next_cmd(); +#if defined(USE_UNIX_SIGNALS) && defined(SIGHUP_SAVE) && defined(USE_CURSES) + if (crawl_state.seen_hups) + sighup_save_and_exit(); +#endif + crawl_state.waiting_for_command = false; if (cmd != CMD_PREV_CMD_AGAIN && cmd != CMD_REPEAT_CMD @@ -2497,6 +2507,7 @@ static void _check_banished() if (you.level_type != LEVEL_ABYSS) { mpr("You are cast into the Abyss!"); + more(); banished(DNGN_ENTER_ABYSS, you.banished_by); } you.banished_by.clear(); diff --git a/crawl-ref/source/cio.cc b/crawl-ref/source/cio.cc index b9ff80c25f..b3382bf6fc 100644 --- a/crawl-ref/source/cio.cc +++ b/crawl-ref/source/cio.cc @@ -426,6 +426,15 @@ int line_reader::read_line(bool clear_previous) { int ch = getchm(c_getch); +#if defined(USE_UNIX_SIGNALS) && defined(SIGHUP_SAVE) && defined(USE_CURSES) + // Don't return a partial string if a HUP signal interrupted things + if (crawl_state.seen_hups) + { + buffer[0] = '\0'; + return (0); + } +#endif + if (keyfn) { int whattodo = (*keyfn)(ch); diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc index 9fd43d7dbc..333d733e54 100644 --- a/crawl-ref/source/directn.cc +++ b/crawl-ref/source/directn.cc @@ -138,6 +138,19 @@ void direction_choose_compass( dist& moves, targeting_behaviour *beh) { const command_type key_command = beh->get_command(); +#if defined(USE_UNIX_SIGNALS) && defined(SIGHUP_SAVE) && defined(USE_CURSES) + // If we've received a HUP signal then the user can't choose a + // target. + if (crawl_state.seen_hups) + { + moves.isValid = false; + moves.isCancel = true; + + mpr("Targetting interrupted by HUP signal.", MSGCH_ERROR); + return; + } +#endif + #ifdef USE_TILE if (key_command == CMD_TARGET_MOUSE_MOVE) { @@ -1069,6 +1082,19 @@ void direction(dist& moves, targeting_type restricts, while (true) { +#if defined(USE_UNIX_SIGNALS) && defined(SIGHUP_SAVE) && defined(USE_CURSES) + // If we've received a HUP signal then the user can't choose a + // target. + if (crawl_state.seen_hups) + { + moves.isValid = false; + moves.isCancel = true; + + mpr("Targetting interrupted by HUP signal.", MSGCH_ERROR); + return; + } +#endif + bool allow_out_of_range = false; // Prompts might get scrolled off if you have too few lines available. diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc index 21ea6807d4..b7898e8d47 100644 --- a/crawl-ref/source/effects.cc +++ b/crawl-ref/source/effects.cc @@ -1572,7 +1572,18 @@ bool acquirement(object_class_type class_wanted, int agent, canned_msg(MSG_OK); return (false); } - break; + +#if defined(USE_UNIX_SIGNALS) && defined(SIGHUP_SAVE) && defined(USE_CURSES) + // If we've gotten a HUP signal then the player will be unable + // to make a selection. + if (crawl_state.seen_hups) + { + mpr("Acquirement interrupted by HUP signal.", MSGCH_ERROR); + you.turn_is_over = false; + return (false); + } +#endif + break; } } diff --git a/crawl-ref/source/libunix.cc b/crawl-ref/source/libunix.cc index 830f03edcb..20dd071ca8 100644 --- a/crawl-ref/source/libunix.cc +++ b/crawl-ref/source/libunix.cc @@ -31,6 +31,7 @@ REVISION("$Rev$"); #include "defines.h" #include "cio.h" +#include "delay.h" #include "enum.h" #include "externs.h" #include "files.h" @@ -330,27 +331,60 @@ static void handle_hangup(int) if (crawl_state.seen_hups++) return; + interrupt_activity( AI_FORCE_INTERRUPT ); + +#ifdef USE_TILE + // XXX: Will a tiles build ever need to handle the HUP signal? + sighup_save_and_exit(); +#elif defined(USE_CURSES) + // When using Curses, closing stdin will cause any Curses call blocking + // on key-presses to immediately return, including any call that was + // still blocking in the main thread when the HUP signal was caught. + // This should guarantee that the main thread will un-stall and + // will eventually return to _input() in acr.cc, which will then + // call sighup_save_and_exit(). + // + // The point to all this is that if a user is playing a game on a + // remote server and disconnects at a --more-- prompt, that when + // the player reconnects the code behind the more() call will execute + // before the disconnected game is saved, thus (for example) preventing + // the hack of avoiding excomunication consesquences because of the + // more() after "You have lost your religion!" + fclose(stdin); +#else + #error "Must use either Curses or tiles on Unix" +#endif +} + +void sighup_save_and_exit() +{ + if (crawl_state.seen_hups == 0) + { + mpr("sighup_save_and_exit() called without a HUP signal; please" + "file a bug report", MSGCH_ERROR); + return; + } + if (crawl_state.saving_game || crawl_state.updating_scores) return; crawl_state.saving_game = true; if (crawl_state.need_save) { + mpr("Received HUP signal, saved and exited game.", MSGCH_ERROR); + // Clean up all the hooks. for (unsigned i = 0; i < crawl_state.exit_hooks.size(); ++i) crawl_state.exit_hooks[i]->restore_state(); crawl_state.exit_hooks.clear(); - // save_game(true) also exits, saving us the trouble of doing so. - save_game(true); + // save_game(true) exits from the game. The "true" is also required + // to save changes to the current level. + save_game(true, "Received HUP signal, saved game."); } else - { - // CROAK! No attempt to clean up curses. This is probably not an - // issue since the term has gone away. - exit(1); - } + end(0, false, "Received HUP signal, game already saved."); } #endif // SIGHUP_SAVE @@ -807,6 +841,10 @@ void get_input_line_from_curses( char *const buff, int len ) echo(); wgetnstr( stdscr, buff, len ); noecho(); + + // Don't return a partial string if a HUP signal interrupted things. + if (crawl_state.seen_hups) + buff[0] = '\0'; } int clrscr() diff --git a/crawl-ref/source/libunix.h b/crawl-ref/source/libunix.h index 4816e43a87..8e6b2d943b 100644 --- a/crawl-ref/source/libunix.h +++ b/crawl-ref/source/libunix.h @@ -68,6 +68,10 @@ inline bool is_smart_cursor_enabled() { return (false); } void set_mouse_enabled(bool enabled); +#if defined(SIGHUP_SAVE) && defined(USE_UNIX_SIGNALS) +void sighup_save_and_exit(); +#endif + #ifndef _LIBUNIX_IMPLEMENTATION /* Some stuff from curses, to remove compiling warnings.. */ extern "C" diff --git a/crawl-ref/source/message.cc b/crawl-ref/source/message.cc index e5606cd39c..67e4739f02 100644 --- a/crawl-ref/source/message.cc +++ b/crawl-ref/source/message.cc @@ -1023,7 +1023,7 @@ void reset_more_autoclear() void more(bool user_forced) { - if (crawl_state.game_crashed) + if (crawl_state.game_crashed || crawl_state.seen_hups) return; #ifdef DEBUG_DIAGNOSTICS diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc index 8740fae83d..56d2c079aa 100644 --- a/crawl-ref/source/spells3.cc +++ b/crawl-ref/source/spells3.cc @@ -1319,6 +1319,18 @@ static bool _teleport_player( bool allow_control, bool new_abyss_area ) show_map(pos, false); redraw_screen(); +#if defined(USE_UNIX_SIGNALS) && defined(SIGHUP_SAVE) && defined(USE_CURSES) + // If we've received a HUP signal then the user can't choose a + // location, so cancel the teleport. + if (crawl_state.seen_hups) + { + mpr("Controlled teleport interrupted by HUP signal, " + "cancelling teleport.", MSGCH_ERROR); + you.turn_is_over = false; + return (false); + } +#endif + #if DEBUG_DIAGNOSTICS mprf(MSGCH_DIAGNOSTICS, "Target square (%d,%d)", pos.x, pos.y ); #endif diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc index 43bcdb7a77..da82087544 100644 --- a/crawl-ref/source/stuff.cc +++ b/crawl-ref/source/stuff.cc @@ -775,7 +775,7 @@ void end(int exit_code, bool print_error, const char *format, ...) } #if defined(WIN32CONSOLE) || defined(DOS) || defined(DGL_PAUSE_AFTER_ERROR) - if (exit_code && !crawl_state.arena) + if (exit_code && !crawl_state.arena && !crawl_state.seen_hups) { fprintf(stderr, "Hit Enter to continue...\n"); getchar(); @@ -1065,12 +1065,21 @@ bool yesno( const char *str, bool safe, int safeanswer, bool clear_after, int tmp = getchm(KMC_CONFIRM); +#if defined(USE_UNIX_SIGNALS) && defined(SIGHUP_SAVE) && defined(USE_CURSES) + // Prevent infinite loop if Curses HUP signal handling happens; + // if there is no safe answer, then just save-and-exit immediately, + // since there's no way to know if it would be better to return + // true or false. + if (crawl_state.seen_hups && !safeanswer) + sighup_save_and_exit(); +#endif + if (map && map->find(tmp) != map->end()) tmp = map->find(tmp)->second; if (safeanswer && (tmp == ' ' || tmp == ESCAPE || tmp == CONTROL('G') - || tmp == '\r' || tmp == '\n')) + || tmp == '\r' || tmp == '\n' || crawl_state.seen_hups)) { tmp = safeanswer; } @@ -1166,8 +1175,11 @@ int yesnoquit( const char* str, bool safe, int safeanswer, bool allow_all, int tmp = getchm(KMC_CONFIRM); - if (tmp == CK_ESCAPE || tmp == CONTROL('G') || tmp == 'q' || tmp == 'Q') + if (tmp == CK_ESCAPE || tmp == CONTROL('G') || tmp == 'q' || tmp == 'Q' + || crawl_state.seen_hups) + { return -1; + } if ((tmp == ' ' || tmp == '\r' || tmp == '\n') && safeanswer) tmp = safeanswer; diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index 69be6e93d3..7d4878c93f 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -3475,6 +3475,16 @@ void show_map( coord_def &spec_place, bool travel_mode ) while (map_alive) { +#if defined(USE_UNIX_SIGNALS) && defined(SIGHUP_SAVE) && defined(USE_CURSES) + // If we've received a HUP signal then the user can't choose a + // location, so indicate this by returning an invalid position. + if (crawl_state.seen_hups) + { + spec_place = coord_def(-1, -1); + return; + } +#endif + start_y = screen_y - half_screen; move_x = move_y = 0; -- cgit v1.2.3