xref: /freebsd/contrib/less/signal.c (revision b00ab754)
1 /*
2  * Copyright (C) 1984-2017  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, see the README file.
8  */
9 
10 /* $FreeBSD$ */
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 extern int quit_on_intr;
37 extern int less_is_more;
38 extern long jump_sline_fraction;
39 
40 /*
41  * Interrupt signal handler.
42  */
43 	/* ARGSUSED*/
44 	static RETSIGTYPE
45 u_interrupt(type)
46 	int type;
47 {
48 	bell();
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(); /* May longjmp */
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 #undef SIG_LESSWINDOW
86 #ifdef SIGWINCH
87 #define SIG_LESSWINDOW SIGWINCH
88 #else
89 #ifdef SIGWIND
90 #define SIG_LESSWINDOW SIGWIND
91 #endif
92 #endif
93 
94 #ifdef SIG_LESSWINDOW
95 /*
96  * "Window" change handler
97  */
98 	/* ARGSUSED*/
99 	public RETSIGTYPE
100 winch(type)
101 	int type;
102 {
103 	LSIGNAL(SIG_LESSWINDOW, winch);
104 	sigs |= S_WINCH;
105 	if (reading)
106 		intread();
107 }
108 #endif
109 
110 #if MSDOS_COMPILER==WIN32C
111 /*
112  * Handle CTRL-C and CTRL-BREAK keys.
113  */
114 #include "windows.h"
115 
116 	static BOOL WINAPI
117 wbreak_handler(dwCtrlType)
118 	DWORD dwCtrlType;
119 {
120 	switch (dwCtrlType)
121 	{
122 	case CTRL_C_EVENT:
123 	case CTRL_BREAK_EVENT:
124 		sigs |= S_INTERRUPT;
125 		return (TRUE);
126 	default:
127 		break;
128 	}
129 	return (FALSE);
130 }
131 #endif
132 
133 	static RETSIGTYPE
134 terminate(type)
135 	int type;
136 {
137 	quit(15);
138 }
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 #ifdef SIGTERM
169 		(void) LSIGNAL(SIGTERM, terminate);
170 #endif
171 	} else
172 	{
173 		/*
174 		 * Restore signals to defaults.
175 		 */
176 		(void) LSIGNAL(SIGINT, SIG_DFL);
177 #if MSDOS_COMPILER==WIN32C
178 		SetConsoleCtrlHandler(wbreak_handler, FALSE);
179 #endif
180 #ifdef SIGTSTP
181 		(void) LSIGNAL(SIGTSTP, SIG_DFL);
182 #endif
183 #ifdef SIGWINCH
184 		(void) LSIGNAL(SIGWINCH, SIG_IGN);
185 #endif
186 #ifdef SIGWIND
187 		(void) LSIGNAL(SIGWIND, SIG_IGN);
188 #endif
189 #ifdef SIGQUIT
190 		(void) LSIGNAL(SIGQUIT, SIG_DFL);
191 #endif
192 #ifdef SIGTERM
193 		(void) LSIGNAL(SIGTERM, SIG_DFL);
194 #endif
195 	}
196 }
197 
198 /*
199  * Process any signals we have received.
200  * A received signal cause a bit to be set in "sigs".
201  */
202 	public void
203 psignals()
204 {
205 	int tsignals;
206 
207 	if ((tsignals = sigs) == 0)
208 		return;
209 	sigs = 0;
210 
211 #ifdef SIGTSTP
212 	if (tsignals & S_STOP)
213 	{
214 		/*
215 		 * Clean up the terminal.
216 		 */
217 #ifdef SIGTTOU
218 		LSIGNAL(SIGTTOU, SIG_IGN);
219 #endif
220 		clear_bot();
221 		deinit();
222 		flush();
223 		raw_mode(0);
224 #ifdef SIGTTOU
225 		LSIGNAL(SIGTTOU, SIG_DFL);
226 #endif
227 		LSIGNAL(SIGTSTP, SIG_DFL);
228 		kill(getpid(), SIGTSTP);
229 		/*
230 		 * ... Bye bye. ...
231 		 * Hopefully we'll be back later and resume here...
232 		 * Reset the terminal and arrange to repaint the
233 		 * screen when we get back to the main command loop.
234 		 */
235 		LSIGNAL(SIGTSTP, stop);
236 		raw_mode(1);
237 		init();
238 		screen_trashed = 1;
239 		tsignals |= S_WINCH;
240 	}
241 #endif
242 #ifdef S_WINCH
243 	if (tsignals & S_WINCH)
244 	{
245 		int old_width, old_height;
246 		/*
247 		 * Re-execute scrsize() to read the new window size.
248 		 */
249 		old_width = sc_width;
250 		old_height = sc_height;
251 		get_term();
252 		if (sc_width != old_width || sc_height != old_height)
253 		{
254 			wscroll = (sc_height + 1) / 2;
255 			calc_jump_sline();
256 			calc_shift_count();
257 			screen_trashed = 1;
258 		}
259 	}
260 #endif
261 	if (tsignals & S_INTERRUPT)
262 	{
263 		if (quit_on_intr)
264 			quit(QUIT_INTERRUPT);
265 	}
266 }
267