replace var_entry_t with env_var_t

This is a step to storing fish vars as actual vectors rather than flat
strings.
This commit is contained in:
Kurtis Rader
2017-08-09 11:11:58 -07:00
parent 745a88f2f6
commit 728a4634a1
11 changed files with 120 additions and 126 deletions

View File

@@ -126,8 +126,8 @@ class env_node_t {
/// Pointer to next level.
std::unique_ptr<env_node_t> next;
/// Returns a pointer to the given entry if present, or NULL.
const var_entry_t *find_entry(const wcstring &key);
/// Returns the given entry if present else env_var_t::missing_var.
const env_var_t find_entry(const wcstring &key);
};
class variable_entry_t {
@@ -174,27 +174,21 @@ struct var_stack_t {
env_node_t *next_scope_to_search(env_node_t *node);
const env_node_t *next_scope_to_search(const env_node_t *node) const;
// Returns the scope used for unspecified scopes
// An unspecified scope is either the topmost shadowing scope, or the global scope if none
// This implements the default behavior of 'set'
// Returns the scope used for unspecified scopes. An unspecified scope is either the topmost
// shadowing scope, or the global scope if none. This implements the default behavior of `set`.
env_node_t *resolve_unspecified_scope();
};
void var_stack_t::push(bool new_scope) {
std::unique_ptr<env_node_t> node(new env_node_t(new_scope));
// Copy local-exported variables
// Copy local-exported variables.
auto top_node = top.get();
// Only if we introduce a new shadowing scope
// i.e. not if it's just `begin; end` or "--no-scope-shadowing".
if (new_scope) {
if (!(top_node == this->global_env)) {
for (auto &var : top_node->env) {
if (var.second.exportv) {
// This should copy var
node->env.insert(var);
}
}
// Only if we introduce a new shadowing scope; i.e. not if it's just `begin; end` or
// "--no-scope-shadowing".
if (new_scope && top_node != this->global_env) {
for (auto &var : top_node->env) {
if (var.second.exportv) node->env.insert(var);
}
}
@@ -240,8 +234,8 @@ void var_stack_t::pop() {
assert(this->top != NULL);
for (const auto &entry_pair : old_top->env) {
const var_entry_t &entry = entry_pair.second;
if (entry.exportv) {
const env_var_t &var = entry_pair.second;
if (var.exportv) {
this->mark_changed_exported();
break;
}
@@ -309,13 +303,10 @@ static bool is_electric(const wcstring &key) {
return env_electric.find(key.c_str()) != env_electric.end();
}
const var_entry_t *env_node_t::find_entry(const wcstring &key) {
const var_entry_t *result = NULL;
var_table_t::const_iterator where = env.find(key);
if (where != env.end()) {
result = &where->second;
}
return result;
const env_var_t env_node_t::find_entry(const wcstring &key) {
var_table_t::const_iterator entry = env.find(key);
if (entry != env.end()) return entry->second;
return env_var_t::missing_var();
}
/// Return the current umask value.
@@ -959,10 +950,8 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
static env_node_t *env_get_node(const wcstring &key) {
env_node_t *env = vars_stack().top.get();
while (env != NULL) {
if (env->find_entry(key) != NULL) {
break;
}
env_var_t var = env->find_entry(key);
if (!var.missing()) break;
env = vars_stack().next_scope_to_search(env);
}
return env;
@@ -1059,8 +1048,8 @@ int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t var_mode)
if (preexisting_node != NULL) {
var_table_t::const_iterator result = preexisting_node->env.find(key);
assert(result != preexisting_node->env.end());
const var_entry_t &entry = result->second;
if (entry.exportv) {
const env_var_t &var = result->second;
if (var.exportv) {
preexisting_entry_exportv = true;
has_changed_new = true;
}
@@ -1074,7 +1063,7 @@ int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t var_mode)
} else if (preexisting_node != NULL) {
node = preexisting_node;
if ((var_mode & (ENV_EXPORT | ENV_UNEXPORT)) == 0) {
// use existing entry's exportv
// Use existing entry's exportv status.
var_mode = //!OCLINT(parameter reassignment)
preexisting_entry_exportv ? ENV_EXPORT : 0;
}
@@ -1108,20 +1097,21 @@ int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t var_mode)
if (!done) {
// Set the entry in the node. Note that operator[] accesses the existing entry, or
// creates a new one.
var_entry_t &entry = node->env[key];
if (entry.exportv) {
env_var_t &var = node->env[key];
if (var.exportv) {
// This variable already existed, and was exported.
has_changed_new = true;
}
entry.val = val;
var.set_val(val);
if (var_mode & ENV_EXPORT) {
// The new variable is exported.
entry.exportv = true;
var.exportv = true;
node->exportv = true;
has_changed_new = true;
} else {
entry.exportv = false;
// Set the node's exportv when it changes something about exports
var.exportv = false;
// Set the node's exported when it changes something about exports
// (also when it redefines a variable to not be exported).
node->exportv = has_changed_old != has_changed_new;
}
@@ -1219,7 +1209,7 @@ int env_remove(const wcstring &key, int var_mode) {
}
wcstring env_var_t::as_string(void) const {
assert(!is_missing);
//assert(!is_missing);
return val;
}
@@ -1276,12 +1266,15 @@ env_var_t env_get(const wcstring &key, env_mode_flags_t mode) {
env_node_t *env = search_local ? vars_stack().top.get() : vars_stack().global_env;
while (env != NULL) {
const var_entry_t *entry = env->find_entry(key);
if (entry != NULL && (entry->exportv ? search_exported : search_unexported)) {
if (entry->val == ENV_NULL) {
return env_var_t::missing_var();
}
return entry->val;
const env_var_t var = env->find_entry(key);
if (!var.missing() && (var.exportv ? search_exported : search_unexported)) {
// The following statement is wrong because ENV_NULL is supposed to mean the var is
// set but has zero elements. Therefore we should not return missing_var. However,
// If this is changed to return `var` without the special-case then unit tests fail.
// Note that tokenize_variable_array() explicitly handles a var whose string
// representation contains only ENV_NULL.
if (var.as_string() == ENV_NULL) return env_var_t::missing_var();
return var;
}
if (has_scope) {
@@ -1342,8 +1335,8 @@ bool env_exist(const wchar_t *key, env_mode_flags_t mode) {
var_table_t::const_iterator result = env->env.find(key);
if (result != env->env.end()) {
const var_entry_t &res = result->second;
return res.exportv ? test_exported : test_unexported;
const env_var_t var = result->second;
return var.exportv ? test_exported : test_unexported;
}
env = vars_stack().next_scope_to_search(env);
}
@@ -1385,9 +1378,9 @@ static void add_key_to_string_set(const var_table_t &envs, std::set<wcstring> *s
bool show_exported, bool show_unexported) {
var_table_t::const_iterator iter;
for (iter = envs.begin(); iter != envs.end(); ++iter) {
const var_entry_t &e = iter->second;
const env_var_t &var = iter->second;
if ((e.exportv && show_exported) || (!e.exportv && show_unexported)) {
if ((var.exportv && show_exported) || (!var.exportv && show_unexported)) {
// Insert this key.
str_set->insert(iter->first);
}
@@ -1440,39 +1433,39 @@ wcstring_list_t env_get_names(int flags) {
}
/// Get list of all exported variables.
static void get_exported(const env_node_t *n, std::map<wcstring, wcstring> *h) {
static void get_exported(const env_node_t *n, var_table_t &h) {
if (!n) return;
if (n->new_scope)
if (n->new_scope) {
get_exported(vars_stack().global_env, h);
else
} else {
get_exported(n->next.get(), h);
}
var_table_t::const_iterator iter;
for (iter = n->env.begin(); iter != n->env.end(); ++iter) {
const wcstring &key = iter->first;
const var_entry_t &val_entry = iter->second;
const env_var_t var = iter->second;
if (val_entry.exportv && val_entry.val != ENV_NULL) {
if (!var.missing() && var.exportv) {
// Export the variable. Don't use std::map::insert here, since we need to overwrite
// existing values from previous scopes.
(*h)[key] = val_entry.val;
h[key] = var;
} else {
// We need to erase from the map if we are not exporting, since a lower scope may have
// exported. See #2132.
h->erase(key);
h.erase(key);
}
}
}
// Given a map from key to value, add values to out of the form key=value.
static void export_func(const std::map<wcstring, wcstring> &envs, std::vector<std::string> &out) {
static void export_func(const var_table_t &envs, std::vector<std::string> &out) {
out.reserve(out.size() + envs.size());
std::map<wcstring, wcstring>::const_iterator iter;
for (iter = envs.begin(); iter != envs.end(); ++iter) {
for (auto iter = envs.begin(); iter != envs.end(); ++iter) {
const wcstring &key = iter->first;
const std::string &ks = wcs2string(key);
std::string vs = wcs2string(iter->second);
std::string vs = wcs2string(iter->second.as_string());
// Arrays in the value are ASCII record separator (0x1e) delimited. But some variables
// should have colons. Add those.
@@ -1497,11 +1490,10 @@ void var_stack_t::update_export_array_if_necessary() {
if (!this->has_changed_exported) {
return;
}
std::map<wcstring, wcstring> vals;
debug(4, L"env_export_arr() recalc");
get_exported(this->top.get(), &vals);
var_table_t vals;
get_exported(this->top.get(), vals);
if (uvars()) {
const wcstring_list_t uni = uvars()->get_names(true, false);
@@ -1544,7 +1536,7 @@ void env_set_argv(const wchar_t *const *argv) {
env_set(L"argv", sb.c_str(), ENV_LOCAL);
} else {
env_set(L"argv", 0, ENV_LOCAL);
env_set(L"argv", NULL, ENV_LOCAL);
}
}