Revert "stop subclassing env_var_t from wcstring"

This reverts commit c36ad27618.
It was meant for the major branch.
This commit is contained in:
Kurtis Rader 2017-08-13 15:31:56 -07:00
parent 7876bc6ef3
commit 296008089c
22 changed files with 184 additions and 203 deletions

View file

@ -69,7 +69,7 @@ int autoload_t::load(const wcstring &cmd, bool reload) {
CHECK_BLOCK(0);
ASSERT_IS_MAIN_THREAD();
env_var_t path_var = env_get(env_var_name);
env_var_t path_var = env_get_string(env_var_name);
// Do we know where to look?
if (path_var.empty()) return 0;
@ -79,7 +79,7 @@ int autoload_t::load(const wcstring &cmd, bool reload) {
if (path_var != this->last_path) {
this->last_path = path_var;
this->last_path_tokenized.clear();
this->last_path.to_list(this->last_path_tokenized);
tokenize_variable_array(this->last_path, this->last_path_tokenized);
scoped_lock locker(lock);
this->evict_all_nodes();
@ -115,7 +115,7 @@ bool autoload_t::can_load(const wcstring &cmd, const env_vars_snapshot_t &vars)
if (path_var.missing_or_empty()) return false;
std::vector<wcstring> path_list;
path_var.to_list(path_list);
tokenize_variable_array(path_var, path_list);
return this->locate_file_and_maybe_load_it(cmd, false, false, path_list);
}

View file

@ -8,7 +8,6 @@
#include <set>
#include "common.h"
#include "env.h"
#include "lru.h"
/// Record of an attempt to access a file.
@ -51,7 +50,7 @@ class autoload_t : public lru_cache_t<autoload_t, autoload_function_t> {
/// The environment variable name.
const wcstring env_var_name;
/// The path from which we most recently autoloaded.
env_var_t last_path;
wcstring last_path;
/// the most reecently autoloaded path, tokenized (split on separators).
wcstring_list_t last_path_tokenized;
/// A table containing all the files that are currently being loaded.

View file

@ -39,7 +39,7 @@ int builtin_cd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (argv[optind]) {
dir_in = env_var_t(argv[optind]);
} else {
dir_in = env_get(L"HOME");
dir_in = env_get_string(L"HOME");
if (dir_in.missing_or_empty()) {
streams.err.append_format(_(L"%ls: Could not find home directory\n"), cmd);
return STATUS_CMD_ERROR;

View file

@ -193,7 +193,7 @@ static wcstring functions_def(const wcstring &name) {
it != end; ++it) {
wcstring_list_t lst;
if (!it->second.missing()) {
it->second.to_list(lst);
tokenize_variable_array(it->second, lst);
}
// This forced tab is crummy, but we don't know what indentation style the function uses.

View file

@ -427,9 +427,9 @@ int builtin_read(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
}
if (!opts.have_delimiter) {
env_var_t ifs = env_get(L"IFS");
env_var_t ifs = env_get_string(L"IFS");
if (!ifs.missing_or_empty()) {
opts.delimiter = ifs.as_string();
opts.delimiter = ifs;
}
}
if (opts.delimiter.empty()) {

View file

@ -239,8 +239,9 @@ static int my_env_path_setup(const wchar_t *cmd, const wchar_t *key, //!OCLINT(
// not the (missing) local value. Also don't bother to complain about relative paths, which
// don't start with /.
wcstring_list_t existing_values;
const env_var_t existing_variable = env_get(key, ENV_DEFAULT);
if (!existing_variable.missing_or_empty()) existing_variable.to_list(existing_values);
const env_var_t existing_variable = env_get_string(key, ENV_DEFAULT);
if (!existing_variable.missing_or_empty())
tokenize_variable_array(existing_variable, existing_values);
for (size_t i = 0; i < list.size(); i++) {
const wcstring &dir = list.at(i);
@ -345,9 +346,9 @@ static int parse_index(std::vector<long> &indexes, wchar_t *src, int scope, io_s
*p = L'\0'; // split the var name from the indexes/slices
p++;
env_var_t var_str = env_get(src, scope);
env_var_t var_str = env_get_string(src, scope);
wcstring_list_t var;
if (!var_str.missing()) var_str.to_list(var);
if (!var_str.missing()) tokenize_variable_array(var_str, var);
int count = 0;
@ -456,16 +457,15 @@ static int builtin_set_list(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
streams.out.append(e_key);
if (!names_only) {
env_var_t var = env_get(key, compute_scope(opts));
if (!var.missing()) {
env_var_t value = env_get_string(key, compute_scope(opts));
if (!value.missing()) {
bool shorten = false;
wcstring val = var.as_string();
if (opts.shorten_ok && val.length() > 64) {
if (opts.shorten_ok && value.length() > 64) {
shorten = true;
val.resize(60);
value.resize(60);
}
wcstring e_value = expand_escape_variable(val);
wcstring e_value = expand_escape_variable(value);
streams.out.append(L" ");
streams.out.append(e_value);
@ -500,8 +500,8 @@ static int builtin_set_query(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
if (idx_count) {
wcstring_list_t result;
env_var_t dest_str = env_get(dest, scope);
if (!dest_str.missing()) dest_str.to_list(result);
env_var_t dest_str = env_get_string(dest, scope);
if (!dest_str.missing()) tokenize_variable_array(dest_str, result);
for (auto idx : indexes) {
if (idx < 1 || (size_t)idx > result.size()) retval++;
@ -538,12 +538,12 @@ static void show_scope(const wchar_t *var_name, int scope, io_streams_t &streams
}
if (env_exist(var_name, scope)) {
const env_var_t evar = env_get(var_name, scope | ENV_EXPORT | ENV_USER);
const env_var_t evar = env_get_string(var_name, scope | ENV_EXPORT | ENV_USER);
const wchar_t *exportv = evar.missing() ? _(L"unexported") : _(L"exported");
const env_var_t var = env_get(var_name, scope | ENV_USER);
const env_var_t var = env_get_string(var_name, scope | ENV_USER);
wcstring_list_t result;
if (!var.empty()) var.to_list(result);
if (!var.empty()) tokenize_variable_array(var, result);
streams.out.append_format(_(L"$%ls: set in %ls scope, %ls, with %d elements\n"), var_name,
scope_name, exportv, result.size());
@ -632,10 +632,10 @@ static int builtin_set_erase(const wchar_t *cmd, set_cmd_opts_t &opts, int argc,
if (idx_count == 0) { // unset the var
retval = env_remove(dest, scope);
} else { // remove just the specified indexes of the var
const env_var_t dest_var = env_get(dest, scope);
const env_var_t dest_var = env_get_string(dest, scope);
if (dest_var.missing()) return STATUS_CMD_ERROR;
wcstring_list_t result;
dest_var.to_list(result);
tokenize_variable_array(dest_var, result);
erase_values(result, indexes);
retval = my_env_set(cmd, dest, result, scope, streams);
}
@ -658,9 +658,9 @@ static int set_var_array(const wchar_t *cmd, set_cmd_opts_t &opts, const wchar_t
for (int i = 0; i < argc; i++) new_values.push_back(argv[i]);
}
env_var_t var_str = env_get(varname, scope);
env_var_t var_str = env_get_string(varname, scope);
wcstring_list_t var_array;
if (!var_str.missing()) var_str.to_list(var_array);
if (!var_str.missing()) tokenize_variable_array(var_str, var_array);
new_values.insert(new_values.end(), var_array.begin(), var_array.end());
if (opts.append) {
@ -691,8 +691,8 @@ static int set_var_slices(const wchar_t *cmd, set_cmd_opts_t &opts, const wchar_
}
int scope = compute_scope(opts); // calculate the variable scope based on the provided options
const env_var_t var_str = env_get(varname, scope);
if (!var_str.missing()) var_str.to_list(new_values);
const env_var_t var_str = env_get_string(varname, scope);
if (!var_str.missing()) tokenize_variable_array(var_str, new_values);
// Slice indexes have been calculated, do the actual work.
wcstring_list_t result;

View file

@ -1554,8 +1554,8 @@ static void validate_new_termsize(struct winsize *new_termsize) {
}
#endif
// Fallback to the environment vars.
env_var_t col_var = env_get(L"COLUMNS");
env_var_t row_var = env_get(L"LINES");
env_var_t col_var = env_get_string(L"COLUMNS");
env_var_t row_var = env_get_string(L"LINES");
if (!col_var.missing_or_empty() && !row_var.missing_or_empty()) {
// Both vars have to have valid values.
int col = fish_wcstoi(col_var.c_str());
@ -1582,11 +1582,11 @@ static void validate_new_termsize(struct winsize *new_termsize) {
/// Export the new terminal size as env vars and to the kernel if possible.
static void export_new_termsize(struct winsize *new_termsize) {
wchar_t buf[64];
env_var_t cols = env_get(L"COLUMNS", ENV_EXPORT);
env_var_t cols = env_get_string(L"COLUMNS", ENV_EXPORT);
swprintf(buf, 64, L"%d", (int)new_termsize->ws_col);
env_set(L"COLUMNS", buf, ENV_GLOBAL | (cols.missing_or_empty() ? 0 : ENV_EXPORT));
env_var_t lines = env_get(L"LINES", ENV_EXPORT);
env_var_t lines = env_get_string(L"LINES", ENV_EXPORT);
swprintf(buf, 64, L"%d", (int)new_termsize->ws_row);
env_set(L"LINES", buf, ENV_GLOBAL | (lines.missing_or_empty() ? 0 : ENV_EXPORT));

View file

@ -1106,13 +1106,12 @@ bool completer_t::complete_variable(const wcstring &str, size_t start_offset) {
wcstring desc;
if (this->wants_descriptions()) {
// Can't use this->vars here, it could be any variable.
env_var_t var = env_get(env_name);
if (var.missing()) continue;
env_var_t value_unescaped = env_get_string(env_name);
if (value_unescaped.missing()) continue;
wcstring value = expand_escape_variable(var.as_string());
if (this->type() != COMPLETE_AUTOSUGGEST) {
wcstring value = expand_escape_variable(value_unescaped);
if (this->type() != COMPLETE_AUTOSUGGEST)
desc = format_string(COMPLETE_VAR_DESC_VAL, value.c_str());
}
}
append_completion(&this->completions, comp, desc, flags, match);

View file

@ -331,13 +331,13 @@ static bool var_is_timezone(const wcstring &key) { return key == L"TZ"; }
/// Properly sets all timezone information.
static void handle_timezone(const wchar_t *env_var_name) {
debug(2, L"handle_timezone() called in response to '%ls' changing", env_var_name);
const env_var_t var = env_get(env_var_name, ENV_EXPORT);
const env_var_t val = env_get_string(env_var_name, ENV_EXPORT);
const std::string &value = wcs2string(val);
const std::string &name = wcs2string(env_var_name);
debug(2, L"timezone var %s='%s'", name.c_str(), var.c_str());
if (var.missing_or_empty()) {
debug(2, L"timezone var %s='%s'", name.c_str(), value.c_str());
if (val.empty()) {
unsetenv(name.c_str());
} else {
const std::string &value = wcs2string(var.as_string());
setenv(name.c_str(), value.c_str(), 1);
}
tzset();
@ -350,13 +350,13 @@ static void fix_colon_delimited_var(const wcstring &var_name) {
// While we auto split/join MANPATH we do not want to replace empty elements with "." (#4158).
if (var_name == L"MANPATH") return;
const env_var_t paths = env_get(var_name);
const env_var_t paths = env_get_string(var_name);
if (paths.missing_or_empty()) return;
bool modified = false;
wcstring_list_t pathsv;
wcstring_list_t new_pathsv;
paths.to_list(pathsv);
tokenize_variable_array(paths, pathsv);
for (auto next_path : pathsv) {
if (next_path.empty()) {
next_path = L".";
@ -400,14 +400,13 @@ static void init_locale() {
char *old_msg_locale = strdup(setlocale(LC_MESSAGES, NULL));
for (auto var_name : locale_variables) {
const env_var_t var = env_get(var_name, ENV_EXPORT);
const env_var_t val = env_get_string(var_name, ENV_EXPORT);
const std::string &name = wcs2string(var_name);
if (var.missing_or_empty()) {
debug(2, L"locale var %s missing or empty", name.c_str());
const std::string &value = wcs2string(val);
debug(2, L"locale var %s='%s'", name.c_str(), value.c_str());
if (val.empty()) {
unsetenv(name.c_str());
} else {
const std::string &value = wcs2string(var.as_string());
debug(2, L"locale var %s='%s'", name.c_str(), value.c_str());
setenv(name.c_str(), value.c_str(), 1);
}
}
@ -456,17 +455,17 @@ bool term_supports_setting_title() { return can_set_term_title; }
/// don't. Since we can't see the underlying terminal below screen there is no way to fix this.
static const wcstring_list_t title_terms({L"xterm", L"screen", L"tmux", L"nxterm", L"rxvt"});
static bool does_term_support_setting_title() {
const env_var_t term_var = env_get(L"TERM");
if (term_var.missing_or_empty()) return false;
const env_var_t term_str = env_get_string(L"TERM");
if (term_str.missing()) return false;
const wchar_t *term = term_var.c_str();
bool recognized = contains(title_terms, term_var.as_string());
const wchar_t *term = term_str.c_str();
bool recognized = contains(title_terms, term_str);
if (!recognized) recognized = !wcsncmp(term, L"xterm-", wcslen(L"xterm-"));
if (!recognized) recognized = !wcsncmp(term, L"screen-", wcslen(L"screen-"));
if (!recognized) recognized = !wcsncmp(term, L"tmux-", wcslen(L"tmux-"));
if (!recognized) {
if (wcscmp(term, L"linux") == 0) return false;
if (wcscmp(term, L"dumb") == 0) return false;
if (term_str == L"linux") return false;
if (term_str == L"dumb") return false;
char buf[PATH_MAX];
int retval = ttyname_r(STDIN_FILENO, buf, PATH_MAX);
@ -480,12 +479,11 @@ static bool does_term_support_setting_title() {
static void update_fish_color_support() {
// Detect or infer term256 support. If fish_term256 is set, we respect it;
// otherwise infer it from the TERM variable or use terminfo.
env_var_t fish_term256 = env_get(L"fish_term256");
env_var_t term_var = env_get(L"TERM");
wcstring term = term_var.missing_or_empty() ? L"" : term_var.as_string();
env_var_t fish_term256 = env_get_string(L"fish_term256");
env_var_t term = env_get_string(L"TERM");
bool support_term256 = false; // default to no support
if (!fish_term256.missing_or_empty()) {
support_term256 = from_string<bool>(fish_term256.as_string());
support_term256 = from_string<bool>(fish_term256);
debug(2, L"256 color support determined by 'fish_term256'");
} else if (term.find(L"256color") != wcstring::npos) {
// TERM=*256color*: Explicitly supported.
@ -493,12 +491,11 @@ static void update_fish_color_support() {
debug(2, L"256 color support enabled for '256color' in TERM");
} else if (term.find(L"xterm") != wcstring::npos) {
// Assume that all xterms are 256, except for OS X SnowLeopard
const env_var_t prog_var = env_get(L"TERM_PROGRAM");
const env_var_t progver_var = env_get(L"TERM_PROGRAM_VERSION");
wcstring term_program = prog_var.missing_or_empty() ? L"" : prog_var.as_string();
if (term_program == L"Apple_Terminal" && !progver_var.missing_or_empty()) {
const env_var_t prog = env_get_string(L"TERM_PROGRAM");
const env_var_t progver = env_get_string(L"TERM_PROGRAM_VERSION");
if (prog == L"Apple_Terminal" && !progver.missing_or_empty()) {
// OS X Lion is version 300+, it has 256 color support
if (strtod(wcs2str(progver_var.as_string()), NULL) > 300) {
if (strtod(wcs2str(progver), NULL) > 300) {
support_term256 = true;
debug(2, L"256 color support enabled for TERM=xterm + modern Terminal.app");
}
@ -514,10 +511,10 @@ static void update_fish_color_support() {
debug(2, L"256 color support not enabled (yet)");
}
env_var_t fish_term24bit = env_get(L"fish_term24bit");
env_var_t fish_term24bit = env_get_string(L"fish_term24bit");
bool support_term24bit;
if (!fish_term24bit.missing_or_empty()) {
support_term24bit = from_string<bool>(fish_term24bit.as_string());
support_term24bit = from_string<bool>(fish_term24bit);
debug(2, L"'fish_term24bit' preference: 24-bit color %s",
support_term24bit ? L"enabled" : L"disabled");
} else {
@ -537,14 +534,12 @@ static void update_fish_color_support() {
static bool initialize_curses_using_fallback(const char *term) {
// If $TERM is already set to the fallback name we're about to use there isn't any point in
// seeing if the fallback name can be used.
env_var_t term_var = env_get(L"TERM");
if (term_var.missing_or_empty()) return false;
const char *term_env = wcs2str(term_var.as_string());
const char *term_env = wcs2str(env_get_string(L"TERM"));
if (!strcmp(term_env, DEFAULT_TERM1) || !strcmp(term_env, DEFAULT_TERM2)) return false;
if (is_interactive_session) debug(1, _(L"Using fallback terminal type '%s'."), term);
if (is_interactive_session) {
debug(1, _(L"Using fallback terminal type '%s'."), term);
}
int err_ret;
if (setupterm((char *)term, STDOUT_FILENO, &err_ret) == OK) return true;
if (is_interactive_session) {
@ -564,21 +559,20 @@ static void init_path_vars() {
/// Initialize the curses subsystem.
static void init_curses() {
for (auto var_name : curses_variables) {
const env_var_t var = env_get(var_name, ENV_EXPORT);
const env_var_t val = env_get_string(var_name, ENV_EXPORT);
const std::string &name = wcs2string(var_name);
if (var.missing_or_empty()) {
debug(2, L"curses var %s missing or empty", name.c_str());
const std::string &value = wcs2string(val);
debug(2, L"curses var %s='%s'", name.c_str(), value.c_str());
if (val.empty()) {
unsetenv(name.c_str());
} else {
const std::string &value = wcs2string(var.as_string());
debug(2, L"curses var %s='%s'", name.c_str(), value.c_str());
setenv(name.c_str(), value.c_str(), 1);
}
}
int err_ret;
if (setupterm(NULL, STDOUT_FILENO, &err_ret) == ERR) {
env_var_t term = env_get(L"TERM");
env_var_t term = env_get_string(L"TERM");
if (is_interactive_session) {
debug(1, _(L"Could not set up terminal."));
if (term.missing_or_empty()) {
@ -672,7 +666,7 @@ static void universal_callback(fish_message_type_t type, const wchar_t *name) {
/// Make sure the PATH variable contains something.
static void setup_path() {
const env_var_t path = env_get(L"PATH");
const env_var_t path = env_get_string(L"PATH");
if (path.missing_or_empty()) {
const wchar_t *value = L"/usr/bin" ARRAY_SEP_STR L"/bin";
env_set(L"PATH", value, ENV_GLOBAL | ENV_EXPORT);
@ -683,10 +677,10 @@ static void setup_path() {
/// defaults. They will be updated later by the `get_current_winsize()` function if they need to be
/// adjusted.
static void env_set_termsize() {
env_var_t cols = env_get(L"COLUMNS");
env_var_t cols = env_get_string(L"COLUMNS");
if (cols.missing_or_empty()) env_set(L"COLUMNS", DFLT_TERM_COL_STR, ENV_GLOBAL);
env_var_t rows = env_get(L"LINES");
env_var_t rows = env_get_string(L"LINES");
if (rows.missing_or_empty()) env_set(L"LINES", DFLT_TERM_ROW_STR, ENV_GLOBAL);
}
@ -704,7 +698,7 @@ bool env_set_pwd() {
/// Allow the user to override the limit on how much data the `read` command will process.
/// This is primarily for testing but could be used by users in special situations.
void env_set_read_limit() {
env_var_t read_byte_limit_var = env_get(L"FISH_READ_BYTE_LIMIT");
env_var_t read_byte_limit_var = env_get_string(L"FISH_READ_BYTE_LIMIT");
if (!read_byte_limit_var.missing_or_empty()) {
size_t limit = fish_wcstoull(read_byte_limit_var.c_str());
if (errno) {
@ -716,11 +710,10 @@ void env_set_read_limit() {
}
wcstring env_get_pwd_slash(void) {
env_var_t pwd_var = env_get(L"PWD");
if (pwd_var.missing_or_empty()) {
env_var_t pwd = env_get_string(L"PWD");
if (pwd.missing_or_empty()) {
return L"";
}
wcstring pwd = pwd_var.as_string();
if (!string_suffixes_string(L"/", pwd)) {
pwd.push_back(L'/');
}
@ -729,7 +722,7 @@ wcstring env_get_pwd_slash(void) {
/// Set up the USER variable.
static void setup_user(bool force) {
if (env_get(L"USER").missing_or_empty() || force) {
if (env_get_string(L"USER").missing_or_empty() || force) {
struct passwd userinfo;
struct passwd *result;
char buf[8192];
@ -870,12 +863,12 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
env_set(L"FISH_VERSION", version.c_str(), ENV_GLOBAL);
// Set up SHLVL variable.
const env_var_t shlvl_var = env_get(L"SHLVL");
const env_var_t shlvl_str = env_get_string(L"SHLVL");
wcstring nshlvl_str = L"1";
if (!shlvl_var.missing_or_empty()) {
if (!shlvl_str.missing()) {
const wchar_t *end;
// TODO: Figure out how to handle invalid numbers better. Shouldn't we issue a diagnostic?
long shlvl_i = fish_wcstol(shlvl_var.c_str(), &end);
long shlvl_i = fish_wcstol(shlvl_str.c_str(), &end);
if (!errno && shlvl_i >= 0) {
nshlvl_str = to_string<long>(shlvl_i + 1);
}
@ -888,10 +881,10 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
// if the target user is root, unless "--preserve-environment" is used.
// Since that is an explicit choice, we should allow it to enable e.g.
// env HOME=(mktemp -d) su --preserve-environment fish
if (env_get(L"HOME").missing_or_empty()) {
env_var_t user_var = env_get(L"USER");
if (!user_var.missing_or_empty()) {
char *unam_narrow = wcs2str(user_var.c_str());
if (env_get_string(L"HOME").missing_or_empty()) {
const env_var_t unam = env_get_string(L"USER");
if (!unam.missing_or_empty()) {
char *unam_narrow = wcs2str(unam.c_str());
struct passwd userinfo;
struct passwd *result;
char buf[8192];
@ -899,11 +892,9 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
if (retval || !result) {
// Maybe USER is set but it's bogus. Reset USER from the db and try again.
setup_user(true);
user_var = env_get(L"USER");
if (!user_var.missing_or_empty()) {
unam_narrow = wcs2str(user_var.c_str());
retval = getpwnam_r(unam_narrow, &userinfo, buf, sizeof(buf), &result);
}
const env_var_t unam = env_get_string(L"USER");
unam_narrow = wcs2str(unam.c_str());
retval = getpwnam_r(unam_narrow, &userinfo, buf, sizeof(buf), &result);
}
if (!retval && result && userinfo.pw_dir) {
const wcstring dir = str2wcstring(userinfo.pw_dir);
@ -927,8 +918,9 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
env_set_read_limit(); // initialize the read_byte_limit
// Set g_use_posix_spawn. Default to true.
env_var_t use_posix_spawn = env_get(L"fish_use_posix_spawn");
g_use_posix_spawn = use_posix_spawn.missing_or_empty() ? true : from_string<bool>(use_posix_spawn.as_string());
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));
// Set fish_bind_mode to "default".
env_set(FISH_BIND_MODE_VAR, DEFAULT_BIND_MODE, ENV_GLOBAL);
@ -1216,22 +1208,12 @@ int env_remove(const wcstring &key, int var_mode) {
return !erased;
}
wcstring env_var_t::as_string(void) const {
assert(!is_missing);
return val;
}
const wchar_t *env_var_t::c_str(void) const {
assert(!is_missing);
return val.c_str();
assert(!is_missing); //!OCLINT(multiple unary operator)
return wcstring::c_str();
}
void env_var_t::to_list(wcstring_list_t &out) const {
assert(!is_missing);
tokenize_variable_array(val, out);
}
env_var_t env_get(const wcstring &key, env_mode_flags_t mode) {
env_var_t env_get_string(const wcstring &key, env_mode_flags_t mode) {
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);
@ -1250,18 +1232,18 @@ env_var_t env_get(const wcstring &key, env_mode_flags_t mode) {
if (!is_main_thread()) {
return env_var_t::missing_var();
}
env_var_t result;
history_t *history = reader_get_history();
if (!history) {
history = &history_t::history_with_name(history_session_id());
}
wcstring result;
if (history) history->get_string_representation(&result, ARRAY_SEP_STR);
return env_var_t(result);
return result;
} else if (key == L"status") {
return env_var_t(to_string(proc_get_last_status()));
return to_string(proc_get_last_status());
} else if (key == L"umask") {
return env_var_t(format_string(L"0%0.3o", get_umask()));
return format_string(L"0%0.3o", get_umask());
}
// We should never get here unless the electric var list is out of sync with the above code.
DIE("unerecognized electric var name");
@ -1294,7 +1276,7 @@ env_var_t env_get(const wcstring &key, env_mode_flags_t mode) {
if (!search_universal) return env_var_t::missing_var();
// Another 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()`.
// 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();
@ -1505,12 +1487,12 @@ void var_stack_t::update_export_array_if_necessary() {
const wcstring_list_t uni = uvars()->get_names(true, false);
for (size_t i = 0; i < uni.size(); i++) {
const wcstring &key = uni.at(i);
const env_var_t var = uvars()->get(key);
const env_var_t val = uvars()->get(key);
if (!var.missing() && var.as_string() != ENV_NULL) {
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, var.as_string()));
vals.insert(std::pair<wcstring, wcstring>(key, val));
}
}
}
@ -1551,16 +1533,16 @@ env_vars_snapshot_t::env_vars_snapshot_t(const wchar_t *const *keys) {
wcstring key;
for (size_t i = 0; keys[i]; i++) {
key.assign(keys[i]);
const env_var_t var = env_get(key);
if (!var.missing()) {
vars[key] = var.as_string();
const env_var_t val = env_get_string(key);
if (!val.missing()) {
vars[key] = val;
}
}
}
env_vars_snapshot_t::env_vars_snapshot_t() {}
// The "current" variables are not a snapshot at all, but instead trampoline to env_get, etc.
// 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.
static const env_vars_snapshot_t sCurrentSnapshot;
const env_vars_snapshot_t &env_vars_snapshot_t::current() { return sCurrentSnapshot; }
@ -1568,9 +1550,9 @@ const env_vars_snapshot_t &env_vars_snapshot_t::current() { return sCurrentSnaps
bool env_vars_snapshot_t::is_current() const { return this == &sCurrentSnapshot; }
env_var_t env_vars_snapshot_t::get(const wcstring &key) const {
// If we represent the current state, bounce to env_get.
// If we represent the current state, bounce to env_get_string.
if (this->is_current()) {
return env_get(key);
return env_get_string(key);
}
std::map<wcstring, wcstring>::const_iterator iter = vars.find(key);
return iter == vars.end() ? env_var_t::missing_var() : env_var_t(iter->second);

View file

@ -24,7 +24,7 @@ extern bool curses_initialized;
/// Value denoting a null string.
#define ENV_NULL L"\x1d"
// Flags that may be passed as the 'mode' in env_set / env_get.
// Flags that may be passed as the 'mode' in env_set / env_get_string.
enum {
/// Default mode.
ENV_DEFAULT = 0,
@ -69,16 +69,11 @@ void env_init(const struct config_paths_t *paths = NULL);
/// routines.
void misc_init();
/// Tokenize the specified string into the specified wcstring_list_t.
///
/// \param val the input string. The contents of this string is not changed.
/// \param out the list in which to place the elements.
void tokenize_variable_array(const wcstring &val, wcstring_list_t &out);
int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t mode);
class env_var_t {
class env_var_t : public wcstring {
private:
bool is_missing;
wcstring val;
public:
static env_var_t missing_var() {
@ -87,36 +82,41 @@ class env_var_t {
return result;
}
env_var_t(const env_var_t &x) : val(x.val), is_missing(x.is_missing) {}
env_var_t(const wcstring &x) : val(x), is_missing(false) {}
env_var_t(const wchar_t *x) : val(x), is_missing(false) {}
env_var_t() : val(L""), is_missing(false) {}
env_var_t(const env_var_t &x) : wcstring(x), is_missing(x.is_missing) {}
env_var_t(const wcstring &x) : wcstring(x), is_missing(false) {}
env_var_t(const wchar_t *x) : wcstring(x), is_missing(false) {}
env_var_t() : wcstring(L""), is_missing(false) {}
bool empty(void) const { return val.empty(); };
bool missing(void) const { return is_missing; }
bool missing_or_empty(void) const { return missing() || val.empty(); }
bool missing_or_empty(void) const { return missing() || empty(); }
const wchar_t *c_str(void) const;
void to_list(wcstring_list_t &out) const;
wcstring as_string() const;
env_var_t &operator=(const env_var_t &v) {
is_missing = v.is_missing;
val = v.val;
env_var_t &operator=(const env_var_t &s) {
is_missing = s.is_missing;
wcstring::operator=(s);
return *this;
}
bool operator==(const env_var_t &s) const { return is_missing == s.is_missing && val == s.val; }
bool operator==(const env_var_t &s) const {
return is_missing == s.is_missing &&
static_cast<const wcstring &>(*this) == static_cast<const wcstring &>(s);
}
bool operator==(const wcstring &s) const { return !is_missing && val == s; }
bool operator==(const wcstring &s) const {
return !is_missing && static_cast<const wcstring &>(*this) == s;
}
bool operator!=(const env_var_t &v) const { return val != v.val; }
bool operator!=(const env_var_t &s) const { return !(*this == s); }
bool operator!=(const wcstring &s) const { return val != s; }
bool operator!=(const wcstring &s) const { return !(*this == s); }
bool operator!=(const wchar_t *s) const { return val != s; }
bool operator==(const wchar_t *s) const {
return !is_missing && static_cast<const wcstring &>(*this) == s;
}
bool operator==(const wchar_t *s) const { return !is_missing && val == s; }
bool operator!=(const wchar_t *s) const { return !(*this == s); }
};
/// Gets the variable with the specified name, or env_var_t::missing_var if it does not exist or is
@ -124,9 +124,7 @@ class env_var_t {
///
/// \param key The name of the variable to get
/// \param mode An optional scope to search in. All scopes are searched if unset
env_var_t env_get(const wcstring &key, env_mode_flags_t mode = ENV_DEFAULT);
int env_set(const wcstring &key, const wchar_t *val, env_mode_flags_t mode);
env_var_t env_get_string(const wcstring &key, env_mode_flags_t mode = ENV_DEFAULT);
/// Returns true if the specified key exists. This can't be reliably done using env_get, since
/// env_get returns null for 0-element arrays.
@ -216,4 +214,10 @@ bool term_supports_setting_title();
/// Returns the fish internal representation for an array of strings.
std::unique_ptr<wcstring> list_to_array_val(const wcstring_list_t &list);
std::unique_ptr<wcstring> list_to_array_val(const wchar_t **list);
/// Tokenize the specified string into the specified wcstring_list_t.
///
/// \param val the input string. The contents of this string is not changed.
/// \param out the list in which to place the elements.
void tokenize_variable_array(const wcstring &val, wcstring_list_t &out);
#endif

View file

@ -405,7 +405,7 @@ void exec_job(parser_t &parser, job_t *j) {
// really make sense, so I'm not trying to fix it here.
if (!setup_child_process(j, 0, all_ios)) {
// Decrement SHLVL as we're removing ourselves from the shell "stack".
const env_var_t shlvl_str = env_get(L"SHLVL", ENV_GLOBAL | ENV_EXPORT);
const env_var_t shlvl_str = env_get_string(L"SHLVL", ENV_GLOBAL | ENV_EXPORT);
wcstring nshlvl_str = L"0";
if (!shlvl_str.missing()) {
long shlvl_i = fish_wcstol(shlvl_str.c_str());
@ -1111,7 +1111,7 @@ static int exec_subshell_internal(const wcstring &cmd, wcstring_list_t *lst, boo
const int prev_status = proc_get_last_status();
bool split_output = false;
const env_var_t ifs = env_get(L"IFS");
const env_var_t ifs = env_get_string(L"IFS");
if (!ifs.missing_or_empty()) {
split_output = true;
}

View file

@ -144,7 +144,7 @@ static void append_cmdsub_error(parse_error_list_t *errors, size_t source_start,
/// Return the environment variable value for the string starting at \c in.
static env_var_t expand_var(const wchar_t *in) {
if (!in) return env_var_t::missing_var();
return env_get(in);
return env_get_string(in);
}
/// Test if the specified string does not contain character which can not be used inside a quoted
@ -777,19 +777,19 @@ static int expand_variables(const wcstring &instr, std::vector<completion_t> *ou
}
var_tmp.append(instr, start_pos, var_len);
env_var_t var;
env_var_t var_val;
if (var_len == 1 && var_tmp[0] == VARIABLE_EXPAND_EMPTY) {
var = env_var_t::missing_var();
var_val = env_var_t::missing_var();
} else {
var = expand_var(var_tmp.c_str());
var_val = expand_var(var_tmp.c_str());
}
if (!var.missing()) {
if (!var_val.missing()) {
int all_vars = 1;
wcstring_list_t var_item_list;
if (is_ok) {
var.to_list(var_item_list);
tokenize_variable_array(var_val, var_item_list);
const size_t slice_start = stop_pos;
if (slice_start < insize && instr.at(slice_start) == L'[') {
@ -1173,7 +1173,7 @@ static void expand_home_directory(wcstring &input) {
env_var_t home;
if (username.empty()) {
// Current users home directory.
home = env_get(L"HOME");
home = env_get_string(L"HOME");
// If home is either missing or empty,
// treat it like an empty list.
// $HOME is defined to be a _path_,
@ -1201,7 +1201,7 @@ static void expand_home_directory(wcstring &input) {
}
}
wchar_t *realhome = wrealpath(home.as_string(), NULL);
wchar_t *realhome = wrealpath(home, NULL);
if (!tilde_error && realhome) {
input.replace(input.begin(), input.begin() + tail_idx, realhome);
@ -1433,12 +1433,12 @@ static expand_error_t expand_stage_wildcards(const wcstring &input, std::vector<
} else {
// Get the PATH/CDPATH and cwd. Perhaps these should be passed in. An empty CDPATH
// implies just the current directory, while an empty PATH is left empty.
env_var_t paths = env_get(for_cd ? L"CDPATH" : L"PATH");
env_var_t paths = env_get_string(for_cd ? L"CDPATH" : L"PATH");
if (paths.missing_or_empty()) paths = for_cd ? L"." : L"";
// Tokenize it into path names.
std::vector<wcstring> pathsv;
paths.to_list(pathsv);
tokenize_variable_array(paths, pathsv);
for (auto next_path : pathsv) {
effective_working_dirs.push_back(
path_apply_working_directory(next_path, working_dir));
@ -1592,9 +1592,9 @@ void update_abbr_cache(const wchar_t *op, const wcstring varname) {
}
abbreviations.erase(abbr);
if (wcscmp(op, L"ERASE") != 0) {
const env_var_t expansion = env_get(varname);
const env_var_t expansion = env_get_string(varname);
if (!expansion.missing_or_empty()) {
abbreviations.emplace(std::make_pair(abbr, expansion.as_string()));
abbreviations.emplace(std::make_pair(abbr, expansion));
}
}
}

View file

@ -78,7 +78,7 @@ static int load(const wcstring &name) {
static void autoload_names(std::set<wcstring> &names, int get_hidden) {
size_t i;
const env_var_t path_var_wstr = env_get(L"fish_function_path");
const env_var_t path_var_wstr = env_get_string(L"fish_function_path");
if (path_var_wstr.missing()) return;
const wchar_t *path_var = path_var_wstr.c_str();
@ -121,7 +121,7 @@ void function_init() {
static std::map<wcstring, env_var_t> snapshot_vars(const wcstring_list_t &vars) {
std::map<wcstring, env_var_t> result;
for (wcstring_list_t::const_iterator it = vars.begin(), end = vars.end(); it != end; ++it) {
result.insert(std::make_pair(*it, env_get(*it)));
result.insert(std::make_pair(*it, env_get_string(*it)));
}
return result;
}

View file

@ -221,12 +221,12 @@ static bool is_potential_cd_path(const wcstring &path, const wcstring &working_d
directories.push_back(working_directory);
} else {
// Get the CDPATH.
env_var_t cdpath = env_get(L"CDPATH");
env_var_t cdpath = env_get_string(L"CDPATH");
if (cdpath.missing_or_empty()) cdpath = L".";
// Tokenize it into directories.
std::vector<wcstring> pathsv;
cdpath.to_list(pathsv);
tokenize_variable_array(cdpath, pathsv);
for (auto next_path : pathsv) {
if (next_path.empty()) next_path = L".";
// Ensure that we use the working directory for relative cdpaths like ".".
@ -268,17 +268,17 @@ rgb_color_t highlight_get_color(highlight_spec_t highlight, bool is_background)
return rgb_color_t::normal();
}
env_var_t var = env_get(highlight_var[idx]);
env_var_t val_wstr = env_get_string(highlight_var[idx]);
// debug( 1, L"%d -> %d -> %ls", highlight, idx, val );
if (var.missing()) var = env_get(highlight_var[0]);
if (val_wstr.missing()) val_wstr = env_get_string(highlight_var[0]);
if (!var.missing()) result = parse_color(var.as_string(), treat_as_background);
if (!val_wstr.missing()) result = parse_color(val_wstr, treat_as_background);
// Handle modifiers.
if (highlight & highlight_modifier_valid_path) {
env_var_t val2_wstr = env_get(L"fish_color_valid_path");
env_var_t val2_wstr = env_get_string(L"fish_color_valid_path");
const wcstring val2 = val2_wstr.missing() ? L"" : val2_wstr.c_str();
rgb_color_t result2 = parse_color(val2, is_background);

View file

@ -1796,9 +1796,8 @@ void history_sanity_check() {
wcstring history_session_id() {
wcstring result = DFLT_FISH_HISTORY_SESSION_ID;
const env_var_t var = env_get(L"FISH_HISTORY");
if (!var.missing()) {
wcstring session_id = var.as_string();
const env_var_t session_id = env_get_string(L"FISH_HISTORY");
if (!session_id.missing()) {
if (session_id.empty()) {
result = L"";
} else if (session_id == L"default") {

View file

@ -201,8 +201,8 @@ static int input_function_args_index = 0;
/// Return the current bind mode.
wcstring input_get_bind_mode() {
env_var_t mode = env_get(FISH_BIND_MODE_VAR);
return mode.missing() ? DEFAULT_BIND_MODE : mode.as_string();
env_var_t mode = env_get_string(FISH_BIND_MODE_VAR);
return mode.missing() ? DEFAULT_BIND_MODE : mode;
}
/// Set the current bind mode.

View file

@ -160,7 +160,7 @@ static wint_t readb() {
// Update the wait_on_escape_ms value in response to the fish_escape_delay_ms user variable being
// set.
void update_wait_on_escape_ms() {
env_var_t escape_time_ms = env_get(L"fish_escape_delay_ms");
env_var_t escape_time_ms = env_get_string(L"fish_escape_delay_ms");
if (escape_time_ms.missing_or_empty()) {
wait_on_escape_ms = WAIT_ON_ESCAPE_DEFAULT;
return;

View file

@ -554,7 +554,7 @@ void writembs_check(char *mbs, const char *mbs_name, const char *file, long line
if (mbs != NULL) {
tputs(mbs, 1, &writeb);
} else {
env_var_t term = env_get(L"TERM");
env_var_t term = env_get_string(L"TERM");
const wchar_t *fmt =
_(L"Tried to use terminfo string %s on line %ld of %s, which is "
L"undefined in terminal of type \"%ls\". Please report this error to %s");

View file

@ -50,7 +50,7 @@ static bool path_get_path_core(const wcstring &cmd, wcstring *out_path,
int err = ENOENT;
wcstring bin_path;
if (!bin_path_var.missing()) {
bin_path = bin_path_var.as_string();
bin_path = bin_path_var;
} else {
// Note that PREFIX is defined in the `Makefile` and is thus defined when this module is
// compiled. This ensures we always default to "/bin", "/usr/bin" and the bin dir defined
@ -104,7 +104,7 @@ bool path_get_path(const wcstring &cmd, wcstring *out_path, const env_vars_snaps
}
bool path_get_path(const wcstring &cmd, wcstring *out_path) {
return path_get_path_core(cmd, out_path, env_get(L"PATH"));
return path_get_path_core(cmd, out_path, env_get_string(L"PATH"));
}
wcstring_list_t path_get_paths(const wcstring &cmd) {
@ -122,9 +122,9 @@ wcstring_list_t path_get_paths(const wcstring &cmd) {
return paths;
}
env_var_t path_var = env_get(L"PATH");
wcstring env_path = env_get_string(L"PATH");
std::vector<wcstring> pathsv;
path_var.to_list(pathsv);
tokenize_variable_array(env_path, pathsv);
for (auto path : pathsv) {
if (path.empty()) continue;
append_path_component(path, cmd);
@ -141,11 +141,10 @@ wcstring_list_t path_get_paths(const wcstring &cmd) {
return paths;
}
bool path_get_cdpath(const env_var_t &dir_var, wcstring *out, const wchar_t *wd,
bool path_get_cdpath(const wcstring &dir, wcstring *out, const wchar_t *wd,
const env_vars_snapshot_t &env_vars) {
int err = ENOENT;
if (dir_var.missing_or_empty()) return false;
wcstring dir = dir_var.as_string();
if (dir.empty()) return false;
if (wd) {
size_t len = wcslen(wd);
@ -169,7 +168,7 @@ bool path_get_cdpath(const env_var_t &dir_var, wcstring *out, const wchar_t *wd,
if (cdpaths.missing_or_empty()) cdpaths = L".";
std::vector<wcstring> cdpathsv;
cdpaths.to_list(cdpathsv);
tokenize_variable_array(cdpaths, cdpathsv);
for (auto next_path : cdpathsv) {
if (next_path.empty()) next_path = L".";
if (next_path == L"." && wd != NULL) {
@ -288,20 +287,19 @@ static void path_create(wcstring &path, const wcstring &xdg_var, const wcstring
// The vars we fetch must be exported. Allowing them to be universal doesn't make sense and
// allowing that creates a lock inversion that deadlocks the shell since we're called before
// uvars are available.
const env_var_t xdg_dir = env_get(xdg_var, ENV_GLOBAL | ENV_EXPORT);
const env_var_t xdg_dir = env_get_string(xdg_var, ENV_GLOBAL | ENV_EXPORT);
if (!xdg_dir.missing_or_empty()) {
using_xdg = true;
path = xdg_dir.as_string() + L"/fish";
path = xdg_dir + L"/fish";
if (create_directory(path) != -1) {
path_done = true;
} else {
saved_errno = errno;
}
} else {
const env_var_t home = env_get(L"HOME", ENV_GLOBAL | ENV_EXPORT);
const env_var_t home = env_get_string(L"HOME", ENV_GLOBAL | ENV_EXPORT);
if (!home.missing_or_empty()) {
path = home.as_string() +
(which_dir == L"config" ? L"/.config/fish" : L"/.local/share/fish");
path = home + (which_dir == L"config" ? L"/.config/fish" : L"/.local/share/fish");
if (create_directory(path) != -1) {
path_done = true;
} else {

View file

@ -61,7 +61,7 @@ wcstring_list_t path_get_paths(const wcstring &cmd);
/// \param vars The environment variable snapshot to use (for the CDPATH variable)
/// \return 0 if the command can not be found, the path of the command otherwise. The path should be
/// free'd with free().
bool path_get_cdpath(const env_var_t &dir, wcstring *out_or_NULL, const wchar_t *wd = NULL,
bool path_get_cdpath(const wcstring &dir, wcstring *out_or_NULL, const wchar_t *wd = NULL,
const env_vars_snapshot_t &vars = env_vars_snapshot_t::current());
/// Returns whether the path can be used for an implicit cd command; if so, also returns the path by

View file

@ -2063,8 +2063,8 @@ void reader_import_history_if_necessary(void) {
// Try opening a bash file. We make an effort to respect $HISTFILE; this isn't very complete
// (AFAIK it doesn't have to be exported), and to really get this right we ought to ask bash
// itself. But this is better than nothing.
const env_var_t var = env_get(L"HISTFILE");
wcstring path = (var.missing() ? L"~/.bash_history" : var.as_string());
const env_var_t var = env_get_string(L"HISTFILE");
wcstring path = (var.missing() ? L"~/.bash_history" : var);
expand_tilde(path);
FILE *f = wfopen(path, "r");
if (f) {

View file

@ -120,8 +120,8 @@ static bool is_screen_name_escape_seq(const wchar_t *code, size_t *resulting_len
#if 0
// TODO: Decide if this should be removed or modified to also test for TERM values that begin
// with "tmux". See issue #3512.
const env_var_t term_name = env_get(L"TERM");
if (term_name.missing_or_empty() || !string_prefixes_string(L"screen", term_name)) {
const env_var_t term_name = env_get_string(L"TERM");
if (term_name.missing() || !string_prefixes_string(L"screen", term_name)) {
return false;
}
#endif