signal.c revision 191930
11556Srgrimes/*
21556Srgrimes * Copyright (C) 1984-2008  Mark Nudelman
31556Srgrimes *
41556Srgrimes * You may distribute under the terms of either the GNU General Public
51556Srgrimes * License or the Less License, as specified in the README file.
61556Srgrimes *
71556Srgrimes * For more information about less, or for information on how to
81556Srgrimes * contact the author, see the README file.
91556Srgrimes */
101556Srgrimes
111556Srgrimes/* $FreeBSD: head/contrib/less/signal.c 191930 2009-05-09 01:35:27Z delphij $ */
121556Srgrimes
131556Srgrimes/*
141556Srgrimes * Routines dealing with signals.
151556Srgrimes *
161556Srgrimes * A signal usually merely causes a bit to be set in the "signals" word.
171556Srgrimes * At some convenient time, the mainline code checks to see if any
181556Srgrimes * signals need processing by calling psignal().
191556Srgrimes * If we happen to be reading from a file [in iread()] at the time
201556Srgrimes * the signal is received, we call intread to interrupt the iread.
211556Srgrimes */
221556Srgrimes
231556Srgrimes#include "less.h"
241556Srgrimes#include <signal.h>
251556Srgrimes
261556Srgrimes/*
271556Srgrimes * "sigs" contains bits indicating signals which need to be processed.
281556Srgrimes */
291556Srgrimespublic int sigs;
301556Srgrimes
311556Srgrimesextern int sc_width, sc_height;
3217987Speterextern int screen_trashed;
3350471Speterextern int lnloop;
341556Srgrimesextern int linenums;
351556Srgrimesextern int wscroll;
361556Srgrimesextern int reading;
371556Srgrimesextern int quit_on_intr;
381556Srgrimesextern int less_is_more;
391556Srgrimesextern long jump_sline_fraction;
4046684Skris
411556Srgrimes/*
421556Srgrimes * Interrupt signal handler.
431556Srgrimes */
441556Srgrimes	/* ARGSUSED*/
451556Srgrimes	static RETSIGTYPE
461556Srgrimesu_interrupt(type)
4738521Scracauer	int type;
481556Srgrimes{
491556Srgrimes	bell();
501556Srgrimes#if OS2
511556Srgrimes	LSIGNAL(SIGINT, SIG_ACK);
521556Srgrimes#endif
531556Srgrimes	LSIGNAL(SIGINT, u_interrupt);
5438530Scracauer	sigs |= S_INTERRUPT;
551556Srgrimes#if MSDOS_COMPILER==DJGPPC
561556Srgrimes	/*
571556Srgrimes	 * If a keyboard has been hit, it must be Ctrl-C
581556Srgrimes	 * (as opposed to Ctrl-Break), so consume it.
59218306Sjilles	 * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.)
601556Srgrimes	 */
611556Srgrimes	if (kbhit())
621556Srgrimes		getkey();
631556Srgrimes#endif
641556Srgrimes	if (less_is_more)
651556Srgrimes		quit(0);
661556Srgrimes	if (reading)
671556Srgrimes		intread(); /* May longjmp */
681556Srgrimes}
6938521Scracauer
7038521Scracauer#ifdef SIGTSTP
711556Srgrimes/*
721556Srgrimes * "Stop" (^Z) signal handler.
7317987Speter */
74199660Sjilles	/* ARGSUSED*/
75199660Sjilles	static RETSIGTYPE
761556Srgrimesstop(type)
771556Srgrimes	int type;
781556Srgrimes{
791556Srgrimes	LSIGNAL(SIGTSTP, stop);
80200967Sjilles	sigs |= S_STOP;
8190111Simp	if (reading)
82216622Sjilles		intread();
83200967Sjilles}
84200967Sjilles#endif
851556Srgrimes
861556Srgrimes#ifdef SIGWINCH
871556Srgrimes/*
881556Srgrimes * "Window" change handler
891556Srgrimes */
901556Srgrimes	/* ARGSUSED*/
911556Srgrimes	public RETSIGTYPE
921556Srgrimeswinch(type)
931556Srgrimes	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			screen_trashed = 1;
252		}
253	}
254#endif
255	if (tsignals & S_INTERRUPT)
256	{
257		if (quit_on_intr)
258			quit(QUIT_OK);
259	}
260}
261