Squashed commit of the following:
commit f0944a89f27e44b1764988806e655f09764e80df Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Tue Aug 30 12:24:08 2016 -0400 exit throws execution of input error w/ possible 0 value. catch it. commit 9e7f9c1ae049aa26513413f4767268b47ee22e98 Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Tue Aug 30 12:23:21 2016 -0400 builtins - more consistent argument handling. commit be4c1c902f5a3a3f01e92ae52c7d6cc5d8731b65 Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Tue Aug 30 12:23:01 2016 -0400 . commit 68d0c29fec112c6e7bc3a672b41eb7eb758a8941 Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Tue Aug 30 12:22:51 2016 -0400 exit command. commit 25b0a7f7da9220b03026123bb5072c2da1d73fde Author: Kelvin Sherlock <ksherlock@gmail.com> Date: Tue Aug 30 12:21:16 2016 -0400 builtin quit command.
This commit is contained in:
parent
f6c5478063
commit
f125b533f7
118
builtins.cpp
118
builtins.cpp
|
@ -4,6 +4,7 @@
|
||||||
#include "fdset.h"
|
#include "fdset.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -279,22 +280,14 @@ static int export_common(Environment &env, bool export_or_unexport, const std::v
|
||||||
|
|
||||||
const char *name = export_or_unexport ? "Export" : "Unexport";
|
const char *name = export_or_unexport ? "Export" : "Unexport";
|
||||||
|
|
||||||
struct {
|
bool _r = false;
|
||||||
int _r = 0;
|
bool _s = false;
|
||||||
int _s = 0;
|
|
||||||
} flags;
|
|
||||||
bool error = false;
|
bool error = false;
|
||||||
|
|
||||||
std::vector<std::string> argv = getopt(tokens, [&](char c){
|
auto argv = getopt(tokens, [&](char c){
|
||||||
switch(c) {
|
switch(tolower(c)) {
|
||||||
case 'r':
|
case 'r': _r = true; break;
|
||||||
case 'R':
|
case 's': _s = true; break;
|
||||||
flags._r = true;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
case 'S':
|
|
||||||
flags._s = true;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
fdprintf(stderr, "### %s - \"-%c\" is not an option.\n", name, c);
|
fdprintf(stderr, "### %s - \"-%c\" is not an option.\n", name, c);
|
||||||
error = true;
|
error = true;
|
||||||
|
@ -308,7 +301,7 @@ static int export_common(Environment &env, bool export_or_unexport, const std::v
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argv.empty()) {
|
if (argv.empty()) {
|
||||||
if (flags._r && flags._s) goto conflict;
|
if (_r && _s) goto conflict;
|
||||||
|
|
||||||
// list of exported vars.
|
// list of exported vars.
|
||||||
// -r will generate unexport commands for exported variables.
|
// -r will generate unexport commands for exported variables.
|
||||||
|
@ -320,14 +313,14 @@ static int export_common(Environment &env, bool export_or_unexport, const std::v
|
||||||
for (const auto &kv : env) {
|
for (const auto &kv : env) {
|
||||||
const std::string& vname = kv.first;
|
const std::string& vname = kv.first;
|
||||||
if (kv.second == export_or_unexport)
|
if (kv.second == export_or_unexport)
|
||||||
fdprintf(stdout, "%s%s\n", flags._s ? "" : name, quote(vname).c_str());
|
fdprintf(stdout, "%s%s\n", _s ? "" : name, quote(vname).c_str());
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// mark as exported.
|
// mark as exported.
|
||||||
|
|
||||||
if (flags._r || flags._s) goto conflict;
|
if (_r || _s) goto conflict;
|
||||||
|
|
||||||
for (std::string s : argv) {
|
for (std::string s : argv) {
|
||||||
auto iter = env.find(s);
|
auto iter = env.find(s);
|
||||||
|
@ -509,12 +502,9 @@ int builtin_directory(Environment &env, const std::vector<std::string> &tokens,
|
||||||
bool error = false;
|
bool error = false;
|
||||||
|
|
||||||
std::vector<std::string> argv = getopt(tokens, [&](char c){
|
std::vector<std::string> argv = getopt(tokens, [&](char c){
|
||||||
switch(c)
|
switch(tolower(c))
|
||||||
{
|
{
|
||||||
case 'q':
|
case 'q': q = true; break;
|
||||||
case 'Q':
|
|
||||||
q = true;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
fdprintf(stderr, "### Directory - \"-%c\" is not an option.\n", c);
|
fdprintf(stderr, "### Directory - \"-%c\" is not an option.\n", c);
|
||||||
error = true;
|
error = true;
|
||||||
|
@ -585,24 +575,12 @@ int builtin_exists(Environment &env, const std::vector<std::string> &tokens, con
|
||||||
std::vector<std::string> argv = getopt(tokens, [&](char c){
|
std::vector<std::string> argv = getopt(tokens, [&](char c){
|
||||||
switch(tolower(c))
|
switch(tolower(c))
|
||||||
{
|
{
|
||||||
case 'a':
|
case 'a': _a = true; break;
|
||||||
_a = true;
|
case 'd': _d = true; break;
|
||||||
break;
|
case 'f': _f = true; break;
|
||||||
case 'd':
|
case 'n': _n = true; break;
|
||||||
_d = true;
|
case 'q': _q = true; break;
|
||||||
break;
|
case 'w': _w = true; break;
|
||||||
case 'f':
|
|
||||||
_f = true;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
_n = true;
|
|
||||||
break;
|
|
||||||
case 'q':
|
|
||||||
_q = true;
|
|
||||||
break;
|
|
||||||
case 'w':
|
|
||||||
_w = true;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
fdprintf(stderr, "### Exists - \"-%c\" is not an option.\n", c);
|
fdprintf(stderr, "### Exists - \"-%c\" is not an option.\n", c);
|
||||||
error = true;
|
error = true;
|
||||||
|
@ -773,15 +751,15 @@ int builtin_evaluate(Environment &env, std::vector<token> &&tokens, const fdmask
|
||||||
int builtin_which(Environment &env, const std::vector<std::string> &tokens, const fdmask &fds) {
|
int builtin_which(Environment &env, const std::vector<std::string> &tokens, const fdmask &fds) {
|
||||||
|
|
||||||
// which [-a] [-p] [command]
|
// which [-a] [-p] [command]
|
||||||
bool a = false;
|
bool _a = false;
|
||||||
bool p = false;
|
bool _p = false;
|
||||||
bool error = false;
|
bool error = false;
|
||||||
|
|
||||||
std::vector<std::string> argv = getopt(tokens, [&](char c){
|
std::vector<std::string> argv = getopt(tokens, [&](char c){
|
||||||
switch(c)
|
switch(tolower(c))
|
||||||
{
|
{
|
||||||
case 'a': case 'A': a = true; break;
|
case 'a': _a = true; break;
|
||||||
case 'p': case 'P': p = true; break;
|
case 'p': _p = true; break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fdprintf(stderr, "### Which - \"-%c\" is not an option.\n", c);
|
fdprintf(stderr, "### Which - \"-%c\" is not an option.\n", c);
|
||||||
|
@ -832,7 +810,7 @@ int builtin_which(Environment &env, const std::vector<std::string> &tokens, cons
|
||||||
}
|
}
|
||||||
|
|
||||||
for(; ss; ++ss) {
|
for(; ss; ++ss) {
|
||||||
if (p) fdprintf(stderr, "checking %s\n", ss->c_str());
|
if (_p) fdprintf(stderr, "checking %s\n", ss->c_str());
|
||||||
|
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
fs::path p(ToolBox::MacToUnix(ss->c_str()));
|
fs::path p(ToolBox::MacToUnix(ss->c_str()));
|
||||||
|
@ -841,13 +819,13 @@ int builtin_which(Environment &env, const std::vector<std::string> &tokens, cons
|
||||||
if (fs::exists(p, ec)) {
|
if (fs::exists(p, ec)) {
|
||||||
found = true;
|
found = true;
|
||||||
fdprintf(stdout, "%s\n", quote(p).c_str());
|
fdprintf(stdout, "%s\n", quote(p).c_str());
|
||||||
if (!a) break;
|
if (!_a) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check builtins...
|
// check builtins...
|
||||||
if (!found || a) {
|
if (!found || _a) {
|
||||||
|
|
||||||
static const char *builtins[] = {
|
static const char *builtins[] = {
|
||||||
"aboutbox",
|
"aboutbox",
|
||||||
|
@ -951,9 +929,7 @@ int builtin_version(Environment &env, const std::vector<std::string> &tokens, co
|
||||||
auto argv = getopt(tokens, [&](char c){
|
auto argv = getopt(tokens, [&](char c){
|
||||||
switch(tolower(c))
|
switch(tolower(c))
|
||||||
{
|
{
|
||||||
case 'v':
|
case 'v': _v = true; break;
|
||||||
_v = true;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
fdprintf(stderr, "### Version - \"-%c\" is not an option.\n", c);
|
fdprintf(stderr, "### Version - \"-%c\" is not an option.\n", c);
|
||||||
error = true;
|
error = true;
|
||||||
|
@ -1039,6 +1015,46 @@ int builtin_false(Environment &, const std::vector<std::string> &, const fdmask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int builtin_quit(Environment &, const std::vector<std::string> &tokens, const fdmask &fds) {
|
||||||
|
|
||||||
|
bool error = false;
|
||||||
|
bool _y = false;
|
||||||
|
bool _n = false;
|
||||||
|
bool _c = false;
|
||||||
|
|
||||||
|
auto argv = getopt(tokens, [&](char c){
|
||||||
|
switch(tolower(c))
|
||||||
|
{
|
||||||
|
case 'c': _c = true; break;
|
||||||
|
case 'n': _n = true; break;
|
||||||
|
case 'y': _y = true; break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fdprintf(stderr, "### Quit - \"-%c\" is not an option.\n", c);
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (_y + _n + _c > 1) {
|
||||||
|
fdprintf(stderr, "### Quit - Conflicting options were specified.\n");
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argv.size() > 0) {
|
||||||
|
fdprintf(stderr, "### Quit - Too many parameters were specified.\n");
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
fdprintf(stderr, "# Usage - Quit [-y | -n | -c]\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw quit_command_t{};
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int builtin_execute(Environment &e, const std::vector<std::string> &tokens, const fdmask &fds) {
|
int builtin_execute(Environment &e, const std::vector<std::string> &tokens, const fdmask &fds) {
|
||||||
|
|
||||||
// runs argv[1] in the current environment. unlike MPW, argv[1] must be a script.
|
// runs argv[1] in the current environment. unlike MPW, argv[1] must be a script.
|
||||||
|
|
|
@ -28,7 +28,7 @@ int builtin_unalias(Environment &e, const std::vector<std::string> &, const fdma
|
||||||
int builtin_execute(Environment &e, const std::vector<std::string> &, const fdmask &);
|
int builtin_execute(Environment &e, const std::vector<std::string> &, const fdmask &);
|
||||||
int builtin_true(Environment &e, const std::vector<std::string> &, const fdmask &);
|
int builtin_true(Environment &e, const std::vector<std::string> &, const fdmask &);
|
||||||
int builtin_false(Environment &e, const std::vector<std::string> &, const fdmask &);
|
int builtin_false(Environment &e, const std::vector<std::string> &, const fdmask &);
|
||||||
int builtin_execute(Environment &e, const std::vector<std::string> &, const fdmask &);
|
int builtin_quit(Environment &e, const std::vector<std::string> &, const fdmask &);
|
||||||
|
|
||||||
|
|
||||||
int builtin_evaluate(Environment &e, std::vector<token> &&, const fdmask &);
|
int builtin_evaluate(Environment &e, std::vector<token> &&, const fdmask &);
|
||||||
|
|
53
command.cpp
53
command.cpp
|
@ -5,6 +5,7 @@
|
||||||
#include "builtins.h"
|
#include "builtins.h"
|
||||||
#include "mpw-shell.h"
|
#include "mpw-shell.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
#include "cxx/filesystem.h"
|
#include "cxx/filesystem.h"
|
||||||
#include "cxx/string_splitter.h"
|
#include "cxx/string_splitter.h"
|
||||||
|
|
||||||
|
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
@ -40,8 +42,7 @@ typedef std::vector<token> token_vector;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct break_command_t {};
|
|
||||||
struct continue_command_t {};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns:
|
* returns:
|
||||||
|
@ -56,6 +57,12 @@ namespace {
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bad_exit() {
|
||||||
|
fprintf(stderr, "### Exit - Missing if keyword.\n");
|
||||||
|
fprintf(stderr, "# Usage - Exit [Number] [if expression...]\n");
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
int evaluate(int type, token_vector &&tokens, Environment &env) {
|
int evaluate(int type, token_vector &&tokens, Environment &env) {
|
||||||
std::reverse(tokens.begin(), tokens.end());
|
std::reverse(tokens.begin(), tokens.end());
|
||||||
|
|
||||||
|
@ -64,6 +71,8 @@ namespace {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
default: return 0;
|
default: return 0;
|
||||||
|
|
||||||
|
// exit [number] [if expr] ([number has been removed])
|
||||||
|
case EXIT:
|
||||||
case BREAK:
|
case BREAK:
|
||||||
case CONTINUE:
|
case CONTINUE:
|
||||||
case ELSE:
|
case ELSE:
|
||||||
|
@ -77,10 +86,12 @@ namespace {
|
||||||
case BREAK: name = "Break"; break;
|
case BREAK: name = "Break"; break;
|
||||||
case CONTINUE: name = "Continue"; break;
|
case CONTINUE: name = "Continue"; break;
|
||||||
case ELSE: name = "Else"; break;
|
case ELSE: name = "Else"; break;
|
||||||
|
case EXIT: name = "Exit"; return bad_exit(); break;
|
||||||
}
|
}
|
||||||
return bad_if(name);
|
return bad_if(name);
|
||||||
}
|
}
|
||||||
// fall through.
|
// fall through.
|
||||||
|
|
||||||
case IF:
|
case IF:
|
||||||
tokens.pop_back();
|
tokens.pop_back();
|
||||||
try {
|
try {
|
||||||
|
@ -202,6 +213,7 @@ namespace {
|
||||||
{"exists", builtin_exists},
|
{"exists", builtin_exists},
|
||||||
{"export", builtin_export},
|
{"export", builtin_export},
|
||||||
{"parameters", builtin_parameters},
|
{"parameters", builtin_parameters},
|
||||||
|
{"quit", builtin_quit},
|
||||||
{"quote", builtin_quote},
|
{"quote", builtin_quote},
|
||||||
{"set", builtin_set},
|
{"set", builtin_set},
|
||||||
{"shift", builtin_shift},
|
{"shift", builtin_shift},
|
||||||
|
@ -388,6 +400,10 @@ int eval_exec(std::string command, Environment &env, const fdmask &fds, bool thr
|
||||||
|
|
||||||
rv = fx(tokens);
|
rv = fx(tokens);
|
||||||
}
|
}
|
||||||
|
catch (const exit_command_t &ex) {
|
||||||
|
// convert to execution of input terminated.
|
||||||
|
throw execution_of_input_terminated(ex.value);
|
||||||
|
}
|
||||||
|
|
||||||
catch (mpw_error &e) {
|
catch (mpw_error &e) {
|
||||||
if (echo) env.echo("%s", command.c_str());
|
if (echo) env.echo("%s", command.c_str());
|
||||||
|
@ -442,6 +458,39 @@ int continue_command::execute(Environment &env, const fdmask &fds, bool throwup)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int exit_command::execute(Environment &env, const fdmask &fds, bool throwup) {
|
||||||
|
|
||||||
|
// exit
|
||||||
|
// exit [number] [if expr ]]
|
||||||
|
// todo --
|
||||||
|
|
||||||
|
return eval_exec(text, env, fds, throwup, [&](token_vector &tokens){
|
||||||
|
env.set("command", "exit");
|
||||||
|
env.status(0);
|
||||||
|
|
||||||
|
if (tokens.size() <= 1) {
|
||||||
|
throw exit_command_t{};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int status = 0;
|
||||||
|
value v(tokens[1]);
|
||||||
|
// remove the return value to make processing easier.
|
||||||
|
if (v.is_number()) {
|
||||||
|
tokens.erase(tokens.begin() + 1);
|
||||||
|
}
|
||||||
|
status = evaluate(EXIT, std::move(tokens), env);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
int ok = v.to_number(0);
|
||||||
|
throw exit_command_t{ok};
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
int or_command::execute(Environment &e, const fdmask &fds, bool throwup) {
|
int or_command::execute(Environment &e, const fdmask &fds, bool throwup) {
|
||||||
|
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
|
|
11
command.h
11
command.h
|
@ -22,7 +22,7 @@ struct command {
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual bool terminal() const noexcept {
|
virtual bool terminal() const noexcept {
|
||||||
return type == EVALUATE || type == COMMAND || type == BREAK || type == CONTINUE || type == ERROR;
|
return type == EVALUATE || type == COMMAND || type == BREAK || type == CONTINUE || type == ERROR || type == EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int type = 0;
|
int type = 0;
|
||||||
|
@ -81,6 +81,15 @@ struct continue_command : public command {
|
||||||
virtual int execute(Environment &e, const fdmask &fds, bool throwup) final override;
|
virtual int execute(Environment &e, const fdmask &fds, bool throwup) final override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct exit_command : public command {
|
||||||
|
|
||||||
|
template<class S>
|
||||||
|
exit_command(S &&s) : command(EXIT), text(std::forward<S>(s))
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string text;
|
||||||
|
virtual int execute(Environment &e, const fdmask &fds, bool throwup) final override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct binary_command : public command {
|
struct binary_command : public command {
|
||||||
|
|
11
error.h
11
error.h
|
@ -67,4 +67,15 @@ public:
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
these are used for flow-control.
|
||||||
|
they do not inherit from std::exception to prevent being caught
|
||||||
|
by normal handlers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct break_command_t {};
|
||||||
|
struct continue_command_t {};
|
||||||
|
struct exit_command_t { int value = 0; };
|
||||||
|
struct quit_command_t {};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -91,8 +91,12 @@ int read_file(Environment &e, const std::string &file, const fdmask &fds) {
|
||||||
mpw_parser p(e, fds);
|
mpw_parser p(e, fds);
|
||||||
e.status(0, false);
|
e.status(0, false);
|
||||||
|
|
||||||
p.parse(mf.begin(), mf.end());
|
try {
|
||||||
p.finish();
|
p.parse(mf.begin(), mf.end());
|
||||||
|
p.finish();
|
||||||
|
} catch(const execution_of_input_terminated &ex) {
|
||||||
|
return ex.status();
|
||||||
|
}
|
||||||
return e.status();
|
return e.status();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,9 +104,14 @@ int read_file(Environment &e, const std::string &file, const fdmask &fds) {
|
||||||
int read_string(Environment &e, const std::string &s, const fdmask &fds) {
|
int read_string(Environment &e, const std::string &s, const fdmask &fds) {
|
||||||
mpw_parser p(e, fds);
|
mpw_parser p(e, fds);
|
||||||
e.status(0, false);
|
e.status(0, false);
|
||||||
p.parse(s);
|
try {
|
||||||
p.finish();
|
p.parse(s);
|
||||||
|
p.finish();
|
||||||
|
} catch(const execution_of_input_terminated &ex) {
|
||||||
|
return ex.status();
|
||||||
|
}
|
||||||
return e.status();
|
return e.status();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,17 +123,21 @@ int read_fd(Environment &e, int fd, const fdmask &fds) {
|
||||||
mpw_parser p(e, fds);
|
mpw_parser p(e, fds);
|
||||||
e.status(0, false);
|
e.status(0, false);
|
||||||
|
|
||||||
for (;;) {
|
try {
|
||||||
size = read(fd, buffer, sizeof(buffer));
|
for (;;) {
|
||||||
if (size < 0) {
|
size = read(fd, buffer, sizeof(buffer));
|
||||||
if (errno == EINTR) continue;
|
if (size < 0) {
|
||||||
perror("read");
|
if (errno == EINTR) continue;
|
||||||
e.status(-1, false);
|
perror("read");
|
||||||
|
e.status(-1, false);
|
||||||
|
}
|
||||||
|
if (size == 0) break;
|
||||||
|
p.parse(buffer, buffer + size);
|
||||||
}
|
}
|
||||||
if (size == 0) break;
|
p.finish();
|
||||||
p.parse(buffer, buffer + size);
|
} catch(const execution_of_input_terminated &ex) {
|
||||||
|
return ex.status();
|
||||||
}
|
}
|
||||||
p.finish();
|
|
||||||
return e.status();
|
return e.status();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,19 +511,28 @@ int main(int argc, char **argv) {
|
||||||
read_file(e, startup);
|
read_file(e, startup);
|
||||||
} catch (const std::system_error &ex) {
|
} catch (const std::system_error &ex) {
|
||||||
fprintf(stderr, "### %s: %s\n", startup.c_str(), ex.what());
|
fprintf(stderr, "### %s: %s\n", startup.c_str(), ex.what());
|
||||||
|
} catch (const quit_command_t &) {
|
||||||
}
|
}
|
||||||
|
|
||||||
e.startup(false);
|
e.startup(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cflag) {
|
try {
|
||||||
read_string(e, cflag);
|
|
||||||
exit(e.status());
|
int rv = 0;
|
||||||
|
if (cflag) {
|
||||||
|
rv = read_string(e, cflag);
|
||||||
|
exit(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isatty(STDIN_FILENO))
|
||||||
|
rv = interactive(e);
|
||||||
|
else
|
||||||
|
rv = read_fd(e, STDIN_FILENO);
|
||||||
|
|
||||||
|
exit(rv);
|
||||||
|
}
|
||||||
|
catch (const quit_command_t &) {
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isatty(STDIN_FILENO))
|
|
||||||
interactive(e);
|
|
||||||
else
|
|
||||||
read_fd(e, STDIN_FILENO);
|
|
||||||
|
|
||||||
exit(e.status());
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,7 @@ void mpw_parser::execute() {
|
||||||
|
|
||||||
command_ptr cmd;
|
command_ptr cmd;
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (!commands.empty()) {
|
while (!commands.empty()) {
|
||||||
cmd = std::move(commands.back());
|
cmd = std::move(commands.back());
|
||||||
|
@ -94,7 +95,7 @@ void mpw_parser::execute() {
|
||||||
|
|
||||||
if (_interactive) {
|
if (_interactive) {
|
||||||
if (!cmd->terminal() || !commands.empty()) {
|
if (!cmd->terminal() || !commands.empty()) {
|
||||||
fprintf(stderr, "### %s\n", ex.what());
|
if (ex.status()) fprintf(stderr, "### %s\n", ex.what());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,6 +193,7 @@ int phase2::classify() {
|
||||||
_("else", ELSE)
|
_("else", ELSE)
|
||||||
_("end", END)
|
_("end", END)
|
||||||
_("evaluate", EVALUATE)
|
_("evaluate", EVALUATE)
|
||||||
|
_("exit", EXIT)
|
||||||
_("for", FOR)
|
_("for", FOR)
|
||||||
_("if", IF)
|
_("if", IF)
|
||||||
_("loop", LOOP)
|
_("loop", LOOP)
|
||||||
|
@ -233,6 +234,7 @@ bool phase2::special() {
|
||||||
case EVALUATE:
|
case EVALUATE:
|
||||||
case BREAK:
|
case BREAK:
|
||||||
case CONTINUE:
|
case CONTINUE:
|
||||||
|
case EXIT:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -139,6 +139,7 @@ term(RV) ::= COMMAND(C). { RV = std::make_unique<simple_command>(std::move
|
||||||
term(RV) ::= EVALUATE(C). { RV = std::make_unique<evaluate_command>(std::move(C)); }
|
term(RV) ::= EVALUATE(C). { RV = std::make_unique<evaluate_command>(std::move(C)); }
|
||||||
term(RV) ::= BREAK(C). { RV = std::make_unique<break_command>(std::move(C)); }
|
term(RV) ::= BREAK(C). { RV = std::make_unique<break_command>(std::move(C)); }
|
||||||
term(RV) ::= CONTINUE(C). { RV = std::make_unique<continue_command>(std::move(C)); }
|
term(RV) ::= CONTINUE(C). { RV = std::make_unique<continue_command>(std::move(C)); }
|
||||||
|
term(RV) ::= EXIT(C). { RV = std::make_unique<exit_command>(std::move(C)); }
|
||||||
term(C) ::= if_command(C).
|
term(C) ::= if_command(C).
|
||||||
term(C) ::= begin_command(C).
|
term(C) ::= begin_command(C).
|
||||||
term(C) ::= paren_command(C).
|
term(C) ::= paren_command(C).
|
||||||
|
|
Loading…
Reference in New Issue