shell_core/
lib.rs

1use std::{
2    fmt::Display,
3    io::{Read, Write},
4};
5
6#[derive(Debug)]
7pub enum Argument {
8    Str(String),
9    Int(i64),
10}
11
12impl Display for Argument {
13    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
14        match self {
15            Argument::Str(s) => write!(f, "{}", s),
16            Argument::Int(i) => write!(f, "{}", i),
17        }
18    }
19}
20
21/// 实现一个函数,从提供的读取器中读取一行文本。
22pub fn read_line<T: Read>(conn: &mut T) -> Result<String, String> {
23    // 用于存储读取的数据的缓冲区。
24    let mut buf = vec![];
25
26    // 用于临时存储读取的数据的缓冲区。
27    let mut tmp_buf = [0u8; 4096];
28
29    loop {
30        // 从读取器中读取数据到临时缓冲区。
31        let sz = conn.read(&mut tmp_buf).map_err(|err| err.to_string())?;
32
33        // 如果读取到的数据大小为 0,表示连接已关闭。
34        if sz == 0 {
35            return Err("connection closed".to_string());
36        }
37
38        // 将读取到的数据添加到缓冲区中。
39        buf.extend_from_slice(&tmp_buf[0..sz]);
40
41        // 如果缓冲区中包含换行符,表示一行文本已读取完成。
42        if buf.ends_with(&[b'\n']) {
43            break;
44        }
45    }
46
47    // 将缓冲区中的数据转换为 UTF-8 字符串并返回。
48    Ok(String::from_utf8(buf)
49        .map_err(|err| err.to_string())?
50        .trim()
51        .to_owned())
52}
53
54/// 实现一个函数,将一行文本写入提供的写入器中。
55pub fn write_line<T: Write>(conn: &mut T, line: &String) -> Result<(), String> {
56    // 将一行文本添加到缓冲区中,并在末尾添加换行符。
57    let data_to_write = line.to_owned() + "\n";
58
59    // 将缓冲区中的数据写入到写入器中。
60    conn.write_all(data_to_write.as_bytes())
61        .map_err(|err| err.to_string())
62}
63
64/// 实现一个函数,将一段文本解析为一组参数。
65pub fn parse_arguments(input: &str) -> Vec<Argument> {
66    // 用于存储解析出的参数的向量。
67    let mut result = Vec::new();
68
69    // 用于存储当前正在解析的参数的字符串。
70    let mut current_arg = String::new();
71
72    // 用于指示是否在引号中。
73    let mut in_quotes = false;
74
75    // 用于指示是否需要转义。
76    let mut escape = false;
77
78    // 迭代输入文本中的字符
79    for c in input.chars() {
80        // 如果需要转义,直接将字符添加到当前参数中并跳过转义处理
81        if escape {
82            current_arg.push(c);
83            escape = false;
84        } else {
85            match c {
86                // 如果遇到引号,切换 in_quotes 状态
87                '"' => in_quotes = !in_quotes,
88
89                // 如果遇到反斜杠,需要转义下一个字符
90                '\\' => escape = true,
91
92                // 如果遇到逗号且不在引号中,表示一个参数结束
93                ',' if !in_quotes => {
94                    // 如果参数以引号开始和结束,移除引号并作为字符串处理
95                    if current_arg.starts_with('"') && current_arg.ends_with('"') {
96                        current_arg.remove(current_arg.len() - 1);
97                        current_arg.remove(0);
98                        result.push(Argument::Str(current_arg.clone()));
99                    } else {
100                        // 尝试将当前参数解析为整数
101                        if let Ok(num) = current_arg.trim().parse::<i64>() {
102                            result.push(Argument::Int(num));
103                        } else {
104                            // 如果无法将参数解析为整数,则作为字符串处理
105                            result.push(Argument::Str(current_arg.clone()));
106                        }
107                    }
108                    // 清空当前参数
109                    current_arg.clear();
110                }
111                // 其他字符直接添加到当前参数中
112                _ => current_arg.push(c),
113            }
114        }
115    }
116
117    // 处理最后一个参数
118    if !current_arg.is_empty() {
119        if current_arg.starts_with('"') && current_arg.ends_with('"') {
120            current_arg.remove(current_arg.len() - 1);
121            current_arg.remove(0);
122            result.push(Argument::Str(current_arg));
123        } else if let Ok(num) = current_arg.parse::<i64>() {
124            result.push(Argument::Int(num));
125        } else {
126            result.push(Argument::Str(current_arg));
127        }
128    }
129
130    // 返回解析出的参数列表
131    result
132}
133
134/// 实现一个函数,将一段命令行文本拆分为命令和参数。
135pub fn split_command(command_line: &str) -> Option<(String, String)> {
136    // 将命令行文本按空格拆分为一组字符串。
137    let sp = command_line.splitn(2, " ").collect::<Vec<&str>>();
138
139    match sp.len() {
140        // 如果没有拆分出任何字符串,返回 None。
141        0 => None,
142
143        // 如果拆分出一个字符串,返回该字符串作为命令,参数为空字符串。
144        1 => Some((sp[0].to_string(), String::new())),
145
146        // 如果拆分出两个字符串,返回前一个字符串作为命令,后一个字符串作为参数。
147        2 => Some((sp[0].to_string(), sp[1].to_string())),
148
149        // 如果拆分出了多个字符串,返回 None。
150        _ => None,
151    }
152}