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