diff --git a/builtins.cpp b/builtins.cpp index fb78d24..639aaa2 100644 --- a/builtins.cpp +++ b/builtins.cpp @@ -318,7 +318,60 @@ int builtin_unexport(Environment &env, const std::vector &tokens, c return export_common(env, false, tokens, fds); } +int builtin_alias(Environment &env, const std::vector &tokens, const fdmask &fds) { + // alias -> lists all aliases + // alias name -> list single alias + // alias name parms... -> add a new alias. + + if (tokens.size() == 1) { + for (const auto &p : env.aliases()) { + fprintf(stdout, "Alias %s %s\n", quote(p.first).c_str(), quote(p.second).c_str()); + } + return 0; + } + + std::string name = tokens[1]; + if (tokens.size() == 2) { + const auto as = env.find_alias(name); + if (as.empty()) { + fprintf(stderr, "### Alias - No alias exists for %s\n", quote(name).c_str()); + return 1; + } + fprintf(stdout, "Alias %s %s\n", quote(name).c_str(), quote(as).c_str()); + return 0; + } + + std::string as; + for (const auto &s : make_offset_range(tokens, 2)) { + as += s; + as.push_back(' '); + } + as.pop_back(); + + // add/remove it to the alias table... + + if (as.empty()) { + env.remove_alias(name); + } + else { + env.add_alias(std::move(name), std::move(as)); + } + return 0; +} + +int builtin_unalias(Environment &env, const std::vector &tokens, const fdmask &) { + // unalias -> remove all aliases. + // unalias name -> remove single alias. + if (tokens.size() == 1) { + env.remove_alias(); + return 0; + } + for (const auto &x : make_offset_range(tokens, 1)) { + env.remove_alias(x); + } + return 0; +} int builtin_echo(Environment &env, const std::vector &tokens, const fdmask &fds) { diff --git a/builtins.h b/builtins.h index 597bd76..c86ff11 100644 --- a/builtins.h +++ b/builtins.h @@ -21,6 +21,8 @@ int builtin_unexport(Environment &e, const std::vector &, const fdm int builtin_unset(Environment &e, const std::vector &, const fdmask &); int builtin_version(Environment &e, const std::vector &, const fdmask &); int builtin_which(Environment &e, const std::vector &, const fdmask &); +int builtin_alias(Environment &e, const std::vector &, const fdmask &); +int builtin_unalias(Environment &e, const std::vector &, const fdmask &); int builtin_evaluate(Environment &e, std::vector &&, const fdmask &); diff --git a/command.cpp b/command.cpp index 0eb0eda..43a628b 100644 --- a/command.cpp +++ b/command.cpp @@ -168,6 +168,7 @@ namespace { std::unordered_map &, const fdmask &)> builtins = { {"aboutbox", builtin_aboutbox}, + {"alias", builtin_alias}, {"directory", builtin_directory}, {"echo", builtin_echo}, {"exists", builtin_exists}, @@ -176,6 +177,7 @@ namespace { {"quote", builtin_quote}, {"set", builtin_set}, {"shift", builtin_shift}, + {"unalias", builtin_unalias}, {"unexport", builtin_unexport}, {"unset", builtin_unset}, {"version", builtin_version}, diff --git a/environment.cpp b/environment.cpp index 4544cc3..77f7622 100644 --- a/environment.cpp +++ b/environment.cpp @@ -190,3 +190,66 @@ namespace { } + void Environment::rebuild_aliases() { + std::string as; + for (const auto &p : _alias_table) { + as += p.first; + as.push_back(','); + } + as.pop_back(); + set_common("aliases", as, true); + } + + void Environment::remove_alias() { + _alias_table.clear(); + set_common("aliases", "", true); + } + + void Environment::remove_alias(const std::string &name) { + + std::string k(name); + lowercase(k); + + auto iter = std::remove_if(_alias_table.begin(), _alias_table.end(), [&k](const auto &p){ + return k == p.first; + }); + _alias_table.erase(iter, _alias_table.end()); + rebuild_aliases(); + } + + const std::string &Environment::find_alias(const std::string &name) const { + + std::string k(name); + lowercase(k); + + auto iter = std::find_if(_alias_table.begin(), _alias_table.end(), [&k](const auto &p){ + return k == p.first; + }); + + if (iter == _alias_table.end()) { + static std::string empty; + return empty; + } + return iter->second; + } + + void Environment::add_alias(std::string &&name, std::string &&value) { + + lowercase(name); + + auto iter = std::find_if(_alias_table.begin(), _alias_table.end(), [&name](const auto &p){ + return name == p.first; + }); + + if (iter == _alias_table.end()) { + _alias_table.emplace_back(std::make_pair(std::move(name), std::move(value))); + } else { + iter->second = std::move(value); + } + rebuild_aliases(); + } + + + + + diff --git a/environment.h b/environment.h index 1c6fee0..7e6c01d 100644 --- a/environment.h +++ b/environment.h @@ -51,6 +51,10 @@ public: typedef mapped_type::iterator iterator; typedef mapped_type::const_iterator const_iterator; + + typedef std::vector> alias_table_type; + typedef alias_table_type::const_iterator const_alias_iterator; + //const EnvironmentEntry & lookup(const std::string &s); void set_argv(const std::string &argv0, const std::vector& argv); @@ -114,6 +118,17 @@ public: constexpr bool loop() const noexcept { return _loop; } + const alias_table_type &aliases() const { return _alias_table; } + + void add_alias(std::string &&name, std::string &&value); + const std::string &find_alias(const std::string &s) const; + + void remove_alias(const std::string &name); + void remove_alias(); + + const_alias_iterator alias_begin() const { return _alias_table.begin(); } + const_alias_iterator alias_end() const { return _alias_table.end(); } + private: // magic variables. @@ -132,8 +147,11 @@ private: bool _passthrough = false; void set_common(const std::string &, const std::string &, bool); + void rebuild_aliases(); std::unordered_map _table; + + alias_table_type _alias_table; }; /*