<commit_before>use architecture::*;
use goblin;
use loader::*;
use memory::backing::Memory;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};

/// The address where the first library will be loaded
const DEFAULT_LIB_BASE: u64 = 0x4000_0000;
/// The step in address between where we will load libraries.
const LIB_BASE_STEP: u64    = 0x0200_0000;

/// Loader which links together multiple Elf files.
///
/// Can do some rudimentary linking of binaries.
#[derive(Debug)]
pub struct ElfLinker {
    /// The filename (path included) of the file we're loading.
    filename: PathBuf,
    /// A mapping from lib name (for example `libc.so.6`) to Elf.
    loaded: BTreeMap<String, Elf>,
    /// The current memory mapping.
    memory: Memory,
    /// A mapping of function symbol names to addresses
    symbols: BTreeMap<String, u64>,
    /// The address we will place the next library at.
    next_lib_address: u64,
    /// Functions as specified by the user
    user_functions: Vec<u64>,
    /// If set, we will do relocations as we link
    do_relocations: bool
}

impl ElfLinker {
    /// Takes a path to an Elf and loads the Elf, its dependencies, and links
    /// them together.
    pub fn new(filename: &Path, do_relocations: bool) -> Result<ElfLinker> {
        let mut file = File::open(filename)?;
        let mut buf = Vec::new();
        file.read_to_end(&mut buf)?;

        // get the endianness of this elf for the memory model
        let mut endian = Endian::Big;
        if let goblin::Object::Elf(elf_peek) = goblin::Object::parse(&buf)? {
            if elf_peek.header.endianness()?.is_little() {
                endian = Endian::Little;
            }
        }
        else {
            bail!(format!("{} was not an Elf", filename.to_str().unwrap()));
        }

        let mut elf_linker = ElfLinker {
            filename: filename.to_owned(),
            loaded: BTreeMap::new(),
            memory: Memory::new(endian),
            symbols: BTreeMap::new(),
            next_lib_address: DEFAULT_LIB_BASE,
            user_functions: Vec::new(),
            do_relocations
        };

        elf_linker.load_elf(filename, 0)?;

        Ok(elf_linker)
    }

    /// Get the ELFs loaded and linked in this loader
    pub fn loaded(&self) -> &BTreeMap<String, Elf> {
        &self.loaded
    }

    /// Get the filename of the ELF we're loading
    pub fn filename(&self) -> &Path {
        &self.filename
    }

    /// Takes the path to an Elf, and a base address the Elf should be loaded
    /// at. Loads the Elf, all it's dependencies (DT_NEEDED), and then handles
    /// the supported relocations.
    pub fn load_elf(&mut self, filename: &Path, base_address: u64)
        -> Result<()> {

        // Does this file exist in the same directory as the original file?
        let mut base_path = match self.filename.as_path().parent() {
            Some(base_path) => base_path.to_path_buf(),
            None => PathBuf::new()
        };
        base_path.push(filename);

        let filename = if base_path.exists() {
            &base_path
        }
        else {
            filename
        };

        info!("Loading {} with base_address 0x{:x}",
            filename.to_str().unwrap(),
            base_address);
        let elf = Elf::from_file_with_base_address(filename, base_address)?;

        // Update our memory map based on what's in the Elf
        for (address, section) in elf.memory()?.sections() {
            self.memory.set_memory(*address,
                                   section.data().to_owned(),
                                   section.permissions());
        }

        // Add this Elf to the loaded Elfs
        let filename = filename.file_name()
                               .unwrap()
                               .to_str()
                               .unwrap()
                               .to_string();
        self.loaded.insert(filename.clone(), elf);

        {
            let ref elf = self.loaded[&filename];

            // Add its exported symbols to our symbols
            for symbol in elf.exported_symbols() {
                if self.symbols.get(symbol.name()).is_some() {
                    continue;
                }
                self.symbols.insert(
                    symbol.name().to_string(),
                    elf.base_address() + symbol.address()
                );
            }
        }

        // Ensure all shared objects we rely on are loaded
        for so_name in self.loaded[&filename].dt_needed()?.clone() {
            if self.loaded.get(&so_name).is_none() {
                self.next_lib_address += LIB_BASE_STEP;
                let next_lib_address = self.next_lib_address;
                self.load_elf(Path::new(&so_name), next_lib_address)?;
            }
        }

        if self.do_relocations {
            match self.loaded[&filename].elf().header.e_machine {
                goblin::elf::header::EM_386 =>
                    self.relocations_x86(&filename)?,
                goblin::elf::header::EM_MIPS =>
                    self.relocations_mips(&filename)?,
                _ => bail!("relocations unsupported for target architecture")
            }
        }

        Ok(())
    }

    fn relocations_x86(&mut self, filename: &str) -> Result<()> {
        // Process relocations
        let ref elf = self.loaded[filename];
        let dynsyms = elf.elf().dynsyms;
        let dynstrtab = elf.elf().dynstrtab;
        for reloc in elf.elf().dynrelas.iter().chain(
            elf.elf().dynrels.iter().chain(
                elf.elf().pltrelocs.iter())) {
            match reloc.r_type {
                goblin::elf::reloc::R_386_32 => {
                    let ref sym = dynsyms.get(reloc.r_sym)
                        .expect("Unable to resolve relocation symbol");
                    let sym_name = &dynstrtab[sym.st_name];
                    let value = match self.symbols.get(sym_name) {
                        Some(v) => v.to_owned() as u32,
                        None => bail!("Could not resolve symbol {}", sym_name)
                    };
                    self.memory.set32(
                        reloc.r_offset as u64 + elf.base_address(),
                        value
                    )?;
                }
                goblin::elf::reloc::R_386_GOT32 => {
                    bail!("R_386_GOT32");
                },
                goblin::elf::reloc::R_386_PLT32 => {
                    let ref sym = dynsyms.get(reloc.r_sym)
                        .expect("Unable to resolve relocation symbol");
                    let sym_name = &dynstrtab[sym.st_name];
                    bail!("R_386_PLT32 {:?}:0x{:x}:{}",
                          self.filename,
                          reloc.r_offset,
                          sym_name);
                },
                goblin::elf::reloc::R_386_COPY => {
                    bail!("R_386_COPY");
                },
                goblin::elf::reloc::R_386_GLOB_DAT => {
                    let ref sym = dynsyms.get(reloc.r_sym)
                        .expect("Unable to resolve relocation symbol");
                    let sym_name = &dynstrtab[sym.st_name];
                    let value = match self.symbols.get(sym_name) {
                        Some(v) => v.to_owned() as u32,
                        None => {
                            warn!("Could not resolve symbol {}", sym_name);
                            continue
                        }
                    };
                    self.memory.set32(
                        reloc.r_offset as u64 + elf.base_address(),
                        value
                    )?;
                },
                goblin::elf::reloc::R_386_JMP_SLOT => {
                    let ref sym = dynsyms.get(reloc.r_sym)
                        .expect("Unable to resolve relocation symbol");
                    let sym_name = &dynstrtab[sym.st_name];
                    let value = match self.symbols.get(sym_name) {
                        Some(v) => v.to_owned() as u32,
                        None => bail!("Could not resolve symbol {}", sym_name)
                    };
                    self.memory.set32(
                        reloc.r_offset as u64 + elf.base_address(),
                        value
                    )?;
                },
                goblin::elf::reloc::R_386_RELATIVE => {
                    let value = self.memory.get32(reloc.r_offset as u64 + elf.base_address());
                    let value = match value {
                        Some(value) => elf.base_address() as u32 + value,
                        None => bail!("Invalid address for R_386_RELATIVE {:?}:{:x}",
                                      self.filename,
                                      reloc.r_offset)
                    };
                    self.memory.set32(reloc.r_offset as u64 + elf.base_address(), value)?;
                },
                goblin::elf::reloc::R_386_GOTPC => {
                    bail!("R_386_GOT_PC");
                },
                goblin::elf::reloc::R_386_TLS_TPOFF => {
                    warn!("Ignoring R_386_TLS_TPOFF Relocation");
                },
                goblin::elf::reloc::R_386_IRELATIVE => {
                    warn!("R_386_IRELATIVE {:?}:0x{:x} going unprocessed",
                          self.filename,
                          reloc.r_offset);
                }
                _ => bail!("unhandled relocation type {}", reloc.r_type)
            }
        }
        Ok(())
    }

    fn relocations_mips(&mut self, filename: &str) -> Result<()> {
        let elf = &self.loaded[filename];

        fn get_dynamic(elf: &Elf, tag: u64) -> Option<u64> {
            elf.elf().dynamic.and_then(|dynamic|
                dynamic.dyns
                    .iter()
                    .find(|dyn| dyn.d_tag == tag)
                    .map(|dyn| dyn.d_val))
        }

        // The number of local GOT entries. Also an index into the GOT
        // for the first external GOT entry.
        let local_gotno =
            get_dynamic(elf, goblin::elf::dyn::DT_MIPS_LOCAL_GOTNO)
            .ok_or("Could not get DT_MIPS_LOCAL_GOTNO")?;

        // Index of the first dynamic symbol table entry that corresponds
        // to an entry in the GOT.
        let gotsym =
            get_dynamic(elf, goblin::elf::dyn::DT_MIPS_GOTSYM)
            .ok_or("Could not get DT_MIPS_GOTSYM")?;

        // The number of entries in the dynamic symbol table
        let symtabno =
            get_dynamic(elf, goblin::elf::dyn::DT_MIPS_SYMTABNO)
            .ok_or("Could not get DT_MIPS_SYMTABNO")?;

        // The address of the GOT section
        let pltgot =
            get_dynamic(elf, goblin::elf::dyn::DT_PLTGOT)
            .ok_or("Could not get DT_PLTGOT")?;

        // Start by adding the base address to all entries in the GOT
        for i in 0..(local_gotno + (symtabno - gotsym)) {
            let address = elf.base_address() + (i * 4) + pltgot;
            let value = self.memory.get32(address)
                .ok_or(format!("Could not get memory at address 0x{:x} for adding base address",
                    address))?;
            self.memory.set32(address, value.wrapping_add(elf.base_address() as u32))?;
        }

        let dynstrtab = elf.elf().dynstrtab;
        let dynsyms = elf.elf().dynsyms;
        let mut address = pltgot + elf.base_address() + (local_gotno * 4);
        for i in gotsym..(symtabno) {
            let sym = dynsyms.get(i as usize)
                .ok_or(format!("Could not get symbol {}", i))?;
            let symbol_name = dynstrtab.get(sym.st_name)
                .ok_or(format!("Could not get symbol name for {}", i))??;
            // Internal entries have already been relocated, so we only need to
            // relocate external entries
            if sym.st_shndx == 0 {
                if let Some(value) = self.symbols.get(symbol_name) {
                    self.memory.set32(address, *value as u32)?;

                    if symbol_name == "_rtld_global" {
                        println!("0x{:08x} symbol {} 0x{:08x} {:02} {} 0x{:x}",
                            address, i, sym.st_value, sym.st_shndx, symbol_name,
                            value);
                    }
                }
                else {
                    format!("Could not get symbol with name: \"{}\"",
                        symbol_name);
                }
            }
            address += 4;
        }

        // handle all relocation entries
        for dynrel in elf.elf().dynrels {
            if dynrel.r_type == goblin::elf::reloc::R_MIPS_REL32 {
                let value =
                    self.memory
                        .get32(dynrel.r_offset + elf.base_address())
                        .ok_or(format!("Could not load R_MIPS_REL32 at 0x{:x}",
                            dynrel.r_offset + elf.base_address()))?;
                self.memory.set32(
                    dynrel.r_offset + elf.base_address(),
                    value + (elf.base_address() as u32)
                )?;
            }
        }

        Ok(())
    }

    /// Inform the linker of a function at the given address.
    ///
    /// This function will be added to calls to `function_entries` and will be automatically
    /// lifted when calling `to_program`.
    pub fn add_user_function(&mut self, address: u64) {
        self.user_functions.push(address);
    }
}

impl Loader for ElfLinker {
    fn memory(&self) -> Result<Memory> {
        Ok(self.memory.clone())
    }

    fn function_entries(&self) -> Result<Vec<FunctionEntry>> {
        let mut function_entries = Vec::new();
        for loaded in &self.loaded {
            // let fe = loaded.1.function_entries()?;
            // for e in &fe {
            //     println!("{} 0x{:x}", loaded.0, e.address());
            // }
            function_entries.append(&mut loaded.1.function_entries()?);
        }
        for address in &self.user_functions {
            function_entries.push(FunctionEntry::new(*address, None));
        }
        Ok(function_entries)
    }

    // TODO Just maybe a bit too much unwrapping here.
    fn program_entry(&self) -> u64 {
        let filename = self.filename
                           .as_path()
                           .file_name()
                           .unwrap()
                           .to_str()
                           .unwrap();
        self.loaded[filename].program_entry()
    }

    fn architecture(&self) -> &Architecture {
        let filename = self.filename
                           .as_path()
                           .file_name()
                           .unwrap()
                           .to_str()
                           .unwrap();
        self.loaded[filename].architecture()
    }
}<commit_msg>Add ElfLinker::get_elf() and ElfLinker::get_interpreter()<commit_after>use architecture::*;
use goblin;
use loader::*;
use memory::backing::Memory;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};

/// The address where the first library will be loaded
const DEFAULT_LIB_BASE: u64 = 0x4000_0000;
/// The step in address between where we will load libraries.
const LIB_BASE_STEP: u64    = 0x0200_0000;

/// Loader which links together multiple Elf files.
///
/// Can do some rudimentary linking of binaries.
#[derive(Debug)]
pub struct ElfLinker {
    /// The filename (path included) of the file we're loading.
    filename: PathBuf,
    /// A mapping from lib name (for example `libc.so.6`) to Elf.
    loaded: BTreeMap<String, Elf>,
    /// The current memory mapping.
    memory: Memory,
    /// A mapping of function symbol names to addresses
    symbols: BTreeMap<String, u64>,
    /// The address we will place the next library at.
    next_lib_address: u64,
    /// Functions as specified by the user
    user_functions: Vec<u64>,
    /// If set, we will do relocations as we link
    do_relocations: bool
}

impl ElfLinker {
    /// Takes a path to an Elf and loads the Elf, its dependencies, and links
    /// them together.
    pub fn new(filename: &Path, do_relocations: bool) -> Result<ElfLinker> {
        let mut file = File::open(filename)?;
        let mut buf = Vec::new();
        file.read_to_end(&mut buf)?;

        // get the endianness of this elf for the memory model
        let mut endian = Endian::Big;
        if let goblin::Object::Elf(elf_peek) = goblin::Object::parse(&buf)? {
            if elf_peek.header.endianness()?.is_little() {
                endian = Endian::Little;
            }
        }
        else {
            bail!(format!("{} was not an Elf", filename.to_str().unwrap()));
        }

        let mut elf_linker = ElfLinker {
            filename: filename.to_owned(),
            loaded: BTreeMap::new(),
            memory: Memory::new(endian),
            symbols: BTreeMap::new(),
            next_lib_address: DEFAULT_LIB_BASE,
            user_functions: Vec::new(),
            do_relocations
        };

        elf_linker.load_elf(filename, 0)?;

        Ok(elf_linker)
    }

    /// Get the ELFs loaded and linked in this loader
    pub fn loaded(&self) -> &BTreeMap<String, Elf> {
        &self.loaded
    }

    /// Get the filename of the ELF we're loading
    pub fn filename(&self) -> &Path {
        &self.filename
    }

    /// Takes the path to an Elf, and a base address the Elf should be loaded
    /// at. Loads the Elf, all it's dependencies (DT_NEEDED), and then handles
    /// the supported relocations.
    pub fn load_elf(&mut self, filename: &Path, base_address: u64)
        -> Result<()> {

        // Does this file exist in the same directory as the original file?
        let mut base_path = match self.filename.as_path().parent() {
            Some(base_path) => base_path.to_path_buf(),
            None => PathBuf::new()
        };
        base_path.push(filename);

        let filename = if base_path.exists() {
            &base_path
        }
        else {
            filename
        };

        info!("Loading {} with base_address 0x{:x}",
            filename.to_str().unwrap(),
            base_address);
        let elf = Elf::from_file_with_base_address(filename, base_address)?;

        // Update our memory map based on what's in the Elf
        for (address, section) in elf.memory()?.sections() {
            self.memory.set_memory(*address,
                                   section.data().to_owned(),
                                   section.permissions());
        }

        // Add this Elf to the loaded Elfs
        let filename = filename.file_name()
                               .unwrap()
                               .to_str()
                               .unwrap()
                               .to_string();
        self.loaded.insert(filename.clone(), elf);

        {
            let ref elf = self.loaded[&filename];

            // Add its exported symbols to our symbols
            for symbol in elf.exported_symbols() {
                if self.symbols.get(symbol.name()).is_some() {
                    continue;
                }
                self.symbols.insert(
                    symbol.name().to_string(),
                    elf.base_address() + symbol.address()
                );
            }
        }

        // Ensure all shared objects we rely on are loaded
        for so_name in self.loaded[&filename].dt_needed()?.clone() {
            if self.loaded.get(&so_name).is_none() {
                self.next_lib_address += LIB_BASE_STEP;
                let next_lib_address = self.next_lib_address;
                self.load_elf(Path::new(&so_name), next_lib_address)?;
            }
        }

        if self.do_relocations {
            match self.loaded[&filename].elf().header.e_machine {
                goblin::elf::header::EM_386 =>
                    self.relocations_x86(&filename)?,
                goblin::elf::header::EM_MIPS =>
                    self.relocations_mips(&filename)?,
                _ => bail!("relocations unsupported for target architecture")
            }
        }

        Ok(())
    }

    /// Get the `Elf` for the primary elf loaded.
    pub fn get_elf(&self) -> Result<&Elf> {
        let loaded = self.loaded();
        let filename = self.filename()
            .file_name()
            .and_then(|filename| filename.to_str())
            .ok_or("Could not get filename for ElfLinker's primary program")?;

        let elf = loaded.get(filename)
              .ok_or(format!("Could not get {} from ElfLinker", filename))?;

        Ok(elf)
    }

    /// If the primary `Elf` we're loading has an interpreter designated in its
    /// dynamic sectino, get the `Elf` for the interpreter.
    pub fn get_interpreter(&self) -> Result<Option<&Elf>> {
        let elf = self.get_elf()?;

        let interpreter_elf = match elf.elf().interpreter {
            Some(interpreter_filename) => {
                let interpreter_filename =
                    Path::new(interpreter_filename)
                        .file_name()
                        .and_then(|filename| filename.to_str())
                        .ok_or(format!("Failed to get filename portion of interpreter filename"))?;
                Some(self.loaded().get(interpreter_filename)
                    .ok_or(format!("Could not find interpreter {}",
                                    interpreter_filename))?)
            }
            None => None
        };

        Ok(interpreter_elf)
    }

    /// Perform x86-specific relocations
    fn relocations_x86(&mut self, filename: &str) -> Result<()> {
        // Process relocations
        let ref elf = self.loaded[filename];
        let dynsyms = elf.elf().dynsyms;
        let dynstrtab = elf.elf().dynstrtab;
        for reloc in elf.elf().dynrelas.iter().chain(
            elf.elf().dynrels.iter().chain(
                elf.elf().pltrelocs.iter())) {
            match reloc.r_type {
                goblin::elf::reloc::R_386_32 => {
                    let ref sym = dynsyms.get(reloc.r_sym)
                        .expect("Unable to resolve relocation symbol");
                    let sym_name = &dynstrtab[sym.st_name];
                    let value = match self.symbols.get(sym_name) {
                        Some(v) => v.to_owned() as u32,
                        None => bail!("Could not resolve symbol {}", sym_name)
                    };
                    self.memory.set32(
                        reloc.r_offset as u64 + elf.base_address(),
                        value
                    )?;
                }
                goblin::elf::reloc::R_386_GOT32 => {
                    bail!("R_386_GOT32");
                },
                goblin::elf::reloc::R_386_PLT32 => {
                    let ref sym = dynsyms.get(reloc.r_sym)
                        .expect("Unable to resolve relocation symbol");
                    let sym_name = &dynstrtab[sym.st_name];
                    bail!("R_386_PLT32 {:?}:0x{:x}:{}",
                          self.filename,
                          reloc.r_offset,
                          sym_name);
                },
                goblin::elf::reloc::R_386_COPY => {
                    bail!("R_386_COPY");
                },
                goblin::elf::reloc::R_386_GLOB_DAT => {
                    let ref sym = dynsyms.get(reloc.r_sym)
                        .expect("Unable to resolve relocation symbol");
                    let sym_name = &dynstrtab[sym.st_name];
                    let value = match self.symbols.get(sym_name) {
                        Some(v) => v.to_owned() as u32,
                        None => {
                            warn!("Could not resolve symbol {}", sym_name);
                            continue
                        }
                    };
                    self.memory.set32(
                        reloc.r_offset as u64 + elf.base_address(),
                        value
                    )?;
                },
                goblin::elf::reloc::R_386_JMP_SLOT => {
                    let ref sym = dynsyms.get(reloc.r_sym)
                        .expect("Unable to resolve relocation symbol");
                    let sym_name = &dynstrtab[sym.st_name];
                    let value = match self.symbols.get(sym_name) {
                        Some(v) => v.to_owned() as u32,
                        None => bail!("Could not resolve symbol {}", sym_name)
                    };
                    self.memory.set32(
                        reloc.r_offset as u64 + elf.base_address(),
                        value
                    )?;
                },
                goblin::elf::reloc::R_386_RELATIVE => {
                    let value = self.memory.get32(reloc.r_offset as u64 + elf.base_address());
                    let value = match value {
                        Some(value) => elf.base_address() as u32 + value,
                        None => bail!("Invalid address for R_386_RELATIVE {:?}:{:x}",
                                      self.filename,
                                      reloc.r_offset)
                    };
                    self.memory.set32(reloc.r_offset as u64 + elf.base_address(), value)?;
                },
                goblin::elf::reloc::R_386_GOTPC => {
                    bail!("R_386_GOT_PC");
                },
                goblin::elf::reloc::R_386_TLS_TPOFF => {
                    warn!("Ignoring R_386_TLS_TPOFF Relocation");
                },
                goblin::elf::reloc::R_386_IRELATIVE => {
                    warn!("R_386_IRELATIVE {:?}:0x{:x} going unprocessed",
                          self.filename,
                          reloc.r_offset);
                }
                _ => bail!("unhandled relocation type {}", reloc.r_type)
            }
        }
        Ok(())
    }

    /// Perform MIPS-specific relocations
    fn relocations_mips(&mut self, filename: &str) -> Result<()> {
        let elf = &self.loaded[filename];

        fn get_dynamic(elf: &Elf, tag: u64) -> Option<u64> {
            elf.elf().dynamic.and_then(|dynamic|
                dynamic.dyns
                    .iter()
                    .find(|dyn| dyn.d_tag == tag)
                    .map(|dyn| dyn.d_val))
        }

        // The number of local GOT entries. Also an index into the GOT
        // for the first external GOT entry.
        let local_gotno =
            get_dynamic(elf, goblin::elf::dyn::DT_MIPS_LOCAL_GOTNO)
            .ok_or("Could not get DT_MIPS_LOCAL_GOTNO")?;

        // Index of the first dynamic symbol table entry that corresponds
        // to an entry in the GOT.
        let gotsym =
            get_dynamic(elf, goblin::elf::dyn::DT_MIPS_GOTSYM)
            .ok_or("Could not get DT_MIPS_GOTSYM")?;

        // The number of entries in the dynamic symbol table
        let symtabno =
            get_dynamic(elf, goblin::elf::dyn::DT_MIPS_SYMTABNO)
            .ok_or("Could not get DT_MIPS_SYMTABNO")?;

        // The address of the GOT section
        let pltgot =
            get_dynamic(elf, goblin::elf::dyn::DT_PLTGOT)
            .ok_or("Could not get DT_PLTGOT")?;

        // Start by adding the base address to all entries in the GOT
        for i in 0..(local_gotno + (symtabno - gotsym)) {
            let address = elf.base_address() + (i * 4) + pltgot;
            let value = self.memory.get32(address)
                .ok_or(format!("Could not get memory at address 0x{:x} for adding base address",
                    address))?;
            self.memory.set32(address, value.wrapping_add(elf.base_address() as u32))?;
        }

        let dynstrtab = elf.elf().dynstrtab;
        let dynsyms = elf.elf().dynsyms;
        let mut address = pltgot + elf.base_address() + (local_gotno * 4);
        for i in gotsym..(symtabno) {
            let sym = dynsyms.get(i as usize)
                .ok_or(format!("Could not get symbol {}", i))?;
            let symbol_name = dynstrtab.get(sym.st_name)
                .ok_or(format!("Could not get symbol name for {}", i))??;
            // Internal entries have already been relocated, so we only need to
            // relocate external entries
            if sym.st_shndx == 0 {
                if let Some(value) = self.symbols.get(symbol_name) {
                    self.memory.set32(address, *value as u32)?;

                    if symbol_name == "_rtld_global" {
                        println!("0x{:08x} symbol {} 0x{:08x} {:02} {} 0x{:x}",
                            address, i, sym.st_value, sym.st_shndx, symbol_name,
                            value);
                    }
                }
                else {
                    format!("Could not get symbol with name: \"{}\"",
                        symbol_name);
                }
            }
            address += 4;
        }

        // handle all relocation entries
        for dynrel in elf.elf().dynrels {
            if dynrel.r_type == goblin::elf::reloc::R_MIPS_REL32 {
                let value =
                    self.memory
                        .get32(dynrel.r_offset + elf.base_address())
                        .ok_or(format!("Could not load R_MIPS_REL32 at 0x{:x}",
                            dynrel.r_offset + elf.base_address()))?;
                self.memory.set32(
                    dynrel.r_offset + elf.base_address(),
                    value + (elf.base_address() as u32)
                )?;
            }
        }

        Ok(())
    }

    /// Inform the linker of a function at the given address.
    ///
    /// This function will be added to calls to `function_entries` and will be automatically
    /// lifted when calling `to_program`.
    pub fn add_user_function(&mut self, address: u64) {
        self.user_functions.push(address);
    }
}

impl Loader for ElfLinker {
    fn memory(&self) -> Result<Memory> {
        Ok(self.memory.clone())
    }

    fn function_entries(&self) -> Result<Vec<FunctionEntry>> {
        let mut function_entries = Vec::new();
        for loaded in &self.loaded {
            // let fe = loaded.1.function_entries()?;
            // for e in &fe {
            //     println!("{} 0x{:x}", loaded.0, e.address());
            // }
            function_entries.append(&mut loaded.1.function_entries()?);
        }
        for address in &self.user_functions {
            function_entries.push(FunctionEntry::new(*address, None));
        }
        Ok(function_entries)
    }

    // TODO Just maybe a bit too much unwrapping here.
    fn program_entry(&self) -> u64 {
        let filename = self.filename
                           .as_path()
                           .file_name()
                           .unwrap()
                           .to_str()
                           .unwrap();
        self.loaded[filename].program_entry()
    }

    fn architecture(&self) -> &Architecture {
        let filename = self.filename
                           .as_path()
                           .file_name()
                           .unwrap()
                           .to_str()
                           .unwrap();
        self.loaded[filename].architecture()
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2016 Tibor Benke <ihrwein@gmail.com>
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use config::ContextConfig;
use serde::de::{Deserialize, Deserializer, MapVisitor, Error, Visitor};

use handlebars::Template;
use uuid::Uuid;

const FIELDS: &'static [&'static str] = &["name", "uuid", "conditions", "actions"];

impl Deserialize for ContextConfig {
    fn deserialize<D>(deserializer: &mut D) -> Result<ContextConfig, D::Error>
        where D: Deserializer
    {
        deserializer.visit_struct("Context", FIELDS, ContextVisitor)
    }
}

enum Field {
    Name,
    Uuid,
    Conditions,
    ContextId,
    Actions,
}

impl Deserialize for Field {
    fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
        where D: Deserializer
    {
        struct FieldVisitor;

        impl Visitor for FieldVisitor {
            type Value = Field;

            fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
                where E: Error
            {
                match value {
                    "name" => Ok(Field::Name),
                    "uuid" => Ok(Field::Uuid),
                    "conditions" => Ok(Field::Conditions),
                    "context_id" => Ok(Field::ContextId),
                    "actions" => Ok(Field::Actions),
                    _ => Err(Error::syntax(&format!("Unexpected field: {}", value))),
                }
            }
        }

        deserializer.visit(FieldVisitor)
    }
}

struct ContextVisitor;

impl ContextVisitor {
    fn parse_uuid<V>(uuid: Option<String>) -> Result<Uuid, V::Error>
        where V: MapVisitor
    {
        match uuid {
            Some(value) => {
                match Uuid::parse_str(&value) {
                    Ok(uuid) => Ok(uuid),
                    Err(err) => {
                        Err(Error::syntax(&format!("Failed to parse field 'uuid': uuid={} \
                                                    error={}",
                                                   value,
                                                   err)))
                    }
                }
            }
            None => Err(Error::missing_field("uuid")),
        }
    }

    fn deser_context_id<V>(context_id: Option<String>,
                           uuid: &Uuid)
                           -> Result<Option<Template>, V::Error>
        where V: MapVisitor
    {
        if let Some(context_id) = context_id {
            ContextVisitor::parse_context_id::<V>(context_id, uuid)
        } else {
            Ok(None)
        }
    }

    fn parse_context_id<V>(context_id: String, uuid: &Uuid) -> Result<Option<Template>, V::Error>
        where V: MapVisitor
    {
        match Template::compile(context_id) {
            Ok(context_id) => Ok(Some(context_id)),
            Err(err) => {
                let errmsg = format!("Invalid handlebars template in 'context_id' field: uuid={} \
                                      error={}",
                                     uuid,
                                     err);
                Err(Error::syntax(&errmsg))
            }
        }
    }
}

impl Visitor for ContextVisitor {
    type Value = ContextConfig;

    fn visit_map<V>(&mut self, mut visitor: V) -> Result<ContextConfig, V::Error>
        where V: MapVisitor
    {
        let mut name = None;
        let mut uuid: Option<String> = None;
        let mut conditions = None;
        let mut context_id: Option<String> = None;
        let mut actions = None;

        while let Some(field) = try!(visitor.visit_key()) {
            match field {
                Field::Name => name = Some(try!(visitor.visit_value())),
                Field::Uuid => uuid = Some(try!(visitor.visit_value())),
                Field::Conditions => conditions = Some(try!(visitor.visit_value())),
                Field::ContextId => context_id = Some(try!(visitor.visit_value())),
                Field::Actions => actions = Some(try!(visitor.visit_value())),
            }
        }

        let uuid = try!(ContextVisitor::parse_uuid::<V>(uuid));
        let context_id = try!(ContextVisitor::deser_context_id::<V>(context_id, &uuid));
        let actions = actions.unwrap_or_default();

        try!(visitor.end());

        Ok(ContextConfig {
            name: name,
            uuid: uuid,
            conditions: conditions.unwrap(),
            context_id: context_id,
            actions: actions,
        })
    }
}

#[cfg(test)]
mod test {
    use config::action::{ActionType, ExecCondition};
    use config::action::message::MessageActionBuilder;
    use conditions::ConditionsBuilder;
    use config::ContextConfig;
    use handlebars::Template;
    use serde_json::from_str;
    use uuid::Uuid;
    use std::time::Duration;

    #[test]
    fn test_given_config_context_when_it_is_deserialized_then_we_get_the_right_results() {
        let text = r#"
        {
            "name": "TEST_NAME",
            "uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "conditions": {
                "timeout": 100,
                "first_opens": true,
                "patterns": [
                    "PATTERN_NAME1",
                    "PATTERN_NAME2",
                    "f13dafee-cd14-4dda-995c-6ed476a21de3"
                ]
            },
            "actions": [
                {
                    "message": {
                        "uuid": "uuid1",
                        "when": {
                            "on_closed": true,
                            "on_opened": false
                        },
                        "message": "message"
                    }
                }
            ]
        }
        "#;

        let result = from_str::<ContextConfig>(text);
        let expected_name = "TEST_NAME".to_owned();
        let expected_uuid = Uuid::parse_str("86ca9f93-84fb-4813-b037-6526f7a585a3").ok().unwrap();
        let expected_conditions = ConditionsBuilder::new(Duration::from_millis(100))
                                      .first_opens(true)
                                      .patterns(vec!["PATTERN_NAME1".to_owned(),
                                                     "PATTERN_NAME2".to_owned(),
                                                     "f13dafee-cd14-4dda-995c-6ed476a21de3"
                                                         .to_owned()])
                                      .build();
        let message = Template::compile("message".to_owned())
                          .expect("Failed to compile a handlebars template");
        let expected_exec_cond = ExecCondition {
            on_opened: false,
            on_closed: true,
        };
        let expected_actions = vec![ActionType::Message(MessageActionBuilder::new("uuid1",
                                                                                message)
                                                            .when(expected_exec_cond)
                                                            .build())];
        let context = result.expect("Failed to deserialize a valid ContextConfig");
        assert_eq!(&Some(expected_name), &context.name);
        assert_eq!(&expected_uuid, &context.uuid);
        assert_eq!(&expected_conditions, &context.conditions);
        assert_eq!(&expected_actions.len(), &context.actions.len());
    }

    #[test]
    fn test_given_config_context_when_it_does_not_have_uuid_then_it_cannot_be_deserialized() {
        let text = r#"{ "conditions": { "timeout": 100 }}"#;
        let result = from_str::<ContextConfig>(text);
        let _ = result.err()
                      .expect("Successfully deserialized a config context without an uuid key");
    }

    #[test]
    fn test_given_config_context_when_it_contains_an_unknown_key_then_it_cannot_be_deserialized
        () {
        let text = r#"
            {"uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "conditions": { "timeout": 100},
            "unknown": "unknown" }"#;
        let result = from_str::<ContextConfig>(text);
        let _ = result.err()
                      .expect("Successfully deserialized a config context with an unknown key");
    }

    #[test]
    fn test_given_config_context_when_it_is_deserialized_and_only_the_required_fields_are_present_then_we_can_deserialize_it_successfully
        () {
        let text = r#"
        {
            "uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "conditions": {
                "timeout": 100
            }
        }
        "#;

        let result = from_str::<ContextConfig>(text);
        let expected_uuid = Uuid::parse_str("86ca9f93-84fb-4813-b037-6526f7a585a3").ok().unwrap();
        let expected_conditions = ConditionsBuilder::new(Duration::from_millis(100)).build();
        let context = result.expect("Failed to deserialize a valid ContextConfig");
        assert_eq!(&expected_uuid, &context.uuid);
        assert_eq!(&expected_conditions, &context.conditions);
    }

    #[test]
    fn test_given_config_context_when_it_is_deserialized_and_the_uuid_is_invalid_then_we_report_an_error
        () {
        let text = r#"
        {
            "uuid": "this is an invalid uuid",
            "conditions": {
                "timeout": 100
            }
        }
        "#;

        let result = from_str::<ContextConfig>(text);
        let _ = result.err()
                      .expect("Successfully deserialized an invalid ContextConfig (UUID is \
                               invalid)");
    }

    #[test]
    fn test_given_config_context_when_it_contains_context_id_then_can_be_deserialized() {
        let text = r#"
        {
            "uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "context_id": "{{HOST}}{{PROGRAM}}",
            "conditions": {
                "timeout": 100
            }
        }
        "#;
        let expected_context_id = "{{HOST}}{{PROGRAM}}".to_owned();
        let result = from_str::<ContextConfig>(text);
        let context = result.expect("Failed to deserialize a valid ContextConfig");
        assert_eq!(&expected_context_id,
                   &context.context_id.as_ref().unwrap().to_string());
    }

    #[test]
    fn test_given_config_context_when_the_context_id_is_invalid_template_then_the_config_cannot_be_deserialized() {
        let text = r#"
        {
            "uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "context_id": "{invalid}}",
            "conditions": {
                "timeout": 100
            }
        }"#;

        let result = from_str::<ContextConfig>(text);
        let _ = result.err().unwrap();
    }
}
<commit_msg>ContextConfig: update deser logic to use the patterns field<commit_after>// Copyright (c) 2016 Tibor Benke <ihrwein@gmail.com>
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use config::ContextConfig;
use serde::de::{Deserialize, Deserializer, MapVisitor, Error, Visitor};

use handlebars::Template;
use uuid::Uuid;

const FIELDS: &'static [&'static str] = &["name", "uuid", "conditions", "actions"];

impl Deserialize for ContextConfig {
    fn deserialize<D>(deserializer: &mut D) -> Result<ContextConfig, D::Error>
        where D: Deserializer
    {
        deserializer.visit_struct("Context", FIELDS, ContextVisitor)
    }
}

enum Field {
    Name,
    Uuid,
    Conditions,
    ContextId,
    Actions,
    Patterns,
}

impl Deserialize for Field {
    fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
        where D: Deserializer
    {
        struct FieldVisitor;

        impl Visitor for FieldVisitor {
            type Value = Field;

            fn visit_str<E>(&mut self, value: &str) -> Result<Field, E>
                where E: Error
            {
                match value {
                    "name" => Ok(Field::Name),
                    "uuid" => Ok(Field::Uuid),
                    "conditions" => Ok(Field::Conditions),
                    "context_id" => Ok(Field::ContextId),
                    "actions" => Ok(Field::Actions),
                    "patterns" => Ok(Field::Patterns),
                    _ => Err(Error::syntax(&format!("Unexpected field: {}", value))),
                }
            }
        }

        deserializer.visit(FieldVisitor)
    }
}

struct ContextVisitor;

impl ContextVisitor {
    fn parse_uuid<V>(uuid: Option<String>) -> Result<Uuid, V::Error>
        where V: MapVisitor
    {
        match uuid {
            Some(value) => {
                match Uuid::parse_str(&value) {
                    Ok(uuid) => Ok(uuid),
                    Err(err) => {
                        Err(Error::syntax(&format!("Failed to parse field 'uuid': uuid={} \
                                                    error={}",
                                                   value,
                                                   err)))
                    }
                }
            }
            None => Err(Error::missing_field("uuid")),
        }
    }

    fn deser_context_id<V>(context_id: Option<String>,
                           uuid: &Uuid)
                           -> Result<Option<Template>, V::Error>
        where V: MapVisitor
    {
        if let Some(context_id) = context_id {
            ContextVisitor::parse_context_id::<V>(context_id, uuid)
        } else {
            Ok(None)
        }
    }

    fn parse_context_id<V>(context_id: String, uuid: &Uuid) -> Result<Option<Template>, V::Error>
        where V: MapVisitor
    {
        match Template::compile(context_id) {
            Ok(context_id) => Ok(Some(context_id)),
            Err(err) => {
                let errmsg = format!("Invalid handlebars template in 'context_id' field: uuid={} \
                                      error={}",
                                     uuid,
                                     err);
                Err(Error::syntax(&errmsg))
            }
        }
    }
}

impl Visitor for ContextVisitor {
    type Value = ContextConfig;

    fn visit_map<V>(&mut self, mut visitor: V) -> Result<ContextConfig, V::Error>
        where V: MapVisitor
    {
        let mut name = None;
        let mut uuid: Option<String> = None;
        let mut conditions = None;
        let mut context_id: Option<String> = None;
        let mut actions = None;
        let mut patterns = None;

        while let Some(field) = try!(visitor.visit_key()) {
            match field {
                Field::Name => name = Some(try!(visitor.visit_value())),
                Field::Uuid => uuid = Some(try!(visitor.visit_value())),
                Field::Conditions => conditions = Some(try!(visitor.visit_value())),
                Field::ContextId => context_id = Some(try!(visitor.visit_value())),
                Field::Actions => actions = Some(try!(visitor.visit_value())),
                Field::Patterns => patterns = Some(try!(visitor.visit_value())),
            }
        }

        let uuid = try!(ContextVisitor::parse_uuid::<V>(uuid));
        let context_id = try!(ContextVisitor::deser_context_id::<V>(context_id, &uuid));
        let actions = actions.unwrap_or_default();

        try!(visitor.end());

        Ok(ContextConfig {
            name: name,
            uuid: uuid,
            conditions: conditions.unwrap(),
            context_id: context_id,
            actions: actions,
            patterns: patterns.unwrap_or_default()
        })
    }
}

#[cfg(test)]
mod test {
    use config::action::{ActionType, ExecCondition};
    use config::action::message::MessageActionBuilder;
    use conditions::ConditionsBuilder;
    use config::ContextConfig;
    use handlebars::Template;
    use serde_json::from_str;
    use uuid::Uuid;
    use std::time::Duration;

    #[test]
    fn test_given_config_context_when_it_is_deserialized_then_we_get_the_right_results() {
        let text = r#"
        {
            "name": "TEST_NAME",
            "uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "conditions": {
                "timeout": 100,
                "first_opens": true,
                "patterns": [
                    "PATTERN_NAME1",
                    "PATTERN_NAME2",
                    "f13dafee-cd14-4dda-995c-6ed476a21de3"
                ]
            },
            "actions": [
                {
                    "message": {
                        "uuid": "uuid1",
                        "when": {
                            "on_closed": true,
                            "on_opened": false
                        },
                        "message": "message"
                    }
                }
            ]
        }
        "#;

        let result = from_str::<ContextConfig>(text);
        let expected_name = "TEST_NAME".to_owned();
        let expected_uuid = Uuid::parse_str("86ca9f93-84fb-4813-b037-6526f7a585a3").ok().unwrap();
        let expected_conditions = ConditionsBuilder::new(Duration::from_millis(100))
                                      .first_opens(true)
                                      .patterns(vec!["PATTERN_NAME1".to_owned(),
                                                     "PATTERN_NAME2".to_owned(),
                                                     "f13dafee-cd14-4dda-995c-6ed476a21de3"
                                                         .to_owned()])
                                      .build();
        let message = Template::compile("message".to_owned())
                          .expect("Failed to compile a handlebars template");
        let expected_exec_cond = ExecCondition {
            on_opened: false,
            on_closed: true,
        };
        let expected_actions = vec![ActionType::Message(MessageActionBuilder::new("uuid1",
                                                                                message)
                                                            .when(expected_exec_cond)
                                                            .build())];
        let context = result.expect("Failed to deserialize a valid ContextConfig");
        assert_eq!(&Some(expected_name), &context.name);
        assert_eq!(&expected_uuid, &context.uuid);
        assert_eq!(&expected_conditions, &context.conditions);
        assert_eq!(&expected_actions.len(), &context.actions.len());
    }

    #[test]
    fn test_given_config_context_when_it_does_not_have_uuid_then_it_cannot_be_deserialized() {
        let text = r#"{ "conditions": { "timeout": 100 }}"#;
        let result = from_str::<ContextConfig>(text);
        let _ = result.err()
                      .expect("Successfully deserialized a config context without an uuid key");
    }

    #[test]
    fn test_given_config_context_when_it_contains_an_unknown_key_then_it_cannot_be_deserialized
        () {
        let text = r#"
            {"uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "conditions": { "timeout": 100},
            "unknown": "unknown" }"#;
        let result = from_str::<ContextConfig>(text);
        let _ = result.err()
                      .expect("Successfully deserialized a config context with an unknown key");
    }

    #[test]
    fn test_given_config_context_when_it_is_deserialized_and_only_the_required_fields_are_present_then_we_can_deserialize_it_successfully
        () {
        let text = r#"
        {
            "uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "conditions": {
                "timeout": 100
            }
        }
        "#;

        let result = from_str::<ContextConfig>(text);
        let expected_uuid = Uuid::parse_str("86ca9f93-84fb-4813-b037-6526f7a585a3").ok().unwrap();
        let expected_conditions = ConditionsBuilder::new(Duration::from_millis(100)).build();
        let context = result.expect("Failed to deserialize a valid ContextConfig");
        assert_eq!(&expected_uuid, &context.uuid);
        assert_eq!(&expected_conditions, &context.conditions);
    }

    #[test]
    fn test_given_config_context_when_it_is_deserialized_and_the_uuid_is_invalid_then_we_report_an_error
        () {
        let text = r#"
        {
            "uuid": "this is an invalid uuid",
            "conditions": {
                "timeout": 100
            }
        }
        "#;

        let result = from_str::<ContextConfig>(text);
        let _ = result.err()
                      .expect("Successfully deserialized an invalid ContextConfig (UUID is \
                               invalid)");
    }

    #[test]
    fn test_given_config_context_when_it_contains_context_id_then_can_be_deserialized() {
        let text = r#"
        {
            "uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "context_id": "{{HOST}}{{PROGRAM}}",
            "conditions": {
                "timeout": 100
            }
        }
        "#;
        let expected_context_id = "{{HOST}}{{PROGRAM}}".to_owned();
        let result = from_str::<ContextConfig>(text);
        let context = result.expect("Failed to deserialize a valid ContextConfig");
        assert_eq!(&expected_context_id,
                   &context.context_id.as_ref().unwrap().to_string());
    }

    #[test]
    fn test_given_config_context_when_the_context_id_is_invalid_template_then_the_config_cannot_be_deserialized() {
        let text = r#"
        {
            "uuid": "86ca9f93-84fb-4813-b037-6526f7a585a3",
            "context_id": "{invalid}}",
            "conditions": {
                "timeout": 100
            }
        }"#;

        let result = from_str::<ContextConfig>(text);
        let _ = result.err().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate regex;

include!("../clap-test.rs");

use clap::{App, Arg, ArgGroup, ErrorKind};

static REQ_GROUP_USAGE: &'static str = "error: The following required arguments were not provided:
    <base|--delete>

USAGE:
    clap-test <base|--delete>

For more information try --help";

static REQ_GROUP_CONFLICT_USAGE: &'static str = "error: The argument '<base>' cannot be used with '--delete'

USAGE:
    clap-test <base|--delete>

For more information try --help";

static REQ_GROUP_CONFLICT_REV: &'static str = "error: The argument '--delete' cannot be used with 'base'

USAGE:
    clap-test <base|--delete>

For more information try --help";

#[test]
fn required_group_missing_arg() {
    let result = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color 'some other flag'")
        .group(ArgGroup::with_name("req")
            .args(&["flag", "color"])
            .required(true))
        .get_matches_from_safe(vec![""]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}

#[test]
fn group_single_value() {
    let m = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color [color] 'some option'")
        .group(ArgGroup::with_name("grp")
            .args(&["flag", "color"]))
        .get_matches_from(vec!["", "-c", "blue"]);
    assert!(m.is_present("grp"));
    assert_eq!(m.value_of("grp").unwrap(), "blue");
}

#[test]
fn group_single_flag() {
    let m = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color [color] 'some option'")
        .group(ArgGroup::with_name("grp")
            .args(&["flag", "color"]))
        .get_matches_from(vec!["", "-f"]);
    assert!(m.is_present("grp"));
    assert!(m.value_of("grp").is_none());
}

#[test]
fn group_empty() {
    let m = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color [color] 'some option'")
        .group(ArgGroup::with_name("grp")
            .args(&["flag", "color"]))
        .get_matches_from(vec![""]);
    assert!(!m.is_present("grp"));
    assert!(m.value_of("grp").is_none());
}

#[test]
fn group_reqired_flags_empty() {
    let result = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color 'some option'")
        .group(ArgGroup::with_name("grp")
            .required(true)
            .args(&["flag", "color"]))
        .get_matches_from_safe(vec![""]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}

#[test]
fn group_multi_value_single_arg() {
    let m = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color [color]... 'some option'")
        .group(ArgGroup::with_name("grp")
            .args(&["flag", "color"]))
        .get_matches_from(vec!["", "-c", "blue", "red", "green"]);
    assert!(m.is_present("grp"));
    assert_eq!(&*m.values_of("grp").unwrap().collect::<Vec<_>>(), &["blue", "red", "green"]);
}

#[test]
fn empty_group() {
    let r = App::new("empty_group")
        .arg(Arg::from_usage("-f, --flag 'some flag'"))
        .group(ArgGroup::with_name("vers")
            .required(true))
        .get_matches_from_safe(vec!["empty_prog"]);
    assert!(r.is_err());
    let err = r.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}

#[test]
fn req_group_usage_string() {
    let app = App::new("req_group")
        .args_from_usage("[base] 'Base commit'
                          -d, --delete 'Remove the base commit information'")
        .group(ArgGroup::with_name("base_or_delete")
            .args(&["base", "delete"])
            .required(true));

    assert!(test::compare_output(app, "clap-test", REQ_GROUP_USAGE, true));
}

#[test]
fn req_group_with_conflict_usage_string() {
    let app = App::new("req_group")
        .arg(Arg::from_usage("[base] 'Base commit'").conflicts_with("delete"))
        .arg(Arg::from_usage("-d, --delete 'Remove the base commit information'"))
        .group(ArgGroup::with_name("base_or_delete")
            .args(&["base", "delete"])
            .required(true));

    assert!(test::compare_output(app, "clap-test --delete base", REQ_GROUP_CONFLICT_REV, true));
}

#[test]
fn req_group_with_conflict_rev_usage_string() {
    let app = App::new("req_group")
        .arg(Arg::from_usage("[base] 'Base commit'").conflicts_with("delete"))
        .arg(Arg::from_usage("-d, --delete 'Remove the base commit information'"))
        .group(ArgGroup::with_name("base_or_delete")
            .args(&["base", "delete"])
            .required(true));

    assert!(test::compare_output(app, "clap-test base --delete", REQ_GROUP_CONFLICT_USAGE, true));
}

#[test]
fn required_group_multiple_args() {
    let result = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color 'some other flag'")
        .group(ArgGroup::with_name("req")
            .args(&["flag", "color"])
            .required(true)
            .multiple(true))
        .get_matches_from_safe(vec!["group", "-f", "-c"]);
    assert!(result.is_ok());
    let m = result.unwrap();
    assert!(m.is_present("flag"));
    assert!(m.is_present("color"));
}

#[test]
fn group_multiple_args_error() {
    let result = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color 'some other flag'")
        .group(ArgGroup::with_name("req")
            .args(&["flag", "color"]))
        .get_matches_from_safe(vec!["group", "-f", "-c"]);
    assert!(result.is_err());
    let err = result.unwrap_err();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}
<commit_msg>tests: adds a test where a non-existing arg is added to a group to ensure a failed debug assertion<commit_after>extern crate clap;
extern crate regex;

include!("../clap-test.rs");

use clap::{App, Arg, ArgGroup, ErrorKind};

static REQ_GROUP_USAGE: &'static str = "error: The following required arguments were not provided:
    <base|--delete>

USAGE:
    clap-test <base|--delete>

For more information try --help";

static REQ_GROUP_CONFLICT_USAGE: &'static str = "error: The argument '<base>' cannot be used with '--delete'

USAGE:
    clap-test <base|--delete>

For more information try --help";

static REQ_GROUP_CONFLICT_REV: &'static str = "error: The argument '--delete' cannot be used with 'base'

USAGE:
    clap-test <base|--delete>

For more information try --help";

#[test]
fn required_group_missing_arg() {
    let result = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color 'some other flag'")
        .group(ArgGroup::with_name("req")
            .args(&["flag", "color"])
            .required(true))
        .get_matches_from_safe(vec![""]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}

#[test]
#[should_panic]
fn non_existing_arg() {
    let _ = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color 'some other flag'")
        .group(ArgGroup::with_name("req")
            .args(&["flg", "color"])
            .required(true))
        .get_matches_from_safe(vec![""]);
}

#[test]
fn group_single_value() {
    let m = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color [color] 'some option'")
        .group(ArgGroup::with_name("grp")
            .args(&["flag", "color"]))
        .get_matches_from(vec!["", "-c", "blue"]);
    assert!(m.is_present("grp"));
    assert_eq!(m.value_of("grp").unwrap(), "blue");
}

#[test]
fn group_single_flag() {
    let m = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color [color] 'some option'")
        .group(ArgGroup::with_name("grp")
            .args(&["flag", "color"]))
        .get_matches_from(vec!["", "-f"]);
    assert!(m.is_present("grp"));
    assert!(m.value_of("grp").is_none());
}

#[test]
fn group_empty() {
    let m = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color [color] 'some option'")
        .group(ArgGroup::with_name("grp")
            .args(&["flag", "color"]))
        .get_matches_from(vec![""]);
    assert!(!m.is_present("grp"));
    assert!(m.value_of("grp").is_none());
}

#[test]
fn group_reqired_flags_empty() {
    let result = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color 'some option'")
        .group(ArgGroup::with_name("grp")
            .required(true)
            .args(&["flag", "color"]))
        .get_matches_from_safe(vec![""]);
    assert!(result.is_err());
    let err = result.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}

#[test]
fn group_multi_value_single_arg() {
    let m = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color [color]... 'some option'")
        .group(ArgGroup::with_name("grp")
            .args(&["flag", "color"]))
        .get_matches_from(vec!["", "-c", "blue", "red", "green"]);
    assert!(m.is_present("grp"));
    assert_eq!(&*m.values_of("grp").unwrap().collect::<Vec<_>>(), &["blue", "red", "green"]);
}

#[test]
fn empty_group() {
    let r = App::new("empty_group")
        .arg(Arg::from_usage("-f, --flag 'some flag'"))
        .group(ArgGroup::with_name("vers")
            .required(true))
        .get_matches_from_safe(vec!["empty_prog"]);
    assert!(r.is_err());
    let err = r.err().unwrap();
    assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
}

#[test]
fn req_group_usage_string() {
    let app = App::new("req_group")
        .args_from_usage("[base] 'Base commit'
                          -d, --delete 'Remove the base commit information'")
        .group(ArgGroup::with_name("base_or_delete")
            .args(&["base", "delete"])
            .required(true));

    assert!(test::compare_output(app, "clap-test", REQ_GROUP_USAGE, true));
}

#[test]
fn req_group_with_conflict_usage_string() {
    let app = App::new("req_group")
        .arg(Arg::from_usage("[base] 'Base commit'").conflicts_with("delete"))
        .arg(Arg::from_usage("-d, --delete 'Remove the base commit information'"))
        .group(ArgGroup::with_name("base_or_delete")
            .args(&["base", "delete"])
            .required(true));

    assert!(test::compare_output(app, "clap-test --delete base", REQ_GROUP_CONFLICT_REV, true));
}

#[test]
fn req_group_with_conflict_rev_usage_string() {
    let app = App::new("req_group")
        .arg(Arg::from_usage("[base] 'Base commit'").conflicts_with("delete"))
        .arg(Arg::from_usage("-d, --delete 'Remove the base commit information'"))
        .group(ArgGroup::with_name("base_or_delete")
            .args(&["base", "delete"])
            .required(true));

    assert!(test::compare_output(app, "clap-test base --delete", REQ_GROUP_CONFLICT_USAGE, true));
}

#[test]
fn required_group_multiple_args() {
    let result = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color 'some other flag'")
        .group(ArgGroup::with_name("req")
            .args(&["flag", "color"])
            .required(true)
            .multiple(true))
        .get_matches_from_safe(vec!["group", "-f", "-c"]);
    assert!(result.is_ok());
    let m = result.unwrap();
    assert!(m.is_present("flag"));
    assert!(m.is_present("color"));
}

#[test]
fn group_multiple_args_error() {
    let result = App::new("group")
        .args_from_usage("-f, --flag 'some flag'
                          -c, --color 'some other flag'")
        .group(ArgGroup::with_name("req")
            .args(&["flag", "color"]))
        .get_matches_from_safe(vec!["group", "-f", "-c"]);
    assert!(result.is_err());
    let err = result.unwrap_err();
    assert_eq!(err.kind, ErrorKind::ArgumentConflict);
}
<|endoftext|>


<commit_before>#[test]
fn health_test() {}
<commit_msg>Added unit test for health/service/:service endpoint<commit_after>extern crate consul;
use consul::{Client, Config};

#[test]
fn health_test() {
    use consul::health::Health;
    let config = Config::new().unwrap();
    let client = Client::new(config);
    // An existing service for a agent in dev mode
    let r = client
        .service("consul", Option::None, true, Option::None)
        .unwrap();
    let (snodes, meta) = (r.0, r.1);
    {
        assert!(snodes.len() > 0, "should have at least one Service Node");
        assert!(meta.last_index.unwrap() > 0, "index must be positive");
    }
    // A non existing, should be empty
    let r = client
        .service("non-existing-service", Option::None, true, Option::None)
        .unwrap();
    let (snodes, meta) = (r.0, r.1);
    {
        assert_eq!(snodes.len(), 0);
        assert!(meta.last_index.unwrap() > 0, "index must be positive");
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2016 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.

// compile-flags: -Z borrowck=mir

fn guard() -> bool {
    false
}

fn guard2(_:i32) -> bool {
    true
}

// no_mangle to make sure this gets instantiated even in an executable.
#[no_mangle]
pub fn full_tested_match() {
    let _ = match Some(42) {
        Some(x) if guard() => (1, x),
        Some(y) => (2, y),
        None => (3, 3),
    };
}

// no_mangle to make sure this gets instantiated even in an executable.
#[no_mangle]
pub fn full_tested_match2() {
    let _ = match Some(42) {
        Some(x) if guard() => (1, x),
        None => (3, 3),
        Some(y) => (2, y),
    };
}

fn main() {
    let _ = match Some(1) {
        Some(_w) if guard() => 1,
        _x => 2,
        Some(y) if guard2(y) => 3,
        _z => 4,
    };
}

// END RUST SOURCE
//
// START rustc.full_tested_match.QualifyAndPromoteConstants.after.mir
//  bb0: {
//      ...
//      _2 = std::option::Option<i32>::Some(const 42i32,);
//      _3 = discriminant(_2);
//      _7 = discriminant(_2);
//      switchInt(move _7) -> [0isize: bb6, 1isize: bb4, otherwise: bb8];
//  }
//  bb1: {
//      resume;
//  }
//  bb2: {  // arm1
//      StorageLive(_9);
//      _9 = _4;
//      _1 = (const 1i32, move _9);
//      StorageDead(_9);
//      goto -> bb13;
//  }
//  bb3: { // binding3(empty) and arm3
//      _1 = (const 3i32, const 3i32);
//      goto -> bb13;
//  }
//  bb4: {
//      falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1
//  }
//  bb5: {
//      falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding2
//  }
//  bb6: {
//      falseEdges -> [real: bb3, imaginary: bb7]; //pre_binding3
//  }
//  bb7: {
//      unreachable;
//  }
//  bb8: {
//      unreachable;
//  }
//  bb9: { // binding1 and guard
//      StorageLive(_5);
//      _11 = promoted[0];
//      _5 = &(((*_11) as Some).0: i32);
//      StorageLive(_8);
//      _8 = const guard() -> [return: bb10, unwind: bb1];
//  }
//  bb10: { // end of guard
//      StorageLive(_4);
//      _4 = ((_2 as Some).0: i32);
//      switchInt(move _8) -> [false: bb11, otherwise: bb2];
//  }
//  bb11: { // to pre_binding2
//      falseEdges -> [real: bb5, imaginary: bb5];
//  }
//  bb12: { // bindingNoLandingPads.before.mir2 and arm2
//      StorageLive(_6);
//      _6 = ((_2 as Some).0: i32);
//      StorageLive(_10);
//      _10 = _6;
//      _1 = (const 2i32, move _10);
//      StorageDead(_10);
//      goto -> bb13;
//  }
//  bb13: {
//      ...
//      return;
//  }
// END rustc.full_tested_match.QualifyAndPromoteConstants.after.mir
//
// START rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir
//  bb0: {
//      ...
//      _2 = std::option::Option<i32>::Some(const 42i32,);
//      _3 = discriminant(_2);
//      _7 = discriminant(_2);
//      switchInt(move _7) -> [0isize: bb5, 1isize: bb4, otherwise: bb8];
//  }
//  bb1: {
//      resume;
//  }
//  bb2: { // arm1
//      StorageLive(_9);
//      _9 = _4;
//      _1 = (const 1i32, move _9);
//      StorageDead(_9);
//      goto -> bb13;
//  }
//  bb3: { // binding3(empty) and arm3
//      _1 = (const 3i32, const 3i32);
//      goto -> bb13;
//  }
//  bb4: {
//      falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1
//  }
//  bb5: {
//      falseEdges -> [real: bb3, imaginary: bb6]; //pre_binding2
//  }
//  bb6: {
//      falseEdges -> [real: bb12, imaginary: bb7]; //pre_binding3
//  }
//  bb7: {
//      unreachable;
//  }
//  bb8: {
//      unreachable;
//  }
//  bb9: { // binding1 and guard
//      StorageLive(_5);
//      _5 = &((_2 as Some).0: i32);
//      StorageLive(_8);
//      _8 = const guard() -> [return: bb10, unwind: bb1];
//  }
//  bb10: { // end of guard
//      StorageLive(_4);
//      _4 = ((_2 as Some).0: i32);
//      switchInt(move _8) -> [false: bb11, otherwise: bb2];
//  }
//  bb11: { // to pre_binding2
//      falseEdges -> [real: bb6, imaginary: bb5];
//  }
//  bb12: { // binding2 and arm2
//      StorageLive(_6);
//      _6 = ((_2 as Some).0: i32);
//      StorageLive(_10);
//      _10 = _6;
//      _1 = (const 2i32, move _10);
//      StorageDead(_10);
//      goto -> bb13;
//  }
//  bb13: {
//      ...
//      return;
//  }
// END rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir
//
// START rustc.main.QualifyAndPromoteConstants.before.mir
// bb0: {
//     ...
//     _2 = std::option::Option<i32>::Some(const 1i32,);
//     _3 = discriminant(_2);
//     _10 = discriminant(_2);
//     switchInt(move _10) -> [1isize: bb4, otherwise: bb5];
// }
// bb1: {
//     resume;
// }
// bb2: { // arm1
//     _1 = const 1i32;
//     goto -> bb17;
// }
// bb3: { // arm3
//     _1 = const 3i32;
//     goto -> bb17;
// }
//
// bb4: {
//     falseEdges -> [real: bb9, imaginary: bb5]; //pre_binding1
// }
// bb5: {
//     falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding2
// }
// bb6: {
//     falseEdges -> [real: bb13, imaginary: bb7]; //pre_binding3
// }
// bb7: {
//     falseEdges -> [real: bb16, imaginary: bb8]; //pre_binding4
// }
// bb8: {
//     unreachable;
// }
// bb9: { // binding1: Some(w) if guard()
//     StorageLive(_5);
//     _5 = &((_2 as Some).0: i32);
//     StorageLive(_11);
//     _11 = const guard() -> [return: bb10, unwind: bb1];
// }
// bb10: { //end of guard
//    StorageLive(_4);
//    _4 = ((_2 as Some).0: i32);
//    switchInt(move _11) -> [false: bb11, otherwise: bb2];
// }
// bb11: { // to pre_binding2
//     falseEdges -> [real: bb5, imaginary: bb5];
// }
// bb12: { // binding2 & arm2
//     StorageLive(_6);
//     _6 = _2;
//     _1 = const 2i32;
//     goto -> bb17;
// }
// bb13: { // binding3: Some(y) if guard2(y)
//     StorageLive(_8);
//     _8 = &((_2 as Some).0: i32);
//     StorageLive(_13);
//     StorageLive(_14);
//     _14 = (*_8);
//     _13 = const guard2(move _14) -> [return: bb14, unwind: bb1];
// }
// bb14: { // end of guard2
//     StorageDead(_14);
//     StorageLive(_7);
//     _7 = ((_2 as Some).0: i32);
//     switchInt(move _13) -> [false: bb15, otherwise: bb3];
// }
// bb15: { // to pre_binding4
//     falseEdges -> [real: bb7, imaginary: bb7];
// }
// bb16: { // binding4 & arm4
//     StorageLive(_9);
//     _9 = _2;
//     _1 = const 4i32;
//     goto -> bb17;
// }
// bb17: {
//     ...
//     return;
// }
// END rustc.main.QualifyAndPromoteConstants.before.mir
<commit_msg>Test update: Fallout from ReadForMatch statements + changes to codegen under NLL.<commit_after>// Copyright 2012-2016 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.

// compile-flags: -Z borrowck=mir

fn guard() -> bool {
    false
}

fn guard2(_:i32) -> bool {
    true
}

// no_mangle to make sure this gets instantiated even in an executable.
#[no_mangle]
pub fn full_tested_match() {
    let _ = match Some(42) {
        Some(x) if guard() => (1, x),
        Some(y) => (2, y),
        None => (3, 3),
    };
}

// no_mangle to make sure this gets instantiated even in an executable.
#[no_mangle]
pub fn full_tested_match2() {
    let _ = match Some(42) {
        Some(x) if guard() => (1, x),
        None => (3, 3),
        Some(y) => (2, y),
    };
}

fn main() {
    let _ = match Some(1) {
        Some(_w) if guard() => 1,
        _x => 2,
        Some(y) if guard2(y) => 3,
        _z => 4,
    };
}

// END RUST SOURCE
//
// START rustc.full_tested_match.QualifyAndPromoteConstants.after.mir
//  bb0: {
//      ...
//      _2 = std::option::Option<i32>::Some(const 42i32,);
//      _3 = discriminant(_2);
//      _14 = promoted[1];
//      _4 = &(*_14);
//      _9 = discriminant(_2);
//      switchInt(move _9) -> [0isize: bb5, 1isize: bb3, otherwise: bb7];
//  }
//  bb1: {
//      resume;
//  }
//  bb2: {  // arm1
//      _1 = (const 3i32, const 3i32);
//      goto -> bb13;
//  }
//  bb3: { // binding3(empty) and arm3
//      ReadForMatch(_4);
//      falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1
//  }
//  bb4: {
//      ReadForMatch(_4);
//      falseEdges -> [real: bb12, imaginary: bb5]; //pre_binding2
//  }
//  bb5: {
//      ReadForMatch(_4);
//      falseEdges -> [real: bb2, imaginary: bb6]; //pre_binding3
//  }
//  bb6: {
//      unreachable;
//  }
//  bb7: {
//      unreachable;
//  }
//  bb8: { // binding1 and guard
//      StorageLive(_7);
//      _13 = promoted[0];
//      _7 = &(((*_13) as Some).0: i32);
//      StorageLive(_10);
//      _10 = const guard() -> [return: bb9, unwind: bb1];
//  }
//  bb9: {
//      switchInt(move _10) -> [false: bb10, otherwise: bb11];
//  }
//  bb10: { // to pre_binding2
//      falseEdges -> [real: bb4, imaginary: bb4];
//  }
//  bb11: { // bindingNoLandingPads.before.mir2 and arm2
//      StorageLive(_5);
//      _5 = ((_2 as Some).0: i32);
//      StorageLive(_11);
//      _11 = _5;
//      _1 = (const 1i32, move _11);
//      StorageDead(_11);
//      goto -> bb13;
//  }
//  bb12: {
//      StorageLive(_8);
//      _8 = ((_2 as Some).0: i32);
//      StorageLive(_12);
//      _12 = _8;
//      _1 = (const 2i32, move_12);
//      StorageDead(_12);
//      goto -> bb13;
//  }
//  bb13: {
//      ...
//      return;
//  }
// END rustc.full_tested_match.QualifyAndPromoteConstants.after.mir
//
// START rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir
//  bb0: {
//      ...
//      _2 = std::option::Option<i32>::Some(const 42i32,);
//      _3 = discriminant(_2);
//      _4 = &_2;
//      _9 = discriminant(_2);
//      switchInt(move _9) -> [0isize: bb4, 1isize: bb3, otherwise: bb7];
//  }
//  bb1: {
//      resume;
//  }
//  bb2: { // arm2
//      _1 = (const 3i32, const 3i32);
//      goto -> bb13;
//  }
//  bb3: {
//      ReadForMatch(_4);
//      falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1
//  }
//  bb4: {
//      ReadForMatch(_4);
//      falseEdges -> [real: bb2, imaginary: bb5]; //pre_binding2
//  }
//  bb5: {
//      ReadForMatch(_4);
//      falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding3
//  }
//  bb6: {
//      unreachable;
//  }
//  bb7: {
//      unreachable;
//  }
//  bb8: { // binding1 and guard
//      StorageLive(_7);
//      _7 = &((_2 as Some).0: i32);
//      StorageLive(_10);
//      _10 = const guard() -> [return: bb9, unwind: bb1];
//  }
//  bb9: { // end of guard
//      switchInt(move _10) -> [false: bb10, otherwise: bb11];
//  }
//  bb10: { // to pre_binding3 (can skip 2 since this is `Some`)
//      falseEdges -> [real: bb5, imaginary: bb4];
//  }
//  bb11: { // arm1
//      StorageLive(_5);
//      _5 = ((_2 as Some).0: i32);
//      StorageLive(_11);
//      _11 = _5;
//      _1 = (const 1i32, move _11);
//      StorageDead(_11);
//      goto -> bb13;
//  }
//  bb12: { // binding3 and arm3
//      StorageLive(_8);
//      _8 = ((_2 as Some).0: i32);
//      StorageLive(_12);
//      _12 = _8;
//      _1 = (const 2i32, move _12);
//      StorageDead(_12);
//      goto -> bb13;
//  }
//  bb13: {
//      ...
//      return;
//  }
// END rustc.full_tested_match2.QualifyAndPromoteConstants.before.mir
//
// START rustc.main.QualifyAndPromoteConstants.before.mir
// bb0: {
//     ...
//     _2 = std::option::Option<i32>::Some(const 1i32,);
//     _3 = discriminant(_2);
//     _4 = &_2;
//     _13 = discriminant(_2);
//     switchInt(move _13) -> [1isize: bb2, otherwise: bb3];
// }
// bb1: {
//     resume;
// }
// bb2: {
//     ReadForMatch(_4);
//     falseEdges -> [real: bb7, imaginary: bb3]; //pre_binding1
// }
// bb3: {
//     ReadForMatch(_4);
//     falseEdges -> [real: bb11, imaginary: bb4]; //pre_binding2
// }
// bb4: {
//     ReadForMatch(_4);
//     falseEdges -> [real: bb12, imaginary: bb5]; //pre_binding3
// }
// bb5: {
//     ReadForMatch(_4);
//     falseEdges -> [real: bb16, imaginary: bb6]; //pre_binding4
// }
// bb6: {
//     unreachable;
// }
// bb7: { // binding1: Some(w) if guard()
//     StorageLive(_7);
//     _7 = &((_2 as Some).0: i32);
//     StorageLive(_14);
//     _14 = const guard() -> [return: bb8, unwind: bb1];
// }
// bb8: { //end of guard
//     switchInt(move _14) -> [false: bb9, otherwise: bb10];
// }
// bb9: { // to pre_binding2
//     falseEdges -> [real: bb3, imaginary: bb3];
// }
// bb10: { // set up bindings for arm1
//     StorageLive(_5);
//     _5 = ((_2 as Some).0: i32);
//     _1 = const 1i32;
//     goto -> bb17;
// }
// bb11: { // binding2 & arm2
//     StorageLive(_8);
//     _8 = _2;
//     _1 = const 2i32;
//     goto -> bb17;
// }
// bb12: { // binding3: Some(y) if guard2(y)
//     StorageLive(_11);
//     _11 = &((_2 as Some).0: i32);
//     StorageLive(_16);
//     StorageLive(_17);
//     _17 = (*_11);
//     _16 = const guard2(move _17) -> [return: bb13, unwind: bb1];
// }
// bb13: { // end of guard2
//     StorageDead(_17);
//     switchInt(move _16) -> [false: bb14, otherwise: bb15];
// }
// bb14: { // to pre_binding4
//     falseEdges -> [real: bb5, imaginary: bb5];
// }
// bb15: { // set up bindings for arm3
//     StorageLive(_9);
//     _9 = ((_2 as Some).0: i32);
//     _1 = const 3i32;
//     goto -> bb17;
// }
// bb16: { // binding4 & arm4
//     StorageLive(_12);
//     _12 = _2;
//     _1 = const 4i32;
//     goto -> bb17;
// }
// bb17: {
//     ...
//     return;
// }
// END rustc.main.QualifyAndPromoteConstants.before.mir
<|endoftext|>


<commit_before>use std::os::unix::io::RawFd;
use std::mem;

use nix::sys::termios;
use nix::sys::termios::{IGNBRK, BRKINT, PARMRK, ISTRIP, INLCR, IGNCR, ICRNL, IXON};
use nix::sys::termios::{OPOST, ECHO, ECHONL, ICANON, ISIG, IEXTEN, CSIZE, PARENB, CS8};
use nix::sys::termios::{VMIN, VTIME};
use nix::sys::termios::SetArg;
use nix::sys::termios::Termios;
use nix::sys::ioctl;

use util::errors::Error;

#[cfg(target_os = "macos")]
const TIOCGWINSZ: u64 = 0x40087468;
#[cfg(target_os = "linux")]
const TIOCGWINSZ: u64 = 0x00005413;

#[repr(C)]
#[derive(Debug, Clone)]
struct WindowSize {
    ws_row: u16,
    ws_col: u16,
    ws_xpixel: u16,
    ws_ypixel: u16,
}

/// Controller for low-level interaction with a terminal device.
pub struct TermCtl {
    fd: RawFd,
    orig_tios: Termios,
}

impl TermCtl {
    pub fn new(fd: RawFd) -> Result<TermCtl, Error> {
        Ok(TermCtl {
            fd: fd,
            orig_tios: try!(termios::tcgetattr(fd)),
        })
    }

    pub fn set(&self) -> Result<(), Error> {
        let mut tios = self.orig_tios.clone();
        tios.c_iflag = tios.c_iflag & !(IGNBRK | BRKINT | PARMRK | ISTRIP |
                                        INLCR | IGNCR | ICRNL | IXON);
        tios.c_oflag = tios.c_oflag & !OPOST;
        tios.c_lflag = tios.c_lflag & !(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
        tios.c_cflag = tios.c_cflag & !(CSIZE | PARENB);
        tios.c_cflag = tios.c_cflag | CS8;
        tios.c_cc[VMIN] = 0;
        tios.c_cc[VTIME] = 0;

        try!(termios::tcsetattr(self.fd, SetArg::TCSAFLUSH, &tios));
        Ok(())
    }

    pub fn window_size(&self) -> Result<(usize, usize), Error> {
        let mut ws = unsafe { mem::uninitialized() };
        try!(unsafe {
            ioctl::read_into::<WindowSize>(self.fd, TIOCGWINSZ, &mut ws)
        });
        Ok((ws.ws_col as usize, ws.ws_row as usize))
    }

    pub fn reset(&self) -> Result<(), Error> {
        try!(termios::tcsetattr(self.fd, SetArg::TCSAFLUSH, &self.orig_tios));
        Ok(())
    }
}
<commit_msg>fix ioctl for 32bit platforms<commit_after>use std::os::unix::io::RawFd;
use std::mem;

use nix::sys::termios;
use nix::sys::termios::{IGNBRK, BRKINT, PARMRK, ISTRIP, INLCR, IGNCR, ICRNL, IXON};
use nix::sys::termios::{OPOST, ECHO, ECHONL, ICANON, ISIG, IEXTEN, CSIZE, PARENB, CS8};
use nix::sys::termios::{VMIN, VTIME};
use nix::sys::termios::SetArg;
use nix::sys::termios::Termios;
use nix::sys::ioctl::{
    self,
    ioctl_op_t,
};

use util::errors::Error;

#[cfg(target_os = "macos")]
const TIOCGWINSZ: ioctl_op_t = 0x40087468;
#[cfg(target_os = "linux")]
const TIOCGWINSZ: ioctl_op_t = 0x00005413;

#[repr(C)]
#[derive(Debug, Clone)]
struct WindowSize {
    ws_row: u16,
    ws_col: u16,
    ws_xpixel: u16,
    ws_ypixel: u16,
}

/// Controller for low-level interaction with a terminal device.
pub struct TermCtl {
    fd: RawFd,
    orig_tios: Termios,
}

impl TermCtl {
    pub fn new(fd: RawFd) -> Result<TermCtl, Error> {
        Ok(TermCtl {
            fd: fd,
            orig_tios: try!(termios::tcgetattr(fd)),
        })
    }

    pub fn set(&self) -> Result<(), Error> {
        let mut tios = self.orig_tios.clone();
        tios.c_iflag = tios.c_iflag & !(IGNBRK | BRKINT | PARMRK | ISTRIP |
                                        INLCR | IGNCR | ICRNL | IXON);
        tios.c_oflag = tios.c_oflag & !OPOST;
        tios.c_lflag = tios.c_lflag & !(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
        tios.c_cflag = tios.c_cflag & !(CSIZE | PARENB);
        tios.c_cflag = tios.c_cflag | CS8;
        tios.c_cc[VMIN] = 0;
        tios.c_cc[VTIME] = 0;

        try!(termios::tcsetattr(self.fd, SetArg::TCSAFLUSH, &tios));
        Ok(())
    }

    pub fn window_size(&self) -> Result<(usize, usize), Error> {
        let mut ws = unsafe { mem::uninitialized() };
        try!(unsafe {
            ioctl::read_into::<WindowSize>(self.fd, TIOCGWINSZ, &mut ws)
        });
        Ok((ws.ws_col as usize, ws.ws_row as usize))
    }

    pub fn reset(&self) -> Result<(), Error> {
        try!(termios::tcsetattr(self.fd, SetArg::TCSAFLUSH, &self.orig_tios));
        Ok(())
    }
}
<|endoftext|>