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 /* $FreeBSD$ */ 11 12 /* 13 * Routines dealing with signals. 14 * 15 * A signal usually merely causes a bit to be set in the "signals" word. 16 * At some convenient time, the mainline code checks to see if any 17 * signals need processing by calling psignal(). 18 * If we happen to be reading from a file [in iread()] at the time 19 * the signal is received, we call intread to interrupt the iread. 20 */ 21 22 #include "less.h" 23 #include <signal.h> 24 25 /* 26 * "sigs" contains bits indicating signals which need to be processed. 27 */ 28 public int sigs; 29 30 extern int sc_width, sc_height; 31 extern int linenums; 32 extern int wscroll; 33 extern int reading; 34 extern int quit_on_intr; 35 extern long jump_sline_fraction; 36 37 extern int less_is_more; 38 39 /* 40 * Interrupt signal handler. 41 */ 42 #if MSDOS_COMPILER!=WIN32C 43 /* ARGSUSED*/ 44 static RETSIGTYPE u_interrupt(int type) 45 { 46 (void) type; 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 (less_is_more) 63 quit(0); 64 #if HILITE_SEARCH 65 set_filter_pattern(NULL, 0); 66 #endif 67 if (reading) 68 intread(); /* May longjmp */ 69 } 70 #endif 71 72 #ifdef SIGTSTP 73 /* 74 * "Stop" (^Z) signal handler. 75 */ 76 /* ARGSUSED*/ 77 static RETSIGTYPE stop(int type) 78 { 79 (void) type; 80 LSIGNAL(SIGTSTP, stop); 81 sigs |= S_STOP; 82 if (reading) 83 intread(); 84 } 85 #endif 86 87 #undef SIG_LESSWINDOW 88 #ifdef SIGWINCH 89 #define SIG_LESSWINDOW SIGWINCH 90 #else 91 #ifdef SIGWIND 92 #define SIG_LESSWINDOW SIGWIND 93 #endif 94 #endif 95 96 #ifdef SIG_LESSWINDOW 97 /* 98 * "Window" change handler 99 */ 100 /* ARGSUSED*/ 101 public RETSIGTYPE winch(int type) 102 { 103 (void) type; 104 LSIGNAL(SIG_LESSWINDOW, winch); 105 sigs |= S_WINCH; 106 if (reading) 107 intread(); 108 } 109 #endif 110 111 #if MSDOS_COMPILER==WIN32C 112 /* 113 * Handle CTRL-C and CTRL-BREAK keys. 114 */ 115 #define WIN32_LEAN_AND_MEAN 116 #include <windows.h> 117 118 static BOOL WINAPI wbreak_handler(DWORD dwCtrlType) 119 { 120 switch (dwCtrlType) 121 { 122 case CTRL_C_EVENT: 123 case CTRL_BREAK_EVENT: 124 sigs |= S_INTERRUPT; 125 #if HILITE_SEARCH 126 set_filter_pattern(NULL, 0); 127 #endif 128 return (TRUE); 129 default: 130 break; 131 } 132 return (FALSE); 133 } 134 #endif 135 136 static RETSIGTYPE terminate(int type) 137 { 138 (void) type; 139 quit(15); 140 } 141 142 /* 143 * Set up the signal handlers. 144 */ 145 public void init_signals(int on) 146 { 147 if (on) 148 { 149 /* 150 * Set signal handlers. 151 */ 152 #if MSDOS_COMPILER==WIN32C 153 SetConsoleCtrlHandler(wbreak_handler, TRUE); 154 #else 155 (void) LSIGNAL(SIGINT, u_interrupt); 156 #endif 157 #ifdef SIGTSTP 158 (void) LSIGNAL(SIGTSTP, !secure_allow(SF_STOP) ? SIG_IGN : stop); 159 #endif 160 #ifdef SIGWINCH 161 (void) LSIGNAL(SIGWINCH, winch); 162 #endif 163 #ifdef SIGWIND 164 (void) LSIGNAL(SIGWIND, winch); 165 #endif 166 #ifdef SIGQUIT 167 (void) LSIGNAL(SIGQUIT, SIG_IGN); 168 #endif 169 #ifdef SIGTERM 170 (void) LSIGNAL(SIGTERM, terminate); 171 #endif 172 } else 173 { 174 /* 175 * Restore signals to defaults. 176 */ 177 #if MSDOS_COMPILER==WIN32C 178 SetConsoleCtrlHandler(wbreak_handler, FALSE); 179 #else 180 (void) LSIGNAL(SIGINT, SIG_DFL); 181 #endif 182 #ifdef SIGTSTP 183 (void) LSIGNAL(SIGTSTP, SIG_DFL); 184 #endif 185 #ifdef SIGWINCH 186 (void) LSIGNAL(SIGWINCH, SIG_IGN); 187 #endif 188 #ifdef SIGWIND 189 (void) LSIGNAL(SIGWIND, SIG_IGN); 190 #endif 191 #ifdef SIGQUIT 192 (void) LSIGNAL(SIGQUIT, SIG_DFL); 193 #endif 194 #ifdef SIGTERM 195 (void) LSIGNAL(SIGTERM, SIG_DFL); 196 #endif 197 } 198 } 199 200 /* 201 * Process any signals we have received. 202 * A received signal cause a bit to be set in "sigs". 203 */ 204 public void psignals(void) 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(); 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 screen_size_changed(); 257 } 258 screen_trashed(); 259 } 260 #endif 261 if (tsignals & S_INTERRUPT) 262 { 263 if (quit_on_intr) 264 quit(QUIT_INTERRUPT); 265 getcc_clear(); 266 #if MSDOS_COMPILER==WIN32C 267 win32_getch_clear(); 268 #endif 269 } 270 } 271