use glob::glob;
use std::env;
use std::ffi::{CStr, OsStr};
use std::os::unix::ffi::OsStrExt;
use std::path::PathBuf;
use libc::{c_char, getpwuid_r, getuid, passwd};
pub fn cd(_args: &str) -> std::io::Result<()> {
if _args.len() == 0 {
match get_home_dir() {
Some(home) => {
if env::set_current_dir(&home).is_ok() {
} else {
eprintln!("Failed to change to home directory");
}
}
None => eprintln!("Could not determine home directory"),
}
return Ok(());
}
let pattern = &_args;
let mut matched = false;
for entry in glob(pattern).expect("Failed to read glob pattern") {
match entry {
Ok(path) => {
if path.is_dir() {
if env::set_current_dir(&path).is_ok() {
matched = true;
break; } else {
eprintln!("Failed to change directory to {}", path.display());
}
}
}
Err(e) => eprintln!("Error: {:?}", e),
}
}
if !matched {
eprintln!("cd: no such file or directory: {}", pattern);
}
Ok(())
}
fn get_home_dir() -> Option<PathBuf> {
unsafe {
let mut buf = Vec::with_capacity(1024);
let mut pwd = std::mem::MaybeUninit::<passwd>::uninit();
let mut result = std::ptr::null_mut();
let uid = getuid();
if getpwuid_r(
uid,
pwd.as_mut_ptr(),
buf.as_mut_ptr() as *mut c_char,
buf.capacity(),
&mut result,
) == 0
&& !result.is_null()
{
let pwd = pwd.assume_init();
let home = CStr::from_ptr(pwd.pw_dir);
Some(PathBuf::from(<OsStr as OsStrExt>::from_bytes(
home.to_bytes(),
)))
} else {
None
}
}
}