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