use std::collections::HashMap;
pub struct ParsedBuiltins {
pub perl_version: String,
pub entries: HashMap<String, String>,
}
const BUNDLED_POD: &str = include_str!("../vendored/perlfunc.pod");
const BUNDLED_VERSION: &str = include_str!("../vendored/perlfunc.version");
pub fn parse_perlfunc() -> Option<ParsedBuiltins> {
parse_runtime_perlfunc().or_else(parse_bundled_perlfunc)
}
fn parse_runtime_perlfunc() -> Option<ParsedBuiltins> {
let perl_version = run_perl(&["-e", r#"printf "%vd", $^V"#])?;
let priv_lib = run_perl(&["-MConfig", "-e", "print $Config{privlibexp}"])?;
if perl_version.is_empty() || priv_lib.is_empty() {
return None;
}
let pod = ["pods", "pod"].iter().find_map(|dir| {
let path = std::path::PathBuf::from(&priv_lib).join(dir).join("perlfunc.pod");
std::fs::read_to_string(&path).ok()
})?;
let tag = format!("{} (runtime)", perl_version);
Some(ParsedBuiltins {
entries: render_entries(&pod, &tag),
perl_version: tag,
})
}
fn parse_bundled_perlfunc() -> Option<ParsedBuiltins> {
let version = BUNDLED_VERSION.trim();
let tag = format!("{} (bundled)", version);
Some(ParsedBuiltins {
entries: render_entries(BUNDLED_POD, &tag),
perl_version: tag,
})
}
fn run_perl(args: &[&str]) -> Option<String> {
let out = std::process::Command::new("perl")
.args(args)
.stdin(std::process::Stdio::null())
.output()
.ok()?;
if !out.status.success() {
return None;
}
Some(String::from_utf8_lossy(&out.stdout).trim().to_string())
}
fn render_entries(pod: &str, perl_version_tag: &str) -> HashMap<String, String> {
let mut entries = crate::pod::extract_perlfunc_items(pod);
let footer = format!("\n\n*from perlfunc.pod (perl {})*", perl_version_tag);
for body in entries.values_mut() {
body.push_str(&footer);
}
entries
}
#[cfg(test)]
#[path = "builtins_pod_tests.rs"]
mod tests;