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