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:
Kelvin Sherlock
2016-08-30 12:25:43 -04:00
parent f6c5478063
commit f125b533f7
9 changed files with 190 additions and 79 deletions

View File

@@ -5,6 +5,7 @@
#include "builtins.h"
#include "mpw-shell.h"
#include "error.h"
#include "value.h"
#include <stdexcept>
#include <unordered_map>
@@ -17,6 +18,7 @@
#include "cxx/filesystem.h"
#include "cxx/string_splitter.h"
#include <strings.h>
#include <unistd.h>
#include <sys/wait.h>
@@ -40,8 +42,7 @@ typedef std::vector<token> token_vector;
namespace {
struct break_command_t {};
struct continue_command_t {};
/*
* returns:
@@ -56,6 +57,12 @@ namespace {
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) {
std::reverse(tokens.begin(), tokens.end());
@@ -64,6 +71,8 @@ namespace {
switch(type) {
default: return 0;
// exit [number] [if expr] ([number has been removed])
case EXIT:
case BREAK:
case CONTINUE:
case ELSE:
@@ -77,10 +86,12 @@ namespace {
case BREAK: name = "Break"; break;
case CONTINUE: name = "Continue"; break;
case ELSE: name = "Else"; break;
case EXIT: name = "Exit"; return bad_exit(); break;
}
return bad_if(name);
}
// fall through.
case IF:
tokens.pop_back();
try {
@@ -202,6 +213,7 @@ namespace {
{"exists", builtin_exists},
{"export", builtin_export},
{"parameters", builtin_parameters},
{"quit", builtin_quit},
{"quote", builtin_quote},
{"set", builtin_set},
{"shift", builtin_shift},
@@ -388,6 +400,10 @@ int eval_exec(std::string command, Environment &env, const fdmask &fds, bool thr
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) {
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 rv = 0;