shift builtin.

This commit is contained in:
Kelvin Sherlock 2016-06-16 16:48:04 -04:00
parent c8f1e370dc
commit 8a2b9ec3cd
5 changed files with 164 additions and 1 deletions

View File

@ -84,6 +84,81 @@ inline int fputc(int c, int fd) {
auto rv = write(fd, &tmp, 1); return rv < 0 ? EOF : c;
}
std::vector<std::string> load_argv(Environment &env) {
std::vector<std::string> rv;
int n = env.pound();
if ( n <= 0 ) return rv;
n = std::min(n, (int)255);
rv.reserve(n);
for (int i = 1; i <= n; ++i) {
rv.push_back(env.get(std::to_string(i)));
}
return rv;
}
int builtin_shift(Environment &env, const std::vector<std::string> &tokens, const fdmask &fds) {
int n = 1;
if (tokens.size() > 3) {
fputs("### Shift - Too many parameters were specified.\n", stderr);
fputs("# Usage - Shift [number]\n", stderr);
return 1;
}
if (tokens.size() == 2) {
value v(tokens[1]);
if (v.is_number() && v.number >= 0) n = v.number;
else {
fputs("### Shift - The parameter must be a positive number.\n", stderr);
fputs("# Usage - Shift [number]\n", stderr);
return 1;
}
}
if (n == 0) return 0;
auto argv = load_argv(env);
if (argv.empty()) return 0;
std::move(argv.begin() + n , argv.end(), argv.begin());
do {
env.unset(std::to_string(argv.size()));
argv.pop_back();
} while (--n);
env.set_argv(argv);
/*
for (unsigned i = 0; i < argv.size(); ++i) {
env.set(std::to_string(i+1), argv[i]);
}
env.set("#", argv.size());
// fix Parameters and "Parameters"
std::string p;
for (const auto &s : argv) {
p += quote(s);
p += " ";
}
p.pop_back();
env.set("\"Parameters\"", p);
p.clear();
for (const auto &s : argv) {
p += s;
p += " ";
}
p.pop_back();
env.set("Parameters", p);
*/
return 0;
}
int builtin_unset(Environment &env, const std::vector<std::string> &tokens, const fdmask &) {
for (auto iter = tokens.begin() + 1; iter != tokens.end(); ++iter) {

View File

@ -16,6 +16,7 @@ int builtin_export(Environment &e, const std::vector<std::string> &, const fdmas
int builtin_parameters(Environment &e, const std::vector<std::string> &, const fdmask &);
int builtin_quote(Environment &e, const std::vector<std::string> &tokens, const fdmask &);
int builtin_set(Environment &e, const std::vector<std::string> &, const fdmask &);
int builtin_shift(Environment &e, const std::vector<std::string> &, const fdmask &);
int builtin_unexport(Environment &e, const std::vector<std::string> &, const fdmask &);
int builtin_unset(Environment &e, const std::vector<std::string> &, const fdmask &);
int builtin_version(Environment &e, const std::vector<std::string> &, const fdmask &);

View File

@ -175,6 +175,7 @@ namespace {
{"parameters", builtin_parameters},
{"quote", builtin_quote},
{"set", builtin_set},
{"shift", builtin_shift},
{"unexport", builtin_unexport},
{"unset", builtin_unset},
{"version", builtin_version},

View File

@ -18,6 +18,22 @@ namespace {
if (s.size() == 1 && s == "0") return false;
return true;
}
bool tf(long v) { return v; }
// used for #. base 10 only, extra chars ignored.
int to_pound_int(const std::string &s) {
if (s.empty()) return 0;
try {
int n = stoi(s);
return std::max(n, (int)0);
}
catch(std::exception e) {}
return 0;
}
int to_pound_int(long n) { return std::max(n, (long)0); }
}
std::string Environment::get(const std::string & key) const {
@ -38,6 +54,7 @@ namespace {
return _table.find(k);
}
void Environment::set(const std::string &key, const std::string &value, bool exported) {
std::string k(key);
lowercase(k);
@ -45,10 +62,65 @@ namespace {
if (k == "echo") _echo = tf(value);
if (k == "exit") _exit = tf(value);
if (k == "test") _test = tf(value);
if (k == "#") _pound = to_pound_int(value);
// don't need to check {status} because that will be clobbered
// by the return value.
set_common(k, value, exported);
}
void Environment::set(const std::string &key, long value, bool exported) {
std::string k(key);
lowercase(k);
if (k == "echo") _echo = tf(value);
if (k == "exit") _exit = tf(value);
if (k == "test") _test = tf(value);
if (k == "#") _pound = to_pound_int(value);
// don't need to check {status} because that will be clobbered
// by the return value.
set_common(k, std::to_string(value), exported);
}
void Environment::set_argv(const std::string &argv0, const std::vector<std::string>& argv) {
set_common("0", argv0, false);
set_argv(argv);
}
void Environment::set_argv(const std::vector<std::string>& argv) {
_pound = argv.size();
set_common("#", std::to_string(argv.size()), false);
int n = 1;
for (const auto &s : argv) {
set_common(std::to_string(n++), s, false);
}
// parameters, "parameters" ...
std::string p;
for (const auto &s : argv) {
p.push_back('"');
p += s;
p.push_back('"');
p.push_back(' ');
}
p.pop_back();
set_common("\"parameters\"", p, false);
p.clear();
for (const auto &s : argv) {
p += s;
p.push_back(' ');
}
p.pop_back();
set_common("parameters", p, false);
}
void Environment::set_common(const std::string &k, const std::string &value, bool exported)
{
EnvironmentEntry v(value, exported);
auto iter = _table.find(k);
@ -59,15 +131,20 @@ namespace {
// if previously exported, keep exported.
if (iter->second) v = true;
iter->second = std::move(v);
}
}
}
void Environment::unset(const std::string &key) {
std::string k(key);
lowercase(k);
if (k == "echo") _echo = false;
if (k == "exit") _exit = false;
if (k == "test") _test = false;
if (k == "#") _pound = 0;
_table.erase(k);
}

View File

@ -5,6 +5,7 @@
#include <unordered_map>
#include <utility>
#include <new>
#include <vector>
@ -52,7 +53,11 @@ public:
//const EnvironmentEntry & lookup(const std::string &s);
void set_argv(const std::string &argv0, const std::vector<std::string>& argv);
void set_argv(const std::vector<std::string>& argv);
void set(const std::string &k, const std::string &value, bool exported = false);
void set(const std::string &k, long l, bool exported = false);
void unset(const std::string &k);
void unset();
@ -62,6 +67,7 @@ public:
constexpr bool test() const noexcept { return _test; }
constexpr bool exit() const noexcept { return _exit; }
constexpr int status() const noexcept { return _status; }
constexpr int pound() const noexcept { return _pound; }
int status(int i, bool throw_up = true);
int status(int i, const std::nothrow_t &);
@ -121,9 +127,12 @@ private:
bool _echo = false;
int _status = 0;
int _pound = 0;
bool _startup = false;
bool _passthrough = false;
void set_common(const std::string &, const std::string &, bool);
std::unordered_map<std::string, EnvironmentEntry> _table;
};