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
use crate::enums::test_result::TestResult;
use crate::methods::reducer_escape::reducer_escape;
use crate::records::reducer::Reducer;
use std::io::{BufRead, BufReader};
use std::process::{Command, Stdio};
impl Reducer {
pub fn run(&mut self) -> TestResult {
self.write_temp_script(false);
let escaped_script_name = reducer_escape(self, &self.script_name);
let mut cmd = self.command.clone();
while let Some(pos) = cmd.find("{}") {
cmd.replace_range(pos..pos + 2, &escaped_script_name);
}
let mut result = TestResult::NoBug;
self.step += 1;
println!("Step {:4}...", self.step);
// Run the user command through the platform shell, mirroring C++
// `popen`, which delegates to `cmd.exe /C` on Windows and `/bin/sh -c`
// elsewhere. The previous port hardcoded `sh`, which does not exist on a
// stock Windows install and made the reducer abort there.
let mut command = {
#[cfg(windows)]
{
use std::os::windows::process::CommandExt;
// cmd.exe does not understand the MSVC `\"`-escaping that Rust's
// normal argument quoting applies; pass the (already shell-quoted)
// command line verbatim with `raw_arg` so cmd parses it itself.
let mut c = Command::new("cmd");
c.arg("/C");
c.raw_arg(&cmd);
c
}
#[cfg(not(windows))]
{
let mut c = Command::new("sh");
c.arg("-c").arg(&cmd);
c
}
};
let mut child = command
.stdout(Stdio::piped())
.spawn()
.expect("failed to run reducer command");
if let Some(stdout) = child.stdout.take() {
let mut reader = BufReader::new(stdout);
let mut line = String::new();
loop {
line.clear();
let bytes_read = reader.read_line(&mut line).unwrap_or(0);
if bytes_read == 0 {
break;
}
if line.contains(self.search_text.as_str()) {
result = TestResult::BugFound;
break;
}
}
}
let _ = child.wait();
result
}
}