diff --git a/command.cpp b/command.cpp index 5773257..5004c46 100644 --- a/command.cpp +++ b/command.cpp @@ -4,6 +4,7 @@ #include "fdset.h" #include "builtins.h" #include "mpw-shell.h" +#include "error.h" #include #include @@ -16,6 +17,8 @@ #include #include +extern volatile int control_c; + namespace { std::string &lowercase(std::string &s) { @@ -121,6 +124,9 @@ command::~command() */ int simple_command::execute(Environment &env, const fdmask &fds, bool throwup) { + + if (control_c) throw execution_of_input_terminated(); + std::string s = expand_vars(text, env); env.echo("%s", s.c_str()); @@ -160,6 +166,8 @@ int simple_command::execute(Environment &env, const fdmask &fds, bool throwup) { int evaluate_command::execute(Environment &env, const fdmask &fds, bool throwup) { + if (control_c) throw execution_of_input_terminated(); + std::string s = expand_vars(text, env); env.echo("%s", s.c_str()); @@ -215,6 +223,9 @@ int vector_command::execute(Environment &e, const fdmask &fds, bool throwup) { } int error_command::execute(Environment &e, const fdmask &fds, bool throwup) { + + if (control_c) throw execution_of_input_terminated(); + std::string s = expand_vars(text, e); e.echo("%s", s.c_str()); diff --git a/error.h b/error.h index 7361c96..bf7afcb 100644 --- a/error.h +++ b/error.h @@ -6,7 +6,7 @@ class execution_of_input_terminated : public std::runtime_error { public: - execution_of_input_terminated(int status) : + execution_of_input_terminated(int status = -9) : std::runtime_error("MPW Shell - Execution of input Terminated."), _status(status) {} constexpr int status() const noexcept { return _status; } diff --git a/mpw-shell.cpp b/mpw-shell.cpp index a311336..2bc1c5e 100644 --- a/mpw-shell.cpp +++ b/mpw-shell.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "mpw-shell.h" #include "fdset.h" @@ -57,6 +58,7 @@ void init(Environment &env) { env.set("echo", std::string("1")); } + int read_file(phase1 &p, const std::string &file) { const mapped_file mf(file, mapped_file::readonly); @@ -96,6 +98,16 @@ int read_fd(phase1 &p, int fd) { return 0; } +volatile int control_c = 0; +void control_c_handler(int signal, siginfo_t *sinfo, void *context) { + + // libedit gobbles up the first control-C and doesn't return until the second. + // GNU's readline may return no the first. + if (control_c > 3) abort(); + control_c++; + //fprintf(stderr, "interrupt!\n"); +} + int interactive(phase1 &p, phase2& p2) { std::string history_file = root(); @@ -103,12 +115,32 @@ int interactive(phase1 &p, phase2& p2) { read_history(history_file.c_str()); + struct sigaction act; + struct sigaction old_act; + memset(&act, 0, sizeof(struct sigaction)); + sigemptyset(&act.sa_mask); + + act.sa_sigaction = control_c_handler; + act.sa_flags = SA_SIGINFO; + + sigaction(SIGINT, &act, &old_act); + for(;;) { const char *prompt = "# "; if (p2.continuation()) prompt = "> "; char *cp = readline(prompt); - if (!cp) break; - + if (!cp) { + if (control_c) { + control_c = 0; + fprintf(stdout, "\n"); + p.abort(); + p2.abort(); + e.status(-9, false); + continue; + } + break; + } + control_c = 0; std::string s(cp); free(cp); @@ -137,9 +169,12 @@ int interactive(phase1 &p, phase2& p2) { p.reset(); } + sigaction(SIGINT, &old_act, nullptr); + write_history(history_file.c_str()); fprintf(stdout, "\n"); + return 0; } @@ -212,9 +247,11 @@ int main(int argc, char **argv) { try { ptr->execute(e, fds); } catch (execution_of_input_terminated &ex) { + control_c = 0; if (!(ptr->terminal() && ++iter == v.end())) { fprintf(stderr, "%s\n", ex.what()); } + e.status(ex.status(), false); return; } }