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 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#if OS2
49	LSIGNAL(SIGINT, SIG_ACK);
50#endif
51	LSIGNAL(SIGINT, u_interrupt);
52	sigs |= S_INTERRUPT;
53#if MSDOS_COMPILER==DJGPPC
54	/*
55	 * If a keyboard has been hit, it must be Ctrl-C
56	 * (as opposed to Ctrl-Break), so consume it.
57	 * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.)
58	 */
59	if (kbhit())
60		getkey();
61#endif
62	if (less_is_more)
63		quit(0);
64	if (reading)
65		intread();
66}
67
68#ifdef SIGTSTP
69/*
70 * "Stop" (^Z) signal handler.
71 */
72	/* ARGSUSED*/
73	static RETSIGTYPE
74stop(type)
75	int type;
76{
77	LSIGNAL(SIGTSTP, stop);
78	sigs |= S_STOP;
79	if (reading)
80		intread();
81}
82#endif
83
84#ifdef SIGWINCH
85/*
86 * "Window" change handler
87 */
88	/* ARGSUSED*/
89	public RETSIGTYPE
90winch(type)
91	int type;
92{
93	LSIGNAL(SIGWINCH, winch);
94	sigs |= S_WINCH;
95	if (reading)
96		intread();
97}
98#else
99#ifdef SIGWIND
100/*
101 * "Window" change handler
102 */
103	/* ARGSUSED*/
104	public RETSIGTYPE
105winch(type)
106	int type;
107{
108	LSIGNAL(SIGWIND, winch);
109	sigs |= S_WINCH;
110	if (reading)
111		intread();
112}
113#endif
114#endif
115
116#if MSDOS_COMPILER==WIN32C
117/*
118 * Handle CTRL-C and CTRL-BREAK keys.
119 */
120#include "windows.h"
121
122	static BOOL WINAPI
123wbreak_handler(dwCtrlType)
124	DWORD dwCtrlType;
125{
126	switch (dwCtrlType)
127	{
128	case CTRL_C_EVENT:
129	case CTRL_BREAK_EVENT:
130		sigs |= S_INTERRUPT;
131		return (TRUE);
132	default:
133		break;
134	}
135	return (FALSE);
136}
137#endif
138
139/*
140 * Set up the signal handlers.
141 */
142	public void
143init_signals(on)
144	int on;
145{
146	if (on)
147	{
148		/*
149		 * Set signal handlers.
150		 */
151		(void) LSIGNAL(SIGINT, u_interrupt);
152#if MSDOS_COMPILER==WIN32C
153		SetConsoleCtrlHandler(wbreak_handler, TRUE);
154#endif
155#ifdef SIGTSTP
156		(void) LSIGNAL(SIGTSTP, stop);
157#endif
158#ifdef SIGWINCH
159		(void) LSIGNAL(SIGWINCH, winch);
160#endif
161#ifdef SIGWIND
162		(void) LSIGNAL(SIGWIND, winch);
163#endif
164#ifdef SIGQUIT
165		(void) LSIGNAL(SIGQUIT, SIG_IGN);
166#endif
167	} else
168	{
169		/*
170		 * Restore signals to defaults.
171		 */
172		(void) LSIGNAL(SIGINT, SIG_DFL);
173#if MSDOS_COMPILER==WIN32C
174		SetConsoleCtrlHandler(wbreak_handler, FALSE);
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	}
189}
190
191/*
192 * Process any signals we have received.
193 * A received signal cause a bit to be set in "sigs".
194 */
195	public void
196psignals()
197{
198	register int tsignals;
199
200	if ((tsignals = sigs) == 0)
201		return;
202	sigs = 0;
203
204#ifdef SIGTSTP
205	if (tsignals & S_STOP)
206	{
207		/*
208		 * Clean up the terminal.
209		 */
210#ifdef SIGTTOU
211		LSIGNAL(SIGTTOU, SIG_IGN);
212#endif
213		clear_bot();
214		deinit();
215		flush();
216		raw_mode(0);
217#ifdef SIGTTOU
218		LSIGNAL(SIGTTOU, SIG_DFL);
219#endif
220		LSIGNAL(SIGTSTP, SIG_DFL);
221		kill(getpid(), SIGTSTP);
222		/*
223		 * ... Bye bye. ...
224		 * Hopefully we'll be back later and resume here...
225		 * Reset the terminal and arrange to repaint the
226		 * screen when we get back to the main command loop.
227		 */
228		LSIGNAL(SIGTSTP, stop);
229		raw_mode(1);
230		init();
231		screen_trashed = 1;
232		tsignals |= S_WINCH;
233	}
234#endif
235#ifdef S_WINCH
236	if (tsignals & S_WINCH)
237	{
238		int old_width, old_height;
239		/*
240		 * Re-execute scrsize() to read the new window size.
241		 */
242		old_width = sc_width;
243		old_height = sc_height;
244		get_term();
245		if (sc_width != old_width || sc_height != old_height)
246		{
247			wscroll = (sc_height + 1) / 2;
248			calc_jump_sline();
249			screen_trashed = 1;
250		}
251	}
252#endif
253	if (tsignals & S_INTERRUPT)
254	{
255		if (quit_on_intr)
256			quit(QUIT_OK);
257		bell();
258		/*
259		 * {{ You may wish to replace the bell() with
260		 *    error("Interrupt", NULL_PARG); }}
261		 */
262
263		/*
264		 * If we were interrupted while in the "calculating
265		 * line numbers" loop, turn off line numbers.
266		 */
267		if (lnloop)
268		{
269			lnloop = 0;
270			if (linenums == 2)
271				screen_trashed = 1;
272			linenums = 0;
273			error("Line numbers turned off", NULL_PARG);
274		}
275
276	}
277}
278