use std::{env, fs}; use std::collections::HashMap; use std::fs::File; use std::io::{BufRead, BufReader, Write}; use std::path::PathBuf; use regex::Regex; fn main() { bindgen_lib(); link_lib(); generate_errors(); } fn bindgen_lib() { let c_dir = get_c_lib_dir(); println!("bindgen_lib{:?}", c_dir); let c_dir = PathBuf::from(c_dir); let c_lib = c_dir.join("VBoxCAPIGlue.h"); let bindings = bindgen::Builder::default() .header(c_lib.to_str().unwrap()) .generate() .unwrap(); let outfile = File::create(output().join("sys_lib.rs")).unwrap(); bindings.write(Box::new(&outfile)).unwrap(); outfile.sync_all().unwrap(); } fn link_lib() { let c_dir = get_c_lib_dir(); println!("bindgen_lib{:?}", c_dir); let c_dir = PathBuf::from(c_dir); let c_lib = c_dir.join("VBoxCAPIGlue.c"); let src = [c_lib.to_str().unwrap()]; let mut builder = cc::Build::new(); let build = builder.files(src.iter()).include("include"); build.compile("vboxapi"); } fn generate_errors() { let ver_str = format!("pub const BUILD_VER: u32 = {};\n", get_ver()); let c_dir = get_c_lib_dir(); let dir_entries = fs::read_dir(c_dir.clone()).unwrap(); let mut map = HashMap::new(); for entry in dir_entries { match entry { Ok(entry) => { println!("{:#?}", entry.file_name().to_str().unwrap()); let file = format!("{}/{}", c_dir.clone(), entry.file_name().to_str().unwrap()); map.extend(parse_to_vec(&file)); } Err(_) => {} }; } let text = generate_file(map.clone()); println!("{:#?}", text); println!("{:#?}", map.clone()); let mut file = File::create(output().join("error_map.rs")).unwrap(); file.write_all(ver_str.as_bytes()).unwrap(); file.write_all(text.as_bytes()).unwrap(); // panic!("{:#?}", map.clone()); } fn generate_file(map: HashMap) -> String { let mut text = String::new(); text.push_str("pub fn get_error_msg(error_code: u32) -> String {\n"); text.push_str(" match error_code {\n"); for (key, value) in map { text.push_str(format!(" {} => \"{}\".to_string(),\n", key, value).as_str()); } text.push_str(" _ => \"UNKNOWN\".to_string()\n"); text.push_str(" }\n"); text.push_str("}\n"); text } fn parse_to_vec(header: &str) -> HashMap { let mut map = HashMap::new(); if let Ok(file) = File::open(header) { let reader = BufReader::new(file); for line in reader.lines() { if let Ok(line) = line { if line.contains("(nsresult)") || line.contains("(HRESULT)") { let re = Regex::new(r"\s+").unwrap(); let result = re.replace_all(&line, " "); let words: Vec<&str> = result.split_whitespace().collect(); if words.len() > 2 { let re = Regex::new(r"0x[\da-fA-F]+").unwrap(); if let Some(capture) = re.find(words.last().unwrap()) { let value = capture.as_str(); if let Ok(value) = u32::from_str_radix(&value[2..], 16) { map.insert(value, words.get(1).unwrap().to_string()); } } } } } } } map } fn output() -> PathBuf { PathBuf::from(env::var("OUT_DIR").unwrap()) } fn get_c_lib_dir() -> String { if cfg!(feature = "v7_1") { "vendor/vbox_7_1".to_string() } else if cfg!(feature = "v7_0") { "vendor/vbox_7_0".to_string() } else if cfg!(feature = "v6_1") { "vendor/vbox_6_1".to_string() } else { "vendor/vbox_7_1".to_string() } } fn get_ver() -> u32 { if cfg!(feature = "v7_1") { 71 } else if cfg!(feature = "v7_0") { 70 } else if cfg!(feature = "v6_1") { 61 } else { 71 } }