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