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