1 /* 2 * Copyright (C) 1984-2002 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 34 /* 35 * Interrupt signal handler. 36 */ 37 /* ARGSUSED*/ 38 static RETSIGTYPE 39 u_interrupt(type) 40 int type; 41 { 42 #if OS2 43 LSIGNAL(SIGINT, SIG_ACK); 44 #endif 45 sigs |= S_INTERRUPT; 46 #if MSDOS_COMPILER==DJGPPC 47 /* 48 * If a keyboard has been hit, it must be Ctrl-C 49 * (as opposed to Ctrl-Break), so consume it. 50 * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.) 51 */ 52 if (kbhit()) 53 getkey(); 54 #endif 55 } 56 57 #ifdef SIGTSTP 58 /* 59 * "Stop" (^Z) signal handler. 60 */ 61 /* ARGSUSED*/ 62 static RETSIGTYPE 63 stop(type) 64 int type; 65 { 66 sigs |= S_STOP; 67 } 68 #endif 69 70 #ifdef SIGWINCH 71 /* 72 * "Window" change handler 73 */ 74 /* ARGSUSED*/ 75 public RETSIGTYPE 76 winch(type) 77 int type; 78 { 79 sigs |= S_WINCH; 80 } 81 #else 82 #ifdef SIGWIND 83 /* 84 * "Window" change handler 85 */ 86 /* ARGSUSED*/ 87 public RETSIGTYPE 88 winch(type) 89 int type; 90 { 91 sigs |= S_WINCH; 92 } 93 #endif 94 #endif 95 96 #if MSDOS_COMPILER==WIN32C 97 /* 98 * Handle CTRL-C and CTRL-BREAK keys. 99 */ 100 #include "windows.h" 101 102 static BOOL WINAPI 103 wbreak_handler(dwCtrlType) 104 DWORD dwCtrlType; 105 { 106 switch (dwCtrlType) 107 { 108 case CTRL_C_EVENT: 109 case CTRL_BREAK_EVENT: 110 sigs |= S_INTERRUPT; 111 return (TRUE); 112 default: 113 break; 114 } 115 return (FALSE); 116 } 117 #endif 118 119 /* 120 * Set up the signal handlers. 121 */ 122 public void 123 init_signals(on) 124 int on; 125 { 126 if (on) 127 { 128 /* 129 * Set signal handlers. 130 */ 131 (void) LSIGNAL(SIGINT, u_interrupt); 132 #if MSDOS_COMPILER==WIN32C 133 SetConsoleCtrlHandler(wbreak_handler, TRUE); 134 #endif 135 #ifdef SIGTSTP 136 (void) LSIGNAL(SIGTSTP, stop); 137 #endif 138 #ifdef SIGWINCH 139 (void) LSIGNAL(SIGWINCH, winch); 140 #else 141 #ifdef SIGWIND 142 (void) LSIGNAL(SIGWIND, winch); 143 #endif 144 #ifdef SIGQUIT 145 (void) LSIGNAL(SIGQUIT, SIG_IGN); 146 #endif 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 screen_trashed = 1; 230 } 231 } 232 #endif 233 if (tsignals & S_INTERRUPT) 234 { 235 bell(); 236 /* 237 * {{ You may wish to replace the bell() with 238 * error("Interrupt", NULL_PARG); }} 239 */ 240 241 /* 242 * If we were interrupted while in the "calculating 243 * line numbers" loop, turn off line numbers. 244 */ 245 if (lnloop) 246 { 247 lnloop = 0; 248 if (linenums == OPT_ONPLUS) 249 screen_trashed = 1; 250 linenums = 0; 251 error("Line numbers turned off", NULL_PARG); 252 } 253 254 } 255 } 256 257 /* 258 * Custom version of signal() that causes syscalls to be interrupted. 259 */ 260 public void 261 (*lsignal(s, a))() 262 int s; 263 void (*a) (); 264 { 265 struct sigaction sa, osa; 266 267 sa.sa_handler = a; 268 sigemptyset(&sa.sa_mask); 269 sa.sa_flags = 0; /* don't restart system calls */ 270 if (sigaction(s, &sa, &osa) != 0) 271 return (SIG_ERR); 272 return (osa.sa_handler); 273 } 274