xref: /dflybsd-src/contrib/less/signal.c (revision ce0bf054ae24dd51413cc9a1106d8b3043c98ef4)
1 /*
2  * Copyright (C) 1984-2023  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 u_interrupt(int type)
45 {
46 	bell();
47 #if OS2
48 	LSIGNAL(SIGINT, SIG_ACK);
49 #endif
50 	LSIGNAL(SIGINT, u_interrupt);
51 	sigs |= S_INTERRUPT;
52 #if MSDOS_COMPILER==DJGPPC
53 	/*
54 	 * If a keyboard has been hit, it must be Ctrl-C
55 	 * (as opposed to Ctrl-Break), so consume it.
56 	 * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.)
57 	 */
58 	if (kbhit())
59 		getkey();
60 #endif
61 #if HILITE_SEARCH
62 	set_filter_pattern(NULL, 0);
63 #endif
64 	if (reading)
65 		intread(); /* May longjmp */
66 }
67 #endif
68 
69 #ifdef SIGTSTP
70 /*
71  * "Stop" (^Z) signal handler.
72  */
73 	/* ARGSUSED*/
74 static RETSIGTYPE stop(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 winch(int type)
98 {
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 	quit(15);
134 }
135 
136 /*
137  * Set up the signal handlers.
138  */
139 public void init_signals(int on)
140 {
141 	if (on)
142 	{
143 		/*
144 		 * Set signal handlers.
145 		 */
146 #if MSDOS_COMPILER==WIN32C
147 		SetConsoleCtrlHandler(wbreak_handler, TRUE);
148 #else
149 		(void) LSIGNAL(SIGINT, u_interrupt);
150 #endif
151 #ifdef SIGTSTP
152 		(void) LSIGNAL(SIGTSTP, secure ? SIG_IGN : stop);
153 #endif
154 #ifdef SIGWINCH
155 		(void) LSIGNAL(SIGWINCH, winch);
156 #endif
157 #ifdef SIGWIND
158 		(void) LSIGNAL(SIGWIND, winch);
159 #endif
160 #ifdef SIGQUIT
161 		(void) LSIGNAL(SIGQUIT, SIG_IGN);
162 #endif
163 #ifdef SIGTERM
164 		(void) LSIGNAL(SIGTERM, terminate);
165 #endif
166 	} else
167 	{
168 		/*
169 		 * Restore signals to defaults.
170 		 */
171 #if MSDOS_COMPILER==WIN32C
172 		SetConsoleCtrlHandler(wbreak_handler, FALSE);
173 #else
174 		(void) LSIGNAL(SIGINT, SIG_DFL);
175 #endif
176 #ifdef SIGTSTP
177 		(void) LSIGNAL(SIGTSTP, SIG_DFL);
178 #endif
179 #ifdef SIGWINCH
180 		(void) LSIGNAL(SIGWINCH, SIG_IGN);
181 #endif
182 #ifdef SIGWIND
183 		(void) LSIGNAL(SIGWIND, SIG_IGN);
184 #endif
185 #ifdef SIGQUIT
186 		(void) LSIGNAL(SIGQUIT, SIG_DFL);
187 #endif
188 #ifdef SIGTERM
189 		(void) LSIGNAL(SIGTERM, SIG_DFL);
190 #endif
191 	}
192 }
193 
194 /*
195  * Process any signals we have received.
196  * A received signal cause a bit to be set in "sigs".
197  */
198 public void psignals(void)
199 {
200 	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 		}
253 		screen_trashed = 1;
254 	}
255 #endif
256 	if (tsignals & S_INTERRUPT)
257 	{
258 		if (quit_on_intr)
259 			quit(QUIT_INTERRUPT);
260 	}
261 }
262