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