/* signals.c -- signal handling support for readline. */
/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
This file is part of the GNU Readline Library, a library for
reading lines of text with interactive input and history editing.
The GNU Readline Library is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 1, or
(at your option) any later version.
The GNU Readline Library is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
The GNU General Public License is often shipped with GNU software, and
is generally kept in a file called COPYING or LICENSE. If you do not
have a copy of the license, write to the Free Software Foundation,
675 Mass Ave, Cambridge, MA 02139, USA. */
#define READLINE_LIBRARY
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#if !defined (NO_SYS_FILE)
#include <sys/file.h>
#endif /* !NO_SYS_FILE */
#include <signal.h>
#if defined (HAVE_UNISTD_H)
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
#if defined (HAVE_STDLIB_H)
#include <stdlib.h>
#else
#include "ansi_stdlib.h"
#endif /* HAVE_STDLIB_H */
#include <errno.h>
/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
#if !defined (errno)
extern int errno;
#endif /* !errno */
#include "posixstat.h"
/* System-specific feature definitions and include files. */
#include "rldefs.h"
#if defined (GWINSZ_IN_SYS_IOCTL)
#include <sys/ioctl.h>
#endif /* GWINSZ_IN_SYS_IOCTL */
/* Some standard library routines. */
#include "readline.h"
#include "history.h"
static void cr();
extern int readline_echoing_p;
extern int rl_pending_input;
extern char *term_cr;
extern int _rl_meta_flag;
extern int _rl_output_character_function();
extern void free_undo_list();
#if defined (VOID_SIGHANDLER)
#define sighandler void
#else
#define sighandler int
#endif /* VOID_SIGHANDLER */
/* This typedef is equivalant to the one for Function; it allows us
to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */
typedef sighandler SigHandler();
#if defined (__GO32__)
#undef HANDLE_SIGNALS
#endif /* __GO32__ */
#if defined (STATIC_MALLOC)
static char *xmalloc(), *xrealloc();
#else
extern char *xmalloc(), *xrealloc();
#endif /* STATIC_MALLOC */
/* **************************************************************** */
/* */
/* Signal Handling */
/* */
/* **************************************************************** */
#if defined (SIGWINCH)
static SigHandler *old_sigwinch = (SigHandler *) NULL;
static sighandler
rl_handle_sigwinch(sig)
int sig;
{
if (readline_echoing_p) {
_rl_set_screen_size(fileno(rl_instream), 1);
cr(); /* was crlf () */
rl_forced_update_display();
}
if (old_sigwinch &&
old_sigwinch != (SigHandler *) SIG_IGN &&
old_sigwinch != (SigHandler *) SIG_DFL)
(*old_sigwinch) (sig);
#if !defined (VOID_SIGHANDLER)
return (0);
#endif /* VOID_SIGHANDLER */
}
#endif /* SIGWINCH */
#if defined (HANDLE_SIGNALS)
/* Interrupt handling. */
static SigHandler
* old_int = (SigHandler *) NULL, *old_alrm = (SigHandler *) NULL;
#if !defined (SHELL)
static SigHandler
* old_tstp = (SigHandler *) NULL, *old_ttou = (SigHandler *) NULL, *old_ttin = (SigHandler *) NULL,
*old_cont = (SigHandler *) NULL;
#endif /* !SHELL */
/* Handle an interrupt character. */
static sighandler
rl_signal_handler(sig)
int sig;
{
#if defined (HAVE_POSIX_SIGNALS)
sigset_t set;
#else /* !HAVE_POSIX_SIGNALS */
#if defined (HAVE_BSD_SIGNALS)
long omask;
#endif /* HAVE_BSD_SIGNALS */
#endif /* !HAVE_POSIX_SIGNALS */
#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS)
/* Since the signal will not be blocked while we are in the signal
handler, ignore it until rl_clear_signals resets the catcher. */
if (sig == SIGINT)
signal(sig, SIG_IGN);
#endif /* !HAVE_BSD_SIGNALS */
switch (sig) {
case SIGINT:
{
register HIST_ENTRY *entry;
free_undo_list();
entry = current_history();
if (entry)
entry->data = (char *) NULL;
}
_rl_kill_kbd_macro();
rl_clear_message();
rl_init_argument();
#if defined (SIGTSTP)
case SIGTSTP:
case SIGTTOU:
case SIGTTIN:
#endif /* SIGTSTP */
case SIGALRM:
rl_clean_up_for_exit();
rl_deprep_terminal();
rl_clear_signals();
rl_pending_input = 0;
#if defined (HAVE_POSIX_SIGNALS)
sigprocmask(SIG_BLOCK, (sigset_t *) NULL, &set);
sigdelset(&set, sig);
#else /* !HAVE_POSIX_SIGNALS */
#if defined (HAVE_BSD_SIGNALS)
omask = sigblock(0);
#endif /* HAVE_BSD_SIGNALS */
#endif /* !HAVE_POSIX_SIGNALS */
kill(getpid(), sig);
/* Let the signal that we just sent through. */
#if defined (HAVE_POSIX_SIGNALS)
sigprocmask(SIG_SETMASK, &set, (sigset_t *) NULL);
#else /* !HAVE_POSIX_SIGNALS */
#if defined (HAVE_BSD_SIGNALS)
sigsetmask(omask & ~(sigmask(sig)));
#endif /* HAVE_BSD_SIGNALS */
#endif /* !HAVE_POSIX_SIGNALS */
rl_prep_terminal(_rl_meta_flag);
rl_set_signals();
}
#if !defined (VOID_SIGHANDLER)
return (0);
#endif /* !VOID_SIGHANDLER */
}
#if defined (HAVE_POSIX_SIGNALS)
static SigHandler *
rl_set_sighandler(sig, handler)
int sig;
SigHandler *handler;
{
struct sigaction act, oact;
act.sa_handler = handler;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigemptyset(&oact.sa_mask);
sigaction(sig, &act, &oact);
return (oact.sa_handler);
}
#else /* !HAVE_POSIX_SIGNALS */
#define rl_set_sighandler(sig, handler) (SigHandler *)signal (sig, handler)
#endif /* !HAVE_POSIX_SIGNALS */
rl_set_signals()
{
old_int = (SigHandler *) rl_set_sighandler(SIGINT, rl_signal_handler);
if (old_int == (SigHandler *) SIG_IGN)
signal(SIGINT, SIG_IGN);
old_alrm = (SigHandler *) rl_set_sighandler(SIGALRM, rl_signal_handler);
if (old_alrm == (SigHandler *) SIG_IGN)
signal(SIGALRM, SIG_IGN);
#if !defined (SHELL)
#if defined (SIGTSTP)
old_tstp = (SigHandler *) rl_set_sighandler(SIGTSTP, rl_signal_handler);
if (old_tstp == (SigHandler *) SIG_IGN)
signal(SIGTSTP, SIG_IGN);
#endif /* SIGTSTP */
#if defined (SIGTTOU)
old_ttou = (SigHandler *) rl_set_sighandler(SIGTTOU, rl_signal_handler);
old_ttin = (SigHandler *) rl_set_sighandler(SIGTTIN, rl_signal_handler);
if (old_tstp == (SigHandler *) SIG_IGN) {
signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
}
#endif /* SIGTTOU */
#endif /* !SHELL */
#if defined (SIGWINCH)
old_sigwinch =
(SigHandler *) rl_set_sighandler(SIGWINCH, rl_handle_sigwinch);
#endif /* SIGWINCH */
return 0;
}
rl_clear_signals()
{
rl_set_sighandler(SIGINT, old_int);
rl_set_sighandler(SIGALRM, old_alrm);
#if !defined (SHELL)
#if defined (SIGTSTP)
signal(SIGTSTP, old_tstp);
#endif
#if defined (SIGTTOU)
signal(SIGTTOU, old_ttou);
signal(SIGTTIN, old_ttin);
#endif /* SIGTTOU */
#endif /* !SHELL */
#if defined (SIGWINCH)
signal(SIGWINCH, old_sigwinch);
#endif
return 0;
}
/* Move to the start of the current line. */
static void cr()
{
if (term_cr)
tputs(term_cr, 1, _rl_output_character_function);
}
#endif /* HANDLE_SIGNALS */