1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//! The `command` builtin — run a command, bypassing shell functions.
//!
//! Also handles `command -v` (like which) and `command -V`.
use crate::{Builtin, ShellEnvironment};
pub struct CommandBuiltin;
impl Builtin for CommandBuiltin {
fn name(&self) -> &str {
"command"
}
fn execute(&self, args: &[&str], _env: &mut dyn ShellEnvironment) -> i32 {
if args.is_empty() {
return 0;
}
match args[0] {
"-v" => {
// command -v: print path to command.
for name in &args[1..] {
if let Some(path) = find_in_path(name) {
println!("{path}");
} else {
return 1;
}
}
0
}
"-V" => {
// command -V: verbose description.
for name in &args[1..] {
if let Some(path) = find_in_path(name) {
println!("{name} is {path}");
} else {
eprintln!("frost: not found: {name}");
return 1;
}
}
0
}
_ => {
// `command foo` — the executor handles bypassing functions.
// This builtin can't actually exec; return 127 so executor knows.
127
}
}
}
}
fn find_in_path(name: &str) -> Option<String> {
if let Ok(path_var) = std::env::var("PATH") {
for dir in path_var.split(':') {
let candidate = format!("{dir}/{name}");
if std::path::Path::new(&candidate).is_file() {
return Some(candidate);
}
}
}
None
}