Switch env_var to using maybe_t

This eliminates the "missing" notion of env_var_t. Instead
env_get returns a maybe_t<env_var_t>, which forces callers to
handle the possibility that the variable is missing.
This commit is contained in:
ridiculousfish 2017-08-28 00:25:41 -07:00
parent 18203a081c
commit 3d40292c00
23 changed files with 202 additions and 242 deletions

View file

@ -65,15 +65,15 @@ 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);
auto path_var = env_get(env_var_name);
// Do we know where to look?
if (path_var.empty()) return 0;
if (path_var.missing_or_empty()) return 0;
// Check if the lookup path has changed. If so, drop all loaded files. path_var may only be
// inspected on the main thread.
if (path_var != this->last_path) {
this->last_path = path_var;
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);
@ -106,11 +106,11 @@ int autoload_t::load(const wcstring &cmd, bool reload) {
}
bool autoload_t::can_load(const wcstring &cmd, const env_vars_snapshot_t &vars) {
const env_var_t path_var = vars.get(env_var_name);
auto path_var = vars.get(env_var_name);
if (path_var.missing_or_empty()) return false;
std::vector<wcstring> path_list;
path_var.to_list(path_list);
path_var->to_list(path_list);
return this->locate_file_and_maybe_load_it(cmd, false, false, path_list);
}

View file

@ -39,19 +39,15 @@ int builtin_cd(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (argv[optind]) {
dir_in = env_var_t(L"", argv[optind]); // unamed var
} else {
dir_in = env_get(L"HOME");
if (dir_in.missing_or_empty()) {
auto maybe_dir_in = env_get(L"HOME");
if (maybe_dir_in.missing_or_empty()) {
streams.err.append_format(_(L"%ls: Could not find home directory\n"), cmd);
return STATUS_CMD_ERROR;
}
dir_in = std::move(*maybe_dir_in);
}
bool got_cd_path = false;
if (!dir_in.missing()) {
got_cd_path = path_get_cdpath(dir_in, &dir);
}
if (!got_cd_path) {
if (!path_get_cdpath(dir_in, &dir)) {
if (errno == ENOTDIR) {
streams.err.append_format(_(L"%ls: '%ls' is not a directory\n"), cmd,
dir_in.as_string().c_str());

View file

@ -192,9 +192,7 @@ static wcstring functions_def(const wcstring &name) {
end = inherit_vars.end();
it != end; ++it) {
wcstring_list_t lst;
if (!it->second.missing()) {
it->second.to_list(lst);
}
it->second.to_list(lst);
// This forced tab is crummy, but we don't know what indentation style the function uses.
append_format(out, L"\n\tset -l %ls", it->first.c_str());

View file

@ -146,17 +146,17 @@ static double *retrieve_var(const wchar_t *var_name, void *user_data) {
UNUSED(user_data);
static double zero_result = 0.0;
env_var_t var = env_get(var_name, ENV_DEFAULT);
if (var.missing()) {
auto var = env_get(var_name, ENV_DEFAULT);
if (!var) {
// We could report an error but we normally don't treat missing vars as a fatal error.
// throw mu::ParserError(L"Var '%ls' does not exist.");
return &zero_result;
}
if (var.empty()) {
if (var->empty()) {
return &zero_result;
}
const wchar_t *first_val = var.as_list()[0].c_str();
const wchar_t *first_val = var->as_list()[0].c_str();
wchar_t *endptr;
errno = 0;
double result = wcstod(first_val, &endptr);

View file

@ -428,8 +428,8 @@ 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");
if (!ifs.missing_or_empty()) opts.delimiter = ifs.as_string();
auto ifs = env_get(L"IFS");
if (!ifs.missing_or_empty()) opts.delimiter = ifs->as_string();
}
if (opts.delimiter.empty()) {

View file

@ -214,8 +214,8 @@ static int validate_cmd_opts(const wchar_t *cmd, set_cmd_opts_t &opts, //!OCLIN
static int check_global_scope_exists(const wchar_t *cmd, set_cmd_opts_t &opts, const wchar_t *dest,
io_streams_t &streams) {
if (opts.universal) {
env_var_t global_dest = env_get(dest, ENV_GLOBAL);
if (!global_dest.missing() && shell_is_interactive()) {
auto global_dest = env_get(dest, ENV_GLOBAL);
if (global_dest && shell_is_interactive()) {
streams.err.append_format(BUILTIN_SET_UVAR_ERR, cmd, dest);
}
}
@ -239,8 +239,8 @@ 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 auto existing_variable = env_get(key, ENV_DEFAULT);
if (!existing_variable.missing_or_empty()) existing_variable->to_list(existing_values);
for (size_t i = 0; i < list.size(); i++) {
const wcstring &dir = list.at(i);
@ -342,9 +342,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);
auto var_str = env_get(src, scope);
wcstring_list_t var;
if (!var_str.missing()) var_str.to_list(var);
if (var_str) var_str->to_list(var);
int count = 0;
@ -453,10 +453,10 @@ 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));
auto var = env_get(key, compute_scope(opts));
if (!var.missing_or_empty()) {
bool shorten = false;
wcstring val = expand_escape_variable(var);
wcstring val = expand_escape_variable(*var);
if (opts.shorten_ok && val.length() > 64) {
shorten = true;
val.resize(60);
@ -495,15 +495,14 @@ 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);
auto dest_str = env_get(dest, scope);
if (dest_str) dest_str->to_list(result);
for (auto idx : indexes) {
if (idx < 1 || (size_t)idx > result.size()) retval++;
}
} else {
env_var_t var = env_get(arg, scope);
if (var.missing()) retval++;
if (! env_get(arg, scope)) retval++;
}
free(dest);
@ -533,14 +532,15 @@ static void show_scope(const wchar_t *var_name, int scope, io_streams_t &streams
}
}
const env_var_t var = env_get(var_name, scope);
if (var.missing()) {
const auto var = env_get(var_name, scope);
if (!var) {
streams.out.append_format(_(L"$%ls: not set in %ls scope\n"), var_name, scope_name);
return;
}
const wchar_t *exportv = var.exportv ? _(L"exported") : _(L"unexported");
const wcstring_list_t &vals = var.as_list();
const wchar_t *exportv = var->exportv ? _(L"exported") : _(L"unexported");
wcstring_list_t vals = var->as_list();
streams.out.append_format(_(L"$%ls: set in %ls scope, %ls, with %d elements\n"), var_name,
scope_name, exportv, vals.size());
for (size_t i = 0; i < vals.size(); i++) {
@ -625,10 +625,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);
if (dest_var.missing()) return STATUS_CMD_ERROR;
const auto dest_var = env_get(dest, scope);
if (!dest_var) return STATUS_CMD_ERROR;
wcstring_list_t result;
dest_var.to_list(result);
dest_var->to_list(result);
erase_values(result, indexes);
retval = my_env_set(cmd, dest, scope, result, streams);
}
@ -650,9 +650,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, ENV_DEFAULT);
auto var_str = env_get(varname, ENV_DEFAULT);
wcstring_list_t var_array;
if (!var_str.missing()) var_str.to_list(var_array);
if (var_str) var_str->to_list(var_array);
new_values.insert(new_values.end(), var_array.begin(), var_array.end());
if (opts.append) {
@ -683,8 +683,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 auto var_str = env_get(varname, scope);
if (var_str) var_str->to_list(new_values);
// Slice indexes have been calculated, do the actual work.
wcstring_list_t result;

View file

@ -1553,13 +1553,13 @@ 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");
maybe_t<env_var_t> col_var = env_get(L"COLUMNS");
maybe_t<env_var_t> row_var = env_get(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.as_string().c_str());
int col = fish_wcstoi(col_var->as_string().c_str());
bool col_ok = errno == 0 && col > 0 && col <= USHRT_MAX;
int row = fish_wcstoi(row_var.as_string().c_str());
int row = fish_wcstoi(row_var->as_string().c_str());
bool row_ok = errno == 0 && row > 0 && row <= USHRT_MAX;
if (col_ok && row_ok) {
new_termsize->ws_col = col;
@ -1582,11 +1582,11 @@ static void validate_new_termsize(struct winsize *new_termsize) {
static void export_new_termsize(struct winsize *new_termsize) {
wchar_t buf[64];
env_var_t cols = env_get(L"COLUMNS", ENV_EXPORT);
auto cols = env_get(L"COLUMNS", ENV_EXPORT);
swprintf(buf, 64, L"%d", (int)new_termsize->ws_col);
env_set_one(L"COLUMNS", ENV_GLOBAL | (cols.missing_or_empty() ? ENV_DEFAULT : ENV_EXPORT), buf);
env_var_t lines = env_get(L"LINES", ENV_EXPORT);
auto lines = env_get(L"LINES", ENV_EXPORT);
swprintf(buf, 64, L"%d", (int)new_termsize->ws_row);
env_set_one(L"LINES", ENV_GLOBAL | (lines.missing_or_empty() ? ENV_DEFAULT : ENV_EXPORT), buf);

View file

@ -1108,10 +1108,10 @@ 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;
auto var = env_get(env_name);
if (!var) continue;
wcstring value = expand_escape_variable(var);
wcstring value = expand_escape_variable(*var);
if (this->type() != COMPLETE_AUTOSUGGEST) {
desc = format_string(COMPLETE_VAR_DESC_VAL, value.c_str());
}

View file

@ -110,15 +110,6 @@ static const wcstring_list_t colon_delimited_variable({L"PATH", L"MANPATH", L"CD
static void init_locale();
static void init_curses();
/// Construct a missing var object
env_var_t create_missing_var() {
env_var_t var;
var.set_missing();
return var;
}
env_var_t missing_var = create_missing_var();
/// This is used to convert a serialized env_var_t back into a list. It is used when reading legacy
/// (fish 2.x) encoded vars stored in the universal variable file and the environment.
static void tokenize_variable_array(const wcstring &val, wcstring_list_t &out) {
@ -165,8 +156,7 @@ class env_node_t {
/// Pointer to next level.
std::unique_ptr<env_node_t> next;
/// Returns the given entry if present else env_var_t::missing_var.
const env_var_t find_entry(const wcstring &key);
maybe_t<env_var_t> find_entry(const wcstring &key);
};
class variable_entry_t {
@ -339,10 +329,10 @@ static bool is_electric(const wcstring &key) {
return env_electric.find(key) != env_electric.end();
}
const env_var_t env_node_t::find_entry(const wcstring &key) {
maybe_t<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 missing_var;
return none();
}
/// Return the current umask value.
@ -356,14 +346,14 @@ static mode_t get_umask() {
/// Properly sets all timezone information.
static void handle_timezone(const wchar_t *env_var_name) {
// const env_var_t var = env_get(env_var_name, ENV_EXPORT);
const env_var_t var = env_get(env_var_name, ENV_DEFAULT);
const auto var = env_get(env_var_name, ENV_DEFAULT);
debug(2, L"handle_timezone() current timezone var: |%ls| => |%ls|", env_var_name,
var.missing() ? L"MISSING" : var.as_string().c_str());
!var ? L"MISSING" : var->as_string().c_str());
const std::string &name = wcs2string(env_var_name);
if (var.missing_or_empty()) {
unsetenv(name.c_str());
} else {
const std::string &value = wcs2string(var.as_string());
const std::string value = wcs2string(var->as_string());
setenv(name.c_str(), value.c_str(), 1);
}
tzset();
@ -376,13 +366,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 auto paths = env_get(var_name);
if (paths.missing_or_empty()) return;
bool modified = false;
wcstring_list_t pathsv;
wcstring_list_t new_pathsv;
paths.to_list(pathsv);
paths->to_list(pathsv);
for (auto next_path : pathsv) {
if (next_path.empty()) {
next_path = L".";
@ -408,13 +398,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 auto var = env_get(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());
unsetenv(name.c_str());
} else {
const std::string &value = wcs2string(var.as_string());
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);
}
@ -454,12 +444,12 @@ 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");
const auto term_var = env_get(L"TERM");
if (term_var.missing_or_empty()) return false;
const wcstring term_str = term_var.as_string();
const wcstring term_str = term_var->as_string();
const wchar_t *term = term_str.c_str();
bool recognized = contains(title_terms, term_var.as_string());
bool recognized = contains(title_terms, term_var->as_string());
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-"));
@ -479,12 +469,12 @@ 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();
auto fish_term256 = env_get(L"fish_term256");
auto term_var = env_get(L"TERM");
wcstring term = term_var.missing_or_empty() ? L"" : term_var->as_string();
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->as_string());
debug(2, L"256 color support determined by 'fish_term256'");
} else if (term.find(L"256color") != wcstring::npos) {
// TERM=*256color*: Explicitly supported.
@ -492,12 +482,12 @@ 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();
const auto prog_var = env_get(L"TERM_PROGRAM");
const auto 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()) {
// OS X Lion is version 300+, it has 256 color support
if (strtod(wcs2str(progver_var.as_string()), NULL) > 300) {
if (strtod(wcs2str(progver_var->as_string()), NULL) > 300) {
support_term256 = true;
debug(2, L"256 color support enabled for TERM=xterm + modern Terminal.app");
}
@ -513,10 +503,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");
auto fish_term24bit = env_get(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->as_string());
debug(2, L"'fish_term24bit' preference: 24-bit color %s",
support_term24bit ? L"enabled" : L"disabled");
} else {
@ -536,10 +526,10 @@ 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");
auto 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(term_var->as_string());
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);
@ -563,13 +553,13 @@ 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 auto var = env_get(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());
unsetenv(name.c_str());
} else {
const std::string &value = wcs2string(var.as_string());
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);
}
@ -577,13 +567,13 @@ static void init_curses() {
int err_ret;
if (setupterm(NULL, STDOUT_FILENO, &err_ret) == ERR) {
env_var_t term = env_get(L"TERM");
auto term = env_get(L"TERM");
if (is_interactive_session) {
debug(1, _(L"Could not set up terminal."));
if (term.missing_or_empty()) {
debug(1, _(L"TERM environment variable not set."));
} else {
debug(1, _(L"TERM environment variable set to '%ls'."), term.as_string().c_str());
debug(1, _(L"TERM environment variable set to '%ls'."), term->as_string().c_str());
debug(1, _(L"Check that this terminal type is supported on this system."));
}
}
@ -656,7 +646,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 auto path = env_get(L"PATH");
if (path.missing_or_empty()) {
wcstring_list_t value({L"/usr/bin", L"/bin"});
env_set(L"PATH", ENV_GLOBAL | ENV_EXPORT, value);
@ -667,10 +657,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");
auto cols = env_get(L"COLUMNS");
if (cols.missing_or_empty()) env_set_one(L"COLUMNS", ENV_GLOBAL, DFLT_TERM_COL_STR);
env_var_t rows = env_get(L"LINES");
auto rows = env_get(L"LINES");
if (rows.missing_or_empty()) env_set_one(L"LINES", ENV_GLOBAL, DFLT_TERM_ROW_STR);
}
@ -688,9 +678,9 @@ 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");
auto read_byte_limit_var = env_get(L"FISH_READ_BYTE_LIMIT");
if (!read_byte_limit_var.missing_or_empty()) {
size_t limit = fish_wcstoull(read_byte_limit_var.as_string().c_str());
size_t limit = fish_wcstoull(read_byte_limit_var->as_string().c_str());
if (errno) {
debug(1, "Ignoring FISH_READ_BYTE_LIMIT since it is not valid");
} else {
@ -700,11 +690,11 @@ void env_set_read_limit() {
}
wcstring env_get_pwd_slash(void) {
env_var_t pwd_var = env_get(L"PWD");
auto pwd_var = env_get(L"PWD");
if (pwd_var.missing_or_empty()) {
return L"";
}
wcstring pwd = pwd_var.as_string();
wcstring pwd = pwd_var->as_string();
if (!string_suffixes_string(L"/", pwd)) {
pwd.push_back(L'/');
}
@ -937,12 +927,12 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
env_set_one(L"FISH_VERSION", ENV_GLOBAL, version);
// Set up SHLVL variable.
const env_var_t shlvl_var = env_get(L"SHLVL");
const auto shlvl_var = env_get(L"SHLVL");
wcstring nshlvl_str = L"1";
if (!shlvl_var.missing_or_empty()) {
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.as_string().c_str(), &end);
long shlvl_i = fish_wcstol(shlvl_var->as_string().c_str(), &end);
if (!errno && shlvl_i >= 0) {
nshlvl_str = to_string<long>(shlvl_i + 1);
}
@ -956,9 +946,9 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
// 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");
auto user_var = env_get(L"USER");
if (!user_var.missing_or_empty()) {
char *unam_narrow = wcs2str(user_var.as_string());
char *unam_narrow = wcs2str(user_var->as_string());
struct passwd userinfo;
struct passwd *result;
char buf[8192];
@ -968,7 +958,7 @@ void env_init(const struct config_paths_t *paths /* or NULL */) {
setup_user(true);
user_var = env_get(L"USER");
if (!user_var.missing_or_empty()) {
unam_narrow = wcs2str(user_var.as_string());
unam_narrow = wcs2str(user_var->as_string());
retval = getpwnam_r(unam_narrow, &userinfo, buf, sizeof(buf), &result);
}
}
@ -992,9 +982,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");
auto 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());
use_posix_spawn.missing_or_empty() ? true : from_string<bool>(use_posix_spawn->as_string());
// Set fish_bind_mode to "default".
env_set_one(FISH_BIND_MODE_VAR, ENV_GLOBAL, DEFAULT_BIND_MODE);
@ -1023,8 +1013,7 @@ 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) {
env_var_t var = env->find_entry(key);
if (!var.missing()) break;
if (env->find_entry(key)) break;
env = vars_stack().next_scope_to_search(env);
}
return env;
@ -1140,7 +1129,7 @@ static int env_set_internal(const wcstring &key, env_mode_flags_t var_mode, wcst
env_universal_barrier();
}
if (uvars() && !uvars()->get(key).missing()) {
if (uvars() && uvars()->get(key)) {
bool exportv;
if (var_mode & ENV_EXPORT) {
exportv = true;
@ -1296,7 +1285,6 @@ const wcstring_list_t &env_var_t::as_list() const { return vals; }
/// Return a string representation of the var. At the present time this uses the legacy 2.x
/// encoding.
wcstring env_var_t::as_string(void) const {
assert(!this->is_missing);
if (this->vals.empty()) return wcstring(ENV_NULL);
wchar_t sep = variable_is_colon_delimited_var(this->name) ? L':' : ARRAY_SEP;
@ -1310,11 +1298,10 @@ wcstring env_var_t::as_string(void) const {
}
void env_var_t::to_list(wcstring_list_t &out) const {
assert(!is_missing);
out = vals;
}
env_var_t env_get(const wcstring &key, env_mode_flags_t mode) {
maybe_t<env_var_t> env_get(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);
@ -1326,12 +1313,12 @@ env_var_t env_get(const wcstring &key, env_mode_flags_t mode) {
// Make the assumption that electric keys can't be shadowed elsewhere, since we currently block
// that in env_set().
if (is_electric(key)) {
if (!search_global) return missing_var;
if (!search_global) return none();
if (key == L"history") {
// 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 (!is_main_thread()) {
return missing_var;
return none();
}
history_t *history = reader_get_history();
@ -1362,7 +1349,7 @@ env_var_t env_get(const wcstring &key, env_mode_flags_t mode) {
var_table_t::const_iterator result = env->env.find(key);
if (result != env->env.end()) {
const env_var_t var = result->second;
if (!var.missing() && (var.exportv ? search_exported : search_unexported)) {
if (var.exportv ? search_exported : search_unexported) {
return var;
}
}
@ -1370,7 +1357,7 @@ env_var_t env_get(const wcstring &key, env_mode_flags_t mode) {
}
}
if (!search_universal) return missing_var;
if (!search_universal) return none();
// 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()`.
@ -1382,13 +1369,13 @@ env_var_t env_get(const wcstring &key, env_mode_flags_t mode) {
// Okay, we couldn't find a local or global var given the requirements. If there is a matching
// universal var return that.
if (uvars()) {
env_var_t var = uvars()->get(key);
if (!var.missing() && (uvars()->get_export(key) ? search_exported : search_unexported)) {
auto var = uvars()->get(key);
if (var && (uvars()->get_export(key) ? search_exported : search_unexported)) {
return var;
}
}
return missing_var;
return none();
}
/// Returns true if the specified scope or any non-shadowed non-global subscopes contain an exported
@ -1482,7 +1469,7 @@ static void get_exported(const env_node_t *n, var_table_t &h) {
const wcstring &key = iter->first;
const env_var_t var = iter->second;
if (!var.missing() && var.exportv) {
if (var.exportv) {
// Export the variable. Don't use std::map::insert here, since we need to overwrite
// existing values from previous scopes.
h[key] = var;
@ -1534,12 +1521,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);
auto var = uvars()->get(key);
if (!var.missing() && !var.empty()) {
if (!var.missing_or_empty()) {
// Note that std::map::insert does NOT overwrite a value already in the map,
// which we depend on here.
vals.insert(std::pair<wcstring, env_var_t>(key, var));
vals.insert(std::pair<wcstring, env_var_t>(key, *var));
}
}
}
@ -1575,9 +1562,9 @@ 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;
const auto var = env_get(key);
if (var) {
vars[key] = *var;
}
}
}
@ -1591,13 +1578,14 @@ 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 {
maybe_t<env_var_t> env_vars_snapshot_t::get(const wcstring &key) const {
// If we represent the current state, bounce to env_get.
if (this->is_current()) {
return env_get(key);
}
auto iter = vars.find(key);
return iter == vars.end() ? missing_var : env_var_t(iter->second);
if (iter == vars.end()) return none();
return env_var_t(iter->second);
}
const wchar_t *const env_vars_snapshot_t::highlighting_keys[] = {L"PATH", L"CDPATH",

View file

@ -11,6 +11,7 @@
#include <vector>
#include "common.h"
#include "maybe.h"
extern size_t read_byte_limit;
extern bool curses_initialized;
@ -71,40 +72,31 @@ class env_var_t {
private:
wcstring name; // name of the var
wcstring_list_t vals; // list of values assigned to the var
bool is_missing; // true if the var is not set in the requested scope
public:
bool exportv; // whether the variable should be exported
void set_missing(void) { is_missing = true; }
// Constructors.
env_var_t(const env_var_t &v)
: name(v.name), vals(v.vals), is_missing(v.is_missing), exportv(v.exportv) {}
env_var_t(const env_var_t &v) : name(v.name), vals(v.vals), exportv(v.exportv) {}
env_var_t(const wcstring &our_name, const wcstring_list_t &l)
: name(our_name), vals(l), is_missing(false), exportv(false) {}
: name(our_name), vals(l), exportv(false) {}
env_var_t(const wcstring &our_name, const wcstring &s)
: name(our_name),
vals({
s,
}),
is_missing(false),
exportv(false) {}
env_var_t(const wcstring &our_name, const wchar_t *s)
: name(our_name),
vals({
wcstring(s),
}),
is_missing(false),
exportv(false) {}
env_var_t() : name(), vals(), is_missing(false), exportv(false) {}
env_var_t() : name(), vals(), exportv(false) {}
bool empty(void) const { return vals.empty() || (vals.size() == 1 && vals[0].empty()); };
bool missing(void) const { return is_missing; }
bool missing_or_empty(void) const { return missing() || empty(); }
bool matches_string(const wcstring &str) {
if (is_missing) return false;
if (vals.size() > 1) return false;
return vals[0] == str;
}
@ -120,35 +112,28 @@ class env_var_t {
env_var_t &operator=(const env_var_t &var) {
this->vals = var.vals;
this->exportv = var.exportv;
this->is_missing = var.is_missing;
return *this;
}
/// Compare a simple string to the var. Returns true iff the var is not missing, has a single
/// Compare a simple string to the var. Returns true iff the var has a single
/// value and that value matches the string being compared to.
bool operator==(const wcstring &str) const {
if (is_missing) return false;
if (vals.size() > 1) return false;
return vals[0] == str;
}
bool operator==(const env_var_t &var) const {
return this->is_missing == var.is_missing && vals == var.vals;
}
bool operator==(const env_var_t &var) const { return vals == var.vals; }
bool operator==(const wcstring_list_t &values) const { return !is_missing && vals == values; }
bool operator==(const wcstring_list_t &values) const { return vals == values; }
bool operator!=(const env_var_t &var) const { return vals != var.vals; }
};
env_var_t create_missing_var();
extern env_var_t missing_var;
/// This is used to convert a serialized env_var_t back into a list.
wcstring_list_t decode_serialized(const wcstring &s);
/// Gets the variable with the specified name, or env_var_t::missing_var if it does not exist.
env_var_t env_get(const wcstring &key, env_mode_flags_t mode = ENV_DEFAULT);
/// Gets the variable with the specified name, or none() if it does not exist.
maybe_t<env_var_t> env_get(const wcstring &key, env_mode_flags_t mode = ENV_DEFAULT);
/// Sets the variable with the specified name to the given values.
int env_set(const wcstring &key, env_mode_flags_t mode, wcstring_list_t vals);
@ -207,7 +192,7 @@ class env_vars_snapshot_t {
env_vars_snapshot_t(const wchar_t *const *keys);
env_vars_snapshot_t();
env_var_t get(const wcstring &key) const;
maybe_t<env_var_t> get(const wcstring &key) const;
// Returns the fake snapshot representing the live variables array.
static const env_vars_snapshot_t &current();

View file

@ -265,10 +265,10 @@ static bool append_file_entry(fish_message_type_t type, const wcstring &key_in,
env_universal_t::env_universal_t(const wcstring &path)
: explicit_vars_path(path), tried_renaming(false), last_read_file(kInvalidFileID) {}
env_var_t env_universal_t::get(const wcstring &name) const {
maybe_t<env_var_t> env_universal_t::get(const wcstring &name) const {
var_table_t::const_iterator where = vars.find(name);
if (where != vars.end()) return where->second;
return missing_var;
return none();
}
bool env_universal_t::get_export(const wcstring &name) const {

View file

@ -71,7 +71,7 @@ class env_universal_t {
explicit env_universal_t(const wcstring &path);
// Get the value of the variable with the specified name.
env_var_t get(const wcstring &name) const;
maybe_t<env_var_t> get(const wcstring &name) const;
// Returns whether the variable with the given name is exported, or false if it does not exist.
bool get_export(const wcstring &name) const;

View file

@ -376,10 +376,10 @@ void internal_exec(job_t *j, const io_chain_t &&all_ios) {
// really make sense, so I'm not trying to fix it here.
if (!setup_child_process(0, all_ios)) {
// Decrement SHLVL as we're removing ourselves from the shell "stack".
const env_var_t shlvl_var = env_get(L"SHLVL", ENV_GLOBAL | ENV_EXPORT);
auto shlvl_var = env_get(L"SHLVL", ENV_GLOBAL | ENV_EXPORT);
wcstring shlvl_str = L"0";
if (!shlvl_var.missing()) {
long shlvl = fish_wcstol(shlvl_var.as_string().c_str());
if (shlvl_var) {
long shlvl = fish_wcstol(shlvl_var->as_string().c_str());
if (!errno && shlvl > 0) {
shlvl_str = to_string<long>(shlvl - 1);
}
@ -1202,7 +1202,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 auto ifs = env_get(L"IFS");
if (!ifs.missing_or_empty()) {
split_output = true;
}

View file

@ -769,19 +769,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;
maybe_t<env_var_t> var;
if (var_len == 1 && var_tmp[0] == VARIABLE_EXPAND_EMPTY) {
var = missing_var;
var = none();
} else {
var = env_get(var_tmp);
}
if (!var.missing()) {
if (var) {
int all_vars = 1;
wcstring_list_t var_item_list;
if (is_ok) {
var.to_list(var_item_list);
var->to_list(var_item_list);
const size_t slice_start = stop_pos;
if (slice_start < insize && instr.at(slice_start) == L'[') {
@ -1161,8 +1161,7 @@ static void expand_home_directory(wcstring &input) {
size_t tail_idx;
wcstring username = get_home_directory_name(input, &tail_idx);
bool tilde_error = false;
env_var_t home;
maybe_t<env_var_t> home;
if (username.empty()) {
// Current users home directory.
home = env_get(L"HOME");
@ -1178,16 +1177,13 @@ static void expand_home_directory(wcstring &input) {
struct passwd *result;
char buf[8192];
int retval = getpwnam_r(name_cstr.c_str(), &userinfo, buf, sizeof(buf), &result);
if (retval || !result) {
tilde_error = true;
} else {
if (!retval && result) {
home = env_var_t(L"HOME", str2wcstring(userinfo.pw_dir));
}
}
wchar_t *realhome = wrealpath(home.as_string(), NULL);
if (!tilde_error && realhome) {
const wchar_t *realhome = home ? wrealpath(home->as_string(), NULL) : nullptr;
if (realhome) {
input.replace(input.begin(), input.begin() + tail_idx, realhome);
} else {
input[0] = L'~';
@ -1417,12 +1413,13 @@ 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");
const wchar_t *name = for_cd ? L"CDPATH" : L"PATH";
auto paths = env_get(name);
if (paths.missing_or_empty()) {
paths = env_var_t(paths.get_name(), for_cd ? L"." : L"");
paths = env_var_t(name, for_cd ? L"." : L"");
}
for (auto next_path : paths.as_list()) {
for (auto next_path : paths->as_list()) {
effective_working_dirs.push_back(
path_apply_working_directory(next_path, working_dir));
}
@ -1575,9 +1572,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 auto expansion = env_get(varname);
if (!expansion.missing_or_empty()) {
abbreviations.emplace(std::make_pair(abbr, expansion.as_string()));
abbreviations.emplace(std::make_pair(abbr, expansion->as_string()));
}
}
}

View file

@ -2579,19 +2579,19 @@ static void test_universal() {
for (int i = 0; i < threads; i++) {
for (int j = 0; j < UVARS_PER_THREAD; j++) {
const wcstring key = format_string(L"key_%d_%d", i, j);
env_var_t expected_val;
maybe_t<env_var_t> expected_val;
if (j == 0) {
expected_val = missing_var;
expected_val = none();
} else {
expected_val = env_var_t(L"", format_string(L"val_%d_%d", i, j));
}
const env_var_t var = uvars.get(key);
if (j == 0) assert(expected_val.missing());
const maybe_t<env_var_t> var = uvars.get(key);
if (j == 0) assert(!expected_val);
if (var != expected_val) {
const wchar_t *missing_desc = L"<missing>";
err(L"Wrong value for key %ls: expected %ls, got %ls\n", key.c_str(),
(expected_val.missing() ? missing_desc : expected_val.as_string().c_str()),
(var.missing() ? missing_desc : var.as_string().c_str()));
(expected_val ? expected_val->as_string().c_str() : missing_desc),
(var ? var->as_string().c_str() : missing_desc));
}
}
}
@ -4179,7 +4179,8 @@ long return_timezone_hour(time_t tstamp, const wchar_t *timezone) {
env_set_one(L"TZ", ENV_EXPORT, timezone);
const env_var_t var = env_get(L"TZ", ENV_DEFAULT);
const auto var = env_get(L"TZ", ENV_DEFAULT);
(void)var;
localtime_r(&tstamp, &ltime);
n = strftime(ltime_str, 3, "%H", &ltime);

View file

@ -79,11 +79,11 @@ static int load(const wcstring &name) {
static void autoload_names(std::unordered_set<wcstring> &names, int get_hidden) {
size_t i;
const env_var_t path_var = env_get(L"fish_function_path");
const auto path_var = env_get(L"fish_function_path");
if (path_var.missing_or_empty()) return;
wcstring_list_t path_list;
path_var.to_list(path_list);
path_var->to_list(path_list);
for (i = 0; i < path_list.size(); i++) {
const wcstring &ndir_str = path_list.at(i);
@ -110,7 +110,8 @@ static void autoload_names(std::unordered_set<wcstring> &names, int get_hidden)
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)));
auto var = env_get(*it);
if (var) result.insert(std::make_pair(*it, std::move(*var)));
}
return result;
}
@ -338,14 +339,6 @@ void function_prepare_environment(const wcstring &name, const wchar_t *const *ar
}
for (auto it = inherited_vars.begin(), end = inherited_vars.end(); it != end; ++it) {
// Note: Prior to my rewrite to address issue #4200 this code did the equivalent of this:
// if (it->second.missing()) {
// env_set_empty(it->first, ENV_LOCAL | ENV_USER);
// } else {
// It should be impossible for the var to be missing since we're inheriting it from an outer
// scope. So we now die horribly if it is missing.
assert(!it->second.missing());
wcstring_list_t vals = it->second.as_list(); // we need a copy
env_set(it->first, ENV_LOCAL | ENV_USER, vals); // because this mutates the list
env_set(it->first, ENV_LOCAL | ENV_USER, it->second.as_list());
}
}

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");
if (cdpath.missing_or_empty()) cdpath = env_var_t(cdpath.get_name(), L".");
auto cdpath = env_get(L"CDPATH");
if (cdpath.missing_or_empty()) cdpath = env_var_t(L"CDPATH", L".");
// Tokenize it into directories.
std::vector<wcstring> pathsv;
cdpath.to_list(pathsv);
cdpath->to_list(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,27 +268,28 @@ 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]);
auto var = env_get(highlight_var[idx]);
// debug( 1, L"%d -> %d -> %ls", highlight, idx, val );
if (var.missing()) var = env_get(highlight_var[0]);
if (!var) var = env_get(highlight_var[0]);
if (!var.missing()) result = parse_color(var, treat_as_background);
if (var) result = parse_color(*var, treat_as_background);
// Handle modifiers.
if (highlight & highlight_modifier_valid_path) {
env_var_t var2 = env_get(L"fish_color_valid_path");
rgb_color_t result2 = parse_color(var2, is_background);
if (result.is_normal())
result = result2;
else {
if (result2.is_bold()) result.set_bold(true);
if (result2.is_underline()) result.set_underline(true);
if (result2.is_italics()) result.set_italics(true);
if (result2.is_dim()) result.set_dim(true);
if (result2.is_reverse()) result.set_reverse(true);
auto var2 = env_get(L"fish_color_valid_path");
if (var2) {
rgb_color_t result2 = parse_color(*var2, is_background);
if (result.is_normal())
result = result2;
else {
if (result2.is_bold()) result.set_bold(true);
if (result2.is_underline()) result.set_underline(true);
if (result2.is_italics()) result.set_italics(true);
if (result2.is_dim()) result.set_dim(true);
if (result2.is_reverse()) result.set_reverse(true);
}
}
}

View file

@ -1780,9 +1780,9 @@ 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 auto var = env_get(L"FISH_HISTORY");
if (var) {
wcstring session_id = var->as_string();
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();
auto mode = env_get(FISH_BIND_MODE_VAR);
return mode ? mode->as_string() : DEFAULT_BIND_MODE;
}
/// Set the current bind mode.

View file

@ -158,18 +158,18 @@ 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");
auto escape_time_ms = env_get(L"fish_escape_delay_ms");
if (escape_time_ms.missing_or_empty()) {
wait_on_escape_ms = WAIT_ON_ESCAPE_DEFAULT;
return;
}
long tmp = fish_wcstol(escape_time_ms.as_string().c_str());
long tmp = fish_wcstol(escape_time_ms->as_string().c_str());
if (errno || tmp < 10 || tmp >= 5000) {
fwprintf(stderr,
L"ignoring fish_escape_delay_ms: value '%ls' "
L"is not an integer or is < 10 or >= 5000 ms\n",
escape_time_ms.as_string().c_str());
escape_time_ms->as_string().c_str());
} else {
wait_on_escape_ms = (int)tmp;
}

View file

@ -554,10 +554,11 @@ 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");
auto term = env_get(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");
debug(0, fmt, mbs_name, line, file, term.as_string().c_str(), PACKAGE_BUGREPORT);
debug(0, fmt, mbs_name, line, file, term ? term->as_string().c_str() : L"",
PACKAGE_BUGREPORT);
}
}

View file

@ -32,7 +32,7 @@
const wcstring_list_t dflt_pathsv({L"/bin", L"/usr/bin", PREFIX L"/bin"});
static bool path_get_path_core(const wcstring &cmd, wcstring *out_path,
const env_var_t &bin_path_var) {
const maybe_t<env_var_t> &bin_path_var) {
debug(3, L"path_get_path( '%ls' )", cmd.c_str());
// If the command has a slash, it must be an absolute or relative path and thus we don't bother
@ -55,8 +55,8 @@ static bool path_get_path_core(const wcstring &cmd, wcstring *out_path,
}
const wcstring_list_t *pathsv;
if (!bin_path_var.missing()) {
pathsv = &bin_path_var.as_list();
if (bin_path_var) {
pathsv = &bin_path_var->as_list();
} else {
pathsv = &dflt_pathsv;
}
@ -122,9 +122,9 @@ wcstring_list_t path_get_paths(const wcstring &cmd) {
return paths;
}
env_var_t path_var = env_get(L"PATH");
auto path_var = env_get(L"PATH");
std::vector<wcstring> pathsv;
path_var.to_list(pathsv);
if (path_var) path_var->to_list(pathsv);
for (auto path : pathsv) {
if (path.empty()) continue;
append_path_component(path, cmd);
@ -144,7 +144,7 @@ wcstring_list_t path_get_paths(const wcstring &cmd) {
bool path_get_cdpath(const env_var_t &dir_var, wcstring *out, const wchar_t *wd,
const env_vars_snapshot_t &env_vars) {
int err = ENOENT;
if (dir_var.missing_or_empty()) return false;
if (dir_var.empty()) return false;
wcstring dir = dir_var.as_string();
if (wd) {
@ -165,11 +165,11 @@ bool path_get_cdpath(const env_var_t &dir_var, wcstring *out, const wchar_t *wd,
paths.push_back(path);
} else {
// Respect CDPATH.
env_var_t cdpaths = env_vars.get(L"CDPATH");
if (cdpaths.missing_or_empty()) cdpaths = env_var_t(cdpaths.get_name(), L".");
auto cdpaths = env_vars.get(L"CDPATH");
if (cdpaths.missing_or_empty()) cdpaths = env_var_t(L"CDPATH", L".");
std::vector<wcstring> cdpathsv;
cdpaths.to_list(cdpathsv);
cdpaths->to_list(cdpathsv);
for (auto next_path : cdpathsv) {
if (next_path.empty()) next_path = L".";
if (next_path == L"." && wd != NULL) {
@ -260,8 +260,8 @@ static void maybe_issue_path_warning(const wcstring &which_dir, const wcstring &
bool using_xdg, const wcstring &xdg_var, const wcstring &path,
int saved_errno) {
wcstring warning_var_name = L"_FISH_WARNED_" + which_dir;
env_var_t var = env_get(warning_var_name, ENV_GLOBAL | ENV_EXPORT);
if (var.missing()) return;
auto var = env_get(warning_var_name, ENV_GLOBAL | ENV_EXPORT);
if (!var) return;
env_set_one(warning_var_name, ENV_GLOBAL | ENV_EXPORT, L"1");
debug(0, custom_error_msg.c_str());
@ -288,19 +288,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 auto xdg_dir = env_get(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->as_string() + 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 auto home = env_get(L"HOME", ENV_GLOBAL | ENV_EXPORT);
if (!home.missing_or_empty()) {
path = home.as_string() +
path = home->as_string() +
(which_dir == L"config" ? L"/.config/fish" : L"/.local/share/fish");
if (create_directory(path) != -1) {
path_done = true;

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 auto var = env_get(L"HISTFILE");
wcstring path = (var ? var->as_string() : L"~/.bash_history");
expand_tilde(path);
FILE *f = wfopen(path, "r");
if (f) {