1 /* 2 * Copyright (C) 1984-2011 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 about less, or for information on how to 8 * contact the author, see the README file. 9 */ 10 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 */ 19 20 #include "less.h" 21 #include <signal.h> 22 23 /* 24 * "sigs" contains bits indicating signals which need to be processed. 25 */ 26 public volatile sig_atomic_t sigs; 27 28 extern int sc_width, sc_height; 29 extern int screen_trashed; 30 extern int lnloop; 31 extern int linenums; 32 extern int wscroll; 33 extern int quit_on_intr; 34 extern long jump_sline_fraction; 35 36 /* 37 * Interrupt signal handler. 38 */ 39 /* ARGSUSED*/ 40 static RETSIGTYPE 41 u_interrupt(type) 42 int type; 43 { 44 #if OS2 45 LSIGNAL(SIGINT, SIG_ACK); 46 #endif 47 sigs |= S_INTERRUPT; 48 #if MSDOS_COMPILER==DJGPPC 49 /* 50 * If a keyboard has been hit, it must be Ctrl-C 51 * (as opposed to Ctrl-Break), so consume it. 52 * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.) 53 */ 54 if (kbhit()) 55 getkey(); 56 #endif 57 } 58 59 #ifdef SIGTSTP 60 /* 61 * "Stop" (^Z) signal handler. 62 */ 63 /* ARGSUSED*/ 64 static RETSIGTYPE 65 stop(type) 66 int type; 67 { 68 sigs |= S_STOP; 69 } 70 #endif 71 72 #ifdef SIGWINCH 73 /* 74 * "Window" change handler 75 */ 76 /* ARGSUSED*/ 77 public RETSIGTYPE 78 winch(type) 79 int type; 80 { 81 sigs |= S_WINCH; 82 } 83 #else 84 #ifdef SIGWIND 85 /* 86 * "Window" change handler 87 */ 88 /* ARGSUSED*/ 89 public RETSIGTYPE 90 winch(type) 91 int type; 92 { 93 sigs |= S_WINCH; 94 } 95 #endif 96 #endif 97 98 #if MSDOS_COMPILER==WIN32C 99 /* 100 * Handle CTRL-C and CTRL-BREAK keys. 101 */ 102 #include "windows.h" 103 104 static BOOL WINAPI 105 wbreak_handler(dwCtrlType) 106 DWORD dwCtrlType; 107 { 108 switch (dwCtrlType) 109 { 110 case CTRL_C_EVENT: 111 case CTRL_BREAK_EVENT: 112 sigs |= S_INTERRUPT; 113 return (TRUE); 114 default: 115 break; 116 } 117 return (FALSE); 118 } 119 #endif 120 121 /* 122 * Set up the signal handlers. 123 */ 124 public void 125 init_signals(on) 126 int on; 127 { 128 if (on) 129 { 130 /* 131 * Set signal handlers. 132 */ 133 (void) LSIGNAL(SIGINT, u_interrupt); 134 #if MSDOS_COMPILER==WIN32C 135 SetConsoleCtrlHandler(wbreak_handler, TRUE); 136 #endif 137 #ifdef SIGTSTP 138 (void) LSIGNAL(SIGTSTP, stop); 139 #endif 140 #ifdef SIGWINCH 141 (void) LSIGNAL(SIGWINCH, winch); 142 #endif 143 #ifdef SIGWIND 144 (void) LSIGNAL(SIGWIND, winch); 145 #endif 146 #ifdef SIGQUIT 147 (void) LSIGNAL(SIGQUIT, SIG_IGN); 148 #endif 149 } else 150 { 151 /* 152 * Restore signals to defaults. 153 */ 154 (void) LSIGNAL(SIGINT, SIG_DFL); 155 #if MSDOS_COMPILER==WIN32C 156 SetConsoleCtrlHandler(wbreak_handler, FALSE); 157 #endif 158 #ifdef SIGTSTP 159 (void) LSIGNAL(SIGTSTP, SIG_DFL); 160 #endif 161 #ifdef SIGWINCH 162 (void) LSIGNAL(SIGWINCH, SIG_IGN); 163 #endif 164 #ifdef SIGWIND 165 (void) LSIGNAL(SIGWIND, SIG_IGN); 166 #endif 167 #ifdef SIGQUIT 168 (void) LSIGNAL(SIGQUIT, SIG_DFL); 169 #endif 170 } 171 } 172 173 /* 174 * Process any signals we have received. 175 * A received signal cause a bit to be set in "sigs". 176 */ 177 public void 178 psignals() 179 { 180 register int tsignals; 181 182 if ((tsignals = sigs) == 0) 183 return; 184 sigs = 0; 185 186 #ifdef SIGTSTP 187 if (tsignals & S_STOP) 188 { 189 /* 190 * Clean up the terminal. 191 */ 192 #ifdef SIGTTOU 193 LSIGNAL(SIGTTOU, SIG_IGN); 194 #endif 195 clear_bot(); 196 deinit(); 197 flush(); 198 raw_mode(0); 199 #ifdef SIGTTOU 200 LSIGNAL(SIGTTOU, SIG_DFL); 201 #endif 202 LSIGNAL(SIGTSTP, SIG_DFL); 203 kill(getpid(), SIGTSTP); 204 /* 205 * ... Bye bye. ... 206 * Hopefully we'll be back later and resume here... 207 * Reset the terminal and arrange to repaint the 208 * screen when we get back to the main command loop. 209 */ 210 LSIGNAL(SIGTSTP, stop); 211 raw_mode(1); 212 init(); 213 screen_trashed = 1; 214 tsignals |= S_WINCH; 215 } 216 #endif 217 #ifdef S_WINCH 218 if (tsignals & S_WINCH) 219 { 220 int old_width, old_height; 221 /* 222 * Re-execute scrsize() to read the new window size. 223 */ 224 old_width = sc_width; 225 old_height = sc_height; 226 get_term(); 227 if (sc_width != old_width || sc_height != old_height) 228 { 229 wscroll = (sc_height + 1) / 2; 230 calc_jump_sline(); 231 calc_shift_count(); 232 screen_trashed = 1; 233 } 234 } 235 #endif 236 if (tsignals & S_INTERRUPT) 237 { 238 bell(); 239 if (quit_on_intr) 240 quit(QUIT_INTERRUPT); 241 } 242 } 243 244 /* 245 * Custom version of signal() that causes syscalls to be interrupted. 246 */ 247 public void 248 (*lsignal(s, a))() 249 int s; 250 void (*a) (); 251 { 252 struct sigaction sa, osa; 253 254 sa.sa_handler = a; 255 sigemptyset(&sa.sa_mask); 256 sa.sa_flags = 0; /* don't restart system calls */ 257 if (sigaction(s, &sa, &osa) != 0) 258 return (SIG_ERR); 259 return (osa.sa_handler); 260 } 261