summaryrefslogtreecommitdiffstats
path: root/src/main.rs
blob: f78e54d71670c2ea5fc5a3f7566e5877e6accb75 (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
99
100
101
102
103
104
105
use ctrlc;
use std::fs;
use std::io;
use std::io::Write;
use std::process::Command;

fn eval(paths: &[&str], prompt: &str) {
    let mut bins: Vec<String> = Vec::new();

    for path in paths {
        let files = fs::read_dir(path).expect("Unable to read files in your path");
        for file in files {
            bins.push(file.unwrap().path().display().to_string());
        }
    }

    loop {
        // Output the prompt
        io::stdout().flush().unwrap();
        print!("{}", prompt);
        io::stdout().flush().unwrap();

        // Wait for user input
        let mut input = String::new();
        let bytes = io::stdin()
            .read_line(&mut input)
            .expect("Unable to evaluate the input string");

        // Check if we've reached EOF (i.e. <C-d>)
        if bytes == 0 {
            break;
        }

        // Trim the input
        let input = input.trim();

        // Check if user wants to exit the shell
        if input == "exit" || input == "quit" {
            break;
        }

        // Parse command and arguments
        let mut split = input.split(' ');
        let cmd = match split.next() {
            Some(str) if str.trim().is_empty() => continue,
            Some(str) => str.trim(),
            None => continue,
        };

        // Parse arguments
        let mut args = vec![];
        loop {
            let next = split.next();
            match next {
                Some(str) => args.push(str),
                None => break,
            }
        }

        // Check if the command exists
        let cmd = match bins.iter().find(|b| b.split("/").last().unwrap() == cmd) {
            Some(cmd) => cmd,
            None => {
                println!("Command not found");
                continue;
            }
        };

        // Run the command (and wait for it to finish)
        let mut child = match Command::new(cmd).args(args).spawn() {
            Ok(ch) => ch,
            Err(_) => {
                println!("Unable to fork");
                continue;
            }
        };
        child.wait().unwrap();
    }
}

fn main() {
    // Define paths
    // TODO: Hardcoded path should only be the fallback
    let paths = [
        "/bin",
        "/sbin",
        "/usr/bin",
        "/usr/sbin",
        "/usr/local/bin",
        "/usr/local/sbin",
    ];

    // Set the prompt
    let prompt = "|> ";

    // Handle signals
    ctrlc::set_handler(move || {
        print!("\n{}", prompt);
        io::stdout().flush().unwrap();
    })
    .expect("Unable to set <C-c> handler");

    // Begin evaluating commands
    eval(&paths, prompt);
}