/* Copyright (c) 1990,1991,1992,1993 Chris and John Downey */

/***

* program name:
    xvi
* function:
    Portable version of UNIX "vi" editor, with extensions.
* module name:
    signal.c
* module function:
    Signal handling routines.

    This is all fairly system-dependent, & may be replaced by more
    system-specific routines if required. On MS-DOS, for instance,
    this module isn't used at all: ignore_signals() &
    catch_signals() are defined in msdos_c.c & msdos_a.asm instead.
* history:
    STEVIE - ST Editor for VI Enthusiasts, Version 3.10
    Originally by Tim Thompson (twitch!tjt)
    Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
    Heavily modified by Chris & John Downey
    Last modified by Martin Guy

***/

#include "xvi.h"

volatile	unsigned char	SIG_suspend_request;
volatile	unsigned char	SIG_user_disconnected;
volatile	unsigned char	SIG_terminate;

static	void	setsigcatcher P((int sig, void (*vec)()));

/*
 * Signal handlers.
 */
#ifdef	SIGINT
    static	void	int_handler P((int));
#endif
#ifdef	SIGTSTP
    static	void	tstp_handler P((int));
#endif
#ifdef	SIGHUP
    static	void	hup_handler P((int));
#endif
#ifdef SIGTERM
    static	void	term_handler P((int));
#endif

void
ignore_signals()
{
#ifdef	SIGINT
    (void) signal(SIGINT, SIG_IGN);
#endif
#ifdef SIGBREAK
    /*
     * On OS/2, this is generated by pressing control-break.
     */
    (void) signal(SIGBREAK, SIG_IGN);
#endif
#ifdef	SIGQUIT
    (void) signal(SIGQUIT, SIG_IGN);
#endif
#ifdef	SIGTSTP
    (void) signal(SIGTSTP, SIG_IGN);
#endif
    /*
     * There isn't much point in catching or ignoring SIGHUP
     * signals until we have some modified buffers to preserve.
     */
#ifdef SIGTERM
    (void) signal(SIGTERM, SIG_IGN);
#endif
}

void
catch_signals()
{
#ifdef	SIGINT
    setsigcatcher(SIGINT, int_handler);
#endif
#ifdef SIGBREAK
    /*
     * On OS/2, this is generated by pressing control-break.
     */
    setsigcatcher(SIGBREAK, int_handler);
#endif
#ifdef	SIGTSTP
    setsigcatcher(SIGTSTP, tstp_handler);
#endif
#ifdef SIGHUP
    setsigcatcher(SIGHUP, hup_handler);
#endif
#ifdef SIGTERM
    setsigcatcher(SIGTERM, term_handler);
#endif
}

static void
setsigcatcher(sig, handler)
int	sig;
void	(*handler)();
{
#ifdef	SV_INTERRUPT
    /*
     * Assume we have BSD-style sigvec(), and that blocking system calls
     * are by default restarted after a signal. We don't want this action,
     * we want the "old" action of returning -1 and errno=EINTR.
     */
    struct sigvec	vec;

    vec.sv_handler = handler;
    vec.sv_mask = sigmask(sig);
    vec.sv_flags = SV_INTERRUPT;
    (void) sigvec(sig, &vec, (struct sigvec *) NULL);

#else	/* no SV_INTERRUPT */

    (void) signal(sig, handler);

#endif	/* no SV_INTERRUPT */
}

/*
 * Handler for SIGINT (keyboard interrupt).
 */
#ifdef	SIGINT
/*ARGSUSED*/
static void
int_handler(sig)
int	sig;
{
    /*
     * POSIX: "If the standard input is not a terminal device,
     * ex shall not write the file or return to command or text input mode,
     * and shall exit with a non-zero exit status."
     */
    if (!isatty(0)) sys_exit(-SIGINT);

    (void) signal(SIGINT, int_handler);
    kbdintr = TRUE;
}
#endif

/*
 * This function is used on UNIX as the signal handler
 * for the keyboard-generated TSTP signal.
 */
#ifdef	SIGTSTP
/*ARGSUSED*/
static void
tstp_handler(sig)
int	sig;
{
    signal(SIGTSTP, tstp_handler);
    SIG_suspend_request = TRUE;
}
#endif

/*
 * This one is used for the hangup signal, which generally means that
 * the terminal line has gone dead.
 */
#ifdef	SIGHUP
/*ARGSUSED*/
static void
hup_handler(sig)
int	sig;
{
    (void) signal(SIGHUP, SIG_IGN);
    SIG_user_disconnected = TRUE;
}
#endif

/*
 * This one is used for the software-generated terminate signal.
 */
#ifdef SIGTERM
/*ARGSUSED*/
static void
term_handler(sig)
int	sig;
{
    (void) signal(SIGTERM, SIG_IGN);
    SIG_terminate = TRUE;
}
#endif
