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*/ 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*/ 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*/ 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 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 (void) type; 134 quit(15); 135 } 136 137 /* 138 * Set up the signal handlers. 139 */ 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 */ 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