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