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