1 use help::Help; 2 use path_clean::PathClean; 3 use regex::{Captures, Regex}; 4 use std::intrinsics::unlikely; 5 use std::io::Read; 6 use std::os::unix::ffi::OsStrExt; 7 use std::{ 8 format, 9 fs::{self, File, OpenOptions}, 10 io::Write, 11 path::Path, 12 print, println, 13 string::String, 14 vec::Vec, 15 }; 16 17 use crate::env::{Env, ENV_FILE_PATH, ROOT_PATH}; 18 use crate::shell::Shell; 19 20 mod help; 21 22 #[derive(Debug, PartialEq, Eq, Clone)] 23 enum CommandType { 24 InternalCommand(BuildInCmd), 25 ExternalCommand(String), 26 } 27 28 #[derive(Debug, PartialEq, Eq, Clone)] 29 pub struct Command { 30 args: Vec<String>, 31 cmd_type: CommandType, 32 } 33 34 #[derive(Debug, PartialEq, Eq, Clone)] 35 pub enum CommandError { 36 CommandNotFound(String), 37 InvalidArgument(String), 38 WrongArgumentCount(usize), 39 EnvironmentVariableNotFound(String), 40 PathNotFound(String), 41 FileNotFound(String), 42 DirectoryNotFound(String), 43 NotDirectory(String), 44 NotFile(String), 45 UnclosedQuotation(usize), 46 } 47 48 impl CommandError { 49 pub fn handle(e: CommandError) { 50 match e { 51 CommandError::CommandNotFound(command) => { 52 println!("cannot find command: {}", command) 53 } 54 CommandError::InvalidArgument(argument) => { 55 println!("invalid argument: {}", argument) 56 } 57 CommandError::WrongArgumentCount(count) => { 58 println!("argument count incorrect: {}", count) 59 } 60 CommandError::EnvironmentVariableNotFound(env) => { 61 println!("environment variable not found: {}", env); 62 } 63 CommandError::PathNotFound(path) => { 64 println!("cannot found file or dirctory: {}", path) 65 } 66 CommandError::FileNotFound(path) => { 67 println!("cannot found file: {}", path) 68 } 69 CommandError::DirectoryNotFound(path) => { 70 println!("cannot found dirctory: {}", path) 71 } 72 CommandError::NotDirectory(path) => { 73 println!("path is not a dirctory: {}", path) 74 } 75 CommandError::NotFile(path) => { 76 println!("path is not a file: {}", path) 77 } 78 CommandError::UnclosedQuotation(index) => { 79 println!("command exists unclosed quotation at index: {}", index) 80 } 81 }; 82 } 83 } 84 85 impl Command { 86 fn new(name: String, args: Vec<String>) -> Result<Command, CommandError> { 87 for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD { 88 if name == *cmd { 89 return Ok(Command { 90 args, 91 cmd_type: CommandType::InternalCommand(BuildInCmd(cmd)), 92 }); 93 } 94 } 95 96 return Ok(Command { 97 args, 98 cmd_type: CommandType::ExternalCommand(name), 99 }); 100 } 101 102 fn parse_command_into_fragments(str: String) -> Result<Vec<String>, usize> { 103 let iter = str.chars(); 104 let mut fragments: Vec<String> = Vec::new(); 105 let mut stack: String = String::with_capacity(str.len()); 106 let mut left_quote: char = ' '; 107 let mut left_quote_index: usize = 0; 108 for (index, ch) in iter.enumerate() { 109 //存在未闭合的左引号,此时除能够配对的引号外,任何字符都加入栈中 110 if left_quote != ' ' { 111 if ch == left_quote { 112 left_quote = ' '; 113 } else { 114 stack.push(ch); 115 } 116 } else { 117 //不存在未闭合的左引号 118 if ch == '\'' || ch == '\"' { 119 //字符为引号,记录下来 120 left_quote = ch; 121 left_quote_index = index; 122 } else if ch == ' ' { 123 if !stack.is_empty() { 124 //字符为空格且栈中不为空,该空格视作命令段之间的分割线 125 //将栈中字符作为一个命令段加入集合,之后重置栈 126 fragments.push(stack.to_string()); 127 stack.clear(); 128 } 129 } else { 130 //其他字符都作为普通字符加入栈中 131 stack.push(ch); 132 } 133 } 134 } 135 //结束时如果栈不为空 136 if !stack.is_empty() { 137 if left_quote == ' ' { 138 //不存在未闭合的引号,将栈中剩余内容作为命令段加入集合 139 fragments.push(stack.to_string()); 140 } else { 141 //存在未闭合的引号,返回此引号的下标 142 return Err(left_quote_index); 143 } 144 } 145 Ok(fragments) 146 } 147 148 fn from_string(str: String) -> Result<Command, CommandError> { 149 let iter = Self::parse_command_into_fragments(str); 150 if let Err(index) = iter { 151 return Err(CommandError::UnclosedQuotation(index)); 152 } 153 let mut iter = iter.unwrap().into_iter(); 154 155 let name = iter.next().unwrap(); 156 let re: Regex = Regex::new(r"\$[\w_]+").unwrap(); 157 let replacement = |caps: &Captures| -> String { 158 match Env::get(&String::from(&caps[0][1..])) { 159 Some(value) => value, 160 None => String::from(&caps[0]), 161 } 162 }; 163 let mut args: Vec<String> = Vec::new(); 164 for arg in iter.collect::<Vec<String>>().iter() { 165 let arg = re.replace_all(arg.as_str(), &replacement).to_string(); 166 match re.captures(arg.as_str()) { 167 Some(caps) => { 168 return Err(CommandError::EnvironmentVariableNotFound(String::from( 169 caps.get(0).unwrap().as_str(), 170 ))) 171 } 172 None => args.push(arg), 173 } 174 } 175 let cmd = Command::new(name, args); 176 return cmd; 177 } 178 179 pub fn from_strings(str: String) -> Vec<Command> { 180 let mut commands = Vec::new(); 181 let segments: Vec<&str> = str.split(';').collect(); 182 for segment in segments { 183 if segment.trim().is_empty() { 184 continue; 185 } else { 186 match Command::from_string(String::from(segment)) { 187 Ok(s) => commands.push(s), 188 Err(e) => { 189 CommandError::handle(e); 190 } 191 } 192 } 193 } 194 195 commands 196 } 197 } 198 199 #[derive(Debug, PartialEq, Eq, Clone)] 200 pub struct BuildInCmd(pub &'static str); 201 202 impl BuildInCmd { 203 pub const BUILD_IN_CMD: &[BuildInCmd] = &[ 204 BuildInCmd("cd"), 205 BuildInCmd("ls"), 206 BuildInCmd("cat"), 207 BuildInCmd("touch"), 208 BuildInCmd("mkdir"), 209 BuildInCmd("rm"), 210 BuildInCmd("rmdir"), 211 BuildInCmd("pwd"), 212 BuildInCmd("cp"), 213 BuildInCmd("exec"), 214 BuildInCmd("echo"), 215 BuildInCmd("reboot"), 216 BuildInCmd("free"), 217 BuildInCmd("kill"), 218 BuildInCmd("help"), 219 BuildInCmd("export"), 220 BuildInCmd("env"), 221 BuildInCmd("compgen"), 222 BuildInCmd("complete"), 223 ]; 224 } 225 226 impl Shell { 227 pub fn exec_internal_command( 228 &mut self, 229 cmd: &str, 230 args: &Vec<String>, 231 ) -> Result<(), CommandError> { 232 match cmd { 233 "cd" => self.shell_cmd_cd(args), 234 "ls" => self.shell_cmd_ls(args), 235 "cat" => self.shell_cmd_cat(args), 236 "touch" => self.shell_cmd_touch(args), 237 "mkdir" => self.shell_cmd_mkdir(args), 238 "rm" => self.shell_cmd_rm(args), 239 "rmdir" => self.shell_cmd_rmdir(args), 240 "pwd" => self.shell_cmd_pwd(args), 241 "cp" => self.shell_cmd_cp(args), 242 "exec" => self.shell_cmd_exec(args), 243 "echo" => self.shell_cmd_echo(args), 244 "reboot" => self.shell_cmd_reboot(args), 245 "free" => self.shell_cmd_free(args), 246 "kill" => self.shell_cmd_kill(args), 247 "help" => self.shell_cmd_help(args), 248 "export" => self.shell_cmd_export(args), 249 "env" => self.shell_cmd_env(args), 250 "compgen" => self.shell_cmd_compgen(args), 251 "complete" => self.shell_cmd_complete(args), 252 253 _ => Err(CommandError::CommandNotFound(String::from(cmd))), 254 } 255 } 256 257 pub fn exec_external_command(&mut self, path: String, args: &Vec<String>) { 258 let mut full_args = args.clone(); 259 full_args.insert(0, path.clone()); 260 self.shell_cmd_exec(&full_args).unwrap_or_else(|e| { 261 let err = match e { 262 CommandError::FileNotFound(rp) => CommandError::CommandNotFound(rp), 263 _ => e, 264 }; 265 CommandError::handle(err); 266 }) 267 } 268 269 pub fn exec_command(&mut self, command: &Command) { 270 match &command.cmd_type { 271 CommandType::ExternalCommand(path) => { 272 self.exec_external_command(path.to_string(), &command.args); 273 } 274 275 CommandType::InternalCommand(BuildInCmd(cmd)) => { 276 match self.exec_internal_command(cmd, &command.args) { 277 Ok(_) => {} 278 Err(e) => CommandError::handle(e), 279 } 280 if command.args.contains(&String::from("--help")) { 281 Help::shell_help(cmd); 282 } 283 } 284 } 285 } 286 287 fn shell_cmd_cd(&mut self, args: &Vec<String>) -> Result<(), CommandError> { 288 let path = match args.len() { 289 0 => String::from(ROOT_PATH), 290 1 => self.is_dir(args.get(0).unwrap())?, 291 _ => return Err(CommandError::WrongArgumentCount(args.len())), 292 }; 293 self.chdir(&path); 294 Ok(()) 295 } 296 297 fn shell_cmd_ls(&self, args: &Vec<String>) -> Result<(), CommandError> { 298 let path = match args.len() { 299 0 => Self::current_dir(), 300 1 => self.is_dir(args.get(0).unwrap())?, 301 _ => return Err(CommandError::WrongArgumentCount(args.len())), 302 }; 303 let dir = match fs::read_dir(Path::new(&path)) { 304 Ok(readdir) => readdir, 305 Err(_) => return Err(CommandError::InvalidArgument(path)), 306 }; 307 308 for entry in dir { 309 let entry = entry.unwrap(); 310 if entry.file_type().unwrap().is_dir() { 311 crate::shell::Printer::print_color( 312 entry.file_name().as_bytes(), 313 0x000088ff, 314 0x00000000, 315 ); 316 print!(" "); 317 } else { 318 print!("{} ", entry.file_name().into_string().unwrap()); 319 } 320 } 321 println!(); 322 Ok(()) 323 } 324 325 fn shell_cmd_cat(&self, args: &Vec<String>) -> Result<(), CommandError> { 326 if args.len() <= 0 { 327 return Err(CommandError::WrongArgumentCount(args.len())); 328 } 329 let path = self.is_file(args.get(0).unwrap())?; 330 let mut buf: Vec<u8> = Vec::new(); 331 332 File::open(path).unwrap().read_to_end(&mut buf).unwrap(); 333 if args.len() == 1 { 334 println!("{}", String::from_utf8(buf.clone()).unwrap()); 335 } 336 337 //TODO: 这部分应该放在`Shell`中,所有指令公用 338 if args.len() == 3 { 339 let mut target_path = args.get(2).unwrap().clone(); 340 match self.is_file(&target_path) { 341 Ok(str) => target_path = str, 342 Err(e) => return Err(e), 343 } 344 345 if args[1] == ">" { 346 match OpenOptions::new().write(true).open(target_path) { 347 Ok(mut file) => { 348 file.write_all(&buf).unwrap(); 349 } 350 Err(e) => print!("{e}"), 351 } 352 } else if args[1] == ">>" { 353 match OpenOptions::new().append(true).open(target_path) { 354 Ok(mut file) => { 355 file.write_all(&buf).unwrap(); 356 } 357 Err(e) => print!("{e}"), 358 } 359 } 360 } 361 Ok(()) 362 } 363 364 fn shell_cmd_touch(&self, args: &Vec<String>) -> Result<(), CommandError> { 365 if unlikely(args.len() != 1) { 366 return Err(CommandError::WrongArgumentCount(args.len())); 367 } 368 let path = args.get(0).unwrap(); 369 370 //路径中提取目录和文件名 371 let index = path.rfind('/').unwrap_or(0); 372 let dir = &path[..index]; 373 let file_name = &path[index..]; 374 375 //判断文件所在目录是否存在 376 let str = self.is_dir(&dir.to_string())?; 377 //判断文件是否存在,存在时不操作,不存在时创建文件 378 let abs_path = format!("{}/{}", str, file_name); 379 if !Path::new(&abs_path).exists() { 380 File::create(&abs_path).unwrap(); 381 } 382 Ok(()) 383 } 384 385 fn shell_cmd_mkdir(&self, args: &Vec<String>) -> Result<(), CommandError> { 386 if unlikely(args.len() != 1) { 387 return Err(CommandError::WrongArgumentCount(args.len())); 388 } 389 let nowpath = Self::current_dir(); 390 let path = args.get(0).unwrap(); 391 let opt_path = nowpath + "/" + path; 392 let target_path; 393 if path.starts_with("/") { 394 target_path = path; 395 } else { 396 target_path = &opt_path; 397 } 398 if let Err(e) = fs::create_dir_all(target_path) { 399 print!("{e}") 400 } 401 Ok(()) 402 } 403 404 fn shell_cmd_rm(&self, args: &Vec<String>) -> Result<(), CommandError> { 405 if unlikely(args.len() != 1) { 406 return Err(CommandError::WrongArgumentCount(args.len())); 407 } 408 let path = self.is_file(args.get(0).unwrap())?; 409 let path_cstr = std::ffi::CString::new(path).unwrap(); 410 unsafe { 411 libc::syscall(libc::SYS_unlinkat, 0, path_cstr.as_ptr(), 0, 0, 0, 0); 412 } 413 Ok(()) 414 } 415 416 fn shell_cmd_rmdir(&self, args: &Vec<String>) -> Result<(), CommandError> { 417 if unlikely(args.len() != 1) { 418 return Err(CommandError::WrongArgumentCount(args.len())); 419 } 420 let path = self.is_dir(args.get(0).unwrap())?; 421 let path_cstr = std::ffi::CString::new(path).unwrap(); 422 unsafe { libc::unlinkat(0, path_cstr.as_ptr(), libc::AT_REMOVEDIR) }; 423 Ok(()) 424 } 425 426 fn shell_cmd_pwd(&self, args: &Vec<String>) -> Result<(), CommandError> { 427 if unlikely(args.len() != 0) { 428 return Err(CommandError::WrongArgumentCount(args.len())); 429 } 430 println!("{}", Self::current_dir()); 431 Ok(()) 432 } 433 434 fn shell_cmd_cp(&self, args: &Vec<String>) -> Result<(), CommandError> { 435 if args.len() == 2 { 436 let mut src_path = args.get(0).unwrap().clone(); 437 let mut target_path = args.get(1).unwrap().clone(); 438 439 match self.is_file(&src_path) { 440 Ok(str) => src_path = str, 441 Err(e) => return Err(e), 442 } 443 444 match self.is_file_or_dir(&target_path) { 445 Ok(str) => target_path = str, 446 Err(e) => { 447 let prefix = &target_path[..target_path.rfind('/').unwrap_or(0)]; 448 if !Path::new(prefix).is_dir() { 449 return Err(e); 450 } 451 } 452 } 453 454 if Path::new(&src_path).is_dir() { 455 let name = &src_path[src_path.rfind('/').unwrap_or(0)..]; 456 target_path = format!("{}/{}", target_path, name); 457 } 458 459 let mut src_file = File::open(&src_path).unwrap(); 460 let mut target_file = File::create(target_path).unwrap(); 461 let mut buf: Vec<u8> = Vec::new(); 462 src_file.read_to_end(&mut buf).unwrap(); 463 target_file.write_all(&buf).unwrap(); 464 return Ok(()); 465 } 466 return Err(CommandError::WrongArgumentCount(args.len())); 467 } 468 469 pub fn shell_cmd_exec(&self, args: &Vec<String>) -> Result<(), CommandError> { 470 if unlikely(args.len() <= 0) { 471 return Err(CommandError::WrongArgumentCount(args.len())); 472 } 473 let path = args.get(0).unwrap(); 474 //在环境变量中搜索 475 //TODO: 放在一个函数里来实现 476 let mut real_path = String::new(); 477 if !path.contains('/') { 478 let mut dir_collection = Env::path(); 479 dir_collection.insert(0, Self::current_dir()); 480 for dir in dir_collection { 481 let possible_path = format!("{}/{}", dir, path); 482 if Path::new(&possible_path).is_file() { 483 real_path = possible_path; 484 break; 485 } 486 } 487 if real_path.is_empty() { 488 return Err(CommandError::FileNotFound(path.clone())); 489 } 490 } else { 491 match self.is_file(path) { 492 Ok(path) => real_path = path, 493 Err(e) => return Err(e), 494 } 495 } 496 497 let mut args = args.clone(); 498 // 如果文件不存在,返回错误 499 if !Path::new(&real_path).is_file() { 500 // println!("{}: command not found", real_path); 501 return Err(CommandError::FileNotFound(real_path.clone())); 502 } 503 504 let pid: libc::pid_t = unsafe { 505 libc::syscall(libc::SYS_fork, 0, 0, 0, 0, 0, 0) 506 .try_into() 507 .unwrap() 508 }; 509 510 let name = &real_path[real_path.rfind('/').map(|pos| pos + 1).unwrap_or(0)..]; 511 *args.get_mut(0).unwrap() = name.to_string(); 512 let mut retval = 0; 513 if pid == 0 { 514 let path_cstr = std::ffi::CString::new(real_path).unwrap(); 515 let args_cstr = args 516 .iter() 517 .map(|str| std::ffi::CString::new(str.as_str()).unwrap()) 518 .collect::<Vec<std::ffi::CString>>(); 519 let mut args_ptr = args_cstr 520 .iter() 521 .map(|c_str| c_str.as_ptr()) 522 .collect::<Vec<*const i8>>(); 523 args_ptr.push(std::ptr::null()); 524 let argv = args_ptr.as_ptr(); 525 526 unsafe { 527 libc::execv(path_cstr.as_ptr(), argv); 528 } 529 } else { 530 if args.last().unwrap() != &"&" { 531 unsafe { libc::waitpid(pid, &mut retval as *mut i32, 0) }; 532 } else { 533 println!("[1] {}", pid); 534 } 535 } 536 return Ok(()); 537 } 538 539 fn shell_cmd_echo(&self, args: &Vec<String>) -> Result<(), CommandError> { 540 if args.len() > 0 { 541 let str = args.get(0).unwrap(); 542 if args.len() == 1 { 543 println!("{str}"); 544 } 545 546 //TODO: 和`cat`中的一样,应放在`Shell`中 547 if args.len() == 3 { 548 let mut target_path = args.get(2).unwrap().clone(); 549 match self.is_file(&target_path) { 550 Ok(str) => target_path = str, 551 Err(e) => return Err(e), 552 } 553 if args[1] == ">" { 554 match OpenOptions::new().write(true).open(target_path) { 555 Ok(mut file) => { 556 file.write_all(str.as_bytes()).unwrap(); 557 } 558 Err(e) => print!("{e}"), 559 } 560 } else if args[1] == ">>" { 561 match OpenOptions::new().append(true).open(target_path) { 562 Ok(mut file) => { 563 file.write_all(str.as_bytes()).unwrap(); 564 } 565 Err(e) => print!("{e}"), 566 } 567 } 568 } 569 return Ok(()); 570 } 571 return Err(CommandError::WrongArgumentCount(args.len())); 572 } 573 574 fn shell_cmd_reboot(&self, args: &Vec<String>) -> Result<(), CommandError> { 575 if args.len() == 0 { 576 unsafe { libc::syscall(libc::SYS_reboot, 0, 0, 0, 0, 0, 0) }; 577 return Ok(()); 578 } else { 579 return Err(CommandError::WrongArgumentCount(args.len())); 580 } 581 } 582 583 fn shell_cmd_free(&self, args: &Vec<String>) -> Result<(), CommandError> { 584 if args.len() == 1 && args.get(0).unwrap() != "-m" { 585 return Err(CommandError::InvalidArgument( 586 args.get(0).unwrap().to_string(), 587 )); 588 } 589 590 struct Mstat { 591 total: u64, // 计算机的总内存数量大小 592 used: u64, // 已使用的内存大小 593 free: u64, // 空闲物理页所占的内存大小 594 shared: u64, // 共享的内存大小 595 cache_used: u64, // 位于slab缓冲区中的已使用的内存大小 596 cache_free: u64, // 位于slab缓冲区中的空闲的内存大小 597 available: u64, // 系统总空闲内存大小(包括kmalloc缓冲区) 598 } 599 600 let mut mst = Mstat { 601 total: 0, 602 used: 0, 603 free: 0, 604 shared: 0, 605 cache_used: 0, 606 cache_free: 0, 607 available: 0, 608 }; 609 610 let mut info_file = File::open("/proc/meminfo").unwrap(); 611 let mut buf: Vec<u8> = Vec::new(); 612 info_file.read_to_end(&mut buf).unwrap(); 613 let str = String::from_utf8(buf).unwrap(); 614 let info = str 615 .split(&['\n', '\t', ' ']) 616 .filter_map(|str| str.parse::<u64>().ok()) 617 .collect::<Vec<u64>>(); 618 mst.total = *info.get(0).unwrap(); 619 mst.free = *info.get(1).unwrap(); 620 mst.used = mst.total - mst.free; 621 622 print!("\ttotal\t\tused\t\tfree\t\tshared\t\tcache_used\tcache_free\tavailable\n"); 623 print!("Mem:\t"); 624 625 if args.len() == 0 { 626 print!( 627 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n", 628 mst.total, 629 mst.used, 630 mst.free, 631 mst.shared, 632 mst.cache_used, 633 mst.cache_free, 634 mst.available 635 ); 636 } else { 637 print!( 638 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n", 639 mst.total >> 10, 640 mst.used >> 10, 641 mst.free >> 10, 642 mst.shared >> 10, 643 mst.cache_used >> 10, 644 mst.available >> 10 645 ); 646 } 647 Ok(()) 648 } 649 650 fn shell_cmd_kill(&self, args: &Vec<String>) -> Result<(), CommandError> { 651 if unlikely(args.len() != 1) { 652 return Err(CommandError::WrongArgumentCount(args.len())); 653 } 654 655 let pid = match args.get(0).unwrap().parse::<i32>() { 656 Ok(x) => x, 657 Err(_) => { 658 return Err(CommandError::InvalidArgument( 659 args.get(0).unwrap().to_string(), 660 )) 661 } 662 }; 663 unsafe { 664 libc::kill(pid, libc::SIGTERM); 665 } 666 Ok(()) 667 } 668 669 fn shell_cmd_help(&self, args: &Vec<String>) -> Result<(), CommandError> { 670 if args.len() == 0 { 671 for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD { 672 Help::shell_help(cmd) 673 } 674 return Ok(()); 675 } 676 return Err(CommandError::WrongArgumentCount(args.len())); 677 } 678 679 fn shell_cmd_export(&self, args: &Vec<String>) -> Result<(), CommandError> { 680 if args.len() == 1 { 681 let pair = args.get(0).unwrap().split('=').collect::<Vec<&str>>(); 682 683 if pair.len() == 2 && !pair.contains(&"") { 684 let name = pair.get(0).unwrap().to_string(); 685 let value = pair.get(1).unwrap().to_string(); 686 Env::insert(name, value); 687 return Ok(()); 688 } else { 689 return Err(CommandError::InvalidArgument(args.get(0).unwrap().clone())); 690 } 691 } 692 return Err(CommandError::WrongArgumentCount(args.len())); 693 } 694 695 fn shell_cmd_env(&self, args: &Vec<String>) -> Result<(), CommandError> { 696 if args.len() == 0 { 697 let mut file = File::open(ENV_FILE_PATH).unwrap(); 698 let mut buf: Vec<u8> = Vec::new(); 699 file.read_to_end(&mut buf).unwrap(); 700 println!("{}", String::from_utf8(buf).unwrap()); 701 return Ok(()); 702 } else { 703 return Err(CommandError::InvalidArgument(args.get(0).unwrap().clone())); 704 } 705 } 706 707 fn shell_cmd_compgen(&self, _args: &Vec<String>) -> Result<(), CommandError> { 708 //TODO 709 Ok(()) 710 } 711 712 fn shell_cmd_complete(&self, _args: &Vec<String>) -> Result<(), CommandError> { 713 //TODO 714 Ok(()) 715 } 716 717 fn path_format(&self, path: &String) -> Result<String, CommandError> { 718 let mut abs_path = path.clone(); 719 if !path.starts_with('/') { 720 abs_path = format!("{}/{}", Self::current_dir(), path); 721 } 722 let path = Path::new(&abs_path).clean(); 723 let mut fmt_path = path.to_str().unwrap().to_string(); 724 let replacement = |_caps: ®ex::Captures| -> String { String::from("/") }; 725 let re = regex::Regex::new(r"\/{2,}").unwrap(); 726 fmt_path = re.replace_all(fmt_path.as_str(), replacement).to_string(); 727 return Ok(fmt_path); 728 } 729 730 fn is_file(&self, path_str: &String) -> Result<String, CommandError> { 731 match self.path_format(path_str) { 732 Ok(path_str) => { 733 let path = Path::new(&path_str); 734 if !path.is_file() { 735 return Err(CommandError::NotFile(path_str.clone())); 736 }; 737 Ok(path_str) 738 } 739 Err(_) => Err(CommandError::FileNotFound(path_str.clone())), 740 } 741 } 742 743 fn is_dir(&self, path_str: &String) -> Result<String, CommandError> { 744 match self.path_format(path_str) { 745 Ok(path_str) => { 746 let path = Path::new(&path_str); 747 if !path.is_dir() { 748 return Err(CommandError::NotDirectory(path_str.clone())); 749 }; 750 Ok(path_str) 751 } 752 Err(_) => Err(CommandError::DirectoryNotFound(path_str.clone())), 753 } 754 } 755 756 fn is_file_or_dir(&self, path_str: &String) -> Result<String, CommandError> { 757 match self.path_format(path_str) { 758 Ok(path_str) => Ok(path_str), 759 Err(_) => Err(CommandError::PathNotFound(path_str.clone())), 760 } 761 } 762 } 763