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