signal.c revision 63120
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/* $FreeBSD: head/contrib/less/signal.c 63120 2000-07-14 09:13:35Z ps $ */
12
13/*
14 * Routines dealing with signals.
15 *
16 * A signal usually merely causes a bit to be set in the "signals" word.
17 * At some convenient time, the mainline code checks to see if any
18 * signals need processing by calling psignal().
19 * If we happen to be reading from a file [in iread()] at the time
20 * the signal is received, we call intread to interrupt the iread.
21 */
22
23#include "less.h"
24#include <signal.h>
25
26/*
27 * "sigs" contains bits indicating signals which need to be processed.
28 */
29public int sigs;
30
31extern int sc_width, sc_height;
32extern int screen_trashed;
33extern int lnloop;
34extern int linenums;
35extern int wscroll;
36extern int reading;
37extern int more_mode;
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 (more_mode)
62		quit(0);
63	if (reading)
64		intread();
65}
66
67#ifdef SIGTSTP
68/*
69 * "Stop" (^Z) signal handler.
70 */
71	/* ARGSUSED*/
72	static RETSIGTYPE
73stop(type)
74	int type;
75{
76	LSIGNAL(SIGTSTP, stop);
77	sigs |= S_STOP;
78	if (reading)
79		intread();
80}
81#endif
82
83#ifdef SIGWINCH
84/*
85 * "Window" change handler
86 */
87	/* ARGSUSED*/
88	public RETSIGTYPE
89winch(type)
90	int type;
91{
92	LSIGNAL(SIGWINCH, winch);
93	sigs |= S_WINCH;
94	if (reading)
95		intread();
96}
97#else
98#ifdef SIGWIND
99/*
100 * "Window" change handler
101 */
102	/* ARGSUSED*/
103	public RETSIGTYPE
104winch(type)
105	int type;
106{
107	LSIGNAL(SIGWIND, winch);
108	sigs |= S_WINCH;
109	if (reading)
110		intread();
111}
112#endif
113#endif
114
115#if MSDOS_COMPILER==WIN32C
116/*
117 * Handle CTRL-C and CTRL-BREAK keys.
118 */
119#include "windows.h"
120
121	static BOOL WINAPI
122wbreak_handler(dwCtrlType)
123	DWORD dwCtrlType;
124{
125	switch (dwCtrlType)
126	{
127	case CTRL_C_EVENT:
128	case CTRL_BREAK_EVENT:
129		sigs |= S_INTERRUPT;
130		return (TRUE);
131	default:
132		break;
133	}
134	return (FALSE);
135}
136#endif
137
138/*
139 * Set up the signal handlers.
140 */
141	public void
142init_signals(on)
143	int on;
144{
145	if (on)
146	{
147		/*
148		 * Set signal handlers.
149		 */
150		(void) LSIGNAL(SIGINT, u_interrupt);
151#if MSDOS_COMPILER==WIN32C
152		SetConsoleCtrlHandler(wbreak_handler, TRUE);
153#endif
154#ifdef SIGTSTP
155		(void) LSIGNAL(SIGTSTP, stop);
156#endif
157#ifdef SIGWINCH
158		(void) LSIGNAL(SIGWINCH, winch);
159#else
160#ifdef SIGWIND
161		(void) LSIGNAL(SIGWIND, winch);
162#endif
163#ifdef SIGQUIT
164		(void) LSIGNAL(SIGQUIT, SIG_IGN);
165#endif
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			screen_trashed = 1;
249		}
250	}
251#endif
252	if (tsignals & S_INTERRUPT)
253	{
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