1use std::collections::HashMap;
29use std::env;
30use std::ffi::OsStr;
31use std::process::{Command, ExitStatus, Output, Stdio};
32
33use std::io::Write;
35use std::iter::IntoIterator;
36
37pub struct OutputString {
39 pub status: ExitStatus,
40 pub stdout: String,
41 pub stderr: String,
42}
43
44fn setup_envs<I, K, V>(cmd: &mut Command, vars: I) -> &mut Command
45where
46 I: IntoIterator<Item = (K, V)>,
47 K: AsRef<OsStr>,
48 V: AsRef<OsStr>,
49{
50 let filtered_env: HashMap<String, String> = env::vars()
51 .filter(|(k, _)| k == "TERM" || k == "TZ" || k == "PATH" || k == "LD_LIBRARY_PATH")
52 .collect();
53 cmd.env_clear()
54 .envs(filtered_env)
55 .envs(vars)
56 .env("LANG", "C")
57}
58
59pub fn exec_target<I, S>(target_exe: &str, args: I) -> OutputString
60where
61 I: IntoIterator<Item = S>,
62 S: AsRef<OsStr>,
63{
64 let mut cmd: Command = Command::new(target_exe);
65 setup_envs(&mut cmd, Vec::<(&str, &str)>::new())
66 .args(args)
67 .stdout(Stdio::piped())
68 .stderr(Stdio::piped());
69 let child = cmd.spawn().expect("failed to execute child");
70 let output: Output = child.wait_with_output().expect("failed to wait on child");
71 OutputString {
73 status: output.status,
74 stdout: String::from(String::from_utf8_lossy(&output.stdout)),
75 stderr: String::from(String::from_utf8_lossy(&output.stderr)),
76 }
77}
78
79pub fn exec_target_with_env<I, S, IKV, K, V>(target_exe: &str, args: I, env: IKV) -> OutputString
80where
81 I: IntoIterator<Item = S>,
82 S: AsRef<OsStr>,
83 IKV: IntoIterator<Item = (K, V)>,
84 K: AsRef<OsStr>,
85 V: AsRef<OsStr>,
86{
87 let mut cmd: Command = Command::new(target_exe);
88 setup_envs(&mut cmd, env)
89 .args(args)
90 .stdout(Stdio::piped())
91 .stderr(Stdio::piped());
92 let child = cmd.spawn().expect("failed to execute child");
93 let output: Output = child.wait_with_output().expect("failed to wait on child");
94 OutputString {
96 status: output.status,
97 stdout: String::from(String::from_utf8_lossy(&output.stdout)),
98 stderr: String::from(String::from_utf8_lossy(&output.stderr)),
99 }
100}
101
102pub fn exec_target_with_in<I, S>(target_exe: &str, args: I, in_bytes: &[u8]) -> OutputString
103where
104 I: IntoIterator<Item = S>,
105 S: AsRef<OsStr>,
106{
107 let mut cmd: Command = Command::new(target_exe);
108 setup_envs(&mut cmd, Vec::<(&str, &str)>::new())
109 .args(args)
110 .stdin(Stdio::piped())
111 .stdout(Stdio::piped())
112 .stderr(Stdio::piped());
113 let mut child = cmd.spawn().expect("failed to execute child");
114 {
115 let stdin = child.stdin.as_mut().expect("failed to get stdin");
116 stdin.write_all(in_bytes).expect("failed to write to stdin");
117 }
118 let output: Output = child.wait_with_output().expect("failed to wait on child");
119 OutputString {
121 status: output.status,
122 stdout: String::from(String::from_utf8_lossy(&output.stdout)),
123 stderr: String::from(String::from_utf8_lossy(&output.stderr)),
124 }
125}
126
127pub fn exec_target_with_env_in<I, S, IKV, K, V>(
149 target_exe: &str,
150 args: I,
151 env: IKV,
152 in_bytes: &[u8],
153) -> OutputString
154where
155 I: IntoIterator<Item = S>,
156 S: AsRef<OsStr>,
157 IKV: IntoIterator<Item = (K, V)>,
158 K: AsRef<OsStr>,
159 V: AsRef<OsStr>,
160{
161 let mut cmd: Command = Command::new(target_exe);
162 setup_envs(&mut cmd, env)
163 .args(args)
164 .stdin(Stdio::piped())
165 .stdout(Stdio::piped())
166 .stderr(Stdio::piped());
167 let mut child = cmd.spawn().expect("failed to execute child");
168 {
169 let stdin = child.stdin.as_mut().expect("failed to get stdin");
170 stdin.write_all(in_bytes).expect("failed to write to stdin");
171 }
172 let output: Output = child.wait_with_output().expect("failed to wait on child");
173 OutputString {
175 status: output.status,
176 stdout: String::from(String::from_utf8_lossy(&output.stdout)),
177 stderr: String::from(String::from_utf8_lossy(&output.stderr)),
178 }
179}
180
181pub fn args_from(s: &str) -> Vec<String> {
193 let mut v: Vec<String> = Vec::new();
194 let mut ss = String::new();
195 let mut enter_q: bool = false;
196 let mut enter_qq: bool = false;
197 let mut back_slash: bool = false;
198 for c in s.chars() {
200 if back_slash {
201 ss.push(c);
202 back_slash = false;
203 continue;
204 }
205 if c == '\\' {
206 back_slash = true;
207 continue;
208 }
209 if enter_q {
210 if c == '\'' {
211 v.push(ss.clone());
212 ss.clear();
213 enter_q = false;
214 } else {
215 ss.push(c);
216 }
217 continue;
218 }
219 if enter_qq {
220 if c == '\"' {
221 v.push(ss.clone());
222 ss.clear();
223 enter_qq = false;
224 } else {
225 ss.push(c);
226 }
227 continue;
228 }
229 match c {
230 '\'' => {
231 enter_q = true;
232 continue;
233 }
234 '\"' => {
235 enter_qq = true;
236 continue;
237 }
238 ' ' => {
239 if !ss.is_empty() {
240 v.push(ss.clone());
241 ss.clear();
242 }
243 }
244 _ => {
245 ss.push(c);
246 }
247 }
248 }
249 if !ss.is_empty() {
250 v.push(ss.clone());
251 ss.clear();
252 }
253 v
255}