1/*
2 * Copyright (C) 1984-2007  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 about less, or for information on how to
8 * contact the author, see the README file.
9 */
10
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 long jump_sline_fraction;
38
39/*
40 * Interrupt signal handler.
41 */
42	/* ARGSUSED*/
43	static RETSIGTYPE
44u_interrupt(type)
45	int type;
46{
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 (reading)
62		intread();
63}
64
65#ifdef SIGTSTP
66/*
67 * "Stop" (^Z) signal handler.
68 */
69	/* ARGSUSED*/
70	static RETSIGTYPE
71stop(type)
72	int type;
73{
74	LSIGNAL(SIGTSTP, stop);
75	sigs |= S_STOP;
76	if (reading)
77		intread();
78}
79#endif
80
81#ifdef SIGWINCH
82/*
83 * "Window" change handler
84 */
85	/* ARGSUSED*/
86	public RETSIGTYPE
87winch(type)
88	int type;
89{
90	LSIGNAL(SIGWINCH, winch);
91	sigs |= S_WINCH;
92	if (reading)
93		intread();
94}
95#else
96#ifdef SIGWIND
97/*
98 * "Window" change handler
99 */
100	/* ARGSUSED*/
101	public RETSIGTYPE
102winch(type)
103	int type;
104{
105	LSIGNAL(SIGWIND, winch);
106	sigs |= S_WINCH;
107	if (reading)
108		intread();
109}
110#endif
111#endif
112
113#if MSDOS_COMPILER==WIN32C
114/*
115 * Handle CTRL-C and CTRL-BREAK keys.
116 */
117#include "windows.h"
118
119	static BOOL WINAPI
120wbreak_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		return (TRUE);
129	default:
130		break;
131	}
132	return (FALSE);
133}
134#endif
135
136/*
137 * Set up the signal handlers.
138 */
139	public void
140init_signals(on)
141	int on;
142{
143	if (on)
144	{
145		/*
146		 * Set signal handlers.
147		 */
148		(void) LSIGNAL(SIGINT, u_interrupt);
149#if MSDOS_COMPILER==WIN32C
150		SetConsoleCtrlHandler(wbreak_handler, TRUE);
151#endif
152#ifdef SIGTSTP
153		(void) LSIGNAL(SIGTSTP, 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	} else
165	{
166		/*
167		 * Restore signals to defaults.
168		 */
169		(void) LSIGNAL(SIGINT, SIG_DFL);
170#if MSDOS_COMPILER==WIN32C
171		SetConsoleCtrlHandler(wbreak_handler, FALSE);
172#endif
173#ifdef SIGTSTP
174		(void) LSIGNAL(SIGTSTP, SIG_DFL);
175#endif
176#ifdef SIGWINCH
177		(void) LSIGNAL(SIGWINCH, SIG_IGN);
178#endif
179#ifdef SIGWIND
180		(void) LSIGNAL(SIGWIND, SIG_IGN);
181#endif
182#ifdef SIGQUIT
183		(void) LSIGNAL(SIGQUIT, SIG_DFL);
184#endif
185	}
186}
187
188/*
189 * Process any signals we have received.
190 * A received signal cause a bit to be set in "sigs".
191 */
192	public void
193psignals()
194{
195	register int tsignals;
196
197	if ((tsignals = sigs) == 0)
198		return;
199	sigs = 0;
200
201#ifdef SIGTSTP
202	if (tsignals & S_STOP)
203	{
204		/*
205		 * Clean up the terminal.
206		 */
207#ifdef SIGTTOU
208		LSIGNAL(SIGTTOU, SIG_IGN);
209#endif
210		clear_bot();
211		deinit();
212		flush();
213		raw_mode(0);
214#ifdef SIGTTOU
215		LSIGNAL(SIGTTOU, SIG_DFL);
216#endif
217		LSIGNAL(SIGTSTP, SIG_DFL);
218		kill(getpid(), SIGTSTP);
219		/*
220		 * ... Bye bye. ...
221		 * Hopefully we'll be back later and resume here...
222		 * Reset the terminal and arrange to repaint the
223		 * screen when we get back to the main command loop.
224		 */
225		LSIGNAL(SIGTSTP, stop);
226		raw_mode(1);
227		init();
228		screen_trashed = 1;
229		tsignals |= S_WINCH;
230	}
231#endif
232#ifdef S_WINCH
233	if (tsignals & S_WINCH)
234	{
235		int old_width, old_height;
236		/*
237		 * Re-execute scrsize() to read the new window size.
238		 */
239		old_width = sc_width;
240		old_height = sc_height;
241		get_term();
242		if (sc_width != old_width || sc_height != old_height)
243		{
244			wscroll = (sc_height + 1) / 2;
245			calc_jump_sline();
246			screen_trashed = 1;
247		}
248	}
249#endif
250	if (tsignals & S_INTERRUPT)
251	{
252		if (quit_on_intr)
253			quit(QUIT_OK);
254		bell();
255		/*
256		 * {{ You may wish to replace the bell() with
257		 *    error("Interrupt", NULL_PARG); }}
258		 */
259
260		/*
261		 * If we were interrupted while in the "calculating
262		 * line numbers" loop, turn off line numbers.
263		 */
264		if (lnloop)
265		{
266			lnloop = 0;
267			if (linenums == 2)
268				screen_trashed = 1;
269			linenums = 0;
270			error("Line numbers turned off", NULL_PARG);
271		}
272
273	}
274}
275