xref: /freebsd/contrib/less/signal.c (revision f0a75d274af375d15b97b830966b99a02b7db911)
1 /*
2  * Copyright (C) 1984-2004  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 more_mode;
39 
40 /*
41  * Interrupt signal handler.
42  */
43 	/* ARGSUSED*/
44 	static RETSIGTYPE
45 u_interrupt(type)
46 	int type;
47 {
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 (more_mode)
63 		quit(0);
64 	if (reading)
65 		intread();
66 }
67 
68 #ifdef SIGTSTP
69 /*
70  * "Stop" (^Z) signal handler.
71  */
72 	/* ARGSUSED*/
73 	static RETSIGTYPE
74 stop(type)
75 	int type;
76 {
77 	LSIGNAL(SIGTSTP, stop);
78 	sigs |= S_STOP;
79 	if (reading)
80 		intread();
81 }
82 #endif
83 
84 #ifdef SIGWINCH
85 /*
86  * "Window" change handler
87  */
88 	/* ARGSUSED*/
89 	public RETSIGTYPE
90 winch(type)
91 	int type;
92 {
93 	LSIGNAL(SIGWINCH, winch);
94 	sigs |= S_WINCH;
95 	if (reading)
96 		intread();
97 }
98 #else
99 #ifdef SIGWIND
100 /*
101  * "Window" change handler
102  */
103 	/* ARGSUSED*/
104 	public RETSIGTYPE
105 winch(type)
106 	int type;
107 {
108 	LSIGNAL(SIGWIND, winch);
109 	sigs |= S_WINCH;
110 	if (reading)
111 		intread();
112 }
113 #endif
114 #endif
115 
116 #if MSDOS_COMPILER==WIN32C
117 /*
118  * Handle CTRL-C and CTRL-BREAK keys.
119  */
120 #include "windows.h"
121 
122 	static BOOL WINAPI
123 wbreak_handler(dwCtrlType)
124 	DWORD dwCtrlType;
125 {
126 	switch (dwCtrlType)
127 	{
128 	case CTRL_C_EVENT:
129 	case CTRL_BREAK_EVENT:
130 		sigs |= S_INTERRUPT;
131 		return (TRUE);
132 	default:
133 		break;
134 	}
135 	return (FALSE);
136 }
137 #endif
138 
139 /*
140  * Set up the signal handlers.
141  */
142 	public void
143 init_signals(on)
144 	int on;
145 {
146 	if (on)
147 	{
148 		/*
149 		 * Set signal handlers.
150 		 */
151 		(void) LSIGNAL(SIGINT, u_interrupt);
152 #if MSDOS_COMPILER==WIN32C
153 		SetConsoleCtrlHandler(wbreak_handler, TRUE);
154 #endif
155 #ifdef SIGTSTP
156 		(void) LSIGNAL(SIGTSTP, stop);
157 #endif
158 #ifdef SIGWINCH
159 		(void) LSIGNAL(SIGWINCH, winch);
160 #else
161 #ifdef SIGWIND
162 		(void) LSIGNAL(SIGWIND, winch);
163 #endif
164 #ifdef SIGQUIT
165 		(void) LSIGNAL(SIGQUIT, SIG_IGN);
166 #endif
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 			screen_trashed = 1;
250 		}
251 	}
252 #endif
253 	if (tsignals & S_INTERRUPT)
254 	{
255 		if (quit_on_intr)
256 			quit(QUIT_OK);
257 		bell();
258 		/*
259 		 * {{ You may wish to replace the bell() with
260 		 *    error("Interrupt", NULL_PARG); }}
261 		 */
262 
263 		/*
264 		 * If we were interrupted while in the "calculating
265 		 * line numbers" loop, turn off line numbers.
266 		 */
267 		if (lnloop)
268 		{
269 			lnloop = 0;
270 			if (linenums == 2)
271 				screen_trashed = 1;
272 			linenums = 0;
273 			error("Line numbers turned off", NULL_PARG);
274 		}
275 
276 	}
277 }
278