xref: /dragonfly/contrib/less/signal.c (revision e0f238eda64c20d98364903e0c003825fd0b66dd)
1 /*
2  * Copyright (C) 1984-2024  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 linenums;
31 extern int wscroll;
32 extern int reading;
33 extern int quit_on_intr;
34 extern long jump_sline_fraction;
35 
36 /*
37  * Interrupt signal handler.
38  */
39 #if MSDOS_COMPILER!=WIN32C
40           /* ARGSUSED*/
u_interrupt(int type)41 static RETSIGTYPE u_interrupt(int type)
42 {
43           (void) type;
44           bell();
45 #if OS2
46           LSIGNAL(SIGINT, SIG_ACK);
47 #endif
48           LSIGNAL(SIGINT, u_interrupt);
49           sigs |= S_INTERRUPT;
50 #if MSDOS_COMPILER==DJGPPC
51           /*
52            * If a keyboard has been hit, it must be Ctrl-C
53            * (as opposed to Ctrl-Break), so consume it.
54            * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.)
55            */
56           if (kbhit())
57                     getkey();
58 #endif
59 #if HILITE_SEARCH
60           set_filter_pattern(NULL, 0);
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*/
stop(int type)72 static RETSIGTYPE stop(int type)
73 {
74           (void) type;
75           LSIGNAL(SIGTSTP, stop);
76           sigs |= S_STOP;
77           if (reading)
78                     intread();
79 }
80 #endif
81 
82 #undef SIG_LESSWINDOW
83 #ifdef SIGWINCH
84 #define SIG_LESSWINDOW SIGWINCH
85 #else
86 #ifdef SIGWIND
87 #define SIG_LESSWINDOW SIGWIND
88 #endif
89 #endif
90 
91 #ifdef SIG_LESSWINDOW
92 /*
93  * "Window" change handler
94  */
95           /* ARGSUSED*/
winch(int type)96 public RETSIGTYPE winch(int type)
97 {
98           (void) type;
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 #define WIN32_LEAN_AND_MEAN
111 #include <windows.h>
112 
wbreak_handler(DWORD dwCtrlType)113 static BOOL WINAPI wbreak_handler(DWORD dwCtrlType)
114 {
115           switch (dwCtrlType)
116           {
117           case CTRL_C_EVENT:
118           case CTRL_BREAK_EVENT:
119                     sigs |= S_INTERRUPT;
120 #if HILITE_SEARCH
121                     set_filter_pattern(NULL, 0);
122 #endif
123                     return (TRUE);
124           default:
125                     break;
126           }
127           return (FALSE);
128 }
129 #endif
130 
terminate(int type)131 static RETSIGTYPE terminate(int type)
132 {
133           (void) type;
134           quit(15);
135 }
136 
137 /*
138  * Set up the signal handlers.
139  */
init_signals(int on)140 public void init_signals(int on)
141 {
142           if (on)
143           {
144                     /*
145                      * Set signal handlers.
146                      */
147 #if MSDOS_COMPILER==WIN32C
148                     SetConsoleCtrlHandler(wbreak_handler, TRUE);
149 #else
150                     (void) LSIGNAL(SIGINT, u_interrupt);
151 #endif
152 #ifdef SIGTSTP
153                     (void) LSIGNAL(SIGTSTP, !secure_allow(SF_STOP) ? SIG_IGN : 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 #if MSDOS_COMPILER==WIN32C
173                     SetConsoleCtrlHandler(wbreak_handler, FALSE);
174 #else
175                     (void) LSIGNAL(SIGINT, SIG_DFL);
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 #ifdef SIGTERM
190                     (void) LSIGNAL(SIGTERM, SIG_DFL);
191 #endif
192           }
193 }
194 
195 /*
196  * Process any signals we have received.
197  * A received signal cause a bit to be set in "sigs".
198  */
psignals(void)199 public void psignals(void)
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();
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                               calc_match_shift();
254                     }
255                     screen_trashed();
256           }
257 #endif
258           if (tsignals & S_INTERRUPT)
259           {
260                     if (quit_on_intr)
261                               quit(QUIT_INTERRUPT);
262                     getcc_clear();
263 #if MSDOS_COMPILER==WIN32C
264                     win32_getch_clear();
265 #endif
266           }
267 }
268