<commit_before>extern crate gluon_base;
extern crate itertools;
extern crate walkdir;

use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;

use itertools::Itertools;

use walkdir::WalkDir;

use gluon_base::filename_to_module;

#[cfg(feature = "test")]
mod gen_skeptic {
    extern crate little_skeptic as skeptic;
    extern crate walkdir;

    use std::env;
    use std::fs::{self, File};
    use std::io::prelude::*;
    use std::path::{Path, PathBuf};

    /// skeptic templates look for `rust` after the opening code fences so writing
    /// ```f#,rust
    /// ```
    /// gives f# syntax highlight while still running the tests through the template
    const TEMPLATE: &'static str = r##"
```rust,skeptic-template

use gluon::vm::api::{Hole, OpaqueValue};
use gluon::{VmBuilder, Compiler, Thread};

let _ = ::env_logger::try_init();
let text = r#"{{test}}"#;
let manifest_path = ::std::env::var("CARGO_MANIFEST_DIR").unwrap();
let vm = VmBuilder::new()
    .import_paths(Some(vec![".".into(), manifest_path.into()]))
    .build();
match Compiler::new().run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "example", text) {
    Ok(_value) => (),
    Err(err) => {
        panic!("{}", err);
    }
}
return;
```

"##;

    fn generate_skeptic_tests(file: &Path) -> String {
        println!("cargo:rerun-if-changed={}", file.display());

        // Preprocess the readme to inject the skeptic template needed to to run the examples
        let out_file_name = Path::new(&env::var("OUT_DIR").unwrap()).join(file);

        if let Some(parent_dir) = out_file_name.parent() {
            fs::create_dir_all(parent_dir).unwrap();
        }

        let mut contents = TEMPLATE.as_bytes().into();
        File::open(file)
            .and_then(|mut raw_file| raw_file.read_to_end(&mut contents))
            .unwrap();
        File::create(&out_file_name)
            .and_then(|mut out_file| out_file.write_all(&contents))
            .unwrap();
        out_file_name.to_str().expect("UTF-8 string").into()
    }

    pub fn generate() {
        let test_locations: Vec<_> = self::walkdir::WalkDir::new("book/src")
            .into_iter()
            .filter_map(|e| {
                let e = e.unwrap();
                if e.path().extension().and_then(|p| p.to_str()) == Some("md") {
                    Some(e.path().to_owned())
                } else {
                    None
                }
            })
            .chain(Some(PathBuf::from("README.md")))
            .chain(Some(PathBuf::from("tests/skeptic-template.md")))
            .map(|p| generate_skeptic_tests(&p))
            .collect();

        assert!(
            test_locations.len() > 10,
            "Search for skeptic tests appear to have missed some files"
        );

        let str_vec: Vec<_> = test_locations.iter().map(|s| &s[..]).collect();
        skeptic::generate_doc_tests(&str_vec);
    }
}

#[cfg(not(feature = "test"))]
mod gen_skeptic {
    pub fn generate() {
        // If we dont run skeptic we do not need to rebuild anything unless the script itself is
        // changed
        println!("cargo:rerun-if-changed=build.rs");
    }
}

/// Safety check to make sure that all .rs files in `tests/` will run
fn check_test_declarations_in_cargo_file() {
    use std::collections::HashSet;
    use std::ffi::OsStr;
    use std::fs::{read_dir, File};
    use std::io::{BufRead, BufReader};

    let cargo_file = BufReader::new(File::open("Cargo.toml").unwrap());

    let tests_in_cargo_file: HashSet<_> = cargo_file
        .lines()
        .map(|line| line.unwrap())
        .filter(|line| line.starts_with("name = \""))
        .map(|line| line.split('"').nth(1).unwrap().to_string())
        .collect();

    for entry in read_dir("tests").unwrap() {
        let entry = entry.unwrap();
        let path = entry.path();
        if path.extension() == Some(OsStr::new("rs")) {
            let filename = path
                .file_stem()
                .expect("file_stem")
                .to_str()
                .expect("utf-8 file_stem");
            if !tests_in_cargo_file.contains(filename) {
                panic!(
                    "Test `{}` must be declared in Cargo.toml, otherwise it does not run",
                    filename
                );
            }
        }
    }
}

fn example_24_up_to_date() {
    let mut readme = String::new();
    {
        let mut readme_file = File::open("README.md").unwrap();
        readme_file.read_to_string(&mut readme).unwrap();

        let offset = readme.find("[24 game]").expect("24 game tag");
        let block_start = readme[offset..].find("```").expect("block start") + offset;
        let inside_block_start =
            readme[block_start..].find('\n').expect("inner block start") + block_start + 1;
        let block_end =
            readme[(block_start + 3)..].find("```").expect("block end") + block_start + 3;

        let example_24_in_readme = readme
            .drain(inside_block_start..block_end)
            .collect::<String>();

        {
            let mut file = File::open("examples/24.glu").unwrap();
            let mut example = String::new();
            file.read_to_string(&mut example).unwrap();
            // No need to write anything if it is up to date
            if example == example_24_in_readme {
                return;
            }
            readme.insert_str(inside_block_start, &example);
        }
    }
    let mut readme_file = File::create("README.md").unwrap();
    readme_file.write_all(readme.as_bytes()).unwrap();
}

fn generate_std_include() {
    let tuples = WalkDir::new("std")
        .into_iter()
        .filter_map(|entry| entry.ok())
        .filter(|entry| {
            entry.file_type().is_file()
                && entry.path().extension() == Some(::std::ffi::OsStr::new("glu"))
        })
        .map(|entry| {
            let module_name = filename_to_module(entry.path().to_str().expect("Invalid path"));
            format!(
                r#"("{}", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/{}"))),"#,
                module_name,
                entry.path().display().to_string().replace('\\', "/")
            )
        })
        .format("\n");

    let out_file_name = Path::new(&env::var("OUT_DIR").unwrap()).join("std_modules.rs");
    let mut file = File::create(&out_file_name).unwrap();

    writeln!(
        file,
        r#"
#[cfg(feature = "test")]
static STD_LIBS: &[(&str, &str)] = &[];"#
    )
    .unwrap();
    write!(
        file,
        r#"
#[cfg(not(feature = "test"))]
static STD_LIBS: &[(&str, &str)] = "#
    )
    .unwrap();
    writeln!(file, "&[{}];", tuples).unwrap();
}

fn main() {
    gen_skeptic::generate();

    check_test_declarations_in_cargo_file();

    example_24_up_to_date();
    println!("cargo:rerun-if-changed=examples/24.glu");

    generate_std_include();
    println!("cargo:rerun-if-changed=std/");
}
<commit_msg>chore: Don't re-run the build script on std/ changes during tests<commit_after>extern crate gluon_base;
extern crate itertools;
extern crate walkdir;

use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;

use itertools::Itertools;

use walkdir::WalkDir;

use gluon_base::filename_to_module;

#[cfg(feature = "test")]
mod gen_skeptic {
    extern crate little_skeptic as skeptic;
    extern crate walkdir;

    use std::env;
    use std::fs::{self, File};
    use std::io::prelude::*;
    use std::path::{Path, PathBuf};

    /// skeptic templates look for `rust` after the opening code fences so writing
    /// ```f#,rust
    /// ```
    /// gives f# syntax highlight while still running the tests through the template
    const TEMPLATE: &'static str = r##"
```rust,skeptic-template

use gluon::vm::api::{Hole, OpaqueValue};
use gluon::{VmBuilder, Compiler, Thread};

let _ = ::env_logger::try_init();
let text = r#"{{test}}"#;
let manifest_path = ::std::env::var("CARGO_MANIFEST_DIR").unwrap();
let vm = VmBuilder::new()
    .import_paths(Some(vec![".".into(), manifest_path.into()]))
    .build();
match Compiler::new().run_expr::<OpaqueValue<&Thread, Hole>>(&vm, "example", text) {
    Ok(_value) => (),
    Err(err) => {
        panic!("{}", err);
    }
}
return;
```

"##;

    fn generate_skeptic_tests(file: &Path) -> String {
        println!("cargo:rerun-if-changed={}", file.display());

        // Preprocess the readme to inject the skeptic template needed to to run the examples
        let out_file_name = Path::new(&env::var("OUT_DIR").unwrap()).join(file);

        if let Some(parent_dir) = out_file_name.parent() {
            fs::create_dir_all(parent_dir).unwrap();
        }

        let mut contents = TEMPLATE.as_bytes().into();
        File::open(file)
            .and_then(|mut raw_file| raw_file.read_to_end(&mut contents))
            .unwrap();
        File::create(&out_file_name)
            .and_then(|mut out_file| out_file.write_all(&contents))
            .unwrap();
        out_file_name.to_str().expect("UTF-8 string").into()
    }

    pub fn generate() {
        let test_locations: Vec<_> = self::walkdir::WalkDir::new("book/src")
            .into_iter()
            .filter_map(|e| {
                let e = e.unwrap();
                if e.path().extension().and_then(|p| p.to_str()) == Some("md") {
                    Some(e.path().to_owned())
                } else {
                    None
                }
            })
            .chain(Some(PathBuf::from("README.md")))
            .chain(Some(PathBuf::from("tests/skeptic-template.md")))
            .map(|p| generate_skeptic_tests(&p))
            .collect();

        assert!(
            test_locations.len() > 10,
            "Search for skeptic tests appear to have missed some files"
        );

        let str_vec: Vec<_> = test_locations.iter().map(|s| &s[..]).collect();
        skeptic::generate_doc_tests(&str_vec);
    }
}

#[cfg(not(feature = "test"))]
mod gen_skeptic {
    pub fn generate() {
        // If we dont run skeptic we do not need to rebuild anything unless the script itself is
        // changed
        println!("cargo:rerun-if-changed=build.rs");
    }
}

/// Safety check to make sure that all .rs files in `tests/` will run
fn check_test_declarations_in_cargo_file() {
    use std::collections::HashSet;
    use std::ffi::OsStr;
    use std::fs::{read_dir, File};
    use std::io::{BufRead, BufReader};

    let cargo_file = BufReader::new(File::open("Cargo.toml").unwrap());

    let tests_in_cargo_file: HashSet<_> = cargo_file
        .lines()
        .map(|line| line.unwrap())
        .filter(|line| line.starts_with("name = \""))
        .map(|line| line.split('"').nth(1).unwrap().to_string())
        .collect();

    for entry in read_dir("tests").unwrap() {
        let entry = entry.unwrap();
        let path = entry.path();
        if path.extension() == Some(OsStr::new("rs")) {
            let filename = path
                .file_stem()
                .expect("file_stem")
                .to_str()
                .expect("utf-8 file_stem");
            if !tests_in_cargo_file.contains(filename) {
                panic!(
                    "Test `{}` must be declared in Cargo.toml, otherwise it does not run",
                    filename
                );
            }
        }
    }
}

fn example_24_up_to_date() {
    let mut readme = String::new();
    {
        let mut readme_file = File::open("README.md").unwrap();
        readme_file.read_to_string(&mut readme).unwrap();

        let offset = readme.find("[24 game]").expect("24 game tag");
        let block_start = readme[offset..].find("```").expect("block start") + offset;
        let inside_block_start =
            readme[block_start..].find('\n').expect("inner block start") + block_start + 1;
        let block_end =
            readme[(block_start + 3)..].find("```").expect("block end") + block_start + 3;

        let example_24_in_readme = readme
            .drain(inside_block_start..block_end)
            .collect::<String>();

        {
            let mut file = File::open("examples/24.glu").unwrap();
            let mut example = String::new();
            file.read_to_string(&mut example).unwrap();
            // No need to write anything if it is up to date
            if example == example_24_in_readme {
                return;
            }
            readme.insert_str(inside_block_start, &example);
        }
    }
    let mut readme_file = File::create("README.md").unwrap();
    readme_file.write_all(readme.as_bytes()).unwrap();
}

fn generate_std_include() {
    let tuples = WalkDir::new("std")
        .into_iter()
        .filter_map(|entry| entry.ok())
        .filter(|entry| {
            entry.file_type().is_file()
                && entry.path().extension() == Some(::std::ffi::OsStr::new("glu"))
        })
        .map(|entry| {
            let module_name = filename_to_module(entry.path().to_str().expect("Invalid path"));
            format!(
                r#"("{}", include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/{}"))),"#,
                module_name,
                entry.path().display().to_string().replace('\\', "/")
            )
        })
        .format("\n");

    let out_file_name = Path::new(&env::var("OUT_DIR").unwrap()).join("std_modules.rs");
    let mut file = File::create(&out_file_name).unwrap();

    writeln!(
        file,
        r#"
#[cfg(feature = "test")]
static STD_LIBS: &[(&str, &str)] = &[];"#
    )
    .unwrap();
    write!(
        file,
        r#"
#[cfg(not(feature = "test"))]
static STD_LIBS: &[(&str, &str)] = "#
    )
    .unwrap();
    writeln!(file, "&[{}];", tuples).unwrap();
}

fn main() {
    gen_skeptic::generate();

    check_test_declarations_in_cargo_file();

    example_24_up_to_date();
    println!("cargo:rerun-if-changed=examples/24.glu");

    generate_std_include();
    if !env::var("CARGO_FEATURE_TEST").is_ok() {
        println!("cargo:rerun-if-changed=std/");
    }
}
<|endoftext|>


<commit_before>extern crate bindgen;
extern crate gcc;

use std::path::Path;
use std::process::{Command, ExitStatus};
use std::env;

/// Link the ISPC code into a static library on Unix using `ar`
#[cfg(unix)]
fn link_ispc(lib_name: &str, objs: &Vec<String>) -> ExitStatus {
    // TODO: should push into a struct
    let out_dir = env::var("OUT_DIR").unwrap();
    let mut args = Vec::with_capacity(2 + objs.len());
    args.push(String::from("crus"));
    args.push(lib_name.to_string());
    for o in objs {
        args.push(o.clone());
    }
    Command::new("ar").args(&args[..])
        .current_dir(&Path::new(&out_dir))
        .status().unwrap()
}
/// Link the ISPC code into a static library on Windows using `lib.exe`
#[cfg(windows)]
fn link_ispc(lib_name: &str, objs: &Vec<String>) -> ExitStatus {
    let out_dir = env::var("OUT_DIR").unwrap();
    let mut lib_cmd = gcc::windows_registry::find_tool(lib_name, "lib.exe")
        .expect("Failed to find link.exe for MSVC toolchain, aborting");
    let mut args = Vec::with_capacity(1 + objs.len());
    args.push(String::from("/OUT:").push_str(lib_name));
    for o in objs {
        args.push(o);
    }
    lib_cmd.args(&args[..])
        .current_dir(&Path::new(&out_dir))
        .status().unwrap()
}

fn main() {
    println!("cargo:rerun-if-changed=src/say_hello.ispc");

    let out_dir = env::var("OUT_DIR").unwrap();
    let debug = env::var("DEBUG").unwrap();
    let opt_level = env::var("OPT_LEVEL").unwrap();

    let mut ispc_args = vec!["src/say_hello.ispc", "--pic"];
    if debug == "true" {
        ispc_args.push("-g");
    }
    if opt_level == "0" {
        ispc_args.push("-O0");
    } else if opt_level == "1" {
        ispc_args.push("-O1");
    } else if opt_level == "2" {
        ispc_args.push("-O2");
    } else if opt_level == "3" {
        ispc_args.push("-O3");
    }

    // Invoke ISPC to compile our code
    let ispc_status = Command::new("ispc").args(&ispc_args[..])
        .args(&["-o", &format!("{}/say_hello.o", out_dir)])
        .args(&["-h", &format!("{}/say_hello.h", out_dir)])
        .status().unwrap();
    if !ispc_status.success() {
        panic!("ISPC compilation failed");
    }

    // Place our code into a static library we can link against
    if !link_ispc("libsay_hello.a", &vec![String::from("say_hello.o")]).success() {
        panic!("Linking ISPC code into archive failed");
    }
    println!("cargo:rustc-flags=-L native={}", out_dir);

    // Generate Rust bindings for the header
    let mut bindings = bindgen::builder();
    bindings.forbid_unknown_types()
        .header(format!("{}/say_hello.h", out_dir))
        .link_static("say_hello");
    match bindings.generate() {
        Ok(b) => b.write_to_file(Path::new(&format!("{}/say_hello.rs", out_dir))).unwrap(),
        Err(_) => panic!("Binding generation failed!"),
    };
}

<commit_msg>Cleaning up into some functions before pushing into a module<commit_after>extern crate bindgen;
extern crate gcc;

use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus};
use std::env;

/// Use the ISPC compiler to compile all ISPC files into object files on Linux
/// Returns true if all ISPC files compiled, or false immediately after one fails to compile
/// Object files will be written to $OUT_DIR/<file_name>.o and headers to
/// $OUT_DIR/<file_name>.h
fn compile_ispc(srcs: &Vec<PathBuf>) -> bool {
    // TODO: again should push into a struct that keeps this state
    let out_dir = env::var("OUT_DIR").unwrap();
    let debug = env::var("DEBUG").unwrap();
    let opt_level = env::var("OPT_LEVEL").unwrap();

    let mut ispc_args = Vec::new();
    if debug == "true" {
        ispc_args.push("-g");
    }
    if opt_level == "0" {
        ispc_args.push("-O0");
    } else if opt_level == "1" {
        ispc_args.push("-O1");
    } else if opt_level == "2" {
        ispc_args.push("-O2");
    } else if opt_level == "3" {
        ispc_args.push("-O3");
    }
    // If we're on Unix we need position independent code
    if cfg!(unix) {
        ispc_args.push("--pic");
    }

    for s in srcs {
        let fname = s.file_name().expect("ISPC source files must be files")
            .to_str().expect("ISPC source file names must be valid UTF-8");

        let status = Command::new("ispc").args(&ispc_args[..])
            .arg(s)
            .args(&["-o", &format!("{}/{}.o", out_dir, fname)])
            .args(&["-h", &format!("{}/{}.h", out_dir, fname)])
            .status().unwrap();
        if !status.success() {
            return false;
        }
    }
    true
}
/// Link the ISPC code into a static library on Unix using `ar`
#[cfg(unix)]
fn link_ispc(lib_name: &str, objs: &Vec<String>) -> ExitStatus {
    // TODO: should push into a struct
    let out_dir = env::var("OUT_DIR").unwrap();
    let mut args = Vec::with_capacity(2 + objs.len());
    args.push(String::from("crus"));
    args.push(String::from("lib") + lib_name + ".a");
    for o in objs {
        args.push(o.clone());
    }
    Command::new("ar").args(&args[..])
        .current_dir(&Path::new(&out_dir))
        .status().unwrap()
}
/// Link the ISPC code into a static library on Windows using `lib.exe`
#[cfg(windows)]
fn link_ispc(lib_name: &str, objs: &Vec<String>) -> ExitStatus {
    let out_dir = env::var("OUT_DIR").unwrap();
    let target = env::var("TARGET").unwrap();
    let lib_cmd = gcc::windows_registry::find_tool(&target[..], "lib.exe")
        .expect("Failed to find lib.exe for MSVC toolchain, aborting");
    let mut args = Vec::with_capacity(2 + objs.len());
    println!("Linker command = {:?}", lib_cmd.path());
    args.push(String::from("/OUT:") + lib_name + ".lib");
    args.push(String::from("/MACHINE:x64"));
    for o in objs {
        args.push(o.clone());
    }
    lib_cmd.to_command().args(&args[..])
        .current_dir(&Path::new(&out_dir))
        .status().unwrap()
}
// Generate Rust bindings for each ISPC file we compiled into the library
fn generate_bindings(lib_name: &str, srcs: &Vec<PathBuf>) -> bool {
    let out_dir = env::var("OUT_DIR").unwrap();
    for s in srcs {
        let fname = s.file_name().expect("ISPC source files must be files")
            .to_str().expect("ISPC source file names must be valid UTF-8");
        let mut bindings = bindgen::builder();
        bindings.forbid_unknown_types()
            .header(format!("{}/{}.h", out_dir, fname))
            .link_static(lib_name);
        match bindings.generate() {
            Ok(b) => b.write_to_file(Path::new(&format!("{}/{}.rs", out_dir, fname))).unwrap(),
            Err(_) => return false,
        };
    }
    true
}

fn main() {
    println!("cargo:rerun-if-changed=src/say_hello.ispc");

    let out_dir = env::var("OUT_DIR").unwrap();

    // Invoke ISPC to compile our code
    let ispc_files = vec![PathBuf::from("src/say_hello.ispc")];
    let ispc_status = compile_ispc(&ispc_files);
    if !ispc_status {
        panic!("ISPC compilation failed");
    }

    // Place our code into a static library we can link against
    if !link_ispc("say_hello", &vec![String::from("say_hello.o")]).success() {
        panic!("Linking ISPC code into archive failed");
    }
    println!("cargo:rustc-flags=-L native={}", out_dir);

    // Generate Rust bindings for the header
    generate_bindings("say_hello", &ispc_files);
}

<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

fn main() {
    // Pass our linker script to the top crate
    let mut ld = String::new();

    let interrupts = env::var_os("CARGO_FEATURE_INTERRUPTS").is_some();
    let static_ram = env::var_os("CARGO_FEATURE_STATIC_RAM").is_some();

    ld.push_str("
MEMORY
{
  CCRAM : ORIGIN = 0x10000000, LENGTH = 8K
  FLASH : ORIGIN = 0x08000000, LENGTH = 256K
  RAM : ORIGIN = 0x20000000, LENGTH = 40K
}

ENTRY(_reset)

SECTIONS
{
  .text ORIGIN(FLASH) :
  {
    /* Vector table */
    LONG(ORIGIN(RAM) + LENGTH(RAM));
    LONG(_reset + 1);
    KEEP(*(.rodata._EXCEPTIONS));
    _eexceptions = .;");

    if interrupts {
        ld.push_str("
    KEEP(*(.rodata._INTERRUPTS));
    _einterrupts = .;");
    }

    ld.push_str("
    /* Entry point: reset handler */
    _reset = .;
    *(.text._reset);

    *(.text.*);
    *(.rodata.*);
  } > FLASH");

    if static_ram {
        ld.push_str("
  .bss : ALIGN(4)
  {
    _sbss = .;
    *(.bss.*);
    _ebss = ALIGN(4);
  } > RAM

  .data : ALIGN(4)
  {
    _sdata = .;
    *(.data.*);
    _edata = ALIGN(4);
  } > RAM AT > FLASH

  _sidata = LOADADDR(.data);");
    }

    ld.push_str("
  /DISCARD/ :
  {
    *(.ARM.exidx.*)");

    if !static_ram {
        ld.push_str("
    *(.bss.*)
    *(.data.*)");
    }

    ld.push_str("
  }
}

/* HACK to make these symbols overrideable by _dependencies_ (they were
   already overridable by the top crate), we declare them as undefined
   (EXTERN) here. */
EXTERN(__aeabi_memclr4);
EXTERN(_default_exception_handler);
EXTERN(_init);

/* Exceptions */
PROVIDE(_nmi = _default_exception_handler);
PROVIDE(_hard_fault = _default_exception_handler);
PROVIDE(_memmanage_fault = _default_exception_handler);
PROVIDE(_bus_fault = _default_exception_handler);
PROVIDE(_usage_fault = _default_exception_handler);
PROVIDE(_svcall = _default_exception_handler);
PROVIDE(_pendsv = _default_exception_handler);
PROVIDE(_systick = _default_exception_handler);");

    if interrupts {

        ld.push_str("
/* Interrupts */
PROVIDE(_wwdg = _default_exception_handler);
PROVIDE(_pvd = _default_exception_handler);
PROVIDE(_tamper_stamp = _default_exception_handler);
PROVIDE(_rtc_wkup = _default_exception_handler);
PROVIDE(_flash = _default_exception_handler);
PROVIDE(_rcc = _default_exception_handler);
PROVIDE(_exti0 = _default_exception_handler);
PROVIDE(_exti1 = _default_exception_handler);
PROVIDE(_exti2_ts = _default_exception_handler);
PROVIDE(_exti3 = _default_exception_handler);
PROVIDE(_exti4 = _default_exception_handler);
PROVIDE(_dma1_channel1 = _default_exception_handler);
PROVIDE(_dma1_channel2 = _default_exception_handler);
PROVIDE(_dma1_channel3 = _default_exception_handler);
PROVIDE(_dma1_channel4 = _default_exception_handler);
PROVIDE(_dma1_channel5 = _default_exception_handler);
PROVIDE(_dma1_channel6 = _default_exception_handler);
PROVIDE(_dma1_channel7 = _default_exception_handler);
PROVIDE(_adc1_2 = _default_exception_handler);
PROVIDE(_usb_hp_can_tx = _default_exception_handler);
PROVIDE(_usb_lp_can_rx0 = _default_exception_handler);
PROVIDE(_can_rx1 = _default_exception_handler);
PROVIDE(_can_sce = _default_exception_handler);
PROVIDE(_exti9_5 = _default_exception_handler);
PROVIDE(_tim1_brk_tim15 = _default_exception_handler);
PROVIDE(_tim1_up_tim16 = _default_exception_handler);
PROVIDE(_tim1_trg_com_tim17 = _default_exception_handler);
PROVIDE(_tim1_cc = _default_exception_handler);
PROVIDE(_tim2 = _default_exception_handler);
PROVIDE(_tim3 = _default_exception_handler);
PROVIDE(_tim4 = _default_exception_handler);
PROVIDE(_i2c1_ev = _default_exception_handler);
PROVIDE(_i2c1_er = _default_exception_handler);
PROVIDE(_i2c2_ev = _default_exception_handler);
PROVIDE(_i2c2_er = _default_exception_handler);
PROVIDE(_spi1 = _default_exception_handler);
PROVIDE(_spi2 = _default_exception_handler);
PROVIDE(_usart1 = _default_exception_handler);
PROVIDE(_usart2 = _default_exception_handler);
PROVIDE(_usart3 = _default_exception_handler);
PROVIDE(_exti15_10 = _default_exception_handler);
PROVIDE(_rtc_alarm = _default_exception_handler);
PROVIDE(_usb_wake_up = _default_exception_handler);
PROVIDE(_tim8_brk = _default_exception_handler);
PROVIDE(_tim8_up = _default_exception_handler);
PROVIDE(_tim8_trg_com = _default_exception_handler);
PROVIDE(_tim8_cc = _default_exception_handler);
PROVIDE(_adc3 = _default_exception_handler);
PROVIDE(_fmc = _default_exception_handler);
PROVIDE(_spi3 = _default_exception_handler);
PROVIDE(_uart4 = _default_exception_handler);
PROVIDE(_uart5 = _default_exception_handler);
PROVIDE(_tim6_dac = _default_exception_handler);
PROVIDE(_tim7 = _default_exception_handler);
PROVIDE(_dma2_channel1 = _default_exception_handler);
PROVIDE(_dma2_channel2 = _default_exception_handler);
PROVIDE(_dma2_channel3 = _default_exception_handler);
PROVIDE(_dma2_channel4 = _default_exception_handler);
PROVIDE(_dma2_channel5 = _default_exception_handler);
PROVIDE(_adc4 = _default_exception_handler);
PROVIDE(_comp1_2_3 = _default_exception_handler);
PROVIDE(_comp4_5_6 = _default_exception_handler);
PROVIDE(_comp7 = _default_exception_handler);
PROVIDE(_i2c3_ev = _default_exception_handler);
PROVIDE(_i2c3_er = _default_exception_handler);
PROVIDE(_usb_hp = _default_exception_handler);
PROVIDE(_usb_lp = _default_exception_handler);
PROVIDE(_usb_wake_up_rmp = _default_exception_handler);
PROVIDE(_tim20_brk = _default_exception_handler);
PROVIDE(_tim20_up = _default_exception_handler);
PROVIDE(_tim20_trg_com = _default_exception_handler);
PROVIDE(_tim20_cc = _default_exception_handler);
PROVIDE(_fpu = _default_exception_handler);
PROVIDE(_spi4 = _default_exception_handler);");
    }

    ld.push_str("
ASSERT(_eexceptions - ORIGIN(FLASH) == 0x40, \"exceptions \
                 not linked where expected\");");

    if interrupts {
        ld.push_str("
ASSERT(_einterrupts - ORIGIN(FLASH) == 0x194, \
                     \"interrupts not linked where expected\");");
    }

    let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    File::create(out.join("stm32f3discovery.ld"))
        .unwrap()
        .write_all(ld.as_bytes())
        .unwrap();

    println!("cargo:rustc-link-search={}", out.display());
}
<commit_msg>ld: discard the .note.gnu.build-id section<commit_after>use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

fn main() {
    // Pass our linker script to the top crate
    let mut ld = String::new();

    let interrupts = env::var_os("CARGO_FEATURE_INTERRUPTS").is_some();
    let static_ram = env::var_os("CARGO_FEATURE_STATIC_RAM").is_some();

    ld.push_str("
MEMORY
{
  CCRAM : ORIGIN = 0x10000000, LENGTH = 8K
  FLASH : ORIGIN = 0x08000000, LENGTH = 256K
  RAM : ORIGIN = 0x20000000, LENGTH = 40K
}

ENTRY(_reset)

SECTIONS
{
  .text ORIGIN(FLASH) :
  {
    /* Vector table */
    LONG(ORIGIN(RAM) + LENGTH(RAM));
    LONG(_reset + 1);
    KEEP(*(.rodata._EXCEPTIONS));
    _eexceptions = .;");

    if interrupts {
        ld.push_str("
    KEEP(*(.rodata._INTERRUPTS));
    _einterrupts = .;");
    }

    ld.push_str("
    /* Entry point: reset handler */
    _reset = .;
    *(.text._reset);

    *(.text.*);
    *(.rodata.*);
  } > FLASH");

    if static_ram {
        ld.push_str("
  .bss : ALIGN(4)
  {
    _sbss = .;
    *(.bss.*);
    _ebss = ALIGN(4);
  } > RAM

  .data : ALIGN(4)
  {
    _sdata = .;
    *(.data.*);
    _edata = ALIGN(4);
  } > RAM AT > FLASH

  _sidata = LOADADDR(.data);");
    }

    ld.push_str("
  /DISCARD/ :
  {
    *(.ARM.exidx.*)
    *(.note.gnu.build-id.*)");

    if !static_ram {
        ld.push_str("
    *(.bss.*)
    *(.data.*)");
    }

    ld.push_str("
  }
}

/* HACK to make these symbols overrideable by _dependencies_ (they were
   already overridable by the top crate), we declare them as undefined
   (EXTERN) here. */
EXTERN(__aeabi_memclr4);
EXTERN(_default_exception_handler);
EXTERN(_init);

/* Exceptions */
PROVIDE(_nmi = _default_exception_handler);
PROVIDE(_hard_fault = _default_exception_handler);
PROVIDE(_memmanage_fault = _default_exception_handler);
PROVIDE(_bus_fault = _default_exception_handler);
PROVIDE(_usage_fault = _default_exception_handler);
PROVIDE(_svcall = _default_exception_handler);
PROVIDE(_pendsv = _default_exception_handler);
PROVIDE(_systick = _default_exception_handler);");

    if interrupts {

        ld.push_str("
/* Interrupts */
PROVIDE(_wwdg = _default_exception_handler);
PROVIDE(_pvd = _default_exception_handler);
PROVIDE(_tamper_stamp = _default_exception_handler);
PROVIDE(_rtc_wkup = _default_exception_handler);
PROVIDE(_flash = _default_exception_handler);
PROVIDE(_rcc = _default_exception_handler);
PROVIDE(_exti0 = _default_exception_handler);
PROVIDE(_exti1 = _default_exception_handler);
PROVIDE(_exti2_ts = _default_exception_handler);
PROVIDE(_exti3 = _default_exception_handler);
PROVIDE(_exti4 = _default_exception_handler);
PROVIDE(_dma1_channel1 = _default_exception_handler);
PROVIDE(_dma1_channel2 = _default_exception_handler);
PROVIDE(_dma1_channel3 = _default_exception_handler);
PROVIDE(_dma1_channel4 = _default_exception_handler);
PROVIDE(_dma1_channel5 = _default_exception_handler);
PROVIDE(_dma1_channel6 = _default_exception_handler);
PROVIDE(_dma1_channel7 = _default_exception_handler);
PROVIDE(_adc1_2 = _default_exception_handler);
PROVIDE(_usb_hp_can_tx = _default_exception_handler);
PROVIDE(_usb_lp_can_rx0 = _default_exception_handler);
PROVIDE(_can_rx1 = _default_exception_handler);
PROVIDE(_can_sce = _default_exception_handler);
PROVIDE(_exti9_5 = _default_exception_handler);
PROVIDE(_tim1_brk_tim15 = _default_exception_handler);
PROVIDE(_tim1_up_tim16 = _default_exception_handler);
PROVIDE(_tim1_trg_com_tim17 = _default_exception_handler);
PROVIDE(_tim1_cc = _default_exception_handler);
PROVIDE(_tim2 = _default_exception_handler);
PROVIDE(_tim3 = _default_exception_handler);
PROVIDE(_tim4 = _default_exception_handler);
PROVIDE(_i2c1_ev = _default_exception_handler);
PROVIDE(_i2c1_er = _default_exception_handler);
PROVIDE(_i2c2_ev = _default_exception_handler);
PROVIDE(_i2c2_er = _default_exception_handler);
PROVIDE(_spi1 = _default_exception_handler);
PROVIDE(_spi2 = _default_exception_handler);
PROVIDE(_usart1 = _default_exception_handler);
PROVIDE(_usart2 = _default_exception_handler);
PROVIDE(_usart3 = _default_exception_handler);
PROVIDE(_exti15_10 = _default_exception_handler);
PROVIDE(_rtc_alarm = _default_exception_handler);
PROVIDE(_usb_wake_up = _default_exception_handler);
PROVIDE(_tim8_brk = _default_exception_handler);
PROVIDE(_tim8_up = _default_exception_handler);
PROVIDE(_tim8_trg_com = _default_exception_handler);
PROVIDE(_tim8_cc = _default_exception_handler);
PROVIDE(_adc3 = _default_exception_handler);
PROVIDE(_fmc = _default_exception_handler);
PROVIDE(_spi3 = _default_exception_handler);
PROVIDE(_uart4 = _default_exception_handler);
PROVIDE(_uart5 = _default_exception_handler);
PROVIDE(_tim6_dac = _default_exception_handler);
PROVIDE(_tim7 = _default_exception_handler);
PROVIDE(_dma2_channel1 = _default_exception_handler);
PROVIDE(_dma2_channel2 = _default_exception_handler);
PROVIDE(_dma2_channel3 = _default_exception_handler);
PROVIDE(_dma2_channel4 = _default_exception_handler);
PROVIDE(_dma2_channel5 = _default_exception_handler);
PROVIDE(_adc4 = _default_exception_handler);
PROVIDE(_comp1_2_3 = _default_exception_handler);
PROVIDE(_comp4_5_6 = _default_exception_handler);
PROVIDE(_comp7 = _default_exception_handler);
PROVIDE(_i2c3_ev = _default_exception_handler);
PROVIDE(_i2c3_er = _default_exception_handler);
PROVIDE(_usb_hp = _default_exception_handler);
PROVIDE(_usb_lp = _default_exception_handler);
PROVIDE(_usb_wake_up_rmp = _default_exception_handler);
PROVIDE(_tim20_brk = _default_exception_handler);
PROVIDE(_tim20_up = _default_exception_handler);
PROVIDE(_tim20_trg_com = _default_exception_handler);
PROVIDE(_tim20_cc = _default_exception_handler);
PROVIDE(_fpu = _default_exception_handler);
PROVIDE(_spi4 = _default_exception_handler);");
    }

    ld.push_str("
ASSERT(_eexceptions - ORIGIN(FLASH) == 0x40, \"exceptions \
                 not linked where expected\");");

    if interrupts {
        ld.push_str("
ASSERT(_einterrupts - ORIGIN(FLASH) == 0x194, \
                     \"interrupts not linked where expected\");");
    }

    let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    File::create(out.join("stm32f3discovery.ld"))
        .unwrap()
        .write_all(ld.as_bytes())
        .unwrap();

    println!("cargo:rustc-link-search={}", out.display());
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests;

use nom::IResult;
use parser::parse_lines;
use std::io::{Read, Write};
use tokens::*;

type AssembleResult = Result<(), String>;

pub fn assemble<R: Read, W: Write>(mut input: R, writer: &mut W) -> AssembleResult {
    let mut buf = Vec::<u8>::new();
    input.read_to_end(&mut buf);
    match parse_lines(&buf) {
        IResult::Error(_) => Err("An error occurred while parsing".to_string()),
        IResult::Incomplete(_) => {
            Err("An error occurred while parsing. Need more input.".to_string())
        }
        IResult::Done(_, opcodes) => {
            let mut res: AssembleResult = Ok(());
            for opcode in opcodes {
                let OpCode(mnemonic, am) = opcode;
                match mnemonic {
                    Mnemonic::Adc => res = adc(am, writer),
                    Mnemonic::And => res = and(am, writer),
                    Mnemonic::Asl => res = asl(am, writer),
                    Mnemonic::Bit => res = bit(am, writer),
                    _ => unimplemented!(),
                }
                if res.is_err() {
                    break;
                }
            }
            res
        }
    }
}

fn adc<T: Write>(am: AddressingMode, writer: &mut T) -> AssembleResult {
    match am {
        AddressingMode::Immediate(val, sign) => immediate(0x69, val, sign, writer),
        AddressingMode::ZeroPageOrRelative(addr, sign) => zero_page(0x65, addr, sign, writer),
        AddressingMode::ZeroPageX(addr) => zero_page_x(0x75, addr, writer),
        AddressingMode::Absolute(addr) => absolute(0x6d, addr, writer),
        AddressingMode::AbsoluteX(addr) => absolute_x(0x7d, addr, writer),
        AddressingMode::AbsoluteY(addr) => absolute_y(0x79, addr, writer),
        AddressingMode::IndexedIndirect(addr) => indexed_indirect(0x61, addr, writer),
        AddressingMode::IndirectIndexed(addr) => indirect_indexed(0x71, addr, writer),
        _ => Err(format!("Unexpected operand encountered for ADC: {:?}", am)),
    }
}

fn and<T: Write>(am: AddressingMode, writer: &mut T) -> AssembleResult {
    match am {
        AddressingMode::Immediate(val, sign) => immediate(0x29, val, sign, writer),
        AddressingMode::ZeroPageOrRelative(addr, sign) => zero_page(0x25, addr, sign, writer),
        AddressingMode::ZeroPageX(addr) => zero_page_x(0x35, addr, writer),
        AddressingMode::Absolute(addr) => absolute(0x2d, addr, writer),
        AddressingMode::AbsoluteX(addr) => absolute_x(0x3d, addr, writer),
        AddressingMode::AbsoluteY(addr) => absolute_y(0x39, addr, writer),
        AddressingMode::IndexedIndirect(addr) => indexed_indirect(0x21, addr, writer),
        AddressingMode::IndirectIndexed(addr) => indirect_indexed(0x31, addr, writer),
        _ => Err(format!("Unexpected operand encountered for AND: {:?}", am)),
    }
}

fn asl<T: Write>(am: AddressingMode, writer: &mut T) -> AssembleResult {
    match am {
        AddressingMode::Accumulator => accumulator(0x0a, writer),
        AddressingMode::ZeroPageOrRelative(addr, sign) => zero_page(0x06, addr, sign, writer),
        AddressingMode::ZeroPageX(addr) => zero_page_x(0x16, addr, writer),
        AddressingMode::Absolute(addr) => absolute(0x0e, addr, writer),
        AddressingMode::AbsoluteX(addr) => absolute_x(0x1e, addr, writer),
        _ => Err(format!("Unexpected operand encountered for ASL: {:?}", am)),
    }
}

fn bit<T: Write>(am: AddressingMode, writer: &mut T) -> AssembleResult {
    match am {
        AddressingMode::ZeroPageOrRelative(addr, sign) => zero_page(0x24, addr, sign, writer),
        AddressingMode::Absolute(addr) => absolute(0x2c, addr, writer),
        _ => Err(format!("Unexpected operand encountered for BIT: {:?}", am)),
    }
}

fn accumulator<T: Write>(opcode: u8, writer: &mut T) -> AssembleResult {
    byte(opcode, writer)
}

fn immediate<T: Write>(opcode: u8, val: u8, sign: Sign, writer: &mut T) -> AssembleResult {
    byte(opcode, writer).and_then(|_| signed(val, sign, writer))
}

fn zero_page<T: Write>(opcode: u8, addr: u8, sign: Sign, writer: &mut T) -> AssembleResult {
    err_if_negative(sign).and_then(|_| byte(opcode, writer).and_then(|_| byte(addr, writer)))
}

fn zero_page_x<T: Write>(opcode: u8, addr: u8, writer: &mut T) -> AssembleResult {
    byte(opcode, writer).and_then(|_| byte(addr, writer))
}

fn absolute<T: Write>(opcode: u8, addr: u16, writer: &mut T) -> AssembleResult {
    byte(opcode, writer).and_then(|_| word(addr, writer))
}

fn absolute_x<T: Write>(opcode: u8, addr: u16, writer: &mut T) -> AssembleResult {
    byte(opcode, writer).and_then(|_| word(addr, writer))
}

fn absolute_y<T: Write>(opcode: u8, addr: u16, writer: &mut T) -> AssembleResult {
    byte(opcode, writer).and_then(|_| word(addr, writer))
}

fn indexed_indirect<T: Write>(opcode: u8, addr: u8, writer: &mut T) -> AssembleResult {
    byte(opcode, writer).and_then(|_| byte(addr, writer))
}

fn indirect_indexed<T: Write>(opcode: u8, addr: u8, writer: &mut T) -> AssembleResult {
    byte(opcode, writer).and_then(|_| byte(addr, writer))
}

fn signed<T: Write>(val: u8, sign: Sign, writer: &mut T) -> AssembleResult {
    match sign {
        Sign::Implied => byte(val, writer),
        Sign::Negative => {
            if val > 127 {
                Err("Signed byte overflow".to_string())
            } else {
                byte(val, writer)
            }
        }
    }
}

fn byte<T: Write>(val: u8, writer: &mut T) -> AssembleResult {
    writer.write(&[val])
        .map(|_| ())
        .map_err(|_| "An error occurred while writing to the buffer".to_string())
}

fn word<T: Write>(val: u16, writer: &mut T) -> AssembleResult {
    let low_byte = (val & 0xff) as u8;
    let high_byte = ((val >> 8) & 0xff) as u8;
    writer.write(&[low_byte, high_byte])
        .map(|_| ())
        .map_err(|_| "An error occurred while writing to the buffer".to_string())
}

fn err_if_negative(sign: Sign) -> AssembleResult {
    if sign == Sign::Negative {
        Err("Unexpected signed operand".to_string())
    } else {
        Ok(())
    }
}
<commit_msg>Fix warning<commit_after>#[cfg(test)]
mod tests;

use nom::IResult;
use parser::parse_lines;
use std::io::{Read, Write};
use tokens::*;

type AssembleResult = Result<(), String>;

pub fn assemble<R: Read, W: Write>(mut input: R, writer: &mut W) -> AssembleResult {
    let mut buf = Vec::<u8>::new();
    input.read_to_end(&mut buf).map_err(|_| "Error reading input".to_string())?;
    match parse_lines(&buf) {
        IResult::Error(_) => Err("An error occurred while parsing".to_string()),
        IResult::Incomplete(_) => {
            Err("An error occurred while parsing. Need more input.".to_string())
        }
        IResult::Done(_, opcodes) => {
            let mut res: AssembleResult = Ok(());
            for opcode in opcodes {
                let OpCode(mnemonic, am) = opcode;
                match mnemonic {
                    Mnemonic::Adc => res = adc(am, writer),
                    Mnemonic::And => res = and(am, writer),
                    Mnemonic::Asl => res = asl(am, writer),
                    Mnemonic::Bit => res = bit(am, writer),
                    _ => unimplemented!(),
                }
                if res.is_err() {
                    break;
                }
            }
            res
        }
    }
}

fn adc<T: Write>(am: AddressingMode, writer: &mut T) -> AssembleResult {
    match am {
        AddressingMode::Immediate(val, sign) => immediate(0x69, val, sign, writer),
        AddressingMode::ZeroPageOrRelative(addr, sign) => zero_page(0x65, addr, sign, writer),
        AddressingMode::ZeroPageX(addr) => zero_page_x(0x75, addr, writer),
        AddressingMode::Absolute(addr) => absolute(0x6d, addr, writer),
        AddressingMode::AbsoluteX(addr) => absolute_x(0x7d, addr, writer),
        AddressingMode::AbsoluteY(addr) => absolute_y(0x79, addr, writer),
        AddressingMode::IndexedIndirect(addr) => indexed_indirect(0x61, addr, writer),
        AddressingMode::IndirectIndexed(addr) => indirect_indexed(0x71, addr, writer),
        _ => Err(format!("Unexpected operand encountered for ADC: {:?}", am)),
    }
}

fn and<T: Write>(am: AddressingMode, writer: &mut T) -> AssembleResult {
    match am {
        AddressingMode::Immediate(val, sign) => immediate(0x29, val, sign, writer),
        AddressingMode::ZeroPageOrRelative(addr, sign) => zero_page(0x25, addr, sign, writer),
        AddressingMode::ZeroPageX(addr) => zero_page_x(0x35, addr, writer),
        AddressingMode::Absolute(addr) => absolute(0x2d, addr, writer),
        AddressingMode::AbsoluteX(addr) => absolute_x(0x3d, addr, writer),
        AddressingMode::AbsoluteY(addr) => absolute_y(0x39, addr, writer),
        AddressingMode::IndexedIndirect(addr) => indexed_indirect(0x21, addr, writer),
        AddressingMode::IndirectIndexed(addr) => indirect_indexed(0x31, addr, writer),
        _ => Err(format!("Unexpected operand encountered for AND: {:?}", am)),
    }
}

fn asl<T: Write>(am: AddressingMode, writer: &mut T) -> AssembleResult {
    match am {
        AddressingMode::Accumulator => accumulator(0x0a, writer),
        AddressingMode::ZeroPageOrRelative(addr, sign) => zero_page(0x06, addr, sign, writer),
        AddressingMode::ZeroPageX(addr) => zero_page_x(0x16, addr, writer),
        AddressingMode::Absolute(addr) => absolute(0x0e, addr, writer),
        AddressingMode::AbsoluteX(addr) => absolute_x(0x1e, addr, writer),
        _ => Err(format!("Unexpected operand encountered for ASL: {:?}", am)),
    }
}

fn bit<T: Write>(am: AddressingMode, writer: &mut T) -> AssembleResult {
    match am {
        AddressingMode::ZeroPageOrRelative(addr, sign) => zero_page(0x24, addr, sign, writer),
        AddressingMode::Absolute(addr) => absolute(0x2c, addr, writer),
        _ => Err(format!("Unexpected operand encountered for BIT: {:?}", am)),
    }
}

fn accumulator<T: Write>(opcode: u8, writer: &mut T) -> AssembleResult {
    byte(opcode, writer)
}

fn immediate<T: Write>(opcode: u8, val: u8, sign: Sign, writer: &mut T) -> AssembleResult {
    byte(opcode, writer).and_then(|_| signed(val, sign, writer))
}

fn zero_page<T: Write>(opcode: u8, addr: u8, sign: Sign, writer: &mut T) -> AssembleResult {
    err_if_negative(sign).and_then(|_| byte(opcode, writer).and_then(|_| byte(addr, writer)))
}

fn zero_page_x<T: Write>(opcode: u8, addr: u8, writer: &mut T) -> AssembleResult {
    byte(opcode, writer).and_then(|_| byte(addr, writer))
}

fn absolute<T: Write>(opcode: u8, addr: u16, writer: &mut T) -> AssembleResult {
    byte(opcode, writer).and_then(|_| word(addr, writer))
}

fn absolute_x<T: Write>(opcode: u8, addr: u16, writer: &mut T) -> AssembleResult {
    byte(opcode, writer).and_then(|_| word(addr, writer))
}

fn absolute_y<T: Write>(opcode: u8, addr: u16, writer: &mut T) -> AssembleResult {
    byte(opcode, writer).and_then(|_| word(addr, writer))
}

fn indexed_indirect<T: Write>(opcode: u8, addr: u8, writer: &mut T) -> AssembleResult {
    byte(opcode, writer).and_then(|_| byte(addr, writer))
}

fn indirect_indexed<T: Write>(opcode: u8, addr: u8, writer: &mut T) -> AssembleResult {
    byte(opcode, writer).and_then(|_| byte(addr, writer))
}

fn signed<T: Write>(val: u8, sign: Sign, writer: &mut T) -> AssembleResult {
    match sign {
        Sign::Implied => byte(val, writer),
        Sign::Negative => {
            if val > 127 {
                Err("Signed byte overflow".to_string())
            } else {
                byte(val, writer)
            }
        }
    }
}

fn byte<T: Write>(val: u8, writer: &mut T) -> AssembleResult {
    writer.write(&[val])
        .map(|_| ())
        .map_err(|_| "An error occurred while writing to the buffer".to_string())
}

fn word<T: Write>(val: u16, writer: &mut T) -> AssembleResult {
    let low_byte = (val & 0xff) as u8;
    let high_byte = ((val >> 8) & 0xff) as u8;
    writer.write(&[low_byte, high_byte])
        .map(|_| ())
        .map_err(|_| "An error occurred while writing to the buffer".to_string())
}

fn err_if_negative(sign: Sign) -> AssembleResult {
    if sign == Sign::Negative {
        Err("Unexpected signed operand".to_string())
    } else {
        Ok(())
    }
}
<|endoftext|>


<commit_before>use cargo::core::features;
use cargo::{self, drop_print, drop_println, CliResult, Config};
use clap::{AppSettings, Arg, ArgMatches};

use super::commands;
use super::list_commands;
use crate::command_prelude::*;

pub fn main(config: &mut Config) -> CliResult {
    // CAUTION: Be careful with using `config` until it is configured below.
    // In general, try to avoid loading config values unless necessary (like
    // the [alias] table).
    let args = match cli().get_matches_safe() {
        Ok(args) => args,
        Err(e) => {
            if e.kind == clap::ErrorKind::UnrecognizedSubcommand {
                // An unrecognized subcommand might be an external subcommand.
                let cmd = &e.info.as_ref().unwrap()[0].to_owned();
                return super::execute_external_subcommand(config, cmd, &[cmd, "--help"])
                    .map_err(|_| e.into());
            } else {
                return Err(e.into());
            }
        }
    };

    if args.value_of("unstable-features") == Some("help") {
        drop_println!(
            config,
            "
Available unstable (nightly-only) flags:

    -Z avoid-dev-deps   -- Avoid installing dev-dependencies if possible
    -Z minimal-versions -- Install minimal dependency versions instead of maximum
    -Z no-index-update  -- Do not update the registry, avoids a network request for benchmarking
    -Z unstable-options -- Allow the usage of unstable options
    -Z timings          -- Display concurrency information
    -Z doctest-xcompile -- Compile and run doctests for non-host target using runner config
    -Z crate-versions   -- Add crate versions to generated docs

Run with 'cargo -Z [FLAG] [SUBCOMMAND]'"
        );
        if !features::nightly_features_allowed() {
            drop_println!(
                config,
                "\nUnstable flags are only available on the nightly channel \
                 of Cargo, but this is the `{}` channel.\n\
                 {}",
                features::channel(),
                features::SEE_CHANNELS
            );
        }
        drop_println!(
            config,
            "\nSee https://doc.rust-lang.org/nightly/cargo/reference/unstable.html \
             for more information about these flags."
        );
        return Ok(());
    }

    let is_verbose = args.occurrences_of("verbose") > 0;
    if args.is_present("version") {
        let version = get_version_string(is_verbose);
        drop_print!(config, "{}", version);
        return Ok(());
    }

    if let Some(code) = args.value_of("explain") {
        let mut procss = config.load_global_rustc(None)?.process();
        procss.arg("--explain").arg(code).exec()?;
        return Ok(());
    }

    if args.is_present("list") {
        drop_println!(config, "Installed Commands:");
        for command in list_commands(config) {
            match command {
                CommandInfo::BuiltIn { name, about } => {
                    let summary = about.unwrap_or_default();
                    let summary = summary.lines().next().unwrap_or(&summary); // display only the first line
                    drop_println!(config, "    {:<20} {}", name, summary);
                }
                CommandInfo::External { name, path } => {
                    if is_verbose {
                        drop_println!(config, "    {:<20} {}", name, path.display());
                    } else {
                        drop_println!(config, "    {}", name);
                    }
                }
            }
        }
        return Ok(());
    }

    // Global args need to be extracted before expanding aliases because the
    // clap code for extracting a subcommand discards global options
    // (appearing before the subcommand).
    let (expanded_args, global_args) = expand_aliases(config, args)?;
    let (cmd, subcommand_args) = match expanded_args.subcommand() {
        (cmd, Some(args)) => (cmd, args),
        _ => {
            // No subcommand provided.
            cli().print_help()?;
            return Ok(());
        }
    };
    config_configure(config, &expanded_args, subcommand_args, global_args)?;
    super::init_git_transports(config);

    execute_subcommand(config, cmd, subcommand_args)
}

pub fn get_version_string(is_verbose: bool) -> String {
    let version = cargo::version();
    let mut version_string = version.to_string();
    version_string.push_str("\n");
    if is_verbose {
        version_string.push_str(&format!(
            "release: {}.{}.{}\n",
            version.major, version.minor, version.patch
        ));
        if let Some(ref cfg) = version.cfg_info {
            if let Some(ref ci) = cfg.commit_info {
                version_string.push_str(&format!("commit-hash: {}\n", ci.commit_hash));
                version_string.push_str(&format!("commit-date: {}\n", ci.commit_date));
            }
        }
    }
    version_string
}

fn expand_aliases(
    config: &mut Config,
    args: ArgMatches<'static>,
) -> Result<(ArgMatches<'static>, GlobalArgs), CliError> {
    if let (cmd, Some(args)) = args.subcommand() {
        match (
            commands::builtin_exec(cmd),
            super::aliased_command(config, cmd)?,
        ) {
            (Some(_), Some(_)) => {
                // User alias conflicts with a built-in subcommand
                config.shell().warn(format!(
                    "user-defined alias `{}` is ignored, because it is shadowed by a built-in command",
                    cmd,
                ))?;
            }
            (_, Some(mut alias)) => {
                alias.extend(
                    args.values_of("")
                        .unwrap_or_default()
                        .map(|s| s.to_string()),
                );
                // new_args strips out everything before the subcommand, so
                // capture those global options now.
                // Note that an alias to an external command will not receive
                // these arguments. That may be confusing, but such is life.
                let global_args = GlobalArgs::new(args);
                let new_args = cli()
                    .setting(AppSettings::NoBinaryName)
                    .get_matches_from_safe(alias)?;
                let (expanded_args, _) = expand_aliases(config, new_args)?;
                return Ok((expanded_args, global_args));
            }
            (_, None) => {}
        }
    };

    Ok((args, GlobalArgs::default()))
}

fn config_configure(
    config: &mut Config,
    args: &ArgMatches<'_>,
    subcommand_args: &ArgMatches<'_>,
    global_args: GlobalArgs,
) -> CliResult {
    let arg_target_dir = &subcommand_args.value_of_path("target-dir", config);
    let verbose = global_args.verbose + args.occurrences_of("verbose") as u32;
    // quiet is unusual because it is redefined in some subcommands in order
    // to provide custom help text.
    let quiet =
        args.is_present("quiet") || subcommand_args.is_present("quiet") || global_args.quiet;
    let global_color = global_args.color; // Extract so it can take reference.
    let color = args.value_of("color").or_else(|| global_color.as_deref());
    let frozen = args.is_present("frozen") || global_args.frozen;
    let locked = args.is_present("locked") || global_args.locked;
    let offline = args.is_present("offline") || global_args.offline;
    let mut unstable_flags = global_args.unstable_flags;
    if let Some(values) = args.values_of("unstable-features") {
        unstable_flags.extend(values.map(|s| s.to_string()));
    }
    let mut config_args = global_args.config_args;
    if let Some(values) = args.values_of("config") {
        config_args.extend(values.map(|s| s.to_string()));
    }
    config.configure(
        verbose,
        quiet,
        color,
        frozen,
        locked,
        offline,
        arg_target_dir,
        &unstable_flags,
        &config_args,
    )?;
    Ok(())
}

fn execute_subcommand(
    config: &mut Config,
    cmd: &str,
    subcommand_args: &ArgMatches<'_>,
) -> CliResult {
    if let Some(exec) = commands::builtin_exec(cmd) {
        return exec(config, subcommand_args);
    }

    let mut ext_args: Vec<&str> = vec![cmd];
    ext_args.extend(subcommand_args.values_of("").unwrap_or_default());
    super::execute_external_subcommand(config, cmd, &ext_args)
}

#[derive(Default)]
struct GlobalArgs {
    verbose: u32,
    quiet: bool,
    color: Option<String>,
    frozen: bool,
    locked: bool,
    offline: bool,
    unstable_flags: Vec<String>,
    config_args: Vec<String>,
}

impl GlobalArgs {
    fn new(args: &ArgMatches<'_>) -> GlobalArgs {
        GlobalArgs {
            verbose: args.occurrences_of("verbose") as u32,
            quiet: args.is_present("quiet"),
            color: args.value_of("color").map(|s| s.to_string()),
            frozen: args.is_present("frozen"),
            locked: args.is_present("locked"),
            offline: args.is_present("offline"),
            unstable_flags: args
                .values_of_lossy("unstable-features")
                .unwrap_or_default(),
            config_args: args
                .values_of("config")
                .unwrap_or_default()
                .map(|s| s.to_string())
                .collect(),
        }
    }
}

fn cli() -> App {
    App::new("cargo")
        .settings(&[
            AppSettings::UnifiedHelpMessage,
            AppSettings::DeriveDisplayOrder,
            AppSettings::VersionlessSubcommands,
            AppSettings::AllowExternalSubcommands,
        ])
        .template(
            "\
Rust's package manager

USAGE:
    {usage}

OPTIONS:
{unified}

Some common cargo commands are (see all commands with --list):
    build       Compile the current package
    check       Analyze the current package and report errors, but don't build object files
    clean       Remove the target directory
    doc         Build this package's and its dependencies' documentation
    new         Create a new cargo package
    init        Create a new cargo package in an existing directory
    run         Run a binary or example of the local package
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this package to the registry
    install     Install a Rust binary. Default location is $HOME/.cargo/bin
    uninstall   Uninstall a Rust binary

See 'cargo help <command>' for more information on a specific command.\n",
        )
        .arg(opt("version", "Print version info and exit").short("V"))
        .arg(opt("list", "List installed commands"))
        .arg(opt("explain", "Run `rustc --explain CODE`").value_name("CODE"))
        .arg(
            opt(
                "verbose",
                "Use verbose output (-vv very verbose/build.rs output)",
            )
            .short("v")
            .multiple(true)
            .global(true),
        )
        .arg(opt("quiet", "No output printed to stdout").short("q"))
        .arg(
            opt("color", "Coloring: auto, always, never")
                .value_name("WHEN")
                .global(true),
        )
        .arg(opt("frozen", "Require Cargo.lock and cache are up to date").global(true))
        .arg(opt("locked", "Require Cargo.lock is up to date").global(true))
        .arg(opt("offline", "Run without accessing the network").global(true))
        .arg(
            multi_opt("config", "KEY=VALUE", "Override a configuration value")
                .global(true)
                .hidden(true),
        )
        .arg(
            Arg::with_name("unstable-features")
                .help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details")
                .short("Z")
                .value_name("FLAG")
                .multiple(true)
                .number_of_values(1)
                .global(true),
        )
        .subcommands(commands::builtin())
}
<commit_msg>Auto merge of #8307 - pickfire:alias-help, r=alexcrichton<commit_after>use cargo::core::features;
use cargo::{self, drop_print, drop_println, CliResult, Config};
use clap::{AppSettings, Arg, ArgMatches};

use super::commands;
use super::list_commands;
use crate::command_prelude::*;

pub fn main(config: &mut Config) -> CliResult {
    // CAUTION: Be careful with using `config` until it is configured below.
    // In general, try to avoid loading config values unless necessary (like
    // the [alias] table).
    let args = match cli().get_matches_safe() {
        Ok(args) => args,
        Err(e) => {
            if e.kind == clap::ErrorKind::UnrecognizedSubcommand {
                // An unrecognized subcommand might be an external subcommand.
                let cmd = &e.info.as_ref().unwrap()[0].to_owned();
                return super::execute_external_subcommand(config, cmd, &[cmd, "--help"])
                    .map_err(|_| e.into());
            } else {
                return Err(e.into());
            }
        }
    };

    if args.value_of("unstable-features") == Some("help") {
        drop_println!(
            config,
            "
Available unstable (nightly-only) flags:

    -Z avoid-dev-deps   -- Avoid installing dev-dependencies if possible
    -Z minimal-versions -- Install minimal dependency versions instead of maximum
    -Z no-index-update  -- Do not update the registry, avoids a network request for benchmarking
    -Z unstable-options -- Allow the usage of unstable options
    -Z timings          -- Display concurrency information
    -Z doctest-xcompile -- Compile and run doctests for non-host target using runner config
    -Z crate-versions   -- Add crate versions to generated docs

Run with 'cargo -Z [FLAG] [SUBCOMMAND]'"
        );
        if !features::nightly_features_allowed() {
            drop_println!(
                config,
                "\nUnstable flags are only available on the nightly channel \
                 of Cargo, but this is the `{}` channel.\n\
                 {}",
                features::channel(),
                features::SEE_CHANNELS
            );
        }
        drop_println!(
            config,
            "\nSee https://doc.rust-lang.org/nightly/cargo/reference/unstable.html \
             for more information about these flags."
        );
        return Ok(());
    }

    let is_verbose = args.occurrences_of("verbose") > 0;
    if args.is_present("version") {
        let version = get_version_string(is_verbose);
        drop_print!(config, "{}", version);
        return Ok(());
    }

    if let Some(code) = args.value_of("explain") {
        let mut procss = config.load_global_rustc(None)?.process();
        procss.arg("--explain").arg(code).exec()?;
        return Ok(());
    }

    if args.is_present("list") {
        drop_println!(config, "Installed Commands:");
        for command in list_commands(config) {
            match command {
                CommandInfo::BuiltIn { name, about } => {
                    let summary = about.unwrap_or_default();
                    let summary = summary.lines().next().unwrap_or(&summary); // display only the first line
                    drop_println!(config, "    {:<20} {}", name, summary);
                }
                CommandInfo::External { name, path } => {
                    if is_verbose {
                        drop_println!(config, "    {:<20} {}", name, path.display());
                    } else {
                        drop_println!(config, "    {}", name);
                    }
                }
            }
        }
        return Ok(());
    }

    // Global args need to be extracted before expanding aliases because the
    // clap code for extracting a subcommand discards global options
    // (appearing before the subcommand).
    let (expanded_args, global_args) = expand_aliases(config, args)?;
    let (cmd, subcommand_args) = match expanded_args.subcommand() {
        (cmd, Some(args)) => (cmd, args),
        _ => {
            // No subcommand provided.
            cli().print_help()?;
            return Ok(());
        }
    };
    config_configure(config, &expanded_args, subcommand_args, global_args)?;
    super::init_git_transports(config);

    execute_subcommand(config, cmd, subcommand_args)
}

pub fn get_version_string(is_verbose: bool) -> String {
    let version = cargo::version();
    let mut version_string = version.to_string();
    version_string.push_str("\n");
    if is_verbose {
        version_string.push_str(&format!(
            "release: {}.{}.{}\n",
            version.major, version.minor, version.patch
        ));
        if let Some(ref cfg) = version.cfg_info {
            if let Some(ref ci) = cfg.commit_info {
                version_string.push_str(&format!("commit-hash: {}\n", ci.commit_hash));
                version_string.push_str(&format!("commit-date: {}\n", ci.commit_date));
            }
        }
    }
    version_string
}

fn expand_aliases(
    config: &mut Config,
    args: ArgMatches<'static>,
) -> Result<(ArgMatches<'static>, GlobalArgs), CliError> {
    if let (cmd, Some(args)) = args.subcommand() {
        match (
            commands::builtin_exec(cmd),
            super::aliased_command(config, cmd)?,
        ) {
            (Some(_), Some(_)) => {
                // User alias conflicts with a built-in subcommand
                config.shell().warn(format!(
                    "user-defined alias `{}` is ignored, because it is shadowed by a built-in command",
                    cmd,
                ))?;
            }
            (_, Some(mut alias)) => {
                alias.extend(
                    args.values_of("")
                        .unwrap_or_default()
                        .map(|s| s.to_string()),
                );
                // new_args strips out everything before the subcommand, so
                // capture those global options now.
                // Note that an alias to an external command will not receive
                // these arguments. That may be confusing, but such is life.
                let global_args = GlobalArgs::new(args);
                let new_args = cli()
                    .setting(AppSettings::NoBinaryName)
                    .get_matches_from_safe(alias)?;
                let (expanded_args, _) = expand_aliases(config, new_args)?;
                return Ok((expanded_args, global_args));
            }
            (_, None) => {}
        }
    };

    Ok((args, GlobalArgs::default()))
}

fn config_configure(
    config: &mut Config,
    args: &ArgMatches<'_>,
    subcommand_args: &ArgMatches<'_>,
    global_args: GlobalArgs,
) -> CliResult {
    let arg_target_dir = &subcommand_args.value_of_path("target-dir", config);
    let verbose = global_args.verbose + args.occurrences_of("verbose") as u32;
    // quiet is unusual because it is redefined in some subcommands in order
    // to provide custom help text.
    let quiet =
        args.is_present("quiet") || subcommand_args.is_present("quiet") || global_args.quiet;
    let global_color = global_args.color; // Extract so it can take reference.
    let color = args.value_of("color").or_else(|| global_color.as_deref());
    let frozen = args.is_present("frozen") || global_args.frozen;
    let locked = args.is_present("locked") || global_args.locked;
    let offline = args.is_present("offline") || global_args.offline;
    let mut unstable_flags = global_args.unstable_flags;
    if let Some(values) = args.values_of("unstable-features") {
        unstable_flags.extend(values.map(|s| s.to_string()));
    }
    let mut config_args = global_args.config_args;
    if let Some(values) = args.values_of("config") {
        config_args.extend(values.map(|s| s.to_string()));
    }
    config.configure(
        verbose,
        quiet,
        color,
        frozen,
        locked,
        offline,
        arg_target_dir,
        &unstable_flags,
        &config_args,
    )?;
    Ok(())
}

fn execute_subcommand(
    config: &mut Config,
    cmd: &str,
    subcommand_args: &ArgMatches<'_>,
) -> CliResult {
    if let Some(exec) = commands::builtin_exec(cmd) {
        return exec(config, subcommand_args);
    }

    let mut ext_args: Vec<&str> = vec![cmd];
    ext_args.extend(subcommand_args.values_of("").unwrap_or_default());
    super::execute_external_subcommand(config, cmd, &ext_args)
}

#[derive(Default)]
struct GlobalArgs {
    verbose: u32,
    quiet: bool,
    color: Option<String>,
    frozen: bool,
    locked: bool,
    offline: bool,
    unstable_flags: Vec<String>,
    config_args: Vec<String>,
}

impl GlobalArgs {
    fn new(args: &ArgMatches<'_>) -> GlobalArgs {
        GlobalArgs {
            verbose: args.occurrences_of("verbose") as u32,
            quiet: args.is_present("quiet"),
            color: args.value_of("color").map(|s| s.to_string()),
            frozen: args.is_present("frozen"),
            locked: args.is_present("locked"),
            offline: args.is_present("offline"),
            unstable_flags: args
                .values_of_lossy("unstable-features")
                .unwrap_or_default(),
            config_args: args
                .values_of("config")
                .unwrap_or_default()
                .map(|s| s.to_string())
                .collect(),
        }
    }
}

fn cli() -> App {
    App::new("cargo")
        .settings(&[
            AppSettings::UnifiedHelpMessage,
            AppSettings::DeriveDisplayOrder,
            AppSettings::VersionlessSubcommands,
            AppSettings::AllowExternalSubcommands,
        ])
        .template(
            "\
Rust's package manager

USAGE:
    {usage}

OPTIONS:
{unified}

Some common cargo commands are (see all commands with --list):
    build, b    Compile the current package
    check, c    Analyze the current package and report errors, but don't build object files
    clean       Remove the target directory
    doc         Build this package's and its dependencies' documentation
    new         Create a new cargo package
    init        Create a new cargo package in an existing directory
    run, r      Run a binary or example of the local package
    test, t     Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock
    search      Search registry for crates
    publish     Package and upload this package to the registry
    install     Install a Rust binary. Default location is $HOME/.cargo/bin
    uninstall   Uninstall a Rust binary

See 'cargo help <command>' for more information on a specific command.\n",
        )
        .arg(opt("version", "Print version info and exit").short("V"))
        .arg(opt("list", "List installed commands"))
        .arg(opt("explain", "Run `rustc --explain CODE`").value_name("CODE"))
        .arg(
            opt(
                "verbose",
                "Use verbose output (-vv very verbose/build.rs output)",
            )
            .short("v")
            .multiple(true)
            .global(true),
        )
        .arg(opt("quiet", "No output printed to stdout").short("q"))
        .arg(
            opt("color", "Coloring: auto, always, never")
                .value_name("WHEN")
                .global(true),
        )
        .arg(opt("frozen", "Require Cargo.lock and cache are up to date").global(true))
        .arg(opt("locked", "Require Cargo.lock is up to date").global(true))
        .arg(opt("offline", "Run without accessing the network").global(true))
        .arg(
            multi_opt("config", "KEY=VALUE", "Override a configuration value")
                .global(true)
                .hidden(true),
        )
        .arg(
            Arg::with_name("unstable-features")
                .help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details")
                .short("Z")
                .value_name("FLAG")
                .multiple(true)
                .number_of_values(1)
                .global(true),
        )
        .subcommands(commands::builtin())
}
<|endoftext|>


<commit_before>#![crate_name = "bindgen"]
#![crate_type = "bin"]

extern crate bindgen;
#[macro_use] extern crate log;

use bindgen::{Bindings, BindgenOptions, LinkType, Logger};
use std::io;
use std::path;
use std::env;
use std::default::Default;
use std::fs;
use std::borrow::ToOwned;
use std::process::exit;

struct StdLogger;

impl Logger for StdLogger {
    fn error(&self, msg: &str) {
        error!("{}", msg);
    }

    fn warn(&self, msg: &str) {
        warn!("{}", msg);
    }
}

enum ParseResult {
    CmdUsage,
    ParseOk(BindgenOptions, Box<io::Write+'static>),
    ParseErr(String)
}

fn parse_args(args: &[String]) -> ParseResult {
    let args_len = args.len();

    let mut options: BindgenOptions = Default::default();
    let mut out = Box::new(io::BufWriter::new(io::stdout())) as Box<io::Write>;

    if args_len == 0 {
        return ParseResult::CmdUsage;
    }

    let mut ix: usize = 0;
    while ix < args_len {
        if args[ix].len() > 2 && &args[ix][..2] == "-l" {
            options.links.push((args[ix][2..].to_string(), LinkType::Default));
            ix += 1;
        } else {
            match &args[ix][..] {
                "--help" | "-h" => {
                    return ParseResult::CmdUsage;
                }
                "-emit-clang-ast" => {
                    options.emit_ast = true;
                    ix += 1;
                }
                "-o" => {
                    if ix + 1 >= args_len {
                        return ParseResult::ParseErr("Missing output filename".to_string());
                    }
                    let path = path::Path::new(&args[ix + 1]);
                    match fs::File::create(&path) {
                        Ok(f) => { out = Box::new(io::BufWriter::new(f)) as Box<io::Write>; }
                        Err(_) => { return ParseResult::ParseErr(format!("Open {} failed", args[ix + 1])); }
                    }
                    ix += 2;
                }
                "-l" => {
                    if ix + 1 >= args_len {
                        return ParseResult::ParseErr("Missing link name".to_string());
                    }
                    options.links.push((args[ix + 1].clone(), LinkType::Default));
                    ix += 2;
                }
                "-static-link" => {
                    if ix + 1 >= args_len {
                        return ParseResult::ParseErr("Missing link name".to_string());
                    }
                    options.links.push((args[ix + 1].clone(), LinkType::Static));
                    ix += 2;
                }
                "-framework-link" => {
                    if ix + 1 >= args_len {
                        return ParseResult::ParseErr("Missing link name".to_string());
                    }
                    options.links.push((args[ix + 1].clone(), LinkType::Framework));
                    ix += 2;
                }
                "-match" => {
                    if ix + 1 >= args_len {
                        return ParseResult::ParseErr("Missing match pattern".to_string());
                    }
                    options.match_pat.push(args[ix + 1].clone());
                    ix += 2;
                }
                "-builtins" => {
                    options.builtins = true;
                    ix += 1;
                }
                "-allow-unknown-types" => {
                    options.fail_on_unknown_type = false;
                    ix += 1;
                }
                "-override-enum-type" => {
                    if ix + 1 >= args_len {
                        return ParseResult::ParseErr("Missing enum type".to_string());
                    }
                    options.override_enum_ty = args[ix + 1].clone();
                    ix += 2;
                }
                _ => {
                    options.clang_args.push(args[ix].clone());
                    ix += 1;
                }
            }
        }
    }

    return ParseResult::ParseOk(options, out);
}

fn print_usage(bin: String) {
    let mut s = format!("Usage: {} [options] input.h", &bin[..]);
    s.push_str(
"
Options:
    -h or --help               Display help message
    -l <name> or -l<name>      Link to a dynamic library, can be proivded
                               multiple times
    -static-link <name>        Link to a static library
    -framework-link <name>     Link to a framework
    -o <output.rs>             Write bindings to <output.rs> (default stdout)
    -match <name>              Only output bindings for definitions from files
                               whose name contains <name>
                               If multiple -match options are provided, files
                               matching any rule are bound to.
    -builtins                  Output bindings for builtin definitions
                               (for example __builtin_va_list)
    -allow-unknown-types       Don't fail if we encounter types we do not support,
                               instead treat them as void
    -emit-clang-ast            Output the ast (for debugging purposes)
    -override-enum-type <type> Override enum type, type name could be
                                 uchar
                                 schar
                                 ushort
                                 sshort
                                 uint
                                 sint
                                 ulong
                                 slong
                                 ulonglong
                                 slonglong

    Options other than stated above are passed to clang.
"
    );
    print!("{}", &s[..]);
}

pub fn main() {
    let mut bind_args: Vec<_> = env::args().collect();
    let bin = bind_args.remove(0);

    match bindgen::get_include_dir() {
        Some(path) => {
            bind_args.push("-I".to_owned());
            bind_args.push(path);
        }
        None => (),
    }

    match parse_args(&bind_args[..]) {
        ParseResult::ParseErr(e) => panic!(e),
        ParseResult::CmdUsage => print_usage(bin),
        ParseResult::ParseOk(options, out) => {
            let logger = StdLogger;
            match Bindings::generate(&options, Some(&logger as &Logger), None) {
                Ok(bindings) => match bindings.write(out) {
                    Ok(()) => (),
                    Err(e) => {
                        logger.error(&format!("Unable to write bindings to file. {}", e)[..]);
                        exit(-1);
                    }
                },
                Err(()) => exit(-1)
            }
        }
    }
}
<commit_msg>Fix a typo<commit_after>#![crate_name = "bindgen"]
#![crate_type = "bin"]

extern crate bindgen;
#[macro_use] extern crate log;

use bindgen::{Bindings, BindgenOptions, LinkType, Logger};
use std::io;
use std::path;
use std::env;
use std::default::Default;
use std::fs;
use std::borrow::ToOwned;
use std::process::exit;

struct StdLogger;

impl Logger for StdLogger {
    fn error(&self, msg: &str) {
        error!("{}", msg);
    }

    fn warn(&self, msg: &str) {
        warn!("{}", msg);
    }
}

enum ParseResult {
    CmdUsage,
    ParseOk(BindgenOptions, Box<io::Write+'static>),
    ParseErr(String)
}

fn parse_args(args: &[String]) -> ParseResult {
    let args_len = args.len();

    let mut options: BindgenOptions = Default::default();
    let mut out = Box::new(io::BufWriter::new(io::stdout())) as Box<io::Write>;

    if args_len == 0 {
        return ParseResult::CmdUsage;
    }

    let mut ix: usize = 0;
    while ix < args_len {
        if args[ix].len() > 2 && &args[ix][..2] == "-l" {
            options.links.push((args[ix][2..].to_string(), LinkType::Default));
            ix += 1;
        } else {
            match &args[ix][..] {
                "--help" | "-h" => {
                    return ParseResult::CmdUsage;
                }
                "-emit-clang-ast" => {
                    options.emit_ast = true;
                    ix += 1;
                }
                "-o" => {
                    if ix + 1 >= args_len {
                        return ParseResult::ParseErr("Missing output filename".to_string());
                    }
                    let path = path::Path::new(&args[ix + 1]);
                    match fs::File::create(&path) {
                        Ok(f) => { out = Box::new(io::BufWriter::new(f)) as Box<io::Write>; }
                        Err(_) => { return ParseResult::ParseErr(format!("Open {} failed", args[ix + 1])); }
                    }
                    ix += 2;
                }
                "-l" => {
                    if ix + 1 >= args_len {
                        return ParseResult::ParseErr("Missing link name".to_string());
                    }
                    options.links.push((args[ix + 1].clone(), LinkType::Default));
                    ix += 2;
                }
                "-static-link" => {
                    if ix + 1 >= args_len {
                        return ParseResult::ParseErr("Missing link name".to_string());
                    }
                    options.links.push((args[ix + 1].clone(), LinkType::Static));
                    ix += 2;
                }
                "-framework-link" => {
                    if ix + 1 >= args_len {
                        return ParseResult::ParseErr("Missing link name".to_string());
                    }
                    options.links.push((args[ix + 1].clone(), LinkType::Framework));
                    ix += 2;
                }
                "-match" => {
                    if ix + 1 >= args_len {
                        return ParseResult::ParseErr("Missing match pattern".to_string());
                    }
                    options.match_pat.push(args[ix + 1].clone());
                    ix += 2;
                }
                "-builtins" => {
                    options.builtins = true;
                    ix += 1;
                }
                "-allow-unknown-types" => {
                    options.fail_on_unknown_type = false;
                    ix += 1;
                }
                "-override-enum-type" => {
                    if ix + 1 >= args_len {
                        return ParseResult::ParseErr("Missing enum type".to_string());
                    }
                    options.override_enum_ty = args[ix + 1].clone();
                    ix += 2;
                }
                _ => {
                    options.clang_args.push(args[ix].clone());
                    ix += 1;
                }
            }
        }
    }

    return ParseResult::ParseOk(options, out);
}

fn print_usage(bin: String) {
    let mut s = format!("Usage: {} [options] input.h", &bin[..]);
    s.push_str(
"
Options:
    -h or --help               Display help message
    -l <name> or -l<name>      Link to a dynamic library, can be provided
                               multiple times
    -static-link <name>        Link to a static library
    -framework-link <name>     Link to a framework
    -o <output.rs>             Write bindings to <output.rs> (default stdout)
    -match <name>              Only output bindings for definitions from files
                               whose name contains <name>
                               If multiple -match options are provided, files
                               matching any rule are bound to.
    -builtins                  Output bindings for builtin definitions
                               (for example __builtin_va_list)
    -allow-unknown-types       Don't fail if we encounter types we do not support,
                               instead treat them as void
    -emit-clang-ast            Output the ast (for debugging purposes)
    -override-enum-type <type> Override enum type, type name could be
                                 uchar
                                 schar
                                 ushort
                                 sshort
                                 uint
                                 sint
                                 ulong
                                 slong
                                 ulonglong
                                 slonglong

    Options other than stated above are passed to clang.
"
    );
    print!("{}", &s[..]);
}

pub fn main() {
    let mut bind_args: Vec<_> = env::args().collect();
    let bin = bind_args.remove(0);

    match bindgen::get_include_dir() {
        Some(path) => {
            bind_args.push("-I".to_owned());
            bind_args.push(path);
        }
        None => (),
    }

    match parse_args(&bind_args[..]) {
        ParseResult::ParseErr(e) => panic!(e),
        ParseResult::CmdUsage => print_usage(bin),
        ParseResult::ParseOk(options, out) => {
            let logger = StdLogger;
            match Bindings::generate(&options, Some(&logger as &Logger), None) {
                Ok(bindings) => match bindings.write(out) {
                    Ok(()) => (),
                    Err(e) => {
                        logger.error(&format!("Unable to write bindings to file. {}", e)[..]);
                        exit(-1);
                    }
                },
                Err(()) => exit(-1)
            }
        }
    }
}
<|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))]

#[macro_use]
extern crate log;
extern crate rustfmt;
extern crate toml;
extern crate env_logger;
extern crate getopts;

use rustfmt::{WriteMode, run, run_from_stdin};
use rustfmt::config::Config;

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

use getopts::Options;

/// Rustfmt operations.
enum Operation {
    /// Format files and its child modules.
    Format(Vec<PathBuf>, WriteMode),
    /// Print the help message.
    Help,
    /// Print detailed configuration help.
    ConfigHelp,
    /// Invalid program input, including reason.
    InvalidInput(String),
    /// No file specified, read from stdin
    Stdin(String, WriteMode),
}

/// Try to find a project file in the input file directory and its parents.
fn lookup_project_file(input_file: &Path) -> io::Result<PathBuf> {
    let mut current = if input_file.is_relative() {
        try!(env::current_dir()).join(input_file)
    } else {
        input_file.to_path_buf()
    };

    // FIXME: We should canonize path to properly handle its parents,
    // but `canonicalize` function is unstable now (recently added API)
    // current = try!(fs::canonicalize(current));

    loop {
        let config_file = current.join("rustfmt.toml");
        if fs::metadata(&config_file).is_ok() {
            return Ok(config_file);
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Err(io::Error::new(io::ErrorKind::NotFound, "Config not found"));
        }
    }
}

/// Try to find a project file. If it's found, read it.
fn lookup_and_read_project_file(input_file: &Path) -> io::Result<(PathBuf, String)> {
    let path = try!(lookup_project_file(input_file));
    let mut file = try!(File::open(&path));
    let mut toml = String::new();
    try!(file.read_to_string(&mut toml));
    Ok((path, toml))
}

fn execute() -> i32 {
    let mut opts = Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optopt("",
                "write-mode",
                "mode to write in (not usable when piping from stdin)",
                "[replace|overwrite|display|diff|coverage]");

    opts.optflag("",
                 "config-help",
                 "show details of rustfmt configuration options");

    let operation = determine_operation(&opts, env::args().skip(1));

    match operation {
        Operation::InvalidInput(reason) => {
            print_usage(&opts, &reason);
            1
        }
        Operation::Help => {
            print_usage(&opts, "");
            0
        }
        Operation::ConfigHelp => {
            Config::print_docs();
            0
        }
        Operation::Stdin(input, write_mode) => {
            // try to read config from local directory
            let config = match lookup_and_read_project_file(&Path::new(".")) {
                Ok((_, toml)) => {
                    Config::from_toml(&toml)
                }
                Err(_) => Default::default(),
            };

            run_from_stdin(input, write_mode, &config);
            0
        }
        Operation::Format(files, write_mode) => {
            for file in files {
                let config = match lookup_and_read_project_file(&file) {
                    Ok((path, toml)) => {
                        println!("Using rustfmt config file {} for {}",
                                 path.display(),
                                 file.display());
                        Config::from_toml(&toml)
                    }
                    Err(_) => Default::default(),
                };

                run(&file, write_mode, &config);
            }
            0
        }
    }
}

fn main() {
    let _ = env_logger::init();
    let exit_code = execute();

    // 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(opts: &Options, reason: &str) {
    let reason = format!("{}\nusage: {} [options] <file>...",
                         reason,
                         env::current_exe().unwrap().display());
    println!("{}", opts.usage(&reason));
}

fn determine_operation<I>(opts: &Options, args: I) -> Operation
    where I: Iterator<Item = String>
{
    let matches = match opts.parse(args) {
        Ok(m) => m,
        Err(e) => return Operation::InvalidInput(e.to_string()),
    };

    if matches.opt_present("h") {
        return Operation::Help;
    }

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

    // if no file argument is supplied, read from stdin
    if matches.free.len() == 0 {

        let mut buffer = String::new();
        match io::stdin().read_to_string(&mut buffer) {
            Ok(..) => (),
            Err(e) => return Operation::InvalidInput(e.to_string()),
        }

        // WriteMode is always plain for Stdin
        return Operation::Stdin(buffer, WriteMode::Plain);
    }

    let write_mode = match matches.opt_str("write-mode") {
        Some(mode) => {
            match mode.parse() {
                Ok(mode) => mode,
                Err(..) => return Operation::InvalidInput("Unrecognized write mode".into()),
            }
        }
        None => WriteMode::Replace,
    };

    let mut files = Vec::with_capacity(matches.free.len());

    for arg in matches.free {
        files.push(PathBuf::from(arg));
    }

    Operation::Format(files, write_mode)
}
<commit_msg>Correct some non-idiomatic code<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))]

#[macro_use]
extern crate log;
extern crate rustfmt;
extern crate toml;
extern crate env_logger;
extern crate getopts;

use rustfmt::{WriteMode, run, run_from_stdin};
use rustfmt::config::Config;

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

use getopts::Options;

/// Rustfmt operations.
enum Operation {
    /// Format files and their child modules.
    Format(Vec<PathBuf>, WriteMode),
    /// Print the help message.
    Help,
    /// Print detailed configuration help.
    ConfigHelp,
    /// Invalid program input, including reason.
    InvalidInput(String),
    /// No file specified, read from stdin
    Stdin(String, WriteMode),
}

/// Try to find a project file in the input file directory and its parents.
fn lookup_project_file(input_file: &Path) -> io::Result<PathBuf> {
    let mut current = if input_file.is_relative() {
        try!(env::current_dir()).join(input_file)
    } else {
        input_file.to_path_buf()
    };

    // FIXME: We should canonize path to properly handle its parents,
    // but `canonicalize` function is unstable now (recently added API)
    // current = try!(fs::canonicalize(current));

    loop {
        let config_file = current.join("rustfmt.toml");
        if fs::metadata(&config_file).is_ok() {
            return Ok(config_file);
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Err(io::Error::new(io::ErrorKind::NotFound, "Config not found"));
        }
    }
}

/// Try to find a project file. If it's found, read it.
fn lookup_and_read_project_file(input_file: &Path) -> io::Result<(PathBuf, String)> {
    let path = try!(lookup_project_file(input_file));
    let mut file = try!(File::open(&path));
    let mut toml = String::new();
    try!(file.read_to_string(&mut toml));
    Ok((path, toml))
}

fn execute() -> i32 {
    let mut opts = Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optopt("",
                "write-mode",
                "mode to write in (not usable when piping from stdin)",
                "[replace|overwrite|display|diff|coverage]");

    opts.optflag("",
                 "config-help",
                 "show details of rustfmt configuration options");

    let operation = determine_operation(&opts, env::args().skip(1));

    match operation {
        Operation::InvalidInput(reason) => {
            print_usage(&opts, &reason);
            1
        }
        Operation::Help => {
            print_usage(&opts, "");
            0
        }
        Operation::ConfigHelp => {
            Config::print_docs();
            0
        }
        Operation::Stdin(input, write_mode) => {
            // try to read config from local directory
            let config = match lookup_and_read_project_file(&Path::new(".")) {
                Ok((_, toml)) => {
                    Config::from_toml(&toml)
                }
                Err(_) => Default::default(),
            };

            run_from_stdin(input, write_mode, &config);
            0
        }
        Operation::Format(files, write_mode) => {
            for file in files {
                let config = match lookup_and_read_project_file(&file) {
                    Ok((path, toml)) => {
                        println!("Using rustfmt config file {} for {}",
                                 path.display(),
                                 file.display());
                        Config::from_toml(&toml)
                    }
                    Err(_) => Default::default(),
                };

                run(&file, write_mode, &config);
            }
            0
        }
    }
}

fn main() {
    let _ = env_logger::init();
    let exit_code = execute();

    // 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(opts: &Options, reason: &str) {
    let reason = format!("{}\nusage: {} [options] <file>...",
                         reason,
                         env::current_exe().unwrap().display());
    println!("{}", opts.usage(&reason));
}

fn determine_operation<I>(opts: &Options, args: I) -> Operation
    where I: Iterator<Item = String>
{
    let matches = match opts.parse(args) {
        Ok(m) => m,
        Err(e) => return Operation::InvalidInput(e.to_string()),
    };

    if matches.opt_present("h") {
        return Operation::Help;
    }

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

    // if no file argument is supplied, read from stdin
    if matches.free.len() == 0 {

        let mut buffer = String::new();
        match io::stdin().read_to_string(&mut buffer) {
            Ok(..) => (),
            Err(e) => return Operation::InvalidInput(e.to_string()),
        }

        // WriteMode is always plain for Stdin
        return Operation::Stdin(buffer, WriteMode::Plain);
    }

    let write_mode = match matches.opt_str("write-mode") {
        Some(mode) => {
            match mode.parse() {
                Ok(mode) => mode,
                Err(..) => return Operation::InvalidInput("Unrecognized write mode".into()),
            }
        }
        None => WriteMode::Replace,
    };

    let files: Vec<_> = matches.free.iter().map(|a| PathBuf::from(a)).collect();

    Operation::Format(files, write_mode)
}
<|endoftext|>