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>
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <stdio.h> /* Just for NULL. Yuck. */
#include <sys/types.h>
-#include <fcntl.h>
-#if !defined (NO_SYS_FILE)
-# include <sys/file.h>
-#endif /* !NO_SYS_FILE */
#include <signal.h>
-/* This is needed to include support for TIOCGWINSZ and window resizing. */
-#if defined (OSF1) || defined (BSD386) || defined (_386BSD) || defined (__BSD_4_4__) || defined (AIX)
-# include <sys/ioctl.h>
-#endif /* OSF1 || BSD386 || _386BSD || __BSD_4_4__ || AIX */
-
-#include <errno.h>
-/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
-#if !defined (errno)
-extern int errno;
-#endif /* !errno */
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_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 */
+
+#if defined (__GO32__) && !defined(__DJGPP__)
+# undef HANDLE_SIGNALS
+#endif /* __GO32__ && !__DJGPP__ */
+
+#if defined (HANDLE_SIGNALS)
/* Some standard library routines. */
#include "readline.h"
#include "history.h"
-static void cr ();
+#if !defined (RETSIGTYPE)
+# if defined (VOID_SIGHANDLER)
+# define RETSIGTYPE void
+# else
+# define RETSIGTYPE int
+# endif /* !VOID_SIGHANDLER */
+#endif /* !RETSIGTYPE */
+
+#if defined (VOID_SIGHANDLER)
+# define SIGHANDLER_RETURN return
+#else
+# define SIGHANDLER_RETURN return (0)
+#endif
+
+/* This typedef is equivalant to the one for Function; it allows us
+ to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */
+typedef RETSIGTYPE SigHandler ();
extern int readline_echoing_p;
extern int rl_pending_input;
-
extern int _rl_meta_flag;
-#ifdef __STDC__
-extern void _rl_output_character_function (int);
-#else
-extern void _rl_output_character_function ();
-#endif
-
extern void free_undo_list ();
+extern void _rl_get_screen_size ();
+extern void _rl_redisplay_after_sigwinch ();
+extern void _rl_clean_up_for_exit ();
+extern void _rl_kill_kbd_macro ();
+extern void _rl_init_argument ();
+extern void rl_deprep_terminal (), rl_prep_terminal ();
-#if defined (VOID_SIGHANDLER)
-# define sighandler void
-#else
-# define sighandler int
-#endif /* VOID_SIGHANDLER */
+static SigHandler *rl_set_sighandler ();
-/* This typedef is equivalant to the one for Function; it allows us
- to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */
-typedef sighandler SigHandler ();
+/* Exported variables for use by applications. */
+
+/* If non-zero, readline will install its own signal handlers for
+ SIGINT, SIGTERM, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */
+int rl_catch_signals = 1;
+
+/* If non-zero, readline will install a signal handler for SIGWINCH. */
+#ifdef SIGWINCH
+int rl_catch_sigwinch = 1;
+#endif
+
+static int signals_set_flag;
+#ifdef SIGWINCH
+static int sigwinch_set_flag;
+#endif
/* **************************************************************** */
/* */
/* */
/* **************************************************************** */
-#if defined (HANDLE_SIGNALS)
+#if defined (HAVE_POSIX_SIGNALS)
+typedef struct sigaction sighandler_cxt;
+# define rl_sigaction(s, nh, oh) sigaction(s, nh, oh)
+#else
+typedef struct { SigHandler *sa_handler; int sa_mask, sa_flags; } sighandler_cxt;
+# define sigemptyset(m)
+#endif /* !HAVE_POSIX_SIGNALS */
+static sighandler_cxt old_int, old_term, old_alrm, old_quit;
+#if defined (SIGTSTP)
+static sighandler_cxt old_tstp, old_ttou, old_ttin;
+#endif
#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);
+static sighandler_cxt old_winch;
+#endif
- cr (); /* was crlf () */
- rl_forced_update_display ();
- }
+/* Readline signal handler functions. */
- 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 */
-
-/* Interrupt handling. */
-static SigHandler
- *old_int = (SigHandler *)NULL,
- *old_tstp = (SigHandler *)NULL,
- *old_ttou = (SigHandler *)NULL,
- *old_ttin = (SigHandler *)NULL,
- *old_cont = (SigHandler *)NULL,
- *old_alrm = (SigHandler *)NULL;
-
-/* Handle an interrupt character. */
-static sighandler
+static RETSIGTYPE
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;
+# else /* !HAVE_BSD_SIGNALS */
+ sighandler_cxt dummy_cxt; /* needed for rl_set_sighandler call */
+# 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 */
+ if (sig == SIGINT || sig == SIGALRM)
+ rl_set_sighandler (sig, SIG_IGN, &dummy_cxt);
+#endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_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 ();
+ rl_free_line_state ();
+ /* FALLTHROUGH */
#if defined (SIGTSTP)
case SIGTSTP:
case SIGTTIN:
#endif /* SIGTSTP */
case SIGALRM:
- rl_clean_up_for_exit ();
- rl_deprep_terminal ();
- rl_clear_signals ();
- rl_pending_input = 0;
+ case SIGTERM:
+ case SIGQUIT:
+ rl_cleanup_after_signal ();
+
+#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);
- SIGNALS_UNBLOCK;
+ /* 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 ();
+ rl_reset_after_signal ();
}
-#if !defined (VOID_SIGHANDLER)
- return (0);
-#endif /* !VOID_SIGHANDLER */
+ SIGHANDLER_RETURN;
}
-#if defined (HAVE_POSIX_SIGNALS)
+#if defined (SIGWINCH)
+static RETSIGTYPE
+rl_sigwinch_handler (sig)
+ int sig;
+{
+ SigHandler *oh;
+
+#if defined (MUST_REINSTALL_SIGHANDLERS)
+ sighandler_cxt dummy_winch;
+
+ /* We don't want to change old_winch -- it holds the state of SIGWINCH
+ disposition set by the calling application. We need this state
+ because we call the application's SIGWINCH handler after updating
+ our own idea of the screen size. */
+ rl_set_sighandler (SIGWINCH, rl_sigwinch_handler, &dummy_winch);
+#endif
+
+ rl_resize_terminal ();
+
+ /* If another sigwinch handler has been installed, call it. */
+ oh = (SigHandler *)old_winch.sa_handler;
+ if (oh && oh != (SigHandler *)SIG_IGN && oh != (SigHandler *)SIG_DFL)
+ (*oh) (sig);
+
+ SIGHANDLER_RETURN;
+}
+#endif /* SIGWINCH */
+
+/* Functions to manage signal handling. */
+
+#if !defined (HAVE_POSIX_SIGNALS)
+static int
+rl_sigaction (sig, nh, oh)
+ int sig;
+ sighandler_cxt *nh, *oh;
+{
+ oh->sa_handler = signal (sig, nh->sa_handler);
+ return 0;
+}
+#endif /* !HAVE_POSIX_SIGNALS */
+
+/* Set up a readline-specific signal handler, saving the old signal
+ information in OHANDLER. Return the old signal handler, like
+ signal(). */
static SigHandler *
-rl_set_sighandler (sig, handler)
+rl_set_sighandler (sig, handler, ohandler)
int sig;
SigHandler *handler;
+ sighandler_cxt *ohandler;
{
- struct sigaction act, oact;
+#if defined (HAVE_POSIX_SIGNALS)
+ struct sigaction act;
act.sa_handler = handler;
act.sa_flags = 0;
sigemptyset (&act.sa_mask);
- sigemptyset (&oact.sa_mask);
- sigaction (sig, &act, &oact);
- return (oact.sa_handler);
+ sigemptyset (&ohandler->sa_mask);
+ sigaction (sig, &act, ohandler);
+#else
+ ohandler->sa_handler = (SigHandler *)signal (sig, handler);
+#endif /* !HAVE_POSIX_SIGNALS */
+ return (ohandler->sa_handler);
}
-#else /* !HAVE_POSIX_SIGNALS */
-# define rl_set_sighandler(sig, handler) (SigHandler *)signal (sig, handler)
-#endif /* !HAVE_POSIX_SIGNALS */
+static void
+rl_maybe_set_sighandler (sig, handler, ohandler)
+ int sig;
+ SigHandler *handler;
+ sighandler_cxt *ohandler;
+{
+ sighandler_cxt dummy;
+ SigHandler *oh;
+
+ sigemptyset (&dummy.sa_mask);
+ oh = rl_set_sighandler (sig, handler, ohandler);
+ if (oh == (SigHandler *)SIG_IGN)
+ rl_sigaction (sig, ohandler, &dummy);
+}
+int
rl_set_signals ()
{
- old_int = (SigHandler *)rl_set_sighandler (SIGINT, rl_signal_handler);
- if (old_int == (SigHandler *)SIG_IGN)
- signal (SIGINT, SIG_IGN);
+ sighandler_cxt dummy;
+ SigHandler *oh;
- old_alrm = (SigHandler *)rl_set_sighandler (SIGALRM, rl_signal_handler);
- if (old_alrm == (SigHandler *)SIG_IGN)
- signal (SIGALRM, SIG_IGN);
+ if (rl_catch_signals && signals_set_flag == 0)
+ {
+ rl_maybe_set_sighandler (SIGINT, rl_signal_handler, &old_int);
+ rl_maybe_set_sighandler (SIGTERM, rl_signal_handler, &old_term);
+ rl_maybe_set_sighandler (SIGQUIT, rl_signal_handler, &old_quit);
+
+ oh = rl_set_sighandler (SIGALRM, rl_signal_handler, &old_alrm);
+ if (oh == (SigHandler *)SIG_IGN)
+ rl_sigaction (SIGALRM, &old_alrm, &dummy);
+#if defined (HAVE_POSIX_SIGNALS) && defined (SA_RESTART)
+ /* If the application using readline has already installed a signal
+ handler with SA_RESTART, SIGALRM will cause reads to be restarted
+ automatically, so readline should just get out of the way. Since
+ we tested for SIG_IGN above, we can just test for SIG_DFL here. */
+ if (oh != (SigHandler *)SIG_DFL && (old_alrm.sa_flags & SA_RESTART))
+ rl_sigaction (SIGALRM, &old_alrm, &dummy);
+#endif /* HAVE_POSIX_SIGNALS */
#if defined (SIGTSTP)
- old_tstp = (SigHandler *)rl_set_sighandler (SIGTSTP, rl_signal_handler);
- if (old_tstp == (SigHandler *)SIG_IGN)
- signal (SIGTSTP, SIG_IGN);
-#endif
+ rl_maybe_set_sighandler (SIGTSTP, rl_signal_handler, &old_tstp);
+#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);
+ rl_maybe_set_sighandler (SIGTTOU, rl_signal_handler, &old_ttou);
+#endif /* SIGTTOU */
- if (old_tstp == (SigHandler *)SIG_IGN)
- {
- signal (SIGTTOU, SIG_IGN);
- signal (SIGTTIN, SIG_IGN);
+#if defined (SIGTTIN)
+ rl_maybe_set_sighandler (SIGTTIN, rl_signal_handler, &old_ttin);
+#endif /* SIGTTIN */
+
+ signals_set_flag = 1;
}
-#endif
#if defined (SIGWINCH)
- old_sigwinch =
- (SigHandler *) rl_set_sighandler (SIGWINCH, rl_handle_sigwinch);
-#endif
+ if (rl_catch_sigwinch && sigwinch_set_flag == 0)
+ {
+ rl_maybe_set_sighandler (SIGWINCH, rl_sigwinch_handler, &old_winch);
+ sigwinch_set_flag = 1;
+ }
+#endif /* SIGWINCH */
+
+ return 0;
}
+int
rl_clear_signals ()
{
- rl_set_sighandler (SIGINT, old_int);
- rl_set_sighandler (SIGALRM, old_alrm);
+ sighandler_cxt dummy;
+
+ if (rl_catch_signals && signals_set_flag == 1)
+ {
+ sigemptyset (&dummy.sa_mask);
+
+ rl_sigaction (SIGINT, &old_int, &dummy);
+ rl_sigaction (SIGTERM, &old_term, &dummy);
+ rl_sigaction (SIGQUIT, &old_quit, &dummy);
+ rl_sigaction (SIGALRM, &old_alrm, &dummy);
#if defined (SIGTSTP)
- signal (SIGTSTP, old_tstp);
-#endif
+ rl_sigaction (SIGTSTP, &old_tstp, &dummy);
+#endif /* SIGTSTP */
#if defined (SIGTTOU)
- signal (SIGTTOU, old_ttou);
- signal (SIGTTIN, old_ttin);
-#endif
+ rl_sigaction (SIGTTOU, &old_ttou, &dummy);
+#endif /* SIGTTOU */
+
+#if defined (SIGTTIN)
+ rl_sigaction (SIGTTIN, &old_ttin, &dummy);
+#endif /* SIGTTIN */
+
+ signals_set_flag = 0;
+ }
#if defined (SIGWINCH)
- signal (SIGWINCH, old_sigwinch);
+ if (rl_catch_sigwinch && sigwinch_set_flag == 1)
+ {
+ sigemptyset (&dummy.sa_mask);
+ rl_sigaction (SIGWINCH, &old_winch, &dummy);
+ sigwinch_set_flag = 0;
+ }
#endif
+
+ return 0;
}
-/* Move to the start of the current line. */
-static void
-cr ()
+/* Clean up the terminal and readline state after catching a signal, before
+ resending it to the calling application. */
+void
+rl_cleanup_after_signal ()
+{
+ _rl_clean_up_for_exit ();
+ (*rl_deprep_term_function) ();
+ rl_clear_signals ();
+ rl_pending_input = 0;
+}
+
+/* Reset the terminal and readline state after a signal handler returns. */
+void
+rl_reset_after_signal ()
+{
+ (*rl_prep_term_function) (_rl_meta_flag);
+ rl_set_signals ();
+}
+
+/* Free up the readline variable line state for the current line (undo list,
+ any partial history entry, any keyboard macros in progress, and any
+ numeric arguments in process) after catching a signal, before calling
+ rl_cleanup_after_signal(). */
+void
+rl_free_line_state ()
{
- extern char *term_cr;
+ register HIST_ENTRY *entry;
- if (term_cr)
- tputs (term_cr, 1, _rl_output_character_function);
+ free_undo_list ();
+
+ entry = current_history ();
+ if (entry)
+ entry->data = (char *)NULL;
+
+ _rl_kill_kbd_macro ();
+ rl_clear_message ();
+ _rl_init_argument ();
}
+
#endif /* HANDLE_SIGNALS */