From fb8a793d66f3337e4a240520781e4354ba784c5a Mon Sep 17 00:00:00 2001 From: q66 Date: Mon, 5 Sep 2016 21:50:24 +0200 Subject: [PATCH] allow SIGINT to interrupt infinite loops --- tools/edit_linenoise.hh | 2 ++ tools/repl.cc | 41 +++++++++++++++++++++++++++++++++++------ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/tools/edit_linenoise.hh b/tools/edit_linenoise.hh index da690654..d52008ff 100644 --- a/tools/edit_linenoise.hh +++ b/tools/edit_linenoise.hh @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -68,6 +69,7 @@ static ostd::Maybe read_line(CsSvar *pr) { if (!line) { /* linenoise traps ctrl-c, detect it and let the user exit */ if (errno == EAGAIN) { + raise(SIGINT); return ostd::nothing; } return ostd::String(); diff --git a/tools/repl.cc b/tools/repl.cc index 4108cd0f..41db9016 100644 --- a/tools/repl.cc +++ b/tools/repl.cc @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -162,6 +164,38 @@ static CsCommand *get_hint_cmd(ostd::ConstCharRange buf) { #include "tools/edit_readline.hh" #include "tools/edit_fallback.hh" +struct InterruptedException { +}; + +static void do_sigint(int n) { + /* in case another SIGINT happens, terminate normally */ + signal(n, SIG_DFL); + if (gcs) { + gcs->set_call_hook([]() { + gcs->set_call_hook(nullptr); + throw InterruptedException{}; + }); + } +} + +static void do_call(CsState &cs, ostd::ConstCharRange line) { + CsValue ret; + ret.set_null(); + signal(SIGINT, do_sigint); + try { + cs.run_ret(line, ret); + } catch (InterruptedException) { + signal(SIGINT, SIG_DFL); + ret.cleanup(); + ostd::writeln(""); + return; + } + signal(SIGINT, SIG_DFL); + if (ret.get_type() != CsValueType::null) { + ostd::writeln(ret.get_str()); + } +} + static void do_tty(CsState &cs) { auto prompt = cs.new_svar("PROMPT", "> "); auto prompt2 = cs.new_svar("PROMPT2", ">> "); @@ -207,12 +241,7 @@ static void do_tty(CsState &cs) { lv += line2.value(); } add_history(lv); - CsValue ret; - ret.set_null(); - cs.run_ret(lv, ret); - if (ret.get_type() != CsValueType::null) { - ostd::writeln(ret.get_str()); - } + do_call(cs, lv); if (do_exit) { return; }