diff --git a/src/common.cpp b/src/common.cpp index a62b395fe..fc1328849 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -95,7 +95,6 @@ int get_debug_stack_frames() { return debug_stack_frames; } /// This is set during startup and not modified after. static relaxed_atomic_t initial_fg_process_group{-1}; -static char *wcs2str_internal(const wchar_t *in, char *out); static void debug_shared(wchar_t msg_level, const wcstring &msg); #if defined(OS_IS_CYGWIN) || defined(WSL) @@ -333,33 +332,6 @@ wcstring str2wcstring(const std::string &in, size_t len) { return str2wcs_internal(in.data(), len); } -char *wcs2str(const wchar_t *in, size_t len) { - if (!in) return nullptr; - size_t desired_size = MAX_UTF8_BYTES * len + 1; - char local_buff[512]; - if (desired_size <= sizeof local_buff / sizeof *local_buff) { - // Convert into local buff, then use strdup() so we don't waste malloc'd space. - char *result = wcs2str_internal(in, local_buff); - if (result) { - // It converted into the local buffer, so copy it. - result = strdup(result); - assert(result); - } - return result; - } - - // Here we probably allocate a buffer probably much larger than necessary. - auto out = static_cast(malloc(MAX_UTF8_BYTES * len + 1)); - assert(out); - // Instead of returning the return value of wcs2str_internal, return `out` directly. - // This eliminates false warnings in coverity about resource leaks. - wcs2str_internal(in, out); - return out; -} - -char *wcs2str(const wchar_t *in) { return wcs2str(in, std::wcslen(in)); } -char *wcs2str(const wcstring &in) { return wcs2str(in.c_str(), in.length()); } - /// This function is distinguished from wcs2str_internal in that it allows embedded null bytes. std::string wcs2string(const wcstring &input) { std::string result; @@ -395,47 +367,6 @@ std::string wcs2string(const wcstring &input) { return result; } -/// Converts the wide character string \c in into it's narrow equivalent, stored in \c out. \c out -/// must have enough space to fit the entire string. -/// -/// This function decodes illegal character sequences in a reversible way using the private use -/// area. -static char *wcs2str_internal(const wchar_t *in, char *out) { - assert(in && out && "in and out must not be null"); - size_t in_pos = 0; - size_t out_pos = 0; - mbstate_t state = {}; - - while (in[in_pos]) { - if (in[in_pos] == INTERNAL_SEPARATOR) { - // do nothing - } else if (in[in_pos] >= ENCODE_DIRECT_BASE && in[in_pos] < ENCODE_DIRECT_BASE + 256) { - out[out_pos++] = in[in_pos] - ENCODE_DIRECT_BASE; - } else if (MB_CUR_MAX == 1) // single-byte locale (C/POSIX/ISO-8859) - { - // If `wc` contains a wide character we emit a question-mark. - if (in[in_pos] & ~0xFF) { - out[out_pos++] = '?'; - } else { - out[out_pos++] = static_cast(in[in_pos]); - } - } else { - size_t len = std::wcrtomb(&out[out_pos], in[in_pos], &state); - if (len == static_cast(-1)) { - FLOGF(char_encoding, L"Wide character U+%4X has no narrow representation", - in[in_pos]); - std::memset(&state, 0, sizeof(state)); - } else { - out_pos += len; - } - } - in_pos++; - } - out[out_pos] = 0; - - return out; -} - /// Test if the character can be encoded using the current locale. static bool can_be_encoded(wchar_t wc) { char converted[MB_LEN_MAX]; diff --git a/src/common.h b/src/common.h index f2fce1b79..433a9aaf2 100644 --- a/src/common.h +++ b/src/common.h @@ -290,8 +290,6 @@ wcstring str2wcstring(const std::string &in, size_t len); /// /// This function decodes illegal character sequences in a reversible way using the private use /// area. -char *wcs2str(const wchar_t *in); -char *wcs2str(const wcstring &in); std::string wcs2string(const wcstring &input); enum fuzzy_match_type_t { diff --git a/src/env.cpp b/src/env.cpp index 108ebf741..6d7143b42 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -324,18 +324,18 @@ void env_init(const struct config_paths_t *paths /* or NULL */) { if (vars.get(L"HOME").missing_or_empty()) { auto user_var = vars.get(L"USER"); if (!user_var.missing_or_empty()) { - char *unam_narrow = wcs2str(user_var->as_string()); + std::string unam_narrow = wcs2string(user_var->as_string()); struct passwd userinfo; struct passwd *result; char buf[8192]; - int retval = getpwnam_r(unam_narrow, &userinfo, buf, sizeof(buf), &result); + int retval = getpwnam_r(unam_narrow.c_str(), &userinfo, buf, sizeof(buf), &result); if (retval || !result) { // Maybe USER is set but it's bogus. Reset USER from the db and try again. setup_user(true); user_var = vars.get(L"USER"); if (!user_var.missing_or_empty()) { - unam_narrow = wcs2str(user_var->as_string()); - retval = getpwnam_r(unam_narrow, &userinfo, buf, sizeof(buf), &result); + unam_narrow = wcs2string(user_var->as_string()); + retval = getpwnam_r(unam_narrow.c_str(), &userinfo, buf, sizeof(buf), &result); } } if (!retval && result && userinfo.pw_dir) { @@ -346,7 +346,6 @@ void env_init(const struct config_paths_t *paths /* or NULL */) { // so it isn't necessary to warn here as well. vars.set_empty(L"HOME", ENV_GLOBAL | ENV_EXPORT); } - free(unam_narrow); } else { // If $USER is empty as well (which we tried to set above), we can't get $HOME. vars.set_empty(L"HOME", ENV_GLOBAL | ENV_EXPORT); diff --git a/src/env_universal_common.cpp b/src/env_universal_common.cpp index bd137c9bd..e4129f165 100644 --- a/src/env_universal_common.cpp +++ b/src/env_universal_common.cpp @@ -537,14 +537,13 @@ autoclose_fd_t env_universal_t::open_temporary_file(const wcstring &directory, w int saved_errno; const wcstring tmp_name_template = directory + L"/fishd.tmp.XXXXXX"; autoclose_fd_t result; - char *narrow_str = nullptr; + std::string narrow_str; for (size_t attempt = 0; attempt < 10 && !result.valid(); attempt++) { - narrow_str = wcs2str(tmp_name_template); - result.reset(fish_mkstemp_cloexec(narrow_str)); + narrow_str = wcs2string(tmp_name_template); + result.reset(fish_mkstemp_cloexec(&narrow_str[0])); saved_errno = errno; } *out_path = str2wcstring(narrow_str); - free(narrow_str); if (!result.valid()) { const char *error = std::strerror(saved_errno); diff --git a/src/exec.cpp b/src/exec.cpp index 61ec2bb85..af7f11085 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -110,12 +110,12 @@ static relaxed_atomic_t s_fork_count{0}; auto export_vars = vars.export_arr(); const char *const *envv = export_vars->get(); - char *actual_cmd = wcs2str(p->actual_cmd); + std::string actual_cmd = wcs2string(p->actual_cmd); // Ensure the terminal modes are what they were before we changed them. restore_term_mode(); // Bounce to launch_process. This never returns. - safe_launch_process(p, actual_cmd, argv_array.get(), envv); + safe_launch_process(p, actual_cmd.c_str(), argv_array.get(), envv); } // Returns whether we can use posix spawn for a given process in a given job. diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index fedbdabea..6f4bf065f 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -496,42 +496,25 @@ static char *str2hex(const char *input) { /// Test wide/narrow conversion by creating random strings and verifying that the original string /// comes back through double conversion. static void test_convert() { - int i; - std::vector sb{}; - say(L"Testing wide/narrow string conversion"); - - for (i = 0; i < ESCAPE_TEST_COUNT; i++) { - const char *o, *n; - char c; - - sb.clear(); + for (int i = 0; i < ESCAPE_TEST_COUNT; i++) { + std::string orig{}; while (random() % ESCAPE_TEST_LENGTH) { - c = random(); - sb.push_back(c); - } - c = 0; - sb.push_back(c); - - o = &sb.at(0); - const wcstring w = str2wcstring(o); - n = wcs2str(w); - - if (!o || !n) { - err(L"Line %d - Conversion cycle of string %s produced null pointer on %s", __LINE__, o, - L"wcs2str"); + char c = random(); + orig.push_back(c); } - if (std::strcmp(o, n)) { - char *o2 = str2hex(o); - char *n2 = str2hex(n); + const wcstring w = str2wcstring(orig); + std::string n = wcs2string(w); + if (orig != n) { + char *o2 = str2hex(orig.c_str()); + char *n2 = str2hex(n.c_str()); err(L"Line %d - %d: Conversion cycle of string:\n%4d chars: %s\n" L"produced different string:\n%4d chars: %s", - __LINE__, i, std::strlen(o), o2, std::strlen(n), n2); + __LINE__, i, orig.size(), o2, n.size(), n2); free(o2); free(n2); } - free((void *)n); } } diff --git a/src/wutil.cpp b/src/wutil.cpp index 75af600d2..c79c3073d 100644 --- a/src/wutil.cpp +++ b/src/wutil.cpp @@ -480,19 +480,15 @@ wcstring path_normalize_for_cd(const wcstring &wd, const wcstring &path) { } wcstring wdirname(const wcstring &path) { - char *tmp = wcs2str(path); - char *narrow_res = dirname(tmp); - wcstring result = format_string(L"%s", narrow_res); - free(tmp); - return result; + std::string tmp = wcs2string(path); + const char *narrow_res = dirname(&tmp[0]); + return str2wcstring(narrow_res); } wcstring wbasename(const wcstring &path) { - char *tmp = wcs2str(path); - char *narrow_res = basename(tmp); - wcstring result = format_string(L"%s", narrow_res); - free(tmp); - return result; + std::string tmp = wcs2string(path); + char *narrow_res = basename(&tmp[0]); + return str2wcstring(narrow_res); } // Really init wgettext.