From 6d9e5dc78cbf3f643bd9fd78bb0eb7ee8b3a10d3 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Tue, 2 Feb 2016 16:19:13 -0500 Subject: [PATCH] throw error for {exit} --- command.cpp | 117 ++++++++++++++++++++++++------------------------ command.h | 29 +++++++----- environment.cpp | 22 ++++++--- environment.h | 21 ++++++++- error.h | 17 +++++++ 5 files changed, 129 insertions(+), 77 deletions(-) create mode 100644 error.h diff --git a/command.cpp b/command.cpp index e19b085..4a91319 100644 --- a/command.cpp +++ b/command.cpp @@ -113,18 +113,18 @@ command::~command() * echo and error should respect the active fdmask. */ -int simple_command::execute(Environment &env, const fdmask &fds) { +int simple_command::execute(Environment &env, const fdmask &fds, bool throwup) { std::string s = expand_vars(text, env); - if (env.echo()) fprintf(stderr, " %s\n", s.c_str()); + env.echo("%s", s.c_str()); process p; try { auto tokens = tokenize(s, false); parse_tokens(std::move(tokens), p); } catch(std::exception &e) { - fprintf(stderr, "%s", e.what()); - return env.status(-4); + fprintf(stderr, "%s\n", e.what()); + return env.status(-4, throwup); } if (p.arguments.empty()) return 0; @@ -137,7 +137,7 @@ int simple_command::execute(Environment &env, const fdmask &fds) { auto iter = builtins.find(name); if (iter != builtins.end()) { int status = iter->second(env, p.arguments, newfds); - return env.status(status); + return env.status(status, throwup); } if (env.test()) return env.status(0); @@ -148,54 +148,56 @@ int simple_command::execute(Environment &env, const fdmask &fds) { int status = execute_external(env, p.arguments, newfds); - return env.status(status); + return env.status(status, throwup); } -int evaluate_command::execute(Environment &env, const fdmask &fds) { +int evaluate_command::execute(Environment &env, const fdmask &fds, bool throwup) { std::string s = expand_vars(text, env); - if (env.echo()) fprintf(stderr, " %s\n", s.c_str()); + env.echo("%s", s.c_str()); - auto tokens = tokenize(s, true); - if (tokens.empty()) return 0; + try { + auto tokens = tokenize(s, true); + if (tokens.empty()) return 0; - int status = builtin_evaluate(env, std::move(tokens), fds); + int status = builtin_evaluate(env, std::move(tokens), fds); - return env.status(status); + return env.status(status, throwup); + } catch (std::exception &e) { + fprintf(stderr, "%s\n", e.what()); + return env.status(1, throwup); + } } -int or_command::execute(Environment &e, const fdmask &fds) { +int or_command::execute(Environment &e, const fdmask &fds, bool throwup) { int rv = 0; - bool pv = e.and_or(true); for (auto &c : children) { - rv = c->execute(e, fds); + if (!c) continue; + rv = c->execute(e, fds, false); if (rv == 0) return rv; } - e.and_or(pv); return e.status(rv); } -int and_command::execute(Environment &e, const fdmask &fds) { +int and_command::execute(Environment &e, const fdmask &fds, bool throwup) { int rv = 0; - bool pv = e.and_or(true); - for (auto &c : children) { - rv = c->execute(e, fds); + if (!c) continue; + c->execute(e, fds, false); if (rv != 0) return rv; } - e.and_or(pv); return rv; } -int vector_command::execute(Environment &e, const fdmask &fds) { +int vector_command::execute(Environment &e, const fdmask &fds, bool throwup) { int rv = 0; for (auto &c : children) { @@ -206,10 +208,10 @@ int vector_command::execute(Environment &e, const fdmask &fds) { return e.status(rv); } -int error_command::execute(Environment &e, const fdmask &fds) { +int error_command::execute(Environment &e, const fdmask &fds, bool throwup) { std::string s = expand_vars(text, e); - if (e.echo()) fprintf(stderr, " %s\n", s.c_str()); + e.echo("%s", s.c_str()); switch(type) { case END: @@ -249,14 +251,14 @@ namespace { } } -int begin_command::execute(Environment &env, const fdmask &fds) { +int begin_command::execute(Environment &env, const fdmask &fds, bool throwup) { // todo -- parse end for redirection. std::string b = expand_vars(begin, env); std::string e = expand_vars(end, env); // echo! - if (env.echo()) fprintf(stderr, " %s ... %s\n", + env.echo("%s ... %s", b.c_str(), e.c_str() ); @@ -276,8 +278,13 @@ int begin_command::execute(Environment &env, const fdmask &fds) { newfds |= fds; if (status) return env.status(status); - int rv = vector_command::execute(env, newfds); - if (env.echo()) fprintf(stderr, " %s\n", type == BEGIN ? "end" : ")"); + int rv; + { + indent_helper indent(env); + rv = vector_command::execute(env, newfds); + } + + env.echo("%s", type == BEGIN ? "end" : ")"); return env.status(rv); } @@ -286,7 +293,7 @@ namespace { - bool evaluate(int type, const std::string &s, Environment &env) { + int evaluate(int type, const std::string &s, Environment &env) { auto tokens = tokenize(s, true); std::reverse(tokens.begin(), tokens.end()); @@ -305,8 +312,7 @@ namespace { } catch (std::exception &ex) { fprintf(stderr, "%s\n", ex.what()); - env.status(-5); - e = 0; + return -5; } break; @@ -315,15 +321,18 @@ namespace { if (tokens.size() > 1) { fprintf(stderr, "### Else - Missing if keyword.\n"); fprintf(stderr, "# Usage - Else [if expression...]\n"); - env.status(-3); - e = 0; + return -3; } } - return e; + return !!e; } } -int if_command::execute(Environment &env, const fdmask &fds) { +/* + * the entire command prints even if there is an error with the expression. + * + */ +int if_command::execute(Environment &env, const fdmask &fds, bool throwup) { int rv = 0; bool ok = false; @@ -334,37 +343,29 @@ int if_command::execute(Environment &env, const fdmask &fds) { fdmask newfds; int status = check_ends(e, newfds); newfds |= fds; - if (status) return env.status(status); + if (status) { + rv = status; + ok = true; + } for (auto &c : clauses) { std::string s = expand_vars(c->clause, env); - if (env.echo()) { - if (c->type == IF) { // special. - fprintf(stderr, " %s ... %s\n", - s.c_str(), e.c_str()); - } - else { - fprintf(stderr, " %s\n", s.c_str()); - } - } + if (c->type == IF) + env.echo("%s ... %s", s.c_str(), e.c_str()); + else + env.echo("%s", s.c_str()); if (ok) continue; - ok = evaluate(c->type, s, env); - if (!ok) continue; - rv = c->execute(env, newfds); + { + indent_helper indent(env); + int tmp = evaluate(c->type, s, env); + if (tmp < 0) { ok = true; rv = tmp; } + else rv = c->execute(env, newfds); + } } - if (env.echo()) fprintf(stderr, " end\n"); + env.echo("end"); return env.status(rv); } -/* -int if_else_clause::execute() { - return 0; -} -*/ - -bool if_else_clause::evaluate(const Environment &e) { - return false; -} diff --git a/command.h b/command.h index 6ad3e5e..57161f2 100644 --- a/command.h +++ b/command.h @@ -1,6 +1,7 @@ #ifndef __command_h__ #define __command_h__ +#include #include #include #include @@ -20,9 +21,13 @@ struct command { command(int t = 0) : type(t) {} + virtual bool terminal() const noexcept { + return type == EVALUATE || type == COMMAND; + } + int type = 0; virtual ~command(); - virtual int execute(Environment &e, const fdmask &fds) = 0; + virtual int execute(Environment &e, const fdmask &fds, bool throwup = true) = 0; }; struct error_command : public command { @@ -32,7 +37,7 @@ struct error_command : public command { {} std::string text; - virtual int execute(Environment &e, const fdmask &fds) override final; + virtual int execute(Environment &e, const fdmask &fds, bool throwup = true) override final; }; struct simple_command : public command { @@ -42,7 +47,7 @@ struct simple_command : public command { std::string text; - virtual int execute(Environment &e, const fdmask &fds) final override; + virtual int execute(Environment &e, const fdmask &fds, bool throwup = true) final override; }; struct evaluate_command : public command { @@ -52,7 +57,7 @@ struct evaluate_command : public command { std::string text; - virtual int execute(Environment &e, const fdmask &fds) final override; + virtual int execute(Environment &e, const fdmask &fds, bool throwup = true) final override; }; struct binary_command : public command { @@ -63,6 +68,10 @@ struct binary_command : public command { command_ptr_pair children; + virtual bool terminal() const noexcept final override { + return children[0]->terminal() && children[1]->terminal(); + } + }; struct or_command : public binary_command { @@ -70,7 +79,7 @@ struct or_command : public binary_command { binary_command(PIPE_PIPE, std::move(a), std::move(b)) {} - virtual int execute(Environment &e, const fdmask &fds) final override; + virtual int execute(Environment &e, const fdmask &fds, bool throwup) final override; }; struct and_command : public binary_command { @@ -78,7 +87,7 @@ struct and_command : public binary_command { binary_command(AMP_AMP, std::move(a), std::move(b)) {} - virtual int execute(Environment &e, const fdmask &fds) final override; + virtual int execute(Environment &e, const fdmask &fds, bool throwup) final override; }; @@ -98,7 +107,7 @@ struct vector_command : public command { {} command_ptr_vector children; - virtual int execute(Environment &e, const fdmask &fds) override; + virtual int execute(Environment &e, const fdmask &fds, bool throwup = true) override; }; struct begin_command : public vector_command { @@ -110,7 +119,7 @@ struct begin_command : public vector_command { std::string begin; std::string end; - virtual int execute(Environment &e, const fdmask &fds) final override; + virtual int execute(Environment &e, const fdmask &fds, bool throwup) final override; }; typedef std::unique_ptr if_else_clause_ptr; @@ -127,7 +136,7 @@ struct if_command : public command { clause_vector_type clauses; std::string end; - virtual int execute(Environment &e, const fdmask &fds) final override; + virtual int execute(Environment &e, const fdmask &fds, bool throwup) final override; }; struct if_else_clause : public vector_command { @@ -139,7 +148,7 @@ struct if_else_clause : public vector_command { std::string clause; - bool evaluate(const Environment &e); + //bool evaluate(const Environment &e); }; #endif \ No newline at end of file diff --git a/environment.cpp b/environment.cpp index 5d7d947..e546ace 100644 --- a/environment.cpp +++ b/environment.cpp @@ -2,6 +2,8 @@ #include #include +#include "error.h" + namespace { @@ -73,7 +75,7 @@ namespace { } - int Environment::status(int i) { + int Environment::status(int i, const std::nothrow_t &) { if (_status == i) return i; @@ -82,21 +84,27 @@ namespace { return i; } -/* - int Environment::status(int i) { + int Environment::status(int i, bool throwup) { status(i, std::nothrow); - if (_exit) { - throw std::runtime_error("Execution of input terminated."); + + if (throwup && _exit && i) { + throw execution_of_input_terminated(i); } return i; } void Environment::echo(const char *fmt, ...) { - if (_echo) {} + if (_echo && !_startup) { + for (unsigned i = 0; i < _indent; ++i) { + fputc(' ', stderr); + fputc(' ', stderr); + } va_list ap; va_start(ap, fmt); va_end(ap); vfprintf(stderr, fmt, ap); + fputc('\n', stderr); } } -*/ + + diff --git a/environment.h b/environment.h index e946743..1621311 100644 --- a/environment.h +++ b/environment.h @@ -4,6 +4,9 @@ #include #include #include +#include + + // environment has a bool which indicates if exported. struct EnvironmentEntry { @@ -58,7 +61,8 @@ public: bool and_or(bool v) { std::swap(v, _and_or); return v; } - int status(int i); + int status(int i, bool throw_up = true); + int status(int i, const std::nothrow_t &); constexpr bool startup() const noexcept { return _startup; } constexpr void startup(bool tf) noexcept { _startup = tf; } @@ -88,6 +92,10 @@ public: private: // magic variables. + friend class indent_helper; + + int _indent = 0; + bool _exit = false; bool _test = false; @@ -95,12 +103,21 @@ private: bool _echo = false; int _status = 0; - int _indent = 0; bool _startup = false; bool _passthrough = false; std::unordered_map _table; }; +class indent_helper { +public: + indent_helper(Environment &e) : env(e) { env._indent++; } + void release() { if (active) { active = false; env._indent--; }} + ~indent_helper() { if (active) env._indent--; } +private: + Environment &env; + bool active = true; +}; + #endif diff --git a/error.h b/error.h new file mode 100644 index 0000000..7361c96 --- /dev/null +++ b/error.h @@ -0,0 +1,17 @@ +#ifndef __mpw_error_h__ +#define __mpw_error_h__ + +#include +#include + +class execution_of_input_terminated : public std::runtime_error { +public: + execution_of_input_terminated(int status) : + std::runtime_error("MPW Shell - Execution of input Terminated."), _status(status) + {} + constexpr int status() const noexcept { return _status; } +private: + int _status; +}; + +#endif \ No newline at end of file