1 /* 2 * Copyright (C) 1984-2023 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 int secure; 37 extern long jump_sline_fraction; 38 39 /* 40 * Interrupt signal handler. 41 */ 42 #if MSDOS_COMPILER!=WIN32C 43 /* ARGSUSED*/ 44 static RETSIGTYPE u_interrupt(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 HILITE_SEARCH 62 set_filter_pattern(NULL, 0); 63 #endif 64 if (reading) 65 intread(); /* May longjmp */ 66 } 67 #endif 68 69 #ifdef SIGTSTP 70 /* 71 * "Stop" (^Z) signal handler. 72 */ 73 /* ARGSUSED*/ 74 static RETSIGTYPE stop(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 winch(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 #define WIN32_LEAN_AND_MEAN 111 #include <windows.h> 112 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 131 static RETSIGTYPE terminate(int type) 132 { 133 quit(15); 134 } 135 136 /* 137 * Set up the signal handlers. 138 */ 139 public void init_signals(int on) 140 { 141 if (on) 142 { 143 /* 144 * Set signal handlers. 145 */ 146 #if MSDOS_COMPILER==WIN32C 147 SetConsoleCtrlHandler(wbreak_handler, TRUE); 148 #else 149 (void) LSIGNAL(SIGINT, u_interrupt); 150 #endif 151 #ifdef SIGTSTP 152 (void) LSIGNAL(SIGTSTP, secure ? SIG_IGN : stop); 153 #endif 154 #ifdef SIGWINCH 155 (void) LSIGNAL(SIGWINCH, winch); 156 #endif 157 #ifdef SIGWIND 158 (void) LSIGNAL(SIGWIND, winch); 159 #endif 160 #ifdef SIGQUIT 161 (void) LSIGNAL(SIGQUIT, SIG_IGN); 162 #endif 163 #ifdef SIGTERM 164 (void) LSIGNAL(SIGTERM, terminate); 165 #endif 166 } else 167 { 168 /* 169 * Restore signals to defaults. 170 */ 171 #if MSDOS_COMPILER==WIN32C 172 SetConsoleCtrlHandler(wbreak_handler, FALSE); 173 #else 174 (void) LSIGNAL(SIGINT, SIG_DFL); 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 psignals(void) 199 { 200 int tsignals; 201 202 if ((tsignals = sigs) == 0) 203 return; 204 sigs = 0; 205 206 #ifdef SIGTSTP 207 if (tsignals & S_STOP) 208 { 209 /* 210 * Clean up the terminal. 211 */ 212 #ifdef SIGTTOU 213 LSIGNAL(SIGTTOU, SIG_IGN); 214 #endif 215 clear_bot(); 216 deinit(); 217 flush(); 218 raw_mode(0); 219 #ifdef SIGTTOU 220 LSIGNAL(SIGTTOU, SIG_DFL); 221 #endif 222 LSIGNAL(SIGTSTP, SIG_DFL); 223 kill(getpid(), SIGTSTP); 224 /* 225 * ... Bye bye. ... 226 * Hopefully we'll be back later and resume here... 227 * Reset the terminal and arrange to repaint the 228 * screen when we get back to the main command loop. 229 */ 230 LSIGNAL(SIGTSTP, stop); 231 raw_mode(1); 232 init(); 233 screen_trashed = 1; 234 tsignals |= S_WINCH; 235 } 236 #endif 237 #ifdef S_WINCH 238 if (tsignals & S_WINCH) 239 { 240 int old_width, old_height; 241 /* 242 * Re-execute scrsize() to read the new window size. 243 */ 244 old_width = sc_width; 245 old_height = sc_height; 246 get_term(); 247 if (sc_width != old_width || sc_height != old_height) 248 { 249 wscroll = (sc_height + 1) / 2; 250 calc_jump_sline(); 251 calc_shift_count(); 252 } 253 screen_trashed = 1; 254 } 255 #endif 256 if (tsignals & S_INTERRUPT) 257 { 258 if (quit_on_intr) 259 quit(QUIT_INTERRUPT); 260 } 261 } 262