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