1
0
mirror of https://git.zap.org.au/git/trader.git synced 2024-10-27 18:20:13 -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; break;
default: default:
if (abort_game)
return;
beep(); beep();
} }
} }
@ -259,9 +256,6 @@ void visit_bank (void)
char *buf; char *buf;
if (abort_game)
return;
buf = malloc(BUFSIZE); buf = malloc(BUFSIZE);
if (buf == NULL) { if (buf == NULL) {
err_exit_nomem(); err_exit_nomem();
@ -334,9 +328,6 @@ void visit_bank (void)
break; break;
default: default:
if (abort_game)
return;
beep(); beep();
} }
} }
@ -491,9 +482,6 @@ void trade_shares (int num, bool *bid_used)
char *buf; char *buf;
if (abort_game)
return;
assert(num >= 0 && num < MAX_COMPANIES); assert(num >= 0 && num < MAX_COMPANIES);
assert(company[num].on_map); assert(company[num].on_map);
@ -593,9 +581,6 @@ void trade_shares (int num, bool *bid_used)
break; break;
default: default:
if (abort_game)
return;
beep(); beep();
} }
} }

View File

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

View File

@ -33,7 +33,6 @@
#include <stdbool.h> #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 int game_num; // Game number (1-9)
extern bool quit_selected; // Is a player trying to quit the game? 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_no_color; // True if --no-color was specified
extern bool option_dont_encrypt; // True if --dont-encrypt 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 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 */ #endif /* included_GLOBALS_H */

View File

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

View File

@ -112,8 +112,9 @@ static void init_title (void);
Parameters: sig - Signal number Parameters: sig - Signal number
Returns: (nothing) Returns: (nothing)
This function handles termination signals (like SIGINT and SIGTERM) by This function handles termination signals (like SIGINT, SIGTERM and
setting the global variable abort_game to true. SIGQUIT) by clearing the screen, uninstalling itself and reraising the
signal.
*/ */
static void sigterm_handler (int sig); static void sigterm_handler (int sig);
@ -163,6 +164,9 @@ void init_screen (void)
if (sigaction(SIGTERM, &sa, NULL) == -1) { if (sigaction(SIGTERM, &sa, NULL) == -1) {
errno_exit("sigaction(SIGTERM)"); errno_exit("sigaction(SIGTERM)");
} }
if (sigaction(SIGQUIT, &sa, NULL) == -1) {
errno_exit("sigaction(SIGQUIT)");
}
// Initialise the screen // Initialise the screen
initscr(); initscr();
@ -312,13 +316,26 @@ void init_title (void)
void sigterm_handler (int sig) void sigterm_handler (int sig)
{ {
/* Note that sigterm_handler() simply sets a volatile variable struct sigaction sa;
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. */
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); key = wgetch(win);
if (key == ERR) { if (key == ERR) {
if (abort_game) { // Do nothing on ERR
ret = ERR; ;
done = true;
}
} else if ((key == KEY_DEFAULTVAL1 || key == KEY_DEFAULTVAL2) } else if ((key == KEY_DEFAULTVAL1 || key == KEY_DEFAULTVAL2)
&& defaultval != NULL && len == 0) { && defaultval != NULL && len == 0) {
// Initialise buffer with the default value // 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 // 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; int key;
bool done; bool done;
@ -1539,8 +1554,6 @@ int answer_yesno (WINDOW *win, chtype attr_keys)
if (key == 'Y' || key == 'N') { if (key == 'Y' || key == 'N') {
done = true; done = true;
} else if (abort_game) {
return ERR;
} else { } else {
beep(); 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 Function: answer_yesno - Wait for a Yes/No answer
Parameters: win - Window to use (should be curwin) Parameters: win - Window to use (should be curwin)
attr_keys - Window rendition to use for key choices 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 This function prompts the user by printing " [Y/N] " using appropriate
character renditions ("Y" and "N" in attr_keys, the rest in the current 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 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 "N" (for No) on the keyboard, then prints the answer using A_BOLD.
"Y" was selected, 1 is returned, if "N", 0 is returned. ERR is True is returned if "Y" was selected, false if "N". Note that the
returned if abort_game becomes true. Note that the cursor becomes cursor becomes invisible after calling this function.
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; bool unique;
if (abort_game)
return;
// How many empty spaces are there in the galaxy map? // How many empty spaces are there in the galaxy map?
count = 0; count = 0;
for (x = 0; x < MAX_X; x++) { for (x = 0; x < MAX_X; x++) {
@ -321,9 +318,6 @@ selection_t get_move (void)
break; break;
default: default:
if (abort_game)
return SEL_QUIT;
beep(); beep();
} }
} }
@ -341,13 +335,10 @@ selection_t get_move (void)
// Ask the player to confirm their choice // Ask the player to confirm their choice
mvwaddstr(curwin, 2, 22, "Are you sure?"); mvwaddstr(curwin, 2, 22, "Are you sure?");
if (answer_yesno(curwin, attr_keycode) != true) { if (! answer_yesno(curwin, attr_keycode)) {
selection = SEL_NONE; selection = SEL_NONE;
} }
if (abort_game)
return SEL_QUIT;
// Save the game if required // Save the game if required
if (selection == SEL_SAVE) { if (selection == SEL_SAVE) {
bool saved = false; bool saved = false;
@ -406,9 +397,6 @@ selection_t get_move (void)
break; break;
default: default:
if (abort_game)
return SEL_QUIT;
beep(); beep();
} }
} }
@ -456,13 +444,12 @@ selection_t get_move (void)
void process_move (selection_t selection) void process_move (selection_t selection)
{ {
if (abort_game)
return;
if (selection == SEL_QUIT) { if (selection == SEL_QUIT) {
// The players want to end the game // The players want to end the game
quit_selected = true; quit_selected = true;
}
if (quit_selected || abort_game) {
deltxwin(); // "Select move" window deltxwin(); // "Select move" window
deltxwin(); // Galaxy map window deltxwin(); // Galaxy map window
txrefresh(); txrefresh();
@ -508,9 +495,6 @@ void process_move (selection_t selection)
assign_vals(x, y, left, right, up, down); assign_vals(x, y, left, right, up, down);
} }
if (abort_game)
return;
if (IS_MAP_COMPANY(left) && IS_MAP_COMPANY(up) if (IS_MAP_COMPANY(left) && IS_MAP_COMPANY(up)
&& left != up) { && left != up) {
galaxy_map[x][y] = left; galaxy_map[x][y] = left;
@ -518,9 +502,6 @@ void process_move (selection_t selection)
assign_vals(x, y, left, right, up, down); assign_vals(x, y, left, right, up, down);
} }
if (abort_game)
return;
if (IS_MAP_COMPANY(left) && IS_MAP_COMPANY(down) if (IS_MAP_COMPANY(left) && IS_MAP_COMPANY(down)
&& left != down) { && left != down) {
galaxy_map[x][y] = left; galaxy_map[x][y] = left;
@ -528,9 +509,6 @@ void process_move (selection_t selection)
assign_vals(x, y, left, right, up, down); assign_vals(x, y, left, right, up, down);
} }
if (abort_game)
return;
if (IS_MAP_COMPANY(right) && IS_MAP_COMPANY(up) if (IS_MAP_COMPANY(right) && IS_MAP_COMPANY(up)
&& right != up) { && right != up) {
galaxy_map[x][y] = right; galaxy_map[x][y] = right;
@ -538,9 +516,6 @@ void process_move (selection_t selection)
assign_vals(x, y, left, right, up, down); assign_vals(x, y, left, right, up, down);
} }
if (abort_game)
return;
if (IS_MAP_COMPANY(right) && IS_MAP_COMPANY(down) if (IS_MAP_COMPANY(right) && IS_MAP_COMPANY(down)
&& right != down) { && right != down) {
galaxy_map[x][y] = right; galaxy_map[x][y] = right;
@ -548,9 +523,6 @@ void process_move (selection_t selection)
assign_vals(x, y, left, right, up, down); assign_vals(x, y, left, right, up, down);
} }
if (abort_game)
return;
if (IS_MAP_COMPANY(up) && IS_MAP_COMPANY(down) if (IS_MAP_COMPANY(up) && IS_MAP_COMPANY(down)
&& up != down) { && up != down) {
galaxy_map[x][y] = up; 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 // See if an existing company can be expanded
nearby = (IS_MAP_COMPANY(left) ? left : nearby = (IS_MAP_COMPANY(left) ? left :
(IS_MAP_COMPANY(right) ? right : (IS_MAP_COMPANY(right) ? right :
@ -627,9 +596,6 @@ void next_player (void)
bool all_out; bool all_out;
if (abort_game)
return;
all_out = true; all_out = true;
for (i = 0; i < number_players; i++) { for (i = 0; i < number_players; i++) {
if (player[i].in_game) { if (player[i].in_game) {
@ -670,9 +636,6 @@ void bankrupt_player (bool forced)
int i; int i;
if (abort_game)
return;
/* It would be nice if we had functions that would do word-wrapping /* It would be nice if we had functions that would do word-wrapping
for us automatically! */ for us automatically! */
@ -827,9 +790,6 @@ void merge_companies (map_val_t a, map_val_t b)
char *buf; char *buf;
if (abort_game)
return;
buf = malloc(BUFSIZE); buf = malloc(BUFSIZE);
if (buf == NULL) { if (buf == NULL) {
err_exit_nomem(); err_exit_nomem();
@ -992,9 +952,6 @@ void adjust_values (void)
int which; int which;
if (abort_game)
return;
// Declare a company bankrupt! // Declare a company bankrupt!
if (randf() > (1.0 - COMPANY_BANKRUPTCY)) { if (randf() > (1.0 - COMPANY_BANKRUPTCY)) {
which = randi(MAX_COMPANIES); which = randi(MAX_COMPANIES);
@ -1128,9 +1085,6 @@ void adjust_values (void)
interest_rate /= randf() + INTEREST_RATE_DIVIDER; interest_rate /= randf() + INTEREST_RATE_DIVIDER;
} }
if (abort_game)
return;
// Calculate current player's debt // Calculate current player's debt
player[current_player].debt *= interest_rate + 1.0; player[current_player].debt *= interest_rate + 1.0;

View File

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