<commit_before>#![feature(phase, macro_rules, if_let)]

extern crate serialize;
extern crate libc;
#[phase(plugin, link)] extern crate log;
extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate time;
extern crate debug;

extern crate argparse;
extern crate quire;
#[phase(plugin, link)] extern crate lithos;

use std::os::{getenv, setenv};
use std::os::args;
use std::io::fs::readdir;
use std::os::{set_exit_status, self_exe_path};
use std::io::fs::PathExtensions;
use std::default::Default;

use argparse::{ArgumentParser, Store, StoreOption, StoreTrue};
use quire::parse_config;

use lithos::utils::{in_range, in_mapping, check_mapping};
use lithos::master_config::MasterConfig;
use lithos::tree_config::TreeConfig;
use lithos::container_config::ContainerConfig;
use lithos::child_config::ChildConfig;
use lithos::network::{get_host_name, get_host_ip};

fn check_master_config(master: &MasterConfig, verbose: bool) {
    // TODO(tailhook) maybe check host only if we need it for hosts file
    match get_host_name() {
        Ok(hostname) => {
            if verbose {
                println!("Hostname is {}", hostname);
            }
        }
        Err(e) => {
            warn!("Can't get hostname: {}", e);
            set_exit_status(1);
        }
    }
    match get_host_ip() {
        Ok(ipaddr) => {
            if verbose {
                println!("IPAddr is {}", ipaddr);
            }
        }
        Err(e) => {
            warn!("Can't get IPAddress: {}", e);
            set_exit_status(1);
        }
    }

    if !master.devfs_dir.exists() {
        error!("Devfs dir ({}) must exist and contain device nodes",
            master.devfs_dir.display());
        set_exit_status(1);
    }
}

fn check_tree_config(tree: &TreeConfig) {
    if tree.allow_users.len() == 0 {
        error!("No allowed users range. Please add `allow-users: [1-1000]`");
        set_exit_status(1);
    }
    if tree.allow_groups.len() == 0 {
        error!("No allowed groups range. Please add `allow-groups: [1-1000]`");
        set_exit_status(1);
    }
}

fn check(config_file: Path, verbose: bool,
    tree_name: Option<String>, replacement_dir: Option<Path>)
{
    let name_re = regex!(r"^([\w-]+)\.yaml$");
    let mut replacement_dir = replacement_dir;
    let master: MasterConfig = match parse_config(&config_file,
        &*MasterConfig::validator(), Default::default()) {
        Ok(cfg) => cfg,
        Err(e) => {
            error!("Can't parse config: {}", e);
            set_exit_status(1);
            return;
        }
    };

    check_master_config(&master, verbose);

    for tree_fn in readdir(&master.config_dir)
        .map_err(|e| {
            error!("Can't open config directory {}: {}",
                master.config_dir.display(), e);
            set_exit_status(1);
        })
        .unwrap_or(Vec::new())
        .into_iter()
        .filter(|f| f.filename_str()
                     .map(|s| name_re.is_match(s))
                     .unwrap_or(false))
    {
        let tree: TreeConfig = match parse_config(&tree_fn,
            &*TreeConfig::validator(), Default::default()) {
            Ok(cfg) => cfg,
            Err(e) => {
                error!("Can't parse config: {}", e);
                set_exit_status(1);
                continue;
            }
        };
        check_tree_config(&tree);

        let config_dir = match (tree_fn.filestem_str(), &tree_name) {
            (Some(ref f), &Some(ref t)) if *f == t.as_slice()
            => replacement_dir.take().unwrap_or(tree.config_dir),
            _ => tree.config_dir,
        };

        debug!("Checking child dir {}", config_dir.display());
        let dirlist = match readdir(&config_dir) {
            Ok(dirlist) => dirlist,
            Err(e) => {
                error!("Can't open config directory {}: {}",
                    config_dir.display(), e);
                set_exit_status(1);
                return;
            }
        };
        for child_fn in dirlist.into_iter() {
            match (child_fn.filestem_str(), child_fn.extension_str()) {
                (Some(""), _) => continue,  // Hidden files
                (_, Some("yaml")) => {}
                _ => continue,  // Non-yaml, old, whatever, files
            }
            debug!("Checking {}", child_fn.display());
            let child_cfg: ChildConfig = match parse_config(&child_fn,
                &*ChildConfig::validator(), Default::default()) {
                Ok(cfg) => cfg,
                Err(e) => {
                    error!("Can't read child config {}: {}",
                        child_fn.display(), e);
                    set_exit_status(1);
                    continue;
                }
            };
            let cfg_path = Path::new(child_cfg.config);
            if !cfg_path.is_absolute() {
                error!("Config path must be absolute");
                set_exit_status(1);
                continue;
            }
            debug!("Opening config {}", child_fn.display());
            let config: ContainerConfig = match parse_config(
                &tree.image_dir
                    .join(child_cfg.image)
                    .join(cfg_path.path_relative_from(
                        &Path::new("/")).unwrap()),
                &*ContainerConfig::validator(), Default::default()) {
                Ok(cfg) => cfg,
                Err(e) => {
                    error!(concat!("Can't read child config {}: {}.",
                        "Sometimes the reason is absolute symlinks for config, ",
                        "in that case it may work in real daemon, but better ",
                        "fix it."), child_fn.display(), e);
                    set_exit_status(1);
                    continue;
                }
            };
            if config.uid_map.len() > 0 {
                if !in_mapping(&config.uid_map, config.user_id) {
                    error!("User is not in mapped range (uid: {})",
                        config.user_id);
                    set_exit_status(1);
                }
            } else {
                if !in_range(&tree.allow_users, config.user_id) {
                    error!("User is not in allowed range (uid: {})",
                        config.user_id);
                    set_exit_status(1);
                }
            }
            if config.gid_map.len() > 0 {
                if !in_mapping(&config.gid_map, config.group_id) {
                    error!("Group is not in mapped range (gid: {})",
                        config.user_id);
                    set_exit_status(1);
                }
            } else {
                if !in_range(&tree.allow_groups, config.group_id) {
                    error!("Group is not in allowed range (gid: {})",
                        config.group_id);
                    set_exit_status(1);
                }
            }
            if !check_mapping(&tree.allow_users, &config.uid_map) {
                error!("Bad uid mapping (probably doesn't match allow_users)");
                set_exit_status(1);
            }
            if !check_mapping(&tree.allow_groups, &config.gid_map) {
                error!("Bad gid mapping (probably doesn't match allow_groups)");
                set_exit_status(1);
            }
        }
    }
    if replacement_dir.is_some() {
        error!("Tree {} is not used", tree_name);
        set_exit_status(1);
    }
}

fn check_binaries() {
    let dir = match self_exe_path() {
        Some(dir) => dir,
        None => {
            error!("Can't find out exe path");
            set_exit_status(1);
            return;
        }
    };
    if !dir.join("lithos_tree").exists() {
        error!("Can't find lithos_tree binary");
        set_exit_status(1);
    }
    if !dir.join("lithos_knot").exists() {
        error!("Can't find lithos_knot binary");
        set_exit_status(1);
    }
}

fn main() {

    if getenv("RUST_LOG").is_none() {
        setenv("RUST_LOG", "warn");
    }

    let mut config_file = Path::new("/etc/lithos.yaml");
    let mut verbose = false;
    let mut config_dir = None;
    let mut tree_name = None;
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Checks if lithos configuration is ok");
        ap.refer(&mut config_file)
          .add_option(["-C", "--config"], box Store::<Path>,
            "Name of the global configuration file (default /etc/lithos.yaml)")
          .metavar("FILE");
        ap.refer(&mut verbose)
          .add_option(["-v", "--verbose"], box StoreTrue,
            "Verbose configuration");
        ap.refer(&mut config_dir)
          .add_option(["-D", "--dir", "--config-dir"], box StoreOption::<Path>,
            concat!("Name of the alterate directory with configs. ",
                    "Useful to test configuration directory before ",
                    "switching it to be primary one. ",
                    "You must also specify --tree."))
          .metavar("DIR");
        ap.refer(&mut tree_name)
          .add_option(["-T", "--tree", "--subtree-name"],
            box StoreOption::<String>,
            concat!("Name of the tree for which --config-dir takes effect"))
          .metavar("NAME");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                set_exit_status(x);
                return;
            }
        }
    }
    if config_dir.is_some() && tree_name.is_none() {
        error!("Please specify --tree if you use --dir");
        set_exit_status(1);
        return;
    }
    check_binaries();
    check(config_file, verbose, tree_name, config_dir);
}
<commit_msg>Fixed error message a little bit<commit_after>#![feature(phase, macro_rules, if_let)]

extern crate serialize;
extern crate libc;
#[phase(plugin, link)] extern crate log;
extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate time;
extern crate debug;

extern crate argparse;
extern crate quire;
#[phase(plugin, link)] extern crate lithos;

use std::os::{getenv, setenv};
use std::os::args;
use std::io::fs::readdir;
use std::os::{set_exit_status, self_exe_path};
use std::io::fs::PathExtensions;
use std::default::Default;

use argparse::{ArgumentParser, Store, StoreOption, StoreTrue};
use quire::parse_config;

use lithos::utils::{in_range, in_mapping, check_mapping};
use lithos::master_config::MasterConfig;
use lithos::tree_config::TreeConfig;
use lithos::container_config::ContainerConfig;
use lithos::child_config::ChildConfig;
use lithos::network::{get_host_name, get_host_ip};

fn check_master_config(master: &MasterConfig, verbose: bool) {
    // TODO(tailhook) maybe check host only if we need it for hosts file
    match get_host_name() {
        Ok(hostname) => {
            if verbose {
                println!("Hostname is {}", hostname);
            }
        }
        Err(e) => {
            warn!("Can't get hostname: {}", e);
            set_exit_status(1);
        }
    }
    match get_host_ip() {
        Ok(ipaddr) => {
            if verbose {
                println!("IPAddr is {}", ipaddr);
            }
        }
        Err(e) => {
            warn!("Can't get IPAddress: {}", e);
            set_exit_status(1);
        }
    }

    if !master.devfs_dir.exists() {
        error!("Devfs dir ({}) must exist and contain device nodes",
            master.devfs_dir.display());
        set_exit_status(1);
    }
}

fn check_tree_config(tree: &TreeConfig) {
    if tree.allow_users.len() == 0 {
        error!("No allowed users range. Please add `allow-users: [1-1000]`");
        set_exit_status(1);
    }
    if tree.allow_groups.len() == 0 {
        error!("No allowed groups range. Please add `allow-groups: [1-1000]`");
        set_exit_status(1);
    }
}

fn check(config_file: Path, verbose: bool,
    tree_name: Option<String>, replacement_dir: Option<Path>)
{
    let name_re = regex!(r"^([\w-]+)\.yaml$");
    let mut replacement_dir = replacement_dir;
    let master: MasterConfig = match parse_config(&config_file,
        &*MasterConfig::validator(), Default::default()) {
        Ok(cfg) => cfg,
        Err(e) => {
            error!("Can't parse config: {}", e);
            set_exit_status(1);
            return;
        }
    };

    check_master_config(&master, verbose);

    for tree_fn in readdir(&master.config_dir)
        .map_err(|e| {
            error!("Can't open config directory {}: {}",
                master.config_dir.display(), e);
            set_exit_status(1);
        })
        .unwrap_or(Vec::new())
        .into_iter()
        .filter(|f| f.filename_str()
                     .map(|s| name_re.is_match(s))
                     .unwrap_or(false))
    {
        let tree: TreeConfig = match parse_config(&tree_fn,
            &*TreeConfig::validator(), Default::default()) {
            Ok(cfg) => cfg,
            Err(e) => {
                error!("Can't parse config: {}", e);
                set_exit_status(1);
                continue;
            }
        };
        check_tree_config(&tree);

        let config_dir = match (tree_fn.filestem_str(), &tree_name) {
            (Some(ref f), &Some(ref t)) if *f == t.as_slice()
            => replacement_dir.take().unwrap_or(tree.config_dir),
            _ => tree.config_dir,
        };

        debug!("Checking child dir {}", config_dir.display());
        let dirlist = match readdir(&config_dir) {
            Ok(dirlist) => dirlist,
            Err(e) => {
                error!("Can't open config directory {}: {}",
                    config_dir.display(), e);
                set_exit_status(1);
                return;
            }
        };
        for child_fn in dirlist.into_iter() {
            match (child_fn.filestem_str(), child_fn.extension_str()) {
                (Some(""), _) => continue,  // Hidden files
                (_, Some("yaml")) => {}
                _ => continue,  // Non-yaml, old, whatever, files
            }
            debug!("Checking {}", child_fn.display());
            let child_cfg: ChildConfig = match parse_config(&child_fn,
                &*ChildConfig::validator(), Default::default()) {
                Ok(cfg) => cfg,
                Err(e) => {
                    error!("Can't read child config {}: {}",
                        child_fn.display(), e);
                    set_exit_status(1);
                    continue;
                }
            };
            let cfg_path = Path::new(child_cfg.config);
            if !cfg_path.is_absolute() {
                error!("Config path must be absolute");
                set_exit_status(1);
                continue;
            }
            debug!("Opening config {}", child_fn.display());
            let config: ContainerConfig = match parse_config(
                &tree.image_dir
                    .join(child_cfg.image)
                    .join(cfg_path.path_relative_from(
                        &Path::new("/")).unwrap()),
                &*ContainerConfig::validator(), Default::default()) {
                Ok(cfg) => cfg,
                Err(e) => {
                    error!("Can't read child config {}: {}.\n\
                        Sometimes the reason of reading configuration is \
                        absolute symlinks for config, in that case it may \
                        work in real daemon, but better fix it.",
                        child_fn.display(), e);
                    set_exit_status(1);
                    continue;
                }
            };
            if config.uid_map.len() > 0 {
                if !in_mapping(&config.uid_map, config.user_id) {
                    error!("User is not in mapped range (uid: {})",
                        config.user_id);
                    set_exit_status(1);
                }
            } else {
                if !in_range(&tree.allow_users, config.user_id) {
                    error!("User is not in allowed range (uid: {})",
                        config.user_id);
                    set_exit_status(1);
                }
            }
            if config.gid_map.len() > 0 {
                if !in_mapping(&config.gid_map, config.group_id) {
                    error!("Group is not in mapped range (gid: {})",
                        config.user_id);
                    set_exit_status(1);
                }
            } else {
                if !in_range(&tree.allow_groups, config.group_id) {
                    error!("Group is not in allowed range (gid: {})",
                        config.group_id);
                    set_exit_status(1);
                }
            }
            if !check_mapping(&tree.allow_users, &config.uid_map) {
                error!("Bad uid mapping (probably doesn't match allow_users)");
                set_exit_status(1);
            }
            if !check_mapping(&tree.allow_groups, &config.gid_map) {
                error!("Bad gid mapping (probably doesn't match allow_groups)");
                set_exit_status(1);
            }
        }
    }
    if replacement_dir.is_some() {
        error!("Tree {} is not used", tree_name);
        set_exit_status(1);
    }
}

fn check_binaries() {
    let dir = match self_exe_path() {
        Some(dir) => dir,
        None => {
            error!("Can't find out exe path");
            set_exit_status(1);
            return;
        }
    };
    if !dir.join("lithos_tree").exists() {
        error!("Can't find lithos_tree binary");
        set_exit_status(1);
    }
    if !dir.join("lithos_knot").exists() {
        error!("Can't find lithos_knot binary");
        set_exit_status(1);
    }
}

fn main() {

    if getenv("RUST_LOG").is_none() {
        setenv("RUST_LOG", "warn");
    }

    let mut config_file = Path::new("/etc/lithos.yaml");
    let mut verbose = false;
    let mut config_dir = None;
    let mut tree_name = None;
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Checks if lithos configuration is ok");
        ap.refer(&mut config_file)
          .add_option(["-C", "--config"], box Store::<Path>,
            "Name of the global configuration file (default /etc/lithos.yaml)")
          .metavar("FILE");
        ap.refer(&mut verbose)
          .add_option(["-v", "--verbose"], box StoreTrue,
            "Verbose configuration");
        ap.refer(&mut config_dir)
          .add_option(["-D", "--dir", "--config-dir"], box StoreOption::<Path>,
            concat!("Name of the alterate directory with configs. ",
                    "Useful to test configuration directory before ",
                    "switching it to be primary one. ",
                    "You must also specify --tree."))
          .metavar("DIR");
        ap.refer(&mut tree_name)
          .add_option(["-T", "--tree", "--subtree-name"],
            box StoreOption::<String>,
            concat!("Name of the tree for which --config-dir takes effect"))
          .metavar("NAME");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                set_exit_status(x);
                return;
            }
        }
    }
    if config_dir.is_some() && tree_name.is_none() {
        error!("Please specify --tree if you use --dir");
        set_exit_status(1);
        return;
    }
    check_binaries();
    check(config_file, verbose, tree_name, config_dir);
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::io::Write;
use std::fs::File;
use std::path;
use std::fs;

use bindgen::config::{Config, Language};
use bindgen::ir::{ItemContainer, Function};
use bindgen::monomorph::TemplateSpecialization;
use bindgen::writer::{ListType, Source, SourceWriter};

pub struct Bindings {
    config: Config,
    items: Vec<ItemContainer>,
    functions: Vec<Function>,
    template_specializations: Vec<TemplateSpecialization>,
}

impl Bindings {
    pub fn new(config: Config,
               items: Vec<ItemContainer>,
               functions: Vec<Function>,
               template_specializations: Vec<TemplateSpecialization>) -> Bindings {
        Bindings {
            config: config,
            items: items,
            functions: functions,
            template_specializations: template_specializations,
        }
    }

    pub fn write_to_file(&self, path: &str) {
        if let Some(parent) = path::Path::new(path).parent() {
            fs::create_dir_all(parent).unwrap();
        }

        self.write(File::create(path).unwrap());
    }

    pub fn write<F: Write>(&self, file: F) {
        let mut out = SourceWriter::new(file, &self.config);

        if let Some(ref f) = self.config.header {
            out.new_line_if_not_start();
            out.write(&f);
            out.new_line();
        }
        if let Some(ref f) = self.config.include_guard {
            out.new_line_if_not_start();
            out.write(&format!("#ifndef {}", f));
            out.new_line();
            out.write(&format!("#define {}", f));
            out.new_line();
        }
        if self.config.include_version {
            out.new_line_if_not_start();
            out.write(&format!("/* Generated with cbindgen:{} */",
                      ::bindgen::config::VERSION));
            out.new_line();
        }
        if let Some(ref f) = self.config.autogen_warning {
            out.new_line_if_not_start();
            out.write(&f);
            out.new_line();
        }

        out.new_line_if_not_start();
        if self.config.language == Language::C {
            out.write("#include <stdint.h>");
            out.new_line();
            out.write("#include <stdlib.h>");
            out.new_line();
            out.write("#include <stdbool.h>");
        } else {
            out.write("#include <cstdint>");
            out.new_line();
            out.write("#include <cstdlib>");
        }
        out.new_line();

        if self.config.language == Language::Cxx {
            out.new_line_if_not_start();
            out.write("extern \"C\" {");
            out.new_line();

            self.open_namespaces(&mut out);
        }

        for item in &self.items {
            out.new_line_if_not_start();
            match item {
                &ItemContainer::Enum(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::Struct(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::OpaqueItem(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::Typedef(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::Specialization(_) => {
                    unreachable!("should not encounter a specialization in a generated library")
                }
            }
            out.new_line();
        }

        if let Some(ref f) = self.config.autogen_warning {
            out.new_line_if_not_start();
            out.write(&f);
            out.new_line();
        }

        for function in &self.functions {
            out.new_line_if_not_start();
            function.write(&self.config, &mut out);
            out.new_line();
        }

        if self.config.language == Language::Cxx {
            self.close_namespaces(&mut out);

            out.new_line_if_not_start();
            out.write("} // extern \"C\"");
            out.new_line();
        }

        if self.config.structure.generic_template_specialization &&
           self.config.language == Language::Cxx {
            self.open_namespaces(&mut out);
            for template in &self.template_specializations {
              out.new_line_if_not_start();
              out.write("template<");
              for (i, param) in template.generic.generic_params.iter().enumerate() {
                  if i != 0 {
                      out.write(", ")
                  }
                  out.write("typename ");
                  out.write(param);
              }
              out.write(">");
              out.new_line();
              out.write(&format!("struct {};", template.generic.name));
              out.new_line();

              for &(ref monomorph_path, ref generic_values) in &template.monomorphs {
                out.new_line();
                out.write("template<>");
                out.new_line();
                out.write(&format!("struct {}<", template.generic.name));
                out.write_horizontal_source_list(generic_values, ListType::Join(", "));
                out.write(&format!("> : public {}", monomorph_path));
                out.open_brace();
                out.close_brace(true);
                out.new_line();
              }
            }
            self.close_namespaces(&mut out);
        }

        if let Some(ref f) = self.config.autogen_warning {
            out.new_line_if_not_start();
            out.write(&f);
            out.new_line();
        }
        if let Some(ref f) = self.config.include_guard {
            out.new_line_if_not_start();
            if self.config.language == Language::C {
                out.write(&format!("#endif /* {} */", f));
            } else {
                out.write(&format!("#endif // {}", f));
            }
            out.new_line();
        }
        if let Some(ref f) = self.config.trailer {
            out.new_line_if_not_start();
            out.write(&f);
            out.new_line();
        }
    }

    pub fn open_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) {
        let mut wrote_namespace: bool = false;
        if let Some(ref namespace) = self.config.namespace {
            wrote_namespace = true;

            out.new_line();
            out.write("namespace ");
            out.write(namespace);
            out.write(" {");
        }
        if let Some(ref namespaces) = self.config.namespaces {
            wrote_namespace = true;
            for namespace in namespaces {
                out.new_line();
                out.write("namespace ");
                out.write(namespace);
                out.write(" {");
            }
        }
        if wrote_namespace {
            out.new_line();
        }
    }

    pub fn close_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) {
        let mut wrote_namespace: bool = false;
        if let Some(ref namespaces) = self.config.namespaces {
            wrote_namespace = true;

            for namespace in namespaces.iter().rev() {
                out.new_line_if_not_start();
                out.write("} // namespace ");
                out.write(namespace);
            }
        }
        if let Some(ref namespace) = self.config.namespace {
            wrote_namespace = true;

            out.new_line_if_not_start();
            out.write("} // namespace ");
            out.write(namespace);
        }
        if wrote_namespace {
            out.new_line();
        }
    }
}
<commit_msg>Add a 'no-export' annotation to mark items that shouldn't be given definitions<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::io::Write;
use std::fs::File;
use std::path;
use std::fs;

use bindgen::config::{Config, Language};
use bindgen::ir::{ItemContainer, Function};
use bindgen::monomorph::TemplateSpecialization;
use bindgen::writer::{ListType, Source, SourceWriter};

pub struct Bindings {
    config: Config,
    items: Vec<ItemContainer>,
    functions: Vec<Function>,
    template_specializations: Vec<TemplateSpecialization>,
}

impl Bindings {
    pub fn new(config: Config,
               items: Vec<ItemContainer>,
               functions: Vec<Function>,
               template_specializations: Vec<TemplateSpecialization>) -> Bindings {
        Bindings {
            config: config,
            items: items,
            functions: functions,
            template_specializations: template_specializations,
        }
    }

    pub fn write_to_file(&self, path: &str) {
        if let Some(parent) = path::Path::new(path).parent() {
            fs::create_dir_all(parent).unwrap();
        }

        self.write(File::create(path).unwrap());
    }

    pub fn write<F: Write>(&self, file: F) {
        let mut out = SourceWriter::new(file, &self.config);

        if let Some(ref f) = self.config.header {
            out.new_line_if_not_start();
            out.write(&f);
            out.new_line();
        }
        if let Some(ref f) = self.config.include_guard {
            out.new_line_if_not_start();
            out.write(&format!("#ifndef {}", f));
            out.new_line();
            out.write(&format!("#define {}", f));
            out.new_line();
        }
        if self.config.include_version {
            out.new_line_if_not_start();
            out.write(&format!("/* Generated with cbindgen:{} */",
                      ::bindgen::config::VERSION));
            out.new_line();
        }
        if let Some(ref f) = self.config.autogen_warning {
            out.new_line_if_not_start();
            out.write(&f);
            out.new_line();
        }

        out.new_line_if_not_start();
        if self.config.language == Language::C {
            out.write("#include <stdint.h>");
            out.new_line();
            out.write("#include <stdlib.h>");
            out.new_line();
            out.write("#include <stdbool.h>");
        } else {
            out.write("#include <cstdint>");
            out.new_line();
            out.write("#include <cstdlib>");
        }
        out.new_line();

        if self.config.language == Language::Cxx {
            out.new_line_if_not_start();
            out.write("extern \"C\" {");
            out.new_line();

            self.open_namespaces(&mut out);
        }

        for item in &self.items {
            if item.deref().annotations().bool("no-export").unwrap_or(false) {
                continue;
            }

            out.new_line_if_not_start();
            match item {
                &ItemContainer::Enum(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::Struct(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::OpaqueItem(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::Typedef(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::Specialization(_) => {
                    unreachable!("should not encounter a specialization in a generated library")
                }
            }
            out.new_line();
        }

        if let Some(ref f) = self.config.autogen_warning {
            out.new_line_if_not_start();
            out.write(&f);
            out.new_line();
        }

        for function in &self.functions {
            out.new_line_if_not_start();
            function.write(&self.config, &mut out);
            out.new_line();
        }

        if self.config.language == Language::Cxx {
            self.close_namespaces(&mut out);

            out.new_line_if_not_start();
            out.write("} // extern \"C\"");
            out.new_line();
        }

        if self.config.structure.generic_template_specialization &&
           self.config.language == Language::Cxx {
            self.open_namespaces(&mut out);
            for template in &self.template_specializations {
              out.new_line_if_not_start();
              out.write("template<");
              for (i, param) in template.generic.generic_params.iter().enumerate() {
                  if i != 0 {
                      out.write(", ")
                  }
                  out.write("typename ");
                  out.write(param);
              }
              out.write(">");
              out.new_line();
              out.write(&format!("struct {};", template.generic.name));
              out.new_line();

              for &(ref monomorph_path, ref generic_values) in &template.monomorphs {
                out.new_line();
                out.write("template<>");
                out.new_line();
                out.write(&format!("struct {}<", template.generic.name));
                out.write_horizontal_source_list(generic_values, ListType::Join(", "));
                out.write(&format!("> : public {}", monomorph_path));
                out.open_brace();
                out.close_brace(true);
                out.new_line();
              }
            }
            self.close_namespaces(&mut out);
        }

        if let Some(ref f) = self.config.autogen_warning {
            out.new_line_if_not_start();
            out.write(&f);
            out.new_line();
        }
        if let Some(ref f) = self.config.include_guard {
            out.new_line_if_not_start();
            if self.config.language == Language::C {
                out.write(&format!("#endif /* {} */", f));
            } else {
                out.write(&format!("#endif // {}", f));
            }
            out.new_line();
        }
        if let Some(ref f) = self.config.trailer {
            out.new_line_if_not_start();
            out.write(&f);
            out.new_line();
        }
    }

    pub fn open_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) {
        let mut wrote_namespace: bool = false;
        if let Some(ref namespace) = self.config.namespace {
            wrote_namespace = true;

            out.new_line();
            out.write("namespace ");
            out.write(namespace);
            out.write(" {");
        }
        if let Some(ref namespaces) = self.config.namespaces {
            wrote_namespace = true;
            for namespace in namespaces {
                out.new_line();
                out.write("namespace ");
                out.write(namespace);
                out.write(" {");
            }
        }
        if wrote_namespace {
            out.new_line();
        }
    }

    pub fn close_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) {
        let mut wrote_namespace: bool = false;
        if let Some(ref namespaces) = self.config.namespaces {
            wrote_namespace = true;

            for namespace in namespaces.iter().rev() {
                out.new_line_if_not_start();
                out.write("} // namespace ");
                out.write(namespace);
            }
        }
        if let Some(ref namespace) = self.config.namespace {
            wrote_namespace = true;

            out.new_line_if_not_start();
            out.write("} // namespace ");
            out.write(namespace);
        }
        if wrote_namespace {
            out.new_line();
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::io::Write;

use syn;

use bindgen::config::{Config, Language};
use bindgen::dependencies::Dependencies;
use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, GenericParams, Item, ItemContainer,
                  Repr, Type};
use bindgen::ir::SynFieldHelpers;
use bindgen::library::Library;
use bindgen::mangle;
use bindgen::monomorph::Monomorphs;
use bindgen::rename::{IdentifierType, RenameRule};
use bindgen::utilities::{find_first_some, IterHelpers};
use bindgen::writer::{ListType, Source, SourceWriter};

#[derive(Debug, Clone)]
pub struct Union {
    pub name: String,
    pub generic_params: GenericParams,
    pub fields: Vec<(String, Type, Documentation)>,
    pub tuple_union: bool,
    pub cfg: Option<Cfg>,
    pub annotations: AnnotationSet,
    pub documentation: Documentation,
}

impl Union {
    pub fn load(item: &syn::ItemUnion, mod_cfg: &Option<Cfg>) -> Result<Union, String> {
        if Repr::load(&item.attrs)? != Repr::C {
            return Err("Union is not marked #[repr(C)].".to_owned());
        }

        let (fields, tuple_union) = {
            let out = item.fields
                .named
                .iter()
                .try_skip_map(|x| x.as_ident_and_type())?;
            (out, false)
        };

        Ok(Union {
            name: item.ident.to_string(),
            generic_params: GenericParams::new(&item.generics),
            fields: fields,
            tuple_union: tuple_union,
            cfg: Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
            annotations: AnnotationSet::load(&item.attrs)?,
            documentation: Documentation::load(&item.attrs),
        })
    }

    pub fn simplify_option_to_ptr(&mut self) {
        for &mut (_, ref mut ty, _) in &mut self.fields {
            ty.simplify_option_to_ptr();
        }
    }

    pub fn is_generic(&self) -> bool {
        self.generic_params.len() > 0
    }

    pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
        // Generic unions can instantiate monomorphs only once they've been
        // instantiated. See `instantiate_monomorph` for more details.
        if self.is_generic() {
            return;
        }

        for &(_, ref ty, _) in &self.fields {
            ty.add_monomorphs(library, out);
        }
    }

    pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) {
        for &mut (_, ref mut ty, _) in &mut self.fields {
            ty.mangle_paths(monomorphs);
        }
    }
}

impl Item for Union {
    fn name(&self) -> &str {
        &self.name
    }

    fn cfg(&self) -> &Option<Cfg> {
        &self.cfg
    }

    fn annotations(&self) -> &AnnotationSet {
        &self.annotations
    }

    fn annotations_mut(&mut self) -> &mut AnnotationSet {
        &mut self.annotations
    }

    fn container(&self) -> ItemContainer {
        ItemContainer::Union(self.clone())
    }

    fn rename_for_config(&mut self, config: &Config) {
        config.export.rename(&mut self.name);
        for &mut (_, ref mut ty, _) in &mut self.fields {
            ty.rename_for_config(config);
        }

        let rules = [
            self.annotations.parse_atom::<RenameRule>("rename-all"),
            config.structure.rename_fields,
        ];

        if let Some(o) = self.annotations.list("field-names") {
            let mut overriden_fields = Vec::new();

            for (i, &(ref name, ref ty, ref doc)) in self.fields.iter().enumerate() {
                if i >= o.len() {
                    overriden_fields.push((name.clone(), ty.clone(), doc.clone()));
                } else {
                    overriden_fields.push((o[i].clone(), ty.clone(), doc.clone()));
                }
            }

            self.fields = overriden_fields;
        } else if let Some(r) = find_first_some(&rules) {
            self.fields = self.fields
                .iter()
                .map(|x| {
                    (
                        r.apply_to_snake_case(&x.0, IdentifierType::StructMember),
                        x.1.clone(),
                        x.2.clone(),
                    )
                })
                .collect();
        } else if self.tuple_union {
            // If we don't have any rules for a tuple union, prefix them with
            // an underscore so it still compiles
            for &mut (ref mut name, ..) in &mut self.fields {
                name.insert(0, '_');
            }
        }
    }

    fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
        for &(_, ref ty, _) in &self.fields {
            ty.add_dependencies_ignoring_generics(&self.generic_params, library, out);
        }
    }

    fn instantiate_monomorph(
        &self,
        generic_values: &Vec<Type>,
        library: &Library,
        out: &mut Monomorphs,
    ) {
        assert!(self.generic_params.len() > 0 && self.generic_params.len() == generic_values.len());

        let mappings = self.generic_params
            .iter()
            .zip(generic_values.iter())
            .collect::<Vec<_>>();

        let monomorph = Union {
            name: mangle::mangle_path(&self.name, generic_values),
            generic_params: GenericParams::default(),
            fields: self.fields
                .iter()
                .map(|x| (x.0.clone(), x.1.specialize(&mappings), x.2.clone()))
                .collect(),
            tuple_union: self.tuple_union,
            cfg: self.cfg.clone(),
            annotations: self.annotations.clone(),
            documentation: self.documentation.clone(),
        };

        // Instantiate any monomorphs for any generic paths we may have just created.
        monomorph.add_monomorphs(library, out);

        out.insert_union(self, monomorph, generic_values.clone());
    }
}

impl Source for Union {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        self.cfg.write_before(config, out);

        self.documentation.write(config, out);

        self.generic_params.write(config, out);

        if config.language == Language::C {
            out.write("typedef union");
        } else {
            write!(out, "union {}", self.name);
        }
        out.open_brace();

        if config.documentation {
            out.write_vertical_source_list(&self.fields, ListType::Cap(";"));
        } else {
            out.write_vertical_source_list(
                &self.fields
                    .iter()
                    .map(|&(ref name, ref ty, _)| (name.clone(), ty.clone()))
                    .collect(),
                ListType::Cap(";"),
            );
        }

        if config.language == Language::C {
            out.close_brace(false);
            write!(out, " {};", self.name);
        } else {
            out.close_brace(true);
        }

        self.cfg.write_after(config, out);
    }
}
<commit_msg>Don't rename union generic type parameters<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::io::Write;

use syn;

use bindgen::config::{Config, Language};
use bindgen::dependencies::Dependencies;
use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, GenericParams, Item, ItemContainer,
                  Repr, Type};
use bindgen::ir::SynFieldHelpers;
use bindgen::library::Library;
use bindgen::mangle;
use bindgen::monomorph::Monomorphs;
use bindgen::rename::{IdentifierType, RenameRule};
use bindgen::utilities::{find_first_some, IterHelpers};
use bindgen::writer::{ListType, Source, SourceWriter};

#[derive(Debug, Clone)]
pub struct Union {
    pub name: String,
    pub generic_params: GenericParams,
    pub fields: Vec<(String, Type, Documentation)>,
    pub tuple_union: bool,
    pub cfg: Option<Cfg>,
    pub annotations: AnnotationSet,
    pub documentation: Documentation,
}

impl Union {
    pub fn load(item: &syn::ItemUnion, mod_cfg: &Option<Cfg>) -> Result<Union, String> {
        if Repr::load(&item.attrs)? != Repr::C {
            return Err("Union is not marked #[repr(C)].".to_owned());
        }

        let (fields, tuple_union) = {
            let out = item.fields
                .named
                .iter()
                .try_skip_map(|x| x.as_ident_and_type())?;
            (out, false)
        };

        Ok(Union {
            name: item.ident.to_string(),
            generic_params: GenericParams::new(&item.generics),
            fields: fields,
            tuple_union: tuple_union,
            cfg: Cfg::append(mod_cfg, Cfg::load(&item.attrs)),
            annotations: AnnotationSet::load(&item.attrs)?,
            documentation: Documentation::load(&item.attrs),
        })
    }

    pub fn simplify_option_to_ptr(&mut self) {
        for &mut (_, ref mut ty, _) in &mut self.fields {
            ty.simplify_option_to_ptr();
        }
    }

    pub fn is_generic(&self) -> bool {
        self.generic_params.len() > 0
    }

    pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) {
        // Generic unions can instantiate monomorphs only once they've been
        // instantiated. See `instantiate_monomorph` for more details.
        if self.is_generic() {
            return;
        }

        for &(_, ref ty, _) in &self.fields {
            ty.add_monomorphs(library, out);
        }
    }

    pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) {
        for &mut (_, ref mut ty, _) in &mut self.fields {
            ty.mangle_paths(monomorphs);
        }
    }
}

impl Item for Union {
    fn name(&self) -> &str {
        &self.name
    }

    fn cfg(&self) -> &Option<Cfg> {
        &self.cfg
    }

    fn annotations(&self) -> &AnnotationSet {
        &self.annotations
    }

    fn annotations_mut(&mut self) -> &mut AnnotationSet {
        &mut self.annotations
    }

    fn container(&self) -> ItemContainer {
        ItemContainer::Union(self.clone())
    }

    fn rename_for_config(&mut self, config: &Config) {
        config.export.rename(&mut self.name);
        for &mut (_, ref mut ty, _) in &mut self.fields {
            let generic_parameter = match ty.get_root_path() {
                Some(ref p) => self.generic_params.contains(p),
                None => false,
            };
            if !generic_parameter {
                ty.rename_for_config(config);
            }
        }

        let rules = [
            self.annotations.parse_atom::<RenameRule>("rename-all"),
            config.structure.rename_fields,
        ];

        if let Some(o) = self.annotations.list("field-names") {
            let mut overriden_fields = Vec::new();

            for (i, &(ref name, ref ty, ref doc)) in self.fields.iter().enumerate() {
                if i >= o.len() {
                    overriden_fields.push((name.clone(), ty.clone(), doc.clone()));
                } else {
                    overriden_fields.push((o[i].clone(), ty.clone(), doc.clone()));
                }
            }

            self.fields = overriden_fields;
        } else if let Some(r) = find_first_some(&rules) {
            self.fields = self.fields
                .iter()
                .map(|x| {
                    (
                        r.apply_to_snake_case(&x.0, IdentifierType::StructMember),
                        x.1.clone(),
                        x.2.clone(),
                    )
                })
                .collect();
        } else if self.tuple_union {
            // If we don't have any rules for a tuple union, prefix them with
            // an underscore so it still compiles
            for &mut (ref mut name, ..) in &mut self.fields {
                name.insert(0, '_');
            }
        }
    }

    fn add_dependencies(&self, library: &Library, out: &mut Dependencies) {
        for &(_, ref ty, _) in &self.fields {
            ty.add_dependencies_ignoring_generics(&self.generic_params, library, out);
        }
    }

    fn instantiate_monomorph(
        &self,
        generic_values: &Vec<Type>,
        library: &Library,
        out: &mut Monomorphs,
    ) {
        assert!(self.generic_params.len() > 0 && self.generic_params.len() == generic_values.len());

        let mappings = self.generic_params
            .iter()
            .zip(generic_values.iter())
            .collect::<Vec<_>>();

        let monomorph = Union {
            name: mangle::mangle_path(&self.name, generic_values),
            generic_params: GenericParams::default(),
            fields: self.fields
                .iter()
                .map(|x| (x.0.clone(), x.1.specialize(&mappings), x.2.clone()))
                .collect(),
            tuple_union: self.tuple_union,
            cfg: self.cfg.clone(),
            annotations: self.annotations.clone(),
            documentation: self.documentation.clone(),
        };

        // Instantiate any monomorphs for any generic paths we may have just created.
        monomorph.add_monomorphs(library, out);

        out.insert_union(self, monomorph, generic_values.clone());
    }
}

impl Source for Union {
    fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
        self.cfg.write_before(config, out);

        self.documentation.write(config, out);

        self.generic_params.write(config, out);

        if config.language == Language::C {
            out.write("typedef union");
        } else {
            write!(out, "union {}", self.name);
        }
        out.open_brace();

        if config.documentation {
            out.write_vertical_source_list(&self.fields, ListType::Cap(";"));
        } else {
            out.write_vertical_source_list(
                &self.fields
                    .iter()
                    .map(|&(ref name, ref ty, _)| (name.clone(), ty.clone()))
                    .collect(),
                ListType::Cap(";"),
            );
        }

        if config.language == Language::C {
            out.close_brace(false);
            write!(out, " {};", self.name);
        } else {
            out.close_brace(true);
        }

        self.cfg.write_after(config, out);
    }
}
<|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.

#![deny(warnings)]

extern crate filetime;

use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::{fs, env};

use filetime::FileTime;

/// A helper macro to `unwrap` a result except also print out details like:
///
/// * The file/line of the panic
/// * The expression that failed
/// * The error itself
///
/// This is currently used judiciously throughout the build system rather than
/// using a `Result` with `try!`, but this may change one day...
#[macro_export]
macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum BuildExpectation {
    Succeeding,
    Failing,
    None,
}

pub fn run(cmd: &mut Command, expect: BuildExpectation) {
    println!("running: {:?}", cmd);
    run_silent(cmd, expect);
}

pub fn run_silent(cmd: &mut Command, expect: BuildExpectation) {
    if !try_run_silent(cmd, expect) {
        std::process::exit(1);
    }
}

pub fn try_run_silent(cmd: &mut Command, expect: BuildExpectation) -> bool {
    let status = match cmd.status() {
        Ok(status) => status,
        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                cmd, e)),
    };
    process_status(
        cmd,
        status.success(),
        expect,
        || println!("\n\ncommand did not execute successfully: {:?}\n\
                    expected success, got: {}\n\n",
                    cmd,
                    status))
}

fn process_status<F: FnOnce()>(
    cmd: &Command,
    success: bool,
    expect: BuildExpectation,
    f: F,
) -> bool {
    use BuildExpectation::*;
    match (expect, success) {
        (None, false) => { f(); false },
        // Non-tool build succeeds, everything is good
        (None, true) => true,
        // Tool expected to work and is working
        (Succeeding, true) => true,
        // Tool expected to fail and is failing
        (Failing, false) => {
            println!("This failure is expected (see `src/tools/toolstate.toml`)");
            true
        },
        // Tool expected to work, but is failing
        (Succeeding, false) => {
            f();
            println!("You can disable the tool in `src/tools/toolstate.toml`");
            false
        },
        // Tool expected to fail, but is working
        (Failing, true) => {
            println!("Expected `{:?}` to fail, but it succeeded.\n\
                     Please adjust `src/tools/toolstate.toml` accordingly", cmd);
            false
        }
    }
}

pub fn run_suppressed(cmd: &mut Command, expect: BuildExpectation) {
    if !try_run_suppressed(cmd, expect) {
        std::process::exit(1);
    }
}

pub fn try_run_suppressed(cmd: &mut Command, expect: BuildExpectation) -> bool {
    let output = match cmd.output() {
        Ok(status) => status,
        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                cmd, e)),
    };
    process_status(
        cmd,
        output.status.success(),
        expect,
        || println!("\n\ncommand did not execute successfully: {:?}\n\
                  expected success, got: {}\n\n\
                  stdout ----\n{}\n\
                  stderr ----\n{}\n\n",
                 cmd,
                 output.status,
                 String::from_utf8_lossy(&output.stdout),
                 String::from_utf8_lossy(&output.stderr)))
}

pub fn gnu_target(target: &str) -> String {
    match target {
        "i686-pc-windows-msvc" => "i686-pc-win32".to_string(),
        "x86_64-pc-windows-msvc" => "x86_64-pc-win32".to_string(),
        "i686-pc-windows-gnu" => "i686-w64-mingw32".to_string(),
        "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32".to_string(),
        s => s.to_string(),
    }
}

pub fn make(host: &str) -> PathBuf {
    if host.contains("bitrig") || host.contains("dragonfly") ||
        host.contains("freebsd") || host.contains("netbsd") ||
        host.contains("openbsd") {
        PathBuf::from("gmake")
    } else {
        PathBuf::from("make")
    }
}

pub fn output(cmd: &mut Command) -> String {
    let output = match cmd.stderr(Stdio::inherit()).output() {
        Ok(status) => status,
        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                cmd, e)),
    };
    if !output.status.success() {
        panic!("command did not execute successfully: {:?}\n\
                expected success, got: {}",
               cmd,
               output.status);
    }
    String::from_utf8(output.stdout).unwrap()
}

pub fn rerun_if_changed_anything_in_dir(dir: &Path) {
    let mut stack = dir.read_dir().unwrap()
                       .map(|e| e.unwrap())
                       .filter(|e| &*e.file_name() != ".git")
                       .collect::<Vec<_>>();
    while let Some(entry) = stack.pop() {
        let path = entry.path();
        if entry.file_type().unwrap().is_dir() {
            stack.extend(path.read_dir().unwrap().map(|e| e.unwrap()));
        } else {
            println!("cargo:rerun-if-changed={}", path.display());
        }
    }
}

/// Returns the last-modified time for `path`, or zero if it doesn't exist.
pub fn mtime(path: &Path) -> FileTime {
    fs::metadata(path).map(|f| {
        FileTime::from_last_modification_time(&f)
    }).unwrap_or(FileTime::zero())
}

/// Returns whether `dst` is up to date given that the file or files in `src`
/// are used to generate it.
///
/// Uses last-modified time checks to verify this.
pub fn up_to_date(src: &Path, dst: &Path) -> bool {
    let threshold = mtime(dst);
    let meta = match fs::metadata(src) {
        Ok(meta) => meta,
        Err(e) => panic!("source {:?} failed to get metadata: {}", src, e),
    };
    if meta.is_dir() {
        dir_up_to_date(src, &threshold)
    } else {
        FileTime::from_last_modification_time(&meta) <= threshold
    }
}

#[must_use]
pub struct NativeLibBoilerplate {
    pub src_dir: PathBuf,
    pub out_dir: PathBuf,
}

impl Drop for NativeLibBoilerplate {
    fn drop(&mut self) {
        t!(File::create(self.out_dir.join("rustbuild.timestamp")));
    }
}

// Perform standard preparations for native libraries that are build only once for all stages.
// Emit rerun-if-changed and linking attributes for Cargo, check if any source files are
// updated, calculate paths used later in actual build with CMake/make or C/C++ compiler.
// If Err is returned, then everything is up-to-date and further build actions can be skipped.
// Timestamps are created automatically when the result of `native_lib_boilerplate` goes out
// of scope, so all the build actions should be completed until then.
pub fn native_lib_boilerplate(src_name: &str,
                              out_name: &str,
                              link_name: &str,
                              search_subdir: &str)
                              -> Result<NativeLibBoilerplate, ()> {
    let current_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    let src_dir = current_dir.join("..").join(src_name);
    rerun_if_changed_anything_in_dir(&src_dir);

    let out_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap());
    let out_dir = PathBuf::from(out_dir).join(out_name);
    t!(fs::create_dir_all(&out_dir));
    if link_name.contains('=') {
        println!("cargo:rustc-link-lib={}", link_name);
    } else {
        println!("cargo:rustc-link-lib=static={}", link_name);
    }
    println!("cargo:rustc-link-search=native={}", out_dir.join(search_subdir).display());

    let timestamp = out_dir.join("rustbuild.timestamp");
    if !up_to_date(Path::new("build.rs"), &timestamp) || !up_to_date(&src_dir, &timestamp) {
        Ok(NativeLibBoilerplate { src_dir: src_dir, out_dir: out_dir })
    } else {
        Err(())
    }
}

pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) -> Result<NativeLibBoilerplate, ()> {
    let (link_name, search_path) = match &*env::var("TARGET").unwrap() {
        "x86_64-unknown-linux-gnu" => (
            format!("clang_rt.{}-x86_64", sanitizer_name),
            "build/lib/linux",
        ),
        "x86_64-apple-darwin" => (
            format!("dylib=clang_rt.{}_osx_dynamic", sanitizer_name),
            "build/lib/darwin",
        ),
        _ => return Err(()),
    };
    native_lib_boilerplate("libcompiler_builtins/compiler-rt",
                           sanitizer_name,
                           &link_name,
                           search_path)
}

fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool {
    t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| {
        let meta = t!(e.metadata());
        if meta.is_dir() {
            dir_up_to_date(&e.path(), threshold)
        } else {
            FileTime::from_last_modification_time(&meta) < *threshold
        }
    })
}

fn fail(s: &str) -> ! {
    println!("\n\n{}\n\n", s);
    std::process::exit(1);
}
<commit_msg>build_helper: destination file can't be up to date when not exists<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.

#![deny(warnings)]

extern crate filetime;

use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::{fs, env};

use filetime::FileTime;

/// A helper macro to `unwrap` a result except also print out details like:
///
/// * The file/line of the panic
/// * The expression that failed
/// * The error itself
///
/// This is currently used judiciously throughout the build system rather than
/// using a `Result` with `try!`, but this may change one day...
#[macro_export]
macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum BuildExpectation {
    Succeeding,
    Failing,
    None,
}

pub fn run(cmd: &mut Command, expect: BuildExpectation) {
    println!("running: {:?}", cmd);
    run_silent(cmd, expect);
}

pub fn run_silent(cmd: &mut Command, expect: BuildExpectation) {
    if !try_run_silent(cmd, expect) {
        std::process::exit(1);
    }
}

pub fn try_run_silent(cmd: &mut Command, expect: BuildExpectation) -> bool {
    let status = match cmd.status() {
        Ok(status) => status,
        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                cmd, e)),
    };
    process_status(
        cmd,
        status.success(),
        expect,
        || println!("\n\ncommand did not execute successfully: {:?}\n\
                    expected success, got: {}\n\n",
                    cmd,
                    status))
}

fn process_status<F: FnOnce()>(
    cmd: &Command,
    success: bool,
    expect: BuildExpectation,
    f: F,
) -> bool {
    use BuildExpectation::*;
    match (expect, success) {
        (None, false) => { f(); false },
        // Non-tool build succeeds, everything is good
        (None, true) => true,
        // Tool expected to work and is working
        (Succeeding, true) => true,
        // Tool expected to fail and is failing
        (Failing, false) => {
            println!("This failure is expected (see `src/tools/toolstate.toml`)");
            true
        },
        // Tool expected to work, but is failing
        (Succeeding, false) => {
            f();
            println!("You can disable the tool in `src/tools/toolstate.toml`");
            false
        },
        // Tool expected to fail, but is working
        (Failing, true) => {
            println!("Expected `{:?}` to fail, but it succeeded.\n\
                     Please adjust `src/tools/toolstate.toml` accordingly", cmd);
            false
        }
    }
}

pub fn run_suppressed(cmd: &mut Command, expect: BuildExpectation) {
    if !try_run_suppressed(cmd, expect) {
        std::process::exit(1);
    }
}

pub fn try_run_suppressed(cmd: &mut Command, expect: BuildExpectation) -> bool {
    let output = match cmd.output() {
        Ok(status) => status,
        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                cmd, e)),
    };
    process_status(
        cmd,
        output.status.success(),
        expect,
        || println!("\n\ncommand did not execute successfully: {:?}\n\
                  expected success, got: {}\n\n\
                  stdout ----\n{}\n\
                  stderr ----\n{}\n\n",
                 cmd,
                 output.status,
                 String::from_utf8_lossy(&output.stdout),
                 String::from_utf8_lossy(&output.stderr)))
}

pub fn gnu_target(target: &str) -> String {
    match target {
        "i686-pc-windows-msvc" => "i686-pc-win32".to_string(),
        "x86_64-pc-windows-msvc" => "x86_64-pc-win32".to_string(),
        "i686-pc-windows-gnu" => "i686-w64-mingw32".to_string(),
        "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32".to_string(),
        s => s.to_string(),
    }
}

pub fn make(host: &str) -> PathBuf {
    if host.contains("bitrig") || host.contains("dragonfly") ||
        host.contains("freebsd") || host.contains("netbsd") ||
        host.contains("openbsd") {
        PathBuf::from("gmake")
    } else {
        PathBuf::from("make")
    }
}

pub fn output(cmd: &mut Command) -> String {
    let output = match cmd.stderr(Stdio::inherit()).output() {
        Ok(status) => status,
        Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
                                cmd, e)),
    };
    if !output.status.success() {
        panic!("command did not execute successfully: {:?}\n\
                expected success, got: {}",
               cmd,
               output.status);
    }
    String::from_utf8(output.stdout).unwrap()
}

pub fn rerun_if_changed_anything_in_dir(dir: &Path) {
    let mut stack = dir.read_dir().unwrap()
                       .map(|e| e.unwrap())
                       .filter(|e| &*e.file_name() != ".git")
                       .collect::<Vec<_>>();
    while let Some(entry) = stack.pop() {
        let path = entry.path();
        if entry.file_type().unwrap().is_dir() {
            stack.extend(path.read_dir().unwrap().map(|e| e.unwrap()));
        } else {
            println!("cargo:rerun-if-changed={}", path.display());
        }
    }
}

/// Returns the last-modified time for `path`, or zero if it doesn't exist.
pub fn mtime(path: &Path) -> FileTime {
    fs::metadata(path).map(|f| {
        FileTime::from_last_modification_time(&f)
    }).unwrap_or(FileTime::zero())
}

/// Returns whether `dst` is up to date given that the file or files in `src`
/// are used to generate it.
///
/// Uses last-modified time checks to verify this.
pub fn up_to_date(src: &Path, dst: &Path) -> bool {
    if !dst.exists() {
        return false;
    }
    let threshold = mtime(dst);
    let meta = match fs::metadata(src) {
        Ok(meta) => meta,
        Err(e) => panic!("source {:?} failed to get metadata: {}", src, e),
    };
    if meta.is_dir() {
        dir_up_to_date(src, &threshold)
    } else {
        FileTime::from_last_modification_time(&meta) <= threshold
    }
}

#[must_use]
pub struct NativeLibBoilerplate {
    pub src_dir: PathBuf,
    pub out_dir: PathBuf,
}

impl Drop for NativeLibBoilerplate {
    fn drop(&mut self) {
        t!(File::create(self.out_dir.join("rustbuild.timestamp")));
    }
}

// Perform standard preparations for native libraries that are build only once for all stages.
// Emit rerun-if-changed and linking attributes for Cargo, check if any source files are
// updated, calculate paths used later in actual build with CMake/make or C/C++ compiler.
// If Err is returned, then everything is up-to-date and further build actions can be skipped.
// Timestamps are created automatically when the result of `native_lib_boilerplate` goes out
// of scope, so all the build actions should be completed until then.
pub fn native_lib_boilerplate(src_name: &str,
                              out_name: &str,
                              link_name: &str,
                              search_subdir: &str)
                              -> Result<NativeLibBoilerplate, ()> {
    let current_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
    let src_dir = current_dir.join("..").join(src_name);
    rerun_if_changed_anything_in_dir(&src_dir);

    let out_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap());
    let out_dir = PathBuf::from(out_dir).join(out_name);
    t!(fs::create_dir_all(&out_dir));
    if link_name.contains('=') {
        println!("cargo:rustc-link-lib={}", link_name);
    } else {
        println!("cargo:rustc-link-lib=static={}", link_name);
    }
    println!("cargo:rustc-link-search=native={}", out_dir.join(search_subdir).display());

    let timestamp = out_dir.join("rustbuild.timestamp");
    if !up_to_date(Path::new("build.rs"), &timestamp) || !up_to_date(&src_dir, &timestamp) {
        Ok(NativeLibBoilerplate { src_dir: src_dir, out_dir: out_dir })
    } else {
        Err(())
    }
}

pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) -> Result<NativeLibBoilerplate, ()> {
    let (link_name, search_path) = match &*env::var("TARGET").unwrap() {
        "x86_64-unknown-linux-gnu" => (
            format!("clang_rt.{}-x86_64", sanitizer_name),
            "build/lib/linux",
        ),
        "x86_64-apple-darwin" => (
            format!("dylib=clang_rt.{}_osx_dynamic", sanitizer_name),
            "build/lib/darwin",
        ),
        _ => return Err(()),
    };
    native_lib_boilerplate("libcompiler_builtins/compiler-rt",
                           sanitizer_name,
                           &link_name,
                           search_path)
}

fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool {
    t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| {
        let meta = t!(e.metadata());
        if meta.is_dir() {
            dir_up_to_date(&e.path(), threshold)
        } else {
            FileTime::from_last_modification_time(&meta) < *threshold
        }
    })
}

fn fail(s: &str) -> ! {
    println!("\n\n{}\n\n", s);
    std::process::exit(1);
}
<|endoftext|>


<commit_before>use std::io::{Read, Write, Error};
use std::path::Path;

use super::super::utils::DEFAULT_BUF_SIZE;
use super::super::io::binary::*;

#[derive(Debug)]
enum Directive {
	// raw, file
	Line(Vec<u8>, String),
	// raw
	HdrStop(Vec<u8>),
	// raw
	Unknown(Vec<u8>)
}

pub fn filter_preprocessed(reader: &mut Read, writer: &mut Write, marker: &Option<String>, keep_headers: bool) -> Result<(), Error> {
	let mut line_begin = true;
	// Entry file.
	let mut entry_file: Option<String> = None;
	let mut header_found: bool = false;
	loop {
		let c = try! (read_u8(reader));
		match c {
			b'\n' | b'\r' => {
				if keep_headers {
					try! (write_u8(writer, c));
				}
				line_begin = true;
			}
			b'\t' | b' ' => {
				if keep_headers {
					try! (write_u8(writer, c));
				}
			}
			b'#' if line_begin => {
				let directive = try! (read_directive(c, reader));
				match directive {
					Directive::Line(raw, raw_file) => {
						let file = raw_file.replace("\\", "/");
						entry_file = match entry_file {
							Some(path) => {
								if header_found && (path  == file) {
									try! (writer.write_all(b"#pragma hdrstop\n"));
									try! (writer.write_all(raw.as_slice()));
									break;
								}
								match *marker {
									Some(ref raw_path) => {
										let path = raw_path.replace("\\", "/");
										if file == path || Path::new(file.as_slice()).ends_with(&Path::new(path.as_slice())) {
											header_found = true;
										}
									}
									None => {}
								}
								Some(path)
							}
							None => Some(file)
						};
						if keep_headers {
							try! (writer.write_all(raw.as_slice()));
						}
					}
					Directive::HdrStop(raw) => {
						try! (writer.write_all(raw.as_slice()));
						break;
					}
					Directive::Unknown(raw) => {
						if keep_headers {
							try! (writer.write_all(raw.as_slice()));
						}
					}
				}
			}
			_ => {
				if keep_headers {
					try! (write_u8(writer, c));
				}
				line_begin = false;
			}
		}
	}
	// Copy end of stream.
	let mut buf: [u8; DEFAULT_BUF_SIZE] = [0; DEFAULT_BUF_SIZE];
	loop {
		let size = try! (reader.read(&mut buf));
		if size <= 0 {
			break;
		}
		try! (writer.write_all(&buf.as_slice()[0..size]));
	}
	Ok(())
}

fn read_directive(first: u8, reader: &mut Read) -> Result<Directive, Error> {
	let mut raw: Vec<u8> = Vec::new();
	raw.push(first);
	let (next, token) = try! (read_token(None, reader, &mut raw));
	match token.as_slice() {
		b"line" => read_directive_line(next, reader, raw),
		b"pragma" => read_directive_pragma(next, reader, raw),
		_ => {
			try! (skip_line(next, reader, &mut raw));
			Ok(Directive::Unknown(raw))
		}
	}
}

fn read_token(first: Option<u8>, reader: &mut Read, raw: &mut Vec<u8>) -> Result<(Option<u8>, Vec<u8>), Error> {
	match try! (skip_spaces(first, reader, raw)) {
		Some(first_char) => {
			let mut token: Vec<u8> = Vec::new();
			let mut escape = false;
			let quote: bool;
			if first_char == b'"' {
				quote = true;
			} else {
				token.push(first_char);
				quote = false;
			}
			loop {
				let c = try! (read_u8(reader));
				raw.push(c);
				if quote {
					if escape {
						match c {
							b'n' => token.push(b'\n'),
							b'r' => token.push(b'\r'),
							b't' => token.push(b'\t'),
							v => token.push(v)
						}
						escape = false;
					} else if c == ('\\' as u8) {
						escape = true;
					} else if c == b'"' {
						let n = try! (read_u8(reader));
						raw.push(n);
						return Ok((Some(n), token));
					} else {
						token.push(c);
					}
				} else {
					match c {
						b'a' ... b'z' | b'A' ... b'Z' | b'0' ... b'9' => {
							token.push(c);
						}
						_ => {
							return Ok((Some(c), token));
						}
					}
				}
			}
		}
		None => {
			return Ok((None, Vec::new()));
		}
	}
}

fn read_directive_line(first: Option<u8>, reader: &mut Read, mut raw: Vec<u8>) -> Result<Directive, Error> {
	// Line number
	let (next1, _) = try! (read_token(first, reader, &mut raw));
	// File name
	let (next2, file) = try! (read_token(next1, reader, &mut raw));
	try! (skip_line(next2, reader, &mut raw));
	Ok(Directive::Line(raw, String::from_utf8_lossy(file.as_slice()).to_string()))
}

fn read_directive_pragma(first: Option<u8>, reader: &mut Read, mut raw: Vec<u8>) -> Result<Directive, Error> {
	let (next, token) = try! (read_token(first, reader, &mut raw));
	try! (skip_line(next, reader, &mut raw));
	match token.as_slice() {
		b"hdrstop" => Ok(Directive::HdrStop(raw)),
		_ => Ok(Directive::Unknown(raw))
	}
}

fn skip_spaces(first: Option<u8>, reader: &mut Read, raw: &mut Vec<u8>) -> Result<Option<u8>, Error> {
	match first {
		Some(c) => {
			match c {
				b'\n' | b'\r' => {return Ok(None);}
				b'\t' | b' ' => {}
				_ => {return Ok(first);}
			}
		}
		_ => {}
	}
	loop {
		let c = try! (read_u8(reader));
		try! (write_u8(raw, c));
		match c {
			b'\n' | b'\r' => {return Ok(None);}
			b'\t' | b' ' => {}
			_ => {return Ok(Some(c));}
		}
	}
}

fn skip_line(first: Option<u8>, reader: &mut Read, raw: &mut Vec<u8>) -> Result<(), Error> {
	match first {
		Some(c) => {
			match c {
				b'\n' | b'\r' => {return Ok(());}
				_ => {}
			}
		}
		_ => {}
	}
	loop {
		let c = try! (read_u8(reader));
		try! (write_u8(raw, c));
		match c {
			b'\n' | b'\r' => {return Ok(());}
			_ => {}
		}
	}
}

#[cfg(test)]
mod test {
	use std::io::Cursor;

	fn check_filter(original: &str, expected: &str, marker: Option<String>, keep_headers: bool) {
		let mut writer: Vec<u8> = Vec::new();
		let mut stream: Vec<u8> = Vec::new();
		stream.push_all(original.as_bytes());
		match super::filter_preprocessed(&mut Cursor::new(stream), &mut writer, &marker, keep_headers) {
			Ok(_) => {assert_eq! (String::from_utf8_lossy(writer.as_slice()), expected)}
			Err(e) => {panic! (e);}
		}
	}

	#[test]
	fn test_filter_precompiled_keep() {
		check_filter(
r#"#line 1 "sample.cpp"
#line 1 "e:/work/octobuild/test_cl/sample header.h"
# pragma once
void hello();
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"#line 1 "sample.cpp"
#line 1 "e:/work/octobuild/test_cl/sample header.h"
# pragma once
void hello();
#pragma hdrstop
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, Some("sample header.h".to_string()), true)
	}

	#[test]
	fn test_filter_precompiled_remove() {
		check_filter(
r#"#line 1 "sample.cpp"
#line 1 "e:/work/octobuild/test_cl/sample header.h"
# pragma once
void hello1();
void hello2();
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"#pragma hdrstop
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, Some("sample header.h".to_string()), false);
	}

	#[test]
	fn test_filter_precompiled_hdrstop() {
		check_filter(
r#"#line 1 "sample.cpp"
 #line 1 "e:/work/octobuild/test_cl/sample header.h"
void hello();
# pragma  hdrstop
void data();
# pragma once
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"# pragma  hdrstop
void data();
# pragma once
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, None, false);
	}

	#[test]
	fn test_filter_precompiled_winpath() {
		check_filter(
r#"#line 1 "sample.cpp"
#line 1 "e:\\work\\octobuild\\test_cl\\sample header.h"
# pragma once
void hello();
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"#line 1 "sample.cpp"
#line 1 "e:\\work\\octobuild\\test_cl\\sample header.h"
# pragma once
void hello();
#pragma hdrstop
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, Some("e:\\work\\octobuild\\test_cl\\sample header.h".to_string()), true);
	}
}
<commit_msg>Add collecting source file name on parsing preprocessort output<commit_after>use std::collections::HashSet;
use std::io::{Read, Write, Error};
use std::iter::FromIterator;
use std::path::Path;

use super::super::utils::DEFAULT_BUF_SIZE;
use super::super::io::binary::*;

#[derive(Debug)]
enum Directive {
	// raw, file
	Line(Vec<u8>, String),
	// raw
	HdrStop(Vec<u8>),
	// raw
	Unknown(Vec<u8>)
}

pub fn filter_preprocessed(reader: &mut Read, writer: &mut Write, marker: &Option<String>, keep_headers: bool) -> Result<Vec<String>, Error> {
	let mut line_begin = true;
	// Entry file.
	let mut entry_file: Option<String> = None;
	let mut header_found: bool = false;
	let mut header_files: HashSet<String> = HashSet::new();
	loop {
		let c = try! (read_u8(reader));
		match c {
			b'\n' | b'\r' => {
				if keep_headers {
					try! (write_u8(writer, c));
				}
				line_begin = true;
			}
			b'\t' | b' ' => {
				if keep_headers {
					try! (write_u8(writer, c));
				}
			}
			b'#' if line_begin => {
				let directive = try! (read_directive(c, reader));
				match directive {
					Directive::Line(raw, raw_file) => {
						let file = raw_file.replace("\\", "/");
						entry_file = match entry_file {
							Some(path) => {
								if header_found && (path == file) {
									try! (writer.write_all(b"#pragma hdrstop\n"));
									try! (writer.write_all(raw.as_slice()));
									break;
								}
								match *marker {
									Some(ref raw_path) => {
										let path = raw_path.replace("\\", "/");
										if file == path || Path::new(file.as_slice()).ends_with(&Path::new(path.as_slice())) {
											header_found = true;
										}
									}
									None => {}
								}
								Some(path)
							}
							None => Some(file.clone())
						};
						header_files.insert(file);
						if keep_headers {
							try! (writer.write_all(raw.as_slice()));
						}
					}
					Directive::HdrStop(raw) => {
						try! (writer.write_all(raw.as_slice()));
						break;
					}
					Directive::Unknown(raw) => {
						if keep_headers {
							try! (writer.write_all(raw.as_slice()));
						}
					}
				}
			}
			_ => {
				if keep_headers {
					try! (write_u8(writer, c));
				}
				line_begin = false;
			}
		}
	}
	// Copy end of stream.
	let mut buf: [u8; DEFAULT_BUF_SIZE] = [0; DEFAULT_BUF_SIZE];
	loop {
		let size = try! (reader.read(&mut buf));
		if size <= 0 {
			break;
		}
		try! (writer.write_all(&buf.as_slice()[0..size]));
	}
	Ok(Vec::from_iter(header_files.into_iter()))
}

fn read_directive(first: u8, reader: &mut Read) -> Result<Directive, Error> {
	let mut raw: Vec<u8> = Vec::new();
	raw.push(first);
	let (next, token) = try! (read_token(None, reader, &mut raw));
	match token.as_slice() {
		b"line" => read_directive_line(next, reader, raw),
		b"pragma" => read_directive_pragma(next, reader, raw),
		_ => {
			try! (skip_line(next, reader, &mut raw));
			Ok(Directive::Unknown(raw))
		}
	}
}

fn read_token(first: Option<u8>, reader: &mut Read, raw: &mut Vec<u8>) -> Result<(Option<u8>, Vec<u8>), Error> {
	match try! (skip_spaces(first, reader, raw)) {
		Some(first_char) => {
			let mut token: Vec<u8> = Vec::new();
			let mut escape = false;
			let quote: bool;
			if first_char == b'"' {
				quote = true;
			} else {
				token.push(first_char);
				quote = false;
			}
			loop {
				let c = try! (read_u8(reader));
				raw.push(c);
				if quote {
					if escape {
						match c {
							b'n' => token.push(b'\n'),
							b'r' => token.push(b'\r'),
							b't' => token.push(b'\t'),
							v => token.push(v)
						}
						escape = false;
					} else if c == ('\\' as u8) {
						escape = true;
					} else if c == b'"' {
						let n = try! (read_u8(reader));
						raw.push(n);
						return Ok((Some(n), token));
					} else {
						token.push(c);
					}
				} else {
					match c {
						b'a' ... b'z' | b'A' ... b'Z' | b'0' ... b'9' => {
							token.push(c);
						}
						_ => {
							return Ok((Some(c), token));
						}
					}
				}
			}
		}
		None => {
			return Ok((None, Vec::new()));
		}
	}
}

fn read_directive_line(first: Option<u8>, reader: &mut Read, mut raw: Vec<u8>) -> Result<Directive, Error> {
	// Line number
	let (next1, _) = try! (read_token(first, reader, &mut raw));
	// File name
	let (next2, file) = try! (read_token(next1, reader, &mut raw));
	try! (skip_line(next2, reader, &mut raw));
	Ok(Directive::Line(raw, String::from_utf8_lossy(file.as_slice()).to_string()))
}

fn read_directive_pragma(first: Option<u8>, reader: &mut Read, mut raw: Vec<u8>) -> Result<Directive, Error> {
	let (next, token) = try! (read_token(first, reader, &mut raw));
	try! (skip_line(next, reader, &mut raw));
	match token.as_slice() {
		b"hdrstop" => Ok(Directive::HdrStop(raw)),
		_ => Ok(Directive::Unknown(raw))
	}
}

fn skip_spaces(first: Option<u8>, reader: &mut Read, raw: &mut Vec<u8>) -> Result<Option<u8>, Error> {
	match first {
		Some(c) => {
			match c {
				b'\n' | b'\r' => {return Ok(None);}
				b'\t' | b' ' => {}
				_ => {return Ok(first);}
			}
		}
		_ => {}
	}
	loop {
		let c = try! (read_u8(reader));
		try! (write_u8(raw, c));
		match c {
			b'\n' | b'\r' => {return Ok(None);}
			b'\t' | b' ' => {}
			_ => {return Ok(Some(c));}
		}
	}
}

fn skip_line(first: Option<u8>, reader: &mut Read, raw: &mut Vec<u8>) -> Result<(), Error> {
	match first {
		Some(c) => {
			match c {
				b'\n' | b'\r' => {return Ok(());}
				_ => {}
			}
		}
		_ => {}
	}
	loop {
		let c = try! (read_u8(reader));
		try! (write_u8(raw, c));
		match c {
			b'\n' | b'\r' => {return Ok(());}
			_ => {}
		}
	}
}

#[cfg(test)]
mod test {
	use std::io::Cursor;

	fn check_filter(original: &str, expected: &str, marker: Option<String>, keep_headers: bool) {
		let mut writer: Vec<u8> = Vec::new();
		let mut stream: Vec<u8> = Vec::new();
		stream.push_all(original.as_bytes());
		match super::filter_preprocessed(&mut Cursor::new(stream), &mut writer, &marker, keep_headers) {
			Ok(_) => {assert_eq! (String::from_utf8_lossy(writer.as_slice()), expected)}
			Err(e) => {panic! (e);}
		}
	}

	#[test]
	fn test_filter_precompiled_keep() {
		check_filter(
r#"#line 1 "sample.cpp"
#line 1 "e:/work/octobuild/test_cl/sample header.h"
# pragma once
void hello();
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"#line 1 "sample.cpp"
#line 1 "e:/work/octobuild/test_cl/sample header.h"
# pragma once
void hello();
#pragma hdrstop
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, Some("sample header.h".to_string()), true)
	}

	#[test]
	fn test_filter_precompiled_remove() {
		check_filter(
r#"#line 1 "sample.cpp"
#line 1 "e:/work/octobuild/test_cl/sample header.h"
# pragma once
void hello1();
void hello2();
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"#pragma hdrstop
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, Some("sample header.h".to_string()), false);
	}

	#[test]
	fn test_filter_precompiled_hdrstop() {
		check_filter(
r#"#line 1 "sample.cpp"
 #line 1 "e:/work/octobuild/test_cl/sample header.h"
void hello();
# pragma  hdrstop
void data();
# pragma once
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"# pragma  hdrstop
void data();
# pragma once
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, None, false);
	}

	#[test]
	fn test_filter_precompiled_winpath() {
		check_filter(
r#"#line 1 "sample.cpp"
#line 1 "e:\\work\\octobuild\\test_cl\\sample header.h"
# pragma once
void hello();
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"#line 1 "sample.cpp"
#line 1 "e:\\work\\octobuild\\test_cl\\sample header.h"
# pragma once
void hello();
#pragma hdrstop
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, Some("e:\\work\\octobuild\\test_cl\\sample header.h".to_string()), true);
	}
}
<|endoftext|>


<commit_before>#![feature(const_fn)]
extern crate spin;

static INIT: spin::Once<usize> = spin::Once::new();

fn get_cached_val() -> usize {
    *INIT.call_once(expensive_computation)
}

fn expensive_computation() -> usize {
    panic!("Once aborted");
}

fn thread_fun() {
    println!("value: {}", get_cached_val());
    println!("Done.");
}

fn main() {
    let j1 = ::std::thread::spawn(thread_fun);
    let j2 = ::std::thread::spawn(thread_fun);

    println!("Thread 1 panicked: {:?}", j1.join().is_err());
    println!("Thread 2 panicked: {:?}", j2.join().is_err());
}
<commit_msg>Remove example as it would fail the builds<commit_after><|endoftext|>


<commit_before>extern crate json_pointer;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate quickcheck;
extern crate regex;

use json_pointer::JsonPointer;
use quickcheck::TestResult;
use regex::Regex;

quickcheck! {

/// Essentially, `unparse(parse("..."))` should be a no-op.
fn faithful_parse(s: String) -> TestResult {
    match s.parse::<JsonPointer<_, _>>() {
        Ok(ptr) => if s == ptr.to_string() {
            TestResult::passed()
        } else {
            TestResult::failed()
        },
        Err(_) => TestResult::discard(),
    }
}

/// Ensuring that parsing succeeds for all strings that match the regex for
/// JSON pointers.
fn parses_all_valid(s: String) -> bool {
    lazy_static! {
        static ref JSON_POINTER_REGEX: Regex = Regex::new("^(/([^/~]|~[01])*)*$").unwrap();
    }

    let matches_regex = JSON_POINTER_REGEX.is_match(&s);
    let parses = s.parse::<JsonPointer<_, _>>().is_ok();

    (matches_regex == parses)
}

}
<commit_msg>Changes faithful_parse to not apply for URI Fragment Identifier Representation.<commit_after>extern crate json_pointer;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate quickcheck;
extern crate regex;

use json_pointer::JsonPointer;
use quickcheck::TestResult;
use regex::Regex;

quickcheck! {

/// Essentially, `unparse(parse("..."))` should be a no-op when not in URI
/// Fragment Identifier Representation.
fn faithful_parse(s: String) -> TestResult {
    if s.chars().next() == Some('#') {
        TestResult::discard()
    } else {
        match s.parse::<JsonPointer<_, _>>() {
            Ok(ptr) => if s == ptr.to_string() {
            TestResult::passed()
            } else {
                TestResult::failed()
            },
            Err(_) => TestResult::discard(),
        }
    }
}

/// Ensuring that parsing succeeds for all strings that match the regex for
/// JSON pointers.
fn parses_all_valid(s: String) -> bool {
    lazy_static! {
        static ref JSON_POINTER_REGEX: Regex = Regex::new("^(/([^/~]|~[01])*)*$").unwrap();
    }

    let matches_regex = JSON_POINTER_REGEX.is_match(&s);
    let parses = s.parse::<JsonPointer<_, _>>().is_ok();

    (matches_regex == parses)
}

}
<|endoftext|>