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();
}
fn generate_file(map: HashMap<u32, String>) -> 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\n");
text.push_str("pub fn get_error_code(error_msg: &str) -> u32 {\n");
text.push_str(" match error_msg {\n");
for (key, value) in &map {
text.push_str(format!(" \"{}\" => {},\n", value, key).as_str());
}
text.push_str(" _ => 0\n");
text.push_str(" }\n");
text.push_str("}\n");
text
}
fn parse_to_vec(header: &str) -> HashMap<u32, String> {
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_2") {
"vendor/vbox_7_2".to_string()
} else 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_2".to_string()
}
}
fn get_ver() -> u32 {
if cfg!(feature = "v7_2") {
72
} else if cfg!(feature = "v7_1") {
71
} else if cfg!(feature = "v7_0") {
70
} else if cfg!(feature = "v6_1") {
61
} else {
72
}
}