1/*
2 * Copyright (C) 1984-2012  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/* $FreeBSD$ */
11
12/*
13 * Routines dealing with signals.
14 *
15 * A signal usually merely causes a bit to be set in the "signals" word.
16 * At some convenient time, the mainline code checks to see if any
17 * signals need processing by calling psignal().
18 * If we happen to be reading from a file [in iread()] at the time
19 * the signal is received, we call intread to interrupt the iread.
20 */
21
22#include "less.h"
23#include <signal.h>
24
25/*
26 * "sigs" contains bits indicating signals which need to be processed.
27 */
28public int sigs;
29
30extern int sc_width, sc_height;
31extern int screen_trashed;
32extern int lnloop;
33extern int linenums;
34extern int wscroll;
35extern int reading;
36extern int quit_on_intr;
37extern int less_is_more;
38extern long jump_sline_fraction;
39
40/*
41 * Interrupt signal handler.
42 */
43	/* ARGSUSED*/
44	static RETSIGTYPE
45u_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 (less_is_more)
64		quit(0);
65	if (reading)
66		intread(); /* May longjmp */
67}
68
69#ifdef SIGTSTP
70/*
71 * "Stop" (^Z) signal handler.
72 */
73	/* ARGSUSED*/
74	static RETSIGTYPE
75stop(type)
76	int type;
77{
78	LSIGNAL(SIGTSTP, stop);
79	sigs |= S_STOP;
80	if (reading)
81		intread();
82}
83#endif
84
85#ifdef SIGWINCH
86/*
87 * "Window" change handler
88 */
89	/* ARGSUSED*/
90	public RETSIGTYPE
91winch(type)
92	int type;
93{
94	LSIGNAL(SIGWINCH, winch);
95	sigs |= S_WINCH;
96	if (reading)
97		intread();
98}
99#else
100#ifdef SIGWIND
101/*
102 * "Window" change handler
103 */
104	/* ARGSUSED*/
105	public RETSIGTYPE
106winch(type)
107	int type;
108{
109	LSIGNAL(SIGWIND, winch);
110	sigs |= S_WINCH;
111	if (reading)
112		intread();
113}
114#endif
115#endif
116
117#if MSDOS_COMPILER==WIN32C
118/*
119 * Handle CTRL-C and CTRL-BREAK keys.
120 */
121#include "windows.h"
122
123	static BOOL WINAPI
124wbreak_handler(dwCtrlType)
125	DWORD dwCtrlType;
126{
127	switch (dwCtrlType)
128	{
129	case CTRL_C_EVENT:
130	case CTRL_BREAK_EVENT:
131		sigs |= S_INTERRUPT;
132		return (TRUE);
133	default:
134		break;
135	}
136	return (FALSE);
137}
138#endif
139
140/*
141 * Set up the signal handlers.
142 */
143	public void
144init_signals(on)
145	int on;
146{
147	if (on)
148	{
149		/*
150		 * Set signal handlers.
151		 */
152		(void) LSIGNAL(SIGINT, u_interrupt);
153#if MSDOS_COMPILER==WIN32C
154		SetConsoleCtrlHandler(wbreak_handler, TRUE);
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	} else
169	{
170		/*
171		 * Restore signals to defaults.
172		 */
173		(void) LSIGNAL(SIGINT, SIG_DFL);
174#if MSDOS_COMPILER==WIN32C
175		SetConsoleCtrlHandler(wbreak_handler, FALSE);
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	}
190}
191
192/*
193 * Process any signals we have received.
194 * A received signal cause a bit to be set in "sigs".
195 */
196	public void
197psignals()
198{
199	register int tsignals;
200
201	if ((tsignals = sigs) == 0)
202		return;
203	sigs = 0;
204
205#ifdef SIGTSTP
206	if (tsignals & S_STOP)
207	{
208		/*
209		 * Clean up the terminal.
210		 */
211#ifdef SIGTTOU
212		LSIGNAL(SIGTTOU, SIG_IGN);
213#endif
214		clear_bot();
215		deinit();
216		flush();
217		raw_mode(0);
218#ifdef SIGTTOU
219		LSIGNAL(SIGTTOU, SIG_DFL);
220#endif
221		LSIGNAL(SIGTSTP, SIG_DFL);
222		kill(getpid(), SIGTSTP);
223		/*
224		 * ... Bye bye. ...
225		 * Hopefully we'll be back later and resume here...
226		 * Reset the terminal and arrange to repaint the
227		 * screen when we get back to the main command loop.
228		 */
229		LSIGNAL(SIGTSTP, stop);
230		raw_mode(1);
231		init();
232		screen_trashed = 1;
233		tsignals |= S_WINCH;
234	}
235#endif
236#ifdef S_WINCH
237	if (tsignals & S_WINCH)
238	{
239		int old_width, old_height;
240		/*
241		 * Re-execute scrsize() to read the new window size.
242		 */
243		old_width = sc_width;
244		old_height = sc_height;
245		get_term();
246		if (sc_width != old_width || sc_height != old_height)
247		{
248			wscroll = (sc_height + 1) / 2;
249			calc_jump_sline();
250			calc_shift_count();
251			screen_trashed = 1;
252		}
253	}
254#endif
255	if (tsignals & S_INTERRUPT)
256	{
257		if (quit_on_intr)
258			quit(QUIT_INTERRUPT);
259	}
260}
261