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