1 /*
2 * Copyright (C) 1984-2024 Mark Nudelman
3 *
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Less License, as specified in the README file.
6 *
7 * For more information, see the README file.
8 */
9
10
11 /*
12 * Routines dealing with signals.
13 *
14 * A signal usually merely causes a bit to be set in the "signals" word.
15 * At some convenient time, the mainline code checks to see if any
16 * signals need processing by calling psignal().
17 * If we happen to be reading from a file [in iread()] at the time
18 * the signal is received, we call intread to interrupt the iread.
19 */
20
21 #include "less.h"
22 #include <signal.h>
23
24 /*
25 * "sigs" contains bits indicating signals which need to be processed.
26 */
27 public int sigs;
28
29 extern int sc_width, sc_height;
30 extern int linenums;
31 extern int wscroll;
32 extern int reading;
33 extern int quit_on_intr;
34 extern long jump_sline_fraction;
35
36 /*
37 * Interrupt signal handler.
38 */
39 #if MSDOS_COMPILER!=WIN32C
40 /* ARGSUSED*/
u_interrupt(int type)41 static RETSIGTYPE u_interrupt(int type)
42 {
43 (void) type;
44 bell();
45 #if OS2
46 LSIGNAL(SIGINT, SIG_ACK);
47 #endif
48 LSIGNAL(SIGINT, u_interrupt);
49 sigs |= S_INTERRUPT;
50 #if MSDOS_COMPILER==DJGPPC
51 /*
52 * If a keyboard has been hit, it must be Ctrl-C
53 * (as opposed to Ctrl-Break), so consume it.
54 * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.)
55 */
56 if (kbhit())
57 getkey();
58 #endif
59 #if HILITE_SEARCH
60 set_filter_pattern(NULL, 0);
61 #endif
62 if (reading)
63 intread(); /* May longjmp */
64 }
65 #endif
66
67 #ifdef SIGTSTP
68 /*
69 * "Stop" (^Z) signal handler.
70 */
71 /* ARGSUSED*/
stop(int type)72 static RETSIGTYPE stop(int type)
73 {
74 (void) type;
75 LSIGNAL(SIGTSTP, stop);
76 sigs |= S_STOP;
77 if (reading)
78 intread();
79 }
80 #endif
81
82 #undef SIG_LESSWINDOW
83 #ifdef SIGWINCH
84 #define SIG_LESSWINDOW SIGWINCH
85 #else
86 #ifdef SIGWIND
87 #define SIG_LESSWINDOW SIGWIND
88 #endif
89 #endif
90
91 #ifdef SIG_LESSWINDOW
92 /*
93 * "Window" change handler
94 */
95 /* ARGSUSED*/
winch(int type)96 public RETSIGTYPE winch(int type)
97 {
98 (void) type;
99 LSIGNAL(SIG_LESSWINDOW, winch);
100 sigs |= S_WINCH;
101 if (reading)
102 intread();
103 }
104 #endif
105
106 #if MSDOS_COMPILER==WIN32C
107 /*
108 * Handle CTRL-C and CTRL-BREAK keys.
109 */
110 #define WIN32_LEAN_AND_MEAN
111 #include <windows.h>
112
wbreak_handler(DWORD dwCtrlType)113 static BOOL WINAPI wbreak_handler(DWORD dwCtrlType)
114 {
115 switch (dwCtrlType)
116 {
117 case CTRL_C_EVENT:
118 case CTRL_BREAK_EVENT:
119 sigs |= S_INTERRUPT;
120 #if HILITE_SEARCH
121 set_filter_pattern(NULL, 0);
122 #endif
123 return (TRUE);
124 default:
125 break;
126 }
127 return (FALSE);
128 }
129 #endif
130
terminate(int type)131 static RETSIGTYPE terminate(int type)
132 {
133 (void) type;
134 quit(15);
135 }
136
137 /*
138 * Set up the signal handlers.
139 */
init_signals(int on)140 public void init_signals(int on)
141 {
142 if (on)
143 {
144 /*
145 * Set signal handlers.
146 */
147 #if MSDOS_COMPILER==WIN32C
148 SetConsoleCtrlHandler(wbreak_handler, TRUE);
149 #else
150 (void) LSIGNAL(SIGINT, u_interrupt);
151 #endif
152 #ifdef SIGTSTP
153 (void) LSIGNAL(SIGTSTP, !secure_allow(SF_STOP) ? SIG_IGN : stop);
154 #endif
155 #ifdef SIGWINCH
156 (void) LSIGNAL(SIGWINCH, winch);
157 #endif
158 #ifdef SIGWIND
159 (void) LSIGNAL(SIGWIND, winch);
160 #endif
161 #ifdef SIGQUIT
162 (void) LSIGNAL(SIGQUIT, SIG_IGN);
163 #endif
164 #ifdef SIGTERM
165 (void) LSIGNAL(SIGTERM, terminate);
166 #endif
167 } else
168 {
169 /*
170 * Restore signals to defaults.
171 */
172 #if MSDOS_COMPILER==WIN32C
173 SetConsoleCtrlHandler(wbreak_handler, FALSE);
174 #else
175 (void) LSIGNAL(SIGINT, SIG_DFL);
176 #endif
177 #ifdef SIGTSTP
178 (void) LSIGNAL(SIGTSTP, SIG_DFL);
179 #endif
180 #ifdef SIGWINCH
181 (void) LSIGNAL(SIGWINCH, SIG_IGN);
182 #endif
183 #ifdef SIGWIND
184 (void) LSIGNAL(SIGWIND, SIG_IGN);
185 #endif
186 #ifdef SIGQUIT
187 (void) LSIGNAL(SIGQUIT, SIG_DFL);
188 #endif
189 #ifdef SIGTERM
190 (void) LSIGNAL(SIGTERM, SIG_DFL);
191 #endif
192 }
193 }
194
195 /*
196 * Process any signals we have received.
197 * A received signal cause a bit to be set in "sigs".
198 */
psignals(void)199 public void psignals(void)
200 {
201 int tsignals;
202
203 if ((tsignals = sigs) == 0)
204 return;
205 sigs = 0;
206
207 #ifdef SIGTSTP
208 if (tsignals & S_STOP)
209 {
210 /*
211 * Clean up the terminal.
212 */
213 #ifdef SIGTTOU
214 LSIGNAL(SIGTTOU, SIG_IGN);
215 #endif
216 clear_bot();
217 deinit();
218 flush();
219 raw_mode(0);
220 #ifdef SIGTTOU
221 LSIGNAL(SIGTTOU, SIG_DFL);
222 #endif
223 LSIGNAL(SIGTSTP, SIG_DFL);
224 kill(getpid(), SIGTSTP);
225 /*
226 * ... Bye bye. ...
227 * Hopefully we'll be back later and resume here...
228 * Reset the terminal and arrange to repaint the
229 * screen when we get back to the main command loop.
230 */
231 LSIGNAL(SIGTSTP, stop);
232 raw_mode(1);
233 init();
234 screen_trashed();
235 tsignals |= S_WINCH;
236 }
237 #endif
238 #ifdef S_WINCH
239 if (tsignals & S_WINCH)
240 {
241 int old_width, old_height;
242 /*
243 * Re-execute scrsize() to read the new window size.
244 */
245 old_width = sc_width;
246 old_height = sc_height;
247 get_term();
248 if (sc_width != old_width || sc_height != old_height)
249 {
250 wscroll = (sc_height + 1) / 2;
251 calc_jump_sline();
252 calc_shift_count();
253 calc_match_shift();
254 }
255 screen_trashed();
256 }
257 #endif
258 if (tsignals & S_INTERRUPT)
259 {
260 if (quit_on_intr)
261 quit(QUIT_INTERRUPT);
262 getcc_clear();
263 #if MSDOS_COMPILER==WIN32C
264 win32_getch_clear();
265 #endif
266 }
267 }
268