aboutsummaryrefslogtreecommitdiff
path: root/readline/signals.c
diff options
context:
space:
mode:
Diffstat (limited to 'readline/signals.c')
-rw-r--r--readline/signals.c277
1 files changed, 259 insertions, 18 deletions
diff --git a/readline/signals.c b/readline/signals.c
index 2dca03f..6a68d78 100644
--- a/readline/signals.c
+++ b/readline/signals.c
@@ -1,24 +1,24 @@
/* signals.c -- signal handling support for readline. */
-/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2009 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.
+ This file is part of the GNU Readline Library (Readline), 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 2, or
+ Readline 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 3 of the License, 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
+ Readline 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,
- 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+ You should have received a copy of the GNU General Public License
+ along with Readline. If not, see <http://www.gnu.org/licenses/>.
+*/
+
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
@@ -40,13 +40,14 @@
# include <sys/ioctl.h>
#endif /* GWINSZ_IN_SYS_IOCTL */
-#if defined (HANDLE_SIGNALS)
/* Some standard library routines. */
#include "readline.h"
#include "history.h"
#include "rlprivate.h"
+#if defined (HANDLE_SIGNALS)
+
#if !defined (RETSIGTYPE)
# if defined (VOID_SIGHANDLER)
# define RETSIGTYPE void
@@ -80,6 +81,9 @@ typedef struct { SigHandler *sa_handler; int sa_mask, sa_flags; } sighandler_cxt
static SigHandler *rl_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *));
static void rl_maybe_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *));
+static RETSIGTYPE rl_signal_handler PARAMS((int));
+static RETSIGTYPE _rl_handle_signal PARAMS((int));
+
/* Exported variables for use by applications. */
/* If non-zero, readline will install its own signal handlers for
@@ -93,6 +97,18 @@ int rl_catch_sigwinch = 1;
int rl_catch_sigwinch = 0; /* for the readline state struct in readline.c */
#endif
+/* Private variables. */
+int _rl_interrupt_immediately = 0;
+int volatile _rl_caught_signal = 0; /* should be sig_atomic_t, but that requires including <signal.h> everywhere */
+
+/* If non-zero, print characters corresponding to received signals as long as
+ the user has indicated his desire to do so (_rl_echo_control_chars). */
+int _rl_echoctl = 0;
+
+int _rl_intr_char = 0;
+int _rl_quit_char = 0;
+int _rl_susp_char = 0;
+
static int signals_set_flag;
static int sigwinch_set_flag;
@@ -112,10 +128,36 @@ static sighandler_cxt old_winch;
/* Readline signal handler functions. */
+/* Called from RL_CHECK_SIGNALS() macro */
+RETSIGTYPE
+_rl_signal_handler (sig)
+ int sig;
+{
+ _rl_caught_signal = 0; /* XXX */
+
+ _rl_handle_signal (sig);
+ SIGHANDLER_RETURN;
+}
+
static RETSIGTYPE
rl_signal_handler (sig)
int sig;
{
+ if (_rl_interrupt_immediately || RL_ISSTATE(RL_STATE_CALLBACK))
+ {
+ _rl_interrupt_immediately = 0;
+ _rl_handle_signal (sig);
+ }
+ else
+ _rl_caught_signal = sig;
+
+ SIGHANDLER_RETURN;
+}
+
+static RETSIGTYPE
+_rl_handle_signal (sig)
+ int sig;
+{
#if defined (HAVE_POSIX_SIGNALS)
sigset_t set;
#else /* !HAVE_POSIX_SIGNALS */
@@ -142,6 +184,7 @@ rl_signal_handler (sig)
switch (sig)
{
case SIGINT:
+ _rl_reset_completion_state ();
rl_free_line_state ();
/* FALLTHROUGH */
@@ -157,9 +200,11 @@ rl_signal_handler (sig)
#if defined (SIGQUIT)
case SIGQUIT:
#endif
+ rl_echo_signal_char (sig);
rl_cleanup_after_signal ();
#if defined (HAVE_POSIX_SIGNALS)
+ sigemptyset (&set);
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &set);
sigdelset (&set, sig);
#else /* !HAVE_POSIX_SIGNALS */
@@ -251,11 +296,11 @@ rl_set_sighandler (sig, handler, ohandler)
struct sigaction act;
act.sa_handler = handler;
-#if defined (SIGWINCH)
+# if defined (SIGWINCH)
act.sa_flags = (sig == SIGWINCH) ? SA_RESTART : 0;
-#else
+# else
act.sa_flags = 0;
-#endif
+# endif /* SIGWINCH */
sigemptyset (&act.sa_mask);
sigemptyset (&ohandler->sa_mask);
sigaction (sig, &act, &old_handler);
@@ -292,9 +337,44 @@ rl_set_signals ()
{
sighandler_cxt dummy;
SigHandler *oh;
+#if defined (HAVE_POSIX_SIGNALS)
+ static int sigmask_set = 0;
+ static sigset_t bset, oset;
+#endif
+
+#if defined (HAVE_POSIX_SIGNALS)
+ if (rl_catch_signals && sigmask_set == 0)
+ {
+ sigemptyset (&bset);
+
+ sigaddset (&bset, SIGINT);
+ sigaddset (&bset, SIGTERM);
+#if defined (SIGQUIT)
+ sigaddset (&bset, SIGQUIT);
+#endif
+#if defined (SIGALRM)
+ sigaddset (&bset, SIGALRM);
+#endif
+#if defined (SIGTSTP)
+ sigaddset (&bset, SIGTSTP);
+#endif
+#if defined (SIGTTIN)
+ sigaddset (&bset, SIGTTIN);
+#endif
+#if defined (SIGTTOU)
+ sigaddset (&bset, SIGTTOU);
+#endif
+ sigmask_set = 1;
+ }
+#endif /* HAVE_POSIX_SIGNALS */
if (rl_catch_signals && signals_set_flag == 0)
{
+#if defined (HAVE_POSIX_SIGNALS)
+ sigemptyset (&oset);
+ sigprocmask (SIG_BLOCK, &bset, &oset);
+#endif
+
rl_maybe_set_sighandler (SIGINT, rl_signal_handler, &old_int);
rl_maybe_set_sighandler (SIGTERM, rl_signal_handler, &old_term);
#if defined (SIGQUIT)
@@ -328,6 +408,10 @@ rl_set_signals ()
#endif /* SIGTTIN */
signals_set_flag = 1;
+
+#if defined (HAVE_POSIX_SIGNALS)
+ sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
+#endif
}
#if defined (SIGWINCH)
@@ -394,8 +478,8 @@ rl_cleanup_after_signal ()
_rl_clean_up_for_exit ();
if (rl_deprep_term_function)
(*rl_deprep_term_function) ();
- rl_clear_signals ();
rl_clear_pending_input ();
+ rl_clear_signals ();
}
/* Reset the terminal and readline state after a signal handler returns. */
@@ -428,3 +512,160 @@ rl_free_line_state ()
}
#endif /* HANDLE_SIGNALS */
+
+/* **************************************************************** */
+/* */
+/* SIGINT Management */
+/* */
+/* **************************************************************** */
+
+#if defined (HAVE_POSIX_SIGNALS)
+static sigset_t sigint_set, sigint_oset;
+static sigset_t sigwinch_set, sigwinch_oset;
+#else /* !HAVE_POSIX_SIGNALS */
+# if defined (HAVE_BSD_SIGNALS)
+static int sigint_oldmask;
+static int sigwinch_oldmask;
+# endif /* HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+static int sigint_blocked;
+static int sigwinch_blocked;
+
+/* Cause SIGINT to not be delivered until the corresponding call to
+ release_sigint(). */
+void
+_rl_block_sigint ()
+{
+ if (sigint_blocked)
+ return;
+
+#if defined (HAVE_POSIX_SIGNALS)
+ sigemptyset (&sigint_set);
+ sigemptyset (&sigint_oset);
+ sigaddset (&sigint_set, SIGINT);
+ sigprocmask (SIG_BLOCK, &sigint_set, &sigint_oset);
+#else /* !HAVE_POSIX_SIGNALS */
+# if defined (HAVE_BSD_SIGNALS)
+ sigint_oldmask = sigblock (sigmask (SIGINT));
+# else /* !HAVE_BSD_SIGNALS */
+# if defined (HAVE_USG_SIGHOLD)
+ sighold (SIGINT);
+# endif /* HAVE_USG_SIGHOLD */
+# endif /* !HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+ sigint_blocked = 1;
+}
+
+/* Allow SIGINT to be delivered. */
+void
+_rl_release_sigint ()
+{
+ if (sigint_blocked == 0)
+ return;
+
+#if defined (HAVE_POSIX_SIGNALS)
+ sigprocmask (SIG_SETMASK, &sigint_oset, (sigset_t *)NULL);
+#else
+# if defined (HAVE_BSD_SIGNALS)
+ sigsetmask (sigint_oldmask);
+# else /* !HAVE_BSD_SIGNALS */
+# if defined (HAVE_USG_SIGHOLD)
+ sigrelse (SIGINT);
+# endif /* HAVE_USG_SIGHOLD */
+# endif /* !HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+ sigint_blocked = 0;
+}
+
+/* Cause SIGWINCH to not be delivered until the corresponding call to
+ release_sigwinch(). */
+void
+_rl_block_sigwinch ()
+{
+ if (sigwinch_blocked)
+ return;
+
+#if defined (HAVE_POSIX_SIGNALS)
+ sigemptyset (&sigwinch_set);
+ sigemptyset (&sigwinch_oset);
+ sigaddset (&sigwinch_set, SIGWINCH);
+ sigprocmask (SIG_BLOCK, &sigwinch_set, &sigwinch_oset);
+#else /* !HAVE_POSIX_SIGNALS */
+# if defined (HAVE_BSD_SIGNALS)
+ sigwinch_oldmask = sigblock (sigmask (SIGWINCH));
+# else /* !HAVE_BSD_SIGNALS */
+# if defined (HAVE_USG_SIGHOLD)
+ sighold (SIGWINCH);
+# endif /* HAVE_USG_SIGHOLD */
+# endif /* !HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+ sigwinch_blocked = 1;
+}
+
+/* Allow SIGWINCH to be delivered. */
+void
+_rl_release_sigwinch ()
+{
+ if (sigwinch_blocked == 0)
+ return;
+
+#if defined (HAVE_POSIX_SIGNALS)
+ sigprocmask (SIG_SETMASK, &sigwinch_oset, (sigset_t *)NULL);
+#else
+# if defined (HAVE_BSD_SIGNALS)
+ sigsetmask (sigwinch_oldmask);
+# else /* !HAVE_BSD_SIGNALS */
+# if defined (HAVE_USG_SIGHOLD)
+ sigrelse (SIGWINCH);
+# endif /* HAVE_USG_SIGHOLD */
+# endif /* !HAVE_BSD_SIGNALS */
+#endif /* !HAVE_POSIX_SIGNALS */
+
+ sigwinch_blocked = 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Echoing special control characters */
+/* */
+/* **************************************************************** */
+void
+rl_echo_signal_char (sig)
+ int sig;
+{
+ char cstr[3];
+ int cslen, c;
+
+ if (_rl_echoctl == 0 || _rl_echo_control_chars == 0)
+ return;
+
+ switch (sig)
+ {
+ case SIGINT: c = _rl_intr_char; break;
+#if defined (SIGQUIT)
+ case SIGQUIT: c = _rl_quit_char; break;
+#endif
+#if defined (SIGTSTP)
+ case SIGTSTP: c = _rl_susp_char; break;
+#endif
+ default: return;
+ }
+
+ if (CTRL_CHAR (c) || c == RUBOUT)
+ {
+ cstr[0] = '^';
+ cstr[1] = CTRL_CHAR (c) ? UNCTRL (c) : '?';
+ cstr[cslen = 2] = '\0';
+ }
+ else
+ {
+ cstr[0] = c;
+ cstr[cslen = 1] = '\0';
+ }
+
+ _rl_output_some_chars (cstr, cslen);
+}