xref: /NovaShell/src/shell/command/mod.rs (revision cf3f377b821b86599b3d086da871b5cdfde193a8)
1 use colored::Colorize;
2 use help::Help;
3 use path_clean::PathClean;
4 use regex::{Captures, Regex};
5 use std::intrinsics::unlikely;
6 use std::io::Read;
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             let name = entry.file_name().into_string().unwrap();
315             if entry.file_type().unwrap().is_dir() {
316                 print!("{}\t", name.truecolor(0x00, 0x88, 0xff));
317             } else {
318                 print!("{}\t", name);
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 = args.get(0).ok_or(CommandError::UnableGetArg)?;
421         let mut parent = Self::current_dir();
422         let mut child = path.clone();
423         if let Some(index) = path.rfind('/') {
424             let (str1, str2) = path.split_at(index + 1);
425             parent = String::from(str1);
426             child = String::from(str2);
427         }
428 
429         let dir =
430             fs::read_dir(Path::new(&parent)).map_err(|_| CommandError::InvalidArgument(parent))?;
431 
432         let is_find = dir.filter_map(Result::ok).any(|entry| {
433             entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false)
434                 && entry.file_name().to_string_lossy().into_owned() == child
435         });
436 
437         if !is_find {
438             return Err(CommandError::DirectoryNotFound(path.clone()));
439         }
440 
441         let path = self.is_dir(path)?;
442         let path_cstr = std::ffi::CString::new(path).unwrap();
443         unsafe { libc::unlinkat(0, path_cstr.as_ptr(), libc::AT_REMOVEDIR) };
444 
445         Ok(())
446     }
447 
448     fn shell_cmd_pwd(&self, args: &Vec<String>) -> Result<(), CommandError> {
449         if unlikely(args.len() != 0) {
450             return Err(CommandError::WrongArgumentCount(args.len()));
451         }
452         println!("{}", Self::current_dir());
453         Ok(())
454     }
455 
456     fn shell_cmd_cp(&self, args: &Vec<String>) -> Result<(), CommandError> {
457         if args.len() == 2 {
458             let mut src_path = args.get(0).unwrap().clone();
459             let mut target_path = args.get(1).unwrap().clone();
460 
461             match self.is_file(&src_path) {
462                 Ok(str) => src_path = str,
463                 Err(e) => return Err(e),
464             }
465 
466             match self.is_file_or_dir(&target_path) {
467                 Ok(str) => target_path = str,
468                 Err(e) => {
469                     let prefix = &target_path[..target_path.rfind('/').unwrap_or(0)];
470                     if !Path::new(prefix).is_dir() {
471                         return Err(e);
472                     }
473                 }
474             }
475 
476             if Path::new(&src_path).is_dir() {
477                 let name = &src_path[src_path.rfind('/').unwrap_or(0)..];
478                 target_path = format!("{}/{}", target_path, name);
479             }
480 
481             let mut src_file = File::open(&src_path).unwrap();
482             let mut target_file = File::create(target_path).unwrap();
483             let mut buf: Vec<u8> = Vec::new();
484             src_file.read_to_end(&mut buf).unwrap();
485             target_file.write_all(&buf).unwrap();
486             return Ok(());
487         }
488         return Err(CommandError::WrongArgumentCount(args.len()));
489     }
490 
491     pub fn shell_cmd_exec(&self, args: &Vec<String>) -> Result<(), CommandError> {
492         if unlikely(args.len() <= 0) {
493             return Err(CommandError::WrongArgumentCount(args.len()));
494         }
495         let path = args.get(0).unwrap();
496         //在环境变量中搜索
497         //TODO: 放在一个函数里来实现
498         let mut real_path = String::new();
499         if !path.contains('/') {
500             let mut dir_collection = Env::path();
501             dir_collection.insert(0, Self::current_dir());
502             for dir in dir_collection {
503                 let possible_path = format!("{}/{}", dir, path);
504                 if Path::new(&possible_path).is_file() {
505                     real_path = possible_path;
506                     break;
507                 }
508             }
509             if real_path.is_empty() {
510                 return Err(CommandError::FileNotFound(path.clone()));
511             }
512         } else {
513             match self.is_file(path) {
514                 Ok(path) => real_path = path,
515                 Err(e) => return Err(e),
516             }
517         }
518 
519         let mut args = args.clone();
520         // 如果文件不存在,返回错误
521         if !Path::new(&real_path).is_file() {
522             // println!("{}: command not found", real_path);
523             return Err(CommandError::FileNotFound(real_path.clone()));
524         }
525 
526         let pid: libc::pid_t = unsafe {
527             libc::syscall(libc::SYS_fork, 0, 0, 0, 0, 0, 0)
528                 .try_into()
529                 .unwrap()
530         };
531 
532         let name = &real_path[real_path.rfind('/').map(|pos| pos + 1).unwrap_or(0)..];
533         *args.get_mut(0).unwrap() = name.to_string();
534         let mut retval = 0;
535         if pid == 0 {
536             let path_cstr = std::ffi::CString::new(real_path).unwrap();
537             let args_cstr = args
538                 .iter()
539                 .map(|str| std::ffi::CString::new(str.as_str()).unwrap())
540                 .collect::<Vec<std::ffi::CString>>();
541             let mut args_ptr = args_cstr
542                 .iter()
543                 .map(|c_str| c_str.as_ptr())
544                 .collect::<Vec<*const i8>>();
545             args_ptr.push(std::ptr::null());
546             let argv = args_ptr.as_ptr();
547 
548             unsafe {
549                 libc::execv(path_cstr.as_ptr(), argv);
550             }
551         } else {
552             if args.last().unwrap() != &"&" {
553                 unsafe { libc::waitpid(pid, &mut retval as *mut i32, 0) };
554             } else {
555                 println!("[1] {}", pid);
556             }
557         }
558         return Ok(());
559     }
560 
561     fn shell_cmd_echo(&self, args: &Vec<String>) -> Result<(), CommandError> {
562         if args.len() > 0 {
563             let str = args.get(0).unwrap();
564             if args.len() == 1 {
565                 println!("{str}");
566             }
567 
568             //TODO: 和`cat`中的一样,应放在`Shell`中
569             if args.len() == 3 {
570                 let mut target_path = args.get(2).unwrap().clone();
571                 match self.is_file(&target_path) {
572                     Ok(str) => target_path = str,
573                     Err(e) => return Err(e),
574                 }
575                 if args[1] == ">" {
576                     match OpenOptions::new().write(true).open(target_path) {
577                         Ok(mut file) => {
578                             file.write_all(str.as_bytes()).unwrap();
579                         }
580                         Err(e) => print!("{e}"),
581                     }
582                 } else if args[1] == ">>" {
583                     match OpenOptions::new().append(true).open(target_path) {
584                         Ok(mut file) => {
585                             file.write_all(str.as_bytes()).unwrap();
586                         }
587                         Err(e) => print!("{e}"),
588                     }
589                 }
590             }
591             return Ok(());
592         }
593         return Err(CommandError::WrongArgumentCount(args.len()));
594     }
595 
596     fn shell_cmd_reboot(&self, args: &Vec<String>) -> Result<(), CommandError> {
597         if args.len() == 0 {
598             unsafe { libc::syscall(libc::SYS_reboot, 0, 0, 0, 0, 0, 0) };
599             return Ok(());
600         } else {
601             return Err(CommandError::WrongArgumentCount(args.len()));
602         }
603     }
604 
605     fn shell_cmd_free(&self, args: &Vec<String>) -> Result<(), CommandError> {
606         if args.len() == 1 && args.get(0).unwrap() != "-m" {
607             return Err(CommandError::InvalidArgument(
608                 args.get(0).unwrap().to_string(),
609             ));
610         }
611 
612         struct Mstat {
613             total: u64,      // 计算机的总内存数量大小
614             used: u64,       // 已使用的内存大小
615             free: u64,       // 空闲物理页所占的内存大小
616             shared: u64,     // 共享的内存大小
617             cache_used: u64, // 位于slab缓冲区中的已使用的内存大小
618             cache_free: u64, // 位于slab缓冲区中的空闲的内存大小
619             available: u64,  // 系统总空闲内存大小(包括kmalloc缓冲区)
620         }
621 
622         let mut mst = Mstat {
623             total: 0,
624             used: 0,
625             free: 0,
626             shared: 0,
627             cache_used: 0,
628             cache_free: 0,
629             available: 0,
630         };
631 
632         let mut info_file = File::open("/proc/meminfo").unwrap();
633         let mut buf: Vec<u8> = Vec::new();
634         info_file.read_to_end(&mut buf).unwrap();
635         let str = String::from_utf8(buf).unwrap();
636         let info = str
637             .split(&['\n', '\t', ' '])
638             .filter_map(|str| str.parse::<u64>().ok())
639             .collect::<Vec<u64>>();
640         mst.total = *info.get(0).unwrap();
641         mst.free = *info.get(1).unwrap();
642         mst.used = mst.total - mst.free;
643 
644         print!("\ttotal\t\tused\t\tfree\t\tshared\t\tcache_used\tcache_free\tavailable\n");
645         print!("Mem:\t");
646 
647         if args.len() == 0 {
648             print!(
649                 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n",
650                 mst.total,
651                 mst.used,
652                 mst.free,
653                 mst.shared,
654                 mst.cache_used,
655                 mst.cache_free,
656                 mst.available
657             );
658         } else {
659             print!(
660                 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n",
661                 mst.total >> 10,
662                 mst.used >> 10,
663                 mst.free >> 10,
664                 mst.shared >> 10,
665                 mst.cache_used >> 10,
666                 mst.available >> 10
667             );
668         }
669         Ok(())
670     }
671 
672     fn shell_cmd_kill(&self, args: &Vec<String>) -> Result<(), CommandError> {
673         if unlikely(args.len() != 1) {
674             return Err(CommandError::WrongArgumentCount(args.len()));
675         }
676 
677         let pid = match args.get(0).unwrap().parse::<i32>() {
678             Ok(x) => x,
679             Err(_) => {
680                 return Err(CommandError::InvalidArgument(
681                     args.get(0).unwrap().to_string(),
682                 ))
683             }
684         };
685         unsafe {
686             libc::kill(pid, libc::SIGTERM);
687         }
688         Ok(())
689     }
690 
691     fn shell_cmd_help(&self, args: &Vec<String>) -> Result<(), CommandError> {
692         if args.len() == 0 {
693             for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD {
694                 Help::shell_help(cmd)
695             }
696             return Ok(());
697         }
698         return Err(CommandError::WrongArgumentCount(args.len()));
699     }
700 
701     fn shell_cmd_export(&self, args: &Vec<String>) -> Result<(), CommandError> {
702         if args.len() == 1 {
703             let pair = args.get(0).unwrap().split('=').collect::<Vec<&str>>();
704 
705             if pair.len() == 2 && !pair.contains(&"") {
706                 let name = pair.get(0).unwrap().to_string();
707                 let value = pair.get(1).unwrap().to_string();
708                 Env::insert(name, value);
709                 return Ok(());
710             } else {
711                 return Err(CommandError::InvalidArgument(args.get(0).unwrap().clone()));
712             }
713         }
714         return Err(CommandError::WrongArgumentCount(args.len()));
715     }
716 
717     fn shell_cmd_env(&self, args: &Vec<String>) -> Result<(), CommandError> {
718         if args.len() == 0 {
719             let mut file = File::open(ENV_FILE_PATH).unwrap();
720             let mut buf: Vec<u8> = Vec::new();
721             file.read_to_end(&mut buf).unwrap();
722             println!("{}", String::from_utf8(buf).unwrap());
723             return Ok(());
724         } else {
725             return Err(CommandError::InvalidArgument(args.get(0).unwrap().clone()));
726         }
727     }
728 
729     fn shell_cmd_compgen(&self, _args: &Vec<String>) -> Result<(), CommandError> {
730         //TODO
731         Ok(())
732     }
733 
734     fn shell_cmd_complete(&self, _args: &Vec<String>) -> Result<(), CommandError> {
735         //TODO
736         Ok(())
737     }
738 
739     fn path_format(&self, path: &String) -> Result<String, CommandError> {
740         let mut abs_path = path.clone();
741         if !path.starts_with('/') {
742             abs_path = format!("{}/{}", Self::current_dir(), path);
743         }
744         let path = Path::new(&abs_path).clean();
745         let mut fmt_path = path.to_str().unwrap().to_string();
746         let replacement = |_caps: &regex::Captures| -> String { String::from("/") };
747         let re = regex::Regex::new(r"\/{2,}").unwrap();
748         fmt_path = re.replace_all(fmt_path.as_str(), replacement).to_string();
749         return Ok(fmt_path);
750     }
751 
752     fn is_file(&self, path_str: &String) -> Result<String, CommandError> {
753         match self.path_format(path_str) {
754             Ok(path_str) => {
755                 let path = Path::new(&path_str);
756                 if !path.is_file() {
757                     return Err(CommandError::NotFile(path_str.clone()));
758                 };
759                 Ok(path_str)
760             }
761             Err(_) => Err(CommandError::FileNotFound(path_str.clone())),
762         }
763     }
764 
765     fn is_dir(&self, path_str: &String) -> Result<String, CommandError> {
766         match self.path_format(path_str) {
767             Ok(path_str) => {
768                 let path = Path::new(&path_str);
769                 if !path.is_dir() {
770                     return Err(CommandError::NotDirectory(path_str.clone()));
771                 };
772                 Ok(path_str)
773             }
774             Err(_) => Err(CommandError::DirectoryNotFound(path_str.clone())),
775         }
776     }
777 
778     fn is_file_or_dir(&self, path_str: &String) -> Result<String, CommandError> {
779         match self.path_format(path_str) {
780             Ok(path_str) => Ok(path_str),
781             Err(_) => Err(CommandError::PathNotFound(path_str.clone())),
782         }
783     }
784 }
785