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