1
0
mirror of https://git.zap.org.au/git/trader.git synced 2024-07-21 16:14:14 -04:00

Rework the signal handler

Rework the signal handler to be somewhat more unsafe, but conceptually
cleaner, in operation.  It now ends the use of Curses, then reraises the
signal.  Remove almost all references to abort_game.
This commit is contained in:
John Zaitseff 2011-08-09 23:20:56 +10:00
parent 5f995f1d36
commit 040e1a5ad6
9 changed files with 45 additions and 133 deletions

View File

@ -211,9 +211,6 @@ void exchange_stock (void)
break;
default:
if (abort_game)
return;
beep();
}
}
@ -259,9 +256,6 @@ void visit_bank (void)
char *buf;
if (abort_game)
return;
buf = malloc(BUFSIZE);
if (buf == NULL) {
err_exit_nomem();
@ -334,9 +328,6 @@ void visit_bank (void)
break;
default:
if (abort_game)
return;
beep();
}
}
@ -491,9 +482,6 @@ void trade_shares (int num, bool *bid_used)
char *buf;
if (abort_game)
return;
assert(num >= 0 && num < MAX_COMPANIES);
assert(company[num].on_map);
@ -593,9 +581,6 @@ void trade_shares (int num, bool *bid_used)
break;
default:
if (abort_game)
return;
beep();
}
}

View File

@ -126,9 +126,6 @@ void init_game (void)
while (number_players == 0) {
int choice = ask_number_players();
if (abort_game)
return;
if (choice == ERR) {
abort_game = true;
return;
@ -136,9 +133,6 @@ void init_game (void)
} else if (choice == 0) {
choice = ask_game_number();
if (abort_game)
return;
if (choice != ERR) {
game_num = choice;
@ -168,9 +162,6 @@ void init_game (void)
ask_player_names();
if (abort_game)
return;
deltxwin(); // "Number of players" window
txrefresh();
@ -230,6 +221,7 @@ void init_game (void)
}
quit_selected = false;
abort_game = false;
}
@ -285,9 +277,6 @@ static int ask_number_players (void)
break;
default:
if (abort_game)
return ERR;
beep();
}
}
@ -344,9 +333,6 @@ int ask_game_number (void)
break;
default:
if (abort_game)
return ERR;
beep();
}
}
@ -362,9 +348,6 @@ int ask_game_number (void)
void ask_player_names (void)
{
if (abort_game)
return;
if (number_players == 1) {
// Ask for the player's name
@ -379,9 +362,6 @@ void ask_player_names (void)
while (true) {
int ret = gettxstr(curwin, &player[0].name, NULL, false,
2, x, w, attr_input_field);
if (abort_game)
return;
if (ret == OK && strlen(player[0].name) != 0) {
break;
} else {
@ -391,7 +371,7 @@ void ask_player_names (void)
newtxwin(5, 44, 6, WCENTER, true, attr_normal_window);
mvwaddstr(curwin, 2, 2, "Do you need any instructions?");
if (answer_yesno(curwin, attr_keycode) == true) {
if (answer_yesno(curwin, attr_keycode)) {
show_help();
}
@ -452,9 +432,6 @@ void ask_player_names (void)
break;
case ERR:
if (abort_game)
return;
beep();
break;
@ -491,7 +468,7 @@ void ask_player_names (void)
newtxwin(5, 50, 6, WCENTER, true, attr_normal_window);
mvwaddstr(curwin, 2, 2, "Does any player need instructions?");
if (answer_yesno(curwin, attr_keycode) == true) {
if (answer_yesno(curwin, attr_keycode)) {
show_help();
}
}
@ -510,8 +487,10 @@ void end_game (void)
char *buf;
if (abort_game)
if (abort_game) {
// init_game() was cancelled by user
return;
}
buf = malloc(BUFSIZE);
if (buf == NULL) {
@ -531,9 +510,6 @@ void end_game (void)
show_status(i);
}
if (abort_game)
return;
if (number_players == 1) {
l_strfmon(buf, BUFSIZE, "%1n", total_value(0));
@ -595,9 +571,6 @@ void show_map (bool closewin)
int n, x, y;
if (abort_game)
return;
newtxwin(MAX_Y + 4, WIN_COLS, 1, WCENTER, true, attr_map_window);
// Draw various borders
@ -697,9 +670,6 @@ void show_status (int num)
int i, line;
if (abort_game)
return;
assert(num >= 0 && num < number_players);
newtxwin(MAX_COMPANIES + 15, WIN_COLS, 1, WCENTER, true,

View File

@ -84,13 +84,12 @@ bool game_loaded = false; // True if game was loaded from disk
int game_num = 0; // Game number (1-9)
bool quit_selected = false; // Is a player trying to quit the game?
bool abort_game = false; // Abort game without declaring winner?
bool option_no_color = false; // True if --no-color was specified
bool option_dont_encrypt = false; // True if --dont-encrypt was specified
int option_max_turn = 0; // Max. turns if --max-turn was specified
volatile sig_atomic_t abort_game = false; // Abort game as quickly as possible?
/***********************************************************************/
// End of file

View File

@ -33,7 +33,6 @@
#include <stdbool.h>
#include <signal.h>
/************************************************************************
@ -196,12 +195,11 @@ extern bool game_loaded; // True if game was loaded from disk
extern int game_num; // Game number (1-9)
extern bool quit_selected; // Is a player trying to quit the game?
extern bool abort_game; // Abort game without declaring winner?
extern bool option_no_color; // True if --no-color was specified
extern bool option_dont_encrypt; // True if --dont-encrypt was specified
extern int option_max_turn; // Max. turns if --max-turn was specified
extern volatile sig_atomic_t abort_game; // Abort game as quickly as possible?
#endif /* included_GLOBALS_H */

View File

@ -162,9 +162,6 @@ void show_help (void)
bool done = false;
if (abort_game)
return;
// Count how many pages appear in the help text
for (numpages = 0; help_text[numpages] != NULL; numpages++)
;
@ -359,9 +356,6 @@ void show_help (void)
break;
default:
if (abort_game)
return;
curpage++;
done = (curpage == numpages);
}

View File

@ -112,8 +112,9 @@ static void init_title (void);
Parameters: sig - Signal number
Returns: (nothing)
This function handles termination signals (like SIGINT and SIGTERM) by
setting the global variable abort_game to true.
This function handles termination signals (like SIGINT, SIGTERM and
SIGQUIT) by clearing the screen, uninstalling itself and reraising the
signal.
*/
static void sigterm_handler (int sig);
@ -163,6 +164,9 @@ void init_screen (void)
if (sigaction(SIGTERM, &sa, NULL) == -1) {
errno_exit("sigaction(SIGTERM)");
}
if (sigaction(SIGQUIT, &sa, NULL) == -1) {
errno_exit("sigaction(SIGQUIT)");
}
// Initialise the screen
initscr();
@ -312,13 +316,26 @@ void init_title (void)
void sigterm_handler (int sig)
{
/* Note that sigterm_handler() simply sets a volatile variable
instead of directly terminating, as functions like endwin() and
end_screen() are NOT reentrant. A side-effect of doing this,
however, is that the main program needs to have abort_game checks
scattered all over it. */
struct sigaction sa;
abort_game = true;
/* The following Curses functions are NOT async-signal-safe (ie, are
not reentrant) as they may well call malloc() or free(). However,
it does allow us to terminate with the correct signal without
having convoluted code in the main program. */
curs_set(CURS_ON);
clear();
refresh();
endwin();
// Reraise the same signal, using the system-default handler
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = SIG_DFL;
sigaction(sig, &sa, NULL);
raise(sig);
}
@ -705,10 +722,8 @@ int gettxline (WINDOW *win, char *buf, int bufsize, bool *restrict modified,
key = wgetch(win);
if (key == ERR) {
if (abort_game) {
ret = ERR;
done = true;
}
// Do nothing on ERR
;
} else if ((key == KEY_DEFAULTVAL1 || key == KEY_DEFAULTVAL2)
&& defaultval != NULL && len == 0) {
// Initialise buffer with the default value
@ -1512,7 +1527,7 @@ int gettxlong (WINDOW *win, long int *restrict result, long int min,
/***********************************************************************/
// answer_yesno: Wait for a Yes/No answer
int answer_yesno (WINDOW *win, chtype attr_keys)
bool answer_yesno (WINDOW *win, chtype attr_keys)
{
int key;
bool done;
@ -1539,8 +1554,6 @@ int answer_yesno (WINDOW *win, chtype attr_keys)
if (key == 'Y' || key == 'N') {
done = true;
} else if (abort_game) {
return ERR;
} else {
beep();
}

View File

@ -534,17 +534,16 @@ extern int gettxlong (WINDOW *win, long int *restrict result, long int min,
Function: answer_yesno - Wait for a Yes/No answer
Parameters: win - Window to use (should be curwin)
attr_keys - Window rendition to use for key choices
Returns: int - 1 if Yes was selected, 0 if No, ERR if error
Returns: bool - True if Yes was selected, false if No
This function prompts the user by printing " [Y/N] " using appropriate
character renditions ("Y" and "N" in attr_keys, the rest in the current
rendition), then waits for the user to press either "Y" (for Yes) or
"N" (for No) on the keyboard, then prints the answer using A_BOLD. If
"Y" was selected, 1 is returned, if "N", 0 is returned. ERR is
returned if abort_game becomes true. Note that the cursor becomes
invisible after calling this function.
"N" (for No) on the keyboard, then prints the answer using A_BOLD.
True is returned if "Y" was selected, false if "N". Note that the
cursor becomes invisible after calling this function.
*/
extern int answer_yesno (WINDOW *win, chtype attr_keys);
extern bool answer_yesno (WINDOW *win, chtype attr_keys);
/*

View File

@ -159,9 +159,6 @@ void select_moves (void)
bool unique;
if (abort_game)
return;
// How many empty spaces are there in the galaxy map?
count = 0;
for (x = 0; x < MAX_X; x++) {
@ -321,9 +318,6 @@ selection_t get_move (void)
break;
default:
if (abort_game)
return SEL_QUIT;
beep();
}
}
@ -341,13 +335,10 @@ selection_t get_move (void)
// Ask the player to confirm their choice
mvwaddstr(curwin, 2, 22, "Are you sure?");
if (answer_yesno(curwin, attr_keycode) != true) {
if (! answer_yesno(curwin, attr_keycode)) {
selection = SEL_NONE;
}
if (abort_game)
return SEL_QUIT;
// Save the game if required
if (selection == SEL_SAVE) {
bool saved = false;
@ -406,9 +397,6 @@ selection_t get_move (void)
break;
default:
if (abort_game)
return SEL_QUIT;
beep();
}
}
@ -456,13 +444,12 @@ selection_t get_move (void)
void process_move (selection_t selection)
{
if (abort_game)
return;
if (selection == SEL_QUIT) {
// The players want to end the game
quit_selected = true;
}
if (quit_selected || abort_game) {
deltxwin(); // "Select move" window
deltxwin(); // Galaxy map window
txrefresh();
@ -508,9 +495,6 @@ void process_move (selection_t selection)
assign_vals(x, y, left, right, up, down);
}
if (abort_game)
return;
if (IS_MAP_COMPANY(left) && IS_MAP_COMPANY(up)
&& left != up) {
galaxy_map[x][y] = left;
@ -518,9 +502,6 @@ void process_move (selection_t selection)
assign_vals(x, y, left, right, up, down);
}
if (abort_game)
return;
if (IS_MAP_COMPANY(left) && IS_MAP_COMPANY(down)
&& left != down) {
galaxy_map[x][y] = left;
@ -528,9 +509,6 @@ void process_move (selection_t selection)
assign_vals(x, y, left, right, up, down);
}
if (abort_game)
return;
if (IS_MAP_COMPANY(right) && IS_MAP_COMPANY(up)
&& right != up) {
galaxy_map[x][y] = right;
@ -538,9 +516,6 @@ void process_move (selection_t selection)
assign_vals(x, y, left, right, up, down);
}
if (abort_game)
return;
if (IS_MAP_COMPANY(right) && IS_MAP_COMPANY(down)
&& right != down) {
galaxy_map[x][y] = right;
@ -548,9 +523,6 @@ void process_move (selection_t selection)
assign_vals(x, y, left, right, up, down);
}
if (abort_game)
return;
if (IS_MAP_COMPANY(up) && IS_MAP_COMPANY(down)
&& up != down) {
galaxy_map[x][y] = up;
@ -559,9 +531,6 @@ void process_move (selection_t selection)
}
}
if (abort_game)
return;
// See if an existing company can be expanded
nearby = (IS_MAP_COMPANY(left) ? left :
(IS_MAP_COMPANY(right) ? right :
@ -627,9 +596,6 @@ void next_player (void)
bool all_out;
if (abort_game)
return;
all_out = true;
for (i = 0; i < number_players; i++) {
if (player[i].in_game) {
@ -670,9 +636,6 @@ void bankrupt_player (bool forced)
int i;
if (abort_game)
return;
/* It would be nice if we had functions that would do word-wrapping
for us automatically! */
@ -827,9 +790,6 @@ void merge_companies (map_val_t a, map_val_t b)
char *buf;
if (abort_game)
return;
buf = malloc(BUFSIZE);
if (buf == NULL) {
err_exit_nomem();
@ -992,9 +952,6 @@ void adjust_values (void)
int which;
if (abort_game)
return;
// Declare a company bankrupt!
if (randf() > (1.0 - COMPANY_BANKRUPTCY)) {
which = randi(MAX_COMPANIES);
@ -1128,9 +1085,6 @@ void adjust_values (void)
interest_rate /= randf() + INTEREST_RATE_DIVIDER;
}
if (abort_game)
return;
// Calculate current player's debt
player[current_player].debt *= interest_rate + 1.0;

View File

@ -180,7 +180,7 @@ int main (int argc, char *argv[])
// Finish up...
end_program();
return abort_game ? EXIT_FAILURE : EXIT_SUCCESS;
return EXIT_SUCCESS;
}