aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Kurtis Rader <krader@skepticism.us>2016-06-26 17:09:29 -0700
committerGravatar Kurtis Rader <krader@skepticism.us>2016-06-26 17:12:03 -0700
commit0f5bfeead29b3c567fc8c3cbb5338dee1b195755 (patch)
tree236e05c121fbb6d4aff1d79abf0929ca94e0f30a
parentea71f0b6103f52aa09c8cef9a9e384cffc548b78 (diff)
add more ways to exit fish_key_reader
A discussion on Gitter proposed allowing the user to signal their desire to exit fish_key_reader by pressing \cC or \cD twice in a row. This implements that. I also decided to refactor how signals are handled. Most notably receiving a signal will no longer print a diagnostic message unless you've enabled debugging with `-d2` (or higher level).
-rw-r--r--src/fish_key_reader.cpp64
1 files changed, 49 insertions, 15 deletions
diff --git a/src/fish_key_reader.cpp b/src/fish_key_reader.cpp
index efac93b9..571e6e54 100644
--- a/src/fish_key_reader.cpp
+++ b/src/fish_key_reader.cpp
@@ -10,10 +10,10 @@
#include <getopt.h>
#include <locale.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/signal.h>
#include <wctype.h>
#include <cmath>
#include <iosfwd>
@@ -44,7 +44,9 @@ static bool should_exit(unsigned char c) {
recent_chars[1] = recent_chars[2];
recent_chars[2] = recent_chars[3];
recent_chars[3] = c;
- return memcmp(recent_chars, "exit", 4) == 0 || memcmp(recent_chars, "quit", 4) == 0;
+ return (memcmp(recent_chars, "exit", 4) == 0 || memcmp(recent_chars, "quit", 4) == 0 ||
+ memcmp(recent_chars + 2, "\x3\x3", 2) == 0 || // ctrl-C, ctrl-C
+ memcmp(recent_chars + 2, "\x4\x4", 2) == 0); // ctrl-D, ctrl-D
}
/// Return the key name if the recent sequence of characters matches a known terminfo sequence.
@@ -148,11 +150,50 @@ static void process_input(bool continuous_mode) {
/// Make sure we cleanup before exiting if we receive a signal that should cause us to exit.
/// Otherwise just report receipt of the signal.
-static void signal_handler(int signo) {
- printf("\nSignal #%d (%ls) received\n\n", signo, sig2wcs(signo));
- if (signo == SIGINT || signo == SIGTERM || signo == SIGABRT || signo == SIGSEGV) {
+static struct sigaction old_sigactions[32];
+static void signal_handler(int signo, siginfo_t *siginfo, void *siginfo_arg) {
+ debug(2, L"signal #%d (%ls) received", signo, sig2wcs(signo));
+ // SIGINT isn't included in the following conditional because it is handled specially by fish;
+ // i.e., it causes \cC to be reinserted into the tty input stream.
+ if (signo == SIGHUP || signo == SIGTERM || signo == SIGABRT || signo == SIGSEGV) {
keep_running = false;
}
+ if (old_sigactions[signo].sa_handler != SIG_IGN &&
+ old_sigactions[signo].sa_handler != SIG_DFL) {
+ int needs_siginfo = old_sigactions[signo].sa_flags & SA_SIGINFO;
+ if (needs_siginfo) {
+ old_sigactions[signo].sa_sigaction(signo, siginfo, siginfo_arg);
+ } else {
+ old_sigactions[signo].sa_handler(signo);
+ }
+ }
+}
+
+/// Install a handler for every signal. This allows us to restore the tty modes so the terminal is
+/// still usable when we die. If the signal already has a handler arrange to invoke it from within
+/// our handler.
+static void install_our_signal_handlers() {
+ struct sigaction new_sa, old_sa;
+ sigemptyset(&new_sa.sa_mask);
+ new_sa.sa_flags = SA_SIGINFO;
+ new_sa.sa_sigaction = signal_handler;
+
+ for (int signo = 1; signo < 32; signo++) {
+ if (sigaction(signo, &new_sa, &old_sa) != -1) {
+ memcpy(&old_sigactions[signo], &old_sa, sizeof(old_sa));
+ if (old_sa.sa_handler == SIG_IGN) {
+ debug(2, "signal #%d (%ls) was being ignored", signo, sig2wcs(signo));
+ }
+ if (old_sa.sa_flags && ~SA_SIGINFO != 0) {
+ debug(2, L"signal #%d (%ls) handler had flags 0x%X", signo, sig2wcs(signo),
+ old_sa.sa_flags);
+ }
+ if (old_sa.sa_mask != new_sa.sa_mask) {
+ debug(2, L"signal #%d (%ls) handler had mask 0x%X", signo, sig2wcs(signo),
+ old_sa.sa_mask);
+ }
+ }
+ }
}
/// Setup our environment (e.g., tty modes), process key strokes, then reset the environment.
@@ -161,24 +202,17 @@ static void setup_and_process_keys(bool continuous_mode) {
setenv("LC_ALL", "POSIX", 1); // ensure we're in a single-byte locale
set_main_thread();
setup_fork_guards();
-
- // Install a handler for every signal. This allows us to restore the tty modes so the terminal
- // is still usable when we die. We do this only to ensure any signal not handled by
- // signal_set_handlers() gets handled for a clean exit.
- for (int signo = 1; signo < 32; signo++) {
- signal(signo, signal_handler);
- }
-
env_init();
reader_init();
input_init();
proc_push_interactive(1);
signal_set_handlers();
+ install_our_signal_handlers();
if (continuous_mode) {
printf("\n");
- printf("To terminate this program type \"exit\" or \"quit\" in this window\n");
- printf("or \"kill %d\" in another window\n", getpid());
+ printf("To terminate this program type \"exit\" or \"quit\" in this window,\n");
+ printf("or press [ctrl-C] or [ctrl-D] twice in a row.\n");
printf("\n");
}