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
|
use std::io::Error;
use std::path::PathBuf;
use std::process::ExitStatus;
// ; on prev cmd any
// && on prev cmd okay
// || on prev cmd fail
mod command;
use command::{Command, RunIf, RunResult};
mod builtins;
pub struct CommandLine(Vec<Command>);
impl CommandLine {
pub fn new(line: &str) -> Self {
CommandLine(split(line))
}
pub fn run(
&self,
home: &PathBuf,
mut status: Option<ExitStatus>,
) -> Result<Option<ExitStatus>, Error> {
for cmd in &self.0 {
if cmd.when.can_run(&status) {
match cmd.run(&home, &status)? {
RunResult::Command(s) => status = Some(s),
RunResult::Builtin => {}
}
}
}
Ok(status)
}
}
fn split(line: &str) -> Vec<Command> {
let mut r: Vec<Command> = Vec::new();
let mut next = line.chars().peekable();
let mut iter = line.chars().enumerate();
let mut start_idx = 0;
let mut state = RunIf::Always;
while let Some((i, v)) = {
next.next();
iter.next()
} {
let n = next.peek();
if v == ';' {
r.push(Command::new(&line[start_idx..i], state));
state = RunIf::Always;
start_idx = i + 1;
} else if v == '|' && n == Some(&'|') {
r.push(Command::new(&line[start_idx..i], state));
state = RunIf::ExitFailure;
start_idx = i + 2;
next.next();
iter.next();
} else if v == '&' && n == Some(&'&') {
r.push(Command::new(&line[start_idx..i], state));
state = RunIf::ExitSuccess;
start_idx = i + 2;
next.next();
iter.next();
} else if n == None {
r.push(Command::new(&line[start_idx..], state));
}
}
r
}
|