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