diff --git a/fish-rust/src/ffi.rs b/fish-rust/src/ffi.rs index deebfe238..0c648de05 100644 --- a/fish-rust/src/ffi.rs +++ b/fish-rust/src/ffi.rs @@ -101,6 +101,7 @@ generate!("re::regex_result_ffi") generate!("re::try_compile_ffi") generate!("wcs2string") + generate!("wcs2zstring") generate!("str2wcstring") generate!("signal_handle") diff --git a/fish-rust/src/wutil/wrealpath.rs b/fish-rust/src/wutil/wrealpath.rs index 87e6872e5..f4d155d6e 100644 --- a/fish-rust/src/wutil/wrealpath.rs +++ b/fish-rust/src/wutil/wrealpath.rs @@ -7,7 +7,7 @@ use cxx::let_cxx_string; use crate::{ - ffi::{str2wcstring, wcs2string}, + ffi::{str2wcstring, wcs2zstring}, wchar::{wstr, WString}, wchar_ffi::{WCharFromFFI, WCharToFFI}, }; @@ -19,7 +19,7 @@ pub fn wrealpath(pathname: &wstr) -> Option { return None; } - let mut narrow_path: Vec = wcs2string(&pathname.to_ffi()).from_ffi(); + let mut narrow_path: Vec = wcs2zstring(&pathname.to_ffi()).from_ffi(); // Strip trailing slashes. This is treats "/a//" as equivalent to "/a" if /a is a non-directory. while narrow_path.len() > 1 && narrow_path[narrow_path.len() - 1] == b'/' { diff --git a/src/common.cpp b/src/common.cpp index c7ced748c..a67bd6fa9 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -400,6 +400,15 @@ std::string wcs2string(const wchar_t *in, size_t len) { return result; } +std::string wcs2zstring(const wcstring &input) { return wcs2zstring(input.data(), input.size()); } + +std::string wcs2zstring(const wchar_t *in, size_t len) { + if (len == 0) return std::string{}; + std::string result; + wcs2string_appending(in, len, &result); + return result; +} + void wcs2string_appending(const wchar_t *in, size_t len, std::string *receiver) { assert(receiver && "Null receiver"); receiver->reserve(receiver->size() + len); diff --git a/src/common.h b/src/common.h index 454e0c214..e329370b7 100644 --- a/src/common.h +++ b/src/common.h @@ -306,6 +306,10 @@ wcstring str2wcstring(const char *in, size_t len); std::string wcs2string(const wcstring &input); std::string wcs2string(const wchar_t *in, size_t len); +/// Same as wcs2string. Meant to be used when we need a zero-terminated string to feed legacy APIs. +std::string wcs2zstring(const wcstring &input); +std::string wcs2zstring(const wchar_t *in, size_t len); + /// Like wcs2string, but appends to \p receiver instead of returning a new string. void wcs2string_appending(const wchar_t *in, size_t len, std::string *receiver); diff --git a/src/env.cpp b/src/env.cpp index d60c1cc28..8bacb4e01 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -220,7 +220,7 @@ static void setup_user(env_stack_t &vars) { // If we have a $USER, we try to get the passwd entry for the name. // If that has the same UID that we use, we assume the data is correct. if (!user_var.missing_or_empty()) { - std::string unam_narrow = wcs2string(user_var->as_string()); + std::string unam_narrow = wcs2zstring(user_var->as_string()); int retval = getpwnam_r(unam_narrow.c_str(), &userinfo, buf, sizeof(buf), &result); if (!retval && result) { if (result->pw_uid == uid) { @@ -730,9 +730,9 @@ std::shared_ptr env_scoped_impl_t::create_export std::vector export_list; export_list.reserve(vals.size()); for (const auto &kv : vals) { - std::string str = wcs2string(kv.first); + std::string str = wcs2zstring(kv.first); str.push_back('='); - str.append(wcs2string(kv.second.as_string())); + str.append(wcs2zstring(kv.second.as_string())); export_list.push_back(std::move(str)); } return std::make_shared(std::move(export_list)); diff --git a/src/env_dispatch.cpp b/src/env_dispatch.cpp index 1b8efe5c3..48f4fdd16 100644 --- a/src/env_dispatch.cpp +++ b/src/env_dispatch.cpp @@ -137,11 +137,11 @@ static void handle_timezone(const wchar_t *env_var_name, const environment_t &va const auto var = vars.get(env_var_name, ENV_DEFAULT); FLOGF(env_dispatch, L"handle_timezone() current timezone var: |%ls| => |%ls|", env_var_name, !var ? L"MISSING" : var->as_string().c_str()); - std::string name = wcs2string(env_var_name); + std::string name = wcs2zstring(env_var_name); if (var.missing_or_empty()) { unsetenv_lock(name.c_str()); } else { - const std::string value = wcs2string(var->as_string()); + const std::string value = wcs2zstring(var->as_string()); setenv_lock(name.c_str(), value.c_str(), 1); } tzset(); @@ -164,7 +164,7 @@ static void guess_emoji_width(const environment_t &vars) { double version = 0; if (auto version_var = vars.get(L"TERM_PROGRAM_VERSION")) { - std::string narrow_version = wcs2string(version_var->as_string()); + std::string narrow_version = wcs2zstring(version_var->as_string()); version = strtod(narrow_version.c_str(), nullptr); } @@ -465,7 +465,7 @@ static void initialize_curses_using_fallbacks(const environment_t &vars) { } int err_ret = 0; - std::string term = wcs2string(fallback); + std::string term = wcs2zstring(fallback); bool success = (setupterm(&term[0], STDOUT_FILENO, &err_ret) == OK); if (is_interactive_session()) { @@ -566,13 +566,13 @@ static bool does_term_support_setting_title(const environment_t &vars) { /// Initialize the curses subsystem. static void init_curses(const environment_t &vars) { for (const auto &var_name : curses_variables) { - std::string name = wcs2string(var_name); + std::string name = wcs2zstring(var_name); const auto var = vars.get(var_name, ENV_EXPORT); if (var.missing_or_empty()) { FLOGF(term_support, L"curses var %s missing or empty", name.c_str()); unsetenv_lock(name.c_str()); } else { - std::string value = wcs2string(var->as_string()); + std::string value = wcs2zstring(var->as_string()); FLOGF(term_support, L"curses var %s='%s'", name.c_str(), value.c_str()); setenv_lock(name.c_str(), value.c_str(), 1); } @@ -618,12 +618,12 @@ static void init_locale(const environment_t &vars) { for (const auto &var_name : locale_variables) { const auto var = vars.get(var_name, ENV_EXPORT); - std::string name = wcs2string(var_name); + std::string name = wcs2zstring(var_name); if (var.missing_or_empty()) { FLOGF(env_locale, L"locale var %s missing or empty", name.c_str()); unsetenv_lock(name.c_str()); } else { - const std::string value = wcs2string(var->as_string()); + const std::string value = wcs2zstring(var->as_string()); FLOGF(env_locale, L"locale var %s='%s'", name.c_str(), value.c_str()); setenv_lock(name.c_str(), value.c_str(), 1); } diff --git a/src/env_universal_common.cpp b/src/env_universal_common.cpp index db50120b5..0159f9efd 100644 --- a/src/env_universal_common.cpp +++ b/src/env_universal_common.cpp @@ -369,7 +369,7 @@ void env_universal_t::load_from_fd(int fd, callback_data_list_t &callbacks) { } bool env_universal_t::load_from_path(const wcstring &path, callback_data_list_t &callbacks) { - return load_from_path(wcs2string(path), callbacks); + return load_from_path(wcs2zstring(path), callbacks); } bool env_universal_t::load_from_path(const std::string &path, callback_data_list_t &callbacks) { @@ -449,7 +449,7 @@ void env_universal_t::initialize_at_path(callback_data_list_t &callbacks, wcstri if (path.empty()) return; assert(!initialized() && "Already initialized"); vars_path_ = std::move(path); - narrow_vars_path_ = wcs2string(vars_path_); + narrow_vars_path_ = wcs2zstring(vars_path_); if (load_from_path(narrow_vars_path_, callbacks)) { // Successfully loaded from our normal path. @@ -475,7 +475,7 @@ autoclose_fd_t env_universal_t::open_temporary_file(const wcstring &directory, w autoclose_fd_t result; std::string narrow_str; for (size_t attempt = 0; attempt < 10 && !result.valid(); attempt++) { - narrow_str = wcs2string(tmp_name_template); + narrow_str = wcs2zstring(tmp_name_template); result.reset(fish_mkstemp_cloexec(&narrow_str[0])); saved_errno = errno; } @@ -1127,7 +1127,7 @@ static wcstring default_named_pipe_path() { static autoclose_fd_t make_fifo(const wchar_t *test_path, const wchar_t *suffix) { wcstring vars_path = test_path ? wcstring(test_path) : default_named_pipe_path(); vars_path.append(suffix); - const std::string narrow_path = wcs2string(vars_path); + const std::string narrow_path = wcs2zstring(vars_path); int mkfifo_status = mkfifo(narrow_path.c_str(), 0600); if (mkfifo_status == -1 && errno != EEXIST) { diff --git a/src/exec.cpp b/src/exec.cpp index de025deb3..9e1b6ab2c 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -7,6 +7,7 @@ #include #include #include + #include "trace.rs.h" #ifdef HAVE_SIGINFO_H #include @@ -197,7 +198,7 @@ bool is_thompson_shell_script(const char *path) { // Construct envp. auto export_vars = vars.export_arr(); const char **envp = export_vars->get(); - std::string actual_cmd = wcs2string(p->actual_cmd); + std::string actual_cmd = wcs2zstring(p->actual_cmd); // Ensure the terminal modes are what they were before we changed them. restore_term_mode(); @@ -525,7 +526,7 @@ static launch_result_t exec_external_command(parser_t &parser, const std::shared const char *const *argv = argv_array.get(); const char *const *envv = export_arr->get(); - std::string actual_cmd_str = wcs2string(p->actual_cmd); + std::string actual_cmd_str = wcs2zstring(p->actual_cmd); const char *actual_cmd = actual_cmd_str.c_str(); filename_ref_t file = parser.libdata().current_filename; diff --git a/src/expand.cpp b/src/expand.cpp index 7cac8a311..7ffa34acd 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -822,7 +822,7 @@ static void expand_home_directory(wcstring &input, const environment_t &vars) { tail_idx = 1; } else { // Some other user's home directory. - std::string name_cstr = wcs2string(username); + std::string name_cstr = wcs2zstring(username); struct passwd userinfo; struct passwd *result; char buf[8192]; diff --git a/src/fds.cpp b/src/fds.cpp index 408d8af46..5049a5434 100644 --- a/src/fds.cpp +++ b/src/fds.cpp @@ -235,7 +235,7 @@ int open_cloexec(const char *path, int flags, mode_t mode) { } int wopen_cloexec(const wcstring &pathname, int flags, mode_t mode) { - return open_cloexec(wcs2string(pathname), flags, mode); + return open_cloexec(wcs2zstring(pathname), flags, mode); } void exec_close(int fd) { diff --git a/src/fish_indent.cpp b/src/fish_indent.cpp index a146efbf0..456d790da 100644 --- a/src/fish_indent.cpp +++ b/src/fish_indent.cpp @@ -865,10 +865,10 @@ static std::string html_colorize(const wcstring &text, } } html.append(L""); - return wcs2string(html); + return wcs2zstring(html); } -static std::string no_colorize(const wcstring &text) { return wcs2string(text); } +static std::string no_colorize(const wcstring &text) { return wcs2zstring(text); } int main(int argc, char *argv[]) { program_name = L"fish_indent"; diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 5297879bc..864ecce68 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -1521,7 +1521,7 @@ void test_dir_iter() { char t1[] = "/tmp/fish_test_dir_iter.XXXXXX"; const std::string basepathn = mkdtemp(t1); const wcstring basepath = str2wcstring(basepathn); - auto makepath = [&](const wcstring &s) { return wcs2string(basepath + L"/" + s); }; + auto makepath = [&](const wcstring &s) { return wcs2zstring(basepath + L"/" + s); }; const wcstring dirname = L"dir"; const wcstring regname = L"reg"; @@ -2995,7 +2995,7 @@ struct autoload_tester_t { wcstring cmd = vformat_string(fmt, va); va_end(va); - int status = system(wcs2string(cmd).c_str()); + int status = system(wcs2zstring(cmd).c_str()); do_test(status == 0); } @@ -3606,7 +3606,7 @@ static void test_autosuggest_suggest_special() { perform_one_autosuggestion_cd_test(L"cd test/autosuggest_test/has_loop/", L"loopy/loop/", vars, __LINE__); - if (!pushd(wcs2string(wd).c_str())) return; + if (!pushd(wcs2zstring(wd).c_str())) return; perform_one_autosuggestion_cd_test(L"cd 0", L"foobar/", vars, __LINE__); perform_one_autosuggestion_cd_test(L"cd \"0", L"foobar/", vars, __LINE__); perform_one_autosuggestion_cd_test(L"cd '0", L"foobar/", vars, __LINE__); @@ -4022,7 +4022,7 @@ static void test_universal_ok_to_save() { say(L"Testing universal Ok to save"); if (system("mkdir -p test/fish_uvars_test/")) err(L"mkdir failed"); constexpr const char contents[] = "# VERSION: 99999.99\n"; - FILE *fp = fopen(wcs2string(UVARS_TEST_PATH).c_str(), "w"); + FILE *fp = fopen(wcs2zstring(UVARS_TEST_PATH).c_str(), "w"); assert(fp && "Failed to open UVARS_TEST_PATH for writing"); fwrite(contents, const_strlen(contents), 1, fp); fclose(fp); @@ -4509,7 +4509,7 @@ void history_tests_t::test_history_path_detection() { // Place one valid file in the directory. wcstring filename = L"testfile"; - std::string path = wcs2string(tmpdir + filename); + std::string path = wcs2zstring(tmpdir + filename); FILE *f = fopen(path.c_str(), "w"); if (!f) { err(L"Failed to open test file from history path detection"); diff --git a/src/history.cpp b/src/history.cpp index 567316ec7..b9f24569c 100644 --- a/src/history.cpp +++ b/src/history.cpp @@ -791,7 +791,7 @@ bool history_impl_t::rewrite_to_temporary_file(int existing_fd, int dst_fd) cons // Returns the fd of an opened temporary file, or an invalid fd on failure. static autoclose_fd_t create_temporary_file(const wcstring &name_template, wcstring *out_path) { for (int attempt = 0; attempt < 10; attempt++) { - std::string narrow_str = wcs2string(name_template); + std::string narrow_str = wcs2zstring(name_template); autoclose_fd_t out_fd{fish_mkstemp_cloexec(&narrow_str[0])}; if (out_fd.valid()) { *out_path = str2wcstring(narrow_str); diff --git a/src/null_terminated_array.cpp b/src/null_terminated_array.cpp index e3ec03839..7d7979f85 100644 --- a/src/null_terminated_array.cpp +++ b/src/null_terminated_array.cpp @@ -4,7 +4,7 @@ std::vector wide_string_list_to_narrow(const wcstring_list_t &strs) std::vector res; res.reserve(strs.size()); for (const wcstring &s : strs) { - res.push_back(wcs2string(s)); + res.push_back(wcs2zstring(s)); } return res; } diff --git a/src/path.cpp b/src/path.cpp index 3a5f9772b..b1978fceb 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -35,7 +35,7 @@ static get_path_result_t path_get_path_core(const wcstring &cmd, const wcstring_ /// Test if the given path can be executed. /// \return 0 on success, an errno value on failure. auto test_path = [](const wcstring &path) -> int { - std::string narrow = wcs2string(path); + std::string narrow = wcs2zstring(path); struct stat buff; if (access(narrow.c_str(), X_OK) != 0 || stat(narrow.c_str(), &buff) != 0) { return errno; @@ -108,7 +108,7 @@ static bool path_is_executable(const std::string &path) { /// \return whether the given path is on a remote filesystem. static dir_remoteness_t path_remoteness(const wcstring &path) { - std::string narrow = wcs2string(path); + std::string narrow = wcs2zstring(path); #if defined(__linux__) struct statfs buf {}; if (statfs(narrow.c_str(), &buf) < 0) { @@ -149,7 +149,7 @@ wcstring_list_t path_get_paths(const wcstring &cmd, const environment_t &vars) { // If the command has a slash, it must be an absolute or relative path and thus we don't bother // looking for matching commands in the PATH var. if (cmd.find(L'/') != wcstring::npos) { - std::string narrow = wcs2string(cmd); + std::string narrow = wcs2zstring(cmd); if (path_is_executable(narrow)) paths.push_back(cmd); return paths; } @@ -161,7 +161,7 @@ wcstring_list_t path_get_paths(const wcstring &cmd, const environment_t &vars) { for (auto path : pathsv) { if (path.empty()) continue; append_path_component(path, cmd); - std::string narrow = wcs2string(path); + std::string narrow = wcs2zstring(path); if (path_is_executable(narrow)) paths.push_back(path); } diff --git a/src/wutil.cpp b/src/wutil.cpp index e88772d67..e7c5d4c31 100644 --- a/src/wutil.cpp +++ b/src/wutil.cpp @@ -56,7 +56,7 @@ wcstring wgetcwd() { } DIR *wopendir(const wcstring &name) { - const cstring tmp = wcs2string(name); + const cstring tmp = wcs2zstring(name); return opendir(tmp.c_str()); } @@ -146,7 +146,7 @@ void dir_iter_t::entry_t::do_stat() const { if (this->dirfd_ < 0) { return; } - std::string narrow = wcs2string(this->name); + std::string narrow = wcs2zstring(this->name); struct stat s {}; if (fstatat(this->dirfd_, narrow.c_str(), &s, 0) == 0) { this->stat_ = s; @@ -238,22 +238,22 @@ const dir_iter_t::entry_t *dir_iter_t::next() { } int wstat(const wcstring &file_name, struct stat *buf) { - const cstring tmp = wcs2string(file_name); + const cstring tmp = wcs2zstring(file_name); return stat(tmp.c_str(), buf); } int lwstat(const wcstring &file_name, struct stat *buf) { - const cstring tmp = wcs2string(file_name); + const cstring tmp = wcs2zstring(file_name); return lstat(tmp.c_str(), buf); } int waccess(const wcstring &file_name, int mode) { - const cstring tmp = wcs2string(file_name); + const cstring tmp = wcs2zstring(file_name); return access(tmp.c_str(), mode); } int wunlink(const wcstring &file_name) { - const cstring tmp = wcs2string(file_name); + const cstring tmp = wcs2zstring(file_name); return unlink(tmp.c_str()); } @@ -292,7 +292,7 @@ maybe_t wreadlink(const wcstring &file_name) { } ssize_t bufsize = buf.st_size + 1; char target_buf[bufsize]; - const std::string tmp = wcs2string(file_name); + const std::string tmp = wcs2zstring(file_name); ssize_t nbytes = readlink(tmp.c_str(), target_buf, bufsize); if (nbytes == -1) { wperror(L"readlink"); @@ -314,7 +314,7 @@ maybe_t wrealpath(const wcstring &pathname) { if (pathname.empty()) return none(); cstring real_path; - cstring narrow_path = wcs2string(pathname); + cstring narrow_path = wcs2zstring(pathname); // Strip trailing slashes. This is treats "/a//" as equivalent to "/a" if /a is a non-directory. while (narrow_path.size() > 1 && narrow_path.at(narrow_path.size() - 1) == '/') { @@ -510,7 +510,7 @@ const wcstring &wgettext(const wchar_t *in) { auto wmap = wgettext_map.acquire(); wcstring &val = (*wmap)[key]; if (val.empty()) { - cstring mbs_in = wcs2string(key); + cstring mbs_in = wcs2zstring(key); char *out = fish_gettext(mbs_in.c_str()); val = format_string(L"%s", out); } @@ -524,13 +524,13 @@ const wcstring &wgettext(const wchar_t *in) { const wchar_t *wgettext_ptr(const wchar_t *in) { return wgettext(in).c_str(); } int wmkdir(const wcstring &name, int mode) { - cstring name_narrow = wcs2string(name); + cstring name_narrow = wcs2zstring(name); return mkdir(name_narrow.c_str(), mode); } int wrename(const wcstring &old, const wcstring &newv) { - cstring old_narrow = wcs2string(old); - cstring new_narrow = wcs2string(newv); + cstring old_narrow = wcs2zstring(old); + cstring new_narrow = wcs2zstring(newv); return rename(old_narrow.c_str(), new_narrow.c_str()); }