OSDN Git Service

[Fix] 消去時に画面右端までの消去されないことがある
[hengbandforosx/hengbandosx.git] / src / io / signal-handlers.cpp
1 /*!
2  * @file signal-handlers.c
3  * @brief シグナルハンドラの管理 / Controlling signal handlers
4  * @date 2020/02/23
5  * @author Hourier
6  */
7
8 #include "io/signal-handlers.h"
9 #include "cmd-io/cmd-dump.h"
10 #include "core/game-closer.h"
11 #include "floor/floor-events.h"
12 #include "game-option/cheat-options.h"
13 #include "io/write-diary.h"
14 #include "monster-floor/monster-lite.h"
15 #include "save/save.h"
16 #include "system/player-type-definition.h"
17 #include "system/system-variables.h"
18 #include "term/term-color-types.h"
19 #include "world/world.h"
20
21 int16_t signal_count; /* Hack -- Count interupts */
22
23 #include <signal.h>
24
25 /*!
26  * @brief OSからのシグナルを受けてサスペンド状態に入る /
27  * Handle signals -- suspend
28  * @param sig 受け取ったシグナル
29  * @details
30  * Actually suspend the game, and then resume cleanly
31  */
32 static void handle_signal_suspend(int sig)
33 {
34     (void)signal(sig, SIG_IGN);
35 #ifdef SIGSTOP
36     term_fresh();
37     term_xtra(TERM_XTRA_ALIVE, 0);
38     (void)kill(0, SIGSTOP);
39     term_xtra(TERM_XTRA_ALIVE, 1);
40     term_redraw();
41     term_fresh();
42 #endif
43     (void)signal(sig, handle_signal_suspend);
44 }
45
46 /*!
47  * @brief OSからのシグナルを受けて中断、終了する /
48  * Handle signals -- simple (interrupt and quit)
49  * @param sig 受け取ったシグナル
50  * @details
51  * <pre>
52  * This function was causing a *huge* number of problems, so it has
53  * been simplified greatly.  We keep a global variable which counts
54  * the number of times the user attempts to kill the process, and
55  * we commit suicide if the user does this a certain number of times.
56  * We attempt to give "feedback" to the user as he approaches the
57  * suicide thresh-hold, but without penalizing accidental keypresses.
58  * To prevent messy accidents, we should reset this global variable
59  * whenever the user enters a keypress, or something like that.
60  * </pre>
61  * @todo ここにPlayerTypeを追加すると関数ポインタ周りの収拾がつかなくなるので保留
62  */
63 static void handle_signal_simple(int sig)
64 {
65     (void)signal(sig, SIG_IGN);
66     if (!w_ptr->character_generated || w_ptr->character_saved) {
67         quit(nullptr);
68     }
69
70     signal_count++;
71     if (p_ptr->is_dead) {
72         p_ptr->died_from = _("強制終了", "Abortion");
73         forget_lite(p_ptr->current_floor_ptr);
74         forget_view(p_ptr->current_floor_ptr);
75         clear_mon_lite(p_ptr->current_floor_ptr);
76         close_game(p_ptr);
77         quit(_("強制終了", "interrupt"));
78     } else if (signal_count >= 5) {
79         p_ptr->died_from = _("強制終了中", "Interrupting");
80         forget_lite(p_ptr->current_floor_ptr);
81         forget_view(p_ptr->current_floor_ptr);
82         clear_mon_lite(p_ptr->current_floor_ptr);
83         p_ptr->playing = false;
84         if (!cheat_immortal) {
85             p_ptr->is_dead = true;
86         }
87         p_ptr->leaving = true;
88         close_game(p_ptr);
89         quit(_("強制終了", "interrupt"));
90     } else if (signal_count >= 4) {
91         term_xtra(TERM_XTRA_NOISE, 0);
92         term_erase(0, 0);
93         term_putstr(0, 0, -1, TERM_WHITE, _("熟慮の上の自殺!", "Contemplating suicide!"));
94         term_fresh();
95     } else if (signal_count >= 2) {
96         term_xtra(TERM_XTRA_NOISE, 0);
97     }
98
99     (void)signal(sig, handle_signal_simple);
100 }
101
102 /*!
103  * @brief OSからのシグナルを受けて強制終了する /
104  * Handle signal -- abort, kill, etc
105  * @param sig 受け取ったシグナル
106  * @details
107  * <pre>
108  * This function was causing a *huge* number of problems, so it has
109  * been simplified greatly.  We keep a global variable which counts
110  * the number of times the user attempts to kill the process, and
111  * we commit suicide if the user does this a certain number of times.
112  * We attempt to give "feedback" to the user as he approaches the
113  * suicide thresh-hold, but without penalizing accidental keypresses.
114  * To prevent messy accidents, we should reset this global variable
115  * whenever the user enters a keypress, or something like that.
116  * </pre>
117  * @todo ここにp_ptrを追加すると関数ポインタ周りの収拾がつかなくなるので保留
118  */
119 static void handle_signal_abort(int sig)
120 {
121     int wid, hgt;
122     term_get_size(&wid, &hgt);
123
124     (void)signal(sig, SIG_IGN);
125     if (!w_ptr->character_generated || w_ptr->character_saved) {
126         quit(nullptr);
127     }
128
129     forget_lite(p_ptr->current_floor_ptr);
130     forget_view(p_ptr->current_floor_ptr);
131     clear_mon_lite(p_ptr->current_floor_ptr);
132
133     term_erase(0, hgt - 1);
134     term_putstr(0, hgt - 1, -1, TERM_RED, _("恐ろしいソフトのバグが飛びかかってきた!", "A gruesome software bug LEAPS out at you!"));
135
136     term_putstr(45, hgt - 1, -1, TERM_RED, _("緊急セーブ...", "Panic save..."));
137
138     exe_write_diary(p_ptr, DiaryKind::GAMESTART, 0, _("----ゲーム異常終了----", "-- Tried Panic Save and Aborted Game --"));
139     term_fresh();
140
141     p_ptr->panic_save = 1;
142     p_ptr->died_from = _("(緊急セーブ)", "(panic save)");
143
144     signals_ignore_tstp();
145
146     if (save_player(p_ptr, SaveType::CLOSE_GAME)) {
147         term_putstr(45, hgt - 1, -1, TERM_RED, _("緊急セーブ成功!", "Panic save succeeded!"));
148     } else {
149         term_putstr(45, hgt - 1, -1, TERM_RED, _("緊急セーブ失敗!", "Panic save failed!"));
150     }
151
152     term_fresh();
153     quit(_("ソフトのバグ", "software bug"));
154 }
155
156 /*!
157  * @brief OSからのSIGTSTPシグナルを無視する関数 /
158  * Ignore SIGTSTP signals (keyboard suspend)
159  * @details
160  */
161 void signals_ignore_tstp(void)
162 {
163 #ifdef SIGTSTP
164     (void)signal(SIGTSTP, SIG_IGN);
165 #endif
166 }
167
168 /*!
169  * @brief OSからのSIGTSTPシグナルハンドラ /
170  * Handle SIGTSTP signals (keyboard suspend)
171  * @details
172  */
173 void signals_handle_tstp(void)
174 {
175 #ifdef SIGTSTP
176     (void)signal(SIGTSTP, handle_signal_suspend);
177 #endif
178 }
179
180 /*!
181  * @brief OSからのシグナルハンドルを初期化する /
182  * Prepare to handle the relevant signals
183  * @details
184  */
185 void signals_init(void)
186 {
187 #ifdef SIGHUP
188     (void)signal(SIGHUP, SIG_IGN);
189 #endif
190
191 #ifdef SIGTSTP
192     (void)signal(SIGTSTP, handle_signal_suspend);
193 #endif
194
195 #ifdef SIGINT
196     (void)signal(SIGINT, handle_signal_simple);
197 #endif
198
199 #ifdef SIGQUIT
200     (void)signal(SIGQUIT, handle_signal_simple);
201 #endif
202
203 #ifdef SIGFPE
204     (void)signal(SIGFPE, handle_signal_abort);
205 #endif
206
207 #ifdef SIGILL
208     (void)signal(SIGILL, handle_signal_abort);
209 #endif
210
211 #ifdef SIGTRAP
212     (void)signal(SIGTRAP, handle_signal_abort);
213 #endif
214
215 #ifdef SIGIOT
216     (void)signal(SIGIOT, handle_signal_abort);
217 #endif
218
219 #ifdef SIGBUS
220     (void)signal(SIGBUS, handle_signal_abort);
221 #endif
222
223 #ifdef SIGSEGV
224     (void)signal(SIGSEGV, handle_signal_abort);
225 #endif
226
227 #ifdef SIGTERM
228     (void)signal(SIGTERM, handle_signal_abort);
229 #endif
230
231 #ifdef SIGPIPE
232     (void)signal(SIGPIPE, handle_signal_abort);
233 #endif
234
235 #ifdef SIGEMT
236     (void)signal(SIGEMT, handle_signal_abort);
237 #endif
238
239 #ifdef SIGDANGER
240     (void)signal(SIGDANGER, handle_signal_abort);
241 #endif
242
243 #ifdef SIGSYS
244     (void)signal(SIGSYS, handle_signal_abort);
245 #endif
246
247 #ifdef SIGXCPU
248     (void)signal(SIGXCPU, handle_signal_abort);
249 #endif
250
251 #ifdef SIGPWR
252     (void)signal(SIGPWR, handle_signal_abort);
253 #endif
254 }