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