aboutsummaryrefslogtreecommitdiffhomepage
path: root/env.cpp
diff options
context:
space:
mode:
authorGravatar Kevin Ballard <kevin@sb.org>2014-07-12 14:40:46 -0700
committerGravatar Kevin Ballard <kevin@sb.org>2014-07-12 15:35:34 -0700
commitdcc043df3b4d3f2f8aae5d8e8fe50051f78ce848 (patch)
treeec71da325775526d617e946bef394210154176c3 /env.cpp
parent2457997cd9c624034f28f1be218f93cdc60a3e58 (diff)
Add an optional mode to env_get_string()
The mode restricts the scope in which the variable is searched for. Use this new restricted scope functionality in the `set` builtin. This fixes `set -g` to not show local shadowing variable values, and also allows for scoped erasing of slices.
Diffstat (limited to 'env.cpp')
-rw-r--r--env.cpp133
1 files changed, 79 insertions, 54 deletions
diff --git a/env.cpp b/env.cpp
index 77ee75aa..278e2af4 100644
--- a/env.cpp
+++ b/env.cpp
@@ -936,82 +936,107 @@ const wchar_t *env_var_t::c_str(void) const
return wcstring::c_str();
}
-env_var_t env_get_string(const wcstring &key)
+env_var_t env_get_string(const wcstring &key, int mode)
{
- /* Big hack...we only allow getting the history on the main thread. Note that history_t may ask for an environment variable, so don't take the lock here (we don't need it) */
- const bool is_main = is_main_thread();
- if (key == L"history" && is_main)
+ const bool has_scope = mode & (ENV_LOCAL | ENV_GLOBAL | ENV_UNIVERSAL);
+ const bool search_local = !has_scope || (mode & ENV_LOCAL);
+ const bool search_global = !has_scope || (mode & ENV_GLOBAL);
+ const bool search_universal = !has_scope || (mode & ENV_UNIVERSAL);
+
+ const bool search_exported = (mode & ENV_EXPORT) || !(mode & ENV_UNEXPORT);
+ const bool search_unexported = (mode & ENV_UNEXPORT) || !(mode & ENV_EXPORT);
+
+ /* Make the assumption that electric keys can't be shadowed elsewhere, since we currently block that in env_set() */
+ if (is_electric(key))
{
- env_var_t result;
+ if (!search_global) return env_var_t::missing_var();
+ /* Big hack...we only allow getting the history on the main thread. Note that history_t may ask for an environment variable, so don't take the lock here (we don't need it) */
+ if (key == L"history" && is_main_thread())
+ {
+ env_var_t result;
- history_t *history = reader_get_history();
- if (! history)
+ history_t *history = reader_get_history();
+ if (! history)
+ {
+ history = &history_t::history_with_name(L"fish");
+ }
+ if (history)
+ history->get_string_representation(result, ARRAY_SEP_STR);
+ return result;
+ }
+ else if (key == L"COLUMNS")
{
- history = &history_t::history_with_name(L"fish");
+ return to_string(common_get_width());
}
- if (history)
- history->get_string_representation(result, ARRAY_SEP_STR);
- return result;
- }
- else if (key == L"COLUMNS")
- {
- return to_string(common_get_width());
- }
- else if (key == L"LINES")
- {
- return to_string(common_get_height());
- }
- else if (key == L"status")
- {
- return to_string(proc_get_last_status());
- }
- else if (key == L"umask")
- {
- return format_string(L"0%0.3o", get_umask());
- }
- else
- {
+ else if (key == L"LINES")
{
- /* Lock around a local region */
- scoped_lock lock(env_lock);
+ return to_string(common_get_height());
+ }
+ else if (key == L"status")
+ {
+ return to_string(proc_get_last_status());
+ }
+ else if (key == L"umask")
+ {
+ return format_string(L"0%0.3o", get_umask());
+ }
+ // we should never get here unless the electric var list is out of sync
+ }
- env_node_t *env = top;
- wcstring result;
+ if (search_local || search_global) {
+ /* Lock around a local region */
+ scoped_lock lock(env_lock);
- while (env != NULL)
+ env_node_t *env = search_local ? top : global_env;
+ wcstring result;
+
+ while (env != NULL)
+ {
+ const var_entry_t *entry = env->find_entry(key);
+ if (entry != NULL && (entry->exportv ? search_exported : search_unexported))
{
- const var_entry_t *entry = env->find_entry(key);
- if (entry != NULL)
+ if (entry->val == ENV_NULL)
+ {
+ return env_var_t::missing_var();
+ }
+ else
{
- if (entry->val == ENV_NULL)
- {
- return env_var_t::missing_var();
- }
- else
- {
- return entry->val;
- }
+ return entry->val;
}
+ }
+ if (has_scope)
+ {
+ if (!search_global || env == global_env) break;
+ env = global_env;
+ }
+ else
+ {
env = env->next_scope_to_search();
}
}
+ }
- /* Another big hack - only do a universal barrier on the main thread (since it can change variable values)
- Make sure we do this outside the env_lock because it may itself call env_get_string */
- if (is_main && ! get_proc_had_barrier())
- {
- set_proc_had_barrier(true);
- env_universal_barrier();
- }
+ if (!search_universal) return env_var_t::missing_var();
+
+ /* Another big hack - only do a universal barrier on the main thread (since it can change variable values)
+ Make sure we do this outside the env_lock because it may itself call env_get_string */
+ if (is_main_thread() && ! get_proc_had_barrier())
+ {
+ set_proc_had_barrier(true);
+ env_universal_barrier();
+ }
- env_var_t env_var = uvars() ? uvars()->get(key) : env_var_t::missing_var();
- if (env_var == ENV_NULL)
+ if (uvars())
+ {
+ env_var_t env_var = uvars()->get(key);
+ if (env_var == ENV_NULL || !(uvars()->get_export(key) ? search_exported : search_unexported))
{
env_var = env_var_t::missing_var();
}
return env_var;
}
+ return env_var_t::missing_var();
}
bool env_exist(const wchar_t *key, int mode)