xref: /freebsd/contrib/less/signal.c (revision 0c927cdd8e6e05387fc5a9ffcb5dbe128d4ad749)
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 }
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 #endif
160 #ifdef SIGWIND
161 		(void) LSIGNAL(SIGWIND, winch);
162 #endif
163 #ifdef SIGQUIT
164 		(void) LSIGNAL(SIGQUIT, SIG_IGN);
165 #endif
166 	} else
167 	{
168 		/*
169 		 * Restore signals to defaults.
170 		 */
171 		(void) LSIGNAL(SIGINT, SIG_DFL);
172 #if MSDOS_COMPILER==WIN32C
173 		SetConsoleCtrlHandler(wbreak_handler, FALSE);
174 #endif
175 #ifdef SIGTSTP
176 		(void) LSIGNAL(SIGTSTP, SIG_DFL);
177 #endif
178 #ifdef SIGWINCH
179 		(void) LSIGNAL(SIGWINCH, SIG_IGN);
180 #endif
181 #ifdef SIGWIND
182 		(void) LSIGNAL(SIGWIND, SIG_IGN);
183 #endif
184 #ifdef SIGQUIT
185 		(void) LSIGNAL(SIGQUIT, SIG_DFL);
186 #endif
187 	}
188 }
189 
190 /*
191  * Process any signals we have received.
192  * A received signal cause a bit to be set in "sigs".
193  */
194 	public void
195 psignals()
196 {
197 	register int tsignals;
198 
199 	if ((tsignals = sigs) == 0)
200 		return;
201 	sigs = 0;
202 
203 #ifdef SIGTSTP
204 	if (tsignals & S_STOP)
205 	{
206 		/*
207 		 * Clean up the terminal.
208 		 */
209 #ifdef SIGTTOU
210 		LSIGNAL(SIGTTOU, SIG_IGN);
211 #endif
212 		clear_bot();
213 		deinit();
214 		flush();
215 		raw_mode(0);
216 #ifdef SIGTTOU
217 		LSIGNAL(SIGTTOU, SIG_DFL);
218 #endif
219 		LSIGNAL(SIGTSTP, SIG_DFL);
220 		kill(getpid(), SIGTSTP);
221 		/*
222 		 * ... Bye bye. ...
223 		 * Hopefully we'll be back later and resume here...
224 		 * Reset the terminal and arrange to repaint the
225 		 * screen when we get back to the main command loop.
226 		 */
227 		LSIGNAL(SIGTSTP, stop);
228 		raw_mode(1);
229 		init();
230 		screen_trashed = 1;
231 		tsignals |= S_WINCH;
232 	}
233 #endif
234 #ifdef S_WINCH
235 	if (tsignals & S_WINCH)
236 	{
237 		int old_width, old_height;
238 		/*
239 		 * Re-execute scrsize() to read the new window size.
240 		 */
241 		old_width = sc_width;
242 		old_height = sc_height;
243 		get_term();
244 		if (sc_width != old_width || sc_height != old_height)
245 		{
246 			wscroll = (sc_height + 1) / 2;
247 			calc_jump_sline();
248 			screen_trashed = 1;
249 		}
250 	}
251 #endif
252 	if (tsignals & S_INTERRUPT)
253 	{
254 		if (quit_on_intr)
255 			quit(QUIT_OK);
256 		bell();
257 		/*
258 		 * {{ You may wish to replace the bell() with
259 		 *    error("Interrupt", NULL_PARG); }}
260 		 */
261 
262 		/*
263 		 * If we were interrupted while in the "calculating
264 		 * line numbers" loop, turn off line numbers.
265 		 */
266 		if (lnloop)
267 		{
268 			lnloop = 0;
269 			if (linenums == 2)
270 				screen_trashed = 1;
271 			linenums = 0;
272 			error("Line numbers turned off", NULL_PARG);
273 		}
274 
275 	}
276 }
277