<commit_before>//! This module integrates the buddy heap allocator into the Rust runtime.
use spin::Mutex;

use ::Allocator;
use super::{BuddyHeapAllocator, FreeList};

static ALLOC: Mutex<Option<BuddyHeapAllocator<'static>>>
    = Mutex::new(None);

pub unsafe fn init_heap( start_addr: *mut u8
                       , free_lists: &'static mut [FreeList<'static>]
                       , heap_size: usize ) {
    *(ALLOC.lock())
        = Some(BuddyHeapAllocator::new(start_addr, free_lists, heap_size));
}

#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    unsafe {
        ALLOC.lock().as_mut()
             .expect("Cannot allocate memory, no system allocator exists!")
             .allocate(size, align)
             .expect("Memory could not be allocated; either the allocator is \
                      out of memory, or the allocation request was invalid.")
    }
}

#[no_mangle]
pub extern "C" fn __rust_deallocate( ptr: *mut u8, old_size: usize
                                   , align: usize ) {
    unsafe {
        ALLOC.lock().as_mut()
             .expect("Cannot deallocate memory, no system allocator exists!")
             .deallocate(ptr, old_size, align)
    }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate( ptr: *mut u8, old_size: usize
                                   , size: usize, align: usize )
                                   -> *mut u8 {
    unsafe {
        ALLOC.lock().as_mut()
             .expect("Cannot reallocate memory, no system allocator exists!")
             .reallocate(ptr, old_size, size, align)
             .expect("Memory could not be reallocated; either the allocator \
                     is out of memory, or the allocation request was invalid.")
     }
}

/// This is currently unsupported, so we just silently ignore it
/// and return the old size.
#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace( ptr: *mut u8, old_size: usize
                                           , _size: usize, _align: usize )
                                           -> usize {
    old_size
}

#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, _align: usize) -> usize {
    size
}
<commit_msg>[alloc] Fix spacing in error messages slightly<commit_after>//! This module integrates the buddy heap allocator into the Rust runtime.
use spin::Mutex;

use ::Allocator;
use super::{BuddyHeapAllocator, FreeList};

static ALLOC: Mutex<Option<BuddyHeapAllocator<'static>>>
    = Mutex::new(None);

pub unsafe fn init_heap( start_addr: *mut u8
                       , free_lists: &'static mut [FreeList<'static>]
                       , heap_size: usize ) {
    *(ALLOC.lock())
        = Some(BuddyHeapAllocator::new(start_addr, free_lists, heap_size));
}

#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    unsafe {
        ALLOC.lock().as_mut()
             .expect("Cannot allocate memory, no system allocator exists!")
             .allocate(size, align)
             .expect("Memory could not be allocated; either the allocator is\
                      out of memory, or the allocation request was invalid.")
    }
}

#[no_mangle]
pub extern "C" fn __rust_deallocate( ptr: *mut u8, old_size: usize
                                   , align: usize ) {
    unsafe {
        ALLOC.lock().as_mut()
             .expect("Cannot deallocate memory, no system allocator exists!")
             .deallocate(ptr, old_size, align)
    }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate( ptr: *mut u8, old_size: usize
                                   , size: usize, align: usize )
                                   -> *mut u8 {
    unsafe {
        ALLOC.lock().as_mut()
             .expect("Cannot reallocate memory, no system allocator exists!")
             .reallocate(ptr, old_size, size, align)
             .expect("Memory could not be reallocated; either the allocator\
                     is out of memory, or the allocation request was invalid.")
     }
}

/// This is currently unsupported, so we just silently ignore it
/// and return the old size.
#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace( ptr: *mut u8, old_size: usize
                                           , _size: usize, _align: usize )
                                           -> usize {
    old_size
}

#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, _align: usize) -> usize {
    size
}
<|endoftext|>


<commit_before>use toml::Value;

/// Check whether the configuration is valid for the store
///
/// The passed `Value` _must be_ the `[store]` sub-tree of the configuration. Otherwise this will
/// fail.
///
/// It checks whether the configuration looks like the store wants it to be:
///
/// ```toml
/// [store]
/// pre-create-hook-aspects = [ "misc", "encryption", "version-control"]
///
/// [[aspects.misc]]
/// parallel = true
/// [[aspects.encryption]]
/// parallel = false
/// [[aspects.version-control]]
/// parallel = false
///
/// [[hooks.gnupg]]
/// aspect = "encryption"
/// key = "0x123456789"
///
/// [[hooks.git]]
/// aspect = "version-control"
/// ```
///
/// It checks:
///  * Whether all the maps are there (whether store, store.aspects, store.aspects.example are all
///  maps)
///  * Whether each aspect configuration has a "parallel = <Boolean>" setting
///  * Whether each hook congfiguration has a "aspect = <String>" setting
///
/// It does NOT check:
///  * Whether all aspects which are used in the hook configuration are also configured
///
/// No configuration is a valid configuration, as the store will use the most conservative settings
/// automatically. This has also performance impact, as all hooks run in no-parallel mode then.
/// You have been warned!
///
///
pub fn config_is_valid(config: &Option<Value>) -> bool {
    use std::collections::BTreeMap;
    use std::io::Write;
    use std::io::stderr;

    if config.is_none() {
        return true;
    }

    fn has_key_with_string_ary(v: &BTreeMap<String, Value>, key: &str) -> bool {
        v.get(key)
            .map_or_else(|| {
                write!(stderr(), "Required key '{}' is not in store config", key).ok();
                false
            }, |t| match *t {
                    Value::Array(ref a) => a.iter().all(|elem| {
                        match *elem {
                            Value::String(_) => true,
                            _ => false,
                        }
                    }),
                    _ => {
                        write!(stderr(), "Key '{}' in store config should contain an array", key)
                            .ok();
                        false
                    }
            })
    }

    /// Check that
    /// * the top-level configuration
    /// * is a table
    /// * where all entries of a key `section` (eg. "hooks" or "aspects")
    ///     * Are maps
    ///     * where each has a key `key` (eg. "aspect" or "parallel")
    ///     * which fullfills constraint `f` (typecheck)
    fn check_all_inner_maps_have_key_with<F>(store_config: &BTreeMap<String, Value>,
                                             section: &str,
                                             key: &str,
                                             f: F)
        -> bool
        where F: Fn(&Value) -> bool
    {
        store_config.get(section) // The store config has the section `section`
            .map_or_else(|| {
                write!(stderr(), "Store config expects section '{}' to be present, but isn't.",
                        section).ok();
                false
            }, |section_table| {
                match *section_table { // which is
                    Value::Table(ref section_table) => // a table
                        section_table
                            .iter() // which has values,
                            .all(|(inner_key, cfg)| { // and all of these values
                                match *cfg {
                                    Value::Table(ref hook_config) => { // are tables
                                        hook_config.get(key) // with a key
                                            // fullfilling this constraint
                                            .map_or(false, |hook_aspect| f(&hook_aspect))
                                    },
                                    _ => {
                                        write!(stderr(), "Store config expects '{}' to be in '{}.{}', but isn't.",
                                                 key, section, inner_key).ok();
                                        false
                                    }
                                }
                            }),
                    _ => {
                        write!(stderr(), "Store config expects '{}' to be a Table, but isn't.",
                               section).ok();
                        false
                    }
                }
            })
    }

    match *config {
        Some(Value::Table(ref t)) => {
            has_key_with_string_ary(t, "store-unload-hook-aspects")    &&

            has_key_with_string_ary(t, "pre-create-hook-aspects")      &&
            has_key_with_string_ary(t, "post-create-hook-aspects")     &&
            has_key_with_string_ary(t, "pre-retrieve-hook-aspects")    &&
            has_key_with_string_ary(t, "post-retrieve-hook-aspects")   &&
            has_key_with_string_ary(t, "pre-update-hook-aspects")      &&
            has_key_with_string_ary(t, "post-update-hook-aspects")     &&
            has_key_with_string_ary(t, "pre-delete-hook-aspects")      &&
            has_key_with_string_ary(t, "post-delete-hook-aspects")     &&

            // The section "hooks" has maps which have a key "aspect" which has a value of type
            // String
            check_all_inner_maps_have_key_with(t, "hooks", "aspect",
                                               |asp| is_match!(asp, &Value::String(_))) &&

            // The section "aspects" has maps which have a key "parllel" which has a value of type
            // Boolean
            check_all_inner_maps_have_key_with(t, "aspects", "parallel",
                                               |asp| is_match!(asp, &Value::Boolean(_)))
        }
        _ => {
            write!(stderr(), "Store config is no table").ok();
            false
        },
    }
}

pub fn get_store_unload_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("store-unload-hook-aspects", value)
}

pub fn get_pre_create_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-create-hook-aspects", value)
}

pub fn get_post_create_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-create-hook-aspects", value)
}

pub fn get_pre_retrieve_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-retrieve-hook-aspects", value)
}

pub fn get_post_retrieve_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-retrieve-hook-aspects", value)
}

pub fn get_pre_update_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-update-hook-aspects", value)
}

pub fn get_post_update_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-update-hook-aspects", value)
}

pub fn get_pre_delete_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-delete-hook-aspects", value)
}

pub fn get_post_delete_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-delete-hook-aspects", value)
}

pub fn get_pre_move_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-move-hook-aspects", value)
}

pub fn get_post_move_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-move-hook-aspects", value)
}

#[derive(Debug)]
pub struct AspectConfig {
    parallel: bool,
    mutable_hooks: bool,
    config: Value,
}

impl AspectConfig {

    pub fn new(init: Value) -> AspectConfig {
        debug!("Trying to parse AspectConfig from: {:?}", init);
        let parallel = AspectConfig::is_parallel(&init);
        let muthooks = AspectConfig::allows_mutable_hooks(&init);
        AspectConfig {
            config: init,
            mutable_hooks: muthooks,
            parallel: parallel,
        }
    }

    fn is_parallel(init: &Value) -> bool {
        match *init {
            Value::Table(ref t) =>
                t.get("parallel")
                    .map_or(false, |value| {
                        match *value {
                            Value::Boolean(b) => b,
                            _ => false,
                        }
                    }),
            _ => false,
        }
    }

    fn allows_mutable_hooks(init: &Value) -> bool {
        match *init {
            Value::Table(ref t) =>
                t.get("mutable_hooks")
                    .map_or(false, |value| {
                        match *value {
                            Value::Boolean(b) => b,
                            _ => false,
                        }
                    }),
            _ => false,
        }
    }

    pub fn allow_mutable_hooks(&self) -> bool {
        self.mutable_hooks
    }

    /// Get the aspect configuration for an aspect.
    ///
    /// Pass the store configuration object, this searches in `[aspects][<aspect_name>]`.
    ///
    /// Returns `None` if one of the keys in the chain is not available
    pub fn get_for(v: &Option<Value>, a_name: String) -> Option<AspectConfig> {
        debug!("Get aspect configuration for {:?} from {:?}", a_name, v);
        let res = match *v {
            Some(Value::Table(ref tabl)) => {
                match tabl.get("aspects") {
                    Some(&Value::Table(ref tabl)) => {
                        tabl.get(&a_name[..]).map(|asp| AspectConfig::new(asp.clone()))
                    },

                    _ => None,
                }
            },
            _ => None,
        };
        debug!("Found aspect configuration for {:?}: {:?}", a_name, res);
        res
    }

}

fn get_aspect_names_for_aspect_position(config_name: &'static str, value: &Option<Value>) -> Vec<String> {
    let mut v = vec![];

    match *value {
        Some(Value::Table(ref t)) => {
            match t.get(config_name) {
                Some(&Value::Array(ref a)) => {
                    for elem in a {
                        match *elem {
                            Value::String(ref s) => v.push(s.clone()),
                            _ => warn!("Non-String in configuration, inside '{}'", config_name),
                        }
                    }
                },
                _ => warn!("'{}' configuration key should contain Array, does not", config_name),
            };
        },
        None => warn!("No store configuration"),
        _ => warn!("Configuration is not a table"),
    }
    v
}

<commit_msg>Fix comment how config has to look<commit_after>use toml::Value;

/// Check whether the configuration is valid for the store
///
/// The passed `Value` _must be_ the `[store]` sub-tree of the configuration. Otherwise this will
/// fail.
///
/// It checks whether the configuration looks like the store wants it to be:
///
/// ```toml
/// [store]
/// pre-create-hook-aspects = [ "misc", "encryption", "version-control"]
///
/// [store.aspects.misc]
/// parallel = true
///
/// [store.aspects.encryption]
/// parallel = false
///
/// [store.aspects.version-control]
/// parallel = false
///
/// [store.hooks.gnupg]
/// aspect = "encryption"
/// key = "0x123456789"
///
/// [store.hooks.git]
/// aspect = "version-control"
/// ```
///
/// It checks:
///  * Whether all the maps are there (whether store, store.aspects, store.aspects.example are all
///  maps)
///  * Whether each aspect configuration has a "parallel = <Boolean>" setting
///  * Whether each hook congfiguration has a "aspect = <String>" setting
///
/// It does NOT check:
///  * Whether all aspects which are used in the hook configuration are also configured
///
/// No configuration is a valid configuration, as the store will use the most conservative settings
/// automatically. This has also performance impact, as all hooks run in no-parallel mode then.
/// You have been warned!
///
///
pub fn config_is_valid(config: &Option<Value>) -> bool {
    use std::collections::BTreeMap;
    use std::io::Write;
    use std::io::stderr;

    if config.is_none() {
        return true;
    }

    fn has_key_with_string_ary(v: &BTreeMap<String, Value>, key: &str) -> bool {
        v.get(key)
            .map_or_else(|| {
                write!(stderr(), "Required key '{}' is not in store config", key).ok();
                false
            }, |t| match *t {
                    Value::Array(ref a) => a.iter().all(|elem| {
                        match *elem {
                            Value::String(_) => true,
                            _ => false,
                        }
                    }),
                    _ => {
                        write!(stderr(), "Key '{}' in store config should contain an array", key)
                            .ok();
                        false
                    }
            })
    }

    /// Check that
    /// * the top-level configuration
    /// * is a table
    /// * where all entries of a key `section` (eg. "hooks" or "aspects")
    ///     * Are maps
    ///     * where each has a key `key` (eg. "aspect" or "parallel")
    ///     * which fullfills constraint `f` (typecheck)
    fn check_all_inner_maps_have_key_with<F>(store_config: &BTreeMap<String, Value>,
                                             section: &str,
                                             key: &str,
                                             f: F)
        -> bool
        where F: Fn(&Value) -> bool
    {
        store_config.get(section) // The store config has the section `section`
            .map_or_else(|| {
                write!(stderr(), "Store config expects section '{}' to be present, but isn't.",
                        section).ok();
                false
            }, |section_table| {
                match *section_table { // which is
                    Value::Table(ref section_table) => // a table
                        section_table
                            .iter() // which has values,
                            .all(|(inner_key, cfg)| { // and all of these values
                                match *cfg {
                                    Value::Table(ref hook_config) => { // are tables
                                        hook_config.get(key) // with a key
                                            // fullfilling this constraint
                                            .map_or(false, |hook_aspect| f(&hook_aspect))
                                    },
                                    _ => {
                                        write!(stderr(), "Store config expects '{}' to be in '{}.{}', but isn't.",
                                                 key, section, inner_key).ok();
                                        false
                                    }
                                }
                            }),
                    _ => {
                        write!(stderr(), "Store config expects '{}' to be a Table, but isn't.",
                               section).ok();
                        false
                    }
                }
            })
    }

    match *config {
        Some(Value::Table(ref t)) => {
            has_key_with_string_ary(t, "store-unload-hook-aspects")    &&

            has_key_with_string_ary(t, "pre-create-hook-aspects")      &&
            has_key_with_string_ary(t, "post-create-hook-aspects")     &&
            has_key_with_string_ary(t, "pre-retrieve-hook-aspects")    &&
            has_key_with_string_ary(t, "post-retrieve-hook-aspects")   &&
            has_key_with_string_ary(t, "pre-update-hook-aspects")      &&
            has_key_with_string_ary(t, "post-update-hook-aspects")     &&
            has_key_with_string_ary(t, "pre-delete-hook-aspects")      &&
            has_key_with_string_ary(t, "post-delete-hook-aspects")     &&

            // The section "hooks" has maps which have a key "aspect" which has a value of type
            // String
            check_all_inner_maps_have_key_with(t, "hooks", "aspect",
                                               |asp| is_match!(asp, &Value::String(_))) &&

            // The section "aspects" has maps which have a key "parllel" which has a value of type
            // Boolean
            check_all_inner_maps_have_key_with(t, "aspects", "parallel",
                                               |asp| is_match!(asp, &Value::Boolean(_)))
        }
        _ => {
            write!(stderr(), "Store config is no table").ok();
            false
        },
    }
}

pub fn get_store_unload_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("store-unload-hook-aspects", value)
}

pub fn get_pre_create_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-create-hook-aspects", value)
}

pub fn get_post_create_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-create-hook-aspects", value)
}

pub fn get_pre_retrieve_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-retrieve-hook-aspects", value)
}

pub fn get_post_retrieve_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-retrieve-hook-aspects", value)
}

pub fn get_pre_update_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-update-hook-aspects", value)
}

pub fn get_post_update_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-update-hook-aspects", value)
}

pub fn get_pre_delete_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-delete-hook-aspects", value)
}

pub fn get_post_delete_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-delete-hook-aspects", value)
}

pub fn get_pre_move_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("pre-move-hook-aspects", value)
}

pub fn get_post_move_aspect_names(value: &Option<Value>) -> Vec<String> {
    get_aspect_names_for_aspect_position("post-move-hook-aspects", value)
}

#[derive(Debug)]
pub struct AspectConfig {
    parallel: bool,
    mutable_hooks: bool,
    config: Value,
}

impl AspectConfig {

    pub fn new(init: Value) -> AspectConfig {
        debug!("Trying to parse AspectConfig from: {:?}", init);
        let parallel = AspectConfig::is_parallel(&init);
        let muthooks = AspectConfig::allows_mutable_hooks(&init);
        AspectConfig {
            config: init,
            mutable_hooks: muthooks,
            parallel: parallel,
        }
    }

    fn is_parallel(init: &Value) -> bool {
        match *init {
            Value::Table(ref t) =>
                t.get("parallel")
                    .map_or(false, |value| {
                        match *value {
                            Value::Boolean(b) => b,
                            _ => false,
                        }
                    }),
            _ => false,
        }
    }

    fn allows_mutable_hooks(init: &Value) -> bool {
        match *init {
            Value::Table(ref t) =>
                t.get("mutable_hooks")
                    .map_or(false, |value| {
                        match *value {
                            Value::Boolean(b) => b,
                            _ => false,
                        }
                    }),
            _ => false,
        }
    }

    pub fn allow_mutable_hooks(&self) -> bool {
        self.mutable_hooks
    }

    /// Get the aspect configuration for an aspect.
    ///
    /// Pass the store configuration object, this searches in `[aspects][<aspect_name>]`.
    ///
    /// Returns `None` if one of the keys in the chain is not available
    pub fn get_for(v: &Option<Value>, a_name: String) -> Option<AspectConfig> {
        debug!("Get aspect configuration for {:?} from {:?}", a_name, v);
        let res = match *v {
            Some(Value::Table(ref tabl)) => {
                match tabl.get("aspects") {
                    Some(&Value::Table(ref tabl)) => {
                        tabl.get(&a_name[..]).map(|asp| AspectConfig::new(asp.clone()))
                    },

                    _ => None,
                }
            },
            _ => None,
        };
        debug!("Found aspect configuration for {:?}: {:?}", a_name, res);
        res
    }

}

fn get_aspect_names_for_aspect_position(config_name: &'static str, value: &Option<Value>) -> Vec<String> {
    let mut v = vec![];

    match *value {
        Some(Value::Table(ref t)) => {
            match t.get(config_name) {
                Some(&Value::Array(ref a)) => {
                    for elem in a {
                        match *elem {
                            Value::String(ref s) => v.push(s.clone()),
                            _ => warn!("Non-String in configuration, inside '{}'", config_name),
                        }
                    }
                },
                _ => warn!("'{}' configuration key should contain Array, does not", config_name),
            };
        },
        None => warn!("No store configuration"),
        _ => warn!("Configuration is not a table"),
    }
    v
}

<|endoftext|>


<commit_before>#![feature(path, io, env, core)]

extern crate "pkg-config" as pkg_config;

use std::env;
use std::old_io::{self, fs, Command};
use std::old_io::process::InheritFd;

fn main() {
    register_dep("SSH2");
    register_dep("OPENSSL");

    let mut opts = pkg_config::default_options("libgit2");
    opts.atleast_version = Some("0.22.0".to_string());
    match pkg_config::find_library_opts("libgit2", &opts) {
        Ok(()) => return,
        Err(..) => {}
    }

    let mut cflags = env::var_string("CFLAGS").unwrap_or(String::new());
    let target = env::var_string("TARGET").unwrap();
    let mingw = target.contains("windows-gnu");
    cflags.push_str(" -ffunction-sections -fdata-sections");

    if target.contains("i686") {
        cflags.push_str(" -m32");
    } else if target.as_slice().contains("x86_64") {
        cflags.push_str(" -m64");
    }
    if !target.contains("i686") {
        cflags.push_str(" -fPIC");
    }

    let src = Path::new(env::var_string("CARGO_MANIFEST_DIR").unwrap());
    let dst = Path::new(env::var_string("OUT_DIR").unwrap());
    let _ = fs::mkdir(&dst.join("build"), old_io::USER_DIR);

    let mut cmd = Command::new("cmake");
    cmd.arg(src.join("libgit2"))
       .cwd(&dst.join("build"));
    if mingw {
        cmd.arg("-G").arg("Unix Makefiles");
    }
    let profile = match env::var_string("PROFILE").unwrap().as_slice() {
        "bench" | "release" => "Release",
        _ => "Debug",
    };
    run(cmd.arg("-DTHREADSAFE=ON")
           .arg("-DBUILD_SHARED_LIBS=OFF")
           .arg("-DBUILD_CLAR=OFF")
           .arg(format!("-DCMAKE_BUILD_TYPE={}", profile))
           .arg(format!("-DCMAKE_INSTALL_PREFIX={}", dst.display()))
           .arg("-DBUILD_EXAMPLES=OFF")
           .arg(format!("-DCMAKE_C_FLAGS={}", cflags)));
    run(Command::new("cmake")
                .arg("--build").arg(".")
                .arg("--target").arg("install")
                .cwd(&dst.join("build")));

    println!("cargo:root={}", dst.display());
    if mingw || target.contains("windows") {
        println!("cargo:rustc-flags=-l winhttp -l rpcrt4 -l ole32 \
                                    -l ws2_32 -l bcrypt -l crypt32 \
                                    -l git2:static -L {}",
                 dst.join("lib").display());
    } else if env::var("HOST") == env::var("TARGET") {
        opts.statik = true;
        opts.atleast_version = None;
        append("PKG_CONFIG_PATH", dst.join("lib/pkgconfig"));
        pkg_config::find_library_opts("libgit2", &opts).unwrap();
    } else {
        println!("cargo:rustc-flags=-l git2:static");
        println!("cargo:rustc-flags=-L {}", dst.join("lib").display());
        if target.contains("apple") {
            println!("cargo:rustc-flags:-l iconv");
        }
    }
}

fn run(cmd: &mut Command) {
    println!("running: {:?}", cmd);
    assert!(cmd.stdout(InheritFd(1))
               .stderr(InheritFd(2))
               .status()
               .unwrap()
               .success());

}

fn register_dep(dep: &str) {
    match env::var_string(format!("DEP_{}_ROOT", dep).as_slice()) {
        Ok(s) => {
            append("CMAKE_PREFIX_PATH", Path::new(s.as_slice()));
            append("PKG_CONFIG_PATH", Path::new(s.as_slice()).join("lib/pkgconfig"));
        }
        Err(..) => {}
    }
}

fn append(var: &str, val: Path) {
    let prefix = env::var_string(var).unwrap_or(String::new());
    let val = env::join_paths(env::split_paths(&prefix)
                                  .chain(Some(val).into_iter())).unwrap();
    env::set_var(var, &val);
}
<commit_msg>Improve error message for build script failures<commit_after>#![feature(path, io, env, core)]

extern crate "pkg-config" as pkg_config;

use std::env;
use std::old_io::{self, fs, Command};
use std::old_io::process::InheritFd;

fn main() {
    register_dep("SSH2");
    register_dep("OPENSSL");

    let mut opts = pkg_config::default_options("libgit2");
    opts.atleast_version = Some("0.22.0".to_string());
    match pkg_config::find_library_opts("libgit2", &opts) {
        Ok(()) => return,
        Err(..) => {}
    }

    let mut cflags = env::var_string("CFLAGS").unwrap_or(String::new());
    let target = env::var_string("TARGET").unwrap();
    let mingw = target.contains("windows-gnu");
    cflags.push_str(" -ffunction-sections -fdata-sections");

    if target.contains("i686") {
        cflags.push_str(" -m32");
    } else if target.as_slice().contains("x86_64") {
        cflags.push_str(" -m64");
    }
    if !target.contains("i686") {
        cflags.push_str(" -fPIC");
    }

    let src = Path::new(env::var_string("CARGO_MANIFEST_DIR").unwrap());
    let dst = Path::new(env::var_string("OUT_DIR").unwrap());
    let _ = fs::mkdir(&dst.join("build"), old_io::USER_DIR);

    let mut cmd = Command::new("cmake");
    cmd.arg(src.join("libgit2"))
       .cwd(&dst.join("build"));
    if mingw {
        cmd.arg("-G").arg("Unix Makefiles");
    }
    let profile = match env::var_string("PROFILE").unwrap().as_slice() {
        "bench" | "release" => "Release",
        _ => "Debug",
    };
    run(cmd.arg("-DTHREADSAFE=ON")
           .arg("-DBUILD_SHARED_LIBS=OFF")
           .arg("-DBUILD_CLAR=OFF")
           .arg(format!("-DCMAKE_BUILD_TYPE={}", profile))
           .arg(format!("-DCMAKE_INSTALL_PREFIX={}", dst.display()))
           .arg("-DBUILD_EXAMPLES=OFF")
           .arg(format!("-DCMAKE_C_FLAGS={}", cflags)), "cmake");
    run(Command::new("cmake")
                .arg("--build").arg(".")
                .arg("--target").arg("install")
                .cwd(&dst.join("build")), "cmake");

    println!("cargo:root={}", dst.display());
    if mingw || target.contains("windows") {
        println!("cargo:rustc-flags=-l winhttp -l rpcrt4 -l ole32 \
                                    -l ws2_32 -l bcrypt -l crypt32 \
                                    -l git2:static -L {}",
                 dst.join("lib").display());
    } else if env::var("HOST") == env::var("TARGET") {
        opts.statik = true;
        opts.atleast_version = None;
        append("PKG_CONFIG_PATH", dst.join("lib/pkgconfig"));
        pkg_config::find_library_opts("libgit2", &opts).unwrap();
    } else {
        println!("cargo:rustc-flags=-l git2:static");
        println!("cargo:rustc-flags=-L {}", dst.join("lib").display());
        if target.contains("apple") {
            println!("cargo:rustc-flags:-l iconv");
        }
    }
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.stdout(InheritFd(1)).stderr(InheritFd(2)).status() {
        Ok(status) => status,
        Err(ref e) if e.kind == old_io::FileNotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn register_dep(dep: &str) {
    match env::var_string(format!("DEP_{}_ROOT", dep).as_slice()) {
        Ok(s) => {
            append("CMAKE_PREFIX_PATH", Path::new(s.as_slice()));
            append("PKG_CONFIG_PATH", Path::new(s.as_slice()).join("lib/pkgconfig"));
        }
        Err(..) => {}
    }
}

fn append(var: &str, val: Path) {
    let prefix = env::var_string(var).unwrap_or(String::new());
    let val = env::join_paths(env::split_paths(&prefix)
                                  .chain(Some(val).into_iter())).unwrap();
    env::set_var(var, &val);
}

fn fail(s: &str) -> ! {
    println!("{}", s);
    env::set_exit_status(1);
    old_io::stdio::set_stderr(Box::new(old_io::util::NullWriter));
    panic!()
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg(not(test))]

extern crate env_logger;
extern crate getopts;
extern crate rustfmt_nightly as rustfmt;

use std::fs::File;
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::{env, error};

use getopts::{Matches, Options};

use rustfmt::config::file_lines::FileLines;
use rustfmt::config::{get_toml_path, Color, Config, WriteMode};
use rustfmt::{run, FileName, Input, Summary};

type FmtError = Box<error::Error + Send + Sync>;
type FmtResult<T> = std::result::Result<T, FmtError>;

/// Rustfmt operations.
enum Operation {
    /// Format files and their child modules.
    Format {
        files: Vec<PathBuf>,
        config_path: Option<PathBuf>,
        minimal_config_path: Option<String>,
    },
    /// Print the help message.
    Help,
    // Print version information
    Version,
    /// Print detailed configuration help.
    ConfigHelp,
    /// Output default config to a file, or stdout if None
    ConfigOutputDefault {
        path: Option<String>,
    },
    /// No file specified, read from stdin
    Stdin {
        input: String,
        config_path: Option<PathBuf>,
    },
}

/// Parsed command line options.
#[derive(Clone, Debug, Default)]
struct CliOptions {
    skip_children: bool,
    verbose: bool,
    write_mode: Option<WriteMode>,
    color: Option<Color>,
    file_lines: FileLines, // Default is all lines in all files.
    unstable_features: bool,
    error_on_unformatted: bool,
}

impl CliOptions {
    fn from_matches(matches: &Matches) -> FmtResult<CliOptions> {
        let mut options = CliOptions::default();
        options.skip_children = matches.opt_present("skip-children");
        options.verbose = matches.opt_present("verbose");
        let unstable_features = matches.opt_present("unstable-features");
        let rust_nightly = option_env!("CFG_RELEASE_CHANNEL")
            .map(|c| c == "nightly")
            .unwrap_or(false);
        if unstable_features && !rust_nightly {
            return Err(FmtError::from(
                "Unstable features are only available on Nightly channel",
            ));
        } else {
            options.unstable_features = unstable_features;
        }

        if let Some(ref write_mode) = matches.opt_str("write-mode") {
            if let Ok(write_mode) = WriteMode::from_str(write_mode) {
                options.write_mode = Some(write_mode);
            } else {
                return Err(FmtError::from(format!(
                    "Invalid write-mode: {}",
                    write_mode
                )));
            }
        }

        if let Some(ref color) = matches.opt_str("color") {
            match Color::from_str(color) {
                Ok(color) => options.color = Some(color),
                _ => return Err(FmtError::from(format!("Invalid color: {}", color))),
            }
        }

        if let Some(ref file_lines) = matches.opt_str("file-lines") {
            options.file_lines = file_lines.parse()?;
        }

        if matches.opt_present("error-on-unformatted") {
            options.error_on_unformatted = true;
        }

        Ok(options)
    }

    fn apply_to(self, config: &mut Config) {
        config.set().skip_children(self.skip_children);
        config.set().verbose(self.verbose);
        config.set().file_lines(self.file_lines);
        config.set().unstable_features(self.unstable_features);
        config.set().error_on_unformatted(self.error_on_unformatted);
        if let Some(write_mode) = self.write_mode {
            config.set().write_mode(write_mode);
        }
        if let Some(color) = self.color {
            config.set().color(color);
        }
    }
}

/// read the given config file path recursively if present else read the project file path
fn match_cli_path_or_file(
    config_path: Option<PathBuf>,
    input_file: &Path,
) -> FmtResult<(Config, Option<PathBuf>)> {
    if let Some(config_file) = config_path {
        let toml = Config::from_toml_path(config_file.as_ref())?;
        return Ok((toml, Some(config_file)));
    }
    Config::from_resolved_toml_path(input_file).map_err(FmtError::from)
}

fn make_opts() -> Options {
    let mut opts = Options::new();

    // Sorted in alphabetical order.
    opts.optopt(
        "",
        "color",
        "Use colored output (if supported)",
        "[always|never|auto]",
    );
    opts.optflag(
        "",
        "config-help",
        "Show details of rustfmt configuration options",
    );
    opts.optopt(
        "",
        "config-path",
        "Recursively searches the given path for the rustfmt.toml config file. If not \
         found reverts to the input file path",
        "[Path for the configuration file]",
    );
    opts.opt(
        "",
        "dump-default-config",
        "Dumps default configuration to PATH. PATH defaults to stdout, if omitted.",
        "PATH",
        getopts::HasArg::Maybe,
        getopts::Occur::Optional,
    );
    opts.optopt(
        "",
        "dump-minimal-config",
        "Dumps configuration options that were checked during formatting to a file.",
        "PATH",
    );
    opts.optflag(
        "",
        "error-on-unformatted",
        "Error if unable to get comments or string literals within max_width, \
         or they are left with trailing whitespaces",
    );
    opts.optopt(
        "",
        "file-lines",
        "Format specified line ranges. See README for more detail on the JSON format.",
        "JSON",
    );
    opts.optflag("h", "help", "Show this message");
    opts.optflag("", "skip-children", "Don't reformat child modules");
    opts.optflag(
        "",
        "unstable-features",
        "Enables unstable features. Only available on nightly channel",
    );
    opts.optflag("v", "verbose", "Print verbose output");
    opts.optflag("V", "version", "Show version information");
    opts.optopt(
        "",
        "write-mode",
        "How to write output (not usable when piping from stdin)",
        "[replace|overwrite|display|plain|diff|coverage|checkstyle]",
    );

    opts
}

fn execute(opts: &Options) -> FmtResult<Summary> {
    let matches = opts.parse(env::args().skip(1))?;

    match determine_operation(&matches)? {
        Operation::Help => {
            print_usage_to_stdout(opts, "");
            Summary::print_exit_codes();
            Ok(Summary::default())
        }
        Operation::Version => {
            print_version();
            Ok(Summary::default())
        }
        Operation::ConfigHelp => {
            Config::print_docs();
            Ok(Summary::default())
        }
        Operation::ConfigOutputDefault { path } => {
            let toml = Config::default().all_options().to_toml()?;
            if let Some(path) = path {
                let mut file = File::create(path)?;
                file.write_all(toml.as_bytes())?;
            } else {
                io::stdout().write_all(toml.as_bytes())?;
            }
            Ok(Summary::default())
        }
        Operation::Stdin { input, config_path } => {
            // try to read config from local directory
            let (mut config, _) =
                match_cli_path_or_file(config_path, &env::current_dir().unwrap())?;

            // write_mode is always Plain for Stdin.
            config.set().write_mode(WriteMode::Plain);

            // parse file_lines
            if let Some(ref file_lines) = matches.opt_str("file-lines") {
                config.set().file_lines(file_lines.parse()?);
                for f in config.file_lines().files() {
                    match *f {
                        FileName::Custom(ref f) if f == "stdin" => {}
                        _ => eprintln!("Warning: Extra file listed in file_lines option '{}'", f),
                    }
                }
            }

            let mut error_summary = Summary::default();
            if config.version_meets_requirement(&mut error_summary) {
                error_summary.add(run(Input::Text(input), &config));
            }

            Ok(error_summary)
        }
        Operation::Format {
            files,
            config_path,
            minimal_config_path,
        } => {
            let options = CliOptions::from_matches(&matches)?;

            for f in options.file_lines.files() {
                match *f {
                    FileName::Real(ref f) if files.contains(f) => {}
                    FileName::Real(_) => {
                        eprintln!("Warning: Extra file listed in file_lines option '{}'", f)
                    }
                    _ => eprintln!("Warning: Not a file '{}'", f),
                }
            }

            let mut config = Config::default();
            // Load the config path file if provided
            if let Some(config_file) = config_path.as_ref() {
                config = Config::from_toml_path(config_file.as_ref())?;
            };

            if options.verbose {
                if let Some(path) = config_path.as_ref() {
                    println!("Using rustfmt config file {}", path.display());
                }
            }

            let mut error_summary = Summary::default();
            for file in files {
                if !file.exists() {
                    eprintln!("Error: file `{}` does not exist", file.to_str().unwrap());
                    error_summary.add_operational_error();
                } else if file.is_dir() {
                    eprintln!("Error: `{}` is a directory", file.to_str().unwrap());
                    error_summary.add_operational_error();
                } else {
                    // Check the file directory if the config-path could not be read or not provided
                    if config_path.is_none() {
                        let (config_tmp, path_tmp) =
                            Config::from_resolved_toml_path(file.parent().unwrap())?;
                        if options.verbose {
                            if let Some(path) = path_tmp.as_ref() {
                                println!(
                                    "Using rustfmt config file {} for {}",
                                    path.display(),
                                    file.display()
                                );
                            }
                        }
                        config = config_tmp;
                    }

                    if !config.version_meets_requirement(&mut error_summary) {
                        break;
                    }

                    options.clone().apply_to(&mut config);
                    error_summary.add(run(Input::File(file), &config));
                }
            }

            // If we were given a path via dump-minimal-config, output any options
            // that were used during formatting as TOML.
            if let Some(path) = minimal_config_path {
                let mut file = File::create(path)?;
                let toml = config.used_options().to_toml()?;
                file.write_all(toml.as_bytes())?;
            }

            Ok(error_summary)
        }
    }
}

fn main() {
    env_logger::init();

    let opts = make_opts();

    let exit_code = match execute(&opts) {
        Ok(summary) => {
            if summary.has_operational_errors() {
                1
            } else if summary.has_parsing_errors() {
                2
            } else if summary.has_formatting_errors() {
                3
            } else if summary.has_diff {
                // should only happen in diff mode
                4
            } else {
                assert!(summary.has_no_errors());
                0
            }
        }
        Err(e) => {
            eprintln!("{}", e.to_string());
            1
        }
    };
    // Make sure standard output is flushed before we exit.
    std::io::stdout().flush().unwrap();

    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    let sep = if reason.is_empty() {
        String::new()
    } else {
        format!("{}\n\n", reason)
    };
    let msg = format!(
        "{}Format Rust code\n\nusage: {} [options] <file>...",
        sep,
        env::args_os().next().unwrap().to_string_lossy()
    );
    println!("{}", opts.usage(&msg));
}

fn print_version() {
    let version_info = format!(
        "{}-{}",
        option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
        include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))
    );

    println!("rustfmt {}", version_info);
}

fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
    if matches.opt_present("h") {
        return Ok(Operation::Help);
    }

    if matches.opt_present("config-help") {
        return Ok(Operation::ConfigHelp);
    }

    if matches.opt_present("dump-default-config") {
        // NOTE for some reason when configured with HasArg::Maybe + Occur::Optional opt_default
        // doesn't recognize `--foo bar` as a long flag with an argument but as a long flag with no
        // argument *plus* a free argument. Thus we check for that case in this branch -- this is
        // required for backward compatibility.
        if let Some(path) = matches.free.get(0) {
            return Ok(Operation::ConfigOutputDefault {
                path: Some(path.clone()),
            });
        } else {
            return Ok(Operation::ConfigOutputDefault {
                path: matches.opt_str("dump-default-config"),
            });
        }
    }

    if matches.opt_present("version") {
        return Ok(Operation::Version);
    }

    let config_path_not_found = |path: &str| -> FmtResult<Operation> {
        Err(FmtError::from(format!(
            "Error: unable to find a config file for the given path: `{}`",
            path
        )))
    };

    // Read the config_path and convert to parent dir if a file is provided.
    // If a config file cannot be found from the given path, return error.
    let config_path: Option<PathBuf> = match matches.opt_str("config-path").map(PathBuf::from) {
        Some(ref path) if !path.exists() => return config_path_not_found(path.to_str().unwrap()),
        Some(ref path) if path.is_dir() => {
            let config_file_path = get_toml_path(path)?;
            if config_file_path.is_some() {
                config_file_path
            } else {
                return config_path_not_found(path.to_str().unwrap());
            }
        }
        path => path,
    };

    // If no path is given, we won't output a minimal config.
    let minimal_config_path = matches.opt_str("dump-minimal-config");

    // if no file argument is supplied, read from stdin
    if matches.free.is_empty() {
        let mut buffer = String::new();
        io::stdin().read_to_string(&mut buffer)?;

        return Ok(Operation::Stdin {
            input: buffer,
            config_path,
        });
    }

    let files: Vec<_> = matches
        .free
        .iter()
        .map(|s| {
            let p = PathBuf::from(s);
            // we will do comparison later, so here tries to canonicalize first
            // to get the expected behavior.
            p.canonicalize().unwrap_or(p)
        })
        .collect();

    Ok(Operation::Format {
        files,
        config_path,
        minimal_config_path,
    })
}
<commit_msg>Fix error_on_unformatted and skip_children override<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg(not(test))]

extern crate env_logger;
extern crate getopts;
extern crate rustfmt_nightly as rustfmt;

use std::fs::File;
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::{env, error};

use getopts::{Matches, Options};

use rustfmt::config::file_lines::FileLines;
use rustfmt::config::{get_toml_path, Color, Config, WriteMode};
use rustfmt::{run, FileName, Input, Summary};

type FmtError = Box<error::Error + Send + Sync>;
type FmtResult<T> = std::result::Result<T, FmtError>;

/// Rustfmt operations.
enum Operation {
    /// Format files and their child modules.
    Format {
        files: Vec<PathBuf>,
        config_path: Option<PathBuf>,
        minimal_config_path: Option<String>,
    },
    /// Print the help message.
    Help,
    // Print version information
    Version,
    /// Print detailed configuration help.
    ConfigHelp,
    /// Output default config to a file, or stdout if None
    ConfigOutputDefault {
        path: Option<String>,
    },
    /// No file specified, read from stdin
    Stdin {
        input: String,
        config_path: Option<PathBuf>,
    },
}

/// Parsed command line options.
#[derive(Clone, Debug, Default)]
struct CliOptions {
    skip_children: Option<bool>,
    verbose: bool,
    write_mode: Option<WriteMode>,
    color: Option<Color>,
    file_lines: FileLines, // Default is all lines in all files.
    unstable_features: bool,
    error_on_unformatted: Option<bool>,
}

impl CliOptions {
    fn from_matches(matches: &Matches) -> FmtResult<CliOptions> {
        let mut options = CliOptions::default();
        options.verbose = matches.opt_present("verbose");
        let unstable_features = matches.opt_present("unstable-features");
        let rust_nightly = option_env!("CFG_RELEASE_CHANNEL")
            .map(|c| c == "nightly")
            .unwrap_or(false);
        if unstable_features && !rust_nightly {
            return Err(FmtError::from(
                "Unstable features are only available on Nightly channel",
            ));
        } else {
            options.unstable_features = unstable_features;
        }

        if let Some(ref write_mode) = matches.opt_str("write-mode") {
            if let Ok(write_mode) = WriteMode::from_str(write_mode) {
                options.write_mode = Some(write_mode);
            } else {
                return Err(FmtError::from(format!(
                    "Invalid write-mode: {}",
                    write_mode
                )));
            }
        }

        if let Some(ref color) = matches.opt_str("color") {
            match Color::from_str(color) {
                Ok(color) => options.color = Some(color),
                _ => return Err(FmtError::from(format!("Invalid color: {}", color))),
            }
        }

        if let Some(ref file_lines) = matches.opt_str("file-lines") {
            options.file_lines = file_lines.parse()?;
        }

        if matches.opt_present("skip-children") {
            options.skip_children = Some(true);
        }
        if matches.opt_present("error-on-unformatted") {
            options.error_on_unformatted = Some(true);
        }

        Ok(options)
    }

    fn apply_to(self, config: &mut Config) {
        config.set().verbose(self.verbose);
        config.set().file_lines(self.file_lines);
        config.set().unstable_features(self.unstable_features);
        if let Some(skip_children) = self.skip_children {
            config.set().skip_children(skip_children);
        }
        if let Some(error_on_unformatted) = self.error_on_unformatted {
            config.set().error_on_unformatted(error_on_unformatted);
        }
        if let Some(write_mode) = self.write_mode {
            config.set().write_mode(write_mode);
        }
        if let Some(color) = self.color {
            config.set().color(color);
        }
    }
}

/// read the given config file path recursively if present else read the project file path
fn match_cli_path_or_file(
    config_path: Option<PathBuf>,
    input_file: &Path,
) -> FmtResult<(Config, Option<PathBuf>)> {
    if let Some(config_file) = config_path {
        let toml = Config::from_toml_path(config_file.as_ref())?;
        return Ok((toml, Some(config_file)));
    }
    Config::from_resolved_toml_path(input_file).map_err(FmtError::from)
}

fn make_opts() -> Options {
    let mut opts = Options::new();

    // Sorted in alphabetical order.
    opts.optopt(
        "",
        "color",
        "Use colored output (if supported)",
        "[always|never|auto]",
    );
    opts.optflag(
        "",
        "config-help",
        "Show details of rustfmt configuration options",
    );
    opts.optopt(
        "",
        "config-path",
        "Recursively searches the given path for the rustfmt.toml config file. If not \
         found reverts to the input file path",
        "[Path for the configuration file]",
    );
    opts.opt(
        "",
        "dump-default-config",
        "Dumps default configuration to PATH. PATH defaults to stdout, if omitted.",
        "PATH",
        getopts::HasArg::Maybe,
        getopts::Occur::Optional,
    );
    opts.optopt(
        "",
        "dump-minimal-config",
        "Dumps configuration options that were checked during formatting to a file.",
        "PATH",
    );
    opts.optflag(
        "",
        "error-on-unformatted",
        "Error if unable to get comments or string literals within max_width, \
         or they are left with trailing whitespaces",
    );
    opts.optopt(
        "",
        "file-lines",
        "Format specified line ranges. See README for more detail on the JSON format.",
        "JSON",
    );
    opts.optflag("h", "help", "Show this message");
    opts.optflag("", "skip-children", "Don't reformat child modules");
    opts.optflag(
        "",
        "unstable-features",
        "Enables unstable features. Only available on nightly channel",
    );
    opts.optflag("v", "verbose", "Print verbose output");
    opts.optflag("V", "version", "Show version information");
    opts.optopt(
        "",
        "write-mode",
        "How to write output (not usable when piping from stdin)",
        "[replace|overwrite|display|plain|diff|coverage|checkstyle]",
    );

    opts
}

fn execute(opts: &Options) -> FmtResult<Summary> {
    let matches = opts.parse(env::args().skip(1))?;

    match determine_operation(&matches)? {
        Operation::Help => {
            print_usage_to_stdout(opts, "");
            Summary::print_exit_codes();
            Ok(Summary::default())
        }
        Operation::Version => {
            print_version();
            Ok(Summary::default())
        }
        Operation::ConfigHelp => {
            Config::print_docs();
            Ok(Summary::default())
        }
        Operation::ConfigOutputDefault { path } => {
            let toml = Config::default().all_options().to_toml()?;
            if let Some(path) = path {
                let mut file = File::create(path)?;
                file.write_all(toml.as_bytes())?;
            } else {
                io::stdout().write_all(toml.as_bytes())?;
            }
            Ok(Summary::default())
        }
        Operation::Stdin { input, config_path } => {
            // try to read config from local directory
            let (mut config, _) =
                match_cli_path_or_file(config_path, &env::current_dir().unwrap())?;

            // write_mode is always Plain for Stdin.
            config.set().write_mode(WriteMode::Plain);

            // parse file_lines
            if let Some(ref file_lines) = matches.opt_str("file-lines") {
                config.set().file_lines(file_lines.parse()?);
                for f in config.file_lines().files() {
                    match *f {
                        FileName::Custom(ref f) if f == "stdin" => {}
                        _ => eprintln!("Warning: Extra file listed in file_lines option '{}'", f),
                    }
                }
            }

            let mut error_summary = Summary::default();
            if config.version_meets_requirement(&mut error_summary) {
                error_summary.add(run(Input::Text(input), &config));
            }

            Ok(error_summary)
        }
        Operation::Format {
            files,
            config_path,
            minimal_config_path,
        } => {
            let options = CliOptions::from_matches(&matches)?;

            for f in options.file_lines.files() {
                match *f {
                    FileName::Real(ref f) if files.contains(f) => {}
                    FileName::Real(_) => {
                        eprintln!("Warning: Extra file listed in file_lines option '{}'", f)
                    }
                    _ => eprintln!("Warning: Not a file '{}'", f),
                }
            }

            let mut config = Config::default();
            // Load the config path file if provided
            if let Some(config_file) = config_path.as_ref() {
                config = Config::from_toml_path(config_file.as_ref())?;
            };

            if options.verbose {
                if let Some(path) = config_path.as_ref() {
                    println!("Using rustfmt config file {}", path.display());
                }
            }

            let mut error_summary = Summary::default();
            for file in files {
                if !file.exists() {
                    eprintln!("Error: file `{}` does not exist", file.to_str().unwrap());
                    error_summary.add_operational_error();
                } else if file.is_dir() {
                    eprintln!("Error: `{}` is a directory", file.to_str().unwrap());
                    error_summary.add_operational_error();
                } else {
                    // Check the file directory if the config-path could not be read or not provided
                    if config_path.is_none() {
                        let (config_tmp, path_tmp) =
                            Config::from_resolved_toml_path(file.parent().unwrap())?;
                        if options.verbose {
                            if let Some(path) = path_tmp.as_ref() {
                                println!(
                                    "Using rustfmt config file {} for {}",
                                    path.display(),
                                    file.display()
                                );
                            }
                        }
                        config = config_tmp;
                    }

                    if !config.version_meets_requirement(&mut error_summary) {
                        break;
                    }

                    options.clone().apply_to(&mut config);
                    error_summary.add(run(Input::File(file), &config));
                }
            }

            // If we were given a path via dump-minimal-config, output any options
            // that were used during formatting as TOML.
            if let Some(path) = minimal_config_path {
                let mut file = File::create(path)?;
                let toml = config.used_options().to_toml()?;
                file.write_all(toml.as_bytes())?;
            }

            Ok(error_summary)
        }
    }
}

fn main() {
    env_logger::init();

    let opts = make_opts();

    let exit_code = match execute(&opts) {
        Ok(summary) => {
            if summary.has_operational_errors() {
                1
            } else if summary.has_parsing_errors() {
                2
            } else if summary.has_formatting_errors() {
                3
            } else if summary.has_diff {
                // should only happen in diff mode
                4
            } else {
                assert!(summary.has_no_errors());
                0
            }
        }
        Err(e) => {
            eprintln!("{}", e.to_string());
            1
        }
    };
    // Make sure standard output is flushed before we exit.
    std::io::stdout().flush().unwrap();

    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    let sep = if reason.is_empty() {
        String::new()
    } else {
        format!("{}\n\n", reason)
    };
    let msg = format!(
        "{}Format Rust code\n\nusage: {} [options] <file>...",
        sep,
        env::args_os().next().unwrap().to_string_lossy()
    );
    println!("{}", opts.usage(&msg));
}

fn print_version() {
    let version_info = format!(
        "{}-{}",
        option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
        include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))
    );

    println!("rustfmt {}", version_info);
}

fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
    if matches.opt_present("h") {
        return Ok(Operation::Help);
    }

    if matches.opt_present("config-help") {
        return Ok(Operation::ConfigHelp);
    }

    if matches.opt_present("dump-default-config") {
        // NOTE for some reason when configured with HasArg::Maybe + Occur::Optional opt_default
        // doesn't recognize `--foo bar` as a long flag with an argument but as a long flag with no
        // argument *plus* a free argument. Thus we check for that case in this branch -- this is
        // required for backward compatibility.
        if let Some(path) = matches.free.get(0) {
            return Ok(Operation::ConfigOutputDefault {
                path: Some(path.clone()),
            });
        } else {
            return Ok(Operation::ConfigOutputDefault {
                path: matches.opt_str("dump-default-config"),
            });
        }
    }

    if matches.opt_present("version") {
        return Ok(Operation::Version);
    }

    let config_path_not_found = |path: &str| -> FmtResult<Operation> {
        Err(FmtError::from(format!(
            "Error: unable to find a config file for the given path: `{}`",
            path
        )))
    };

    // Read the config_path and convert to parent dir if a file is provided.
    // If a config file cannot be found from the given path, return error.
    let config_path: Option<PathBuf> = match matches.opt_str("config-path").map(PathBuf::from) {
        Some(ref path) if !path.exists() => return config_path_not_found(path.to_str().unwrap()),
        Some(ref path) if path.is_dir() => {
            let config_file_path = get_toml_path(path)?;
            if config_file_path.is_some() {
                config_file_path
            } else {
                return config_path_not_found(path.to_str().unwrap());
            }
        }
        path => path,
    };

    // If no path is given, we won't output a minimal config.
    let minimal_config_path = matches.opt_str("dump-minimal-config");

    // if no file argument is supplied, read from stdin
    if matches.free.is_empty() {
        let mut buffer = String::new();
        io::stdin().read_to_string(&mut buffer)?;

        return Ok(Operation::Stdin {
            input: buffer,
            config_path,
        });
    }

    let files: Vec<_> = matches
        .free
        .iter()
        .map(|s| {
            let p = PathBuf::from(s);
            // we will do comparison later, so here tries to canonicalize first
            // to get the expected behavior.
            p.canonicalize().unwrap_or(p)
        })
        .collect();

    Ok(Operation::Format {
        files,
        config_path,
        minimal_config_path,
    })
}
<|endoftext|>


<commit_before>extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate xxd;

use clap::{Arg, ArgMatches, App, SubCommand};
use std::process::exit;
use std::fmt::Display;
use std::fs::File;
use std::io::Read;

mod errors {
    error_chain! {
        foreign_links {
            ParseError(::std::num::ParseIntError);
            Xxd(::xxd::errors::Error);
            Io(::std::io::Error);
        }
    }
}

use errors::*;

fn main() {
    let matches = create_arg_parser().get_matches();
    match run(&matches) {
        Ok(_) => exit(0),
        Err(e) => {
            report_error(&e);
            exit(1)
        }
    }
}

fn run(args: &ArgMatches) -> Result<()> {
    match args.subcommand_name() {
        Some("dump") => dump(args.subcommand_matches("dump")),
        Some("convert") => convert(args.subcommand_matches("convert")),
        Some("generate") => generate(args.subcommand_matches("generate")),
        _ => bail!(args.usage()),
    }
}

fn dump<'a>(args: Option<&ArgMatches<'a>>) -> Result<()> {
    let args = args.ok_or("No arguments available")?;
    let input_file = args.value_of("infile").unwrap_or("stdin");
    let seek = usize::from_str_radix(args.value_of("seek").unwrap_or("0"), 10)?;
    let length = args.value_of("length");
    let output_settings = create_output_settings(args)?;
    let reader = create_reader(input_file.to_string())?;
    match length {
        None => dump_iterator(Box::new(reader.bytes().skip(seek)), output_settings),
        Some(n) => {
            dump_iterator(Box::new(reader.bytes().skip(seek).take(usize::from_str_radix(n, 10)?)),
                          output_settings)
        }
    };
    Ok(())
}

fn dump_iterator<I: Iterator<Item = std::result::Result<u8, std::io::Error>>>(it: Box<I>, output_settings: ::xxd::dump::OutputSettings) -> Result<()>{
    let mut data: Vec<u8> = Vec::new();
    let mut address = 0;
    for byte in *it {
        data.push(byte?);
        if data.len() == output_settings.bytes_per_line() {
            dump_line(&data, output_settings.start_address(address));
            address += data.len();
            data.clear();
        }
    }
    if data.len() > 0 {
        dump_line(&data, output_settings.start_address(address));
        address += data.len();
        data.clear();
    }
    Ok(())
}

fn create_output_settings<'a>(args: &ArgMatches<'a>) -> Result<::xxd::dump::OutputSettings> {
    let columns = usize::from_str_radix(args.value_of("columns").unwrap_or("8"), 10)?;
    let format = args.value_of("format").unwrap_or("hex");
    let group_size = usize::from_str_radix(args.value_of("group-size").unwrap_or("1"), 10)?;
    Ok(::xxd::dump::OutputSettings::new()
           .format(::xxd::dump::OutputFormat::from(format.to_string()))
           .group_size(group_size)
           .columns(columns))
}

fn dump_line(data: &[u8], output_settings: ::xxd::dump::OutputSettings) {
    let output_line = ::xxd::dump::OutputLine::new(data).format(output_settings);
    println!("{}", output_line);
}

fn create_reader(path: String) -> Result<Box<std::io::Read>> {
    match path.as_ref() {
        "stdin" => Ok(Box::new(std::io::stdin())),
        _ => {
            let file_reader = std::fs::File::open(path)?;
            Ok(Box::new(file_reader))
        }
    }
}

fn convert<'a>(args: Option<&ArgMatches<'a>>) -> Result<()> {
    command_not_supported()
}

fn generate<'a>(args: Option<&ArgMatches<'a>>) -> Result<()> {
    command_not_supported()
}

fn command_not_supported() -> Result<()> {
    bail!("Command not supported yet!")
}

fn report_error<T: Display>(error: &T) {
    println!("xxd-rs: {}", error)
}

fn create_arg_parser<'a, 'b>() -> App<'a, 'b> {
    App::new("A rust based clone of the all time classic xxd tool")
        .version("0.1.0")
        .author("Nicola Coretti <nicola.coretti@gmail.com>")
        .about("make a hexdump or the reverse")
        .arg(Arg::with_name("infile")
                 .required(false)
                 .global(true)
                 .index(1)
                 .help("Input file which shall be used (default: stdin)"))
        .arg(Arg::with_name("outfile")
                 .required(false)
                 .global(true)
                 .index(2)
                 .help("File to which the output will be written (default: stdout)"))
        .arg(Arg::with_name("seek")
                 .short("s")
                 .long("seek")
                 .required(false)
                 .takes_value(true)
                 .global(true)
                 .help("Offset in the file where to start reading"))
        .arg(Arg::with_name("length")
                 .short("l")
                 .long("length")
                 .required(false)
                 .takes_value(true)
                 .global(true)
                 .help("Amount of bytes which shall be read"))
        .subcommand(SubCommand::with_name("dump")
                        .about("Dumps an input file in the appropriate output format")
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("hex")
                                 .possible_value("bin")
                                 .possible_value("oct")
                                 .help("Specifies the output format for the value (default: hex)"))
                        .arg(Arg::with_name("group-size")
                                 .short("g")
                                 .long("group-size")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Separate  the output of every <bytes> bytes (two hex characters or eight bit-digits each) by a whitespace."))
                        .arg(Arg::with_name("columns")
                                 .short("c")
                                 .long("columns")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Specifies the amount of output columns")))
        .subcommand(SubCommand::with_name("convert")
                        .about("Converts input data to a file (e.g. hexstream -> binary file")
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("binary")
                                 .possible_value("c-array")
                                 .possible_value("oct")
                                 .help("Specifies the output format (default: hex)")))
        .subcommand(SubCommand::with_name("generate")
                        .about("Generates a source file containing the specified file as array")
                        .arg(Arg::with_name("template")
                                 .short("t")
                                 .long("template")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("c")
                                 .possible_value("cpp")
                                 .possible_value("rs")
                                 .help("Specifies a template file which shall be used for \
                                        generation"))
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("hex")
                                 .possible_value("oct")
                                 .possible_value("dec")
                                 .possible_value("bin")
                                 .help("Specifies the output format (default: hex)"))
                        .arg(Arg::with_name("Separator")
                                 .long("separator")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Specifies the the separator between single values \
                                        (default: ',')")))
}
<commit_msg>Add decimal output format<commit_after>extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate xxd;

use clap::{Arg, ArgMatches, App, SubCommand};
use std::process::exit;
use std::fmt::Display;
use std::fs::File;
use std::io::Read;

mod errors {
    error_chain! {
        foreign_links {
            ParseError(::std::num::ParseIntError);
            Xxd(::xxd::errors::Error);
            Io(::std::io::Error);
        }
    }
}

use errors::*;

fn main() {
    let matches = create_arg_parser().get_matches();
    match run(&matches) {
        Ok(_) => exit(0),
        Err(e) => {
            report_error(&e);
            exit(1)
        }
    }
}

fn run(args: &ArgMatches) -> Result<()> {
    match args.subcommand_name() {
        Some("dump") => dump(args.subcommand_matches("dump")),
        Some("convert") => convert(args.subcommand_matches("convert")),
        Some("generate") => generate(args.subcommand_matches("generate")),
        _ => bail!(args.usage()),
    }
}

fn dump<'a>(args: Option<&ArgMatches<'a>>) -> Result<()> {
    let args = args.ok_or("No arguments available")?;
    let input_file = args.value_of("infile").unwrap_or("stdin");
    let seek = usize::from_str_radix(args.value_of("seek").unwrap_or("0"), 10)?;
    let length = args.value_of("length");
    let output_settings = create_output_settings(args)?;
    let reader = create_reader(input_file.to_string())?;
    match length {
        None => dump_iterator(Box::new(reader.bytes().skip(seek)), output_settings),
        Some(n) => {
            dump_iterator(Box::new(reader.bytes().skip(seek).take(usize::from_str_radix(n, 10)?)),
                          output_settings)
        }
    };
    Ok(())
}

fn dump_iterator<I: Iterator<Item = std::result::Result<u8, std::io::Error>>>(it: Box<I>, output_settings: ::xxd::dump::OutputSettings) -> Result<()>{
    let mut data: Vec<u8> = Vec::new();
    let mut address = 0;
    for byte in *it {
        data.push(byte?);
        if data.len() == output_settings.bytes_per_line() {
            dump_line(&data, output_settings.start_address(address));
            address += data.len();
            data.clear();
        }
    }
    if data.len() > 0 {
        dump_line(&data, output_settings.start_address(address));
        address += data.len();
        data.clear();
    }
    Ok(())
}

fn create_output_settings<'a>(args: &ArgMatches<'a>) -> Result<::xxd::dump::OutputSettings> {
    let columns = usize::from_str_radix(args.value_of("columns").unwrap_or("8"), 10)?;
    let format = args.value_of("format").unwrap_or("hex");
    let group_size = usize::from_str_radix(args.value_of("group-size").unwrap_or("1"), 10)?;
    Ok(::xxd::dump::OutputSettings::new()
           .format(::xxd::dump::OutputFormat::from(format.to_string()))
           .group_size(group_size)
           .columns(columns))
}

fn dump_line(data: &[u8], output_settings: ::xxd::dump::OutputSettings) {
    let output_line = ::xxd::dump::OutputLine::new(data).format(output_settings);
    println!("{}", output_line);
}

fn create_reader(path: String) -> Result<Box<std::io::Read>> {
    match path.as_ref() {
        "stdin" => Ok(Box::new(std::io::stdin())),
        _ => {
            let file_reader = std::fs::File::open(path)?;
            Ok(Box::new(file_reader))
        }
    }
}

fn convert<'a>(args: Option<&ArgMatches<'a>>) -> Result<()> {
    command_not_supported()
}

fn generate<'a>(args: Option<&ArgMatches<'a>>) -> Result<()> {
    command_not_supported()
}

fn command_not_supported() -> Result<()> {
    bail!("Command not supported yet!")
}

fn report_error<T: Display>(error: &T) {
    println!("xxd-rs: {}", error)
}

fn create_arg_parser<'a, 'b>() -> App<'a, 'b> {
    App::new("A rust based clone of the all time classic xxd tool")
        .version("0.1.0")
        .author("Nicola Coretti <nicola.coretti@gmail.com>")
        .about("make a hexdump or the reverse")
        .arg(Arg::with_name("infile")
                 .required(false)
                 .global(true)
                 .index(1)
                 .help("Input file which shall be used (default: stdin)"))
        .arg(Arg::with_name("outfile")
                 .required(false)
                 .global(true)
                 .index(2)
                 .help("File to which the output will be written (default: stdout)"))
        .arg(Arg::with_name("seek")
                 .short("s")
                 .long("seek")
                 .required(false)
                 .takes_value(true)
                 .global(true)
                 .help("Offset in the file where to start reading"))
        .arg(Arg::with_name("length")
                 .short("l")
                 .long("length")
                 .required(false)
                 .takes_value(true)
                 .global(true)
                 .help("Amount of bytes which shall be read"))
        .subcommand(SubCommand::with_name("dump")
                        .about("Dumps an input file in the appropriate output format")
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("hex")
                                 .possible_value("bin")
                                 .possible_value("oct")
                                 .possible_value("dec")
                                 .help("Specifies the output format for the value (default: hex)"))
                        .arg(Arg::with_name("group-size")
                                 .short("g")
                                 .long("group-size")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Separate  the output of every <bytes> bytes (two hex characters or eight bit-digits each) by a whitespace."))
                        .arg(Arg::with_name("columns")
                                 .short("c")
                                 .long("columns")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Specifies the amount of output columns")))
        .subcommand(SubCommand::with_name("convert")
                        .about("Converts input data to a file (e.g. hexstream -> binary file")
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("binary")
                                 .possible_value("c-array")
                                 .possible_value("oct")
                                 .help("Specifies the output format (default: hex)")))
        .subcommand(SubCommand::with_name("generate")
                        .about("Generates a source file containing the specified file as array")
                        .arg(Arg::with_name("template")
                                 .short("t")
                                 .long("template")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("c")
                                 .possible_value("cpp")
                                 .possible_value("rs")
                                 .help("Specifies a template file which shall be used for \
                                        generation"))
                        .arg(Arg::with_name("format")
                                 .short("f")
                                 .long("format")
                                 .required(false)
                                 .takes_value(true)
                                 .possible_value("hex")
                                 .possible_value("oct")
                                 .possible_value("dec")
                                 .possible_value("bin")
                                 .help("Specifies the output format (default: hex)"))
                        .arg(Arg::with_name("Separator")
                                 .long("separator")
                                 .required(false)
                                 .takes_value(true)
                                 .help("Specifies the the separator between single values \
                                        (default: ',')")))
}
<|endoftext|>


<commit_before>use libc;
use std::ptr;
use std::ffi::CStr;
use error::*;
use capstone_sys::*;
use capstone_sys;
use instruction::Instructions;

/// An instance of the capstone disassembler
pub struct Capstone {
    csh: capstone_sys::csh,
    _arch: Arch,
}

/// Architectures for the disassembler
#[derive(Clone, Debug)]
pub enum Arch {
    ARM,
    ARM64,
    MIPS,
    X86,
    PPC,
    SPARC,
    SYSZ,
    XCORE,
    MAX,
    /// used for `cs_support()`
    ALL,
}

impl Arch {
    pub fn to_cs_arch(&self) -> cs_arch {
        use Arch::*;
        match *self {
            ARM => CS_ARCH_ARM,
            ARM64 => CS_ARCH_ARM64,
            MIPS => CS_ARCH_MIPS,
            X86 => CS_ARCH_X86,
            PPC => CS_ARCH_PPC,
            SPARC => CS_ARCH_SPARC,
            SYSZ => CS_ARCH_SYSZ,
            XCORE => CS_ARCH_XCORE,
            MAX => CS_ARCH_MAX,
            ALL => CS_ARCH_ALL,
        }
    }
}

/// Disassembler modes
#[derive(Debug, Clone)]
pub enum Mode {
    /// little-endian mode (default mode)
    LittleEndian,
    /// 32-bit ARM
    Arm32,
    /// 16-bit mode (X86)
    Mode16,
    /// 32-bit mode (X86)
    Mode32,
    /// 64-bit mode (X86, PPC)
    Mode64,
    /// ARM's Thumb mode, including Thumb-2
    Thumb,
    /// ARM's Cortex-M series
    MClass,
    /// ARMv8 A32 encodings for ARM
    V8,
    /// MicroMips mode (MIPS)
    Micro,
    /// Mips III ISA
    Mips3,
    /// Mips32r6 ISA
    Mips32R6,
    /// General Purpose Registers are 64-bit wide (MIPS)
    MipsGP64,
    /// SparcV9 mode (Sparc)
    V9,
    /// big-endian mode
    BigEndian,
    /// Mips32 ISA (Mips)
    Mips32,
    /// Mips64 ISA (Mips)
    Mips64,
}

impl Mode {
    pub fn to_cs_mode(&self) -> capstone_sys::cs_mode {
        use Mode::*;
        match *self {
            LittleEndian => CS_MODE_LITTLE_ENDIAN,
            Arm32 => CS_MODE_ARM,
            Mode16 => CS_MODE_16,
            Mode32 => CS_MODE_32,
            Mode64 => CS_MODE_64,
            Thumb => CS_MODE_THUMB,
            MClass => CS_MODE_MCLASS,
            V8 => CS_MODE_V8,
            Micro => CS_MODE_MICRO,
            Mips3 => CS_MODE_MIPS3,
            Mips32R6 => CS_MODE_MIPS32R6,
            MipsGP64 => CS_MODE_MIPSGP64,
            V9 => CS_MODE_V9,
            BigEndian => CS_MODE_BIG_ENDIAN,
            Mips32 => CS_MODE_MIPS32,
            Mips64 => CS_MODE_MIPS64,
        }
    }
}

impl Capstone {
    /// Create a new instance of the decompiler. Defaults to 64-bit little-endian mode.
    ///
    /// ```
    /// use capstone::{self, Capstone};
    /// let cs = Capstone::new(capstone::Arch::X86);
    /// assert!(cs.is_ok());
    /// ```
    pub fn new(arch: Arch) -> CsResult<Capstone> {
        let mut handle: capstone_sys::csh = 0;
        let csarch = arch.to_cs_arch();
        let csmode = CS_MODE_LITTLE_ENDIAN;
        let err = unsafe { cs_open(csarch, csmode, &mut handle) };
        // this can be put into a macro, cs_try, but i guess who cares
        if CS_ERR_OK == err {
            Ok(Capstone { csh: handle, _arch: arch })
        } else {
            Err(Err::from(err))
        }
    }

    #[inline]
    fn set_option(&self, opt_type: cs_opt_type, value: libc::size_t) -> CsResult<()> {
        let err = unsafe {
            cs_option(self.csh, opt_type, value)
        };
        if CS_ERR_OK == err {
            Ok(())
        } else {
            Err(Err::from(err))
        }
    }

    /// Set the disassembly engine to use detail mode
    pub fn detail(&self) -> CsResult<()> {
        self.set_option(capstone_sys::CS_OPT_DETAIL, capstone_sys::CS_OPT_ON)
    }

    /// Sets the engine's disassembly mode.
    /// Be careful, various combinations of modes aren't supported
    /// See the capstone-sys documentation for more information.
    pub fn mode(&mut self, modes: &[Mode]) -> CsResult<()> {
        let mut value = 0;
        for mode in modes {
            value |= mode.to_cs_mode();
        }
        self.set_option(CS_OPT_MODE, value as capstone_sys::cs_opt_value)
    }

    /// Set the X86 assembly to AT&T style (has no effect on other platforms)
    pub fn att(&self) {
        self.set_option(capstone_sys::CS_OPT_SYNTAX, capstone_sys::CS_OPT_SYNTAX_ATT).unwrap()
    }

    /// Set the X86 assembly to Intel style (default)
    pub fn intel(&self) {
        self.set_option(capstone_sys::CS_OPT_SYNTAX, capstone_sys::CS_OPT_SYNTAX_INTEL).unwrap()
    }

    /// Disassemble a &[u8] `buffer` full of instructions
    ///
    /// Disassembles all instructions in `code`. If you want to disassemble less, then pass a smaller slice :]
    pub fn disasm(&self, buffer: &[u8], addr: u64) -> CsResult<Instructions> {
        let mut ptr: *mut capstone_sys::cs_insn = ptr::null_mut();
        let insn_count = unsafe {
            cs_disasm(self.csh,
                      buffer.as_ptr(),
                      buffer.len() as libc::size_t,
                      addr,
                      0 as libc::size_t,
                      &mut ptr)
        };
        if insn_count == 0 {
            println!("count: {}", insn_count);
            let err = unsafe { cs_errno(self.csh) };
            println!("err: {}", err);
            return Err(Err::from(err))
        }

        Ok(unsafe { Instructions::from_raw_parts(ptr, insn_count as isize) })
    }

    /// Convert a reg_id to a String naming the register
    pub fn reg_name(&self, reg_id: u64) -> Option<String> {
        let reg_name = unsafe {
            let _reg_name = cs_reg_name(self.csh, reg_id as libc::c_uint);
            if _reg_name == ptr::null() {
                return None
            }

            CStr::from_ptr(_reg_name).to_string_lossy().into_owned()
        };

        Some(reg_name)
    }

    /// Convert an instruction_id to a String naming the instruction
    pub fn insn_name(&self, insn_id: u64) -> Option<String> {
        let insn_name = unsafe {
            let _insn_name = cs_insn_name(self.csh, insn_id as libc::c_uint);
            if _insn_name == ptr::null() {
                return None
            }
            CStr::from_ptr(_insn_name).to_string_lossy().into_owned()
        };

        Some(insn_name)
    }
}

impl Drop for Capstone {
    fn drop(&mut self) {
        unsafe { cs_close(&mut self.csh) };
    }
}
<commit_msg>capstone: remove prints add major bug TODO<commit_after>use libc;
use std::ptr;
use std::ffi::CStr;
use error::*;
use capstone_sys::*;
use capstone_sys;
use instruction::Instructions;

/// An instance of the capstone disassembler
pub struct Capstone {
    csh: capstone_sys::csh,
    _arch: Arch,
}

/// Architectures for the disassembler
#[derive(Clone, Debug)]
pub enum Arch {
    ARM,
    ARM64,
    MIPS,
    X86,
    PPC,
    SPARC,
    SYSZ,
    XCORE,
    MAX,
    /// used for `cs_support()`
    ALL,
}

impl Arch {
    pub fn to_cs_arch(&self) -> cs_arch {
        use Arch::*;
        match *self {
            ARM => CS_ARCH_ARM,
            ARM64 => CS_ARCH_ARM64,
            MIPS => CS_ARCH_MIPS,
            X86 => CS_ARCH_X86,
            PPC => CS_ARCH_PPC,
            SPARC => CS_ARCH_SPARC,
            SYSZ => CS_ARCH_SYSZ,
            XCORE => CS_ARCH_XCORE,
            MAX => CS_ARCH_MAX,
            ALL => CS_ARCH_ALL,
        }
    }
}

/// Disassembler modes
#[derive(Debug, Clone)]
pub enum Mode {
    /// little-endian mode (default mode)
    LittleEndian,
    /// 32-bit ARM
    Arm32,
    /// 16-bit mode (X86)
    Mode16,
    /// 32-bit mode (X86)
    Mode32,
    /// 64-bit mode (X86, PPC)
    Mode64,
    /// ARM's Thumb mode, including Thumb-2
    Thumb,
    /// ARM's Cortex-M series
    MClass,
    /// ARMv8 A32 encodings for ARM
    V8,
    /// MicroMips mode (MIPS)
    Micro,
    /// Mips III ISA
    Mips3,
    /// Mips32r6 ISA
    Mips32R6,
    /// General Purpose Registers are 64-bit wide (MIPS)
    MipsGP64,
    /// SparcV9 mode (Sparc)
    V9,
    /// big-endian mode
    BigEndian,
    /// Mips32 ISA (Mips)
    Mips32,
    /// Mips64 ISA (Mips)
    Mips64,
}

impl Mode {
    pub fn to_cs_mode(&self) -> capstone_sys::cs_mode {
        use Mode::*;
        match *self {
            LittleEndian => CS_MODE_LITTLE_ENDIAN,
            Arm32 => CS_MODE_ARM,
            Mode16 => CS_MODE_16,
            Mode32 => CS_MODE_32,
            Mode64 => CS_MODE_64,
            Thumb => CS_MODE_THUMB,
            MClass => CS_MODE_MCLASS,
            V8 => CS_MODE_V8,
            Micro => CS_MODE_MICRO,
            Mips3 => CS_MODE_MIPS3,
            Mips32R6 => CS_MODE_MIPS32R6,
            MipsGP64 => CS_MODE_MIPSGP64,
            V9 => CS_MODE_V9,
            BigEndian => CS_MODE_BIG_ENDIAN,
            Mips32 => CS_MODE_MIPS32,
            Mips64 => CS_MODE_MIPS64,
        }
    }
}

impl Capstone {
    /// Create a new instance of the decompiler. Defaults to 64-bit little-endian mode.
    ///
    /// ```
    /// use capstone::{self, Capstone};
    /// let cs = Capstone::new(capstone::Arch::X86);
    /// assert!(cs.is_ok());
    /// ```
    pub fn new(arch: Arch) -> CsResult<Capstone> {
        let mut handle: capstone_sys::csh = 0;
        let csarch = arch.to_cs_arch();
        let csmode = CS_MODE_LITTLE_ENDIAN;
        let err = unsafe { cs_open(csarch, csmode, &mut handle) };
        // this can be put into a macro, cs_try, but i guess who cares
        if CS_ERR_OK == err {
            Ok(Capstone { csh: handle, _arch: arch })
        } else {
            Err(Err::from(err))
        }
    }

    #[inline]
    fn set_option(&self, opt_type: cs_opt_type, value: libc::size_t) -> CsResult<()> {
        let err = unsafe {
            cs_option(self.csh, opt_type, value)
        };
        if CS_ERR_OK == err {
            Ok(())
        } else {
            Err(Err::from(err))
        }
    }

    /// Set the disassembly engine to use detail mode
    pub fn detail(&self) -> CsResult<()> {
        self.set_option(capstone_sys::CS_OPT_DETAIL, capstone_sys::CS_OPT_ON)
    }

    /// Sets the engine's disassembly mode.
    /// Be careful, various combinations of modes aren't supported
    /// See the capstone-sys documentation for more information.
    pub fn mode(&mut self, modes: &[Mode]) -> CsResult<()> {
        let mut value = 0;
        for mode in modes {
            value |= mode.to_cs_mode();
        }
        self.set_option(CS_OPT_MODE, value as capstone_sys::cs_opt_value)
    }

    /// Set the X86 assembly to AT&T style (has no effect on other platforms)
    pub fn att(&self) {
        self.set_option(capstone_sys::CS_OPT_SYNTAX, capstone_sys::CS_OPT_SYNTAX_ATT).unwrap()
    }

    /// Set the X86 assembly to Intel style (default)
    pub fn intel(&self) {
        self.set_option(capstone_sys::CS_OPT_SYNTAX, capstone_sys::CS_OPT_SYNTAX_INTEL).unwrap()
    }

    /// Disassemble a &[u8] `buffer` full of instructions
    ///
    /// Disassembles all instructions in `code`. If you want to disassemble less, then pass a smaller slice :]
    pub fn disasm(&self, buffer: &[u8], addr: u64) -> CsResult<Instructions> {
        let mut ptr: *mut capstone_sys::cs_insn = ptr::null_mut();
        let insn_count = unsafe {
            cs_disasm(self.csh,
                      buffer.as_ptr(),
                      buffer.len() as libc::size_t,
                      addr,
                      0 as libc::size_t,
                      &mut ptr)
        };
        if insn_count == 0 {
            // TODO: this is a pretty major bug; if it disassembles 0 instructions, it can return
            // CS_ERR_OK (i.e., the buffer you passed has no instructions, that's fine),
            // so we should return an empty instructions list. but the current API
            // does not permit such a thing... need to refactor instructions, ideally it pre-parses
            // and generates a vector of instructions, but this will require careful memory management iiuc
            let err = unsafe { cs_errno(self.csh) };
            return Err(Err::from(err))
        }

        Ok(unsafe { Instructions::from_raw_parts(ptr, insn_count as isize) })
    }

    /// Convert a reg_id to a String naming the register
    pub fn reg_name(&self, reg_id: u64) -> Option<String> {
        let reg_name = unsafe {
            let _reg_name = cs_reg_name(self.csh, reg_id as libc::c_uint);
            if _reg_name == ptr::null() {
                return None
            }

            CStr::from_ptr(_reg_name).to_string_lossy().into_owned()
        };

        Some(reg_name)
    }

    /// Convert an instruction_id to a String naming the instruction
    pub fn insn_name(&self, insn_id: u64) -> Option<String> {
        let insn_name = unsafe {
            let _insn_name = cs_insn_name(self.csh, insn_id as libc::c_uint);
            if _insn_name == ptr::null() {
                return None
            }
            CStr::from_ptr(_insn_name).to_string_lossy().into_owned()
        };

        Some(insn_name)
    }
}

impl Drop for Capstone {
    fn drop(&mut self) {
        unsafe { cs_close(&mut self.csh) };
    }
}
<|endoftext|>