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