1 /* $NetBSD: signal.c,v 1.5 2023/10/06 05:49:49 simonb Exp $ */ 2 3 /* 4 * Copyright (C) 1984-2023 Mark Nudelman 5 * 6 * You may distribute under the terms of either the GNU General Public 7 * License or the Less License, as specified in the README file. 8 * 9 * For more information, see the README file. 10 */ 11 12 13 /* 14 * Routines dealing with signals. 15 * 16 * A signal usually merely causes a bit to be set in the "signals" word. 17 * At some convenient time, the mainline code checks to see if any 18 * signals need processing by calling psignal(). 19 * If we happen to be reading from a file [in iread()] at the time 20 * the signal is received, we call intread to interrupt the iread. 21 */ 22 23 #include "less.h" 24 #include <signal.h> 25 26 /* 27 * "sigs" contains bits indicating signals which need to be processed. 28 */ 29 public int sigs; 30 31 static RETSIGTYPE u_interrupt __P((int)); 32 static RETSIGTYPE stop __P((int)); 33 #if MSDOS_COMPILER==WIN32C 34 static BOOL WINAPI wbreak_handler __P((DWORD)); 35 #endif 36 37 extern int sc_width, sc_height; 38 extern int screen_trashed; 39 extern int lnloop; 40 extern int linenums; 41 extern int wscroll; 42 extern int reading; 43 extern int quit_on_intr; 44 extern int secure; 45 extern long jump_sline_fraction; 46 47 /* 48 * Interrupt signal handler. 49 */ 50 #if MSDOS_COMPILER!=WIN32C 51 /* ARGSUSED*/ 52 static RETSIGTYPE u_interrupt(int type) 53 { 54 bell(); 55 #if OS2 56 LSIGNAL(SIGINT, SIG_ACK); 57 #endif 58 LSIGNAL(SIGINT, u_interrupt); 59 sigs |= S_INTERRUPT; 60 #if MSDOS_COMPILER==DJGPPC 61 /* 62 * If a keyboard has been hit, it must be Ctrl-C 63 * (as opposed to Ctrl-Break), so consume it. 64 * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.) 65 */ 66 if (kbhit()) 67 getkey(); 68 #endif 69 #if HILITE_SEARCH 70 set_filter_pattern(NULL, 0); 71 #endif 72 if (reading) 73 intread(); /* May longjmp */ 74 } 75 #endif 76 77 #ifdef SIGTSTP 78 /* 79 * "Stop" (^Z) signal handler. 80 */ 81 /* ARGSUSED*/ 82 static RETSIGTYPE stop(int type) 83 { 84 LSIGNAL(SIGTSTP, stop); 85 sigs |= S_STOP; 86 if (reading) 87 intread(); 88 } 89 #endif 90 91 #undef SIG_LESSWINDOW 92 #ifdef SIGWINCH 93 #define SIG_LESSWINDOW SIGWINCH 94 #else 95 #ifdef SIGWIND 96 #define SIG_LESSWINDOW SIGWIND 97 #endif 98 #endif 99 100 #ifdef SIG_LESSWINDOW 101 /* 102 * "Window" change handler 103 */ 104 /* ARGSUSED*/ 105 public RETSIGTYPE winch(int type) 106 { 107 LSIGNAL(SIG_LESSWINDOW, winch); 108 sigs |= S_WINCH; 109 if (reading) 110 intread(); 111 } 112 #endif 113 114 #if MSDOS_COMPILER==WIN32C 115 /* 116 * Handle CTRL-C and CTRL-BREAK keys. 117 */ 118 #define WIN32_LEAN_AND_MEAN 119 #include <windows.h> 120 121 static BOOL WINAPI wbreak_handler(DWORD dwCtrlType) 122 { 123 switch (dwCtrlType) 124 { 125 case CTRL_C_EVENT: 126 case CTRL_BREAK_EVENT: 127 sigs |= S_INTERRUPT; 128 #if HILITE_SEARCH 129 set_filter_pattern(NULL, 0); 130 #endif 131 return (TRUE); 132 default: 133 break; 134 } 135 return (FALSE); 136 } 137 #endif 138 139 static RETSIGTYPE terminate(int type) 140 { 141 quit(15); 142 } 143 144 /* 145 * Set up the signal handlers. 146 */ 147 public void init_signals(int on) 148 { 149 if (on) 150 { 151 /* 152 * Set signal handlers. 153 */ 154 #if MSDOS_COMPILER==WIN32C 155 SetConsoleCtrlHandler(wbreak_handler, TRUE); 156 #else 157 (void) LSIGNAL(SIGINT, u_interrupt); 158 #endif 159 #ifdef SIGTSTP 160 (void) LSIGNAL(SIGTSTP, secure ? SIG_IGN : stop); 161 #endif 162 #ifdef SIGWINCH 163 (void) LSIGNAL(SIGWINCH, winch); 164 #endif 165 #ifdef SIGWIND 166 (void) LSIGNAL(SIGWIND, winch); 167 #endif 168 #ifdef SIGQUIT 169 (void) LSIGNAL(SIGQUIT, SIG_IGN); 170 #endif 171 #ifdef SIGTERM 172 (void) LSIGNAL(SIGTERM, terminate); 173 #endif 174 } else 175 { 176 /* 177 * Restore signals to defaults. 178 */ 179 #if MSDOS_COMPILER==WIN32C 180 SetConsoleCtrlHandler(wbreak_handler, FALSE); 181 #else 182 (void) LSIGNAL(SIGINT, SIG_DFL); 183 #endif 184 #ifdef SIGTSTP 185 (void) LSIGNAL(SIGTSTP, SIG_DFL); 186 #endif 187 #ifdef SIGWINCH 188 (void) LSIGNAL(SIGWINCH, SIG_IGN); 189 #endif 190 #ifdef SIGWIND 191 (void) LSIGNAL(SIGWIND, SIG_IGN); 192 #endif 193 #ifdef SIGQUIT 194 (void) LSIGNAL(SIGQUIT, SIG_DFL); 195 #endif 196 #ifdef SIGTERM 197 (void) LSIGNAL(SIGTERM, SIG_DFL); 198 #endif 199 } 200 } 201 202 /* 203 * Process any signals we have received. 204 * A received signal cause a bit to be set in "sigs". 205 */ 206 public void psignals(void) 207 { 208 int tsignals; 209 210 if ((tsignals = sigs) == 0) 211 return; 212 sigs = 0; 213 214 #ifdef SIGTSTP 215 if (tsignals & S_STOP) 216 { 217 /* 218 * Clean up the terminal. 219 */ 220 #ifdef SIGTTOU 221 LSIGNAL(SIGTTOU, SIG_IGN); 222 #endif 223 clear_bot(); 224 deinit(); 225 flush(); 226 raw_mode(0); 227 #ifdef SIGTTOU 228 LSIGNAL(SIGTTOU, SIG_DFL); 229 #endif 230 LSIGNAL(SIGTSTP, SIG_DFL); 231 kill(getpid(), SIGTSTP); 232 /* 233 * ... Bye bye. ... 234 * Hopefully we'll be back later and resume here... 235 * Reset the terminal and arrange to repaint the 236 * screen when we get back to the main command loop. 237 */ 238 LSIGNAL(SIGTSTP, stop); 239 raw_mode(1); 240 init(); 241 screen_trashed = 1; 242 tsignals |= S_WINCH; 243 } 244 #endif 245 #ifdef S_WINCH 246 if (tsignals & S_WINCH) 247 { 248 int old_width, old_height; 249 /* 250 * Re-execute scrsize() to read the new window size. 251 */ 252 old_width = sc_width; 253 old_height = sc_height; 254 get_term(); 255 if (sc_width != old_width || sc_height != old_height) 256 { 257 wscroll = (sc_height + 1) / 2; 258 calc_jump_sline(); 259 calc_shift_count(); 260 } 261 screen_trashed = 1; 262 } 263 #endif 264 if (tsignals & S_INTERRUPT) 265 { 266 if (quit_on_intr) 267 quit(QUIT_INTERRUPT); 268 } 269 } 270