signals.c revision 114478
1/* signals.c -- install and maintain Info signal handlers. 2 $Id: signals.c,v 1.4 2003/01/29 19:23:22 karl Exp $ 3 $FreeBSD: head/contrib/texinfo/info/signals.c 114478 2003-05-02 00:50:59Z ru $ 4 5 Copyright (C) 1993, 1994, 1995, 1998, 2002, 2003 Free Software 6 Foundation, Inc. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2, or (at your option) 11 any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 21 22 Written by Brian Fox (bfox@ai.mit.edu). */ 23 24#include "info.h" 25#include "signals.h" 26 27/* **************************************************************** */ 28/* */ 29/* Pretending That We Have POSIX Signals */ 30/* */ 31/* **************************************************************** */ 32 33#if !defined (HAVE_SIGPROCMASK) && defined (HAVE_SIGSETMASK) 34/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */ 35static void 36sigprocmask (operation, newset, oldset) 37 int operation, *newset, *oldset; 38{ 39 switch (operation) 40 { 41 case SIG_UNBLOCK: 42 sigsetmask (sigblock (0) & ~(*newset)); 43 break; 44 45 case SIG_BLOCK: 46 *oldset = sigblock (*newset); 47 break; 48 49 case SIG_SETMASK: 50 sigsetmask (*newset); 51 break; 52 53 default: 54 abort (); 55 } 56} 57#endif /* !HAVE_SIGPROCMASK && HAVE_SIGSETMASK */ 58 59/* **************************************************************** */ 60/* */ 61/* Signal Handling for Info */ 62/* */ 63/* **************************************************************** */ 64 65#if defined (HAVE_SIGACTION) || defined (HAVE_SIGPROCMASK) ||\ 66 defined (HAVE_SIGSETMASK) 67static void 68mask_termsig (set) 69 sigset_t *set; 70{ 71# if defined (SIGTSTP) 72 sigaddset (set, SIGTSTP); 73 sigaddset (set, SIGTTOU); 74 sigaddset (set, SIGTTIN); 75# endif 76# if defined (SIGWINCH) 77 sigaddset (set, SIGWINCH); 78# endif 79#if defined (SIGINT) 80 sigaddset (set, SIGINT); 81#endif 82# if defined (SIGUSR1) 83 sigaddset (set, SIGUSR1); 84# endif 85} 86#endif /* HAVE_SIGACTION || HAVE_SIGPROCMASK || HAVE_SIGSETMASK */ 87 88static RETSIGTYPE info_signal_proc (); 89#if defined (HAVE_SIGACTION) 90typedef struct sigaction signal_info; 91signal_info info_signal_handler; 92 93static void 94set_termsig (sig, old) 95 int sig; 96 signal_info *old; 97{ 98 sigaction (sig, &info_signal_handler, old); 99} 100 101static void 102restore_termsig (sig, saved) 103 int sig; 104 const signal_info *saved; 105{ 106 sigaction (sig, saved, NULL); 107} 108#else /* !HAVE_SIGACTION */ 109typedef RETSIGTYPE (*signal_info) (); 110#define set_termsig(sig, old) (void)(*(old) = signal (sig, info_signal_proc)) 111#define restore_termsig(sig, saved) (void)signal (sig, *(saved)) 112#define info_signal_handler info_signal_proc 113static int term_conf_busy = 0; 114#endif /* !HAVE_SIGACTION */ 115 116static signal_info old_TSTP, old_TTOU, old_TTIN; 117static signal_info old_WINCH, old_INT, old_USR1, old_CONT; 118 119void 120initialize_info_signal_handler () 121{ 122#if defined (HAVE_SIGACTION) 123 info_signal_handler.sa_handler = info_signal_proc; 124 info_signal_handler.sa_flags = 0; 125 mask_termsig (&info_signal_handler.sa_mask); 126#endif /* HAVE_SIGACTION */ 127 128#if defined (SIGTSTP) 129 set_termsig (SIGTSTP, &old_TSTP); 130 set_termsig (SIGTTOU, &old_TTOU); 131 set_termsig (SIGTTIN, &old_TTIN); 132#endif /* SIGTSTP */ 133 134#if defined (SIGWINCH) 135 set_termsig (SIGWINCH, &old_WINCH); 136#if defined (SIGCONT) 137 set_termsig (SIGCONT, &old_CONT); 138#endif 139#endif 140 141#if defined (SIGINT) 142 set_termsig (SIGINT, &old_INT); 143#endif 144 145#if defined (SIGUSR1) 146 /* Used by DJGPP to simulate SIGTSTP on Ctrl-Z. */ 147 set_termsig (SIGUSR1, &old_USR1); 148#endif 149} 150 151static void 152redisplay_after_signal () 153{ 154 terminal_clear_screen (); 155 display_clear_display (the_display); 156 window_mark_chain (windows, W_UpdateWindow); 157 display_update_display (windows); 158 display_cursor_at_point (active_window); 159 fflush (stdout); 160} 161 162static void 163reset_info_window_sizes () 164{ 165 terminal_goto_xy (0, 0); 166 fflush (stdout); 167 terminal_unprep_terminal (); 168 terminal_get_screen_size (); 169 terminal_prep_terminal (); 170 display_initialize_display (screenwidth, screenheight); 171 window_new_screen_size (screenwidth, screenheight, NULL); 172 redisplay_after_signal (); 173} 174 175static RETSIGTYPE 176info_signal_proc (sig) 177 int sig; 178{ 179 signal_info *old_signal_handler; 180 181#if !defined (HAVE_SIGACTION) 182 /* best effort: first increment this counter and later block signals */ 183 if (term_conf_busy) 184 return; 185 term_conf_busy++; 186#if defined (HAVE_SIGPROCMASK) || defined (HAVE_SIGSETMASK) 187 { 188 sigset_t nvar, ovar; 189 sigemptyset (&nvar); 190 mask_termsig (&nvar); 191 sigprocmask (SIG_BLOCK, &nvar, &ovar); 192 } 193#endif /* HAVE_SIGPROCMASK || HAVE_SIGSETMASK */ 194#endif /* !HAVE_SIGACTION */ 195 switch (sig) 196 { 197#if defined (SIGTSTP) 198 case SIGTSTP: 199 case SIGTTOU: 200 case SIGTTIN: 201#endif 202#if defined (SIGINT) 203 case SIGINT: 204#endif 205 { 206#if defined (SIGTSTP) 207 if (sig == SIGTSTP) 208 old_signal_handler = &old_TSTP; 209 if (sig == SIGTTOU) 210 old_signal_handler = &old_TTOU; 211 if (sig == SIGTTIN) 212 old_signal_handler = &old_TTIN; 213#endif /* SIGTSTP */ 214#if defined (SIGINT) 215 if (sig == SIGINT) 216 old_signal_handler = &old_INT; 217#endif /* SIGINT */ 218 219 /* For stop signals, restore the terminal IO, leave the cursor 220 at the bottom of the window, and stop us. */ 221 terminal_goto_xy (0, screenheight - 1); 222 terminal_clear_to_eol (); 223 fflush (stdout); 224 terminal_unprep_terminal (); 225 restore_termsig (sig, old_signal_handler); 226 UNBLOCK_SIGNAL (sig); 227 kill (getpid (), sig); 228 229 /* The program is returning now. Restore our signal handler, 230 turn on terminal handling, redraw the screen, and place the 231 cursor where it belongs. */ 232 terminal_prep_terminal (); 233 set_termsig (sig, old_signal_handler); 234 /* window size might be changed while sleeping */ 235 reset_info_window_sizes (); 236 } 237 break; 238 239#if defined (SIGWINCH) || defined (SIGUSR1) 240#ifdef SIGWINCH 241#ifdef SIGCONT 242 case SIGCONT: 243 /* pretend a SIGWINCH in case the terminal window size has changed 244 while we've been asleep */ 245 /* FALLTHROUGH */ 246#endif 247 case SIGWINCH: 248#endif 249#ifdef SIGUSR1 250 case SIGUSR1: 251#endif 252 { 253 /* Turn off terminal IO, tell our parent that the window has changed, 254 then reinitialize the terminal and rebuild our windows. */ 255#ifdef SIGWINCH 256 if (sig == SIGWINCH) 257 old_signal_handler = &old_WINCH; 258#ifdef SIGCONT 259 else if (sig == SIGCONT) 260 old_signal_handler = &old_CONT; 261#endif 262#endif 263#ifdef SIGUSR1 264 if (sig == SIGUSR1) 265 old_signal_handler = &old_USR1; 266#endif 267 terminal_goto_xy (0, 0); 268 fflush (stdout); 269 terminal_unprep_terminal (); /* needless? */ 270 restore_termsig (sig, old_signal_handler); 271 UNBLOCK_SIGNAL (sig); 272 kill (getpid (), sig); 273 274 /* After our old signal handler returns... */ 275 set_termsig (sig, old_signal_handler); /* needless? */ 276 terminal_prep_terminal (); 277 reset_info_window_sizes (); 278 } 279 break; 280#endif /* SIGWINCH || SIGUSR1 */ 281 } 282#if !defined (HAVE_SIGACTION) 283 /* at this time it is safer to perform unblock after decrement */ 284 term_conf_busy--; 285#if defined (HAVE_SIGPROCMASK) || defined (HAVE_SIGSETMASK) 286 { 287 sigset_t nvar, ovar; 288 sigemptyset (&nvar); 289 mask_termsig (&nvar); 290 sigprocmask (SIG_UNBLOCK, &nvar, &ovar); 291 } 292#endif /* HAVE_SIGPROCMASK || HAVE_SIGSETMASK */ 293#endif /* !HAVE_SIGACTION */ 294} 295/* vim: set sw=2 cino={1s>2sn-s^-se-s: */ 296