control-c support

This commit is contained in:
Kelvin Sherlock 2016-02-05 13:19:20 -05:00
parent f58f6d4115
commit 0dfecbd520
3 changed files with 51 additions and 3 deletions

View File

@ -4,6 +4,7 @@
#include "fdset.h"
#include "builtins.h"
#include "mpw-shell.h"
#include "error.h"
#include <stdexcept>
#include <unordered_map>
@ -16,6 +17,8 @@
#include <sys/wait.h>
#include <sysexits.h>
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());

View File

@ -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; }

View File

@ -8,6 +8,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <cerrno>
#include <signal.h>
#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;
}
}