use super::*;
pub(super) fn run_shell(cmd: &str, topic: Option<&Value>) -> Option<Value> {
use std::io::Write;
let mut child = std::process::Command::new("sh")
.arg("-c")
.arg(cmd)
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.spawn()
.ok()?;
if let Some(v) = topic
&& let Some(mut stdin) = child.stdin.take()
{
let text = v.to_string();
std::thread::spawn(move || {
let _ = stdin.write_all(text.as_bytes());
if !text.ends_with('\n') {
let _ = stdin.write_all(b"\n");
}
});
}
drop(child.stdin.take());
let out = child.wait_with_output().ok()?;
if !out.status.success() {
return None;
}
let mut text = String::from_utf8_lossy(&out.stdout).into_owned();
if text.ends_with('\n') {
text.pop();
}
Some(Value::Str(text))
}
thread_local! {
static REGEX_MEMO: std::cell::RefCell<HashMap<String, Option<Regex>>> =
std::cell::RefCell::new(HashMap::new());
}
pub(crate) fn compiled_regex(pattern: &str) -> Option<Regex> {
REGEX_MEMO.with(|m| {
let mut m = m.borrow_mut();
if let Some(re) = m.get(pattern) {
return re.clone();
}
if m.len() >= 4_096 {
m.clear();
}
let re = Regex::new(pattern).ok();
m.insert(pattern.to_string(), re.clone());
re
})
}
pub(super) fn regex_test(a: &Value, b: &Value, want: bool) -> bool {
if matches!(a, Value::Null) || matches!(b, Value::Null) {
return !want;
}
match compiled_regex(&b.to_string()) {
Some(re) => re.is_match(&a.to_string()) == want,
None => false,
}
}