diff options
Diffstat (limited to '')
-rw-r--r-- | src/shlex.hh | 173 |
1 files changed, 40 insertions, 133 deletions
diff --git a/src/shlex.hh b/src/shlex.hh index 2317a2c..b51d86f 100644 --- a/src/shlex.hh +++ b/src/shlex.hh @@ -32,32 +32,36 @@ #ifndef LNAV_SHLEX_HH_H #define LNAV_SHLEX_HH_H +#include <functional> #include <map> #include <string> #include <vector> #include <pwd.h> +#include "base/attr_line.hh" #include "base/intern_string.hh" #include "base/opt_util.hh" #include "shlex.resolver.hh" enum class shlex_token_t { - ST_ERROR, - ST_WHITESPACE, - ST_ESCAPE, - ST_DOUBLE_QUOTE_START, - ST_DOUBLE_QUOTE_END, - ST_SINGLE_QUOTE_START, - ST_SINGLE_QUOTE_END, - ST_VARIABLE_REF, - ST_QUOTED_VARIABLE_REF, - ST_TILDE, + eof, + whitespace, + escape, + double_quote_start, + double_quote_end, + single_quote_start, + single_quote_end, + variable_ref, + quoted_variable_ref, + tilde, }; class shlex { public: - shlex(const char* str, size_t len) : s_str(str), s_len(len){}; + static std::string escape(std::string s); + + shlex(const char* str, size_t len) : s_str(str), s_len(len) {} explicit shlex(const string_fragment& sf) : s_str(sf.data()), s_len(sf.length()) @@ -65,7 +69,9 @@ public: } explicit shlex(const std::string& str) - : s_str(str.c_str()), s_len(str.size()){}; + : s_str(str.c_str()), s_len(str.size()) + { + } shlex& with_ignore_quotes(bool val) { @@ -73,128 +79,27 @@ public: return *this; } - bool tokenize(string_fragment& cap_out, shlex_token_t& token_out); + struct tokenize_result_t { + shlex_token_t tr_token; + string_fragment tr_frag; + }; - template<typename Resolver = scoped_resolver> - bool eval(std::string& result, const Resolver& vars) - { - result.clear(); - - string_fragment cap; - shlex_token_t token; - int last_index = 0; - - while (this->tokenize(cap, token)) { - result.append(&this->s_str[last_index], cap.sf_begin - last_index); - switch (token) { - case shlex_token_t::ST_ERROR: - return false; - case shlex_token_t::ST_ESCAPE: - result.append(1, this->s_str[cap.sf_begin + 1]); - break; - case shlex_token_t::ST_WHITESPACE: - result.append(&this->s_str[cap.sf_begin], cap.length()); - break; - case shlex_token_t::ST_VARIABLE_REF: - case shlex_token_t::ST_QUOTED_VARIABLE_REF: { - int extra = token == shlex_token_t::ST_VARIABLE_REF ? 0 : 1; - std::string var_name(&this->s_str[cap.sf_begin + 1 + extra], - cap.length() - 1 - extra * 2); - auto local_var = vars.find(var_name); - const char* var_value = getenv(var_name.c_str()); - - if (local_var != vars.end()) { - result.append(fmt::to_string(local_var->second)); - } else if (var_value != nullptr) { - result.append(var_value); - } - break; - } - case shlex_token_t::ST_TILDE: - this->resolve_home_dir(result, cap); - break; - case shlex_token_t::ST_DOUBLE_QUOTE_START: - case shlex_token_t::ST_DOUBLE_QUOTE_END: - result.append("\""); - break; - case shlex_token_t::ST_SINGLE_QUOTE_START: - case shlex_token_t::ST_SINGLE_QUOTE_END: - result.append("'"); - break; - default: - break; - } - last_index = cap.sf_end; - } - - result.append(&this->s_str[last_index], this->s_len - last_index); - - return true; - } + struct tokenize_error_t { + const char* te_msg{nullptr}; + string_fragment te_source; + }; - template<typename Resolver> - bool split(std::vector<std::string>& result, const Resolver& vars) - { - result.clear(); - - string_fragment cap; - shlex_token_t token; - int last_index = 0; - bool start_new = true; - - while (isspace(this->s_str[this->s_index])) { - this->s_index += 1; - } - while (this->tokenize(cap, token)) { - if (start_new) { - result.emplace_back(""); - start_new = false; - } - result.back().append(&this->s_str[last_index], - cap.sf_begin - last_index); - switch (token) { - case shlex_token_t::ST_ERROR: - return false; - case shlex_token_t::ST_ESCAPE: - result.back().append(1, this->s_str[cap.sf_begin + 1]); - break; - case shlex_token_t::ST_WHITESPACE: - start_new = true; - break; - case shlex_token_t::ST_VARIABLE_REF: - case shlex_token_t::ST_QUOTED_VARIABLE_REF: { - int extra = token == shlex_token_t::ST_VARIABLE_REF ? 0 : 1; - std::string var_name(&this->s_str[cap.sf_begin + 1 + extra], - cap.length() - 1 - extra * 2); - auto local_var = vars.find(var_name); - const char* var_value = getenv(var_name.c_str()); - - if (local_var != vars.end()) { - result.back().append(fmt::to_string(local_var->second)); - } else if (var_value != nullptr) { - result.back().append(var_value); - } - break; - } - case shlex_token_t::ST_TILDE: - this->resolve_home_dir(result.back(), cap); - break; - default: - break; - } - last_index = cap.sf_end; - } - - if (last_index < this->s_len) { - if (start_new || result.empty()) { - result.emplace_back(""); - } - result.back().append(&this->s_str[last_index], - this->s_len - last_index); - } - - return true; - } + Result<tokenize_result_t, tokenize_error_t> tokenize(); + + bool eval(std::string& result, const scoped_resolver& vars); + + struct split_element_t { + string_fragment se_origin; + std::string se_value; + }; + + Result<std::vector<split_element_t>, tokenize_error_t> split( + const scoped_resolver& vars); void reset() { @@ -202,10 +107,12 @@ public: this->s_state = state_t::STATE_NORMAL; } - void scan_variable_ref(string_fragment& cap_out, shlex_token_t& token_out); + Result<tokenize_result_t, tokenize_error_t> scan_variable_ref(); void resolve_home_dir(std::string& result, string_fragment cap) const; + attr_line_t to_attr_line(const tokenize_error_t& te) const; + enum class state_t { STATE_NORMAL, STATE_IN_DOUBLE_QUOTE, |