signal.c revision 170259
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 170259 2007-06-04 01:43:11Z 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}
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#endif
160#ifdef SIGWIND
161		(void) LSIGNAL(SIGWIND, winch);
162#endif
163#ifdef SIGQUIT
164		(void) LSIGNAL(SIGQUIT, SIG_IGN);
165#endif
166	} else
167	{
168		/*
169		 * Restore signals to defaults.
170		 */
171		(void) LSIGNAL(SIGINT, SIG_DFL);
172#if MSDOS_COMPILER==WIN32C
173		SetConsoleCtrlHandler(wbreak_handler, FALSE);
174#endif
175#ifdef SIGTSTP
176		(void) LSIGNAL(SIGTSTP, SIG_DFL);
177#endif
178#ifdef SIGWINCH
179		(void) LSIGNAL(SIGWINCH, SIG_IGN);
180#endif
181#ifdef SIGWIND
182		(void) LSIGNAL(SIGWIND, SIG_IGN);
183#endif
184#ifdef SIGQUIT
185		(void) LSIGNAL(SIGQUIT, SIG_DFL);
186#endif
187	}
188}
189
190/*
191 * Process any signals we have received.
192 * A received signal cause a bit to be set in "sigs".
193 */
194	public void
195psignals()
196{
197	register int tsignals;
198
199	if ((tsignals = sigs) == 0)
200		return;
201	sigs = 0;
202
203#ifdef SIGTSTP
204	if (tsignals & S_STOP)
205	{
206		/*
207		 * Clean up the terminal.
208		 */
209#ifdef SIGTTOU
210		LSIGNAL(SIGTTOU, SIG_IGN);
211#endif
212		clear_bot();
213		deinit();
214		flush();
215		raw_mode(0);
216#ifdef SIGTTOU
217		LSIGNAL(SIGTTOU, SIG_DFL);
218#endif
219		LSIGNAL(SIGTSTP, SIG_DFL);
220		kill(getpid(), SIGTSTP);
221		/*
222		 * ... Bye bye. ...
223		 * Hopefully we'll be back later and resume here...
224		 * Reset the terminal and arrange to repaint the
225		 * screen when we get back to the main command loop.
226		 */
227		LSIGNAL(SIGTSTP, stop);
228		raw_mode(1);
229		init();
230		screen_trashed = 1;
231		tsignals |= S_WINCH;
232	}
233#endif
234#ifdef S_WINCH
235	if (tsignals & S_WINCH)
236	{
237		int old_width, old_height;
238		/*
239		 * Re-execute scrsize() to read the new window size.
240		 */
241		old_width = sc_width;
242		old_height = sc_height;
243		get_term();
244		if (sc_width != old_width || sc_height != old_height)
245		{
246			wscroll = (sc_height + 1) / 2;
247			calc_jump_sline();
248			screen_trashed = 1;
249		}
250	}
251#endif
252	if (tsignals & S_INTERRUPT)
253	{
254		if (quit_on_intr)
255			quit(QUIT_OK);
256		bell();
257		/*
258		 * {{ You may wish to replace the bell() with
259		 *    error("Interrupt", NULL_PARG); }}
260		 */
261
262		/*
263		 * If we were interrupted while in the "calculating
264		 * line numbers" loop, turn off line numbers.
265		 */
266		if (lnloop)
267		{
268			lnloop = 0;
269			if (linenums == 2)
270				screen_trashed = 1;
271			linenums = 0;
272			error("Line numbers turned off", NULL_PARG);
273		}
274
275	}
276}
277