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