signal.c revision 161478
1/*
2 * Copyright (C) 1984-2004  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 161478 2006-08-20 15:50:51Z 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 more_mode;
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 (more_mode)
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#else
161#ifdef SIGWIND
162		(void) LSIGNAL(SIGWIND, winch);
163#endif
164#ifdef SIGQUIT
165		(void) LSIGNAL(SIGQUIT, SIG_IGN);
166#endif
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			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