summaryrefslogtreecommitdiffstats
path: root/src/shlex.hh
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/shlex.hh173
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,