<commit_before>//! Common traits for input backends to receive input from.

use backend::{SeatInternal, TouchSlotInternal};

use std::error::Error;

/// A seat describes a group of input devices and at least one
/// graphics device belonging together.
///
/// By default only one seat exists for most systems and smithay backends
/// however multiseat configurations are possible and should be treated as
/// separated users, all with their own focus, input and cursor available.
///
/// Seats can be checked for equality and hashed for differentiation.
#[derive(Debug, Clone, Copy, Eq)]
pub struct Seat {
    id: u64,
    capabilities: SeatCapabilities,
}

impl SeatInternal for Seat {
    fn new(id: u64, capabilities: SeatCapabilities) -> Seat {
        Seat {
            id: id,
            capabilities: capabilities,
        }
    }

    fn capabilities_mut(&mut self) -> &mut SeatCapabilities {
        &mut self.capabilities
    }
}

impl Seat {
    /// Get the currently capabilities of this `Seat`
    pub fn capabilities(&self) -> &SeatCapabilities {
        &self.capabilities
    }
}

impl ::std::cmp::PartialEq for Seat {
    fn eq(&self, other: &Seat) -> bool {
        self.id == other.id
    }
}

impl ::std::hash::Hash for Seat {
    fn hash<H>(&self, state: &mut H) where H: ::std::hash::Hasher {
        self.id.hash(state);
    }
}

/// Describes capabilities a `Seat` has.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SeatCapabilities {
    /// `Seat` has a pointer
    pub pointer: bool,
    /// `Seat` has a keyboard
    pub keyboard: bool,
    /// `Seat` has a touchscreen
    pub touch: bool,
}

/// State of key on a keyboard. Either pressed or released
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum KeyState {
    /// Key is released
    Released,
    /// Key is pressed
    Pressed,
}

/// A particular mouse button
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum MouseButton {
    /// Left mouse button
    Left,
    /// Middle mouse button
    Middle,
    /// Right mouse button
    Right,
    /// Other mouse button with index
    Other(u8),
}

/// State of a button on a mouse. Either pressed or released
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum MouseButtonState {
    /// Button is released
    Released,
    /// Button is pressed
    Pressed,
}

/// Axis when scrolling
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Axis {
    /// Vertical axis
    Vertical,
    /// Horizonal axis
    Horizontal,
}

/// Source of an axis when scrolling
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum AxisSource {
    /// Finger. Mostly used for trackpads.
    ///
    /// Guarantees that a scroll sequence is terminated with a scroll value of 0.
    /// A caller may use this information to decide on whether kinetic scrolling should
    /// be triggered on this scroll sequence.
    ///
    /// The coordinate system is identical to the
    /// cursor movement, i.e. a scroll value of 1 represents the equivalent relative
    /// motion of 1.
    Finger,
    /// Continous scrolling device. Almost identical to `Finger`
    ///
    /// No terminating event is guaranteed (though it may happen).
    ///
    /// The coordinate system is identical to
    /// the cursor movement, i.e. a scroll value of 1 represents the equivalent relative
    /// motion of 1.
    Continuous,
    /// Scroll wheel.
    ///
    /// No terminating event is guaranteed (though it may happen). Scrolling is in
    /// discrete steps. It is up to the caller how to interpret such different step sizes.
    Wheel,
    /// Scrolling through tilting the scroll wheel.
    ///
    /// No terminating event is guaranteed (though it may happen). Scrolling is in
    /// discrete steps. It is up to the caller how to interpret such different step sizes.
    WheelTilt,
}

/// Slot of a different touch event.
///
/// Touch events are groubed by slots, usually to identify different
/// fingers on a multi-touch enabled input device. Events should only
/// be interpreted in the context of other events on the same slot.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TouchSlot {
    id: u32,
}

impl TouchSlotInternal for TouchSlot {
    fn new(id: u32) -> Self {
        TouchSlot { id: id }
    }
}

/// Touch event
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum TouchEvent {
    /// The start of an event at a given position (x, y).
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Down {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
        /// Absolute x-coordinate of the touch position.
        x: f64,
        /// Absolute y-coordinate of the touch position.
        y: f64,
    },
    /// Movement of a touch on the device surface to a given position (x, y).
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Motion {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
        /// Absolute x-coordinate of the final touch position after the motion.
        x: f64,
        /// Absolute y-coordinate of the final touch position after the motion.
        y: f64,
    },
    /// Stop of an event chain.
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Up {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
    },
    /// Cancel of an event chain. All previous events in the chain should be ignored.
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Cancel {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
    },
    /// Signals the end of a set of touchpoints at one device sample time.
    Frame,
}

/// Trait that describes objects providing a source of input events. All input backends
/// need to implemenent this and provide the same base gurantees about the presicion of
/// given events.
pub trait InputBackend: Sized {
    /// Type of input device associated with the backend
    type InputConfig: ?Sized;

    /// Type representing errors that may be returned when processing events
    type EventError: Error;

    /// Sets a new handler for this `InputBackend`
    fn set_handler<H: InputHandler<Self> + 'static>(&mut self, handler: H);
    /// Get a reference to the currently set handler, if any
    fn get_handler(&mut self) -> Option<&mut InputHandler<Self>>;
    /// Clears the currently handler, if one is set
    fn clear_handler(&mut self);

    /// Get current `InputConfig`
    fn input_config(&mut self) -> &mut Self::InputConfig;

    /// Processes new events of the underlying backend and drives the `InputHandler`.
    fn dispatch_new_events(&mut self) -> Result<(), Self::EventError>;

    /// Sets the cursor position, useful for e.g. pointer wrapping.
    ///
    /// Not guaranteed to be supported on every backend. The result usually
    /// depends on the capability of the backend, but may also fail for certain
    /// specific actions. See the backends documentation.
    fn set_cursor_position(&mut self, x: u32, y: u32) -> Result<(), ()>;
}

/// Implement to receive input events from any `InputBackend`.
pub trait InputHandler<B: InputBackend> {
    /// Called when a new `Seat` has been created
    fn on_seat_created(&mut self, seat: &Seat);
    /// Called when an existing `Seat` has been destroyed.
    fn on_seat_destroyed(&mut self, seat: &Seat);
    /// Called when a `Seat`'s properties have changed.
    fn on_seat_changed(&mut self, seat: &Seat);

    /// Called when a new keyboard event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `key_code` - Code of the pressed key. See linux/input-event-codes.h
    /// - `state` - `KeyState` of the event
    /// - `count` - Total number of keys pressed on all devices on the associated `Seat`
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_keyboard_key(&mut self, seat: &Seat, time: u32, key_code: u32, state: KeyState, count: u32);
    /// Called when a new pointer movement event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `to` - Absolute screen coordinates of the pointer moved to.
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_pointer_move(&mut self, seat: &Seat, time: u32, to: (u32, u32));
    /// Called when a new pointer button event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `button` - Which button was pressed..
    /// - `state` - `MouseButtonState` of the event
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_pointer_button(&mut self, seat: &Seat, time: u32, button: MouseButton, state: MouseButtonState);
    /// Called when a new pointer scroll event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `axis` - `Axis` this event was generated for.
    /// - `source` - Source of the scroll event. Important for interpretation of `amount`.
    /// - `amount` - Amount of scrolling on the given `Axis`. See `source` for interpretation.
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_pointer_scroll(&mut self, seat: &Seat, time: u32, axis: Axis, source: AxisSource, amount: f64);
    /// Called when a new touch event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `event` - Touch event recieved. See `TouchEvent`.
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_touch(&mut self, seat: &Seat, time: u32, event: TouchEvent);

    /// Called when the `InputConfig` was changed through an external event.
    ///
    /// What kind of events can trigger this call is completely backend dependent.
    /// E.g. an input devices was attached/detached or changed it's own configuration.
    fn on_input_config_changed(&mut self, config: &mut B::InputConfig);
}

impl<B: InputBackend> InputHandler<B> for Box<InputHandler<B>> {
    fn on_seat_created(&mut self, seat: &Seat) {
        (**self).on_seat_created(seat)
    }

    fn on_seat_destroyed(&mut self, seat: &Seat) {
        (**self).on_seat_destroyed(seat)
    }

    fn on_seat_changed(&mut self, seat: &Seat) {
        (**self).on_seat_changed(seat)
    }

    fn on_keyboard_key(&mut self, seat: &Seat, time: u32, key_code: u32, state: KeyState, count: u32) {
        (**self).on_keyboard_key(seat, time, key_code, state, count)
    }

    fn on_pointer_move(&mut self, seat: &Seat, time: u32, to: (u32, u32)) {
        (**self).on_pointer_move(seat, time, to)
    }

    fn on_pointer_button(&mut self, seat: &Seat, time: u32, button: MouseButton, state: MouseButtonState) {
        (**self).on_pointer_button(seat, time, button, state)
    }

    fn on_pointer_scroll(&mut self, seat: &Seat, time: u32, axis: Axis, source: AxisSource, amount: f64) {
        (**self).on_pointer_scroll(seat, time, axis, source, amount)
    }

    fn on_touch(&mut self, seat: &Seat, time: u32, event: TouchEvent) {
        (**self).on_touch(seat, time, event)
    }

    fn on_input_config_changed(&mut self, config: &mut B::InputConfig) {
        (**self).on_input_config_changed(config)
    }
}
<commit_msg>Expand `on_seat_changed` documentation<commit_after>//! Common traits for input backends to receive input from.

use backend::{SeatInternal, TouchSlotInternal};

use std::error::Error;

/// A seat describes a group of input devices and at least one
/// graphics device belonging together.
///
/// By default only one seat exists for most systems and smithay backends
/// however multiseat configurations are possible and should be treated as
/// separated users, all with their own focus, input and cursor available.
///
/// Seats can be checked for equality and hashed for differentiation.
#[derive(Debug, Clone, Copy, Eq)]
pub struct Seat {
    id: u64,
    capabilities: SeatCapabilities,
}

impl SeatInternal for Seat {
    fn new(id: u64, capabilities: SeatCapabilities) -> Seat {
        Seat {
            id: id,
            capabilities: capabilities,
        }
    }

    fn capabilities_mut(&mut self) -> &mut SeatCapabilities {
        &mut self.capabilities
    }
}

impl Seat {
    /// Get the currently capabilities of this `Seat`
    pub fn capabilities(&self) -> &SeatCapabilities {
        &self.capabilities
    }
}

impl ::std::cmp::PartialEq for Seat {
    fn eq(&self, other: &Seat) -> bool {
        self.id == other.id
    }
}

impl ::std::hash::Hash for Seat {
    fn hash<H>(&self, state: &mut H) where H: ::std::hash::Hasher {
        self.id.hash(state);
    }
}

/// Describes capabilities a `Seat` has.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SeatCapabilities {
    /// `Seat` has a pointer
    pub pointer: bool,
    /// `Seat` has a keyboard
    pub keyboard: bool,
    /// `Seat` has a touchscreen
    pub touch: bool,
}

/// State of key on a keyboard. Either pressed or released
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum KeyState {
    /// Key is released
    Released,
    /// Key is pressed
    Pressed,
}

/// A particular mouse button
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum MouseButton {
    /// Left mouse button
    Left,
    /// Middle mouse button
    Middle,
    /// Right mouse button
    Right,
    /// Other mouse button with index
    Other(u8),
}

/// State of a button on a mouse. Either pressed or released
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum MouseButtonState {
    /// Button is released
    Released,
    /// Button is pressed
    Pressed,
}

/// Axis when scrolling
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Axis {
    /// Vertical axis
    Vertical,
    /// Horizonal axis
    Horizontal,
}

/// Source of an axis when scrolling
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum AxisSource {
    /// Finger. Mostly used for trackpads.
    ///
    /// Guarantees that a scroll sequence is terminated with a scroll value of 0.
    /// A caller may use this information to decide on whether kinetic scrolling should
    /// be triggered on this scroll sequence.
    ///
    /// The coordinate system is identical to the
    /// cursor movement, i.e. a scroll value of 1 represents the equivalent relative
    /// motion of 1.
    Finger,
    /// Continous scrolling device. Almost identical to `Finger`
    ///
    /// No terminating event is guaranteed (though it may happen).
    ///
    /// The coordinate system is identical to
    /// the cursor movement, i.e. a scroll value of 1 represents the equivalent relative
    /// motion of 1.
    Continuous,
    /// Scroll wheel.
    ///
    /// No terminating event is guaranteed (though it may happen). Scrolling is in
    /// discrete steps. It is up to the caller how to interpret such different step sizes.
    Wheel,
    /// Scrolling through tilting the scroll wheel.
    ///
    /// No terminating event is guaranteed (though it may happen). Scrolling is in
    /// discrete steps. It is up to the caller how to interpret such different step sizes.
    WheelTilt,
}

/// Slot of a different touch event.
///
/// Touch events are groubed by slots, usually to identify different
/// fingers on a multi-touch enabled input device. Events should only
/// be interpreted in the context of other events on the same slot.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TouchSlot {
    id: u32,
}

impl TouchSlotInternal for TouchSlot {
    fn new(id: u32) -> Self {
        TouchSlot { id: id }
    }
}

/// Touch event
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum TouchEvent {
    /// The start of an event at a given position (x, y).
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Down {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
        /// Absolute x-coordinate of the touch position.
        x: f64,
        /// Absolute y-coordinate of the touch position.
        y: f64,
    },
    /// Movement of a touch on the device surface to a given position (x, y).
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Motion {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
        /// Absolute x-coordinate of the final touch position after the motion.
        x: f64,
        /// Absolute y-coordinate of the final touch position after the motion.
        y: f64,
    },
    /// Stop of an event chain.
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Up {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
    },
    /// Cancel of an event chain. All previous events in the chain should be ignored.
    ///
    /// If the device has multi-touch capabilities a slot is given.
    Cancel {
        /// `TouchSlot`, if the device has multi-touch capabilities
        slot: Option<TouchSlot>,
    },
    /// Signals the end of a set of touchpoints at one device sample time.
    Frame,
}

/// Trait that describes objects providing a source of input events. All input backends
/// need to implemenent this and provide the same base gurantees about the presicion of
/// given events.
pub trait InputBackend: Sized {
    /// Type of input device associated with the backend
    type InputConfig: ?Sized;

    /// Type representing errors that may be returned when processing events
    type EventError: Error;

    /// Sets a new handler for this `InputBackend`
    fn set_handler<H: InputHandler<Self> + 'static>(&mut self, handler: H);
    /// Get a reference to the currently set handler, if any
    fn get_handler(&mut self) -> Option<&mut InputHandler<Self>>;
    /// Clears the currently handler, if one is set
    fn clear_handler(&mut self);

    /// Get current `InputConfig`
    fn input_config(&mut self) -> &mut Self::InputConfig;

    /// Processes new events of the underlying backend and drives the `InputHandler`.
    fn dispatch_new_events(&mut self) -> Result<(), Self::EventError>;

    /// Sets the cursor position, useful for e.g. pointer wrapping.
    ///
    /// Not guaranteed to be supported on every backend. The result usually
    /// depends on the capability of the backend, but may also fail for certain
    /// specific actions. See the backends documentation.
    fn set_cursor_position(&mut self, x: u32, y: u32) -> Result<(), ()>;
}

/// Implement to receive input events from any `InputBackend`.
pub trait InputHandler<B: InputBackend> {
    /// Called when a new `Seat` has been created
    fn on_seat_created(&mut self, seat: &Seat);
    /// Called when an existing `Seat` has been destroyed.
    fn on_seat_destroyed(&mut self, seat: &Seat);
    /// Called when a `Seat`'s properties have changed.
    ///
    /// ## Note:
    ///
    /// It is not guaranteed that any change has actually happened.
    fn on_seat_changed(&mut self, seat: &Seat);

    /// Called when a new keyboard event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `key_code` - Code of the pressed key. See linux/input-event-codes.h
    /// - `state` - `KeyState` of the event
    /// - `count` - Total number of keys pressed on all devices on the associated `Seat`
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_keyboard_key(&mut self, seat: &Seat, time: u32, key_code: u32, state: KeyState, count: u32);
    /// Called when a new pointer movement event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `to` - Absolute screen coordinates of the pointer moved to.
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_pointer_move(&mut self, seat: &Seat, time: u32, to: (u32, u32));
    /// Called when a new pointer button event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `button` - Which button was pressed..
    /// - `state` - `MouseButtonState` of the event
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_pointer_button(&mut self, seat: &Seat, time: u32, button: MouseButton, state: MouseButtonState);
    /// Called when a new pointer scroll event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `axis` - `Axis` this event was generated for.
    /// - `source` - Source of the scroll event. Important for interpretation of `amount`.
    /// - `amount` - Amount of scrolling on the given `Axis`. See `source` for interpretation.
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_pointer_scroll(&mut self, seat: &Seat, time: u32, axis: Axis, source: AxisSource, amount: f64);
    /// Called when a new touch event was received.
    ///
    /// # Arguments
    ///
    /// - `seat` - The `Seat` the event belongs to
    /// - `time` - A upward counting variable useful for event ordering. Makes no gurantees about actual time passed between events.
    /// - `event` - Touch event recieved. See `TouchEvent`.
    ///
    /// # TODO:
    /// - check if events can arrive out of order.
    /// - Make stronger time guarantees
    fn on_touch(&mut self, seat: &Seat, time: u32, event: TouchEvent);

    /// Called when the `InputConfig` was changed through an external event.
    ///
    /// What kind of events can trigger this call is completely backend dependent.
    /// E.g. an input devices was attached/detached or changed it's own configuration.
    fn on_input_config_changed(&mut self, config: &mut B::InputConfig);
}

impl<B: InputBackend> InputHandler<B> for Box<InputHandler<B>> {
    fn on_seat_created(&mut self, seat: &Seat) {
        (**self).on_seat_created(seat)
    }

    fn on_seat_destroyed(&mut self, seat: &Seat) {
        (**self).on_seat_destroyed(seat)
    }

    fn on_seat_changed(&mut self, seat: &Seat) {
        (**self).on_seat_changed(seat)
    }

    fn on_keyboard_key(&mut self, seat: &Seat, time: u32, key_code: u32, state: KeyState, count: u32) {
        (**self).on_keyboard_key(seat, time, key_code, state, count)
    }

    fn on_pointer_move(&mut self, seat: &Seat, time: u32, to: (u32, u32)) {
        (**self).on_pointer_move(seat, time, to)
    }

    fn on_pointer_button(&mut self, seat: &Seat, time: u32, button: MouseButton, state: MouseButtonState) {
        (**self).on_pointer_button(seat, time, button, state)
    }

    fn on_pointer_scroll(&mut self, seat: &Seat, time: u32, axis: Axis, source: AxisSource, amount: f64) {
        (**self).on_pointer_scroll(seat, time, axis, source, amount)
    }

    fn on_touch(&mut self, seat: &Seat, time: u32, event: TouchEvent) {
        (**self).on_touch(seat, time, event)
    }

    fn on_input_config_changed(&mut self, config: &mut B::InputConfig) {
        (**self).on_input_config_changed(config)
    }
}
<|endoftext|>


<commit_before>/// Brainfuck language interpreter
/// As specified here: http://www.muppetlabs.com/~breadbox/bf/
#[macro_use]
extern crate clap;

use std::process;
use std::path::{Path};
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::collections::VecDeque;
use std::thread;
use std::time::Duration;

use clap::{Arg, App};

macro_rules! exit_with_error(
    ($($arg:tt)*) => { {
        writeln!(&mut ::std::io::stderr(), $($arg)*)
            .expect("Failed while printing to stderr");
        process::exit(1);
    } }
);

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn main() {
    let args = App::new(crate_name!())
        .version(crate_version!())
        .version_short("v")
        .author(crate_authors!())
        .about(crate_description!())
        .arg(Arg::with_name("input-file")
            .help("The brainfuck file to process. Should contain brainfuck instructions")
            .value_name("file")
            .takes_value(true)
            .required(true)
        )
        .arg(Arg::with_name("debug-enabled")
            .short("D")
            .long("debug")
            .help("Enables debug mode which outputs debugging information to stderr")
        )
        .arg(Arg::with_name("delay")
            .long("delay")
            .takes_value(true)
            .help("Delays execution of each instruction by this amount in ms")
        )
        .get_matches();

    let source_path = Path::new(args.value_of("input-file").unwrap());
    if !source_path.exists() || !source_path.is_file() {
        exit_with_error!("Not a valid file: '{}'", source_path.display());
    }

    let debug_mode = args.is_present("debug-enabled");

    let delay: u64 = if let Some(delay_str) = args.value_of("delay") {
        delay_str.parse().unwrap_or_else(|e: std::num::ParseIntError| exit_with_error!("Invalid delay: {}", e))
    } else {
        0
    };

    let f = File::open(source_path).unwrap_or_else(|e| {
        exit_with_error!("Could not open source file: {}", e);
    });

    let program = f.bytes().map(
        |c| c.expect("Fatal: Could not read char") as char
    ).collect::<Vec<char>>();

    interpret(program, debug_mode, delay);
}

fn interpret(program: Vec<char>, debug: bool, delay: u64) {
    let mut buffer: VecDeque<u8> = VecDeque::new();
    // Make sure there is at least one cell to begin with
    buffer.push_back(0u8);

    // p is the position "pointer" in the buffer
    let mut p: usize = 0;
    // i is the instruction index in the program
    let mut i: usize = 0;

    loop {
        if i >= program.len() {
            break;
        }
        let c = program[i];
        i += 1;

        match c {
            '>' => {
                p += 1;
                if p >= buffer.len() {
                    buffer.push_back(0u8);
                }
            },
            '<' => {
                if p == 0 {
                    buffer.push_front(0u8);
                }
                else {
                    p -= 1;
                }
            },
            '+' => buffer[p] = buffer[p].wrapping_add(1),
            '-' => buffer[p] = buffer[p].wrapping_sub(1),
            '.' => print!("{}", buffer[p] as char),
            ',' => {
                let chr = io::stdin().bytes().next();
                if chr.is_none() {
                    buffer[p] = 0;
                }
                else {
                    buffer[p] = chr.unwrap().expect("Could not read input");
                }
            },
            '[' => {
                if buffer[p] == 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            ']' => {
                if buffer[p] != 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            _ => continue,
        }

        if debug {
            println_stderr!("{{\"lastInstructionIndex\": {}, \"lastInstruction\": \"{}\", \"currentPointer\": {}, \"memory\": \"{}\"}}", i-1, c, p,
                buffer.iter().fold(String::new(), |acc, v| format!("{} {}", acc, v)));
        }

        thread::sleep(Duration::from_millis(delay));
    }
}

/// Finds the matching '[' or ']' for the given position within the program
/// panics if a match is not found
fn find_matching(program: &Vec<char>, start: usize) -> usize {
    let direction: isize = match program[start] {
        '[' => 1,
        ']' => -1,
        _ => unreachable!(),
    };

    let mut count = direction;
    let mut current = start;
    loop {
        if (direction < 0 && current == 0) || (direction > 0 && current >= program.len() - 1) {
            panic!("Could not find matching parenthesis for instruction {}", start);
        }
        current = (current as isize + direction) as usize;
        let c = program[current];

        count = match c {
            '[' => count + 1,
            ']' => count - 1,
            _ => count,
        };

        if count == 0 {
            break;
        }
    }

    current
}
<commit_msg>Specification is now in the repo<commit_after>/// Brainfuck language interpreter

#[macro_use]
extern crate clap;

use std::process;
use std::path::{Path};
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::collections::VecDeque;
use std::thread;
use std::time::Duration;

use clap::{Arg, App};

macro_rules! exit_with_error(
    ($($arg:tt)*) => { {
        writeln!(&mut ::std::io::stderr(), $($arg)*)
            .expect("Failed while printing to stderr");
        process::exit(1);
    } }
);

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn main() {
    let args = App::new(crate_name!())
        .version(crate_version!())
        .version_short("v")
        .author(crate_authors!())
        .about(crate_description!())
        .arg(Arg::with_name("input-file")
            .help("The brainfuck file to process. Should contain brainfuck instructions")
            .value_name("file")
            .takes_value(true)
            .required(true)
        )
        .arg(Arg::with_name("debug-enabled")
            .short("D")
            .long("debug")
            .help("Enables debug mode which outputs debugging information to stderr")
        )
        .arg(Arg::with_name("delay")
            .long("delay")
            .takes_value(true)
            .help("Delays execution of each instruction by this amount in ms")
        )
        .get_matches();

    let source_path = Path::new(args.value_of("input-file").unwrap());
    if !source_path.exists() || !source_path.is_file() {
        exit_with_error!("Not a valid file: '{}'", source_path.display());
    }

    let debug_mode = args.is_present("debug-enabled");

    let delay: u64 = if let Some(delay_str) = args.value_of("delay") {
        delay_str.parse().unwrap_or_else(|e: std::num::ParseIntError| exit_with_error!("Invalid delay: {}", e))
    } else {
        0
    };

    let f = File::open(source_path).unwrap_or_else(|e| {
        exit_with_error!("Could not open source file: {}", e);
    });

    let program = f.bytes().map(
        |c| c.expect("Fatal: Could not read char") as char
    ).collect::<Vec<char>>();

    interpret(program, debug_mode, delay);
}

fn interpret(program: Vec<char>, debug: bool, delay: u64) {
    let mut buffer: VecDeque<u8> = VecDeque::new();
    // Make sure there is at least one cell to begin with
    buffer.push_back(0u8);

    // p is the position "pointer" in the buffer
    let mut p: usize = 0;
    // i is the instruction index in the program
    let mut i: usize = 0;

    loop {
        if i >= program.len() {
            break;
        }
        let c = program[i];
        i += 1;

        match c {
            '>' => {
                p += 1;
                if p >= buffer.len() {
                    buffer.push_back(0u8);
                }
            },
            '<' => {
                if p == 0 {
                    buffer.push_front(0u8);
                }
                else {
                    p -= 1;
                }
            },
            '+' => buffer[p] = buffer[p].wrapping_add(1),
            '-' => buffer[p] = buffer[p].wrapping_sub(1),
            '.' => print!("{}", buffer[p] as char),
            ',' => {
                let chr = io::stdin().bytes().next();
                if chr.is_none() {
                    buffer[p] = 0;
                }
                else {
                    buffer[p] = chr.unwrap().expect("Could not read input");
                }
            },
            '[' => {
                if buffer[p] == 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            ']' => {
                if buffer[p] != 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            _ => continue,
        }

        if debug {
            println_stderr!("{{\"lastInstructionIndex\": {}, \"lastInstruction\": \"{}\", \"currentPointer\": {}, \"memory\": \"{}\"}}", i-1, c, p,
                buffer.iter().fold(String::new(), |acc, v| format!("{} {}", acc, v)));
        }

        thread::sleep(Duration::from_millis(delay));
    }
}

/// Finds the matching '[' or ']' for the given position within the program
/// panics if a match is not found
fn find_matching(program: &Vec<char>, start: usize) -> usize {
    let direction: isize = match program[start] {
        '[' => 1,
        ']' => -1,
        _ => unreachable!(),
    };

    let mut count = direction;
    let mut current = start;
    loop {
        if (direction < 0 && current == 0) || (direction > 0 && current >= program.len() - 1) {
            panic!("Could not find matching parenthesis for instruction {}", start);
        }
        current = (current as isize + direction) as usize;
        let c = program[current];

        count = match c {
            '[' => count + 1,
            ']' => count - 1,
            _ => count,
        };

        if count == 0 {
            break;
        }
    }

    current
}
<|endoftext|>


<commit_before>/// Brainfuck language interpreter
/// As specified here: http://www.muppetlabs.com/~breadbox/bf/
#[macro_use]
extern crate clap;

use std::process;
use std::path::{Path};
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::collections::VecDeque;

use clap::{Arg, App};

macro_rules! exit_with_error(
    ($($arg:tt)*) => { {
        writeln!(&mut ::std::io::stderr(), $($arg)*)
            .expect("Failed while printing to stderr");
        process::exit(1);
    } }
);

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn main() {
    let args = App::new(crate_name!())
        .version(crate_version!())
        .version_short("v")
        .author(crate_authors!())
        .about("Brainfuck interpreter companion to the brain language compiler")
        .arg(Arg::with_name("input-file")
            .help("The brainfuck file to process. Should contain brainfuck instructions")
            .value_name("file")
            .takes_value(true)
            .required(true)
        )
        .arg(Arg::with_name("debug-enabled")
            .short("D")
            .long("debug")
            .help("Enables debug mode which outputs debugging information to stderr")
        )
        .get_matches();

    let source_path = Path::new(args.value_of("input-file").unwrap());
    if !source_path.exists() || !source_path.is_file() {
        exit_with_error!("Not a valid file: '{}'", source_path.display());
    }

    let debug_mode = args.is_present("debug-enabled");

    let f = File::open(source_path).unwrap_or_else(|e| {
        exit_with_error!("Could not open source file: {}", e);
    });

    let program = f.bytes().map(
        |c| c.expect("Fatal: Could not read char") as char
    ).collect::<Vec<char>>();

    interpret(program, debug_mode);
}

fn interpret(program: Vec<char>, debug: bool) {
    if debug {
        println_stderr!("last instruction number,last instruction,current pointer,memory dump");
    }

    let mut buffer: VecDeque<u8> = VecDeque::new();
    // Make sure there is at least one cell to begin with
    buffer.push_back(0u8);

    // p is the position "pointer" in the buffer
    let mut p: usize = 0;
    // i is the instruction index in the program
    let mut i: usize = 0;

    loop {
        if i >= program.len() {
            break;
        }
        let c = program[i];
        i += 1;

        match c {
            '>' => {
                p += 1;
                if p >= buffer.len() {
                    buffer.push_back(0u8);
                }
            },
            '<' => {
                if p == 0 {
                    buffer.push_front(0u8);
                }
                else {
                    p -= 1;
                }
            },
            '+' => buffer[p] = buffer[p].wrapping_add(1),
            '-' => buffer[p] = buffer[p].wrapping_sub(1),
            '.' => print!("{}", buffer[p] as char),
            ',' => {
                let chr = io::stdin().bytes().next();
                if chr.is_none() {
                    break;
                }
                buffer[p] = chr.unwrap().expect("Could not read input");
            },
            '[' => {
                if buffer[p] == 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            ']' => {
                if buffer[p] != 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            _ => continue,
        }

        if debug {
            println_stderr!("{},{},{},{}", i-1, c, p,
                buffer.iter().fold(String::new(), |acc, v| format!("{} {}", acc, v)));
        }
    }
}

/// Finds the matching '[' or ']' for the given position within the program
/// panics if a match is not found
fn find_matching(program: &Vec<char>, start: usize) -> usize {
    let direction: isize = match program[start] {
        '[' => 1,
        ']' => -1,
        _ => unreachable!(),
    };

    let mut count = direction;
    let mut current = start;
    loop {
        if (direction < 0 && current == 0) || (direction > 0 && current >= program.len() - 1) {
            panic!("Could not find matching parenthesis for instruction {}", start);
        }
        current = (current as isize + direction) as usize;
        let c = program[current];

        count = match c {
            '[' => count + 1,
            ']' => count - 1,
            _ => count,
        };

        if count == 0 {
            break;
        }
    }

    current
}
<commit_msg>Changed debug output format to JSON and added a delay parameter in brainfuck interpreter<commit_after>/// Brainfuck language interpreter
/// As specified here: http://www.muppetlabs.com/~breadbox/bf/
#[macro_use]
extern crate clap;

use std::process;
use std::path::{Path};
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::collections::VecDeque;
use std::thread;
use std::time::Duration;

use clap::{Arg, App};

macro_rules! exit_with_error(
    ($($arg:tt)*) => { {
        writeln!(&mut ::std::io::stderr(), $($arg)*)
            .expect("Failed while printing to stderr");
        process::exit(1);
    } }
);

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn main() {
    let args = App::new(crate_name!())
        .version(crate_version!())
        .version_short("v")
        .author(crate_authors!())
        .about("Brainfuck interpreter companion to the brain language compiler")
        .arg(Arg::with_name("input-file")
            .help("The brainfuck file to process. Should contain brainfuck instructions")
            .value_name("file")
            .takes_value(true)
            .required(true)
        )
        .arg(Arg::with_name("debug-enabled")
            .short("D")
            .long("debug")
            .help("Enables debug mode which outputs debugging information to stderr")
        )
        .arg(Arg::with_name("delay")
            .long("delay")
            .takes_value(true)
            .help("Delays execution of each instruction by this amount in ms")
        )
        .get_matches();

    let source_path = Path::new(args.value_of("input-file").unwrap());
    if !source_path.exists() || !source_path.is_file() {
        exit_with_error!("Not a valid file: '{}'", source_path.display());
    }

    let debug_mode = args.is_present("debug-enabled");

    let delay: u64 = if let Some(delay_str) = args.value_of("delay") {
        delay_str.parse().unwrap_or_else(|e: std::num::ParseIntError| exit_with_error!("Invalid delay: {}", e))
    } else {
        0
    };

    let f = File::open(source_path).unwrap_or_else(|e| {
        exit_with_error!("Could not open source file: {}", e);
    });

    let program = f.bytes().map(
        |c| c.expect("Fatal: Could not read char") as char
    ).collect::<Vec<char>>();

    interpret(program, debug_mode, delay);
}

fn interpret(program: Vec<char>, debug: bool, delay: u64) {
    let mut buffer: VecDeque<u8> = VecDeque::new();
    // Make sure there is at least one cell to begin with
    buffer.push_back(0u8);

    // p is the position "pointer" in the buffer
    let mut p: usize = 0;
    // i is the instruction index in the program
    let mut i: usize = 0;

    loop {
        if i >= program.len() {
            break;
        }
        let c = program[i];
        i += 1;

        match c {
            '>' => {
                p += 1;
                if p >= buffer.len() {
                    buffer.push_back(0u8);
                }
            },
            '<' => {
                if p == 0 {
                    buffer.push_front(0u8);
                }
                else {
                    p -= 1;
                }
            },
            '+' => buffer[p] = buffer[p].wrapping_add(1),
            '-' => buffer[p] = buffer[p].wrapping_sub(1),
            '.' => print!("{}", buffer[p] as char),
            ',' => {
                let chr = io::stdin().bytes().next();
                if chr.is_none() {
                    break;
                }
                buffer[p] = chr.unwrap().expect("Could not read input");
            },
            '[' => {
                if buffer[p] == 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            ']' => {
                if buffer[p] != 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            _ => continue,
        }

        thread::sleep(Duration::from_millis(delay));

        if debug {
            println_stderr!("{{lastInstructionIndex: {}, lastInstruction: \"{}\", currentPointer: {}, memory: \"{}\"}}", i-1, c, p,
                buffer.iter().fold(String::new(), |acc, v| format!("{} {}", acc, v)));
        }
    }
}

/// Finds the matching '[' or ']' for the given position within the program
/// panics if a match is not found
fn find_matching(program: &Vec<char>, start: usize) -> usize {
    let direction: isize = match program[start] {
        '[' => 1,
        ']' => -1,
        _ => unreachable!(),
    };

    let mut count = direction;
    let mut current = start;
    loop {
        if (direction < 0 && current == 0) || (direction > 0 && current >= program.len() - 1) {
            panic!("Could not find matching parenthesis for instruction {}", start);
        }
        current = (current as isize + direction) as usize;
        let c = program[current];

        count = match c {
            '[' => count + 1,
            ']' => count - 1,
            _ => count,
        };

        if count == 0 {
            break;
        }
    }

    current
}
<|endoftext|>


<commit_before>extern crate octobuild;
extern crate petgraph;
extern crate tempdir;
extern crate regex;
#[macro_use]
extern crate lazy_static;

use octobuild::common::BuildTask;
use octobuild::config::Config;
use octobuild::cache::Cache;
use octobuild::xg;
use octobuild::version;
use octobuild::vs::compiler::VsCompiler;
use octobuild::io::statistic::Statistic;
use octobuild::clang::compiler::ClangCompiler;
use octobuild::compiler::*;

use petgraph::{Graph, EdgeDirection};
use petgraph::graph::NodeIndex;
use tempdir::TempDir;
use regex::Regex;

use std::fs::File;
use std::env;
use std::io::{BufReader, Error, ErrorKind, Write};
use std::io;
use std::iter::FromIterator;
use std::path::Path;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::process;
use std::thread;

#[derive(Debug)]
struct TaskMessage {
	index: NodeIndex,
	task: BuildTask
}

#[derive(Debug)]
struct ResultMessage {
	index: NodeIndex,
	task: BuildTask,
	worker: usize,
	result: Result<OutputInfo, Error>
}

fn main() {
	println!("xgConsole ({}):", version::full_version());
	let args = Vec::from_iter(env::args());
	for arg in args.iter() {
		println!("  {}", arg);
	}
	if args.len() == 1 {
		println!("");
		Config::help();
		return;
	}

	process::exit(match execute(&args[1..]) {
		Ok(result) => {
			match result {
				Some(r) => r,
				None => 501
			}
		}
		Err(e) => {
			println!("FATAL ERROR: {:?}", e);
			500
		}
	})
}

fn is_flag(arg: &str) -> bool {
  lazy_static! {
    static ref RE: Regex = Regex::new(r"^/\w+([=].*)?$").unwrap();
  }
  RE.is_match(arg)
}

fn execute(args: &[String]) -> Result<Option<i32>, Error> {
	let statistic = Arc::new(RwLock::new(Statistic::new()));
	let config = try! (Config::new());
	let cache = Cache::new(&config);
	let temp_dir = try! (TempDir::new("octobuild"));
	let files = Vec::from_iter(args.iter().filter(|a| !is_flag(a)));
	if files.len() == 0 {
		return Err(Error::new(ErrorKind::InvalidInput, "Build task files not found"));
	}

	let mut graph = Graph::new();
	for arg in files.iter() {
		let file = try! (File::open(&Path::new(arg)));
		try! (xg::parser::parse(&mut graph, BufReader::new(file)));
	}
	let validated_graph = try! (validate_graph(graph));

	let (tx_result, rx_result): (Sender<ResultMessage>, Receiver<ResultMessage>) = channel();
	let (tx_task, rx_task): (Sender<TaskMessage>, Receiver<TaskMessage>) = channel();
	let mutex_rx_task = create_threads(rx_task, tx_result, config.process_limit, |worker_id:usize| {
		let temp_path = temp_dir.path().to_path_buf();
		let temp_cache = cache.clone();
		let temp_statistic = statistic.clone();
		move |task:TaskMessage| -> ResultMessage {
			execute_task(&temp_cache, &temp_path, worker_id, task, &temp_statistic)
		}
	});

	match try! (execute_graph(&validated_graph, tx_task, mutex_rx_task, rx_result)) {
		Some(v) if v == 0 => {}
		v => {return Ok(v)}
	}
	cache.cleanup();
	println!("{}", statistic.read().unwrap().to_string());
	Ok(Some(0))
}

fn create_threads<R: 'static + Send, T: 'static + Send, Worker:'static + Fn(T) -> R + Send, Factory:Fn(usize) -> Worker>(rx_task: Receiver<T>, tx_result: Sender<R>, num_cpus: usize, factory: Factory) ->  Arc<Mutex<Receiver<T>>> {
	let mutex_rx_task = Arc::new(Mutex::new(rx_task));
	for cpu_id in 0..num_cpus {
		let local_rx_task = mutex_rx_task.clone();
		let local_tx_result = tx_result.clone();
		let worker = factory(cpu_id);
		thread::spawn(move || {
			loop {
				let task: T;
				match local_rx_task.lock().unwrap().recv() {
					Ok(v) => {task = v;}
					Err(_) => {break;}
				}
				match local_tx_result.send(worker(task)) {
					Ok(_) => {}
					Err(_) => {break;}
				}
			}
		});
	}
	mutex_rx_task
}

fn validate_graph(graph: Graph<BuildTask, ()>) -> Result<Graph<BuildTask, ()>, Error> {
	let mut completed:Vec<bool> = Vec::new();
	let mut queue:Vec<NodeIndex> = Vec::new();
	for index in 0 .. graph.node_count() {
		completed.push(false);
		queue.push(NodeIndex::new(index));
	}
	let mut count:usize = 0;
	let mut i:usize = 0;
	while i < queue.len() {
		let index = queue[i];
		if (!completed[index.index()]) && (is_ready(&graph, &completed, &index)) {
			completed[index.index()] = true;
			for neighbor in graph.neighbors_directed(index, EdgeDirection::Incoming) {
				queue.push(neighbor);
			}
			count += 1;
			if count == completed.len() {
				return Ok(graph);
			}
		}
		i = i + 1;
	}
	Err(Error::new(ErrorKind::InvalidInput, "Found cycles in build dependencies"))
}

fn execute_task(cache: &Cache, temp_dir: &Path, worker: usize, message: TaskMessage, statistic: &RwLock<Statistic>) -> ResultMessage {
	let args = expand_args(&message.task.args, &|name:&str|->Option<String>{env::var(name).ok()});
	let output = execute_compiler(cache, temp_dir, &message.task, &args, statistic);
	ResultMessage {
		index: message.index,
		task: message.task,
		worker: worker,
		result: output,
	}
}

fn execute_compiler(cache: &Cache, temp_dir: &Path, task: &BuildTask, args: &[String], statistic: &RwLock<Statistic>) -> Result<OutputInfo, Error> {
	let command = CommandInfo {
		program: Path::new(&task.exec).to_path_buf(),
		current_dir: Some(Path::new(&task.working_dir).to_path_buf()),
		env: task.env.clone(),
	};
	let exec = Path::new(&task.exec);
	if exec.ends_with("cl.exe") {
		let compiler = VsCompiler::new(cache, temp_dir);
		compiler.compile(command, args, statistic)
	} else if exec.file_name().map_or(None, |name| name.to_str()).map_or(false, |name| name.starts_with("clang")) {
		let compiler = ClangCompiler::new(cache);
		compiler.compile(command, args, statistic)
	} else {
		command.to_command()
			.args(&args)
			.output()
			.map(|o| OutputInfo::new(o))
	}
}

fn execute_graph(graph: &Graph<BuildTask, ()>, tx_task: Sender<TaskMessage>, mutex_rx_task: Arc<Mutex<Receiver<TaskMessage>>>, rx_result: Receiver<ResultMessage>) -> Result<Option<i32>, Error> {
	// Run all tasks.
	let mut count: usize = 0;
	let result = execute_until_failed(graph, tx_task, &rx_result, &mut count);
	// Cleanup task queue.
	for _ in mutex_rx_task.lock().unwrap().iter() {
	}
	// Wait for in progress task completion.
	for message in rx_result.iter() {
		try! (print_task_result(&message, &mut count, graph.node_count()));
	}
	result
}

fn execute_until_failed(graph: &Graph<BuildTask, ()>, tx_task: Sender<TaskMessage>, rx_result: &Receiver<ResultMessage>, count: &mut usize) -> Result<Option<i32>, Error> {
	let mut completed:Vec<bool> = Vec::new();
	for _ in 0 .. graph.node_count() {
		completed.push(false);
	}
	for index in graph.externals(EdgeDirection::Outgoing) {
		try! (tx_task.send(TaskMessage{
			index: index,
			task: graph.node_weight(index).unwrap().clone(),
		}).map_err(|e| Error::new(ErrorKind::Other, e)));
	}

	for message in rx_result.iter() {
		assert!(!completed[message.index.index()]);
		try! (print_task_result(&message, count, graph.node_count()));
		let result = try! (message.result);
		if !result.success() {
			return Ok(result.status);
		}
		completed[message.index.index()] = true;

		for source in graph.neighbors_directed(message.index, EdgeDirection::Incoming) {
			if is_ready(graph, &completed, &source) {
				try! (tx_task.send(TaskMessage{
					index: source,
					task: graph.node_weight(source).unwrap().clone(),
				}).map_err(|e| Error::new(ErrorKind::Other, e)));
			}
		}

		if *count == completed.len() {
			return Ok(Some(0));
		}
	}
	panic! ("Unexpected end of result pipe");
}

fn print_task_result(message: &ResultMessage, completed: &mut usize, total: usize) -> Result<(), Error> {
	*completed += 1;
	println!("#{} {}/{}: {}", message.worker, completed, total, message.task.title);
	match message.result {
		Ok(ref output) => {
			try! (io::stdout().write_all(&output.stdout));
			try! (io::stderr().write_all(&output.stderr));
		}
		Err(_) => {
		}
	}
	Ok(())
}

fn is_ready(graph: &Graph<BuildTask, ()>, completed: &Vec<bool>, source: &NodeIndex) -> bool {
	for neighbor in graph.neighbors_directed(*source, EdgeDirection::Outgoing) {
		if !completed[neighbor.index()]{
			return false
		}
	}
	true
}

fn expand_arg<F: Fn(&str) -> Option<String>>(arg: &str, resolver: &F) -> String {
	let mut result = String::new();
	let mut suffix = arg;
	loop {
		match suffix.find("$(") {
			Some(begin) => {
				match suffix[begin..].find(")") {
					Some(end) => {
						let name = &suffix[begin + 2..begin + end];
						match resolver(name) {
							Some(ref value) => {
								result = result + &suffix[..begin] + &value;
							}
							None => {
								result = result + &suffix[..begin + end + 1];
							}
						}
						suffix = &suffix[begin + end + 1..];
					}
					None => {
						result = result+suffix;
						break;
					}
				}
			}
			None => {
				result = result+ suffix;
				break;
			}
		}
	}
	result
}

fn expand_args<F: Fn(&str) -> Option<String>>(args: &Vec<String>, resolver: &F) -> Vec<String> {
	let mut result:Vec<String> = Vec::new();
	for arg in args.iter() {
		result.push(expand_arg(&arg, resolver));
	}
	result
}

#[test]
fn test_parse_vars() {
	assert_eq!(expand_arg("A$(test)$(inner)$(none)B", &|name:&str|->Option<String> {
		match name {
			"test" => {
				Some("foo".to_string())
			}
			"inner" => {
				Some("$(bar)".to_string())
			}
			"none" => {
				None
			}
			_ => {
				assert!(false, format!("Unexpected value: {}", name));
				None
			}
		}
	}), "Afoo$(bar)$(none)B");
}

#[test]
fn test_is_flag() {
  assert_eq!(is_flag("/Wait"), true);
  assert_eq!(is_flag("/out=/foo/bar"), true);
  assert_eq!(is_flag("/out/foo/bar"), false);
  assert_eq!(is_flag("foo/bar"), false);
  assert_eq!(is_flag("/Wait.xml"), false);
  assert_eq!(is_flag("/Wait/foo=bar"), false);
  assert_eq!(is_flag("/WaitFoo=bar"), true);
  assert_eq!(is_flag("/Wait.Foo=bar"), false);
  assert_eq!(is_flag("/Wait=/foo/bar"), true);
}
<commit_msg>xgConsole: Add expand path masks on Windows<commit_after>extern crate octobuild;
extern crate petgraph;
extern crate tempdir;
extern crate regex;
#[macro_use]
extern crate lazy_static;

use octobuild::common::BuildTask;
use octobuild::config::Config;
use octobuild::cache::Cache;
use octobuild::xg;
use octobuild::version;
use octobuild::vs::compiler::VsCompiler;
use octobuild::io::statistic::Statistic;
use octobuild::clang::compiler::ClangCompiler;
use octobuild::compiler::*;

use petgraph::{Graph, EdgeDirection};
use petgraph::graph::NodeIndex;
use tempdir::TempDir;
use regex::Regex;

use std::fs::File;
use std::env;
use std::io::{BufReader, Error, ErrorKind, Write};
use std::io;
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};
use std::process;
use std::thread;

#[derive(Debug)]
struct TaskMessage {
	index: NodeIndex,
	task: BuildTask
}

#[derive(Debug)]
struct ResultMessage {
	index: NodeIndex,
	task: BuildTask,
	worker: usize,
	result: Result<OutputInfo, Error>
}

fn main() {
	println!("xgConsole ({}):", version::full_version());
	let args = Vec::from_iter(env::args());
	for arg in args.iter() {
		println!("  {}", arg);
	}
	if args.len() == 1 {
		println!("");
		Config::help();
		return;
	}

	process::exit(match execute(&args[1..]) {
		Ok(result) => {
			match result {
				Some(r) => r,
				None => 501
			}
		}
		Err(e) => {
			println!("FATAL ERROR: {:?}", e);
			500
		}
	})
}

fn is_flag(arg: &str) -> bool {
	lazy_static! {
		static ref RE: Regex = Regex::new(r"^/\w+([=].*)?$").unwrap();
	}
	RE.is_match(arg)
}

#[cfg(unix)]
fn expand_files(mut files: Vec<PathBuf>, arg: &str) -> Vec<PathBuf> {
	files.push(Path::new(arg).to_path_buf());
	files
}

#[cfg(windows)]
fn expand_files(mut files: Vec<PathBuf>, arg: &str) -> Vec<PathBuf> {
	use std::fs;

	fn mask_to_regex(mask: &str) -> Regex {
		let mut result = String::new();
		let mut begin = 0;
		result.push_str("^");
		for (index, separator) in mask.match_indices(|c| c == '?' || c == '*') {
			result.push_str(&regex::quote(&mask[begin..index]));
			result.push_str(match separator {
				"?" => ".",
				"*" => ".*",
				unknown => panic!("Unexpected separator: {}", unknown),
			});
			begin = index + separator.len()
		}
		result.push_str(&regex::quote(&mask[begin..]));
		result.push_str("$");
		return Regex::new(&result).unwrap();
	}

	fn find_files(dir: &Path, mask: &str) -> Result<Vec<PathBuf>, Error> {
		let mut result = Vec::new();
		let expr = mask_to_regex(&mask.to_lowercase());
		for entry in try!(fs::read_dir(dir)) {
			let entry = try!(entry);
			if entry.file_name().to_str().map_or(false, |s| expr.is_match(&s.to_lowercase())) {
				result.push(entry.path());
			}
		}
		Ok(result)
	}

	let path = Path::new(arg).to_path_buf();
	let mask = path.file_name().map_or(None, |name| name.to_str()).map_or(None, |s| Some(s.to_string()));
	match mask {
		Some(ref mask) if mask.contains(|c| c == '?' || c == '*') => {
			match find_files(path.parent().unwrap_or(Path::new(".")), mask) {
				Ok(ref mut found) if found.len() > 0 => {
					files.append(found);
				}
				_ => {
					files.push(path);
				}
			}
		}
		_ => {
			files.push(path);
		}
	}
	files
}

fn execute(args: &[String]) -> Result<Option<i32>, Error> {
	let statistic = Arc::new(RwLock::new(Statistic::new()));
	let config = try! (Config::new());
	let cache = Cache::new(&config);
	let temp_dir = try! (TempDir::new("octobuild"));
	let files = args.iter().filter(|a| !is_flag(a)).fold(Vec::new(), |state, a| expand_files(state, &a));
	if files.len() == 0 {
		return Err(Error::new(ErrorKind::InvalidInput, "Build task files not found"));
	}

	let mut graph = Graph::new();
	for arg in files.iter() {
		let file = try! (File::open(&Path::new(arg)));
		try! (xg::parser::parse(&mut graph, BufReader::new(file)));
	}
	let validated_graph = try! (validate_graph(graph));

	let (tx_result, rx_result): (Sender<ResultMessage>, Receiver<ResultMessage>) = channel();
	let (tx_task, rx_task): (Sender<TaskMessage>, Receiver<TaskMessage>) = channel();
	let mutex_rx_task = create_threads(rx_task, tx_result, config.process_limit, |worker_id:usize| {
		let temp_path = temp_dir.path().to_path_buf();
		let temp_cache = cache.clone();
		let temp_statistic = statistic.clone();
		move |task:TaskMessage| -> ResultMessage {
			execute_task(&temp_cache, &temp_path, worker_id, task, &temp_statistic)
		}
	});

	match try! (execute_graph(&validated_graph, tx_task, mutex_rx_task, rx_result)) {
		Some(v) if v == 0 => {}
		v => {return Ok(v)}
	}
	cache.cleanup();
	println!("{}", statistic.read().unwrap().to_string());
	Ok(Some(0))
}

fn create_threads<R: 'static + Send, T: 'static + Send, Worker:'static + Fn(T) -> R + Send, Factory:Fn(usize) -> Worker>(rx_task: Receiver<T>, tx_result: Sender<R>, num_cpus: usize, factory: Factory) ->  Arc<Mutex<Receiver<T>>> {
	let mutex_rx_task = Arc::new(Mutex::new(rx_task));
	for cpu_id in 0..num_cpus {
		let local_rx_task = mutex_rx_task.clone();
		let local_tx_result = tx_result.clone();
		let worker = factory(cpu_id);
		thread::spawn(move || {
			loop {
				let task: T;
				match local_rx_task.lock().unwrap().recv() {
					Ok(v) => {task = v;}
					Err(_) => {break;}
				}
				match local_tx_result.send(worker(task)) {
					Ok(_) => {}
					Err(_) => {break;}
				}
			}
		});
	}
	mutex_rx_task
}

fn validate_graph(graph: Graph<BuildTask, ()>) -> Result<Graph<BuildTask, ()>, Error> {
	let mut completed:Vec<bool> = Vec::new();
	let mut queue:Vec<NodeIndex> = Vec::new();
	for index in 0 .. graph.node_count() {
		completed.push(false);
		queue.push(NodeIndex::new(index));
	}
	let mut count:usize = 0;
	let mut i:usize = 0;
	while i < queue.len() {
		let index = queue[i];
		if (!completed[index.index()]) && (is_ready(&graph, &completed, &index)) {
			completed[index.index()] = true;
			for neighbor in graph.neighbors_directed(index, EdgeDirection::Incoming) {
				queue.push(neighbor);
			}
			count += 1;
			if count == completed.len() {
				return Ok(graph);
			}
		}
		i = i + 1;
	}
	Err(Error::new(ErrorKind::InvalidInput, "Found cycles in build dependencies"))
}

fn execute_task(cache: &Cache, temp_dir: &Path, worker: usize, message: TaskMessage, statistic: &RwLock<Statistic>) -> ResultMessage {
	let args = expand_args(&message.task.args, &|name:&str|->Option<String>{env::var(name).ok()});
	let output = execute_compiler(cache, temp_dir, &message.task, &args, statistic);
	ResultMessage {
		index: message.index,
		task: message.task,
		worker: worker,
		result: output,
	}
}

fn execute_compiler(cache: &Cache, temp_dir: &Path, task: &BuildTask, args: &[String], statistic: &RwLock<Statistic>) -> Result<OutputInfo, Error> {
	let command = CommandInfo {
		program: Path::new(&task.exec).to_path_buf(),
		current_dir: Some(Path::new(&task.working_dir).to_path_buf()),
		env: task.env.clone(),
	};
	let exec = Path::new(&task.exec);
	if exec.ends_with("cl.exe") {
		let compiler = VsCompiler::new(cache, temp_dir);
		compiler.compile(command, args, statistic)
	} else if exec.file_name().map_or(None, |name| name.to_str()).map_or(false, |name| name.starts_with("clang")) {
		let compiler = ClangCompiler::new(cache);
		compiler.compile(command, args, statistic)
	} else {
		command.to_command()
			.args(&args)
			.output()
			.map(|o| OutputInfo::new(o))
	}
}

fn execute_graph(graph: &Graph<BuildTask, ()>, tx_task: Sender<TaskMessage>, mutex_rx_task: Arc<Mutex<Receiver<TaskMessage>>>, rx_result: Receiver<ResultMessage>) -> Result<Option<i32>, Error> {
	// Run all tasks.
	let mut count: usize = 0;
	let result = execute_until_failed(graph, tx_task, &rx_result, &mut count);
	// Cleanup task queue.
	for _ in mutex_rx_task.lock().unwrap().iter() {
	}
	// Wait for in progress task completion.
	for message in rx_result.iter() {
		try! (print_task_result(&message, &mut count, graph.node_count()));
	}
	result
}

fn execute_until_failed(graph: &Graph<BuildTask, ()>, tx_task: Sender<TaskMessage>, rx_result: &Receiver<ResultMessage>, count: &mut usize) -> Result<Option<i32>, Error> {
	let mut completed:Vec<bool> = Vec::new();
	for _ in 0 .. graph.node_count() {
		completed.push(false);
	}
	for index in graph.externals(EdgeDirection::Outgoing) {
		try! (tx_task.send(TaskMessage{
			index: index,
			task: graph.node_weight(index).unwrap().clone(),
		}).map_err(|e| Error::new(ErrorKind::Other, e)));
	}

	for message in rx_result.iter() {
		assert!(!completed[message.index.index()]);
		try! (print_task_result(&message, count, graph.node_count()));
		let result = try! (message.result);
		if !result.success() {
			return Ok(result.status);
		}
		completed[message.index.index()] = true;

		for source in graph.neighbors_directed(message.index, EdgeDirection::Incoming) {
			if is_ready(graph, &completed, &source) {
				try! (tx_task.send(TaskMessage{
					index: source,
					task: graph.node_weight(source).unwrap().clone(),
				}).map_err(|e| Error::new(ErrorKind::Other, e)));
			}
		}

		if *count == completed.len() {
			return Ok(Some(0));
		}
	}
	panic! ("Unexpected end of result pipe");
}

fn print_task_result(message: &ResultMessage, completed: &mut usize, total: usize) -> Result<(), Error> {
	*completed += 1;
	println!("#{} {}/{}: {}", message.worker, completed, total, message.task.title);
	match message.result {
		Ok(ref output) => {
			try! (io::stdout().write_all(&output.stdout));
			try! (io::stderr().write_all(&output.stderr));
		}
		Err(_) => {
		}
	}
	Ok(())
}

fn is_ready(graph: &Graph<BuildTask, ()>, completed: &Vec<bool>, source: &NodeIndex) -> bool {
	for neighbor in graph.neighbors_directed(*source, EdgeDirection::Outgoing) {
		if !completed[neighbor.index()]{
			return false
		}
	}
	true
}

fn expand_arg<F: Fn(&str) -> Option<String>>(arg: &str, resolver: &F) -> String {
	let mut result = String::new();
	let mut suffix = arg;
	loop {
		match suffix.find("$(") {
			Some(begin) => {
				match suffix[begin..].find(")") {
					Some(end) => {
						let name = &suffix[begin + 2..begin + end];
						match resolver(name) {
							Some(ref value) => {
								result = result + &suffix[..begin] + &value;
							}
							None => {
								result = result + &suffix[..begin + end + 1];
							}
						}
						suffix = &suffix[begin + end + 1..];
					}
					None => {
						result = result+suffix;
						break;
					}
				}
			}
			None => {
				result = result+ suffix;
				break;
			}
		}
	}
	result
}

fn expand_args<F: Fn(&str) -> Option<String>>(args: &Vec<String>, resolver: &F) -> Vec<String> {
	let mut result:Vec<String> = Vec::new();
	for arg in args.iter() {
		result.push(expand_arg(&arg, resolver));
	}
	result
}

#[test]
fn test_parse_vars() {
	assert_eq!(expand_arg("A$(test)$(inner)$(none)B", &|name:&str|->Option<String> {
		match name {
			"test" => {
				Some("foo".to_string())
			}
			"inner" => {
				Some("$(bar)".to_string())
			}
			"none" => {
				None
			}
			_ => {
				assert!(false, format!("Unexpected value: {}", name));
				None
			}
		}
	}), "Afoo$(bar)$(none)B");
}

#[test]
fn test_is_flag() {
	assert_eq!(is_flag("/Wait"), true);
	assert_eq!(is_flag("/out=/foo/bar"), true);
	assert_eq!(is_flag("/out/foo/bar"), false);
	assert_eq!(is_flag("foo/bar"), false);
	assert_eq!(is_flag("/Wait.xml"), false);
	assert_eq!(is_flag("/Wait/foo=bar"), false);
	assert_eq!(is_flag("/WaitFoo=bar"), true);
	assert_eq!(is_flag("/Wait.Foo=bar"), false);
	assert_eq!(is_flag("/Wait=/foo/bar"), true);
}
<|endoftext|>


<commit_before>//! Functions to choose good boundaries for block splitting. Deflate allows
//! encoding the data in multiple blocks, with a separate Huffman tree for each
//! block. The Huffman tree itself requires some bytes to encode, so by
//! choosing certain blocks, you can either hurt, or enhance compression. These
//! functions choose good ones that enhance it.

use std::io::Write;
use std::mem::{transmute, uninitialized};
use std::ptr::null_mut;

use libc::size_t;
use libc::funcs::c95::stdlib::{free, malloc};

use super::Options;

use deflate::calculate_block_size;
use lz77::{BlockState, LZ77Store, clean_lz77_store, lz77_greedy};
use util;

/// Finds minimum of function f(i) where is is of type size_t, f(i) is of type
/// double, i is in range start-end (excluding end).
unsafe fn find_minimum<F>(f: F, start: usize, end: usize) -> usize
    where F: Fn(usize) -> f64
{

    if end - start < 1024 {
        let mut best: f64 = util::LARGE_FLOAT;
        let mut result = start;
        for i in start..end {
            let v = f(i);
            if v < best {
                best = v;
                result = i;
            }
        }
        result
    } else {
        // Try to find minimum faster by recursively checking multiple points.

        // Good value: 9.
        const NUM: usize = 9;

        let mut p: [usize; NUM] = uninitialized();
        let mut vp: [f64; NUM] = uninitialized();
        let mut lastbest: f64 = util::LARGE_FLOAT;
        let mut pos = start;

        let mut start = start;
        let mut end = end;
        loop {
            if end - start <= NUM {
                break;
            }

            for i in 0..NUM {
                p[i] = start + (i + 1) * ((end - start) / (NUM + 1));
                vp[i] = f(p[i]);
            }
            let mut besti: usize = 0;
            let mut best: f64 = vp[0];
            for i in 1..NUM {
                if vp[i] < best {
                    best = vp[i];
                    besti = i;
                }
            }
            if best > lastbest {
                break;
            }

            start = if besti == 0 { start } else { p[besti - 1] };
            end = if besti == NUM - 1 { end } else { p[besti + 1] };

            pos = p[besti];
            lastbest = best;
        }
        pos
    }
}

/**
 * Returns estimated cost of a block in bits.  It includes the size to encode the
 * tree and the size to encode all literal, length and distance symbols and their
 * extra bits.
 *
 * litlens: lz77 lit/lengths
 * dists: ll77 distances
 * lstart: start of block
 * lend: end of block (not inclusive)
 */
unsafe fn estimate_cost(litlens: *const u16, dists: *const u16, lstart: usize, lend: usize) -> f64 {
    calculate_block_size(litlens, dists, lstart, lend, 2)
}

struct SplitCostContext {
    litlens: *const u16,
    dists: *const u16,
    _llsize: usize,
    start: usize,
    end: usize,
}

/// Gets the cost which is the sum of the cost of the left and the right section
/// of the data.
/// type: FindMinimumFun
unsafe fn split_cost(i: usize, c: &SplitCostContext) -> f64 {
    estimate_cost(c.litlens, c.dists, c.start, i) + estimate_cost(c.litlens, c.dists, i, c.end)
}

unsafe fn add_sorted(value: usize, out: &mut Vec<usize>) {
    out.push(value);
    let mut i: usize = 0;
    while i + 1 < out.len() {
        if out[i] > value {
            let mut j: usize = out.len() - 1;
            while j > i {
                out[j] = out[j - 1];
                j -= 1;
            }
            out[i] = value;
            break;
        }
        i += 1;
    }
}

/// Prints the block split points as decimal and hex values in the terminal.
unsafe fn print_block_split_points(litlens: *const u16,
                                   dists: *const u16,
                                   llsize: usize,
                                   lz77splitpoints: &Vec<usize>) {
    let mut splitpoints: Vec<usize> = Vec::new();

    // The input is given as lz77 indices, but we want to see the uncompressed
    // index values.
    let mut pos: usize = 0;
    if lz77splitpoints.len() > 0 {
        for i in 0..llsize {
            let length: usize = if *dists.offset(i as isize) == 0 { 1 } else { *litlens.offset(i as isize) as usize };
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == lz77splitpoints.len() {
                    break;
                }
            }
            pos += length;
        }
    }
    assert_eq!(splitpoints.len(), lz77splitpoints.len());

    print_err!("block split points: ");
    for i in 0..splitpoints.len() {
        print_err!("{} ", splitpoints[i] as i32);
    }
    print_err!("(hex:");
    for i in 0..splitpoints.len() {
        print_err!(" {:x}", splitpoints[i] as i32);
    }
    println_err!(")");
}

/// Finds next block to try to split, the largest of the available ones.
/// The largest is chosen to make sure that if only a limited amount of blocks is
/// requested, their sizes are spread evenly.
/// llsize: the size of the LL77 data, which is the size of the done array here.
/// done: array indicating which blocks starting at that position are no longer
///     splittable (splitting them increases rather than decreases cost).
/// splitpoints: the splitpoints found so far.
/// npoints: the amount of splitpoints found so far.
/// lstart: output variable, giving start of block.
/// lend: output variable, giving end of block.
/// returns 1 if a block was found, 0 if no block found (all are done).
unsafe fn find_largest_splittable_block(llsize: usize,
                                        done: *const u8,
                                        splitpoints: &Vec<usize>,
                                        lstart: *mut usize,
                                        lend: *mut usize)
                                        -> bool {
    let mut longest: usize = 0;
    let mut found = false;
    for i in 0..splitpoints.len()+1 {
        let start: usize = if i == 0 { 0 } else { splitpoints[i - 1] };
        let end: usize = if i == splitpoints.len() { llsize - 1 } else { splitpoints[i] };
        if *done.offset(start as isize) == 0 && end - start > longest {
            *lstart = start;
            *lend = end;
            found = true;
            longest = end - start;
        }
    }
    found
}

/// Does blocksplitting on LZ77 data.
/// The output splitpoints are indices in the LZ77 data.
/// litlens: lz77 lit/lengths
/// dists: lz77 distances
/// llsize: size of litlens and dists
/// maxblocks: set a limit to the amount of blocks. Set to 0 to mean no limit.
pub unsafe fn block_split_lz77(options: *const Options,
                               litlens: *const u16,
                               dists: *const u16,
                               llsize: usize,
                               maxblocks: usize,
                               splitpoints: &mut Vec<usize>) {
    if llsize < 10 {
        // This code fails on tiny files.
        return;
    }

    let done: *mut u8 = transmute(malloc(llsize as size_t));
    if done.is_null() {
        panic!("Allocation failed!");
    }
    for i in 0..llsize {
        *done.offset(i as isize) = 0;
    }

    let mut lstart: usize = 0;
    let mut lend: usize = llsize;
    let mut numblocks: usize = 1;
    loop {
        if maxblocks > 0 && numblocks >= maxblocks {
            break;
        }

        let c = SplitCostContext {
            litlens: litlens,
            dists: dists,
            _llsize: llsize,
            start: lstart,
            end: lend,
        };
        assert!(lstart < lend);
        let llpos: usize = find_minimum(|i| split_cost(i, &c), lstart + 1, lend);

        assert!(llpos > lstart);
        assert!(llpos < lend);

        let splitcost: f64 = estimate_cost(litlens, dists, lstart, llpos) +
                             estimate_cost(litlens, dists, llpos, lend);
        let origcost: f64 = estimate_cost(litlens, dists, lstart, lend);

        if splitcost > origcost || llpos == lstart + 1 || llpos == lend {
            *done.offset(lstart as isize) = 1;
        } else {
            add_sorted(llpos, splitpoints);
            numblocks += 1;
        }

        if !find_largest_splittable_block(llsize, done, splitpoints, &mut lstart, &mut lend) {
            // No further split will probably reduce compression.
            break;
        }

        if lend - lstart < 10 {
            break;
        }
    }

    if (*options).verbose {
        print_block_split_points(litlens, dists, llsize, splitpoints);
    }

    free(transmute(done));
}

/**
 * Does blocksplitting on uncompressed data.
 * The output splitpoints are indices in the uncompressed bytes.
 *
 * options: general program options.
 * in: uncompressed input data
 * instart: where to start splitting
 * inend: where to end splitting (not inclusive)
 * maxblocks: maximum amount of blocks to split into, or 0 for no limit
 * splitpoints: dynamic array to put the resulting split point coordinates into.
 *   The coordinates are indices in the input array.
 * npoints: pointer to amount of splitpoints, for the dynamic array. The amount of
 *   blocks is the amount of splitpoitns + 1.
 */
pub unsafe fn block_split(options: *const Options,
                          in_: &[u8],
                          instart: usize,
                          inend: usize,
                          maxblocks: usize,
                          splitpoints: &mut Vec<usize>) {
    let s = BlockState::new(options, instart, inend, null_mut());
    let mut lz77splitpoints: Vec<usize> = Vec::new();
    let mut store = LZ77Store::new();

    splitpoints.clear();

    // Unintuitively, Using a simple LZ77 method here instead of ZopfliLZ77Optimal
    // results in better blocks.
    lz77_greedy(&s, in_, instart, inend, &mut store);

    block_split_lz77(options,
                     store.litlens,
                     store.dists,
                     store.size,
                     maxblocks,
                     &mut lz77splitpoints);

    // Convert LZ77 positions to positions in the uncompressed input.
    let mut pos: usize = instart;
    if lz77splitpoints.len() > 0 {
        for i in 0..store.size {
            let length: usize = if *store.dists.offset(i as isize) == 0 { 1 } else { *store.litlens.offset(i as isize) as usize };
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == lz77splitpoints.len() {
                    break;
                }
            }
            pos += length;
        }
    }
    assert_eq!(splitpoints.len(), lz77splitpoints.len());

    clean_lz77_store(&mut store);
}

/// Divides the input into equal blocks, does not even take LZ77 lengths into
/// account.
pub unsafe fn block_split_simple(_in: &[u8],
                                 instart: usize,
                                 inend: usize,
                                 blocksize: usize,
                                 splitpoints: &mut Vec<usize>) {
    let mut i: usize = instart;
    while i < inend {
        splitpoints.push(i);
        i += blocksize;
    }
}
<commit_msg>Use Vec instead of malloc in block_split_lz77<commit_after>//! Functions to choose good boundaries for block splitting. Deflate allows
//! encoding the data in multiple blocks, with a separate Huffman tree for each
//! block. The Huffman tree itself requires some bytes to encode, so by
//! choosing certain blocks, you can either hurt, or enhance compression. These
//! functions choose good ones that enhance it.

use std::io::Write;
use std::iter;
use std::mem::uninitialized;
use std::ptr::null_mut;

use super::Options;

use deflate::calculate_block_size;
use lz77::{BlockState, LZ77Store, clean_lz77_store, lz77_greedy};
use util;

/// Finds minimum of function f(i) where is is of type size_t, f(i) is of type
/// double, i is in range start-end (excluding end).
unsafe fn find_minimum<F>(f: F, start: usize, end: usize) -> usize
    where F: Fn(usize) -> f64
{

    if end - start < 1024 {
        let mut best: f64 = util::LARGE_FLOAT;
        let mut result = start;
        for i in start..end {
            let v = f(i);
            if v < best {
                best = v;
                result = i;
            }
        }
        result
    } else {
        // Try to find minimum faster by recursively checking multiple points.

        // Good value: 9.
        const NUM: usize = 9;

        let mut p: [usize; NUM] = uninitialized();
        let mut vp: [f64; NUM] = uninitialized();
        let mut lastbest: f64 = util::LARGE_FLOAT;
        let mut pos = start;

        let mut start = start;
        let mut end = end;
        loop {
            if end - start <= NUM {
                break;
            }

            for i in 0..NUM {
                p[i] = start + (i + 1) * ((end - start) / (NUM + 1));
                vp[i] = f(p[i]);
            }
            let mut besti: usize = 0;
            let mut best: f64 = vp[0];
            for i in 1..NUM {
                if vp[i] < best {
                    best = vp[i];
                    besti = i;
                }
            }
            if best > lastbest {
                break;
            }

            start = if besti == 0 { start } else { p[besti - 1] };
            end = if besti == NUM - 1 { end } else { p[besti + 1] };

            pos = p[besti];
            lastbest = best;
        }
        pos
    }
}

/**
 * Returns estimated cost of a block in bits.  It includes the size to encode the
 * tree and the size to encode all literal, length and distance symbols and their
 * extra bits.
 *
 * litlens: lz77 lit/lengths
 * dists: ll77 distances
 * lstart: start of block
 * lend: end of block (not inclusive)
 */
unsafe fn estimate_cost(litlens: *const u16, dists: *const u16, lstart: usize, lend: usize) -> f64 {
    calculate_block_size(litlens, dists, lstart, lend, 2)
}

struct SplitCostContext {
    litlens: *const u16,
    dists: *const u16,
    _llsize: usize,
    start: usize,
    end: usize,
}

/// Gets the cost which is the sum of the cost of the left and the right section
/// of the data.
/// type: FindMinimumFun
unsafe fn split_cost(i: usize, c: &SplitCostContext) -> f64 {
    estimate_cost(c.litlens, c.dists, c.start, i) + estimate_cost(c.litlens, c.dists, i, c.end)
}

unsafe fn add_sorted(value: usize, out: &mut Vec<usize>) {
    out.push(value);
    let mut i: usize = 0;
    while i + 1 < out.len() {
        if out[i] > value {
            let mut j: usize = out.len() - 1;
            while j > i {
                out[j] = out[j - 1];
                j -= 1;
            }
            out[i] = value;
            break;
        }
        i += 1;
    }
}

/// Prints the block split points as decimal and hex values in the terminal.
unsafe fn print_block_split_points(litlens: *const u16,
                                   dists: *const u16,
                                   llsize: usize,
                                   lz77splitpoints: &Vec<usize>) {
    let mut splitpoints: Vec<usize> = Vec::new();

    // The input is given as lz77 indices, but we want to see the uncompressed
    // index values.
    let mut pos: usize = 0;
    if lz77splitpoints.len() > 0 {
        for i in 0..llsize {
            let length: usize = if *dists.offset(i as isize) == 0 { 1 } else { *litlens.offset(i as isize) as usize };
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == lz77splitpoints.len() {
                    break;
                }
            }
            pos += length;
        }
    }
    assert_eq!(splitpoints.len(), lz77splitpoints.len());

    print_err!("block split points: ");
    for i in 0..splitpoints.len() {
        print_err!("{} ", splitpoints[i] as i32);
    }
    print_err!("(hex:");
    for i in 0..splitpoints.len() {
        print_err!(" {:x}", splitpoints[i] as i32);
    }
    println_err!(")");
}

/// Finds next block to try to split, the largest of the available ones.
/// The largest is chosen to make sure that if only a limited amount of blocks is
/// requested, their sizes are spread evenly.
/// llsize: the size of the LL77 data, which is the size of the done array here.
/// done: array indicating which blocks starting at that position are no longer
///     splittable (splitting them increases rather than decreases cost).
/// splitpoints: the splitpoints found so far.
/// npoints: the amount of splitpoints found so far.
/// lstart: output variable, giving start of block.
/// lend: output variable, giving end of block.
/// returns 1 if a block was found, 0 if no block found (all are done).
unsafe fn find_largest_splittable_block(llsize: usize,
                                        done: &Vec<u8>,
                                        splitpoints: &Vec<usize>,
                                        lstart: *mut usize,
                                        lend: *mut usize)
                                        -> bool {
    assert_eq!(llsize, done.len());
    let mut longest: usize = 0;
    let mut found = false;
    for i in 0..splitpoints.len()+1 {
        let start: usize = if i == 0 { 0 } else { splitpoints[i - 1] };
        let end: usize = if i == splitpoints.len() { llsize - 1 } else { splitpoints[i] };
        if done[start] == 0 && end - start > longest {
            *lstart = start;
            *lend = end;
            found = true;
            longest = end - start;
        }
    }
    found
}

/// Does blocksplitting on LZ77 data.
/// The output splitpoints are indices in the LZ77 data.
/// litlens: lz77 lit/lengths
/// dists: lz77 distances
/// llsize: size of litlens and dists
/// maxblocks: set a limit to the amount of blocks. Set to 0 to mean no limit.
pub unsafe fn block_split_lz77(options: *const Options,
                               litlens: *const u16,
                               dists: *const u16,
                               llsize: usize,
                               maxblocks: usize,
                               splitpoints: &mut Vec<usize>) {
    if llsize < 10 {
        // This code fails on tiny files.
        return;
    }

    let mut done: Vec<u8> = iter::repeat(0).take(llsize).collect();

    let mut lstart: usize = 0;
    let mut lend: usize = llsize;
    let mut numblocks: usize = 1;
    loop {
        if maxblocks > 0 && numblocks >= maxblocks {
            break;
        }

        let c = SplitCostContext {
            litlens: litlens,
            dists: dists,
            _llsize: llsize,
            start: lstart,
            end: lend,
        };
        assert!(lstart < lend);
        let llpos: usize = find_minimum(|i| split_cost(i, &c), lstart + 1, lend);

        assert!(llpos > lstart);
        assert!(llpos < lend);

        let splitcost: f64 = estimate_cost(litlens, dists, lstart, llpos) +
                             estimate_cost(litlens, dists, llpos, lend);
        let origcost: f64 = estimate_cost(litlens, dists, lstart, lend);

        if splitcost > origcost || llpos == lstart + 1 || llpos == lend {
            done[lstart] = 1;
        } else {
            add_sorted(llpos, splitpoints);
            numblocks += 1;
        }

        if !find_largest_splittable_block(llsize, &done, splitpoints, &mut lstart, &mut lend) {
            // No further split will probably reduce compression.
            break;
        }

        if lend - lstart < 10 {
            break;
        }
    }

    if (*options).verbose {
        print_block_split_points(litlens, dists, llsize, splitpoints);
    }
}

/**
 * Does blocksplitting on uncompressed data.
 * The output splitpoints are indices in the uncompressed bytes.
 *
 * options: general program options.
 * in: uncompressed input data
 * instart: where to start splitting
 * inend: where to end splitting (not inclusive)
 * maxblocks: maximum amount of blocks to split into, or 0 for no limit
 * splitpoints: dynamic array to put the resulting split point coordinates into.
 *   The coordinates are indices in the input array.
 * npoints: pointer to amount of splitpoints, for the dynamic array. The amount of
 *   blocks is the amount of splitpoitns + 1.
 */
pub unsafe fn block_split(options: *const Options,
                          in_: &[u8],
                          instart: usize,
                          inend: usize,
                          maxblocks: usize,
                          splitpoints: &mut Vec<usize>) {
    let s = BlockState::new(options, instart, inend, null_mut());
    let mut lz77splitpoints: Vec<usize> = Vec::new();
    let mut store = LZ77Store::new();

    splitpoints.clear();

    // Unintuitively, Using a simple LZ77 method here instead of ZopfliLZ77Optimal
    // results in better blocks.
    lz77_greedy(&s, in_, instart, inend, &mut store);

    block_split_lz77(options,
                     store.litlens,
                     store.dists,
                     store.size,
                     maxblocks,
                     &mut lz77splitpoints);

    // Convert LZ77 positions to positions in the uncompressed input.
    let mut pos: usize = instart;
    if lz77splitpoints.len() > 0 {
        for i in 0..store.size {
            let length: usize = if *store.dists.offset(i as isize) == 0 { 1 } else { *store.litlens.offset(i as isize) as usize };
            if lz77splitpoints[splitpoints.len()] == i {
                splitpoints.push(pos);
                if splitpoints.len() == lz77splitpoints.len() {
                    break;
                }
            }
            pos += length;
        }
    }
    assert_eq!(splitpoints.len(), lz77splitpoints.len());

    clean_lz77_store(&mut store);
}

/// Divides the input into equal blocks, does not even take LZ77 lengths into
/// account.
pub unsafe fn block_split_simple(_in: &[u8],
                                 instart: usize,
                                 inend: usize,
                                 blocksize: usize,
                                 splitpoints: &mut Vec<usize>) {
    let mut i: usize = instart;
    while i < inend {
        splitpoints.push(i);
        i += blocksize;
    }
}
<|endoftext|>


<commit_before>use constants::{CLI_DEFAULT_CONFIG_SUBC_NAME};

use clap::{App,Arg,SubCommand};

pub fn cli<'a, 'b>() -> App<'a, 'b> {
    // FIXME: populate about with this
    // let ref def_conf_desc = format!("Create default config at \"{}\".", get_default_config_path().to_str().unwrap());
    App::new("pretty-zsh-prompt")
        .version("0.0.1")
        .author("Tomas Tomecek <tomas@tomecek.net>")
        .about("Get `git status` inside your shell prompt.")
        .subcommand(SubCommand::with_name(CLI_DEFAULT_CONFIG_SUBC_NAME))
        .arg(Arg::with_name("config")
             .short("c")
             .long("config")
             .value_name("FILE")
             .help("Use the given config file.")
             .takes_value(true))
        .arg(Arg::with_name("debug")
             .short("d")
             .long("debug")
             .help("Print debug messages, useful for identifying issues."))
}
<commit_msg>make version match Cargo.toml<commit_after>use constants::{CLI_DEFAULT_CONFIG_SUBC_NAME};

use clap::{App,Arg,SubCommand};

pub fn cli<'a, 'b>() -> App<'a, 'b> {
    // FIXME: populate about with this
    // let ref def_conf_desc = format!("Create default config at \"{}\".", get_default_config_path().to_str().unwrap());
    App::new("pretty-zsh-prompt")
        .version("0.1.0")
        .author("Tomas Tomecek <tomas@tomecek.net>")
        .about("Get `git status` inside your shell prompt.")
        .subcommand(SubCommand::with_name(CLI_DEFAULT_CONFIG_SUBC_NAME))
        .arg(Arg::with_name("config")
             .short("c")
             .long("config")
             .value_name("FILE")
             .help("Use the given config file.")
             .takes_value(true))
        .arg(Arg::with_name("debug")
             .short("d")
             .long("debug")
             .help("Print debug messages, useful for identifying issues."))
}
<|endoftext|>


<commit_before>use clap::{App, ArgMatches};
use std::path::{PathBuf};

use dir;
use error::{ToResult};

extern crate env_logger;

#[derive(Debug)]
pub struct Request {
    pub name: String,
    pub directory: PathBuf,
    pub action: Action,
}

impl Request {
    fn new(action: Action) -> Request {
        Request {
            name: String::from("foo"),
            directory: PathBuf::from("bar"),
            action: action,
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum Action {
    Get,
    Put,
    Delete,
    List,
    Last,
    ChangeDirectory,
}

pub fn get_request() -> ToResult<Request> {
    let yaml = load_yaml!("cli.yml");
    let app = App::from_yaml(yaml);
    let matches = app.get_matches();

    return get(matches);
}

pub fn get(matches: ArgMatches) -> ToResult<Request> {
    info!("building request from clap::{:?}", matches);

    let pathname = match matches.value_of("directory") {
        Some(value) => value,
        None => "",
    };

    let directory = try!(dir::resolve(pathname));

    let request = Request::new(Action::ChangeDirectory);
    return Ok(request);
}

#[cfg(test)]
mod tests {
    extern crate env_logger;
    extern crate clap;

    use super::*;
    use std::path::{PathBuf};

    fn run(mut args: Vec<&str>) -> Request {
        let logger_result = env_logger::init();
        assert!(logger_result.is_ok());

        args.insert(0, "to");

        let yaml = load_yaml!("cli.yml");
        let app = clap::App::from_yaml(yaml);
        let matches = app.get_matches_from(args);

        let result = get(matches);
        assert!(result.is_ok());

        return result.unwrap();
    }

    #[test]
    fn basic() {
        let result = get_request();
        assert!(result.is_ok());
    }

    #[test]
    fn to_name() -> () {
        let args = vec!["foo"];
        let request = run(args);

        assert_eq!(request.action, Action::ChangeDirectory);
        assert_eq!(request.name, "foo");
        assert_eq!(request.directory, PathBuf::from("bar"));
    }
}
<commit_msg>cli now uses dir::resolve<commit_after>use clap::{App, ArgMatches};
use std::path::{PathBuf};

use dir;
use error::{ToResult};

extern crate env_logger;

#[derive(Debug)]
pub struct Request {
    pub name: String,
    pub directory: PathBuf,
    pub action: Action,
}

impl Request {
    fn new(name: &str, directory: PathBuf, action: Action) -> Request {
        Request {
            name: String::from(name),
            directory: directory,
            action: action,
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum Action {
    Get,
    Put,
    Delete,
    List,
    Last,
    ChangeDirectory,
}

pub fn get_request() -> ToResult<Request> {
    let yaml = load_yaml!("cli.yml");
    let app = App::from_yaml(yaml);
    let matches = app.get_matches();

    return get(matches);
}

pub fn get(matches: ArgMatches) -> ToResult<Request> {
    info!("building request from clap::{:?}", matches);

    let pathname = match matches.value_of("directory") {
        Some(value) => value,
        None => "",
    };

    let directory = try!(dir::resolve(pathname));

    let request = Request::new("foo", directory, Action::ChangeDirectory);

    return Ok(request);
}

#[cfg(test)]
mod tests {
    extern crate env_logger;
    extern crate clap;

    use super::*;
    use std::env;
    use std::path::{PathBuf};

    fn run(mut args: Vec<&str>) -> Request {
        // Logger might fail if it is already initialized.
        // let logger_result = env_logger::init();
        // assert!(logger_result.is_ok());
        let _ = env_logger::init();

        args.insert(0, "to");

        let yaml = load_yaml!("cli.yml");
        let app = clap::App::from_yaml(yaml);
        let matches = app.get_matches_from(args);

        let request = get(matches).expect("should not fail");
        return request;
    }

    #[test]
    fn basic() {
        let result = get_request();
        assert!(result.is_ok());
    }

    #[test]
    fn to_name() {
        let cwd = env::current_dir().expect("should not fail");
        let args = vec!["foo"];
        let request = run(args);

        assert_eq!(request.action, Action::ChangeDirectory);
        assert_eq!(request.name, "foo");
        assert_eq!(request.directory, cwd);
    }
}
<|endoftext|>