signal.c revision 161478
120253Sjoerg/*
220302Sjoerg * Copyright (C) 1984-2004  Mark Nudelman
320302Sjoerg *
420253Sjoerg * You may distribute under the terms of either the GNU General Public
520253Sjoerg * License or the Less License, as specified in the README file.
620253Sjoerg *
720253Sjoerg * For more information about less, or for information on how to
820253Sjoerg * contact the author, see the README file.
920302Sjoerg */
1020253Sjoerg
1120253Sjoerg/* $FreeBSD: head/contrib/less/signal.c 161478 2006-08-20 15:50:51Z delphij $ */
1220253Sjoerg
1320253Sjoerg/*
1420302Sjoerg * Routines dealing with signals.
1520253Sjoerg *
1620253Sjoerg * A signal usually merely causes a bit to be set in the "signals" word.
1720302Sjoerg * At some convenient time, the mainline code checks to see if any
1820253Sjoerg * signals need processing by calling psignal().
1920253Sjoerg * If we happen to be reading from a file [in iread()] at the time
2020253Sjoerg * the signal is received, we call intread to interrupt the iread.
2120253Sjoerg */
2220253Sjoerg
2320253Sjoerg#include "less.h"
2420253Sjoerg#include <signal.h>
2544229Sdavidn
2620253Sjoerg/*
2720253Sjoerg * "sigs" contains bits indicating signals which need to be processed.
2830259Scharnier */
2930259Scharnierpublic int sigs;
3050479Speter
3130259Scharnierextern int sc_width, sc_height;
3230259Scharnierextern int screen_trashed;
3330259Scharnierextern int lnloop;
3430259Scharnierextern int linenums;
3520253Sjoergextern int wscroll;
3620253Sjoergextern int reading;
3720253Sjoergextern int quit_on_intr;
3830259Scharnierextern int more_mode;
3920253Sjoerg
4020555Sdavidn/*
4120555Sdavidn * Interrupt signal handler.
4220555Sdavidn */
4330259Scharnier	/* ARGSUSED*/
4422394Sdavidn	static RETSIGTYPE
4564918Sgreenu_interrupt(type)
4622394Sdavidn	int type;
4720555Sdavidn{
4822394Sdavidn#if OS2
4920253Sjoerg	LSIGNAL(SIGINT, SIG_ACK);
5020253Sjoerg#endif
5120253Sjoerg	LSIGNAL(SIGINT, u_interrupt);
5223318Sache	sigs |= S_INTERRUPT;
5322394Sdavidn#if MSDOS_COMPILER==DJGPPC
5422394Sdavidn	/*
5523318Sache	 * If a keyboard has been hit, it must be Ctrl-C
5622394Sdavidn	 * (as opposed to Ctrl-Break), so consume it.
5722394Sdavidn	 * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.)
5852512Sdavidn	 */
5924214Sache	if (kbhit())
6044386Sdavidn		getkey();
6120253Sjoerg#endif
6220253Sjoerg	if (more_mode)
6320253Sjoerg		quit(0);
6420253Sjoerg	if (reading)
6520253Sjoerg		intread();
6620253Sjoerg}
6720253Sjoerg
6820253Sjoerg#ifdef SIGTSTP
6920253Sjoerg/*
7085145Sache * "Stop" (^Z) signal handler.
7120253Sjoerg */
7220253Sjoerg	/* ARGSUSED*/
7320253Sjoerg	static RETSIGTYPE
7420253Sjoergstop(type)
7520253Sjoerg	int type;
7620253Sjoerg{
7720253Sjoerg	LSIGNAL(SIGTSTP, stop);
7820253Sjoerg	sigs |= S_STOP;
7920253Sjoerg	if (reading)
8020253Sjoerg		intread();
8120253Sjoerg}
8220253Sjoerg#endif
8320253Sjoerg
8420253Sjoerg#ifdef SIGWINCH
8520253Sjoerg/*
8620253Sjoerg * "Window" change handler
8720253Sjoerg */
8820253Sjoerg	/* ARGSUSED*/
89124382Siedowse	public RETSIGTYPE
9020253Sjoergwinch(type)
9120253Sjoerg	int type;
9220253Sjoerg{
9320253Sjoerg	LSIGNAL(SIGWINCH, winch);
9420253Sjoerg	sigs |= S_WINCH;
9520253Sjoerg	if (reading)
9620253Sjoerg		intread();
9720253Sjoerg}
9820253Sjoerg#else
9920253Sjoerg#ifdef SIGWIND
10020253Sjoerg/*
10120253Sjoerg * "Window" change handler
10220253Sjoerg */
10320253Sjoerg	/* ARGSUSED*/
10420253Sjoerg	public RETSIGTYPE
10520253Sjoergwinch(type)
10620253Sjoerg	int type;
10752527Sdavidn{
10820253Sjoerg	LSIGNAL(SIGWIND, winch);
10952512Sdavidn	sigs |= S_WINCH;
11020253Sjoerg	if (reading)
11120253Sjoerg		intread();
11220253Sjoerg}
11320253Sjoerg#endif
11420253Sjoerg#endif
11520253Sjoerg
11620747Sdavidn#if MSDOS_COMPILER==WIN32C
11782868Sdd/*
11820253Sjoerg * Handle CTRL-C and CTRL-BREAK keys.
11920253Sjoerg */
12020253Sjoerg#include "windows.h"
12120253Sjoerg
12220253Sjoerg	static BOOL WINAPI
12320253Sjoergwbreak_handler(dwCtrlType)
12420253Sjoerg	DWORD dwCtrlType;
12520253Sjoerg{
12620253Sjoerg	switch (dwCtrlType)
12720253Sjoerg	{
12856000Sdavidn	case CTRL_C_EVENT:
12920253Sjoerg	case CTRL_BREAK_EVENT:
13020253Sjoerg		sigs |= S_INTERRUPT;
13156000Sdavidn		return (TRUE);
13256000Sdavidn	default:
13356000Sdavidn		break;
13420253Sjoerg	}
13520253Sjoerg	return (FALSE);
13652512Sdavidn}
13720253Sjoerg#endif
13820267Sjoerg
13920267Sjoerg/*
14020267Sjoerg * Set up the signal handlers.
14120267Sjoerg */
14220267Sjoerg	public void
14320267Sjoerginit_signals(on)
14420267Sjoerg	int on;
14520267Sjoerg{
14620267Sjoerg	if (on)
14720267Sjoerg	{
14820267Sjoerg		/*
14920267Sjoerg		 * Set signal handlers.
15020267Sjoerg		 */
15120267Sjoerg		(void) LSIGNAL(SIGINT, u_interrupt);
15220253Sjoerg#if MSDOS_COMPILER==WIN32C
15320253Sjoerg		SetConsoleCtrlHandler(wbreak_handler, TRUE);
15420253Sjoerg#endif
15520253Sjoerg#ifdef SIGTSTP
15620267Sjoerg		(void) LSIGNAL(SIGTSTP, stop);
15720253Sjoerg#endif
15821052Sdavidn#ifdef SIGWINCH
15921052Sdavidn		(void) LSIGNAL(SIGWINCH, winch);
16021052Sdavidn#else
16121052Sdavidn#ifdef SIGWIND
16221052Sdavidn		(void) LSIGNAL(SIGWIND, winch);
16321052Sdavidn#endif
16421052Sdavidn#ifdef SIGQUIT
16521052Sdavidn		(void) LSIGNAL(SIGQUIT, SIG_IGN);
16621052Sdavidn#endif
16721052Sdavidn#endif
16821052Sdavidn	} else
16921052Sdavidn	{
17030259Scharnier		/*
17121052Sdavidn		 * Restore signals to defaults.
17221052Sdavidn		 */
17321052Sdavidn		(void) LSIGNAL(SIGINT, SIG_DFL);
17421052Sdavidn#if MSDOS_COMPILER==WIN32C
17521242Sdavidn		SetConsoleCtrlHandler(wbreak_handler, FALSE);
17621242Sdavidn#endif
17721242Sdavidn#ifdef SIGTSTP
17821242Sdavidn		(void) LSIGNAL(SIGTSTP, SIG_DFL);
17921242Sdavidn#endif
18021242Sdavidn#ifdef SIGWINCH
18121242Sdavidn		(void) LSIGNAL(SIGWINCH, SIG_IGN);
18221242Sdavidn#endif
18321242Sdavidn#ifdef SIGWIND
18421242Sdavidn		(void) LSIGNAL(SIGWIND, SIG_IGN);
18521242Sdavidn#endif
18621242Sdavidn#ifdef SIGQUIT
18721242Sdavidn		(void) LSIGNAL(SIGQUIT, SIG_DFL);
18821242Sdavidn#endif
18921242Sdavidn	}
19021052Sdavidn}
19121052Sdavidn
19221242Sdavidn/*
19321242Sdavidn * Process any signals we have received.
19421242Sdavidn * A received signal cause a bit to be set in "sigs".
19521242Sdavidn */
19621242Sdavidn	public void
19721242Sdavidnpsignals()
19821242Sdavidn{
19921242Sdavidn	register int tsignals;
20030259Scharnier
20121242Sdavidn	if ((tsignals = sigs) == 0)
20221242Sdavidn		return;
20321052Sdavidn	sigs = 0;
20421242Sdavidn
20521052Sdavidn#ifdef SIGTSTP
20630259Scharnier	if (tsignals & S_STOP)
20721052Sdavidn	{
20821052Sdavidn		/*
20921052Sdavidn		 * Clean up the terminal.
21021052Sdavidn		 */
21130259Scharnier#ifdef SIGTTOU
21221052Sdavidn		LSIGNAL(SIGTTOU, SIG_IGN);
21321052Sdavidn#endif
21420253Sjoerg		clear_bot();
21520253Sjoerg		deinit();
21620253Sjoerg		flush();
21721330Sdavidn		raw_mode(0);
21821330Sdavidn#ifdef SIGTTOU
21921330Sdavidn		LSIGNAL(SIGTTOU, SIG_DFL);
22020253Sjoerg#endif
22120253Sjoerg		LSIGNAL(SIGTSTP, SIG_DFL);
22220253Sjoerg		kill(getpid(), SIGTSTP);
22320253Sjoerg		/*
22463596Sdavidn		 * ... Bye bye. ...
22563596Sdavidn		 * Hopefully we'll be back later and resume here...
22663596Sdavidn		 * Reset the terminal and arrange to repaint the
22763596Sdavidn		 * screen when we get back to the main command loop.
22863596Sdavidn		 */
22963596Sdavidn		LSIGNAL(SIGTSTP, stop);
23063596Sdavidn		raw_mode(1);
23163596Sdavidn		init();
23220253Sjoerg		screen_trashed = 1;
23320253Sjoerg		tsignals |= S_WINCH;
23420253Sjoerg	}
23520679Sdavidn#endif
23620253Sjoerg#ifdef S_WINCH
23720253Sjoerg	if (tsignals & S_WINCH)
23852527Sdavidn	{
23920253Sjoerg		int old_width, old_height;
24020747Sdavidn		/*
24144229Sdavidn		 * Re-execute scrsize() to read the new window size.
24261957Sache		 */
24330259Scharnier		old_width = sc_width;
24420253Sjoerg		old_height = sc_height;
24520747Sdavidn		get_term();
24620747Sdavidn		if (sc_width != old_width || sc_height != old_height)
24720253Sjoerg		{
24820747Sdavidn			wscroll = (sc_height + 1) / 2;
24920253Sjoerg			screen_trashed = 1;
25020253Sjoerg		}
25152527Sdavidn	}
25220253Sjoerg#endif
25326088Sdavidn	if (tsignals & S_INTERRUPT)
25430259Scharnier	{
25520253Sjoerg		if (quit_on_intr)
25652527Sdavidn			quit(QUIT_OK);
25720253Sjoerg		bell();
25820253Sjoerg		/*
25920253Sjoerg		 * {{ You may wish to replace the bell() with
26063600Sdavidn		 *    error("Interrupt", NULL_PARG); }}
26163600Sdavidn		 */
26220253Sjoerg
26320253Sjoerg		/*
26430259Scharnier		 * If we were interrupted while in the "calculating
26520253Sjoerg		 * line numbers" loop, turn off line numbers.
26620253Sjoerg		 */
26720253Sjoerg		if (lnloop)
26820253Sjoerg		{
26920253Sjoerg			lnloop = 0;
27020253Sjoerg			if (linenums == 2)
27120253Sjoerg				screen_trashed = 1;
27220253Sjoerg			linenums = 0;
27320253Sjoerg			error("Line numbers turned off", NULL_PARG);
27420253Sjoerg		}
27520253Sjoerg
27620253Sjoerg	}
27720253Sjoerg}
27820253Sjoerg