Skip to content

Instantly share code, notes, and snippets.

@64
Last active July 17, 2017 02:26
Show Gist options
  • Save 64/8ac13019f4faa491018aab6b5c265141 to your computer and use it in GitHub Desktop.
Save 64/8ac13019f4faa491018aab6b5c265141 to your computer and use it in GitHub Desktop.
Generate reason and function error codes for rust-openssl
// Quite slow in debug, make sure to run in release (< 2s on my computer)
// TODO: Convert stuff in "err.h" correctly
extern crate regex;
use std::io::Write;
use std::io::BufRead;
use std::collections::BTreeMap;
use regex::Regex;
const USAGE: &'static str = "\
errgen: generates rust constants from OpenSSL include directory
usage: errgen [path] [outfile]";
const FILE_HEADER: &'static str = "\
// Generated by https://gist.github.com/64/8ac13019f4faa491018aab6b5c265141
extern crate libc;
use libc::c_int;\n\n";
macro_rules! println_stderr(
($($arg:tt)*) => { {
let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
r.expect("failed printing to stderr");
} }
);
// TODO: Rewrite this with an iterator
fn parse_filename(file: std::io::Result<std::fs::DirEntry>) -> Result<Option<std::fs::DirEntry>, std::io::Error> {
match file {
Ok(entry) => {
if !entry.file_type().unwrap().is_file() {
return Ok(None);
} else {
let filename = entry.file_name().into_string().unwrap();
let split: Vec<&str> = filename.split(".h").collect();
match split.len() {
0 => unreachable!(), // Shouldn't happen
1 => Ok(None),
2 => {
/*let module_name = split[0];
// Special cases:
let module_name = match module_name {
"" => "err", // Stuff in here relies on other #defines so it doesn't work properly
"buffer" => "buf",
"store" => "ossl_store",
"objects" => "obj",
x => x,
};
Ok(Some((module_name.to_owned(), entry)))*/
Ok(Some(entry))
},
_ => Ok(None),
}
}
},
Err(e) => Err(e),
}
}
// Returns number of lines successfully converted
fn parse_file(entry: std::fs::DirEntry, map: &mut BTreeMap<String, i32>) -> Result<usize, std::io::Error> {
let mut count = 0;
let file = std::fs::File::open(entry.path())?;
let buffer = std::io::BufReader::new(&file);
for line in buffer.lines().map(|l| l.unwrap()) {
if let Some((name, value)) = parse_line(line, entry.path().file_name().unwrap().to_str().unwrap()) {
count += 1;
map.insert(name, value);
}
}
Ok(count)
}
fn parse_line(line: String, file_name: &str) -> Option<(String, i32)> {
// sslerr.h -> \# define SSL_[RF]_[A-Z_]+[\s]+[\d]+
// this code is very good, nothing to see here
let regex_string = "\\# define [A-Z]+_[RF]_[A-Z_]+[\\s]+[\\d]+";
let regexpr = Regex::new(&regex_string).unwrap();
if regexpr.is_match(line.trim()) {
let mut iter = regexpr.find(&line).unwrap().as_str().split_whitespace().skip(2);
let varname = iter.next().unwrap();
let value_str = iter.next().unwrap();
match value_str.parse::<i32>() {
Ok(value) => Some((varname.to_owned(), value)),
Err(_) => {
println_stderr!("can't convert string \"{}\" in {}", value_str, file_name);
None
},
}
} else {
None
}
}
// Returns number of files successfully converted
fn run(dirpath: &str, outpath: &str) -> Result<usize, std::io::Error> {
let mut count = 0;
let dir = std::fs::read_dir(dirpath)?;
let mut map = BTreeMap::new();
for file in dir {
if let Some(entry) = parse_filename(file)? {
parse_file(entry, &mut map)?;
count += 1;
}
}
let mut outfile = std::fs::File::create(outpath)?;
outfile.write(&FILE_HEADER.as_bytes())?;
for (varname, value) in map {
outfile.write_fmt(format_args!("pub const {}: c_int = {};\n", varname, value))?;
}
Ok(count)
}
fn main() {
if std::env::args().count() != 3 {
println_stderr!("incorrect number of arguments");
println_stderr!("{}", USAGE);
std::process::exit(-1);
}
let mut args = std::env::args().skip(1);
let dirpath = args.next().unwrap();
let outpath = args.next().unwrap();
let done = run(&dirpath, &outpath).unwrap();
match done {
0...10 => {
println_stderr!("warning: low number of files converted ({})", done);
},
n => {
println!("successfully converted {} files", n);
println!("output written to {}", outpath);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment