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