signal.c revision 60787
10SN/A/*
20SN/A * Copyright (C) 1984-2000  Mark Nudelman
30SN/A *
40SN/A * You may distribute under the terms of either the GNU General Public
50SN/A * License or the Less License, as specified in the README file.
62362SN/A *
70SN/A * For more information about less, or for information on how to
82362SN/A * contact the author, see the README file.
90SN/A */
100SN/A
110SN/A
120SN/A/*
130SN/A * Routines dealing with signals.
140SN/A *
150SN/A * A signal usually merely causes a bit to be set in the "signals" word.
160SN/A * At some convenient time, the mainline code checks to see if any
170SN/A * signals need processing by calling psignal().
180SN/A * If we happen to be reading from a file [in iread()] at the time
190SN/A * the signal is received, we call intread to interrupt the iread.
202362SN/A */
212362SN/A
222362SN/A#include "less.h"
230SN/A#include <signal.h>
240SN/A
250SN/A/*
260SN/A * "sigs" contains bits indicating signals which need to be processed.
270SN/A */
280SN/Apublic int sigs;
290SN/A
300SN/Aextern int sc_width, sc_height;
310SN/Aextern int screen_trashed;
320SN/Aextern int lnloop;
330SN/Aextern int linenums;
341693SN/Aextern int wscroll;
351693SN/Aextern int reading;
361693SN/A
371693SN/A/*
381693SN/A * Interrupt signal handler.
390SN/A */
400SN/A	/* ARGSUSED*/
410SN/A	static RETSIGTYPE
420SN/Au_interrupt(type)
433171SN/A	int type;
440SN/A{
450SN/A#if OS2
460SN/A	LSIGNAL(SIGINT, SIG_ACK);
470SN/A#endif
480SN/A	LSIGNAL(SIGINT, u_interrupt);
491693SN/A	sigs |= S_INTERRUPT;
501693SN/A#if MSDOS_COMPILER==DJGPPC
510SN/A	/*
520SN/A	 * If a keyboard has been hit, it must be Ctrl-C
530SN/A	 * (as opposed to Ctrl-Break), so consume it.
546936SN/A	 * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.)
553171SN/A	 */
563171SN/A	if (kbhit())
573171SN/A		getkey();
583171SN/A#endif
593171SN/A	if (reading)
603171SN/A		intread();
610SN/A}
620SN/A
630SN/A#ifdef SIGTSTP
646936SN/A/*
653171SN/A * "Stop" (^Z) signal handler.
660SN/A */
670SN/A	/* ARGSUSED*/
680SN/A	static RETSIGTYPE
690SN/Astop(type)
700SN/A	int type;
710SN/A{
720SN/A	LSIGNAL(SIGTSTP, stop);
730SN/A	sigs |= S_STOP;
740SN/A	if (reading)
750SN/A		intread();
761693SN/A}
770SN/A#endif
78
79#ifdef SIGWINCH
80/*
81 * "Window" change handler
82 */
83	/* ARGSUSED*/
84	public RETSIGTYPE
85winch(type)
86	int type;
87{
88	LSIGNAL(SIGWINCH, winch);
89	sigs |= S_WINCH;
90	if (reading)
91		intread();
92}
93#else
94#ifdef SIGWIND
95/*
96 * "Window" change handler
97 */
98	/* ARGSUSED*/
99	public RETSIGTYPE
100winch(type)
101	int type;
102{
103	LSIGNAL(SIGWIND, winch);
104	sigs |= S_WINCH;
105	if (reading)
106		intread();
107}
108#endif
109#endif
110
111#if MSDOS_COMPILER==WIN32C
112/*
113 * Handle CTRL-C and CTRL-BREAK keys.
114 */
115#include "windows.h"
116
117	static BOOL WINAPI
118wbreak_handler(dwCtrlType)
119	DWORD dwCtrlType;
120{
121	switch (dwCtrlType)
122	{
123	case CTRL_C_EVENT:
124	case CTRL_BREAK_EVENT:
125		sigs |= S_INTERRUPT;
126		return (TRUE);
127	default:
128		break;
129	}
130	return (FALSE);
131}
132#endif
133
134/*
135 * Set up the signal handlers.
136 */
137	public void
138init_signals(on)
139	int on;
140{
141	if (on)
142	{
143		/*
144		 * Set signal handlers.
145		 */
146		(void) LSIGNAL(SIGINT, u_interrupt);
147#if MSDOS_COMPILER==WIN32C
148		SetConsoleCtrlHandler(wbreak_handler, TRUE);
149#endif
150#ifdef SIGTSTP
151		(void) LSIGNAL(SIGTSTP, stop);
152#endif
153#ifdef SIGWINCH
154		(void) LSIGNAL(SIGWINCH, winch);
155#else
156#ifdef SIGWIND
157		(void) LSIGNAL(SIGWIND, winch);
158#endif
159#ifdef SIGQUIT
160		(void) LSIGNAL(SIGQUIT, SIG_IGN);
161#endif
162#endif
163	} else
164	{
165		/*
166		 * Restore signals to defaults.
167		 */
168		(void) LSIGNAL(SIGINT, SIG_DFL);
169#if MSDOS_COMPILER==WIN32C
170		SetConsoleCtrlHandler(wbreak_handler, FALSE);
171#endif
172#ifdef SIGTSTP
173		(void) LSIGNAL(SIGTSTP, SIG_DFL);
174#endif
175#ifdef SIGWINCH
176		(void) LSIGNAL(SIGWINCH, SIG_IGN);
177#endif
178#ifdef SIGWIND
179		(void) LSIGNAL(SIGWIND, SIG_IGN);
180#endif
181#ifdef SIGQUIT
182		(void) LSIGNAL(SIGQUIT, SIG_DFL);
183#endif
184	}
185}
186
187/*
188 * Process any signals we have received.
189 * A received signal cause a bit to be set in "sigs".
190 */
191	public void
192psignals()
193{
194	register int tsignals;
195
196	if ((tsignals = sigs) == 0)
197		return;
198	sigs = 0;
199
200#ifdef SIGTSTP
201	if (tsignals & S_STOP)
202	{
203		/*
204		 * Clean up the terminal.
205		 */
206#ifdef SIGTTOU
207		LSIGNAL(SIGTTOU, SIG_IGN);
208#endif
209		clear_bot();
210		deinit();
211		flush();
212		raw_mode(0);
213#ifdef SIGTTOU
214		LSIGNAL(SIGTTOU, SIG_DFL);
215#endif
216		LSIGNAL(SIGTSTP, SIG_DFL);
217		kill(getpid(), SIGTSTP);
218		/*
219		 * ... Bye bye. ...
220		 * Hopefully we'll be back later and resume here...
221		 * Reset the terminal and arrange to repaint the
222		 * screen when we get back to the main command loop.
223		 */
224		LSIGNAL(SIGTSTP, stop);
225		raw_mode(1);
226		init();
227		screen_trashed = 1;
228		tsignals |= S_WINCH;
229	}
230#endif
231#ifdef S_WINCH
232	if (tsignals & S_WINCH)
233	{
234		int old_width, old_height;
235		/*
236		 * Re-execute scrsize() to read the new window size.
237		 */
238		old_width = sc_width;
239		old_height = sc_height;
240		get_term();
241		if (sc_width != old_width || sc_height != old_height)
242		{
243			wscroll = (sc_height + 1) / 2;
244			screen_trashed = 1;
245		}
246	}
247#endif
248	if (tsignals & S_INTERRUPT)
249	{
250		bell();
251		/*
252		 * {{ You may wish to replace the bell() with
253		 *    error("Interrupt", NULL_PARG); }}
254		 */
255
256		/*
257		 * If we were interrupted while in the "calculating
258		 * line numbers" loop, turn off line numbers.
259		 */
260		if (lnloop)
261		{
262			lnloop = 0;
263			if (linenums == 2)
264				screen_trashed = 1;
265			linenums = 0;
266			error("Line numbers turned off", NULL_PARG);
267		}
268
269	}
270}
271