xref: /dragonfly/contrib/less/signal.c (revision 04277bb2)
1 /*
2  * Copyright (C) 1984-2019  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 
11 /*
12  * Routines dealing with signals.
13  *
14  * A signal usually merely causes a bit to be set in the "signals" word.
15  * At some convenient time, the mainline code checks to see if any
16  * signals need processing by calling psignal().
17  * If we happen to be reading from a file [in iread()] at the time
18  * the signal is received, we call intread to interrupt the iread.
19  */
20 
21 #include "less.h"
22 #include <signal.h>
23 
24 /*
25  * "sigs" contains bits indicating signals which need to be processed.
26  */
27 public int sigs;
28 
29 extern int sc_width, sc_height;
30 extern int screen_trashed;
31 extern int lnloop;
32 extern int linenums;
33 extern int wscroll;
34 extern int reading;
35 extern int quit_on_intr;
36 extern long jump_sline_fraction;
37 
38 /*
39  * Interrupt signal handler.
40  */
41 #if MSDOS_COMPILER!=WIN32C
42 	/* ARGSUSED*/
43 	static RETSIGTYPE
44 u_interrupt(type)
45 	int type;
46 {
47 	bell();
48 #if OS2
49 	LSIGNAL(SIGINT, SIG_ACK);
50 #endif
51 	LSIGNAL(SIGINT, u_interrupt);
52 	sigs |= S_INTERRUPT;
53 #if MSDOS_COMPILER==DJGPPC
54 	/*
55 	 * If a keyboard has been hit, it must be Ctrl-C
56 	 * (as opposed to Ctrl-Break), so consume it.
57 	 * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.)
58 	 */
59 	if (kbhit())
60 		getkey();
61 #endif
62 	if (reading)
63 		intread(); /* May longjmp */
64 }
65 #endif
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 #undef SIG_LESSWINDOW
84 #ifdef SIGWINCH
85 #define SIG_LESSWINDOW SIGWINCH
86 #else
87 #ifdef SIGWIND
88 #define SIG_LESSWINDOW SIGWIND
89 #endif
90 #endif
91 
92 #ifdef SIG_LESSWINDOW
93 /*
94  * "Window" change handler
95  */
96 	/* ARGSUSED*/
97 	public RETSIGTYPE
98 winch(type)
99 	int type;
100 {
101 	LSIGNAL(SIG_LESSWINDOW, winch);
102 	sigs |= S_WINCH;
103 	if (reading)
104 		intread();
105 }
106 #endif
107 
108 #if MSDOS_COMPILER==WIN32C
109 /*
110  * Handle CTRL-C and CTRL-BREAK keys.
111  */
112 #define WIN32_LEAN_AND_MEAN
113 #include <windows.h>
114 
115 	static BOOL WINAPI
116 wbreak_handler(dwCtrlType)
117 	DWORD dwCtrlType;
118 {
119 	switch (dwCtrlType)
120 	{
121 	case CTRL_C_EVENT:
122 	case CTRL_BREAK_EVENT:
123 		sigs |= S_INTERRUPT;
124 		return (TRUE);
125 	default:
126 		break;
127 	}
128 	return (FALSE);
129 }
130 #endif
131 
132 	static RETSIGTYPE
133 terminate(type)
134 	int type;
135 {
136 	quit(15);
137 }
138 
139 /*
140  * Set up the signal handlers.
141  */
142 	public void
143 init_signals(on)
144 	int on;
145 {
146 	if (on)
147 	{
148 		/*
149 		 * Set signal handlers.
150 		 */
151 #if MSDOS_COMPILER==WIN32C
152 		SetConsoleCtrlHandler(wbreak_handler, TRUE);
153 #else
154 		(void) LSIGNAL(SIGINT, u_interrupt);
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 #if MSDOS_COMPILER==WIN32C
177 		SetConsoleCtrlHandler(wbreak_handler, FALSE);
178 #else
179 		(void) LSIGNAL(SIGINT, SIG_DFL);
180 #endif
181 #ifdef SIGTSTP
182 		(void) LSIGNAL(SIGTSTP, SIG_DFL);
183 #endif
184 #ifdef SIGWINCH
185 		(void) LSIGNAL(SIGWINCH, SIG_IGN);
186 #endif
187 #ifdef SIGWIND
188 		(void) LSIGNAL(SIGWIND, SIG_IGN);
189 #endif
190 #ifdef SIGQUIT
191 		(void) LSIGNAL(SIGQUIT, SIG_DFL);
192 #endif
193 #ifdef SIGTERM
194 		(void) LSIGNAL(SIGTERM, SIG_DFL);
195 #endif
196 	}
197 }
198 
199 /*
200  * Process any signals we have received.
201  * A received signal cause a bit to be set in "sigs".
202  */
203 	public void
204 psignals(VOID_PARAM)
205 {
206 	int tsignals;
207 
208 	if ((tsignals = sigs) == 0)
209 		return;
210 	sigs = 0;
211 
212 #ifdef SIGTSTP
213 	if (tsignals & S_STOP)
214 	{
215 		/*
216 		 * Clean up the terminal.
217 		 */
218 #ifdef SIGTTOU
219 		LSIGNAL(SIGTTOU, SIG_IGN);
220 #endif
221 		clear_bot();
222 		deinit();
223 		flush();
224 		raw_mode(0);
225 #ifdef SIGTTOU
226 		LSIGNAL(SIGTTOU, SIG_DFL);
227 #endif
228 		LSIGNAL(SIGTSTP, SIG_DFL);
229 		kill(getpid(), SIGTSTP);
230 		/*
231 		 * ... Bye bye. ...
232 		 * Hopefully we'll be back later and resume here...
233 		 * Reset the terminal and arrange to repaint the
234 		 * screen when we get back to the main command loop.
235 		 */
236 		LSIGNAL(SIGTSTP, stop);
237 		raw_mode(1);
238 		init();
239 		screen_trashed = 1;
240 		tsignals |= S_WINCH;
241 	}
242 #endif
243 #ifdef S_WINCH
244 	if (tsignals & S_WINCH)
245 	{
246 		int old_width, old_height;
247 		/*
248 		 * Re-execute scrsize() to read the new window size.
249 		 */
250 		old_width = sc_width;
251 		old_height = sc_height;
252 		get_term();
253 		if (sc_width != old_width || sc_height != old_height)
254 		{
255 			wscroll = (sc_height + 1) / 2;
256 			calc_jump_sline();
257 			calc_shift_count();
258 		}
259 		screen_trashed = 1;
260 	}
261 #endif
262 	if (tsignals & S_INTERRUPT)
263 	{
264 		if (quit_on_intr)
265 			quit(QUIT_INTERRUPT);
266 	}
267 }
268