|
1 | 1 | #[allow(unused_imports)] |
2 | 2 | use std::io::{self, Write}; |
| 3 | +use std::path::PathBuf; |
3 | 4 |
|
4 | 5 | const BUILT_IN_COMMANDS: [&str;3] = ["echo","exit","type"]; |
5 | 6 |
|
| 7 | +enum CommandLocation { |
| 8 | + Builtin, |
| 9 | + Executable(PathBuf), |
| 10 | + NotFound, |
| 11 | +} |
| 12 | + |
| 13 | +impl CommandLocation{ |
| 14 | + fn resolve(command_name:&str) -> Self{ |
| 15 | + if BUILT_IN_COMMANDS.contains(&command_name){ |
| 16 | + return Self::Builtin; |
| 17 | + } |
| 18 | + if let Some(path_var) = std::env::var_os("PATH"){ |
| 19 | + for dir in std::env::split_paths(&path_var){ |
| 20 | + let full_path = dir.join(command_name); |
| 21 | + if !full_path.exists() {continue}; |
| 22 | + |
| 23 | + #[cfg(unix)] |
| 24 | + { |
| 25 | + use std::os::unix::fs::PermissionsExt; |
| 26 | + if let Ok(metadata) = std::fs::metadata(&full_path) { |
| 27 | + if metadata.permissions().mode() & 0o111 == 0 { |
| 28 | + continue; |
| 29 | + } |
| 30 | + } else { |
| 31 | + continue; |
| 32 | + } |
| 33 | + } |
| 34 | + return Self::Executable(full_path); |
| 35 | + } |
| 36 | + } |
| 37 | + Self::NotFound |
| 38 | + } |
| 39 | + fn describe(&self,name:&str) -> String{ |
| 40 | + match self { |
| 41 | + CommandLocation::Builtin => format!("{} is a shell builtin", name), |
| 42 | + CommandLocation::Executable(path) => format!("{} is {}", name, path.display()), |
| 43 | + CommandLocation::NotFound => format!("{}: not found", name), |
| 44 | + } |
| 45 | + } |
| 46 | +} |
| 47 | + |
6 | 48 | enum Command{ |
7 | 49 | ExitCommand, |
8 | 50 | EchoCommand {display_string:String}, |
@@ -49,43 +91,8 @@ fn main() { |
49 | 91 | Command::ExitCommand => break, |
50 | 92 | Command::EchoCommand {display_string} => println!("{}", display_string), |
51 | 93 | Command::TypeCommand {command_name} => { |
52 | | - if BUILT_IN_COMMANDS.contains(&command_name.as_str()){ |
53 | | - println!("{} is a shell builtin",command_name); |
54 | | - continue; |
55 | | - } |
56 | | - let mut found = false; |
57 | | - //finding the files using rust std library |
58 | | - if let Some(path_var) = std::env::var_os("PATH"){ |
59 | | - for dir in std::env::split_paths(&path_var){ |
60 | | - let full_path = dir.join(&command_name); |
61 | | - |
62 | | - // skip if file/comand does not exist |
63 | | - if !full_path.exists(){ |
64 | | - continue; |
65 | | - } |
66 | | - |
67 | | - #[cfg(unix)] |
68 | | - { |
69 | | - use std::os::unix::fs::PermissionsExt; |
70 | | - |
71 | | - if let Ok(metadata) = std::fs::metadata(&full_path) { |
72 | | - let perms = metadata.permissions().mode(); |
73 | | - |
74 | | - // owner/group/other execute bits: 0o111 |
75 | | - if perms & 0o111 == 0 { |
76 | | - continue; // skip non-executable |
77 | | - } |
78 | | - } else { |
79 | | - continue; // could not read metadata |
80 | | - } |
81 | | - } |
82 | | - |
83 | | - println!("{} is {}", command_name, full_path.display()); |
84 | | - found=true; |
85 | | - break; |
86 | | - } |
87 | | - } |
88 | | - if !found{println!("{}: not found", command_name)}; |
| 94 | + let location = CommandLocation::resolve(&command_name); |
| 95 | + println!("{}", location.describe(&command_name)); |
89 | 96 | }, |
90 | 97 | Command::CommandNotFound => println!("{}: command not found", input.trim()), |
91 | 98 | } |
|
0 commit comments