Imported Upstream version 551
[platform/upstream/less.git] / signal.c
1 /*
2  * Copyright (C) 1984-2019  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
11 /*
12  * Routines dealing with signals.
13  *
14  * A signal usually merely causes a bit to be set in the "signals" word.
15  * At some convenient time, the mainline code checks to see if any
16  * signals need processing by calling psignal().
17  * If we happen to be reading from a file [in iread()] at the time
18  * the signal is received, we call intread to interrupt the iread.
19  */
20
21 #include "less.h"
22 #include <signal.h>
23
24 /*
25  * "sigs" contains bits indicating signals which need to be processed.
26  */
27 public int sigs;
28
29 extern int sc_width, sc_height;
30 extern int screen_trashed;
31 extern int lnloop;
32 extern int linenums;
33 extern int wscroll;
34 extern int reading;
35 extern int quit_on_intr;
36 extern long jump_sline_fraction;
37
38 /*
39  * Interrupt signal handler.
40  */
41 #if MSDOS_COMPILER!=WIN32C
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 #endif
66
67 #ifdef SIGTSTP
68 /*
69  * "Stop" (^Z) signal handler.
70  */
71         /* ARGSUSED*/
72         static RETSIGTYPE
73 stop(type)
74         int type;
75 {
76         LSIGNAL(SIGTSTP, stop);
77         sigs |= S_STOP;
78         if (reading)
79                 intread();
80 }
81 #endif
82
83 #undef SIG_LESSWINDOW
84 #ifdef SIGWINCH
85 #define SIG_LESSWINDOW SIGWINCH
86 #else
87 #ifdef SIGWIND
88 #define SIG_LESSWINDOW SIGWIND
89 #endif
90 #endif
91
92 #ifdef SIG_LESSWINDOW
93 /*
94  * "Window" change handler
95  */
96         /* ARGSUSED*/
97         public RETSIGTYPE
98 winch(type)
99         int type;
100 {
101         LSIGNAL(SIG_LESSWINDOW, winch);
102         sigs |= S_WINCH;
103         if (reading)
104                 intread();
105 }
106 #endif
107
108 #if MSDOS_COMPILER==WIN32C
109 /*
110  * Handle CTRL-C and CTRL-BREAK keys.
111  */
112 #define WIN32_LEAN_AND_MEAN
113 #include <windows.h>
114
115         static BOOL WINAPI 
116 wbreak_handler(dwCtrlType)
117         DWORD dwCtrlType;
118 {
119         switch (dwCtrlType)
120         {
121         case CTRL_C_EVENT:
122         case CTRL_BREAK_EVENT:
123                 sigs |= S_INTERRUPT;
124                 return (TRUE);
125         default:
126                 break;
127         }
128         return (FALSE);
129 }
130 #endif
131
132         static RETSIGTYPE
133 terminate(type)
134         int type;
135 {
136         quit(15);
137 }
138
139 /*
140  * Set up the signal handlers.
141  */
142         public void
143 init_signals(on)
144         int on;
145 {
146         if (on)
147         {
148                 /*
149                  * Set signal handlers.
150                  */
151 #if MSDOS_COMPILER==WIN32C
152                 SetConsoleCtrlHandler(wbreak_handler, TRUE);
153 #else
154                 (void) LSIGNAL(SIGINT, u_interrupt);
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 #ifdef SIGTERM
169                 (void) LSIGNAL(SIGTERM, terminate);
170 #endif
171         } else
172         {
173                 /*
174                  * Restore signals to defaults.
175                  */
176 #if MSDOS_COMPILER==WIN32C
177                 SetConsoleCtrlHandler(wbreak_handler, FALSE);
178 #else
179                 (void) LSIGNAL(SIGINT, SIG_DFL);
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 #ifdef SIGTERM
194                 (void) LSIGNAL(SIGTERM, SIG_DFL);
195 #endif
196         }
197 }
198
199 /*
200  * Process any signals we have received.
201  * A received signal cause a bit to be set in "sigs".
202  */
203         public void
204 psignals(VOID_PARAM)
205 {
206         int tsignals;
207
208         if ((tsignals = sigs) == 0)
209                 return;
210         sigs = 0;
211
212 #ifdef SIGTSTP
213         if (tsignals & S_STOP)
214         {
215                 /*
216                  * Clean up the terminal.
217                  */
218 #ifdef SIGTTOU
219                 LSIGNAL(SIGTTOU, SIG_IGN);
220 #endif
221                 clear_bot();
222                 deinit();
223                 flush();
224                 raw_mode(0);
225 #ifdef SIGTTOU
226                 LSIGNAL(SIGTTOU, SIG_DFL);
227 #endif
228                 LSIGNAL(SIGTSTP, SIG_DFL);
229                 kill(getpid(), SIGTSTP);
230                 /*
231                  * ... Bye bye. ...
232                  * Hopefully we'll be back later and resume here...
233                  * Reset the terminal and arrange to repaint the
234                  * screen when we get back to the main command loop.
235                  */
236                 LSIGNAL(SIGTSTP, stop);
237                 raw_mode(1);
238                 init();
239                 screen_trashed = 1;
240                 tsignals |= S_WINCH;
241         }
242 #endif
243 #ifdef S_WINCH
244         if (tsignals & S_WINCH)
245         {
246                 int old_width, old_height;
247                 /*
248                  * Re-execute scrsize() to read the new window size.
249                  */
250                 old_width = sc_width;
251                 old_height = sc_height;
252                 get_term();
253                 if (sc_width != old_width || sc_height != old_height)
254                 {
255                         wscroll = (sc_height + 1) / 2;
256                         calc_jump_sline();
257                         calc_shift_count();
258                 }
259                 screen_trashed = 1;
260         }
261 #endif
262         if (tsignals & S_INTERRUPT)
263         {
264                 if (quit_on_intr)
265                         quit(QUIT_INTERRUPT);
266         }
267 }