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 int 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 bell(); 45 #if OS2 46 LSIGNAL(SIGINT, SIG_ACK); 47 #endif 48 sigs |= S_INTERRUPT; 49 #if MSDOS_COMPILER==DJGPPC 50 /* 51 * If a keyboard has been hit, it must be Ctrl-C 52 * (as opposed to Ctrl-Break), so consume it. 53 * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.) 54 */ 55 if (kbhit()) 56 getkey(); 57 #endif 58 } 59 60 #ifdef SIGTSTP 61 /* 62 * "Stop" (^Z) signal handler. 63 */ 64 /* ARGSUSED*/ 65 static RETSIGTYPE 66 stop(type) 67 int type; 68 { 69 sigs |= S_STOP; 70 } 71 #endif 72 73 #ifdef SIGWINCH 74 /* 75 * "Window" change handler 76 */ 77 /* ARGSUSED*/ 78 public RETSIGTYPE 79 winch(type) 80 int type; 81 { 82 sigs |= S_WINCH; 83 } 84 #else 85 #ifdef SIGWIND 86 /* 87 * "Window" change handler 88 */ 89 /* ARGSUSED*/ 90 public RETSIGTYPE 91 winch(type) 92 int type; 93 { 94 sigs |= S_WINCH; 95 } 96 #endif 97 #endif 98 99 #if MSDOS_COMPILER==WIN32C 100 /* 101 * Handle CTRL-C and CTRL-BREAK keys. 102 */ 103 #include "windows.h" 104 105 static BOOL WINAPI 106 wbreak_handler(dwCtrlType) 107 DWORD dwCtrlType; 108 { 109 switch (dwCtrlType) 110 { 111 case CTRL_C_EVENT: 112 case CTRL_BREAK_EVENT: 113 sigs |= S_INTERRUPT; 114 return (TRUE); 115 default: 116 break; 117 } 118 return (FALSE); 119 } 120 #endif 121 122 /* 123 * Set up the signal handlers. 124 */ 125 public void 126 init_signals(on) 127 int on; 128 { 129 if (on) 130 { 131 /* 132 * Set signal handlers. 133 */ 134 (void) LSIGNAL(SIGINT, u_interrupt); 135 #if MSDOS_COMPILER==WIN32C 136 SetConsoleCtrlHandler(wbreak_handler, TRUE); 137 #endif 138 #ifdef SIGTSTP 139 (void) LSIGNAL(SIGTSTP, stop); 140 #endif 141 #ifdef SIGWINCH 142 (void) LSIGNAL(SIGWINCH, winch); 143 #endif 144 #ifdef SIGWIND 145 (void) LSIGNAL(SIGWIND, winch); 146 #endif 147 #ifdef SIGQUIT 148 (void) LSIGNAL(SIGQUIT, SIG_IGN); 149 #endif 150 } else 151 { 152 /* 153 * Restore signals to defaults. 154 */ 155 (void) LSIGNAL(SIGINT, SIG_DFL); 156 #if MSDOS_COMPILER==WIN32C 157 SetConsoleCtrlHandler(wbreak_handler, FALSE); 158 #endif 159 #ifdef SIGTSTP 160 (void) LSIGNAL(SIGTSTP, SIG_DFL); 161 #endif 162 #ifdef SIGWINCH 163 (void) LSIGNAL(SIGWINCH, SIG_IGN); 164 #endif 165 #ifdef SIGWIND 166 (void) LSIGNAL(SIGWIND, SIG_IGN); 167 #endif 168 #ifdef SIGQUIT 169 (void) LSIGNAL(SIGQUIT, SIG_DFL); 170 #endif 171 } 172 } 173 174 /* 175 * Process any signals we have received. 176 * A received signal cause a bit to be set in "sigs". 177 */ 178 public void 179 psignals() 180 { 181 register int tsignals; 182 183 if ((tsignals = sigs) == 0) 184 return; 185 sigs = 0; 186 187 #ifdef SIGTSTP 188 if (tsignals & S_STOP) 189 { 190 /* 191 * Clean up the terminal. 192 */ 193 #ifdef SIGTTOU 194 LSIGNAL(SIGTTOU, SIG_IGN); 195 #endif 196 clear_bot(); 197 deinit(); 198 flush(); 199 raw_mode(0); 200 #ifdef SIGTTOU 201 LSIGNAL(SIGTTOU, SIG_DFL); 202 #endif 203 LSIGNAL(SIGTSTP, SIG_DFL); 204 kill(getpid(), SIGTSTP); 205 /* 206 * ... Bye bye. ... 207 * Hopefully we'll be back later and resume here... 208 * Reset the terminal and arrange to repaint the 209 * screen when we get back to the main command loop. 210 */ 211 LSIGNAL(SIGTSTP, stop); 212 raw_mode(1); 213 init(); 214 screen_trashed = 1; 215 tsignals |= S_WINCH; 216 } 217 #endif 218 #ifdef S_WINCH 219 if (tsignals & S_WINCH) 220 { 221 int old_width, old_height; 222 /* 223 * Re-execute scrsize() to read the new window size. 224 */ 225 old_width = sc_width; 226 old_height = sc_height; 227 get_term(); 228 if (sc_width != old_width || sc_height != old_height) 229 { 230 wscroll = (sc_height + 1) / 2; 231 calc_jump_sline(); 232 calc_shift_count(); 233 screen_trashed = 1; 234 } 235 } 236 #endif 237 if (tsignals & S_INTERRUPT) 238 { 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