From 3d40292c0085cf53beaa84a746c45ac2d1f16883 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Mon, 28 Aug 2017 00:25:41 -0700 Subject: [PATCH] Switch env_var to using maybe_t This eliminates the "missing" notion of env_var_t. Instead env_get returns a maybe_t, which forces callers to handle the possibility that the variable is missing. --- src/autoload.cpp | 12 +-- src/builtin_cd.cpp | 12 +-- src/builtin_functions.cpp | 4 +- src/builtin_math.cpp | 8 +- src/builtin_read.cpp | 4 +- src/builtin_set.cpp | 46 ++++++------ src/common.cpp | 12 +-- src/complete.cpp | 6 +- src/env.cpp | 138 ++++++++++++++++------------------- src/env.h | 35 +++------ src/env_universal_common.cpp | 4 +- src/env_universal_common.h | 2 +- src/exec.cpp | 8 +- src/expand.cpp | 31 ++++---- src/fish_tests.cpp | 15 ++-- src/function.cpp | 17 ++--- src/highlight.cpp | 35 ++++----- src/history.cpp | 6 +- src/input.cpp | 4 +- src/input_common.cpp | 6 +- src/output.cpp | 5 +- src/path.cpp | 30 ++++---- src/reader.cpp | 4 +- 23 files changed, 202 insertions(+), 242 deletions(-) diff --git a/src/autoload.cpp b/src/autoload.cpp index f701dcdd3..1107d6ca6 100644 --- a/src/autoload.cpp +++ b/src/autoload.cpp @@ -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 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); } diff --git a/src/builtin_cd.cpp b/src/builtin_cd.cpp index 29328e22c..542019a5d 100644 --- a/src/builtin_cd.cpp +++ b/src/builtin_cd.cpp @@ -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()); diff --git a/src/builtin_functions.cpp b/src/builtin_functions.cpp index 6a3a3ef49..a7e6ff3b4 100644 --- a/src/builtin_functions.cpp +++ b/src/builtin_functions.cpp @@ -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()); diff --git a/src/builtin_math.cpp b/src/builtin_math.cpp index b7169ed7d..f47b0c7ce 100644 --- a/src/builtin_math.cpp +++ b/src/builtin_math.cpp @@ -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); diff --git a/src/builtin_read.cpp b/src/builtin_read.cpp index 43d701bdf..84d6c4d56 100644 --- a/src/builtin_read.cpp +++ b/src/builtin_read.cpp @@ -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()) { diff --git a/src/builtin_set.cpp b/src/builtin_set.cpp index c19a3d749..7aee8a143 100644 --- a/src/builtin_set.cpp +++ b/src/builtin_set.cpp @@ -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 &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; diff --git a/src/common.cpp b/src/common.cpp index 688a62ff5..241915c16 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -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 col_var = env_get(L"COLUMNS"); + maybe_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); diff --git a/src/complete.cpp b/src/complete.cpp index d41ba6d53..ad02d7ede 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -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()); } diff --git a/src/env.cpp b/src/env.cpp index de6321121..085631461 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -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 next; - /// Returns the given entry if present else env_var_t::missing_var. - const env_var_t find_entry(const wcstring &key); + maybe_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_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(fish_term256.as_string()); + support_term256 = from_string(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(fish_term24bit.as_string()); + support_term24bit = from_string(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(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(use_posix_spawn.as_string()); + use_posix_spawn.missing_or_empty() ? true : from_string(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_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(key, var)); + vals.insert(std::pair(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_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", diff --git a/src/env.h b/src/env.h index 5d1db6b18..b74a0a3f4 100644 --- a/src/env.h +++ b/src/env.h @@ -11,6 +11,7 @@ #include #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_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 get(const wcstring &key) const; // Returns the fake snapshot representing the live variables array. static const env_vars_snapshot_t ¤t(); diff --git a/src/env_universal_common.cpp b/src/env_universal_common.cpp index 5bbb6ea5d..880d5c73b 100644 --- a/src/env_universal_common.cpp +++ b/src/env_universal_common.cpp @@ -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_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 { diff --git a/src/env_universal_common.h b/src/env_universal_common.h index 03ba238c9..43c8d78ca 100644 --- a/src/env_universal_common.h +++ b/src/env_universal_common.h @@ -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 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; diff --git a/src/exec.cpp b/src/exec.cpp index d584642ba..209f7ab0f 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -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(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; } diff --git a/src/expand.cpp b/src/expand.cpp index 733d11422..ce908e591 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -769,19 +769,19 @@ static int expand_variables(const wcstring &instr, std::vector *ou } var_tmp.append(instr, start_pos, var_len); - env_var_t var; + maybe_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 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())); } } } diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 1817533f1..2d0f5ba65 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -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 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 var = uvars.get(key); + if (j == 0) assert(!expected_val); if (var != expected_val) { const wchar_t *missing_desc = L""; 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, <ime); n = strftime(ltime_str, 3, "%H", <ime); diff --git a/src/function.cpp b/src/function.cpp index 3e2486076..5efadc689 100644 --- a/src/function.cpp +++ b/src/function.cpp @@ -79,11 +79,11 @@ static int load(const wcstring &name) { static void autoload_names(std::unordered_set &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 &names, int get_hidden) static std::map snapshot_vars(const wcstring_list_t &vars) { std::map 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()); } } diff --git a/src/highlight.cpp b/src/highlight.cpp index ae8d7955d..0d0b08e0a 100644 --- a/src/highlight.cpp +++ b/src/highlight.cpp @@ -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 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); + } } } diff --git a/src/history.cpp b/src/history.cpp index 3f6863621..33361273c 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -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") { diff --git a/src/input.cpp b/src/input.cpp index ee578160c..b759c1982 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -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. diff --git a/src/input_common.cpp b/src/input_common.cpp index 1cf7ce357..19ad41e2e 100644 --- a/src/input_common.cpp +++ b/src/input_common.cpp @@ -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; } diff --git a/src/output.cpp b/src/output.cpp index b160822c5..10009956f 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -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); } } diff --git a/src/path.cpp b/src/path.cpp index 04395bd50..c8e8b6af7 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -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 &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 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 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; diff --git a/src/reader.cpp b/src/reader.cpp index 0c1c5a825..065f30f3e 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -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) {