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