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