summaryrefslogtreecommitdiffstats
path: root/src/poem/anthology/which.rs
blob: 9a1708aa3bcd4c404f802580cb1dbcf6bd55f587 (plain)
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use crate::compose::Environment;
use crate::poem::elements::verse::Spelling;
use crate::poem::Verse;
use std::os::unix::process::ExitStatusExt;
use std::process::{ExitStatus, Output};

/// which
///
/// The built-in `which` command. Used to check what program would be
/// called when not providing a full path. On Linux, it seems most
/// distros ship with a standalone `which` program. BSD systems, on the
/// other hand, tend to just use the shell built-in.
///
/// # Shell Examples
/// ```sh
/// which ls # -> /bin/ls
/// which exit # -> shell built-in command
/// ```
pub fn incant(clause: &Option<Vec<String>>, uout: bool, uerr: bool, env: &Environment) -> Output {
    let mut status = 0;
    let mut out: Vec<u8> = Vec::new();
    let mut err: Vec<u8> = Vec::new();
    match clause {
        Some(clause) => {
            let mut output: String;
            for word in clause {
                // Check if it's an alias
                if env.aliases.contains_key(word) {
                    output = format!("{}: aliased to {}\n", word, env.aliases.get(word).unwrap());
                    if uout {
                        out.append(&mut output.as_bytes().to_vec());
                    } else {
                        print!("{}", output);
                    }
                    continue;
                }

                // Manually check the path
                let mut verb = Verse::new();
                verb.push(word.clone());
                match verb.spellcheck(&env.bins) {
                    Some(Spelling::OnPath(i)) => {
                        output = format!("{}\n", env.bins[i]);
                        if uout {
                            out.append(&mut output.as_bytes().to_vec());
                        } else {
                            print!("{}", output);
                        }
                    }
                    Some(Spelling::BuiltIn(_)) => {
                        output = format!("{}: shell built-in command\n", word);
                        if uout {
                            out.append(&mut output.as_bytes().to_vec());
                        } else {
                            print!("{}", output);
                        }
                    }
                    Some(Spelling::FullPath) => {
                        output = format!("{}\n", word);
                        if uout {
                            out.append(&mut output.as_bytes().to_vec());
                        } else {
                            print!("{}", output);
                        }
                    }
                    None => {
                        output = format!("{} not found\n", word);
                        status = 1;
                        if uerr {
                            err.append(&mut output.as_bytes().to_vec());
                        } else {
                            eprint!("{}", output);
                        }
                    }
                }
            }
        }
        None => {
            status = 1;
            if uerr {
                err.append(&mut "which: not enough arguments".as_bytes().to_vec());
            } else {
                eprintln!("which: not enough arguments");
            }
            return Output {
                status: ExitStatus::from_raw(status),
                stdout: out,
                stderr: err,
            };
        }
    }

    Output {
        status: ExitStatus::from_raw(status),
        stdout: out,
        stderr: err,
    }
}