mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-22 10:30:28 +08:00
Rewrite wrealpath
from wutil
in Rust (#9613)
* wutil: Rewrite `wrealpath` in Rust * Reduce use of FFI types in `wrealpath` * Addressed PR comments regarding allocation * Replace let binding assignment with regular comparison
This commit is contained in:
parent
6f5be9bae4
commit
c7ea768a74
|
@ -91,6 +91,8 @@ include_cpp! {
|
|||
generate!("re::regex_t")
|
||||
generate!("re::regex_result_ffi")
|
||||
generate!("re::try_compile_ffi")
|
||||
generate!("wcs2string")
|
||||
generate!("str2wcstring")
|
||||
}
|
||||
|
||||
impl parser_t {
|
||||
|
|
|
@ -143,3 +143,15 @@ impl WCharFromFFI<WString> for cxx::SharedPtr<cxx::CxxWString> {
|
|||
WString::from_chars(self.as_chars())
|
||||
}
|
||||
}
|
||||
|
||||
impl WCharFromFFI<Vec<u8>> for cxx::UniquePtr<cxx::CxxString> {
|
||||
fn from_ffi(&self) -> Vec<u8> {
|
||||
self.as_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
impl WCharFromFFI<Vec<u8>> for cxx::SharedPtr<cxx::CxxString> {
|
||||
fn from_ffi(&self) -> Vec<u8> {
|
||||
self.as_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
pub mod format;
|
||||
pub mod gettext;
|
||||
mod wcstoi;
|
||||
mod wrealpath;
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
pub(crate) use format::printf::sprintf;
|
||||
pub(crate) use gettext::{wgettext, wgettext_fmt};
|
||||
pub use wcstoi::*;
|
||||
pub use wrealpath::*;
|
||||
|
||||
/// Port of the wide-string wperror from `src/wutil.cpp` but for rust `&str`.
|
||||
pub fn perror(s: &str) {
|
||||
|
|
74
fish-rust/src/wutil/wrealpath.rs
Normal file
74
fish-rust/src/wutil/wrealpath.rs
Normal file
|
@ -0,0 +1,74 @@
|
|||
use std::{
|
||||
ffi::OsStr,
|
||||
fs::canonicalize,
|
||||
os::unix::prelude::{OsStrExt, OsStringExt},
|
||||
};
|
||||
|
||||
use cxx::let_cxx_string;
|
||||
|
||||
use crate::{
|
||||
ffi::{str2wcstring, wcs2string},
|
||||
wchar::{wstr, WString},
|
||||
wchar_ffi::{WCharFromFFI, WCharToFFI},
|
||||
};
|
||||
|
||||
/// Wide character realpath. The last path component does not need to be valid. If an error occurs,
|
||||
/// `wrealpath()` returns `None`
|
||||
pub fn wrealpath(pathname: &wstr) -> Option<WString> {
|
||||
if pathname.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut narrow_path: Vec<u8> = wcs2string(&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'/' {
|
||||
narrow_path.pop();
|
||||
}
|
||||
|
||||
// `from_bytes` is Unix specific but there isn't really any other way to do this
|
||||
// since `libc::realpath` is also Unix specific. I also don't think we support Windows
|
||||
// outside of WSL + Cygwin (which should be fairly Unix-like anyways)
|
||||
let narrow_res = canonicalize(OsStr::from_bytes(&narrow_path));
|
||||
|
||||
let real_path = if let Ok(result) = narrow_res {
|
||||
result.into_os_string().into_vec()
|
||||
} else {
|
||||
// Check if everything up to the last path component is valid.
|
||||
let pathsep_idx = narrow_path.iter().rposition(|&c| c == b'/');
|
||||
|
||||
if pathsep_idx == Some(0) {
|
||||
// If the only pathsep is the first character then it's an absolute path with a
|
||||
// single path component and thus doesn't need conversion.
|
||||
narrow_path
|
||||
} else {
|
||||
// Only call realpath() on the portion up to the last component.
|
||||
let narrow_res = if let Some(pathsep_idx) = pathsep_idx {
|
||||
// Only call realpath() on the portion up to the last component.
|
||||
canonicalize(OsStr::from_bytes(&narrow_path[0..pathsep_idx]))
|
||||
} else {
|
||||
// If there is no "/", this is a file in $PWD, so give the realpath to that.
|
||||
canonicalize(".")
|
||||
};
|
||||
|
||||
let Ok(narrow_result) = narrow_res else { return None; };
|
||||
|
||||
let pathsep_idx = pathsep_idx.map_or(0, |idx| idx + 1);
|
||||
|
||||
let mut real_path = narrow_result.into_os_string().into_vec();
|
||||
|
||||
// This test is to deal with cases such as /../../x => //x.
|
||||
if real_path.len() > 1 {
|
||||
real_path.push(b'/');
|
||||
}
|
||||
|
||||
real_path.extend_from_slice(&narrow_path[pathsep_idx..]);
|
||||
|
||||
real_path
|
||||
}
|
||||
};
|
||||
|
||||
let_cxx_string!(s = real_path);
|
||||
|
||||
Some(str2wcstring(&s).from_ffi())
|
||||
}
|
|
@ -289,10 +289,10 @@ void show_stackframe(int frame_count = 100, int skip_levels = 0);
|
|||
///
|
||||
/// This function encodes illegal character sequences in a reversible way using the private use
|
||||
/// area.
|
||||
wcstring str2wcstring(const char *in);
|
||||
wcstring str2wcstring(const char *in, size_t len);
|
||||
wcstring str2wcstring(const std::string &in);
|
||||
wcstring str2wcstring(const std::string &in, size_t len);
|
||||
wcstring str2wcstring(const char *in);
|
||||
wcstring str2wcstring(const char *in, size_t len);
|
||||
|
||||
/// Returns a newly allocated multibyte character string equivalent of the specified wide character
|
||||
/// string.
|
||||
|
|
Loading…
Reference in New Issue
Block a user