xref: /openbsd-src/gnu/usr.bin/texinfo/info/signals.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /* signals.c -- install and maintain Info signal handlers.
2    $Id: signals.c,v 1.1.1.3 2000/02/09 01:25:00 espie Exp $
3 
4    Copyright (C) 1993, 94, 95, 98 Free Software Foundation, Inc.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 
20    Written by Brian Fox (bfox@ai.mit.edu). */
21 
22 #include "info.h"
23 #include "signals.h"
24 
25 /* **************************************************************** */
26 /*                                                                  */
27 /*              Pretending That We Have POSIX Signals               */
28 /*                                                                  */
29 /* **************************************************************** */
30 
31 /* Non-zero when our signal handler has been called to handle SIGWINCH. */
32 static int in_sigwinch = 0;
33 
34 #if !defined (HAVE_SIGPROCMASK) && defined (HAVE_SIGSETMASK)
35 /* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
36 static void
37 sigprocmask (operation, newset, oldset)
38      int operation, *newset, *oldset;
39 {
40   switch (operation)
41     {
42     case SIG_UNBLOCK:
43       sigsetmask (sigblock (0) & ~(*newset));
44       break;
45 
46     case SIG_BLOCK:
47       *oldset = sigblock (*newset);
48       break;
49 
50     case SIG_SETMASK:
51       sigsetmask (*newset);
52       break;
53 
54     default:
55       abort ();
56     }
57 }
58 #endif /* !HAVE_SIGPROCMASK && HAVE_SIGSETMASK */
59 
60 /* **************************************************************** */
61 /*                                                                  */
62 /*                  Signal Handling for Info                        */
63 /*                                                                  */
64 /* **************************************************************** */
65 
66 typedef RETSIGTYPE signal_handler ();
67 
68 static RETSIGTYPE info_signal_handler ();
69 static signal_handler *old_TSTP, *old_TTOU, *old_TTIN;
70 static signal_handler *old_WINCH, *old_INT, *old_USR1;
71 
72 void
73 initialize_info_signal_handler ()
74 {
75 #if defined (SIGTSTP)
76   old_TSTP = (signal_handler *) signal (SIGTSTP, info_signal_handler);
77   old_TTOU = (signal_handler *) signal (SIGTTOU, info_signal_handler);
78   old_TTIN = (signal_handler *) signal (SIGTTIN, info_signal_handler);
79 #endif /* SIGTSTP */
80 
81 #if defined (SIGWINCH)
82   old_WINCH = (signal_handler *) signal (SIGWINCH, info_signal_handler);
83 #endif
84 
85 #if defined (SIGINT)
86   old_INT = (signal_handler *) signal (SIGINT, info_signal_handler);
87 #endif
88 
89 #if defined (SIGUSR1)
90   /* Used by DJGPP to simulate SIGTSTP on Ctrl-Z.  */
91   old_USR1 = (signal_handler *) signal (SIGUSR1, info_signal_handler);
92 #endif
93 }
94 
95 static void
96 redisplay_after_signal ()
97 {
98   terminal_clear_screen ();
99   display_clear_display (the_display);
100   window_mark_chain (windows, W_UpdateWindow);
101   display_update_display (windows);
102   display_cursor_at_point (active_window);
103   fflush (stdout);
104 }
105 
106 static void
107 reset_info_window_sizes ()
108 {
109   terminal_goto_xy (0, 0);
110   fflush (stdout);
111   terminal_unprep_terminal ();
112   terminal_get_screen_size ();
113   terminal_prep_terminal ();
114   display_initialize_display (screenwidth, screenheight);
115   window_new_screen_size (screenwidth, screenheight, NULL);
116   redisplay_after_signal ();
117 }
118 
119 static RETSIGTYPE
120 info_signal_handler (sig)
121      int sig;
122 {
123   signal_handler **old_signal_handler;
124 
125   switch (sig)
126     {
127 #if defined (SIGTSTP)
128     case SIGTSTP:
129     case SIGTTOU:
130     case SIGTTIN:
131 #endif
132 #if defined (SIGINT)
133     case SIGINT:
134 #endif
135       {
136 #if defined (SIGTSTP)
137         if (sig == SIGTSTP)
138           old_signal_handler = &old_TSTP;
139         if (sig == SIGTTOU)
140           old_signal_handler = &old_TTOU;
141         if (sig == SIGTTIN)
142           old_signal_handler = &old_TTIN;
143 #endif /* SIGTSTP */
144         if (sig == SIGINT)
145           old_signal_handler = &old_INT;
146 
147         /* For stop signals, restore the terminal IO, leave the cursor
148            at the bottom of the window, and stop us. */
149         terminal_goto_xy (0, screenheight - 1);
150         terminal_clear_to_eol ();
151         fflush (stdout);
152         terminal_unprep_terminal ();
153         signal (sig, *old_signal_handler);
154         UNBLOCK_SIGNAL (sig);
155         kill (getpid (), sig);
156 
157         /* The program is returning now.  Restore our signal handler,
158            turn on terminal handling, redraw the screen, and place the
159            cursor where it belongs. */
160         terminal_prep_terminal ();
161         *old_signal_handler = (signal_handler *) signal (sig, info_signal_handler);
162         redisplay_after_signal ();
163         fflush (stdout);
164       }
165       break;
166 
167 #if defined (SIGWINCH) || defined (SIGUSR1)
168 #ifdef SIGWINCH
169     case SIGWINCH:
170 #endif
171 #ifdef SIGUSR1
172     case SIGUSR1:
173 #endif
174       {
175         if (!in_sigwinch) {
176           in_sigwinch++;
177 
178           /* Turn off terminal IO, tell our parent that the window has changed,
179              then reinitialize the terminal and rebuild our windows. */
180 #ifdef SIGWINCH
181           if (sig == SIGWINCH)
182             old_signal_handler = &old_WINCH;
183 #endif
184 #ifdef SIGUSR1
185           if (sig == SIGUSR1)
186             old_signal_handler = &old_USR1;
187 #endif
188           terminal_goto_xy (0, 0);
189           fflush (stdout);
190           terminal_unprep_terminal ();
191           signal (sig, *old_signal_handler);
192           UNBLOCK_SIGNAL (sig);
193           kill (getpid (), sig);
194 
195           /* After our old signal handler returns... */
196           *old_signal_handler
197             = (signal_handler *) signal (sig, info_signal_handler);
198           terminal_prep_terminal ();
199           reset_info_window_sizes ();
200           in_sigwinch--;
201         }
202       }
203       break;
204 #endif /* SIGWINCH || SIGUSR1 */
205     }
206 }
207