11590Srgrimes/*
21590Srgrimes * Copyright (C) 1984-2023  Mark Nudelman
31590Srgrimes *
41590Srgrimes * You may distribute under the terms of either the GNU General Public
51590Srgrimes * License or the Less License, as specified in the README file.
61590Srgrimes *
71590Srgrimes * For more information, see the README file.
81590Srgrimes */
91590Srgrimes
101590Srgrimes/* $FreeBSD$ */
111590Srgrimes
121590Srgrimes/*
131590Srgrimes * Routines dealing with signals.
141590Srgrimes *
151590Srgrimes * A signal usually merely causes a bit to be set in the "signals" word.
161590Srgrimes * At some convenient time, the mainline code checks to see if any
171590Srgrimes * signals need processing by calling psignal().
181590Srgrimes * If we happen to be reading from a file [in iread()] at the time
191590Srgrimes * the signal is received, we call intread to interrupt the iread.
201590Srgrimes */
211590Srgrimes
221590Srgrimes#include "less.h"
231590Srgrimes#include <signal.h>
241590Srgrimes
251590Srgrimes/*
261590Srgrimes * "sigs" contains bits indicating signals which need to be processed.
271590Srgrimes */
281590Srgrimespublic int sigs;
291590Srgrimes
301590Srgrimesextern int sc_width, sc_height;
3129207Sjoergextern int screen_trashed;
3250477Speterextern int lnloop;
331590Srgrimesextern int linenums;
34200632Sjhextern int wscroll;
351590Srgrimesextern int reading;
361590Srgrimesextern int quit_on_intr;
371590Srgrimesextern int secure;
381590Srgrimesextern long jump_sline_fraction;
391590Srgrimes
401590Srgrimesextern int less_is_more;
4128503Scharnier
421590Srgrimes/*
4329207Sjoerg * Interrupt signal handler.
4497257Strhodes */
451590Srgrimes#if MSDOS_COMPILER!=WIN32C
461590Srgrimes	/* ARGSUSED*/
471590Srgrimesstatic RETSIGTYPE u_interrupt(int type)
481590Srgrimes{
491590Srgrimes	bell();
501590Srgrimes#if OS2
511590Srgrimes	LSIGNAL(SIGINT, SIG_ACK);
5228503Scharnier#endif
5397529Stjr	LSIGNAL(SIGINT, u_interrupt);
5497529Stjr	sigs |= S_INTERRUPT;
5597529Stjr#if MSDOS_COMPILER==DJGPPC
5697529Stjr	/*
5797529Stjr	 * If a keyboard has been hit, it must be Ctrl-C
5897529Stjr	 * (as opposed to Ctrl-Break), so consume it.
5997529Stjr	 * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.)
6097529Stjr	 */
61107276Sru	if (kbhit())
6297529Stjr		getkey();
6397529Stjr#endif
6497529Stjr	if (less_is_more)
6597529Stjr		quit(0);
661590Srgrimes#if HILITE_SEARCH
671590Srgrimes	set_filter_pattern(NULL, 0);
681590Srgrimes#endif
691590Srgrimes	if (reading)
701590Srgrimes		intread(); /* May longjmp */
711590Srgrimes}
721590Srgrimes#endif
731590Srgrimes
741590Srgrimes#ifdef SIGTSTP
751590Srgrimes/*
761590Srgrimes * "Stop" (^Z) signal handler.
7744769Sbillf */
7897070Strhodes	/* ARGSUSED*/
791590Srgrimesstatic RETSIGTYPE stop(int type)
8097070Strhodes{
8197257Strhodes	LSIGNAL(SIGTSTP, stop);
821590Srgrimes	sigs |= S_STOP;
831590Srgrimes	if (reading)
84131491Sru		intread();
851590Srgrimes}
861590Srgrimes#endif
871590Srgrimes
881590Srgrimes#undef SIG_LESSWINDOW
891590Srgrimes#ifdef SIGWINCH
901590Srgrimes#define SIG_LESSWINDOW SIGWINCH
911590Srgrimes#else
921590Srgrimes#ifdef SIGWIND
931590Srgrimes#define SIG_LESSWINDOW SIGWIND
9497070Strhodes#endif
951590Srgrimes#endif
96131491Sru
971590Srgrimes#ifdef SIG_LESSWINDOW
9844769Sbillf/*
9929207Sjoerg * "Window" change handler
10029207Sjoerg */
1011590Srgrimes	/* ARGSUSED*/
1021590Srgrimespublic RETSIGTYPE winch(int type)
1031590Srgrimes{
1041590Srgrimes	LSIGNAL(SIG_LESSWINDOW, winch);
1051590Srgrimes	sigs |= S_WINCH;
1061590Srgrimes	if (reading)
1071590Srgrimes		intread();
1081590Srgrimes}
1091590Srgrimes#endif
1101590Srgrimes
1111590Srgrimes#if MSDOS_COMPILER==WIN32C
1121590Srgrimes/*
1131590Srgrimes * Handle CTRL-C and CTRL-BREAK keys.
1141590Srgrimes */
1151590Srgrimes#define WIN32_LEAN_AND_MEAN
1161590Srgrimes#include <windows.h>
1171590Srgrimes
1181590Srgrimesstatic BOOL WINAPI wbreak_handler(DWORD dwCtrlType)
1191590Srgrimes{
120113382Stjr	switch (dwCtrlType)
121113382Stjr	{
122113382Stjr	case CTRL_C_EVENT:
123113382Stjr	case CTRL_BREAK_EVENT:
124113382Stjr		sigs |= S_INTERRUPT;
125113382Stjr#if HILITE_SEARCH
126113382Stjr		set_filter_pattern(NULL, 0);
127113382Stjr#endif
128113382Stjr		return (TRUE);
129113382Stjr	default:
130113382Stjr		break;
131140368Sru	}
13281687Sru	return (FALSE);
1331590Srgrimes}
1341590Srgrimes#endif
1351590Srgrimes
1361590Srgrimesstatic RETSIGTYPE terminate(int type)
1371590Srgrimes{
1381590Srgrimes	quit(15);
1391590Srgrimes}
1401590Srgrimes
1411590Srgrimes/*
1421590Srgrimes * Set up the signal handlers.
14328503Scharnier */
144113382Stjrpublic void init_signals(int on)
145113382Stjr{
146131491Sru	if (on)
14799435Stjr	{
14899435Stjr		/*
14999435Stjr		 * Set signal handlers.
15099435Stjr		 */
15199435Stjr#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, secure ? SIG_IGN : 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 */
203public void psignals(void)
204{
205	int tsignals;
206
207	if ((tsignals = sigs) == 0)
208		return;
209	sigs = 0;
210
211#ifdef SIGTSTP
212	if (tsignals & S_STOP)
213	{
214		/*
215		 * Clean up the terminal.
216		 */
217#ifdef SIGTTOU
218		LSIGNAL(SIGTTOU, SIG_IGN);
219#endif
220		clear_bot();
221		deinit();
222		flush();
223		raw_mode(0);
224#ifdef SIGTTOU
225		LSIGNAL(SIGTTOU, SIG_DFL);
226#endif
227		LSIGNAL(SIGTSTP, SIG_DFL);
228		kill(getpid(), SIGTSTP);
229		/*
230		 * ... Bye bye. ...
231		 * Hopefully we'll be back later and resume here...
232		 * Reset the terminal and arrange to repaint the
233		 * screen when we get back to the main command loop.
234		 */
235		LSIGNAL(SIGTSTP, stop);
236		raw_mode(1);
237		init();
238		screen_trashed = 1;
239		tsignals |= S_WINCH;
240	}
241#endif
242#ifdef S_WINCH
243	if (tsignals & S_WINCH)
244	{
245		int old_width, old_height;
246		/*
247		 * Re-execute scrsize() to read the new window size.
248		 */
249		old_width = sc_width;
250		old_height = sc_height;
251		get_term();
252		if (sc_width != old_width || sc_height != old_height)
253		{
254			wscroll = (sc_height + 1) / 2;
255			calc_jump_sline();
256			calc_shift_count();
257		}
258		screen_trashed = 1;
259	}
260#endif
261	if (tsignals & S_INTERRUPT)
262	{
263		if (quit_on_intr)
264			quit(QUIT_INTERRUPT);
265	}
266}
267