use std::ffi::OsString;
use std::io::{self, Write};
use std::path::Path;
use std::process::ExitCode;
use std::sync::atomic::AtomicU64;
use std::sync::{Arc, Mutex};
use super::host::{Host, SANDBOX_OUTPUT_CAP, Sandbox, reset_sigpipe};
mod args;
mod messages;
mod run;
pub fn run(name: &'static str, args: Vec<OsString>) -> ExitCode {
reset_sigpipe();
let env = |k: &str| std::env::var_os(k);
ExitCode::from(main(name, &args, &env, &mut Host::Real, &mut io::stderr()))
}
fn main(
name: &'static str,
args: &[OsString],
env: &dyn Fn(&str) -> Option<OsString>,
host: &mut Host,
err: &mut dyn Write,
) -> u8 {
match args::parse(name, args, env, err) {
args::Parsed::Exit(c) => c,
args::Parsed::Run(s) => run::execute(name, s, host, err),
}
}
#[doc(hidden)]
pub fn run_in(
dir: &Path,
name: &'static str,
args: &[OsString],
stdin: &[u8],
) -> (i32, Vec<u8>, Vec<u8>) {
let stdout = Arc::new(Mutex::new(Vec::new()));
let mut host = Host::Sandbox(Sandbox {
dir: dir.to_path_buf(),
stdin: Some(stdin.to_vec()),
stdout: stdout.clone(),
budget: Arc::new(AtomicU64::new(SANDBOX_OUTPUT_CAP)),
reads: Default::default(),
});
let mut err = Vec::new();
let code = main(name, args, &|_| None, &mut host, &mut err);
drop(host);
let out = std::mem::take(&mut *stdout.lock().unwrap_or_else(|p| p.into_inner()));
(i32::from(code), out, err)
}