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