<commit_before>/* diosix hypervisor code for handling hardware interrupts and software exceptions
 *
 * (c) Chris Williams, 2019-2020.
 *
 * See LICENSE for usage and copying.
 */

use super::scheduler;
use super::capsule;
use super::pcore;

/* platform-specific code must implement all this */
use platform;
use platform::irq::{IRQContext, IRQType, IRQCause, IRQ};
use platform::cpu::PrivilegeMode;

/* hypervisor_irq_handler
   entry point for hardware interrupts and software exceptions, collectively known as IRQs.
   call down into platform-specific handlers
   => context = platform-specific context of the IRQ
   <= returns flag word describing IRQ
*/
#[no_mangle]
pub extern "C" fn hypervisor_irq_handler(context: IRQContext)
{
    let irq = platform::irq::dispatch(context);
    match irq.irq_type
    {
        IRQType::Exception => exception(irq),
        IRQType::Interrupt => interrupt(irq),
    };
}

/* handle software exception */
fn exception(irq: IRQ)
{
    match (irq.fatal, irq.privilege_mode, irq.cause)
    {
        /* catch non-fatal supervisor-level exceptions */
        (false, PrivilegeMode::Supervisor, IRQCause::SupervisorEnvironmentCall) =>
        {
            if let Some(c) = pcore::PhysicalCore::get_capsule_id()
            {
                hvdebug!("Environment call from supervisor-mode capsule ID {}", c);
            }
            else
            {
                hvalert!("BUG: Environment call from supervisor mode but no capsule found");
            }
        },

        /* catch fatal supervisor-level exceptions */
        (true, PrivilegeMode::Supervisor, cause) =>
        {
            hvalert!(
                "Fatal exception in {:?}: {:?} at 0x{:x}, stack 0x{:x}",
                PrivilegeMode::Supervisor, cause, irq.pc, irq.sp);

            /* terminate the capsule running on this core */
            if let Some(c) = pcore::PhysicalCore::get_capsule_id()
            {
                if capsule::destroy(c).is_ok() != true
                {
                    hvalert!("BUG: Could not kill capsule ID {}", c);
                }
            }
            else
            {
                hvalert!("BUG: Exception in supervisor mode but no capsule found");
            }

            /* force a context switch */
            scheduler::run_next(true);
        },

        /* catch everything else, halting if fatal */
        (fatal, privilege, cause) =>
        {
            hvalert!("Unhandled exception in {:?}: {:?} at 0x{:x}, stack 0x{:x}, fatal = {:?}",
                privilege, cause, irq.pc, irq.sp, fatal);
            debughousekeeper!(); // flush the debug output

            /* stop here if we hit an unhandled fatal exception */
            if fatal == true
            {
                loop {}
            }
        }
    };
}

/* handle hardware interrupt */
fn interrupt(irq: IRQ)
{
    match irq.cause
    {
        /* handle our scheduler's timer by picking another thing to run, if possible */
        IRQCause::HypervisorTimer => scheduler::run_next(false),
        _ => hvdebug!("Unhandled hardware interrupt: {:?}", irq.cause)
    };

    /* clear the interrupt condition */
    platform::irq::acknowledge(irq);
}
<commit_msg>Fix warning when building debug target<commit_after>/* diosix hypervisor code for handling hardware interrupts and software exceptions
 *
 * (c) Chris Williams, 2019-2020.
 *
 * See LICENSE for usage and copying.
 */

use super::scheduler;
use super::capsule;
use super::pcore;

/* platform-specific code must implement all this */
use platform;
use platform::irq::{IRQContext, IRQType, IRQCause, IRQ};
use platform::cpu::PrivilegeMode;

/* hypervisor_irq_handler
   entry point for hardware interrupts and software exceptions, collectively known as IRQs.
   call down into platform-specific handlers
   => context = platform-specific context of the IRQ
   <= returns flag word describing IRQ
*/
#[no_mangle]
pub extern "C" fn hypervisor_irq_handler(context: IRQContext)
{
    let irq = platform::irq::dispatch(context);
    match irq.irq_type
    {
        IRQType::Exception => exception(irq),
        IRQType::Interrupt => interrupt(irq),
    };
}

/* handle software exception */
fn exception(irq: IRQ)
{
    match (irq.fatal, irq.privilege_mode, irq.cause)
    {
        /* catch non-fatal supervisor-level exceptions */
        (false, PrivilegeMode::Supervisor, IRQCause::SupervisorEnvironmentCall) =>
        {
            if let Some(_c) = pcore::PhysicalCore::get_capsule_id()
            {
                hvdebug!("Environment call from supervisor-mode capsule ID {}", _c);
            }
            else
            {
                hvalert!("BUG: Environment call from supervisor mode but no capsule found");
            }
        },

        /* catch fatal supervisor-level exceptions */
        (true, PrivilegeMode::Supervisor, cause) =>
        {
            hvalert!(
                "Fatal exception in {:?}: {:?} at 0x{:x}, stack 0x{:x}",
                PrivilegeMode::Supervisor, cause, irq.pc, irq.sp);

            /* terminate the capsule running on this core */
            if let Some(c) = pcore::PhysicalCore::get_capsule_id()
            {
                if capsule::destroy(c).is_ok() != true
                {
                    hvalert!("BUG: Could not kill capsule ID {}", c);
                }
            }
            else
            {
                hvalert!("BUG: Exception in supervisor mode but no capsule found");
            }

            /* force a context switch */
            scheduler::run_next(true);
        },

        /* catch everything else, halting if fatal */
        (fatal, privilege, cause) =>
        {
            hvalert!("Unhandled exception in {:?}: {:?} at 0x{:x}, stack 0x{:x}, fatal = {:?}",
                privilege, cause, irq.pc, irq.sp, fatal);
            debughousekeeper!(); // flush the debug output

            /* stop here if we hit an unhandled fatal exception */
            if fatal == true
            {
                loop {}
            }
        }
    };
}

/* handle hardware interrupt */
fn interrupt(irq: IRQ)
{
    match irq.cause
    {
        /* handle our scheduler's timer by picking another thing to run, if possible */
        IRQCause::HypervisorTimer => scheduler::run_next(false),
        _ => hvdebug!("Unhandled hardware interrupt: {:?}", irq.cause)
    };

    /* clear the interrupt condition */
    platform::irq::acknowledge(irq);
}
<|endoftext|>


<commit_before>// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

/*!
 * A type representing values that may be computed concurrently and
 * operations for working with them.
 *
 * # Example
 *
 * ~~~
 * let delayed_fib = future::spawn {|| fib(5000) };
 * make_a_sandwich();
 * io::println(fmt!("fib(5000) = %?", delayed_fib.get()))
 * ~~~
 */

use either::Either;
use pipes::recv;
use unsafe::copy_lifetime;

export Future;
export extensions;
export from_value;
export from_port;
export from_fn;
export get;
export with;
export spawn;

// for task.rs
export future_pipe;

#[doc = "The future type"]
struct Future<A> {
    /*priv*/ mut state: FutureState<A>;

    // FIXME(#2829) -- futures should not be copyable, because they close
    // over fn~'s that have pipes and so forth within!
    drop {}
}

priv enum FutureState<A> {
    Pending(fn~() -> A),
    Evaluating,
    Forced(A)
}

/// Methods on the `future` type
impl<A:Copy> Future<A> {
    fn get() -> A {
        //! Get the value of the future

        get(&self)
    }
}

impl<A> Future<A> {
    fn get_ref(&self) -> &self/A {
        get_ref(self)
    }

    fn with<B>(blk: fn((&A)) -> B) -> B {
        //! Work with the value without copying it

        with(&self, blk)
    }
}

fn from_value<A>(+val: A) -> Future<A> {
    /*!
     * Create a future from a value
     *
     * The value is immediately available and calling `get` later will
     * not block.
     */

    Future {state: Forced(val)}
}

fn from_port<A:Send>(+port: future_pipe::client::waiting<A>) -> Future<A> {
    /*!
     * Create a future from a port
     *
     * The first time that the value is requested the task will block
     * waiting for the result to be received on the port.
     */

    let port = ~mut Some(port);
    do from_fn |move port| {
        let mut port_ = None;
        port_ <-> *port;
        let port = option::unwrap(port_);
        match recv(port) {
            future_pipe::completed(move data) => data
        }
    }
}

fn from_fn<A>(+f: ~fn() -> A) -> Future<A> {
    /*!
     * Create a future from a function.
     *
     * The first time that the value is requested it will be retreived by
     * calling the function.  Note that this function is a local
     * function. It is not spawned into another task.
     */

    Future {state: Pending(f)}
}

fn spawn<A:Send>(+blk: fn~() -> A) -> Future<A> {
    /*!
     * Create a future from a unique closure.
     *
     * The closure will be run in a new task and its result used as the
     * value of the future.
     */

    from_port(pipes::spawn_service_recv(future_pipe::init, |ch| {
        future_pipe::server::completed(ch, blk());
    }))
}

fn get_ref<A>(future: &r/Future<A>) -> &r/A {
    /*!
     * Executes the future's closure and then returns a borrowed
     * pointer to the result.  The borrowed pointer lasts as long as
     * the future.
     */

    // The unsafety here is to hide the aliases from borrowck, which
    // would otherwise be concerned that someone might reassign
    // `future.state` and cause the value of the future to be freed.
    // But *we* know that once `future.state` is `Forced()` it will
    // never become "unforced"---so we can safely return a pointer
    // into the interior of the Forced() variant which will last as
    // long as the future itself.

    match future.state {
      Forced(ref v) => { // v here has type &A, but with a shorter lifetime.
        return unsafe{ copy_lifetime(future, v) }; // ...extend it.
      }
      Evaluating => {
        fail ~"Recursive forcing of future!";
      }
      Pending(_) => {}
    }

    let mut state = Evaluating;
    state <-> future.state;
    match move state {
      Forced(_) | Evaluating => {
        fail ~"Logic error.";
      }
      Pending(move f) => {
        future.state = Forced(f());
        return get_ref(future);
      }
    }
}

fn get<A:Copy>(future: &Future<A>) -> A {
    //! Get the value of the future

    *get_ref(future)
}

fn with<A,B>(future: &Future<A>, blk: fn((&A)) -> B) -> B {
    //! Work with the value without copying it

    blk(get_ref(future))
}

proto! future_pipe (
    waiting:recv<T:Send> {
        completed(T) -> !
    }
)

#[allow(non_implicitly_copyable_typarams)]
mod test {
    #[test]
    fn test_from_value() {
        let f = from_value(~"snail");
        assert get(&f) == ~"snail";
    }

    #[test]
    fn test_from_port() {
        let (po, ch) = future_pipe::init();
        future_pipe::server::completed(ch, ~"whale");
        let f = from_port(po);
        assert get(&f) == ~"whale";
    }

    #[test]
    fn test_from_fn() {
        let f = from_fn(|| ~"brail");
        assert get(&f) == ~"brail";
    }

    #[test]
    fn test_interface_get() {
        let f = from_value(~"fail");
        assert f.get() == ~"fail";
    }

    #[test]
    fn test_with() {
        let f = from_value(~"nail");
        assert with(&f, |v| copy *v) == ~"nail";
    }

    #[test]
    fn test_get_ref_method() {
        let f = from_value(22);
        assert *f.get_ref() == 22;
    }

    #[test]
    fn test_get_ref_fn() {
        let f = from_value(22);
        assert *get_ref(&f) == 22;
    }

    #[test]
    fn test_interface_with() {
        let f = from_value(~"kale");
        assert f.with(|v| copy *v) == ~"kale";
    }

    #[test]
    fn test_spawn() {
        let f = spawn(|| ~"bale");
        assert get(&f) == ~"bale";
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn test_futurefail() {
        let f = spawn(|| fail);
        let _x: ~str = get(&f);
    }

    #[test]
    fn test_sendable_future() {
        let expected = ~"schlorf";
        let f = do spawn |copy expected| { expected };
        do task::spawn {
            let actual = get(&f);
            assert actual == expected;
        }
    }
}
<commit_msg>core: change FutureState Forced(A) to Forced(~A)<commit_after>// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

/*!
 * A type representing values that may be computed concurrently and
 * operations for working with them.
 *
 * # Example
 *
 * ~~~
 * let delayed_fib = future::spawn {|| fib(5000) };
 * make_a_sandwich();
 * io::println(fmt!("fib(5000) = %?", delayed_fib.get()))
 * ~~~
 */

use either::Either;
use pipes::recv;
use unsafe::copy_lifetime;

export Future;
export extensions;
export from_value;
export from_port;
export from_fn;
export get;
export with;
export spawn;

// for task.rs
export future_pipe;

#[doc = "The future type"]
struct Future<A> {
    /*priv*/ mut state: FutureState<A>;

    // FIXME(#2829) -- futures should not be copyable, because they close
    // over fn~'s that have pipes and so forth within!
    drop {}
}

priv enum FutureState<A> {
    Pending(fn~() -> A),
    Evaluating,
    Forced(~A)
}

/// Methods on the `future` type
impl<A:Copy> Future<A> {
    fn get() -> A {
        //! Get the value of the future

        get(&self)
    }
}

impl<A> Future<A> {
    fn get_ref(&self) -> &self/A {
        get_ref(self)
    }

    fn with<B>(blk: fn((&A)) -> B) -> B {
        //! Work with the value without copying it

        with(&self, blk)
    }
}

fn from_value<A>(+val: A) -> Future<A> {
    /*!
     * Create a future from a value
     *
     * The value is immediately available and calling `get` later will
     * not block.
     */

    Future {state: Forced(~val)}
}

fn from_port<A:Send>(+port: future_pipe::client::waiting<A>) -> Future<A> {
    /*!
     * Create a future from a port
     *
     * The first time that the value is requested the task will block
     * waiting for the result to be received on the port.
     */

    let port = ~mut Some(port);
    do from_fn |move port| {
        let mut port_ = None;
        port_ <-> *port;
        let port = option::unwrap(port_);
        match recv(port) {
            future_pipe::completed(move data) => data
        }
    }
}

fn from_fn<A>(+f: ~fn() -> A) -> Future<A> {
    /*!
     * Create a future from a function.
     *
     * The first time that the value is requested it will be retreived by
     * calling the function.  Note that this function is a local
     * function. It is not spawned into another task.
     */

    Future {state: Pending(f)}
}

fn spawn<A:Send>(+blk: fn~() -> A) -> Future<A> {
    /*!
     * Create a future from a unique closure.
     *
     * The closure will be run in a new task and its result used as the
     * value of the future.
     */

    from_port(pipes::spawn_service_recv(future_pipe::init, |ch| {
        future_pipe::server::completed(ch, blk());
    }))
}

fn get_ref<A>(future: &r/Future<A>) -> &r/A {
    /*!
     * Executes the future's closure and then returns a borrowed
     * pointer to the result.  The borrowed pointer lasts as long as
     * the future.
     */

    // The unsafety here is to hide the aliases from borrowck, which
    // would otherwise be concerned that someone might reassign
    // `future.state` and cause the value of the future to be freed.
    // But *we* know that once `future.state` is `Forced()` it will
    // never become "unforced"---so we can safely return a pointer
    // into the interior of the Forced() variant which will last as
    // long as the future itself.

    match future.state {
      Forced(ref v) => { // v here has type &A, but with a shorter lifetime.
        return unsafe{ copy_lifetime(future, &**v) }; // ...extend it.
      }
      Evaluating => {
        fail ~"Recursive forcing of future!";
      }
      Pending(_) => {}
    }

    let mut state = Evaluating;
    state <-> future.state;
    match move state {
      Forced(_) | Evaluating => {
        fail ~"Logic error.";
      }
      Pending(move f) => {
        future.state = Forced(~f());
        return get_ref(future);
      }
    }
}

fn get<A:Copy>(future: &Future<A>) -> A {
    //! Get the value of the future

    *get_ref(future)
}

fn with<A,B>(future: &Future<A>, blk: fn((&A)) -> B) -> B {
    //! Work with the value without copying it

    blk(get_ref(future))
}

proto! future_pipe (
    waiting:recv<T:Send> {
        completed(T) -> !
    }
)

#[allow(non_implicitly_copyable_typarams)]
mod test {
    #[test]
    fn test_from_value() {
        let f = from_value(~"snail");
        assert get(&f) == ~"snail";
    }

    #[test]
    fn test_from_port() {
        let (po, ch) = future_pipe::init();
        future_pipe::server::completed(ch, ~"whale");
        let f = from_port(po);
        assert get(&f) == ~"whale";
    }

    #[test]
    fn test_from_fn() {
        let f = from_fn(|| ~"brail");
        assert get(&f) == ~"brail";
    }

    #[test]
    fn test_interface_get() {
        let f = from_value(~"fail");
        assert f.get() == ~"fail";
    }

    #[test]
    fn test_with() {
        let f = from_value(~"nail");
        assert with(&f, |v| copy *v) == ~"nail";
    }

    #[test]
    fn test_get_ref_method() {
        let f = from_value(22);
        assert *f.get_ref() == 22;
    }

    #[test]
    fn test_get_ref_fn() {
        let f = from_value(22);
        assert *get_ref(&f) == 22;
    }

    #[test]
    fn test_interface_with() {
        let f = from_value(~"kale");
        assert f.with(|v| copy *v) == ~"kale";
    }

    #[test]
    fn test_spawn() {
        let f = spawn(|| ~"bale");
        assert get(&f) == ~"bale";
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(target_os = "win32"))]
    fn test_futurefail() {
        let f = spawn(|| fail);
        let _x: ~str = get(&f);
    }

    #[test]
    fn test_sendable_future() {
        let expected = ~"schlorf";
        let f = do spawn |copy expected| { expected };
        do task::spawn {
            let actual = get(&f);
            assert actual == expected;
        }
    }
}
<|endoftext|>


<commit_before>use core::{prelude::*, util::sort::Rated};
use diesel::r2d2::{self, Pool};
use infrastructure::error::AppError;
use rocket::{self,
             config::{Config, Environment},
             Rocket};
use rocket_contrib::Json;
use std::{collections::HashMap, result, sync::Mutex};

#[cfg(feature = "email")]
use infrastructure::mail;

lazy_static! {
    static ref ENTRY_RATINGS: Mutex<HashMap<String, f64>> = Mutex::new(HashMap::new());
}

mod api;
#[cfg(test)]
mod mockdb;
pub mod sqlite;
#[cfg(test)]
mod tests;
mod util;

use self::sqlite::create_connection_pool;

type Result<T> = result::Result<Json<T>, AppError>;

fn calculate_all_ratings<D: Db>(db: &D) -> Result<()> {
    let entries = db.all_entries()?;
    let ratings = db.all_ratings()?;
    let mut avg_ratings = match ENTRY_RATINGS.lock() {
        Ok(guard) => guard,
        Err(poisoned) => poisoned.into_inner(),
    };
    for e in entries {
        avg_ratings.insert(e.id.clone(), e.avg_rating(&ratings));
    }
    Ok(Json(()))
}

fn calculate_rating_for_entry<D: Db>(db: &D, e_id: &str) -> Result<()> {
    let ratings = db.all_ratings()?;
    let e = db.get_entry(e_id)?;
    let mut avg_ratings = match ENTRY_RATINGS.lock() {
        Ok(guard) => guard,
        Err(poisoned) => poisoned.into_inner(),
    };
    avg_ratings.insert(e.id.clone(), e.avg_rating(&ratings));
    Ok(Json(()))
}

fn rocket_instance<T: r2d2::ManageConnection>(cfg: Config, pool: Pool<T>) -> Rocket
where
    <T as r2d2::ManageConnection>::Connection: Db,
{
    info!("Calculating the average rating of all entries...");
    calculate_all_ratings(&*pool.get().unwrap()).unwrap();
    rocket::custom(cfg, true)
        .manage(pool)
        .mount("/", api::routes())
}

pub fn run(db_url: &str, port: u16, enable_cors: bool) {
    if enable_cors {
        panic!(
            "enable-cors is currently not available until\
             \nhttps://github.com/SergioBenitez/Rocket/pull/141\nis merged :("
        );
    }

    let cfg = Config::build(Environment::Production)
        .address("127.0.0.1")
        .port(port)
        .finalize()
        .unwrap();

    let pool = create_connection_pool(db_url).unwrap();

    rocket_instance(cfg, pool).launch();
}
<commit_msg>new(info-message): notify user when calculating average ratings is finished<commit_after>use core::{prelude::*, util::sort::Rated};
use diesel::r2d2::{self, Pool};
use infrastructure::error::AppError;
use rocket::{self,
             config::{Config, Environment},
             Rocket};
use rocket_contrib::Json;
use std::{collections::HashMap, result, sync::Mutex};

#[cfg(feature = "email")]
use infrastructure::mail;

lazy_static! {
    static ref ENTRY_RATINGS: Mutex<HashMap<String, f64>> = Mutex::new(HashMap::new());
}

mod api;
#[cfg(test)]
mod mockdb;
pub mod sqlite;
#[cfg(test)]
mod tests;
mod util;

use self::sqlite::create_connection_pool;

type Result<T> = result::Result<Json<T>, AppError>;

fn calculate_all_ratings<D: Db>(db: &D) -> Result<()> {
    let entries = db.all_entries()?;
    let ratings = db.all_ratings()?;
    let mut avg_ratings = match ENTRY_RATINGS.lock() {
        Ok(guard) => guard,
        Err(poisoned) => poisoned.into_inner(),
    };
    for e in entries {
        avg_ratings.insert(e.id.clone(), e.avg_rating(&ratings));
    }
    Ok(Json(()))
}

fn calculate_rating_for_entry<D: Db>(db: &D, e_id: &str) -> Result<()> {
    let ratings = db.all_ratings()?;
    let e = db.get_entry(e_id)?;
    let mut avg_ratings = match ENTRY_RATINGS.lock() {
        Ok(guard) => guard,
        Err(poisoned) => poisoned.into_inner(),
    };
    avg_ratings.insert(e.id.clone(), e.avg_rating(&ratings));
    Ok(Json(()))
}

fn rocket_instance<T: r2d2::ManageConnection>(cfg: Config, pool: Pool<T>) -> Rocket
where
    <T as r2d2::ManageConnection>::Connection: Db,
{
    info!("Calculating the average rating of all entries...");
    calculate_all_ratings(&*pool.get().unwrap()).unwrap();
    info!("done.");
    rocket::custom(cfg, true)
        .manage(pool)
        .mount("/", api::routes())
}

pub fn run(db_url: &str, port: u16, enable_cors: bool) {
    if enable_cors {
        panic!(
            "enable-cors is currently not available until\
             \nhttps://github.com/SergioBenitez/Rocket/pull/141\nis merged :("
        );
    }

    let cfg = Config::build(Environment::Production)
        .address("127.0.0.1")
        .port(port)
        .finalize()
        .unwrap();

    let pool = create_connection_pool(db_url).unwrap();

    rocket_instance(cfg, pool).launch();
}
<|endoftext|>


<commit_before>use crate::io::ErrorKind;
use std::io::{self, BufWriter, Write};
use std::process::exit;

use crate::{constants::*, refiner};
use regex::Regex;

const HUNK_HEADER: &str = "\x1b[36m"; // Cyan

lazy_static! {
    static ref STATIC_HEADER_PREFIXES: Vec<(&'static str, &'static str)> = vec![
        ("diff ", BOLD),
        ("index ", BOLD),
        ("--- ", BOLD),
        ("+++ ", BOLD),
        ("@@ ", HUNK_HEADER),
    ];
    static ref ANSI_COLOR_REGEX: Regex = Regex::new("\x1b[^m]*m").unwrap();
}

#[must_use]
fn get_fixed_highlight(line: &str) -> &str {
    for static_header_prefix in STATIC_HEADER_PREFIXES.iter() {
        let prefix = static_header_prefix.0;
        if line.starts_with(prefix) {
            return static_header_prefix.1;
        }
    }

    return "";
}

fn print(stream: &mut BufWriter<&mut dyn Write>, text: &str) {
    if let Err(error) = stream.write_all(text.as_bytes()) {
        if error.kind() == ErrorKind::BrokenPipe {
            // This is fine, somebody probably just quit their pager before it
            // was done reading our output.
            exit(0);
        }

        panic!("Error writing diff to pager: {:?}", error);
    }
}

fn println(stream: &mut BufWriter<&mut dyn Write>, text: &str) {
    print(stream, text);
    print(stream, "\n");
}

pub struct LineCollector<'a> {
    old_text: String,
    new_text: String,
    plain_text: String,
    output: BufWriter<&'a mut dyn Write>,
}

impl<'a> LineCollector<'a> {
    pub fn new(output: &mut dyn io::Write) -> LineCollector {
        let output = BufWriter::new(output);
        return LineCollector {
            old_text: String::from(""),
            new_text: String::from(""),
            plain_text: String::from(""),
            output,
        };
    }

    fn drop(&mut self) {
        // Flush any outstanding lines. This can be done in any order, at most
        // one of them is going to do anything anyway.
        self.drain_oldnew();
        self.drain_plain();
    }

    fn drain_oldnew(&mut self) {
        if self.old_text.is_empty() && self.new_text.is_empty() {
            return;
        }

        for line in refiner::format(&self.old_text, &self.new_text) {
            println(&mut self.output, &line);
        }
        self.old_text.clear();
        self.new_text.clear();
    }

    fn drain_plain(&mut self) {
        if self.plain_text.is_empty() {
            return;
        }

        print(&mut self.output, &self.plain_text);
        self.plain_text.clear();
    }

    fn consume_plain_line(&mut self, line: &str) {
        self.drain_oldnew();
        self.plain_text.push_str(line);
        self.plain_text.push('\n');
    }

    fn consume_old_line(&mut self, line: &str) {
        self.drain_plain();
        self.old_text.push_str(&line[1..])
    }

    fn consume_new_line(&mut self, line: &str) {
        self.drain_plain();
        self.new_text.push_str(&line[1..])
    }

    fn consume_no_eof_newline_marker(&mut self) {
        if !self.new_text.is_empty() {
            // New section comes after old, so if we get in here it's a new
            // section that doesn't end in a newline. Remove its trailing
            // newline.
            assert!(self.new_text.pop().unwrap() == '\n');
            return;
        }

        if !self.old_text.is_empty() {
            // Old text doesn't end in a newline, remove its trailing newline
            assert!(self.old_text.pop().unwrap() == '\n');
            return;
        }

        // It's a piece of unchanged text that doesn't end in a newline, just
        // consume the colorized marker as plain text
        self.consume_plain_line(&format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, &NO_EOF_NEWLINE_MARKER, NORMAL
        ))
    }

    pub fn consume_line(&mut self, line: String) {
        // Strip out incoming ANSI formatting. This enables us to highlight
        // already-colored input.
        let line = ANSI_COLOR_REGEX.replace_all(&line, "");

        let fixed_highlight = get_fixed_highlight(&line);
        if !fixed_highlight.is_empty() {
            self.consume_plain_line(&format!("{}{}{}", fixed_highlight, line, NORMAL));
            return;
        }

        if line.is_empty() {
            self.consume_plain_line("");
            return;
        }

        if line.starts_with('-') {
            self.consume_old_line(&line);
            return;
        }

        if line.starts_with('+') {
            self.consume_new_line(&line);
            return;
        }

        if line == NO_EOF_NEWLINE_MARKER {
            self.consume_no_eof_newline_marker();
            return;
        }

        self.consume_plain_line(&line);
    }
}
<commit_msg>Move the destructor to the right place<commit_after>use crate::io::ErrorKind;
use std::io::{self, BufWriter, Write};
use std::process::exit;

use crate::{constants::*, refiner};
use regex::Regex;

const HUNK_HEADER: &str = "\x1b[36m"; // Cyan

lazy_static! {
    static ref STATIC_HEADER_PREFIXES: Vec<(&'static str, &'static str)> = vec![
        ("diff ", BOLD),
        ("index ", BOLD),
        ("--- ", BOLD),
        ("+++ ", BOLD),
        ("@@ ", HUNK_HEADER),
    ];
    static ref ANSI_COLOR_REGEX: Regex = Regex::new("\x1b[^m]*m").unwrap();
}

#[must_use]
fn get_fixed_highlight(line: &str) -> &str {
    for static_header_prefix in STATIC_HEADER_PREFIXES.iter() {
        let prefix = static_header_prefix.0;
        if line.starts_with(prefix) {
            return static_header_prefix.1;
        }
    }

    return "";
}

fn print(stream: &mut BufWriter<&mut dyn Write>, text: &str) {
    if let Err(error) = stream.write_all(text.as_bytes()) {
        if error.kind() == ErrorKind::BrokenPipe {
            // This is fine, somebody probably just quit their pager before it
            // was done reading our output.
            exit(0);
        }

        panic!("Error writing diff to pager: {:?}", error);
    }
}

fn println(stream: &mut BufWriter<&mut dyn Write>, text: &str) {
    print(stream, text);
    print(stream, "\n");
}

pub struct LineCollector<'a> {
    old_text: String,
    new_text: String,
    plain_text: String,
    output: BufWriter<&'a mut dyn Write>,
}

impl<'a> Drop for LineCollector<'a> {
    fn drop(&mut self) {
        // Flush any outstanding lines. This can be done in any order, at most
        // one of them is going to do anything anyway.
        self.drain_oldnew();
        self.drain_plain();
    }
}

impl<'a> LineCollector<'a> {
    pub fn new(output: &mut dyn io::Write) -> LineCollector {
        let output = BufWriter::new(output);
        return LineCollector {
            old_text: String::from(""),
            new_text: String::from(""),
            plain_text: String::from(""),
            output,
        };
    }

    fn drain_oldnew(&mut self) {
        if self.old_text.is_empty() && self.new_text.is_empty() {
            return;
        }

        for line in refiner::format(&self.old_text, &self.new_text) {
            println(&mut self.output, &line);
        }
        self.old_text.clear();
        self.new_text.clear();
    }

    fn drain_plain(&mut self) {
        if self.plain_text.is_empty() {
            return;
        }

        print(&mut self.output, &self.plain_text);
        self.plain_text.clear();
    }

    fn consume_plain_line(&mut self, line: &str) {
        self.drain_oldnew();
        self.plain_text.push_str(line);
        self.plain_text.push('\n');
    }

    fn consume_old_line(&mut self, line: &str) {
        self.drain_plain();
        self.old_text.push_str(&line[1..])
    }

    fn consume_new_line(&mut self, line: &str) {
        self.drain_plain();
        self.new_text.push_str(&line[1..])
    }

    fn consume_no_eof_newline_marker(&mut self) {
        if !self.new_text.is_empty() {
            // New section comes after old, so if we get in here it's a new
            // section that doesn't end in a newline. Remove its trailing
            // newline.
            assert!(self.new_text.pop().unwrap() == '\n');
            return;
        }

        if !self.old_text.is_empty() {
            // Old text doesn't end in a newline, remove its trailing newline
            assert!(self.old_text.pop().unwrap() == '\n');
            return;
        }

        // It's a piece of unchanged text that doesn't end in a newline, just
        // consume the colorized marker as plain text
        self.consume_plain_line(&format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, &NO_EOF_NEWLINE_MARKER, NORMAL
        ))
    }

    pub fn consume_line(&mut self, line: String) {
        // Strip out incoming ANSI formatting. This enables us to highlight
        // already-colored input.
        let line = ANSI_COLOR_REGEX.replace_all(&line, "");

        let fixed_highlight = get_fixed_highlight(&line);
        if !fixed_highlight.is_empty() {
            self.consume_plain_line(&format!("{}{}{}", fixed_highlight, line, NORMAL));
            return;
        }

        if line.is_empty() {
            self.consume_plain_line("");
            return;
        }

        if line.starts_with('-') {
            self.consume_old_line(&line);
            return;
        }

        if line.starts_with('+') {
            self.consume_new_line(&line);
            return;
        }

        if line == NO_EOF_NEWLINE_MARKER {
            self.consume_no_eof_newline_marker();
            return;
        }

        self.consume_plain_line(&line);
    }
}
<|endoftext|>


<commit_before>use std::process::{Command, Stdio};
use std::env;

fn main() {
    Command::new("make")
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .status()
        .unwrap();
    let out_dir = env::var("OUT_DIR").unwrap();
    println!("cargo:rustc-flags=-L {} -l static=parser", out_dir);
}
<commit_msg>Stop build if make failed<commit_after>use std::process::{Command, Stdio};
use std::env;

fn main() {
    let ret = Command::new("make")
        .stdin(Stdio::inherit())
        .stdout(Stdio::inherit())
        .stderr(Stdio::inherit())
        .status()
        .unwrap();
    assert!(ret.success());
    let out_dir = env::var("OUT_DIR").unwrap();
    println!("cargo:rustc-flags=-L {} -l static=parser", out_dir);
}
<|endoftext|>


<commit_before>use std::fs;
use std::io::{self, Write};
use std::process::exit;

use clap::Shell;

include!("src/app.rs");

fn main() {
    match version_check::is_min_version("1.36") {
        Some(true) => {}
        // rustc version too small or can't figure it out
        _ => {
            writeln!(&mut io::stderr(), "'fd' requires rustc >= 1.36").unwrap();
            exit(1);
        }
    }

    let var = std::env::var_os("SHELL_COMPLETIONS_DIR").or(std::env::var_os("OUT_DIR"));
    let outdir = match var {
        None => return,
        Some(outdir) => outdir,
    };
    fs::create_dir_all(&outdir).unwrap();

    let mut app = build_app();
    app.gen_completions("fd", Shell::Bash, &outdir);
    app.gen_completions("fd", Shell::Fish, &outdir);
    app.gen_completions("fd", Shell::Zsh, &outdir);
    app.gen_completions("fd", Shell::PowerShell, &outdir);
}
<commit_msg>Clean up build.rs<commit_after>use std::fs;

use clap::Shell;

include!("src/app.rs");

fn main() {
    let min_version = "1.36";

    match version_check::is_min_version(min_version) {
        Some(true) => {}
        // rustc version too small or can't figure it out
        _ => {
            eprintln!("'fd' requires rustc >= {}", min_version);
            std::process::exit(1);
        }
    }

    let var = std::env::var_os("SHELL_COMPLETIONS_DIR").or(std::env::var_os("OUT_DIR"));
    let outdir = match var {
        None => return,
        Some(outdir) => outdir,
    };
    fs::create_dir_all(&outdir).unwrap();

    let mut app = build_app();
    app.gen_completions("fd", Shell::Bash, &outdir);
    app.gen_completions("fd", Shell::Fish, &outdir);
    app.gen_completions("fd", Shell::Zsh, &outdir);
    app.gen_completions("fd", Shell::PowerShell, &outdir);
}
<|endoftext|>


<commit_before>// Copyright 2016 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Finds the required `libclang` libraries and links to them.
//!
//! # Environment Variables
//!
//! This build script can make use of several environment variables to help it find the required
//! static or dynamic libraries.
//!
//! * `LLVM_CONFIG_PATH` - provides a path to an `llvm-config` executable
//! * `LIBCLANG_PATH` - provides a path to a directory containing a `libclang` shared library
//! * `LIBCLANG_STATIC_PATH` - provides a path to a directory containing LLVM and Clang static libraries

#![allow(unused_attributes)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", warn(clippy))]

extern crate glob;

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

use glob::{MatchOptions};

/// Returns the components of the version appended to the supplied file.
fn parse_version(file: &Path) -> Vec<u32> {
    let string = file.to_str().unwrap_or("");
    let components = string.split('.').skip(2);
    components.map(|s| s.parse::<u32>().unwrap_or(0)).collect()
}

/// Returns a path to one of the supplied files if such a file can be found in the supplied directory.
fn contains(directory: &Path, files: &[String]) -> Option<PathBuf> {
    // Join the directory to the files to obtain our glob patterns.
    let patterns = files.iter().filter_map(|f| directory.join(f).to_str().map(ToOwned::to_owned));

    // Prevent wildcards from matching path separators.
    let mut options = MatchOptions::new();
    options.require_literal_separator = true;

    // Collect any files that match the glob patterns.
    let mut matches = patterns.flat_map(|p| {
        if let Ok(paths) = glob::glob_with(&p, &options) {
            paths.filter_map(Result::ok).collect()
        } else {
            vec![]
        }
    }).collect::<Vec<_>>();

    // Sort the matches by their version, preferring shorter and higher versions.
    matches.sort_by_key(|m| parse_version(m));
    matches.pop()
}

/// Runs a console command, returning the output if the command was successfully executed.
fn run(command: &str, arguments: &[&str]) -> Option<String> {
    Command::new(command).args(arguments).output().map(|o| {
        String::from_utf8_lossy(&o.stdout).into_owned()
    }).ok()
}

/// Runs `llvm-config`, returning the output if the command was successfully executed.
fn run_llvm_config(arguments: &[&str]) -> Result<String, String> {
    match run(&env::var("LLVM_CONFIG_PATH").unwrap_or_else(|_| "llvm-config".into()), arguments) {
        Some(output) => Ok(output),
        None => {
            let message = format!(
                "couldn't execute `llvm-config {}`, set the LLVM_CONFIG_PATH environment variable \
                to a path to a valid `llvm-config` executable",
                arguments.join(" "),
            );
            Err(message)
        },
    }
}

/// Backup search directory globs for FreeBSD and Linux.
const SEARCH_LINUX: &'static [&'static str] = &[
    "/usr/lib*",
    "/usr/lib*/*",
    "/usr/lib*/*/*",
    "/usr/local/lib*",
    "/usr/local/lib*/*",
    "/usr/local/lib*/*/*",
    "/usr/local/llvm*/lib",
];

/// Backup search directory globs for OS X.
const SEARCH_OSX: &'static [&'static str] = &[
    "/usr/local/opt/llvm*/lib",
    "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib",
    "/Library/Developer/CommandLineTools/usr/lib",
    "/usr/local/opt/llvm*/lib/llvm*/lib",
];

/// Backup search directory globs for Windows.
const SEARCH_WINDOWS: &'static [&'static str] = &[
    "C:\\LLVM\\lib",
    "C:\\Program Files*\\LLVM\\lib",
    "C:\\MSYS*\\MinGW*\\lib",
];

/// Indicates the type of library being searched for.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Library {
    Dynamic,
    Static,
}

impl Library {
    /// Checks whether the supplied file is a valid library for the architecture.
    fn check(&self, file: &PathBuf) -> Result<(), String> {
        if cfg!(any(target_os="freebsd", target_os="linux")) {
            if *self == Library::Static {
                return Ok(());
            }
            let mut file = try!(File::open(file).map_err(|e| e.to_string()));
            let mut elf = [0; 5];
            try!(file.read_exact(&mut elf).map_err(|e| e.to_string()));
            if elf[..4] != [127, 69, 76, 70] {
                return Err("invalid ELF header".into());
            }
            if cfg!(target_pointer_width="32") && elf[4] != 1 {
                return Err("invalid ELF class (64-bit)".into());
            }
            if cfg!(target_pointer_width="64") && elf[4] != 2 {
                return Err("invalid ELF class (32-bit)".into());
            }
            Ok(())
        } else {
            Ok(())
        }
    }
}

/// Searches for a library, returning the directory it can be found in if the search was successful.
fn find(library: Library, files: &[String], env: &str) -> Result<PathBuf, String> {
    let mut skipped = vec![];

    /// Attempts to return the supplied file.
    macro_rules! try_file {
        ($file:expr) => ({
            match library.check(&$file) {
                Ok(_) => return Ok($file),
                Err(message) => skipped.push(format!("({}: {})", $file.display(), message)),
            }
        });
    }

    /// Searches the supplied directory and, on Windows, any relevant sibling directories.
    macro_rules! search_directory {
        ($directory:ident) => {
            if let Some(file) = contains(&$directory, files) {
                try_file!(file);
            }

            // On Windows, `libclang.dll` is usually found in the LLVM `bin` directory while
            // `libclang.lib` is usually found in the LLVM `lib` directory. To keep things
            // consistent with other platforms, only LLVM `lib` directories are included in the
            // backup search directory globs so we need to search the LLVM `bin` directory here.
            if cfg!(target_os="windows") && $directory.ends_with("lib") {
                let sibling = $directory.parent().unwrap().join("bin");
                if let Some(file) = contains(&sibling, files) {
                    try_file!(file);
                }
            }
        }
    }

    // Search the directory provided by the relevant environment variable if it is set.
    if let Ok(directory) = env::var(env).map(|d| Path::new(&d).to_path_buf()) {
        search_directory!(directory);
    }

    // Search the `bin` and `lib` subdirectories in the directory returned by
    // `llvm-config --prefix` if `llvm-config` is available.
    if let Ok(output) = run_llvm_config(&["--prefix"]) {
        let directory = Path::new(output.lines().next().unwrap()).to_path_buf();
        let bin = directory.join("bin");
        if let Some(file) = contains(&bin, files) {
            try_file!(file);
        }
        let lib = directory.join("lib");
        if let Some(file) = contains(&lib, files) {
            try_file!(file);
        }
    }

    // Search the backup directories.
    let search = if cfg!(any(target_os="freebsd", target_os="linux")) {
        SEARCH_LINUX
    } else if cfg!(target_os="macos") {
        SEARCH_OSX
    } else if cfg!(target_os="windows") {
        SEARCH_WINDOWS
    } else {
        &[]
    };
    for pattern in search {
        let mut options = MatchOptions::new();
        options.case_sensitive = false;
        options.require_literal_separator = true;
        if let Ok(paths) = glob::glob_with(pattern, &options) {
            for path in paths.filter_map(Result::ok).filter(|p| p.is_dir()) {
                search_directory!(path);
            }
        }
    }

    let message = format!(
        "couldn't find any of [{}], set the {} environment variable to a path where one of these \
         files can be found (skipped: [{}])",
        files.iter().map(|f| format!("'{}'", f)).collect::<Vec<_>>().join(", "),
        env,
        skipped.join(", "),
    );
    Err(message)
}

/// Searches for a `libclang` shared library, returning the path to such a shared library if the
/// search was successful.
pub fn find_shared_library() -> Result<PathBuf, String> {
    let mut files = vec![format!("{}clang{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX)];
    if cfg!(any(target_os="freebsd", target_os="linux", target_os="openbsd")) {
        // Some BSDs and Linux distributions don't create a `libclang.so` symlink, so we need to
        // look for any versioned files (e.g., `libclang.so.3.9`).
        files.push("libclang.so.*".into());
    }
    if cfg!(target_os="windows") {
        // The official LLVM build uses `libclang.dll` on Windows instead of `clang.dll`. However,
        // unofficial builds such as MinGW use `clang.dll`.
        files.push("libclang.dll".into());
    }
    find(Library::Dynamic, &files, "LIBCLANG_PATH")
}

/// Returns the name of an LLVM or Clang library from a path to such a library.
fn get_library_name(path: &Path) -> Option<String> {
    path.file_stem().map(|l| l.to_string_lossy()[3..].into())
}

/// Returns the LLVM libraries required to link to `libclang` statically.
fn get_llvm_libraries() -> Vec<String> {
    run_llvm_config(&["--libs"]).unwrap().split_whitespace().filter_map(|p| {
        // Depending on the version of `llvm-config` in use, listed libraries may be in one of two
        // forms, a full path to the library or simply prefixed with `-l`.
        if p.starts_with("-l") {
            Some(p[2..].into())
        } else {
            get_library_name(Path::new(p))
        }
    }).collect()
}

/// Clang libraries required to link to `libclang` 3.5 and later statically.
const CLANG_LIBRARIES: &'static [&'static str] = &[
    "clang",
    "clangAST",
    "clangAnalysis",
    "clangBasic",
    "clangDriver",
    "clangEdit",
    "clangFrontend",
    "clangIndex",
    "clangLex",
    "clangParse",
    "clangRewrite",
    "clangSema",
    "clangSerialization",
];

/// Returns the Clang libraries required to link to `libclang` statically.
fn get_clang_libraries<P: AsRef<Path>>(directory: P) -> Vec<String> {
    let pattern = directory.as_ref().join("libclang*.a").to_string_lossy().to_string();
    if let Ok(libraries) = glob::glob(&pattern) {
        libraries.filter_map(|l| l.ok().and_then(|l| get_library_name(&l))).collect()
    } else {
        CLANG_LIBRARIES.iter().map(|l| l.to_string()).collect()
    }
}

/// Find and link to `libclang` statically.
#[cfg_attr(feature="runtime", allow(dead_code))]
fn link_static() {
    let file = find(Library::Static, &["libclang.a".into()], "LIBCLANG_STATIC_PATH").unwrap();
    let directory = file.parent().unwrap();
    print!("cargo:rustc-flags=");

    // Specify required Clang static libraries.
    print!("-L {} ", directory.display());
    for library in get_clang_libraries(directory) {
        print!("-l static={} ", library);
    }

    // Specify required LLVM static libraries.
    print!("-L {} ", run_llvm_config(&["--libdir"]).unwrap().trim_right());
    for library in get_llvm_libraries() {
        print!("-l static={} ", library);
    }

    // Specify required system libraries.
    if cfg!(target_os="freebsd") {
        println!("-l ffi -l ncursesw -l c++ -l z");
    } else if cfg!(target_os="linux") {
        println!("-l ffi -l ncursesw -l stdc++ -l z");
    } else if cfg!(target_os="macos") {
        println!("-l ffi -l ncurses -l c++ -l z");
    } else {
        panic!("unsupported operating system for static linking");
    }
}

/// Find and link to `libclang` dynamically.
#[cfg_attr(feature="runtime", allow(dead_code))]
fn link_dynamic() {
    let file = find_shared_library().unwrap();
    let directory = file.parent().unwrap();
    println!("cargo:rustc-link-search={}", directory.display());

    if cfg!(all(target_os="windows", target_env="msvc")) {
        // Find the `libclang` stub static library required for the MSVC toolchain.
        let libdir = if !directory.ends_with("bin") {
            directory.to_owned()
        } else {
            directory.parent().unwrap().join("lib")
        };
        if libdir.join("libclang.lib").exists() {
            println!("cargo:rustc-link-search={}", libdir.display());
        } else if libdir.join("libclang.dll.a").exists() {
            // MSYS and MinGW use `libclang.dll.a` instead of `libclang.lib`. It is linkable with
            // the MSVC linker, but Rust doesn't recognize the `.a` suffix, so we need to copy it
            // with a different name.
            //
            // FIXME: Maybe we can just hardlink or symlink it?
            let out = env::var("OUT_DIR").unwrap();
            fs::copy(libdir.join("libclang.dll.a"), Path::new(&out).join("libclang.lib")).unwrap();
            println!("cargo:rustc-link-search=native={}", out);
        } else {
            panic!(
                "using '{}', so 'libclang.lib' or 'libclang.dll.a' must be available in {}",
                file.display(),
                libdir.display(),
            );
        }
        println!("cargo:rustc-link-lib=dylib=libclang");
    } else {
        println!("cargo:rustc-link-lib=dylib=clang");
    }
}

#[cfg_attr(feature="runtime", allow(dead_code))]
fn main() {
    if cfg!(feature="runtime") {
        if cfg!(feature="static") {
            panic!("`runtime` and `static` features can't be combined");
        }
    } else if cfg!(feature="static") {
        link_static();
    } else {
        link_dynamic();
    }

    if let Ok(output) = run_llvm_config(&["--includedir"]) {
        let directory = Path::new(output.trim_right());
        println!("cargo:include={}", directory.display());
    }
}
<commit_msg>Link LLVM according to its preferred --shared-mode (#62)<commit_after>// Copyright 2016 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Finds the required `libclang` libraries and links to them.
//!
//! # Environment Variables
//!
//! This build script can make use of several environment variables to help it find the required
//! static or dynamic libraries.
//!
//! * `LLVM_CONFIG_PATH` - provides a path to an `llvm-config` executable
//! * `LIBCLANG_PATH` - provides a path to a directory containing a `libclang` shared library
//! * `LIBCLANG_STATIC_PATH` - provides a path to a directory containing LLVM and Clang static libraries

#![allow(unused_attributes)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", warn(clippy))]

extern crate glob;

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

use glob::{MatchOptions};

/// Returns the components of the version appended to the supplied file.
fn parse_version(file: &Path) -> Vec<u32> {
    let string = file.to_str().unwrap_or("");
    let components = string.split('.').skip(2);
    components.map(|s| s.parse::<u32>().unwrap_or(0)).collect()
}

/// Returns a path to one of the supplied files if such a file can be found in the supplied directory.
fn contains(directory: &Path, files: &[String]) -> Option<PathBuf> {
    // Join the directory to the files to obtain our glob patterns.
    let patterns = files.iter().filter_map(|f| directory.join(f).to_str().map(ToOwned::to_owned));

    // Prevent wildcards from matching path separators.
    let mut options = MatchOptions::new();
    options.require_literal_separator = true;

    // Collect any files that match the glob patterns.
    let mut matches = patterns.flat_map(|p| {
        if let Ok(paths) = glob::glob_with(&p, &options) {
            paths.filter_map(Result::ok).collect()
        } else {
            vec![]
        }
    }).collect::<Vec<_>>();

    // Sort the matches by their version, preferring shorter and higher versions.
    matches.sort_by_key(|m| parse_version(m));
    matches.pop()
}

/// Runs a console command, returning the output if the command was successfully executed.
fn run(command: &str, arguments: &[&str]) -> Option<String> {
    Command::new(command).args(arguments).output().map(|o| {
        String::from_utf8_lossy(&o.stdout).into_owned()
    }).ok()
}

/// Runs `llvm-config`, returning the output if the command was successfully executed.
fn run_llvm_config(arguments: &[&str]) -> Result<String, String> {
    match run(&env::var("LLVM_CONFIG_PATH").unwrap_or_else(|_| "llvm-config".into()), arguments) {
        Some(output) => Ok(output),
        None => {
            let message = format!(
                "couldn't execute `llvm-config {}`, set the LLVM_CONFIG_PATH environment variable \
                to a path to a valid `llvm-config` executable",
                arguments.join(" "),
            );
            Err(message)
        },
    }
}

/// Backup search directory globs for FreeBSD and Linux.
const SEARCH_LINUX: &'static [&'static str] = &[
    "/usr/lib*",
    "/usr/lib*/*",
    "/usr/lib*/*/*",
    "/usr/local/lib*",
    "/usr/local/lib*/*",
    "/usr/local/lib*/*/*",
    "/usr/local/llvm*/lib",
];

/// Backup search directory globs for OS X.
const SEARCH_OSX: &'static [&'static str] = &[
    "/usr/local/opt/llvm*/lib",
    "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib",
    "/Library/Developer/CommandLineTools/usr/lib",
    "/usr/local/opt/llvm*/lib/llvm*/lib",
];

/// Backup search directory globs for Windows.
const SEARCH_WINDOWS: &'static [&'static str] = &[
    "C:\\LLVM\\lib",
    "C:\\Program Files*\\LLVM\\lib",
    "C:\\MSYS*\\MinGW*\\lib",
];

/// Indicates the type of library being searched for.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Library {
    Dynamic,
    Static,
}

impl Library {
    /// Checks whether the supplied file is a valid library for the architecture.
    fn check(&self, file: &PathBuf) -> Result<(), String> {
        if cfg!(any(target_os="freebsd", target_os="linux")) {
            if *self == Library::Static {
                return Ok(());
            }
            let mut file = try!(File::open(file).map_err(|e| e.to_string()));
            let mut elf = [0; 5];
            try!(file.read_exact(&mut elf).map_err(|e| e.to_string()));
            if elf[..4] != [127, 69, 76, 70] {
                return Err("invalid ELF header".into());
            }
            if cfg!(target_pointer_width="32") && elf[4] != 1 {
                return Err("invalid ELF class (64-bit)".into());
            }
            if cfg!(target_pointer_width="64") && elf[4] != 2 {
                return Err("invalid ELF class (32-bit)".into());
            }
            Ok(())
        } else {
            Ok(())
        }
    }
}

/// Searches for a library, returning the directory it can be found in if the search was successful.
fn find(library: Library, files: &[String], env: &str) -> Result<PathBuf, String> {
    let mut skipped = vec![];

    /// Attempts to return the supplied file.
    macro_rules! try_file {
        ($file:expr) => ({
            match library.check(&$file) {
                Ok(_) => return Ok($file),
                Err(message) => skipped.push(format!("({}: {})", $file.display(), message)),
            }
        });
    }

    /// Searches the supplied directory and, on Windows, any relevant sibling directories.
    macro_rules! search_directory {
        ($directory:ident) => {
            if let Some(file) = contains(&$directory, files) {
                try_file!(file);
            }

            // On Windows, `libclang.dll` is usually found in the LLVM `bin` directory while
            // `libclang.lib` is usually found in the LLVM `lib` directory. To keep things
            // consistent with other platforms, only LLVM `lib` directories are included in the
            // backup search directory globs so we need to search the LLVM `bin` directory here.
            if cfg!(target_os="windows") && $directory.ends_with("lib") {
                let sibling = $directory.parent().unwrap().join("bin");
                if let Some(file) = contains(&sibling, files) {
                    try_file!(file);
                }
            }
        }
    }

    // Search the directory provided by the relevant environment variable if it is set.
    if let Ok(directory) = env::var(env).map(|d| Path::new(&d).to_path_buf()) {
        search_directory!(directory);
    }

    // Search the `bin` and `lib` subdirectories in the directory returned by
    // `llvm-config --prefix` if `llvm-config` is available.
    if let Ok(output) = run_llvm_config(&["--prefix"]) {
        let directory = Path::new(output.lines().next().unwrap()).to_path_buf();
        let bin = directory.join("bin");
        if let Some(file) = contains(&bin, files) {
            try_file!(file);
        }
        let lib = directory.join("lib");
        if let Some(file) = contains(&lib, files) {
            try_file!(file);
        }
    }

    // Search the backup directories.
    let search = if cfg!(any(target_os="freebsd", target_os="linux")) {
        SEARCH_LINUX
    } else if cfg!(target_os="macos") {
        SEARCH_OSX
    } else if cfg!(target_os="windows") {
        SEARCH_WINDOWS
    } else {
        &[]
    };
    for pattern in search {
        let mut options = MatchOptions::new();
        options.case_sensitive = false;
        options.require_literal_separator = true;
        if let Ok(paths) = glob::glob_with(pattern, &options) {
            for path in paths.filter_map(Result::ok).filter(|p| p.is_dir()) {
                search_directory!(path);
            }
        }
    }

    let message = format!(
        "couldn't find any of [{}], set the {} environment variable to a path where one of these \
         files can be found (skipped: [{}])",
        files.iter().map(|f| format!("'{}'", f)).collect::<Vec<_>>().join(", "),
        env,
        skipped.join(", "),
    );
    Err(message)
}

/// Searches for a `libclang` shared library, returning the path to such a shared library if the
/// search was successful.
pub fn find_shared_library() -> Result<PathBuf, String> {
    let mut files = vec![format!("{}clang{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX)];
    if cfg!(any(target_os="freebsd", target_os="linux", target_os="openbsd")) {
        // Some BSDs and Linux distributions don't create a `libclang.so` symlink, so we need to
        // look for any versioned files (e.g., `libclang.so.3.9`).
        files.push("libclang.so.*".into());
    }
    if cfg!(target_os="windows") {
        // The official LLVM build uses `libclang.dll` on Windows instead of `clang.dll`. However,
        // unofficial builds such as MinGW use `clang.dll`.
        files.push("libclang.dll".into());
    }
    find(Library::Dynamic, &files, "LIBCLANG_PATH")
}

/// Returns the name of an LLVM or Clang library from a path to such a library.
fn get_library_name(path: &Path) -> Option<String> {
    path.file_stem().map(|l| l.to_string_lossy()[3..].into())
}

/// Returns the LLVM libraries required to link to `libclang` statically.
fn get_llvm_libraries() -> Vec<String> {
    run_llvm_config(&["--libs"]).unwrap().split_whitespace().filter_map(|p| {
        // Depending on the version of `llvm-config` in use, listed libraries may be in one of two
        // forms, a full path to the library or simply prefixed with `-l`.
        if p.starts_with("-l") {
            Some(p[2..].into())
        } else {
            get_library_name(Path::new(p))
        }
    }).collect()
}

/// Clang libraries required to link to `libclang` 3.5 and later statically.
const CLANG_LIBRARIES: &'static [&'static str] = &[
    "clang",
    "clangAST",
    "clangAnalysis",
    "clangBasic",
    "clangDriver",
    "clangEdit",
    "clangFrontend",
    "clangIndex",
    "clangLex",
    "clangParse",
    "clangRewrite",
    "clangSema",
    "clangSerialization",
];

/// Returns the Clang libraries required to link to `libclang` statically.
fn get_clang_libraries<P: AsRef<Path>>(directory: P) -> Vec<String> {
    let pattern = directory.as_ref().join("libclang*.a").to_string_lossy().to_string();
    if let Ok(libraries) = glob::glob(&pattern) {
        libraries.filter_map(|l| l.ok().and_then(|l| get_library_name(&l))).collect()
    } else {
        CLANG_LIBRARIES.iter().map(|l| l.to_string()).collect()
    }
}

/// Find and link to `libclang` statically.
#[cfg_attr(feature="runtime", allow(dead_code))]
fn link_static() {
    let file = find(Library::Static, &["libclang.a".into()], "LIBCLANG_STATIC_PATH").unwrap();
    let directory = file.parent().unwrap();
    print!("cargo:rustc-flags=");

    // Specify required Clang static libraries.
    print!("-L {} ", directory.display());
    for library in get_clang_libraries(directory) {
        print!("-l static={} ", library);
    }

    // Specify required LLVM static libraries.
    let llvm_supports_static = run_llvm_config(&["--shared-mode"])
        .map(|mode|mode.trim()=="static").unwrap_or(false);

    print!("-L {} ", run_llvm_config(&["--libdir"]).unwrap().trim_right());
    for library in get_llvm_libraries() {
        print!("-l {}{} ", if llvm_supports_static {"static="} else {""}, library);
    }

    // Specify required system libraries.
    if cfg!(target_os="freebsd") {
        println!("-l ffi -l ncursesw -l c++ -l z");
    } else if cfg!(target_os="linux") {
        println!("-l ffi -l ncursesw -l stdc++ -l z");
    } else if cfg!(target_os="macos") {
        println!("-l ffi -l ncurses -l c++ -l z");
    } else {
        panic!("unsupported operating system for static linking");
    }
}

/// Find and link to `libclang` dynamically.
#[cfg_attr(feature="runtime", allow(dead_code))]
fn link_dynamic() {
    let file = find_shared_library().unwrap();
    let directory = file.parent().unwrap();
    println!("cargo:rustc-link-search={}", directory.display());

    if cfg!(all(target_os="windows", target_env="msvc")) {
        // Find the `libclang` stub static library required for the MSVC toolchain.
        let libdir = if !directory.ends_with("bin") {
            directory.to_owned()
        } else {
            directory.parent().unwrap().join("lib")
        };
        if libdir.join("libclang.lib").exists() {
            println!("cargo:rustc-link-search={}", libdir.display());
        } else if libdir.join("libclang.dll.a").exists() {
            // MSYS and MinGW use `libclang.dll.a` instead of `libclang.lib`. It is linkable with
            // the MSVC linker, but Rust doesn't recognize the `.a` suffix, so we need to copy it
            // with a different name.
            //
            // FIXME: Maybe we can just hardlink or symlink it?
            let out = env::var("OUT_DIR").unwrap();
            fs::copy(libdir.join("libclang.dll.a"), Path::new(&out).join("libclang.lib")).unwrap();
            println!("cargo:rustc-link-search=native={}", out);
        } else {
            panic!(
                "using '{}', so 'libclang.lib' or 'libclang.dll.a' must be available in {}",
                file.display(),
                libdir.display(),
            );
        }
        println!("cargo:rustc-link-lib=dylib=libclang");
    } else {
        println!("cargo:rustc-link-lib=dylib=clang");
    }
}

#[cfg_attr(feature="runtime", allow(dead_code))]
fn main() {
    if cfg!(feature="runtime") {
        if cfg!(feature="static") {
            panic!("`runtime` and `static` features can't be combined");
        }
    } else if cfg!(feature="static") {
        link_static();
    } else {
        link_dynamic();
    }

    if let Ok(output) = run_llvm_config(&["--includedir"]) {
        let directory = Path::new(output.trim_right());
        println!("cargo:include={}", directory.display());
    }
}
<|endoftext|>


<commit_before>extern crate bindgen;

use std::env;
use std::path::Path;

fn main() {
    let out_dir = env::var("OUT_DIR").expect("failed to get envvar OUT_DIR");
    let emscripten_dir = env::var("EMSCRIPTEN").expect("failed to get envvar EMSCRIPTEN");

    let whitelist = "^_?em_|^_?emscripten_|^_?EM_|^_?EMSCRIPTEN_";

    let builder = bindgen::builder()
        .header("etc/emscripten.h")
        .generate_comments(true)
        .whitelisted_type(whitelist)
        .whitelisted_function(whitelist)
        .whitelisted_var(whitelist)
        .no_unstable_rust()
        .use_core()
        .clang_arg(format!("-I{}/system/include", emscripten_dir))
        .clang_arg("-x")
        .clang_arg("c++")
        .clang_arg("-std=c++11")
        .clang_arg("-D__EMSCRIPTEN__");

    builder.generate()
        .expect("failed to generate rust bindings")
        .write_to_file(Path::new(&out_dir).join("emscripten.rs"))
        .expect("failed to write to file")
}
<commit_msg>build.rs: Add emscripten's stdlib include path<commit_after>extern crate bindgen;

use std::env;
use std::path::Path;

fn main() {
    let out_dir = env::var("OUT_DIR").expect("failed to get envvar OUT_DIR");
    let emscripten_dir = env::var("EMSCRIPTEN").expect("failed to get envvar EMSCRIPTEN");

    let whitelist = "^_?em_|^_?emscripten_|^_?EM_|^_?EMSCRIPTEN_";

    let builder = bindgen::builder()
        .header("etc/emscripten.h")
        .generate_comments(true)
        .whitelisted_type(whitelist)
        .whitelisted_function(whitelist)
        .whitelisted_var(whitelist)
        .no_unstable_rust()
        .use_core()
        .clang_arg(format!("-I{}/system/include", emscripten_dir))
        .clang_arg(format!("-I{}/system/include/libc", emscripten_dir))
        .clang_arg(format!("-I{}/system/include/libcxx", emscripten_dir))
        .clang_arg("-x")
        .clang_arg("c++")
        .clang_arg("-std=c++11")
        .clang_arg("-D__EMSCRIPTEN__");

    builder
        .generate()
        .expect("failed to generate rust bindings")
        .write_to_file(Path::new(&out_dir).join("emscripten.rs"))
        .expect("failed to write to file")
}
<|endoftext|>


<commit_before>fn main() {
  if let Ok(ref s) = std::env::var("LIBXML2") {
      // println!("{:?}", std::env::vars());
      // panic!("set libxml2.");
      let p = std::path::Path::new(s);
      let fname = std::path::Path::new(p.file_name().expect("no file name in LIBXML2 env"));
      assert!(p.is_file());
      println!("cargo:rustc-link-lib={}", fname.file_stem().unwrap().to_string_lossy());
      println!("cargo:rustc-link-search={}", p.parent().expect("no library path in LIBXML2 env").to_string_lossy());
  } else {
    #[cfg(any(target_family = "unix", target_os = "macos"))]
        {
          if pkg_config_dep::find() {
            return;
          }
        }

    #[cfg(windows)]
        {
          if vcpkg_dep::find() {
            return;
          }
        }

    panic!("Could not find libxml2.")
  }
}

#[cfg(any(target_family="unix", target_os="macos"))]
mod pkg_config_dep {
  pub fn find() -> bool {
    if pkg_config::find_library("libxml-2.0").is_ok() {
      return true;
    }
    false
  }
}

#[cfg(target_family="windows")]
mod vcpkg_dep {
  pub fn find() -> bool {
    if vcpkg::find_package("libxml2").is_ok() {
      return true
    }
    false
  }
}<commit_msg>use the LIBXML2 variable if set directly instead of figuring out packaging<commit_after>fn main() {
  if let Ok(ref s) = std::env::var("LIBXML2") {
      // println!("{:?}", std::env::vars());
      // panic!("set libxml2.");
      let p = std::path::Path::new(s);
      let fname = std::path::Path::new(p.file_name().expect("no file name in LIBXML2 env"));
      assert!(p.is_file());
      println!("cargo:rustc-link-lib={}", fname.file_stem().unwrap().to_string_lossy().strip_prefix("lib").unwrap());
      println!("cargo:rustc-link-search={}", p.parent().expect("no library path in LIBXML2 env").to_string_lossy());
  } else {
    #[cfg(any(target_family = "unix", target_os = "macos"))]
        {
          if pkg_config_dep::find() {
            return;
          }
        }

    #[cfg(windows)]
        {
          if vcpkg_dep::find() {
            return;
          }
        }

    panic!("Could not find libxml2.")
  }
}

#[cfg(any(target_family="unix", target_os="macos"))]
mod pkg_config_dep {
  pub fn find() -> bool {
    if pkg_config::find_library("libxml-2.0").is_ok() {
      return true;
    }
    false
  }
}

#[cfg(target_family="windows")]
mod vcpkg_dep {
  pub fn find() -> bool {
    if vcpkg::find_package("libxml2").is_ok() {
      return true
    }
    false
  }
}<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::io::prelude::*;
use std::io::Write;
use std::path::Path;
use std::collections::HashMap;
use std::cell::RefCell;

enum KeyAlignment {
    Slanted,
    Aligned,
}

struct WordData {
    name: String,
    count: Option<usize>,
    data: RefCell<Vec<String>>,
}

fn parse_data(data: String) -> Vec<String> {
    let mut word_list : Vec<String> = Vec::new();

    for line in data.lines() {
        let mut l = line.split_whitespace();
        let size = line.split_whitespace().count();
        match size  {
            1 | 2=> {
                match l.next() {
                    Some(frqs) => word_list.push(frqs.to_string()),
                    None => continue,
                };
            },
            _ => continue,
        }
    }
    word_list
}

fn is_rare_and_short(word: &String, rank: u32) -> bool {
    let result = if word.len() < 8 {
        rank >=10u32.pow(word.len() as u32)
    } else {
        false
    };
    result
}

fn filter_data(dicts: &mut Vec<WordData>) {
    let mut best_match : HashMap<String, (usize, String)> = HashMap::new();
    // Build best matches. Shows precedence of words in different dictionaries
    for datum in dicts.iter() {
        if datum.count.is_some() {
            let words = datum.data.borrow();
            for (rank, word) in words.iter().enumerate() {
                if best_match.contains_key(word) {
                    if rank < best_match.get(word).unwrap().0 {
                        best_match.insert(word.clone(),
                                          (rank, datum.name.clone()));
                    }
                } else {
                    best_match.insert(word.clone(),
                                      (rank, datum.name.clone()));
                }
            }
        }
    }

    for datum in dicts {
        if datum.count.is_some() {

            let conditional = |w: &String| {
                best_match.get(w).unwrap().1 == datum.name &&
                    !is_rare_and_short(w, best_match.get(w).unwrap().0 as u32)
            };

            let mut words = datum.data.borrow_mut();
            words.retain(conditional);
        }
    }
}

/// Use trailing spaces at the start of lines to represent non character keys
/// such as caps tab and shift.
fn generate_adjacencies(keyboard: String,
                        align: KeyAlignment) -> HashMap<String, String> {
    let mut adj_list : HashMap<String, String> = HashMap::new();
    let rows = keyboard.lines()
        .map(|x| x.split(' ').collect::<Vec<&str>>())
        .collect::<Vec<Vec<&str>>>();

    for (i, row) in rows.iter().enumerate() {
        for (j, key) in row.iter().enumerate() {
            if !key.is_empty() {
                let mut value : String = String::new();
                // Values for row above
                if i>0 {
                    let prev = rows.get(i-1).unwrap();
                    let ap = format!("{} ", prev.get(j).unwrap());
                    value.push_str(ap.as_str());
                    if let Some(pchar) = prev.get(j+1) {
                        let ap = format!("{} ", pchar);
                        value.push_str(ap.as_str());
                    }
                }
                // Values for this row
                if j > 0 {
                    let ap = format!("{} ", row.get(j-1).unwrap());
                    value.push_str(ap.as_str());
                }
                if let Some(next) = row.get(j+1) {
                    let ap = format!("{} ", next);
                    value.push_str(ap.as_str());
                }
                // Values for next row
                if let Some(next) = rows.get(i+1) {
                    if let Some(nchar) = next.get(j) {
                        if !nchar.is_empty()
                        {
                            let ap = format!("{} ", nchar);
                            value.push_str(ap.as_str());

                            if let Some(nchar) = next.get(j+1) {
                                let ap = format!("{} ", nchar);
                                value.push_str(ap.as_str());
                            }
                        }
                    }
                }
                adj_list.insert(key.to_string(), value);
            }
        }
    }
    adj_list
}

// Choose word limits for each file...
fn main() {
    // Data files are either lists or frequency tables. Load all files in data
    // and then identify and parse accordingly and generate code
    println!("Generating source from /data/");
    let limits : HashMap<&str, usize> = {
        let mut map = HashMap::new();
        map.insert("us_tv_and_film", 30000);
        map.insert("english_wikipedia", 30000);
        map.insert("passwords", 30000);
        map.insert("surnames", 10000);
        map
    };

    let mut exported_data : Vec<WordData> = Vec::new();

    for entry in fs::read_dir("./data").unwrap() {
        let dir = match entry {
            Ok(dir) => dir,
            Err(_) => continue,
        };
        let path = dir.path();
        let file_name = path.file_stem();
        let mut file = match fs::File::open(dir.path()) {
            Ok(file) => file,
            Err(_) => continue,
        };
        let mut s = String::new();

        match file.read_to_string(&mut s) {
            Err(_) => continue,
            Ok(_) => {
                let name = match file_name.unwrap().to_str() {
                    Some(fname) => fname,
                    None => continue,
                };
                let count = match limits.get(name) {
                    Some(t) => Some(*t),
                    None => None,
                };
                let temp = WordData{ name: name.to_string(), count: count,
                                          data: RefCell::new(parse_data(s)),
                };
                exported_data.push(temp);
            },
        }
    }
    println!("Filtering data");
    filter_data(&mut exported_data);
    println!("Applying size limits");
    // Apply limits
    for lists in exported_data.iter_mut() {
        if let Some(limit) = limits.get(lists.name.as_str()) {
            lists.data.borrow_mut().truncate(limit.clone());
        }
    }
    println!("Exporting data");
    let mut source : String = String::new();

    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("global_data.rs");
    let mut f = fs::File::create(&dest_path).unwrap();

    for lists in exported_data.iter() {
        let mut line = format!("static {}: &'static [String] = &[ \n",
                               lists.name);

        let data = lists.data.borrow();

        for word in data.iter() {
            let entry = format!("\t\"{}\",\n", word);
            line.push_str(entry.as_str());
        }
        line.push_str("];\n\n");
        source.push_str(line.as_str());
    }
    // Trailing space after \n is to represent offset of keyboard. (¬ is hard)
    let qwerty_uk = "¬` 1! 2\" 3£ 4$ %5 6^ 7& 8* 9( 0) -_ =+ \n \
    qQ wW eE rR tT yY uU iI oO pP [{ ]}\n \
    aA sS dD fF gG hH jJ kK lL ;: '@ #~\n \
    \\| zZ xX cC vV bB nN mM ,< /?".to_string();

    generate_adjacencies(qwerty_uk, KeyAlignment::Slanted);
    f.write_all(source.as_bytes()).unwrap();
    panic!("Test");
}
<commit_msg>Fixed issue in generate_adjacencies, created stub for export_adjacencies and added string constant for dvorak.<commit_after>use std::env;
use std::fs;
use std::io::prelude::*;
use std::io::Write;
use std::path::Path;
use std::collections::HashMap;
use std::cell::RefCell;

enum KeyAlignment {
    Slanted,
    Aligned,
}

struct WordData {
    name: String,
    count: Option<usize>,
    data: RefCell<Vec<String>>,
}

fn parse_data(data: String) -> Vec<String> {
    let mut word_list : Vec<String> = Vec::new();

    for line in data.lines() {
        let mut l = line.split_whitespace();
        let size = line.split_whitespace().count();
        match size  {
            1 | 2=> {
                match l.next() {
                    Some(frqs) => word_list.push(frqs.to_string()),
                    None => continue,
                };
            },
            _ => continue,
        }
    }
    word_list
}

fn is_rare_and_short(word: &String, rank: u32) -> bool {
    let result = if word.len() < 8 {
        rank >=10u32.pow(word.len() as u32)
    } else {
        false
    };
    result
}

fn filter_data(dicts: &mut Vec<WordData>) {
    let mut best_match : HashMap<String, (usize, String)> = HashMap::new();
    // Build best matches. Shows precedence of words in different dictionaries
    for datum in dicts.iter() {
        if datum.count.is_some() {
            let words = datum.data.borrow();
            for (rank, word) in words.iter().enumerate() {
                if best_match.contains_key(word) {
                    if rank < best_match.get(word).unwrap().0 {
                        best_match.insert(word.clone(),
                                          (rank, datum.name.clone()));
                    }
                } else {
                    best_match.insert(word.clone(),
                                      (rank, datum.name.clone()));
                }
            }
        }
    }

    for datum in dicts {
        if datum.count.is_some() {

            let conditional = |w: &String| {
                best_match.get(w).unwrap().1 == datum.name &&
                    !is_rare_and_short(w, best_match.get(w).unwrap().0 as u32)
            };

            let mut words = datum.data.borrow_mut();
            words.retain(conditional);
        }
    }
}

/// Use trailing spaces at the start of lines to represent non character keys
/// such as caps tab and shift.
fn generate_adjacencies(keyboard: String,
                        align: KeyAlignment) -> HashMap<String, String> {
    let mut adj_list : HashMap<String, String> = HashMap::new();
    let rows = keyboard.lines()
        .map(|x| x.split(' ').collect::<Vec<&str>>())
        .collect::<Vec<Vec<&str>>>();
    for (i, row) in rows.iter().enumerate() {
        for (j, key) in row.iter().enumerate() {
            if !key.is_empty() {
                let mut value : String = String::new();
                // Values for row above
                if i>0 {
                    let prev = rows.get(i-1).unwrap();
                    if let Some(pchar) = prev.get(j) {
                        let ap = format!("{} ", pchar);
                        value.push_str(ap.as_str());
                    }
                    if let Some(pchar) = prev.get(j+1) {
                        let ap = format!("{} ", pchar);
                        value.push_str(ap.as_str());
                    }
                }
                // Values for this row
                if j > 0 {
                    let ap = format!("{} ", row.get(j-1).unwrap());
                    value.push_str(ap.as_str());
                }
                if let Some(next) = row.get(j+1) {
                    let ap = format!("{} ", next);
                    value.push_str(ap.as_str());
                }
                // Values for next row
                if let Some(next) = rows.get(i+1) {
                    if let Some(nchar) = next.get(j) {
                        if !nchar.is_empty()
                        {
                            let ap = format!("{} ", nchar);
                            value.push_str(ap.as_str());

                            if let Some(nchar) = next.get(j+1) {
                                let ap = format!("{} ", nchar);
                                value.push_str(ap.as_str());
                            }
                        }
                    }
                }
                adj_list.insert(key.to_string(), value);
            }
        }
    }
    adj_list
}

fn export_adjacencies(target: fs::File, name: String,
                      data: HashMap<String, String>) {
    println!("exportin");
}

// Choose word limits for each file...
fn main() {
    // Data files are either lists or frequency tables. Load all files in data
    // and then identify and parse accordingly and generate code
    println!("Generating source from /data/");
    let limits : HashMap<&str, usize> = {
        let mut map = HashMap::new();
        map.insert("us_tv_and_film", 30000);
        map.insert("english_wikipedia", 30000);
        map.insert("passwords", 30000);
        map.insert("surnames", 10000);
        map
    };

    let mut exported_data : Vec<WordData> = Vec::new();

    for entry in fs::read_dir("./data").unwrap() {
        let dir = match entry {
            Ok(dir) => dir,
            Err(_) => continue,
        };
        let path = dir.path();
        let file_name = path.file_stem();
        let mut file = match fs::File::open(dir.path()) {
            Ok(file) => file,
            Err(_) => continue,
        };
        let mut s = String::new();

        match file.read_to_string(&mut s) {
            Err(_) => continue,
            Ok(_) => {
                let name = match file_name.unwrap().to_str() {
                    Some(fname) => fname,
                    None => continue,
                };
                let count = match limits.get(name) {
                    Some(t) => Some(*t),
                    None => None,
                };
                let temp = WordData{ name: name.to_string(), count: count,
                                          data: RefCell::new(parse_data(s)),
                };
                exported_data.push(temp);
            },
        }
    }
    println!("Filtering data");
    filter_data(&mut exported_data);
    println!("Applying size limits");
    // Apply limits
    for lists in exported_data.iter_mut() {
        if let Some(limit) = limits.get(lists.name.as_str()) {
            lists.data.borrow_mut().truncate(limit.clone());
        }
    }
    println!("Exporting data");
    let mut source : String = String::new();

    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("frequency_data.rs");
    let mut f = fs::File::create(&dest_path).unwrap();

    for lists in exported_data.iter() {
        let mut line = format!("static {}: &'static [String] = &[ \n",
                               lists.name);

        let data = lists.data.borrow();

        for word in data.iter() {
            let entry = format!("\t\"{}\",\n", word);
            line.push_str(entry.as_str());
        }
        line.push_str("];\n\n");
        source.push_str(line.as_str());
    }

    f.write_all(source.as_bytes()).unwrap();
    // Trailing space after \n is to represent offset of keyboard. (¬ is hard)
    let qwerty_uk = "¬` 1! 2\" 3£ 4$ %5 6^ 7& 8* 9( 0) -_ =+\n \
                    qQ wW eE rR tT yY uU iI oO pP [{ ]}\n \
                    aA sS dD fF gG hH jJ kK lL ;: '@ #~\n \
                    \\| zZ xX cC vV bB nN mM ,< /?".to_string();

    let dvorak = "~ 1! 2@ 3# 4$ 5% 6^ 7& 8* 9( 0) [{ ]}\n \
                  '\" ,< .> pP yY fF gG cC rR lL /? =+ \\|\n \
                  aA oO eE uU iI dD hH tT nN sS -_\n \
                  ;: qQ jJ kK xX bB mM vV zZ".to_string();

    let dest_path = Path::new(&out_dir).join("adjacency_data.rs");
    let mut f = fs::File::create(&dest_path).unwrap();
    println!("Generating adjacencies");
    if let Ok(clone_file) = f.try_clone() {
        let data = generate_adjacencies(qwerty_uk, KeyAlignment::Slanted);
        export_adjacencies(clone_file, "qwerty".to_string(), data);
    }
    if let Ok(clone_file) = f.try_clone() {
        let data = generate_adjacencies(dvorak, KeyAlignment::Slanted);
        export_adjacencies(clone_file, "dvorak".to_string(), data);
    }
    panic!("Test");
}
<|endoftext|>


<commit_before>#![allow(unstable)]
use std::io::Command;
use std::os;

fn main() {
    let out_dir = os::getenv("OUT_DIR").unwrap();

    // 1. duktape.o
    Command::new("gcc").args(&["deps/duktape/src/duktape.c", "-c", "-fPIC", "-o"])
                       .arg(format!("{}/duktape.o", out_dir))
                       .status().unwrap();
    // 2. dt.o
    Command::new("gcc").args(&["-I", "deps/duktape/src", "src/dt/dt.c", "-c", "-fPIC", "-o"])
                       .arg(format!("{}/dt.o", out_dir))
                       .status().unwrap();
    // 3. libdt.a
    Command::new("ar").args(&["crus", "libdt.a", "dt.o", "duktape.o"])
                      .cwd(&Path::new(&out_dir))
                      .status().unwrap();
    // 4. configure rustc
    println!("cargo:rustc-flags=-L {} -l dt:static", out_dir);
}
<commit_msg>force clang as C compiler<commit_after>#![allow(unstable)]
use std::io::Command;
use std::os;

fn main() {
    let out_dir = os::getenv("OUT_DIR").unwrap();

    // 1. duktape.o
    Command::new("clang").args(&["deps/duktape/src/duktape.c", "-c", "-fPIC", "-o"])
                       .arg(format!("{}/duktape.o", out_dir))
                       .status().unwrap();
    // 2. dt.o
    Command::new("clang").args(&["-I", "deps/duktape/src", "src/dt/dt.c", "-c", "-fPIC", "-o"])
                       .arg(format!("{}/dt.o", out_dir))
                       .status().unwrap();
    // 3. libdt.a
    Command::new("ar").args(&["crus", "libdt.a", "dt.o", "duktape.o"])
                      .cwd(&Path::new(&out_dir))
                      .status().unwrap();
    // 4. configure rustc
    println!("cargo:rustc-flags=-L {} -l dt:static", out_dir);
}
<|endoftext|>


<commit_before>extern crate gcc;

use std::fs::File;
use std::path::Path;
use std::io::Write;
use std::process::Command;
use std::env;

fn main() {
    if cfg!(target_os = "linux") || cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        env::set_var("CC", "gcc");
        env::set_var("AS", "gcc -c");
        if cfg!(target_os = "linux") {
            env::set_var("AR", "ar");
        }
    } else if cfg!(target_os = "freebsd") || cfg!(target_os = "openbsd") {
        env::set_var("CC", "cc");
        env::set_var("AS", "cc -c");
        env::set_var("AR", "ar");
    }

    let sse3 = if cfg!(target_os = "windows") {
        cfg!(feature = "sse")
    } else {
        let output = if cfg!(target_os = "freebsd") || cfg!(target_os = "openbsd") {
            // /usr/bin/grep -o SSSE3 /var/run/dmesg.boot | /usr/bin/head -1
            Command::new("/usr/bin/grep")
                .arg("-o")
                .arg("SSE3")
                .arg("/var/run/dmesg.boot")
                .output()
                .unwrap()
        } else if cfg!(target_os = "macos") {
            // /usr/sbin/sysctl machdep.cpu.features | grep -m 1 -ow SSSE3
            Command::new("/usr/sbin/sysctl")
                .arg("machdep.cpu.features")
                .output()
                .unwrap()
        } else {
            // /bin/grep -m 1 -o ssse3 /proc/cpuinfo
            Command::new("/bin/grep")
                .arg("-m")
                .arg("1")
                .arg("-o")
                .arg("ssse3")
                .arg("/proc/cpuinfo")
                .output()
                .unwrap()
        };
        let output = std::str::from_utf8(&output.stdout[..]).unwrap().trim();

        if cfg!(target_os = "freebsd") || cfg!(target_os = "openbsd") || cfg!(target_os = "macos") {
            output.contains("SSSE3")
        } else {
            output == "ssse3"
        }
    };

    let mut cflags = "-g -Wall -Wextra -Wno-unused-parameter".to_owned();
    if !cfg!(feature = "no-sse") && sse3 {
        cflags = cflags + " -mssse3";
    }
    if cfg!(feature = "no-sse") && cfg!(target_os = "macos") {
        cflags = cflags + " -march=x86-64";
    }
    cflags = cflags + " -O2";

    env::set_var("CFLAGS", cflags);

    let mut config = gcc::Config::new();
    config.file("src/c/src/bitstring.c")
          .file("src/c/src/encparams.c")
          .file("src/c/src/hash.c")
          .file("src/c/src/idxgen.c")
          .file("src/c/src/key.c")
          .file("src/c/src/mgf.c")
          .file("src/c/src/ntru.c")
          .file("src/c/src/poly.c")
          .file("src/c/src/rand.c")
          .file("src/c/src/arith.c")
          .file("src/c/src/sha1.c")
          .file("src/c/src/sha2.c")
          .file("src/c/src/nist_ctr_drbg.c")
          .file("src/c/src/rijndael.c")
          .file("src/c/src/rijndael-alg-fst.c");

    if sse3 &&
       (cfg!(target_pointer_width = "64") || cfg!(target_os = "macos") ||
        cfg!(target_os = "windows")) {
        let out = if cfg!(target_os = "windows") {
            Command::new("c:\\mingw\\msys\\1.0\\bin\\perl")
                .arg("src/c/src/sha1-mb-x86_64.pl")
                .arg("elf")
                .output()
                .unwrap()
        } else {
            Command::new("/usr/bin/perl")
                .arg("src/c/src/sha1-mb-x86_64.pl")
                .arg("elf")
                .output()
                .unwrap()
        };
        let out = std::str::from_utf8(&out.stdout[..]).unwrap().trim();

        let p = Path::new("src/c/src/sha1-mb-x86_64.s");
        let mut f = File::create(&p).unwrap();
        f.write(out.as_bytes()).unwrap();

        println!("Exists .s: {}", p.exists());

        let out = Command::new(env::var("CC").unwrap())
            .arg("-c")
            .arg("src/c/src/sha1-mb-x86_64.s")
            .arg("-o")
            .arg("src/c/src/sha1-mb-x86_64.o")
            .output()
            .unwrap();

        println!("Exists .o: {}", Path::new("src/c/src/sha1-mb-x86_64.o").exists());
        println!("Out: {}", std::str::from_utf8(&out.stderr[..]).unwrap().trim());

        panic!();

        let out = if cfg!(target_os = "windows") {
            Command::new("c:\\mingw\\msys\\1.0\\bin\\perl")
                .arg("src/c/src/sha256-mb-x86_64.pl")
                .arg("elf")
                .output()
                .unwrap()
        } else {
            Command::new("/usr/bin/perl")
                .arg("src/c/src/sha256-mb-x86_64.pl")
                .arg("elf")
                .output()
                .unwrap()
        };
        let out = std::str::from_utf8(&out.stdout[..]).unwrap().trim();

        let p = Path::new("src/c/src/sha256-mb-x86_64.s");
        let mut f = File::create(&p).unwrap();
        f.write(out.as_bytes()).unwrap();

        Command::new(env::var("CC").unwrap())
            .arg("-c")
            .arg("src/c/src/sha256-mb-x86_64.s")
            .arg("-o")
            .arg("src/c/src/sha256-mb-x86_64.o")
            .output()
            .unwrap();

        config.object("src/c/src/sha1-mb-x86_64.o").object("src/c/src/sha256-mb-x86_64.o");
    }

    config.include("src/c/src").compile("libntru.a");

    if !cfg!(feature = "no-sse") && sse3 {
        println!("cargo:rustc-cfg=SSE3")
    }
}
<commit_msg>Fixed build in MacOS (I hope)<commit_after>extern crate gcc;

use std::fs::File;
use std::path::Path;
use std::io::Write;
use std::process::Command;
use std::env;

fn main() {
    if cfg!(target_os = "linux") || cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        env::set_var("CC", "gcc");
        env::set_var("AS", "gcc -c");
        if cfg!(target_os = "linux") {
            env::set_var("AR", "ar");
        }
    } else if cfg!(target_os = "freebsd") || cfg!(target_os = "openbsd") {
        env::set_var("CC", "cc");
        env::set_var("AS", "cc -c");
        env::set_var("AR", "ar");
    }

    let sse3 = if cfg!(target_os = "windows") {
        cfg!(feature = "sse")
    } else {
        let output = if cfg!(target_os = "freebsd") || cfg!(target_os = "openbsd") {
            // /usr/bin/grep -o SSSE3 /var/run/dmesg.boot | /usr/bin/head -1
            Command::new("/usr/bin/grep")
                .arg("-o")
                .arg("SSE3")
                .arg("/var/run/dmesg.boot")
                .output()
                .unwrap()
        } else if cfg!(target_os = "macos") {
            // /usr/sbin/sysctl machdep.cpu.features | grep -m 1 -ow SSSE3
            Command::new("/usr/sbin/sysctl")
                .arg("machdep.cpu.features")
                .output()
                .unwrap()
        } else {
            // /bin/grep -m 1 -o ssse3 /proc/cpuinfo
            Command::new("/bin/grep")
                .arg("-m")
                .arg("1")
                .arg("-o")
                .arg("ssse3")
                .arg("/proc/cpuinfo")
                .output()
                .unwrap()
        };
        let output = std::str::from_utf8(&output.stdout[..]).unwrap().trim();

        if cfg!(target_os = "freebsd") || cfg!(target_os = "openbsd") || cfg!(target_os = "macos") {
            output.contains("SSSE3")
        } else {
            output == "ssse3"
        }
    };

    let mut cflags = "-g -Wall -Wextra -Wno-unused-parameter".to_owned();
    if !cfg!(feature = "no-sse") && sse3 {
        cflags = cflags + " -mssse3";
    }
    if cfg!(feature = "no-sse") && cfg!(target_os = "macos") {
        cflags = cflags + " -march=x86-64";
    }
    cflags = cflags + " -O2";

    env::set_var("CFLAGS", cflags);

    let mut config = gcc::Config::new();
    config.file("src/c/src/bitstring.c")
          .file("src/c/src/encparams.c")
          .file("src/c/src/hash.c")
          .file("src/c/src/idxgen.c")
          .file("src/c/src/key.c")
          .file("src/c/src/mgf.c")
          .file("src/c/src/ntru.c")
          .file("src/c/src/poly.c")
          .file("src/c/src/rand.c")
          .file("src/c/src/arith.c")
          .file("src/c/src/sha1.c")
          .file("src/c/src/sha2.c")
          .file("src/c/src/nist_ctr_drbg.c")
          .file("src/c/src/rijndael.c")
          .file("src/c/src/rijndael-alg-fst.c");

    if sse3 &&
       (cfg!(target_pointer_width = "64") || cfg!(target_os = "macos") ||
        cfg!(target_os = "windows")) {
        let out = if cfg!(target_os = "windows") {
            Command::new("c:\\mingw\\msys\\1.0\\bin\\perl")
                .arg("src/c/src/sha1-mb-x86_64.pl")
                .arg("coff")
                .output()
                .unwrap()
        } else if cfg!(target_os = "macos") {
            Command::new("/usr/bin/perl")
                .arg("src/c/src/sha1-mb-x86_64.pl")
                .arg("macosx")
                .output()
                .unwrap()
        } else  {
            Command::new("/usr/bin/perl")
                .arg("src/c/src/sha1-mb-x86_64.pl")
                .arg("elf")
                .output()
                .unwrap()
        };
        let out = std::str::from_utf8(&out.stdout[..]).unwrap().trim();

        let p = Path::new("src/c/src/sha1-mb-x86_64.s");
        let mut f = File::create(&p).unwrap();
        f.write(out.as_bytes()).unwrap();

        println!("Exists .s: {}", p.exists());

        Command::new(env::var("CC").unwrap())
            .arg("-c")
            .arg("src/c/src/sha1-mb-x86_64.s")
            .arg("-o")
            .arg("src/c/src/sha1-mb-x86_64.o")
            .output()
            .unwrap();

        let out = if cfg!(target_os = "windows") {
            Command::new("c:\\mingw\\msys\\1.0\\bin\\perl")
                .arg("src/c/src/sha256-mb-x86_64.pl")
                .arg("coff")
                .output()
                .unwrap()
        } else if cfg!(target_os = "macos") {
            Command::new("/usr/bin/perl")
                .arg("src/c/src/sha256-mb-x86_64.pl")
                .arg("macosx")
                .output()
                .unwrap()
        } else {
            Command::new("/usr/bin/perl")
                .arg("src/c/src/sha256-mb-x86_64.pl")
                .arg("elf")
                .output()
                .unwrap()
        };
        let out = std::str::from_utf8(&out.stdout[..]).unwrap().trim();

        let p = Path::new("src/c/src/sha256-mb-x86_64.s");
        let mut f = File::create(&p).unwrap();
        f.write(out.as_bytes()).unwrap();

        Command::new(env::var("CC").unwrap())
            .arg("-c")
            .arg("src/c/src/sha256-mb-x86_64.s")
            .arg("-o")
            .arg("src/c/src/sha256-mb-x86_64.o")
            .output()
            .unwrap();

        config.object("src/c/src/sha1-mb-x86_64.o").object("src/c/src/sha256-mb-x86_64.o");
    }

    config.include("src/c/src").compile("libntru.a");

    if !cfg!(feature = "no-sse") && sse3 {
        println!("cargo:rustc-cfg=SSE3")
    }
}
<|endoftext|>


<commit_before>use std::process::Command;
use std::env;
use std::fs;
use std::path::Path;

fn main() {
    let mut cmd = Command::new("make");
    cmd.arg("static").current_dir("sophia");
    cmd.status().unwrap();

    let dst = env::var("OUT_DIR").unwrap();
    fs::copy("sophia/libsophia.a", Path::new(&dst).join("libsophia.a")).unwrap();
    println!("cargo:rustc-link-search=native={}", dst);
    println!("cargo:rustc-link-lib=static=sophia");
}
<commit_msg>FreeBSD and DragonFly use gmake instead of make<commit_after>use std::process::Command;
use std::env;
use std::fs;
use std::path::Path;

#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
const MAKE: &'static str = "gmake";

#[cfg(not(any(target_os = "dragonfly", target_os = "freebsd")))]
const MAKE: &'static str = "make";

fn main() {
    let mut cmd = Command::new(MAKE);
    cmd.arg("static").current_dir("sophia");
    cmd.status().unwrap();

    let dst = env::var("OUT_DIR").unwrap();
    fs::copy("sophia/libsophia.a", Path::new(&dst).join("libsophia.a")).unwrap();
    println!("cargo:rustc-link-search=native={}", dst);
    println!("cargo:rustc-link-lib=static=sophia");
}
<|endoftext|>