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