execute_command_tokens/
lib.rs

1/*!
2# Execute Command Tokens
3
4Parse command strings.
5
6See [`execute`](https://crates.io/crates/execute).
7*/
8
9/// Parse a command string.
10pub fn command_tokens<S: AsRef<str>>(cmd: S) -> Vec<String> {
11    let cmd = cmd.as_ref();
12
13    let mut tokens = Vec::with_capacity(1);
14    let mut string_buffer = String::new();
15
16    let mut append_mode = false;
17    let mut quote_mode = false;
18    let mut quote_mode_ending = false; // to deal with '123''456' -> 123456
19    let mut quote_char = ' ';
20    let mut escaping = false;
21
22    for c in cmd.chars() {
23        if escaping {
24            append_mode = true;
25            escaping = false;
26
27            string_buffer.push(c);
28        } else if c.is_whitespace() {
29            if append_mode {
30                if quote_mode {
31                    string_buffer.push(c);
32                } else {
33                    append_mode = false;
34
35                    tokens.push(string_buffer);
36                    string_buffer = String::new();
37                }
38            } else if quote_mode_ending {
39                quote_mode_ending = false;
40
41                tokens.push(string_buffer);
42                string_buffer = String::new();
43            }
44        } else {
45            match c {
46                '"' | '\'' => {
47                    if append_mode {
48                        if quote_mode {
49                            if quote_char == c {
50                                append_mode = false;
51                                quote_mode = false;
52                                quote_mode_ending = true;
53                            } else {
54                                string_buffer.push(c);
55                            }
56                        } else {
57                            quote_mode = true;
58                            quote_char = c;
59                        }
60                    } else {
61                        append_mode = true;
62                        quote_mode = true;
63                        quote_char = c;
64                    }
65                },
66                '\\' => {
67                    escaping = true;
68                },
69                _ => {
70                    append_mode = true;
71                    escaping = false;
72
73                    string_buffer.push(c);
74                },
75            }
76        }
77    }
78
79    if append_mode || quote_mode_ending {
80        tokens.push(string_buffer);
81    }
82
83    tokens
84}