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