use libc::c_char;
const SLASH: c_char = b'/' as c_char;
#[no_mangle]
unsafe extern "C" fn basename(path: *mut c_char) -> *mut c_char {
#[cfg(target_env = "gnu")]
{
let p = libc::strrchr(path, SLASH as _);
if p.is_null() {
path
} else {
p.add(1)
}
}
#[cfg(not(target_env = "gnu"))]
{
__xpg_basename(path)
}
}
#[no_mangle]
unsafe extern "C" fn __xpg_basename(path: *mut c_char) -> *mut c_char {
if path.is_null() || *path == 0 {
return c".".as_ptr().cast_mut();
}
let mut p = libc::strrchr(path, SLASH as _);
if p.is_null() {
return path;
}
if *p.add(1) != 0 {
return p.add(1);
}
while p > path && *p.sub(1) == SLASH {
p = p.sub(1);
}
if p == path {
return p.add(libc::strlen(p) - 1);
}
*p = 0;
p = p.sub(1);
while p > path && *p.sub(1) != SLASH {
p = p.sub(1);
}
p
}
#[no_mangle]
unsafe extern "C" fn dirname(path: *mut c_char) -> *mut c_char {
libc!(libc::dirname(path));
if path.is_null() {
return c".".as_ptr().cast_mut();
}
let mut i = libc::strlen(path);
if i == 2 && *path == SLASH && *path.add(1) == SLASH {
return b"//\0".as_ptr() as _;
}
while i >= 2 && *path.add(i - 1) == SLASH {
i -= 1;
}
while i >= 1 && *path.add(i - 1) != SLASH {
i -= 1;
}
while i >= 2 && *path.add(i - 1) == SLASH {
i -= 1;
}
if i == 0 {
return c".".as_ptr().cast_mut();
}
*path.add(i) = 0;
path
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dirname_basename() {
use core::ffi::CStr;
fn test(input: &CStr, expected_dir: &CStr, expected_gnu: &CStr, expected_posix: &CStr) {
unsafe {
let mut s = input.to_bytes_with_nul().to_vec();
let i = s.as_mut_ptr().cast();
let o = libc::dirname(i);
assert_eq!(CStr::from_ptr(o), expected_dir);
let mut s = input.to_bytes_with_nul().to_vec();
let i = s.as_mut_ptr().cast();
let o = libc::gnu_basename(i);
assert_eq!(CStr::from_ptr(o), expected_gnu);
let mut s = input.to_bytes_with_nul().to_vec();
let i = s.as_mut_ptr().cast();
let o = libc::posix_basename(i);
assert_eq!(CStr::from_ptr(o), expected_posix);
}
}
test(c"/usr/lib", c"/usr", c"lib", c"lib");
test(c"/usr//lib", c"/usr", c"lib", c"lib");
test(c"/usr/lib/", c"/usr", c"", c"lib");
test(c"/usr/lib//", c"/usr", c"", c"lib");
test(c"/", c"/", c"", c"/");
test(c"//", c"//", c"", c"/");
test(c"///", c"/", c"", c"/");
test(c"", c".", c"", c".");
test(c"usr", c".", c"usr", c"usr");
test(c"usr/", c".", c"", c"usr");
test(c"usr//", c".", c"", c"usr");
}
}