aboutsummaryrefslogtreecommitdiffhomepage
path: root/env.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'env.cpp')
-rw-r--r--env.cpp609
1 files changed, 276 insertions, 333 deletions
diff --git a/env.cpp b/env.cpp
index 703d619c..13aacf57 100644
--- a/env.cpp
+++ b/env.cpp
@@ -21,6 +21,8 @@
#if HAVE_NCURSES_H
#include <ncurses.h>
+#elif HAVE_NCURSES_CURSES_H
+#include <ncurses/curses.h>
#else
#include <curses.h>
#endif
@@ -49,18 +51,13 @@
#include "history.h"
#include "reader.h"
#include "parser.h"
-#include "env_universal.h"
+#include "env_universal_common.h"
#include "input.h"
#include "event.h"
#include "path.h"
#include "complete.h"
-
-/** Command used to start fishd */
-#define FISHD_CMD L"fishd ^ $__fish_runtime_dir/fishd.log.%s"
-
-// Version for easier debugging
-//#define FISHD_CMD L"fishd"
+#include "fish_version.h"
/** Value denoting a null string */
#define ENV_NULL L"\x1d"
@@ -80,20 +77,6 @@ extern char **environ;
*/
extern char **__environ;
-/**
- A variable entry. Stores the value of a variable and whether it
- should be exported. Obviously, it needs to be allocated large
- enough to fit the value string.
-*/
-struct var_entry_t
-{
- wcstring val; /**< The value of the variable */
- bool exportv; /**< Whether the variable should be exported */
-
- var_entry_t() : exportv(false) { }
-};
-
-typedef std::map<wcstring, var_entry_t> var_table_t;
bool g_log_forks = false;
bool g_use_posix_spawn = false; //will usually be set to true
@@ -148,6 +131,13 @@ static env_node_t *top = NULL;
/** Bottom node on the function stack */
static env_node_t *global_env = NULL;
+/** Universal variables global instance. Initialized in env_init. */
+static env_universal_t *s_universal_variables = NULL;
+
+/* Getter for universal variables */
+static env_universal_t *uvars() {
+ return s_universal_variables;
+}
/**
Table for global variables
@@ -232,43 +222,6 @@ env_node_t *env_node_t::next_scope_to_search(void)
return this->new_scope ? global_env : this->next;
}
-
-/**
- When fishd isn't started, this function is provided to
- env_universal as a callback, it tries to start up fishd. It's
- implementation is a bit of a hack, since it evaluates a bit of
- shellscript, and it might be used at times when that might not be
- the best idea.
-*/
-static void start_fishd()
-{
- struct passwd *pw = getpwuid(getuid());
-
- debug(3, L"Spawning new copy of fishd");
-
- if (!pw)
- {
- debug(0, _(L"Could not get user information"));
- return;
- }
-
- wcstring cmd = format_string(FISHD_CMD, pw->pw_name);
-
- /* Prefer the fishd in __fish_bin_dir, if exists */
- const env_var_t bin_dir = env_get_string(L"__fish_bin_dir");
- if (! bin_dir.missing_or_empty())
- {
- wcstring path = bin_dir + L"/fishd";
- if (waccess(path, X_OK) == 0)
- {
- /* The path command just looks like 'fishd', so insert the bin path to make it absolute */
- cmd.insert(0, bin_dir + L"/");
- }
- }
- parser_t &parser = parser_t::principal_parser();
- parser.eval(cmd, io_chain_t(), TOP);
-}
-
/**
Return the current umask value.
*/
@@ -299,7 +252,6 @@ static bool var_is_locale(const wcstring &key)
static void handle_locale()
{
const env_var_t lc_all = env_get_string(L"LC_ALL");
- int i;
const wcstring old_locale = wsetlocale(LC_MESSAGES, NULL);
/*
@@ -330,7 +282,7 @@ static void handle_locale()
wsetlocale(LC_ALL, lang.c_str());
}
- for (i=2; locale_variable[i]; i++)
+ for (int i=2; locale_variable[i]; i++)
{
const env_var_t val = env_get_string(locale_variable[i]);
@@ -360,7 +312,7 @@ static void handle_locale()
if (get_is_interactive())
{
- debug(0, _(L"Changing language to English"));
+ debug(2, _(L"Changing language to English"));
}
}
}
@@ -373,9 +325,9 @@ static void react_to_variable_change(const wcstring &key)
{
handle_locale();
}
- else if (key == L"fish_term256")
+ else if (key == L"fish_term256" || key == L"fish_term24bit")
{
- update_fish_term256();
+ update_fish_color_support();
reader_react_to_color_change();
}
else if (string_prefixes_string(L"fish_color_", key))
@@ -388,9 +340,7 @@ static void react_to_variable_change(const wcstring &key)
Universal variable callback function. This function makes sure the
proper events are triggered when an event occurs.
*/
-static void universal_callback(fish_message_type_t type,
- const wchar_t *name,
- const wchar_t *val)
+static void universal_callback(fish_message_type_t type, const wchar_t *name, const wchar_t *val)
{
const wchar_t *str = NULL;
@@ -402,13 +352,13 @@ static void universal_callback(fish_message_type_t type,
str=L"SET";
break;
}
-
+
case ERASE:
{
str=L"ERASE";
break;
}
-
+
default:
break;
}
@@ -467,50 +417,10 @@ wcstring env_get_pwd_slash(void)
return pwd;
}
-/**
- Set up default values for various variables if not defined.
- */
-static void env_set_defaults()
-{
-
- if (env_get_string(L"USER").missing())
- {
- struct passwd *pw = getpwuid(getuid());
- if (pw->pw_name != NULL)
- {
- const wcstring wide_name = str2wcstring(pw->pw_name);
- env_set(L"USER", NULL, ENV_GLOBAL);
- }
- }
-
- if (env_get_string(L"HOME").missing())
- {
- const env_var_t unam = env_get_string(L"USER");
- char *unam_narrow = wcs2str(unam.c_str());
- struct passwd *pw = getpwnam(unam_narrow);
- if (pw->pw_dir != NULL)
- {
- const wcstring dir = str2wcstring(pw->pw_dir);
- env_set(L"HOME", dir.c_str(), ENV_GLOBAL);
- }
- free(unam_narrow);
- }
-
- env_set_pwd();
-
-}
-
-// Some variables should not be arrays. This used to be handled by a startup script, but we'd like to get down to 0 forks for startup, so handle it here.
-static bool variable_can_be_array(const wcstring &key)
+/* Here is the whitelist of variables that we colon-delimit, both incoming from the environment and outgoing back to it. This is deliberately very short - we don't want to add language-specific values like CLASSPATH. */
+static bool variable_is_colon_delimited_array(const wcstring &str)
{
- if (key == L"DISPLAY")
- {
- return false;
- }
- else
- {
- return true;
- }
+ return contains(str, L"PATH", L"MANPATH", L"CDPATH");
}
void env_init(const struct config_paths_t *paths /* or NULL */)
@@ -528,7 +438,7 @@ void env_init(const struct config_paths_t *paths /* or NULL */)
L"LINES",
L"COLUMNS",
L"PWD",
- L"SHLVL",
+ //L"SHLVL", // will be inserted a bit lower down
L"FISH_VERSION",
};
for (size_t i=0; i < sizeof ro_keys / sizeof *ro_keys; i++)
@@ -537,21 +447,13 @@ void env_init(const struct config_paths_t *paths /* or NULL */)
}
/*
- HOME and USER should be writeable by root, since this can be a
- convenient way to install software.
- */
- if (getuid() != 0)
- {
- env_read_only.insert(L"HOME");
- env_read_only.insert(L"USER");
- }
-
- /*
Names of all dynamically calculated variables
*/
env_electric.insert(L"history");
env_electric.insert(L"status");
env_electric.insert(L"umask");
+ env_electric.insert(L"COLUMNS");
+ env_electric.insert(L"LINES");
top = new env_node_t;
global_env = top;
@@ -572,13 +474,15 @@ void env_init(const struct config_paths_t *paths /* or NULL */)
if (eql == wcstring::npos)
{
// no equals found
- env_set(key_and_val, L"", ENV_EXPORT);
+ if (is_read_only(key_and_val) || is_electric(key_and_val)) continue;
+ env_set(key_and_val, L"", ENV_EXPORT | ENV_GLOBAL);
}
else
{
wcstring key = key_and_val.substr(0, eql);
+ if (is_read_only(key) || is_electric(key)) continue;
wcstring val = key_and_val.substr(eql + 1);
- if (variable_can_be_array(val))
+ if (variable_is_colon_delimited_array(key))
{
std::replace(val.begin(), val.end(), L':', ARRAY_SEP);
}
@@ -604,31 +508,23 @@ void env_init(const struct config_paths_t *paths /* or NULL */)
/*
Set up the USER variable
*/
- const struct passwd *pw = getpwuid(getuid());
- if (pw && pw->pw_name)
+ if (env_get_string(L"USER").missing_or_empty())
{
- const wcstring uname = str2wcstring(pw->pw_name);
- env_set(L"USER", uname.c_str(), ENV_GLOBAL | ENV_EXPORT);
+ const struct passwd *pw = getpwuid(getuid());
+ if (pw && pw->pw_name)
+ {
+ const wcstring uname = str2wcstring(pw->pw_name);
+ env_set(L"USER", uname.c_str(), ENV_GLOBAL | ENV_EXPORT);
+ }
}
/*
Set up the version variables
*/
- wcstring version = str2wcstring(FISH_BUILD_VERSION);
+ wcstring version = str2wcstring(get_fish_version());
env_set(L"version", version.c_str(), ENV_GLOBAL);
env_set(L"FISH_VERSION", version.c_str(), ENV_GLOBAL);
- const env_var_t user_dir_wstr = env_get_string(L"USER");
-
- std::string fishd_dir = common_get_runtime_path();
- env_set(L"__fish_runtime_dir", str2wcstring(fishd_dir).c_str(), ENV_GLOBAL | ENV_EXPORT);
-
- wchar_t * user_dir = user_dir_wstr.missing()?NULL:const_cast<wchar_t*>(user_dir_wstr.c_str());
-
- env_universal_init(fishd_dir , user_dir ,
- &start_fishd,
- &universal_callback);
-
/*
Set up SHLVL variable
*/
@@ -636,16 +532,38 @@ void env_init(const struct config_paths_t *paths /* or NULL */)
wcstring nshlvl_str = L"1";
if (! shlvl_str.missing())
{
- long shlvl_i = wcstol(shlvl_str.c_str(), NULL, 10);
- if (shlvl_i >= 0)
+ wchar_t *end;
+ long shlvl_i = wcstol(shlvl_str.c_str(), &end, 10);
+ while (iswspace(*end)) ++end; /* skip trailing whitespace */
+ if (shlvl_i >= 0 && *end == '\0')
{
nshlvl_str = to_string<long>(shlvl_i + 1);
}
}
env_set(L"SHLVL", nshlvl_str.c_str(), ENV_GLOBAL | ENV_EXPORT);
+ env_read_only.insert(L"SHLVL");
- /* Set correct defaults for e.g. USER and HOME variables */
- env_set_defaults();
+ /* Set up the HOME variable */
+ if (env_get_string(L"HOME").missing_or_empty())
+ {
+ const env_var_t unam = env_get_string(L"USER");
+ char *unam_narrow = wcs2str(unam.c_str());
+ struct passwd *pw = getpwnam(unam_narrow);
+ if (pw->pw_dir != NULL)
+ {
+ const wcstring dir = str2wcstring(pw->pw_dir);
+ env_set(L"HOME", dir.c_str(), ENV_GLOBAL | ENV_EXPORT);
+ }
+ free(unam_narrow);
+ }
+
+ /* Set PWD */
+ env_set_pwd();
+
+ /* Set up universal variables. The empty string means to use the deafult path. */
+ assert(s_universal_variables == NULL);
+ s_universal_variables = new env_universal_t(L"");
+ s_universal_variables->load();
/* Set g_log_forks */
env_var_t log_forks = env_get_string(L"fish_log_forks");
@@ -654,32 +572,17 @@ void env_init(const struct config_paths_t *paths /* or NULL */)
/* Set g_use_posix_spawn. Default to true. */
env_var_t use_posix_spawn = env_get_string(L"fish_use_posix_spawn");
g_use_posix_spawn = (use_posix_spawn.missing_or_empty() ? true : from_string<bool>(use_posix_spawn));
-}
-void env_destroy()
-{
- env_universal_destroy();
+ /* Set fish_bind_mode to "default" */
+ env_set(FISH_BIND_MODE_VAR, DEFAULT_BIND_MODE, ENV_GLOBAL);
- while (&top->env != global)
- {
- env_pop();
- }
-
- env_read_only.clear();
- env_electric.clear();
-
- var_table_t::iterator iter;
- for (iter = global->begin(); iter != global->end(); ++iter)
- {
- const var_entry_t &entry = iter->second;
- if (entry.exportv)
- {
- mark_changed_exported();
- break;
- }
- }
-
- delete top;
+ /*
+ Now that the global scope is fully initialized, add a toplevel local
+ scope. This same local scope will persist throughout the lifetime of the
+ fish process, and it will ensure that `set -l` commands run at the
+ command-line don't affect the global scope.
+ */
+ env_push(false);
}
/**
@@ -701,15 +604,13 @@ static env_node_t *env_get_node(const wcstring &key)
return env;
}
-int env_set(const wcstring &key, const wchar_t *val, int var_mode)
+int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t var_mode)
{
ASSERT_IS_MAIN_THREAD();
bool has_changed_old = has_changed_exported;
bool has_changed_new = false;
int done=0;
- int is_universal = 0;
-
if (val && contains(key, L"PWD", L"HOME"))
{
/* Canoncalize our path; if it changes, recurse and try again. */
@@ -721,6 +622,15 @@ int env_set(const wcstring &key, const wchar_t *val, int var_mode)
}
}
+ if ((var_mode & (ENV_LOCAL | ENV_UNIVERSAL)) && (is_read_only(key) || is_electric(key)))
+ {
+ return ENV_SCOPE;
+ }
+ if ((var_mode & ENV_EXPORT) && is_electric(key))
+ {
+ return ENV_SCOPE;
+ }
+
if ((var_mode & ENV_USER) && is_read_only(key))
{
return ENV_PERM;
@@ -741,10 +651,12 @@ int env_set(const wcstring &key, const wchar_t *val, int var_mode)
if (!errno && (!*end) && (mask <= 0777) && (mask >= 0))
{
umask(mask);
+ /* Do not actually create a umask variable, on env_get, it will be calculated dynamically */
+ return 0;
}
}
- /* Do not actually create a umask variable, on env_get, it will be calculated dynamically */
- return 0;
+
+ return ENV_INVALID;
}
/*
@@ -758,25 +670,32 @@ int env_set(const wcstring &key, const wchar_t *val, int var_mode)
if (var_mode & ENV_UNIVERSAL)
{
- bool exportv;
+ const bool old_export = uvars() && uvars()->get_export(key);
+ bool new_export;
if (var_mode & ENV_EXPORT)
{
// export
- exportv = true;
+ new_export = true;
}
else if (var_mode & ENV_UNEXPORT)
{
// unexport
- exportv = false;
+ new_export = false;
}
else
{
// not changing the export
- exportv = env_universal_get_export(key);
+ new_export = old_export;
+ }
+ if (uvars())
+ {
+ uvars()->set(key, val, new_export);
+ env_universal_barrier();
+ if (old_export || new_export)
+ {
+ mark_changed_exported();
+ }
}
- env_universal_set(key, val, exportv);
- is_universal = 1;
-
}
else
{
@@ -823,7 +742,7 @@ int env_set(const wcstring &key, const wchar_t *val, int var_mode)
env_universal_barrier();
}
- if (env_universal_get(key))
+ if (uvars() && ! uvars()->get(key).missing())
{
bool exportv;
if (var_mode & ENV_EXPORT)
@@ -836,11 +755,11 @@ int env_set(const wcstring &key, const wchar_t *val, int var_mode)
}
else
{
- exportv = env_universal_get_export(key);
+ exportv = uvars()->get_export(key);
}
- env_universal_set(key, val, exportv);
- is_universal = 1;
+ uvars()->set(key, val, exportv);
+ env_universal_barrier();
done = 1;
@@ -887,20 +806,17 @@ int env_set(const wcstring &key, const wchar_t *val, int var_mode)
if (has_changed_old || has_changed_new)
mark_changed_exported();
}
-
}
- if (!is_universal)
- {
- event_t ev = event_t::variable_event(key);
- ev.arguments.push_back(L"VARIABLE");
- ev.arguments.push_back(L"SET");
- ev.arguments.push_back(key);
+ event_t ev = event_t::variable_event(key);
+ ev.arguments.reserve(3);
+ ev.arguments.push_back(L"VARIABLE");
+ ev.arguments.push_back(L"SET");
+ ev.arguments.push_back(key);
- // debug( 1, L"env_set: fire events on variable %ls", key );
- event_fire(&ev);
- // debug( 1, L"env_set: return from event firing" );
- }
+ // debug( 1, L"env_set: fire events on variable %ls", key );
+ event_fire(&ev);
+ // debug( 1, L"env_set: return from event firing" );
react_to_variable_change(key);
@@ -975,7 +891,6 @@ int env_remove(const wcstring &key, int var_mode)
ev.arguments.push_back(L"VARIABLE");
ev.arguments.push_back(L"ERASE");
ev.arguments.push_back(key);
-
event_fire(&ev);
erased = 1;
@@ -986,7 +901,16 @@ int env_remove(const wcstring &key, int var_mode)
!(var_mode & ENV_GLOBAL) &&
!(var_mode & ENV_LOCAL))
{
- erased = ! env_universal_remove(key.c_str());
+ erased = uvars() && uvars()->remove(key);
+ if (erased)
+ {
+ env_universal_barrier();
+ event_t ev = event_t::variable_event(key);
+ ev.arguments.push_back(L"VARIABLE");
+ ev.arguments.push_back(L"ERASE");
+ ev.arguments.push_back(key);
+ event_fire(&ev);
+ }
}
react_to_variable_change(key);
@@ -1000,148 +924,162 @@ 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, env_mode_flags_t 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")
+ {
+ return to_string(common_get_height());
+ }
+ else if (key == L"status")
+ {
+ return to_string(proc_get_last_status());
+ }
+ else if (key == L"umask")
{
- /* Lock around a local region */
- scoped_lock lock(env_lock);
+ 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;
+
+ 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();
- const wchar_t *item = env_universal_get(key);
+ /* 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();
+ }
- if (!item || (wcscmp(item, ENV_NULL)==0))
- {
- return env_var_t::missing_var();
- }
- else
+ if (uvars())
+ {
+ env_var_t env_var = uvars()->get(key);
+ if (env_var == ENV_NULL || !(uvars()->get_export(key) ? search_exported : search_unexported))
{
- return item;
+ 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)
+bool env_exist(const wchar_t *key, env_mode_flags_t mode)
{
env_node_t *env;
- const wchar_t *item = NULL;
CHECK(key, false);
- /*
- Read only variables all exist, and they are all global. A local
- version can not exist.
- */
- if (!(mode & ENV_LOCAL) && !(mode & ENV_UNIVERSAL))
+ const bool has_scope = mode & (ENV_LOCAL | ENV_GLOBAL | ENV_UNIVERSAL);
+ const bool test_local = !has_scope || (mode & ENV_LOCAL);
+ const bool test_global = !has_scope || (mode & ENV_GLOBAL);
+ const bool test_universal = !has_scope || (mode & ENV_UNIVERSAL);
+
+ const bool test_exported = (mode & ENV_EXPORT) || !(mode & ENV_UNEXPORT);
+ const bool test_unexported = (mode & ENV_UNEXPORT) || !(mode & ENV_EXPORT);
+
+ if (is_electric(key))
{
- if (is_read_only(key) || is_electric(key))
+ /*
+ Electric variables all exist, and they are all global. A local or
+ universal version can not exist. They are also never exported.
+ */
+ if (test_global && test_unexported)
{
- //Such variables are never exported
- if (mode & ENV_EXPORT)
- {
- return false;
- }
- else if (mode & ENV_UNEXPORT)
- {
- return true;
- }
return true;
}
+ return false;
}
- if (!(mode & ENV_UNIVERSAL))
+ if (test_local || test_global)
{
- env = (mode & ENV_GLOBAL)?global_env:top;
+ env = test_local ? top : global_env;
- while (env != 0)
+ while (env)
{
var_table_t::iterator result = env->env.find(key);
if (result != env->env.end())
{
const var_entry_t &res = result->second;
-
- if (mode & ENV_EXPORT)
- {
- return res.exportv;
- }
- else if (mode & ENV_UNEXPORT)
- {
- return ! res.exportv;
- }
-
- return true;
+ return res.exportv ? test_exported : test_unexported;
}
- if (mode & ENV_LOCAL)
- break;
-
- env = env->next_scope_to_search();
+ if (has_scope)
+ {
+ if (!test_global || env == global_env) break;
+ env = global_env;
+ }
+ else
+ {
+ env = env->next_scope_to_search();
+ }
}
}
- if (!(mode & ENV_LOCAL) && !(mode & ENV_GLOBAL))
+ if (test_universal)
{
if (! get_proc_had_barrier())
{
@@ -1149,20 +1087,9 @@ bool env_exist(const wchar_t *key, int mode)
env_universal_barrier();
}
- item = env_universal_get(key);
-
- if (item != NULL)
+ if (uvars() && ! uvars()->get(key).missing())
{
- if (mode & ENV_EXPORT)
- {
- return env_universal_get_export(key) == 1;
- }
- else if (mode & ENV_UNEXPORT)
- {
- return env_universal_get_export(key) == 0;
- }
-
- return 1;
+ return uvars()->get_export(key) ? test_exported : test_unexported;
}
}
@@ -1317,22 +1244,11 @@ wcstring_list_t env_get_names(int flags)
{
result.insert(result.end(), env_electric.begin(), env_electric.end());
}
-
- if (show_exported)
- {
- result.push_back(L"COLUMNS");
- result.push_back(L"LINES");
- }
-
}
- if (show_universal)
+ if (show_universal && uvars())
{
-
- wcstring_list_t uni_list;
- env_universal_get_names(uni_list,
- show_exported,
- show_unexported);
+ const wcstring_list_t uni_list = uvars()->get_names(show_exported, show_unexported);
names.insert(uni_list.begin(), uni_list.end());
}
@@ -1367,19 +1283,22 @@ static void get_exported(const env_node_t *n, std::map<wcstring, wcstring> &h)
}
}
+/* 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)
{
+ out.reserve(out.size() + envs.size());
std::map<wcstring, wcstring>::const_iterator iter;
for (iter = envs.begin(); iter != envs.end(); ++iter)
{
- const std::string ks = wcs2string(iter->first);
+ const wcstring &key = iter->first;
+ const std::string &ks = wcs2string(key);
std::string vs = wcs2string(iter->second);
- for (size_t i=0; i < vs.size(); i++)
+ /* Arrays in the value are ASCII record separator (0x1e) delimited. But some variables should have colons. Add those. */
+ if (variable_is_colon_delimited_array(key))
{
- char &vc = vs.at(i);
- if (vc == ARRAY_SEP)
- vc = ':';
+ /* Replace ARRAY_SEP with colon */
+ std::replace(vs.begin(), vs.end(), (char)ARRAY_SEP, ':');
}
/* Put a string on the vector */
@@ -1412,18 +1331,20 @@ static void update_export_array_if_necessary(bool recalc)
get_exported(top, vals);
- wcstring_list_t uni;
- env_universal_get_names(uni, 1, 0);
- for (i=0; i<uni.size(); i++)
+ if (uvars())
{
- const wcstring &key = uni.at(i);
- const wchar_t *val = env_universal_get(key);
-
- if (wcscmp(val, ENV_NULL))
+ const wcstring_list_t uni = uvars()->get_names(true, false);
+ for (i=0; i<uni.size(); i++)
{
- // Note that std::map::insert does NOT overwrite a value already in the map,
- // which we depend on here
- vals.insert(std::pair<wcstring, wcstring>(key, val));
+ const wcstring &key = uni.at(i);
+ const env_var_t val = uvars()->get(key);
+
+ if (! val.missing() && val != ENV_NULL)
+ {
+ // Note that std::map::insert does NOT overwrite a value already in the map,
+ // which we depend on here
+ vals.insert(std::pair<wcstring, wcstring>(key, val));
+ }
}
}
@@ -1457,6 +1378,28 @@ env_vars_snapshot_t::env_vars_snapshot_t(const wchar_t * const *keys)
}
}
+
+void env_universal_barrier()
+{
+ ASSERT_IS_MAIN_THREAD();
+ if (uvars())
+ {
+ callback_data_list_t changes;
+ bool changed = uvars()->sync(&changes);
+ if (changed)
+ {
+ universal_notifier_t::default_notifier().post_notification();
+ }
+
+ /* Post callbacks */
+ for (size_t i=0; i < changes.size(); i++)
+ {
+ const callback_data_t &data = changes.at(i);
+ universal_callback(data.type, data.key.c_str(), data.val.c_str());
+ }
+ }
+}
+
env_vars_snapshot_t::env_vars_snapshot_t() { }
/* The "current" variables are not a snapshot at all, but instead trampoline to env_get_string, etc. We identify the current snapshot based on pointer values. */