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