signal.c revision 172471
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/* $FreeBSD: head/contrib/less/signal.c 172471 2007-10-08 16:17:42Z delphij $ */
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 quit_on_intr;
38extern int less_is_more;
39extern long jump_sline_fraction;
40
41/*
42 * Interrupt signal handler.
43 */
44	/* ARGSUSED*/
45	static RETSIGTYPE
46u_interrupt(type)
47	int type;
48{
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();
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			screen_trashed = 1;
251		}
252	}
253#endif
254	if (tsignals & S_INTERRUPT)
255	{
256		if (quit_on_intr)
257			quit(QUIT_OK);
258		bell();
259		/*
260		 * {{ You may wish to replace the bell() with
261		 *    error("Interrupt", NULL_PARG); }}
262		 */
263
264		/*
265		 * If we were interrupted while in the "calculating
266		 * line numbers" loop, turn off line numbers.
267		 */
268		if (lnloop)
269		{
270			lnloop = 0;
271			if (linenums == 2)
272				screen_trashed = 1;
273			linenums = 0;
274			error("Line numbers turned off", NULL_PARG);
275		}
276
277	}
278}
279