<commit_before>extern crate hex;
use hex::FromHex as VecFromHex;
use cryptography::crypto_box;

pub const PUBLIC_KEY_BYTES: usize = crypto_box::PUBLICKEYBYTES;
pub const SECRET_KEY_BYTES: usize = crypto_box::SECRETKEYBYTES;

/// Used to decode a CryptoAuth public key.
///
/// # Example
///
/// ```
/// use fcp_cryptoauth::cryptography::crypto_box::PublicKey;
/// use fcp_cryptoauth::keys::FromBase32;
/// let pk = PublicKey::from_base32(b"2wrpv8p4tjwm532sjxcbqzkp7kdwfwzzbg7g0n5l6g3s8df4kvv0.k");
/// assert!(pk.is_some());
/// ```
pub trait FromBase32: Sized {
    // decode a base32-encoded byte array into an other byte array
    // Returns Err(c) if a character c is not valid in a Base32 string.
    fn from_base32(characters: &[u8]) -> Option<Self>;
}

/// Used to decode a CryptoAuth secret key.
///
/// # Example
///
/// ```
/// use fcp_cryptoauth::cryptography::crypto_box::SecretKey;
/// use fcp_cryptoauth::keys::FromHex;
/// let sk = SecretKey::from_hex(b"ac3e53b518e68449692b0b2f2926ef2fdc1eac5b9dbd10a48114263b8c8ed12e");
/// assert!(sk.is_some());
/// ```
pub trait FromHex: Sized {
    fn from_hex(characters: &[u8]) -> Option<Self>;
}

// DNSCurve's Base32 decoding table
const BASE32_DECODING_TABLE: [u8; 128] = [
        99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
        99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
        99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
         0, 1, 2, 3, 4, 5, 6, 7, 8, 9,99,99,99,99,99,99,
        99,99,10,11,12,99,13,14,15,99,16,17,18,19,20,99,
        21,22,23,24,25,26,27,28,29,30,31,99,99,99,99,99,
        99,99,10,11,12,99,13,14,15,99,16,17,18,19,20,99,
        21,22,23,24,25,26,27,28,29,30,31,99,99,99,99,99
        ];
pub fn decode_base32(encoded: &[u8]) -> Result<Vec<u8>, u8> {
    let mut res = Vec::with_capacity(encoded.len()*5/8);
    let mut last_word_length = 0;
    let mut last_word = 0u16;
    for c in encoded.iter() {
        let c = c.clone();
        if c >= 128 {
            return Err(c);
        }
        let bits = BASE32_DECODING_TABLE[c as usize];
        if bits == 99 {
            return Err(c);
        }

        // Add the new bits at the left of the current word
        last_word += (bits as u16) << last_word_length;
        last_word_length += 5;

        // If the right byte of the current word is full, push the on the vector
        // and shift the current word to remove the right byte.
        if last_word_length >= 8 {
            last_word_length -= 8;
            res.push((last_word & 0b11111111) as u8);
            last_word >>= 8;
        }
    }
    if last_word > 0 {
        res.push(last_word as u8);
    }
    Ok(res)
}

#[test]
fn test_decode_base32() {
    assert_eq!(decode_base32(b"4321"), Ok(vec![0x64, 0x88]));
    decode_base32(b"2j1xz5k5y1xwz7kcczc4565jurhp8bbz1lqfu9kljw36p3nmb050").unwrap();
}

impl FromBase32 for crypto_box::PublicKey {
    /// Returns a Public key from its Base32 representation.
    ///
    /// TODO: better errors
    fn from_base32(characters: &[u8]) -> Option<crypto_box::PublicKey> {
        assert!(characters.len() >= 2);
        let length: usize = characters.len()-2;
        assert_eq!(characters[length..], b".k".to_owned());
        if let Ok(bytes) = decode_base32(&characters[..length]) {
            crypto_box::PublicKey::from_slice(&bytes)
        }
        else {
            None
        }
    }
}

impl FromHex for crypto_box::SecretKey {
    fn from_hex(characters: &[u8]) -> Option<crypto_box::SecretKey> {
        let res = Vec::from_hex(characters);
        match res {
            Ok(vec) => {
                if vec.len() == 32 {
                    let mut bytes = [0u8; 32];
                    bytes.copy_from_slice(&vec);
                    crypto_box::SecretKey::from_slice(&bytes)
                }
                else {
                    None
                }
            },
            Err(_) => None,
        }
    }
}
<commit_msg>Add Base32 encoder.<commit_after>extern crate hex;
use hex::FromHex as VecFromHex;
use cryptography::crypto_box;

pub const PUBLIC_KEY_BYTES: usize = crypto_box::PUBLICKEYBYTES;
pub const SECRET_KEY_BYTES: usize = crypto_box::SECRETKEYBYTES;

/// Used to decode a CryptoAuth public key.
///
/// # Example
///
/// ```
/// use fcp_cryptoauth::cryptography::crypto_box::PublicKey;
/// use fcp_cryptoauth::keys::FromBase32;
/// let pk = PublicKey::from_base32(b"2wrpv8p4tjwm532sjxcbqzkp7kdwfwzzbg7g0n5l6g3s8df4kvv0.k");
/// assert!(pk.is_some());
/// ```
pub trait FromBase32: Sized {
    // decode a base32-encoded byte array into an other byte array
    // Returns Err(c) if a character c is not valid in a Base32 string.
    fn from_base32(characters: &[u8]) -> Option<Self>;
}

/// Used to encode a CryptoAuth public key.
///
/// # Example
///
/// ```
/// use fcp_cryptoauth::cryptography::crypto_box::PublicKey;
/// use fcp_cryptoauth::keys::FromBase32;
/// use fcp_cryptoauth::keys::ToBase32;
/// let representation = b"2wrpv8p4tjwm532sjxcbqzkp7kdwfwzzbg7g0n5l6g3s8df4kvv0.k";
/// let pk = PublicKey::from_base32(representation).unwrap();
/// assert_eq!(pk.to_base32(), representation.to_vec());
/// ```
pub trait ToBase32: Sized {
    // encode a byte array into an other base32-encoded byte array
    fn to_base32(&self) -> Vec<u8>;
}

/// Used to decode a CryptoAuth secret key.
///
/// # Example
///
/// ```
/// use fcp_cryptoauth::cryptography::crypto_box::SecretKey;
/// use fcp_cryptoauth::keys::FromHex;
/// let sk = SecretKey::from_hex(b"ac3e53b518e68449692b0b2f2926ef2fdc1eac5b9dbd10a48114263b8c8ed12e");
/// assert!(sk.is_some());
/// ```
pub trait FromHex: Sized {
    fn from_hex(characters: &[u8]) -> Option<Self>;
}

// DNSCurve's Base32 decoding table
const BASE32_DECODING_TABLE: [u8; 128] = [
        99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
        99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
        99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,
         0, 1, 2, 3, 4, 5, 6, 7, 8, 9,99,99,99,99,99,99,
        99,99,10,11,12,99,13,14,15,99,16,17,18,19,20,99,
        21,22,23,24,25,26,27,28,29,30,31,99,99,99,99,99,
        99,99,10,11,12,99,13,14,15,99,16,17,18,19,20,99,
        21,22,23,24,25,26,27,28,29,30,31,99,99,99,99,99
        ];
pub fn decode_base32(encoded: &[u8]) -> Result<Vec<u8>, u8> {
    let mut res = Vec::with_capacity(encoded.len()*5/8);
    let mut last_word_length = 0;
    let mut last_word = 0u16;
    for c in encoded.iter() {
        let c = c.clone();
        if c >= 128 {
            return Err(c);
        }
        let bits = BASE32_DECODING_TABLE[c as usize];
        if bits == 99 {
            return Err(c);
        }

        // Add the new bits at the left of the current word
        last_word += (bits as u16) << last_word_length;
        last_word_length += 5;

        // If the right byte of the current word is full, push the on the vector
        // and shift the current word to remove the right byte.
        if last_word_length >= 8 {
            last_word_length -= 8;
            res.push((last_word & 0b11111111) as u8);
            last_word >>= 8;
        }
    }
    if last_word > 0 {
        res.push(last_word as u8);
    }
    Ok(res)
}

#[test]
fn test_decode_base32() {
    assert_eq!(decode_base32(b"4321"), Ok(vec![0x64, 0x88]));
    decode_base32(b"2j1xz5k5y1xwz7kcczc4565jurhp8bbz1lqfu9kljw36p3nmb050").unwrap();
}

impl FromBase32 for crypto_box::PublicKey {
    /// Returns a Public key from its Base32 representation.
    ///
    /// TODO: better errors
    fn from_base32(characters: &[u8]) -> Option<crypto_box::PublicKey> {
        assert!(characters.len() >= 2);
        let length: usize = characters.len()-2;
        assert_eq!(characters[length..], b".k".to_owned());
        if let Ok(bytes) = decode_base32(&characters[..length]) {
            crypto_box::PublicKey::from_slice(&bytes)
        }
        else {
            None
        }
    }
}

const BASE32_ENCODING_TABLE: [u8; 32] = [
        '0' as u8, '1' as u8, '2' as u8, '3' as u8, '4' as u8,
        '5' as u8, '6' as u8, '7' as u8, '8' as u8, '9' as u8,
        'b' as u8, 'c' as u8, 'd' as u8, 'f' as u8, 'g' as u8,
        'h' as u8, 'j' as u8, 'k' as u8, 'l' as u8, 'm' as u8,
        'n' as u8, 'p' as u8, 'q' as u8, 'r' as u8, 's' as u8,
        't' as u8, 'u' as u8, 'v' as u8, 'w' as u8, 'x' as u8,
        'y' as u8, 'z' as u8];
pub fn encode_base32(bytes: &[u8]) -> Vec<u8> {
    let mut encoded: Vec<u8> = Vec::new();
    encoded.reserve(bytes.len()*8/5);
    let mut window = 0u16;
    let mut bits_in_window = 0;
    let mut bytes_offset = 0;
    assert!(BASE32_ENCODING_TABLE.len() == 32);
    while bytes_offset < bytes.len() || window > 0 {
        if bits_in_window < 5 {
            let byte = *bytes.get(bytes_offset).unwrap_or(&0);
            bytes_offset += 1;
            window += (byte as u16) << bits_in_window;
            bits_in_window += 8;
        }
        let char_index = (window & 0b11111) as usize;
        window >>= 5;
        bits_in_window -= 5;
        encoded.push(BASE32_ENCODING_TABLE[char_index]);
    }
    encoded
}

#[test]
fn test_encode_decode_base32() {
    let key = b"2j1xz5k5y1xwz7kcczc4565jurhp8bbz1lqfu9kljw36p3nmb050";
    let expected = "2j1xz5k5y1xwz7kcczc4565jurhp8bbz1lqfu9kljw36p3nmb05";
    assert_eq!(String::from_utf8(encode_base32(&decode_base32(key).unwrap())).unwrap(), expected)
}

#[test]
fn test_encode_base32() {
    assert_eq!(String::from_utf8(encode_base32(&vec![0x64, 0x88])).unwrap(), "4321");
}

impl ToBase32 for crypto_box::PublicKey {
    /// Returns the Base32 representation of a Public key
    ///
    /// TODO: better errors
    fn to_base32(&self) -> Vec<u8> {
        let mut repr = encode_base32(&self.0);
        assert!(repr.len() <= 52);
        repr.resize(52, '0' as u8);
        repr.push('.' as u8);
        repr.push('k' as u8);
        repr
    }
}

impl FromHex for crypto_box::SecretKey {
    fn from_hex(characters: &[u8]) -> Option<crypto_box::SecretKey> {
        let res = Vec::from_hex(characters);
        match res {
            Ok(vec) => {
                if vec.len() == 32 {
                    let mut bytes = [0u8; 32];
                    bytes.copy_from_slice(&vec);
                    crypto_box::SecretKey::from_slice(&bytes)
                }
                else {
                    None
                }
            },
            Err(_) => None,
        }
    }
}
<|endoftext|>


<commit_before>//! Contains information for keybindings.

use std::collections::{HashMap, HashSet};
use std::sync::{Arc, RwLock};
use rustwlc::xkb::{Keysym, NameFlags};
use rustwlc::types::*; // Need * for bitflags...
use std::hash::{Hash, Hasher};

lazy_static! {
    static ref BINDINGS: RwLock<HashMap<KeyPress, KeyEvent>> = {
        let mut map = HashMap::<KeyPress, KeyEvent>::new();

        let press_s = KeyPress::from_key_names(vec!["Mod4"], vec!["s"]).unwrap();
        map.insert(press_s, Arc::new(Box::new(key_s)));

        let press_f4 = KeyPress::from_key_names(vec!["Alt"], vec!["F4"]).unwrap();
        map.insert(press_f4, Arc::new(Box::new(key_f4)));

        let press_l = KeyPress::from_key_names(vec!["Ctrl"], vec!["l"]).unwrap();
        map.insert(press_l, Arc::new(Box::new(key_lua)));

        RwLock::new(map)
    };
}

fn key_s() {
    info!("[Key handler] S keypress!");
}

fn key_f4() {
    info!("[Key handler] F4 keypress!");
}

fn key_lua() {
    use super::lua;
    use lua::LuaQuery;
    info!("[Key handler] ctrl+l keypress!");
    lua::send(LuaQuery::Execute("print('Hello world from lua keypress!')".to_string()));
}

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct KeyPress {
    modifiers: KeyMod,
    keys: Vec<Keysym>
}

/// Parses a KeyMod from key names.
pub fn keymod_from_names(keys: Vec<&str>) -> Result<KeyMod, String> {
    let mut result = KeyMod::empty();
    for key in keys {
        match key.to_lowercase().as_str() {
            "shift"            => result = result | MOD_SHIFT,
            "control" | "ctrl" => result = result | MOD_CTRL,
            "alt"              => result = result | MOD_ALT,
            "mod2"             => result = result | MOD_MOD2,
            "mod3"             => result = result | MOD_MOD3,
            "mod4" | "super" | "logo" => result = result | MOD_MOD4,
            "mod5" | "5mod5me" => result = result | MOD_MOD5,
            err => return Err(format!("Invalid modifier: {}", err))
        }
    }
    return Ok(result);
}

impl KeyPress {
    /// Creates a new KeyPress struct from a list of modifier and key names
    pub fn from_key_names(mods: Vec<&str>, keys: Vec<&str>) -> Result<KeyPress, String> {
        match keymod_from_names(mods) {
            Err(message) => Err(message),
            Ok(mods) => {
                let mut syms: Vec<Keysym> = Vec::with_capacity(keys.len());
                for name in keys {
                    if let Some(sym) = Keysym::from_name(name.to_string(),
                                                         NameFlags::None) {
                            syms.push(sym);
                    }
                    // Else if could not parse
                    else if let Some(sym) = Keysym::from_name(name.to_string(),
                                                        NameFlags::CaseInsensitive) {
                        syms.push(sym);
                    }
                    else {
                        return Err(format!("Invalid key: {}", name));
                    }
                }
                syms.sort_by_key(|s| s.get_code());
                syms.dedup();
                return Ok(KeyPress { modifiers: mods, keys: syms });
            }
        }
    }

    /// Creates a KeyPress from keys that are pressed at the moment
    pub fn new(mods: KeyMod, mut keys: Vec<Keysym>) -> KeyPress {
        keys.sort_by_key(|k| k.get_code());
        keys.dedup();

        KeyPress { modifiers: mods, keys: keys }
    }
}

impl Hash for KeyPress {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        hasher.write_u32(self.modifiers.bits());
        for ref sym in &self.keys {
            hasher.write_u32(sym.get_code());
        }
    }
}

/// The type of function a key press handler is.
pub type KeyEvent = Arc<Box<Fn() + Send + Sync>>;

/// Get a key mapping from the list.
pub fn get(key: &KeyPress) -> Option<KeyEvent> {
    let bindings = BINDINGS.read().unwrap();
    match bindings.get(key) {
        None => None,
        Some(val) => Some(val.clone())
    }
}

/// Register a new key mapping
pub fn register(values: Vec<(KeyPress, KeyEvent)>) {
    let mut bindings = BINDINGS.write().unwrap();
    for value in values {
        bindings.insert(value.0, value.1);
    }
}
<commit_msg>Added lua sleep key for debugging lua thread state<commit_after>//! Contains information for keybindings.

use std::collections::{HashMap, HashSet};
use std::sync::{Arc, RwLock};
use rustwlc::xkb::{Keysym, NameFlags};
use rustwlc::types::*; // Need * for bitflags...
use std::hash::{Hash, Hasher};

lazy_static! {
    static ref BINDINGS: RwLock<HashMap<KeyPress, KeyEvent>> = {
        let mut map = HashMap::<KeyPress, KeyEvent>::new();

        let press_s = KeyPress::from_key_names(vec!["Mod4"], vec!["s"]).unwrap();
        map.insert(press_s, Arc::new(Box::new(key_s)));

        let press_f4 = KeyPress::from_key_names(vec!["Alt"],vec!["F4"]).unwrap();
        map.insert(press_f4, Arc::new(Box::new(key_f4)));

        let press_l = KeyPress::from_key_names(vec!["Ctrl"], vec!["l"]).unwrap();
        map.insert(press_l, Arc::new(Box::new(key_lua)));

        let press_k = KeyPress::from_key_names(
            vec!["Ctrl"], vec!["k"]).unwrap();
        map.insert(press_k, Arc::new(Box::new(key_sleep)));

        RwLock::new(map)
    };
}

fn key_sleep() {
    use std::thread;
    use std::time::Duration;

    use super::lua;
    use lua::LuaQuery;

    info!("keyhandler: Beginning thread::sleep keypress!");
    lua::send(LuaQuery::Execute("print('>entering sleep')\
                                 os.execute('sleep 5')\
                                 print('>leaving sleep')".to_string()));
    //thread::sleep(Duration::from_secs(5));
    info!("keyhandler: Finished thread::sleep keypress!");
}

fn key_s() {
    info!("[Key handler] S keypress!");
}

fn key_f4() {
    info!("[Key handler] F4 keypress!");
}

fn key_lua() {
    use super::lua;
    use lua::LuaQuery;
    info!("[Key handler] ctrl+l keypress!");
    lua::send(LuaQuery::Execute("print('Hello world from lua keypress!')".to_string()));
}

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct KeyPress {
    modifiers: KeyMod,
    keys: Vec<Keysym>
}

/// Parses a KeyMod from key names.
pub fn keymod_from_names(keys: Vec<&str>) -> Result<KeyMod, String> {
    let mut result = KeyMod::empty();
    for key in keys {
        match key.to_lowercase().as_str() {
            "shift"            => result = result | MOD_SHIFT,
            "control" | "ctrl" => result = result | MOD_CTRL,
            "alt"              => result = result | MOD_ALT,
            "mod2"             => result = result | MOD_MOD2,
            "mod3"             => result = result | MOD_MOD3,
            "mod4" | "super" | "logo" => result = result | MOD_MOD4,
            "mod5" | "5mod5me" => result = result | MOD_MOD5,
            err => return Err(format!("Invalid modifier: {}", err))
        }
    }
    return Ok(result);
}

impl KeyPress {
    /// Creates a new KeyPress struct from a list of modifier and key names
    pub fn from_key_names(mods: Vec<&str>, keys: Vec<&str>) -> Result<KeyPress, String> {
        match keymod_from_names(mods) {
            Err(message) => Err(message),
            Ok(mods) => {
                let mut syms: Vec<Keysym> = Vec::with_capacity(keys.len());
                for name in keys {
                    if let Some(sym) = Keysym::from_name(name.to_string(),
                                                         NameFlags::None) {
                            syms.push(sym);
                    }
                    // Else if could not parse
                    else if let Some(sym) = Keysym::from_name(name.to_string(),
                                                        NameFlags::CaseInsensitive) {
                        syms.push(sym);
                    }
                    else {
                        return Err(format!("Invalid key: {}", name));
                    }
                }
                syms.sort_by_key(|s| s.get_code());
                syms.dedup();
                return Ok(KeyPress { modifiers: mods, keys: syms });
            }
        }
    }

    /// Creates a KeyPress from keys that are pressed at the moment
    pub fn new(mods: KeyMod, mut keys: Vec<Keysym>) -> KeyPress {
        keys.sort_by_key(|k| k.get_code());
        keys.dedup();

        KeyPress { modifiers: mods, keys: keys }
    }
}

impl Hash for KeyPress {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        hasher.write_u32(self.modifiers.bits());
        for ref sym in &self.keys {
            hasher.write_u32(sym.get_code());
        }
    }
}

/// The type of function a key press handler is.
pub type KeyEvent = Arc<Box<Fn() + Send + Sync>>;

/// Get a key mapping from the list.
pub fn get(key: &KeyPress) -> Option<KeyEvent> {
    let bindings = BINDINGS.read().unwrap();
    match bindings.get(key) {
        None => None,
        Some(val) => Some(val.clone())
    }
}

/// Register a new key mapping
pub fn register(values: Vec<(KeyPress, KeyEvent)>) {
    let mut bindings = BINDINGS.write().unwrap();
    for value in values {
        bindings.insert(value.0, value.1);
    }
}
<|endoftext|>


<commit_before>extern crate gtk;

use gtk::{IconSize, Orientation, ReliefStyle};
use gtk::signal::Inhibit;
use gtk::traits::*;

struct NoteBook {
    notebook: gtk::NoteBook,
    tabs: Vec<gtk::Box>
}

impl NoteBook {
    fn new() -> NoteBook {
        NoteBook {
            notebook: gtk::NoteBook::new().unwrap(),
            tabs: Vec::new()
        }
    }

    fn create_tab<'a, Widget: gtk::WidgetTrait>(&mut self, title: &'a str, widget: &Widget) ->
            Option<u32> {
        let close_image = gtk::Image::new_from_icon_name("window-close", IconSize::Button).unwrap();
        let button = gtk::Button::new().unwrap();
        let label = gtk::Label::new(title).unwrap();
        let tab = gtk::Box::new(Orientation::Horizontal, 0).unwrap();

        button.set_relief(ReliefStyle::None);
        button.set_focus_on_click(false);
        button.add(&close_image);

        tab.pack_start(&label, false, false, 0);
        tab.pack_start(&button, false, false, 0);
        tab.show_all();

        let index = match self.notebook.append_page(widget, Some(&tab)) {
            Some(index) => index,
            _ => return None
        };

        let notebook_clone = self.notebook.clone();
        button.connect_clicked(move |_| notebook_clone.remove_page(index as i32));

        self.tabs.push(tab);

        Some(index)
    }
}

fn main() {
    gtk::init();

    let window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();

    window.set_title("Notebook");
    window.set_window_position(gtk::WindowPosition::Center);
    window.set_default_size(640, 480);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    let mut notebook = NoteBook::new();

    for i in 1..4 {
        let title = format!("sheet {}", i);
        let label = gtk::Label::new(&title[..]).unwrap();
        notebook.create_tab(&title[..], &label);
    }

    window.add(&notebook.notebook);
    window.show_all();
    gtk::main();
}

<commit_msg>Use correct tab indexes in signal handler<commit_after>extern crate gtk;

use gtk::{IconSize, Orientation, ReliefStyle};
use gtk::signal::Inhibit;
use gtk::traits::*;

struct NoteBook {
    notebook: gtk::NoteBook,
    tabs: Vec<gtk::Box>
}

impl NoteBook {
    fn new() -> NoteBook {
        NoteBook {
            notebook: gtk::NoteBook::new().unwrap(),
            tabs: Vec::new()
        }
    }

    fn create_tab<'a, Widget>(&mut self, title: &'a str, widget: &Widget) -> Option<u32>
    where Widget: gtk::WidgetTrait + Clone + 'static {
        let close_image = gtk::Image::new_from_icon_name("window-close", IconSize::Button).unwrap();
        let button = gtk::Button::new().unwrap();
        let label = gtk::Label::new(title).unwrap();
        let tab = gtk::Box::new(Orientation::Horizontal, 0).unwrap();

        button.set_relief(ReliefStyle::None);
        button.set_focus_on_click(false);
        button.add(&close_image);

        tab.pack_start(&label, false, false, 0);
        tab.pack_start(&button, false, false, 0);
        tab.show_all();

        let index = match self.notebook.append_page(widget, Some(&tab)) {
            Some(index) => index,
            _ => return None
        };

        let notebook_clone = self.notebook.clone();
        let widget_clone = widget.clone();
        button.connect_clicked(move |_| {
            let index = notebook_clone.page_num(&widget_clone).unwrap();
            notebook_clone.remove_page(index as i32);
        });

        self.tabs.push(tab);

        Some(index)
    }
}

fn main() {
    gtk::init();

    let window = gtk::Window::new(gtk::WindowType::TopLevel).unwrap();

    window.set_title("Notebook");
    window.set_window_position(gtk::WindowPosition::Center);
    window.set_default_size(640, 480);

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(true)
    });

    let mut notebook = NoteBook::new();

    for i in 1..4 {
        let title = format!("sheet {}", i);
        let label = gtk::Label::new(&title[..]).unwrap();
        notebook.create_tab(&title[..], &label);
    }

    window.add(&notebook.notebook);
    window.show_all();
    gtk::main();
}

<|endoftext|>


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

extern crate bldr;
extern crate rustc_serialize;
extern crate docopt;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate ansi_term;
extern crate libc;
use docopt::Docopt;
use std::process;
use ansi_term::Colour::{Red, Green, Yellow};
use libc::funcs::posix88::unistd::execvp;
use std::ffi::CString;
use std::ptr;

use bldr::config::{Command, Config};
use bldr::error::{BldrResult, BldrError};
use bldr::command::*;
use bldr::topology::Topology;

/// The version number
#[allow(dead_code)]
static VERSION: &'static str = "0.0.1";

/// The [docopts](http://burntsushi.net/rustdoc/docopt/index.html) usage
/// string. Determines what options are accepted.
#[allow(dead_code)]
#[cfg_attr(rustfmt, rustfmt_skip)]
static USAGE: &'static str = "
Usage: bldr install <package> -u <url> [-v <version>] [-r <release>]
       bldr start <package> [-u <url>] [--group=<group>] [--topology=<topology>] [--watch=<watch>...]
       bldr sh
       bldr bash
       bldr repo [-p <path>] [--port=<port>]
       bldr upload <package> -u <url> [-v <version>] [-r <release>]
       bldr key <key> [-u <url>]
       bldr key-upload <key> -u <url>
       bldr config <package>

Options:
    -g, --group=<group>        The service group; shared config and topology [default: default]
    -r, --release=<release>    A package release
    -t, --topology=<topology>  Specify a service topology [default: standalone]
    -p, --path=<path>          The path to use for a repository [default: /opt/bldr/srvc/bldr/data]
    -u, --url=<url>            Use the specified package repository url
    -v, --version=<version>    A package version
    -w, --watch=<watch>        One or more service groups to watch for updates
";

/// The struct that docopts renders options
/// into.
#[derive(RustcDecodable, Debug)]
struct Args {
    cmd_install: bool,
    cmd_start: bool,
    cmd_key: bool,
    cmd_sh: bool,
    cmd_bash: bool,
    cmd_repo: bool,
    cmd_upload: bool,
    cmd_key_upload: bool,
    cmd_config: bool,
    arg_package: Option<String>,
    arg_key: Option<String>,
    flag_path: String,
    flag_port: Option<u16>,
    flag_version: String,
    flag_release: String,
    flag_url: String,
    flag_topology: Option<String>,
    flag_group: String,
    flag_watch: Vec<String>,
}

/// Creates a [Config](config/struct.Config.html) from the [Args](/Args)
/// struct.
fn config_from_args(args: &Args, command: Command) -> BldrResult<Config> {
    let mut config = Config::new();
    config.set_command(command);
    if let Some(ref package) = args.arg_package {
        let (deriv, name) = try!(split_package_arg(package));
        config.set_deriv(deriv);
        config.set_package(name);
    }
    if let Some(ref arg_key) = args.arg_key {
        config.set_key(arg_key.clone());
    }
    if let Some(ref topology) = args.flag_topology {
        match topology.as_ref() {
            "standalone" => {
                config.set_topology(Topology::Standalone);
            }
            "leader" => {
                config.set_topology(Topology::Leader);
            }
            "initializer" => {
                config.set_topology(Topology::Initializer);
            }
            t => return Err(BldrError::UnknownTopology(String::from(t))),
        }
    }
    if let Some(port) = args.flag_port {
        config.set_port(port);
    }
    config.set_url(args.flag_url.clone());
    config.set_group(args.flag_group.clone());
    config.set_watch(args.flag_watch.clone());
    config.set_path(args.flag_path.clone());
    config.set_version(args.flag_version.clone());
    config.set_release(args.flag_release.clone());
    Ok(config)
}

/// The primary loop for bldr.
///
/// * Set up the logger
/// * Pull in the arguments from the Command Line, push through Docopts
/// * Dispatch to a function that handles that action called
/// * Exit cleanly, or if we return an `Error`, call `exit_with(E, 1)`
#[allow(dead_code)]
fn main() {
    env_logger::init().unwrap();

    let args: Args = Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());
    debug!("Docopt Args: {:?}", args);
    let result = match args {
        Args{cmd_install: true, ..} => {
            match config_from_args(&args, Command::Install) {
                Ok(config) => install(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_start: true, ..} => {
            match config_from_args(&args, Command::Start) {
                Ok(config) => start(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_key: true, ..} => {
            match config_from_args(&args, Command::Key) {
                Ok(config) => key(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_key_upload: true, ..} => {
            match config_from_args(&args, Command::KeyUpload) {
                Ok(config) => key_upload(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_sh: true, ..} => {
            match config_from_args(&args, Command::Shell) {
                Ok(config) => shell(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_bash: true, ..} => {
            match config_from_args(&args, Command::Shell) {
                Ok(config) => shell(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_repo: true, ..} => {
            match config_from_args(&args, Command::Repo) {
                Ok(config) => repo(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_upload: true, ..} => {
            match config_from_args(&args, Command::Upload) {
                Ok(config) => upload(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_config: true, ..} => {
            match config_from_args(&args, Command::Configuration) {
                Ok(config) => configure(&config),
                Err(e) => Err(e),
            }
        }
        _ => Err(BldrError::CommandNotImplemented),
    };

    match result {
        Ok(_) => {}
        Err(e) => exit_with(e, 1),
    }
}

/// Print the banner
#[allow(dead_code)]
fn banner() {
    println!("{} version {}", Green.bold().paint("bldr"), VERSION);
}

/// Start a shell
#[allow(dead_code)]
fn shell(_config: &Config) -> BldrResult<()> {
    banner();
    let shell_arg = try!(CString::new("sh"));
    let mut argv = [shell_arg.as_ptr(), ptr::null()];
    unsafe {
        execvp(shell_arg.as_ptr(), argv.as_mut_ptr());
    }
    // Yeah, you don't know any better.. but we aren't coming back from
    // what happens next.
    Ok(())
}

/// Show the configuration options for a service
#[allow(dead_code)]
fn configure(config: &Config) -> BldrResult<()> {
    banner();
    println!("Displaying config for {}",
             Yellow.bold().paint(config.package()));
    println!("");
    try!(configure::display(config));
    Ok(())
}

/// Install a package
#[allow(dead_code)]
fn install(config: &Config) -> BldrResult<()> {
    banner();
    println!("Installing {}", Yellow.bold().paint(config.package()));
    let pkg_file = try!(install::latest_from_url(config.deriv(),
                                                 config.package(),
                                                 &config.url().as_ref().unwrap()));
    try!(install::verify(config.package(), &pkg_file));
    try!(install::unpack(config.package(), &pkg_file));
    Ok(())
}

/// Start a service
#[allow(dead_code)]
fn start(config: &Config) -> BldrResult<()> {
    banner();
    println!("Starting {}", Yellow.bold().paint(config.package()));
    try!(start::package(config));
    println!("Finished with {}", Yellow.bold().paint(config.package()));
    Ok(())
}

/// Run a package repo
#[allow(dead_code)]
fn repo(config: &Config) -> BldrResult<()> {
    banner();
    println!("Starting Bldr Repository at {}",
             Yellow.bold().paint(config.path()));
    try!(repo::start(&config));
    println!("Finished with {}", Yellow.bold().paint(config.package()));
    Ok(())
}

/// Upload a package
#[allow(dead_code)]
fn upload(config: &Config) -> BldrResult<()> {
    banner();
    println!("Upload Bldr Package {}",
             Yellow.bold().paint(config.package()));
    try!(upload::package(&config));
    println!("Finished with {}", Yellow.bold().paint(config.package()));
    Ok(())
}

/// Download/install a key
#[allow(dead_code)]
fn key(config: &Config) -> BldrResult<()> {
    banner();
    println!("Installing key {}", Yellow.bold().paint(config.key()));
    try!(key::install(&config));
    Ok(())
}

/// Upload a key
#[allow(dead_code)]
fn key_upload(config: &Config) -> BldrResult<()> {
    banner();
    println!("Upload Bldr key {}", Yellow.bold().paint(config.key()));
    try!(key_upload::key(&config));
    println!("Finished with {}", Yellow.bold().paint(config.key()));
    Ok(())
}

/// Exit with an error message and the right status code
#[allow(dead_code)]
fn exit_with(e: BldrError, code: i32) {
    println!("{}", Red.bold().paint(&format!("{}", e)));
    process::exit(code)
}

fn split_package_arg(arg: &str) -> BldrResult<(String, String)> {
    let items: Vec<&str> = arg.split("/").collect();
    if items.len() == 2 {
        Ok((items[0].to_string(), items[1].to_string()))
    } else {
        Err(BldrError::InvalidPackageIdent(arg.to_string()))
    }
}
<commit_msg>make `-u` flag optional for `bldr start`<commit_after>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

extern crate bldr;
extern crate rustc_serialize;
extern crate docopt;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate ansi_term;
extern crate libc;
use docopt::Docopt;
use std::process;
use ansi_term::Colour::{Red, Green, Yellow};
use libc::funcs::posix88::unistd::execvp;
use std::ffi::CString;
use std::ptr;

use bldr::config::{Command, Config};
use bldr::error::{BldrResult, BldrError};
use bldr::command::*;
use bldr::topology::Topology;

/// The version number
#[allow(dead_code)]
static VERSION: &'static str = "0.0.1";

/// The [docopts](http://burntsushi.net/rustdoc/docopt/index.html) usage
/// string. Determines what options are accepted.
#[allow(dead_code)]
#[cfg_attr(rustfmt, rustfmt_skip)]
static USAGE: &'static str = "
Usage: bldr install <package> -u <url> [-v <version>] [-r <release>]
       bldr start <package> [-u <url>] [--group=<group>] [--topology=<topology>] [--watch=<watch>...]
       bldr sh
       bldr bash
       bldr repo [-p <path>] [--port=<port>]
       bldr upload <package> -u <url> [-v <version>] [-r <release>]
       bldr key <key> [-u <url>]
       bldr key-upload <key> -u <url>
       bldr config <package>

Options:
    -g, --group=<group>        The service group; shared config and topology [default: default]
    -r, --release=<release>    A package release
    -t, --topology=<topology>  Specify a service topology [default: standalone]
    -p, --path=<path>          The path to use for a repository [default: /opt/bldr/srvc/bldr/data]
    -u, --url=<url>            Use the specified package repository url
    -v, --version=<version>    A package version
    -w, --watch=<watch>        One or more service groups to watch for updates
";

/// The struct that docopts renders options
/// into.
#[derive(RustcDecodable, Debug)]
struct Args {
    cmd_install: bool,
    cmd_start: bool,
    cmd_key: bool,
    cmd_sh: bool,
    cmd_bash: bool,
    cmd_repo: bool,
    cmd_upload: bool,
    cmd_key_upload: bool,
    cmd_config: bool,
    arg_package: Option<String>,
    arg_key: Option<String>,
    flag_path: String,
    flag_port: Option<u16>,
    flag_version: String,
    flag_release: String,
    flag_url: Option<String>,
    flag_topology: Option<String>,
    flag_group: String,
    flag_watch: Vec<String>,
}

/// Creates a [Config](config/struct.Config.html) from the [Args](/Args)
/// struct.
fn config_from_args(args: &Args, command: Command) -> BldrResult<Config> {
    let mut config = Config::new();
    config.set_command(command);
    if let Some(ref package) = args.arg_package {
        let (deriv, name) = try!(split_package_arg(package));
        config.set_deriv(deriv);
        config.set_package(name);
    }
    if let Some(ref arg_key) = args.arg_key {
        config.set_key(arg_key.clone());
    }
    if let Some(ref topology) = args.flag_topology {
        match topology.as_ref() {
            "standalone" => {
                config.set_topology(Topology::Standalone);
            }
            "leader" => {
                config.set_topology(Topology::Leader);
            }
            "initializer" => {
                config.set_topology(Topology::Initializer);
            }
            t => return Err(BldrError::UnknownTopology(String::from(t))),
        }
    }
    if let Some(port) = args.flag_port {
        config.set_port(port);
    }
    if let Some(ref url) = args.flag_url {
        config.set_url(url.clone());
    }
    config.set_group(args.flag_group.clone());
    config.set_watch(args.flag_watch.clone());
    config.set_path(args.flag_path.clone());
    config.set_version(args.flag_version.clone());
    config.set_release(args.flag_release.clone());
    Ok(config)
}

/// The primary loop for bldr.
///
/// * Set up the logger
/// * Pull in the arguments from the Command Line, push through Docopts
/// * Dispatch to a function that handles that action called
/// * Exit cleanly, or if we return an `Error`, call `exit_with(E, 1)`
#[allow(dead_code)]
fn main() {
    env_logger::init().unwrap();

    let args: Args = Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());
    debug!("Docopt Args: {:?}", args);
    let result = match args {
        Args{cmd_install: true, ..} => {
            match config_from_args(&args, Command::Install) {
                Ok(config) => install(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_start: true, ..} => {
            match config_from_args(&args, Command::Start) {
                Ok(config) => start(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_key: true, ..} => {
            match config_from_args(&args, Command::Key) {
                Ok(config) => key(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_key_upload: true, ..} => {
            match config_from_args(&args, Command::KeyUpload) {
                Ok(config) => key_upload(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_sh: true, ..} => {
            match config_from_args(&args, Command::Shell) {
                Ok(config) => shell(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_bash: true, ..} => {
            match config_from_args(&args, Command::Shell) {
                Ok(config) => shell(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_repo: true, ..} => {
            match config_from_args(&args, Command::Repo) {
                Ok(config) => repo(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_upload: true, ..} => {
            match config_from_args(&args, Command::Upload) {
                Ok(config) => upload(&config),
                Err(e) => Err(e),
            }
        }
        Args{cmd_config: true, ..} => {
            match config_from_args(&args, Command::Configuration) {
                Ok(config) => configure(&config),
                Err(e) => Err(e),
            }
        }
        _ => Err(BldrError::CommandNotImplemented),
    };

    match result {
        Ok(_) => {}
        Err(e) => exit_with(e, 1),
    }
}

/// Print the banner
#[allow(dead_code)]
fn banner() {
    println!("{} version {}", Green.bold().paint("bldr"), VERSION);
}

/// Start a shell
#[allow(dead_code)]
fn shell(_config: &Config) -> BldrResult<()> {
    banner();
    let shell_arg = try!(CString::new("sh"));
    let mut argv = [shell_arg.as_ptr(), ptr::null()];
    unsafe {
        execvp(shell_arg.as_ptr(), argv.as_mut_ptr());
    }
    // Yeah, you don't know any better.. but we aren't coming back from
    // what happens next.
    Ok(())
}

/// Show the configuration options for a service
#[allow(dead_code)]
fn configure(config: &Config) -> BldrResult<()> {
    banner();
    println!("Displaying config for {}",
             Yellow.bold().paint(config.package()));
    println!("");
    try!(configure::display(config));
    Ok(())
}

/// Install a package
#[allow(dead_code)]
fn install(config: &Config) -> BldrResult<()> {
    banner();
    println!("Installing {}", Yellow.bold().paint(config.package()));
    let pkg_file = try!(install::latest_from_url(config.deriv(),
                                                 config.package(),
                                                 &config.url().as_ref().unwrap()));
    try!(install::verify(config.package(), &pkg_file));
    try!(install::unpack(config.package(), &pkg_file));
    Ok(())
}

/// Start a service
#[allow(dead_code)]
fn start(config: &Config) -> BldrResult<()> {
    banner();
    println!("Starting {}", Yellow.bold().paint(config.package()));
    try!(start::package(config));
    println!("Finished with {}", Yellow.bold().paint(config.package()));
    Ok(())
}

/// Run a package repo
#[allow(dead_code)]
fn repo(config: &Config) -> BldrResult<()> {
    banner();
    println!("Starting Bldr Repository at {}",
             Yellow.bold().paint(config.path()));
    try!(repo::start(&config));
    println!("Finished with {}", Yellow.bold().paint(config.package()));
    Ok(())
}

/// Upload a package
#[allow(dead_code)]
fn upload(config: &Config) -> BldrResult<()> {
    banner();
    println!("Upload Bldr Package {}",
             Yellow.bold().paint(config.package()));
    try!(upload::package(&config));
    println!("Finished with {}", Yellow.bold().paint(config.package()));
    Ok(())
}

/// Download/install a key
#[allow(dead_code)]
fn key(config: &Config) -> BldrResult<()> {
    banner();
    println!("Installing key {}", Yellow.bold().paint(config.key()));
    try!(key::install(&config));
    Ok(())
}

/// Upload a key
#[allow(dead_code)]
fn key_upload(config: &Config) -> BldrResult<()> {
    banner();
    println!("Upload Bldr key {}", Yellow.bold().paint(config.key()));
    try!(key_upload::key(&config));
    println!("Finished with {}", Yellow.bold().paint(config.key()));
    Ok(())
}

/// Exit with an error message and the right status code
#[allow(dead_code)]
fn exit_with(e: BldrError, code: i32) {
    println!("{}", Red.bold().paint(&format!("{}", e)));
    process::exit(code)
}

fn split_package_arg(arg: &str) -> BldrResult<(String, String)> {
    let items: Vec<&str> = arg.split("/").collect();
    if items.len() == 2 {
        Ok((items[0].to_string(), items[1].to_string()))
    } else {
        Err(BldrError::InvalidPackageIdent(arg.to_string()))
    }
}
<|endoftext|>


<commit_before>#![feature(collections)]

use std::io;
use std::io::prelude::*;
use std::iter::repeat;
use std::str::FromStr;
use std::collections::BitVec;

enum Hamming { Encode, Decode }

fn main() {
    let title = "RUSTYHAM: A HAMMING CODE GENERATOR IN RUST";
    let border: String = repeat('=').take(title.len()).collect::<>();
    println!("{}", border);
    println!("{}", title);
    println!("{}", border);

    loop {
        let mut linebuf = String::new();
        println!("(1) Encode ASCII");
        println!("*(2) Encode binary");
        println!("(3) Decode to ASCII");
        println!("*(4) Decode to binary");
        println!("Note: options marked as * are not supported yet.");
        print!("Enter your choice: ");
        io::stdout().flush().unwrap();
        io::stdin().read_line(&mut linebuf).unwrap();

        let num = i32::from_str(linebuf.trim());
        match num.ok() {
            Some(n) => {
                let mut good = true;
                println!("{}", match n {
                    1 => hamming(Hamming::Encode),
                    3 => hamming(Hamming::Decode),
                    2 | 4 => "Sorry, not implemented yet.".to_string(),
                    _ => { good = false; "Invalid input.".to_string() }
                });
                if good { break; }
            }
            None => {
                println!("Invalid input.");
            }
        };
    }
}

fn hamming(action: Hamming) -> String {
    match action {
        Hamming::Encode => {
            // prompt for ASCII input
            let mut message = String::new();
            print!("Enter string to encode: ");
            io::stdout().flush().unwrap();
            io::stdin().read_line(&mut message).unwrap();

            // compute block and message length
            message = message.trim().to_string();
            let mlen = message.len() as u32 * 7;
            let lenpow = (2..).find(|&r| 2u32.pow(r) - r - 1 >= mlen).unwrap();
            let len = 2us.pow(lenpow) - 1;

            // the thing we're storing the hamming code in
            let mut bv = BitVec::from_elem(len, false);

            // convert ASCII string to binary
            // IMPORTANT NOTE: the following line takes ownership of the
            // `message' variable. We no longer have access to the original
            // string from this point onwards.
            let bytes = message.into_bytes();
            let bytes_str = bytes.iter().map(|&c| format!("{:0>1$b}", c, 7))
                .collect::<Vec<String>>().concat();

            // set data bits
            let mut bytes_iter = bytes_str.chars();
            for i in 1..len {
                if (i & (i - 1)) != 0 {  // if i is not a power of 2
                    bv.set(i-1, bytes_iter.next().unwrap_or('0') == '1');
                }
            }

            // set parity bits
            for i in 0..lenpow {
                let bi = 2us.pow(i) - 1;
                let (mut parity, mut ignore, mut counter) = (false, false, 0);
                for j in bi..len {
                    if !ignore && bv.get(j).unwrap() { parity = !parity; }
                    counter += 1;
                    if counter >= 2u32.pow(i) {
                        ignore = !ignore;
                        counter = 0;
                    }
                }
                bv.set(bi, parity);
            }

            format!("{:?}", bv)
        },
        Hamming::Decode => {
            // TODO make this support error correction (which is basically the
            // whole point of a hamming code...)

            // prompt for binary input
            let mut code = String::new();
            print!("Enter Hamming code to decode: ");
            io::stdout().flush().unwrap();
            io::stdin().read_line(&mut code).unwrap();

            // collect all bits at non-powers-of-2
            let data = &code.trim().chars().enumerate()
                .filter(|x| ((x.0 + 1) & x.0) != 0).map(|x| x.1)
                .collect::<Vec<char>>()[..];
            let chars = data.chunks(7)
                .map(|x| u8::from_str_radix(&x.iter().cloned().collect::<String>()[..], 2).unwrap())
                .collect::<Vec<u8>>();

            String::from_utf8(chars).unwrap()
        }
    }
}
<commit_msg>get rid of BitVec (use Vec<bool> instead), new calc_parity function<commit_after>use std::io;
use std::io::prelude::*;
use std::iter::repeat;
use std::str::FromStr;

enum Hamming { Encode, Decode }

fn main() {
    let title = "RUSTYHAM: A HAMMING CODE GENERATOR IN RUST";
    let border: String = repeat('=').take(title.len()).collect::<>();
    println!("{}", border);
    println!("{}", title);
    println!("{}", border);

    loop {
        let mut linebuf = String::new();
        println!("(1) Encode ASCII");
        println!("*(2) Encode binary");
        println!("(3) Decode to ASCII");
        println!("*(4) Decode to binary");
        println!("Note: options marked as * are not supported yet.");
        print!("Enter your choice: ");
        io::stdout().flush().unwrap();
        io::stdin().read_line(&mut linebuf).unwrap();

        let num = i32::from_str(linebuf.trim());
        match num.ok() {
            Some(n) => {
                let mut good = true;
                println!("{}", match n {
                    1 => hamming(Hamming::Encode),
                    3 => hamming(Hamming::Decode),
                    2 | 4 => "Sorry, not implemented yet.".to_string(),
                    _ => { good = false; "Invalid input.".to_string() }
                });
                if good { break; }
            }
            None => {
                println!("Invalid input.");
            }
        };
    }
}

fn hamming(action: Hamming) -> String {
    match action {
        Hamming::Encode => {
            // prompt for ASCII input
            let mut message = String::new();
            print!("Enter string to encode: ");
            io::stdout().flush().unwrap();
            io::stdin().read_line(&mut message).unwrap();

            // compute block and message length
            message = message.trim().to_string();
            let mlen = message.len() as u32 * 7;
            let lenpow = (2..).find(|&r| 2u32.pow(r) - r - 1 >= mlen).unwrap();
            let len = 2us.pow(lenpow) - 1;

            // the thing we're storing the hamming code in
            let mut code: Vec<bool> = repeat(false).take(len).collect::<>();

            // convert ASCII string to binary
            // IMPORTANT NOTE: the following line takes ownership of the
            // `message' variable. We no longer have access to the original
            // string from this point onwards.
            let bytes = message.into_bytes();
            let bytes_str = bytes.iter().map(|&c| format!("{:0>1$b}", c, 7))
                .collect::<Vec<String>>().concat();

            // set data bits
            let mut bytes_iter = bytes_str.chars();
            for i in 1..len {
                if (i & (i - 1)) != 0 {  // if i is not a power of 2
                    code[i-1] = bytes_iter.next().unwrap_or('0') == '1';
                }
            }

            // set parity bits
            for i in 0..lenpow {
                let bi = 2us.pow(i) - 1;
                let (mut parity, mut ignore, mut counter) = (false, false, 0);
                for j in bi..len {
                    if !ignore && code[j] { parity = !parity; }
                    counter += 1;
                    if counter >= 2u32.pow(i) {
                        ignore = !ignore;
                        counter = 0;
                    }
                }
                code[bi] = parity;
            }

            code.into_iter().map(|x| if x {"1"} else {"0"}).collect::<Vec<_>>().concat()
        },
        Hamming::Decode => {
            // prompt for binary input
            let mut code_str = String::new();
            print!("Enter Hamming code to decode: ");
            io::stdout().flush().unwrap();
            io::stdin().read_line(&mut code_str).unwrap();

            // verify parity bits, fix 1-bit-flipped errors if any
            // TODO avoid code repetition in Hamming::Encode =>
            let len = code_str.len() - 1;
            let lenpow = ((len + 1) as f32).sqrt().round() as u32;
            let chars = code_str.chars().map(|x| x == '1').collect::<Vec<bool>>();
            for i in 0..lenpow {
                println!("{:?}", calc_parity(chars, i));
            }

            // collect all bits at non-powers-of-2
            let data = &code_str.trim().chars().enumerate()
                .filter(|x| ((x.0 + 1) & x.0) != 0).map(|x| x.1)
                .collect::<Vec<char>>()[..];
            let chars = data.chunks(7)
                .map(|x| u8::from_str_radix(&x.iter().cloned().collect::<String>()[..], 2).unwrap())
                .collect::<Vec<u8>>();

            String::from_utf8(chars).unwrap()
        }
    }
}

fn calc_parity(code: Vec<bool>, i: u32) -> bool {
    let bi = 2us.pow(i) - 1;
    let (mut parity, mut ignore, mut counter) = (false, false, 0);
    for j in bi..code.len() {
        if !ignore && code[j] { parity = !parity }
        counter += 1;
        if counter >= 2u32.pow(i) {
            ignore = !ignore;
            counter = 0;
        }
    }
    parity
}
<|endoftext|>


<commit_before>//! An implementation of [tldr](https://github.com/tldr-pages/tldr) in Rust.
//
// Copyright (c) 2015-2020 tealdeer developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be
// copied, modified, or distributed except according to those terms.

#![deny(clippy::all)]
#![warn(clippy::pedantic)]
#![allow(clippy::similar_names)]
#![allow(clippy::module_name_repetitions)]

#[cfg(feature = "logging")]
extern crate env_logger;

use std::env;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use std::process;

use ansi_term::{Color, Style};
use app_dirs::AppInfo;
use atty::Stream;
use docopt::Docopt;
#[cfg(not(target_os = "windows"))]
use pager::Pager;
use serde_derive::Deserialize;

mod cache;
mod config;
mod error;
mod formatter;
mod tokenizer;
mod types;

use crate::cache::Cache;
use crate::config::{get_config_path, make_default_config, Config, MAX_CACHE_AGE};
use crate::error::TealdeerError::{CacheError, ConfigError, UpdateError};
use crate::formatter::print_lines;
use crate::tokenizer::Tokenizer;
use crate::types::{ColorOptions, OsType};

const NAME: &str = "tealdeer";
const APP_INFO: AppInfo = AppInfo {
    name: NAME,
    author: NAME,
};
const VERSION: &str = env!("CARGO_PKG_VERSION");
const USAGE: &str = "
Usage:

    tldr [options] <command>...
    tldr [options]

Options:

    -h --help           Show this screen
    -v --version        Show version information
    -l --list           List all commands in the cache
    -f --render <file>  Render a specific markdown file
    -o --os <type>      Override the operating system [linux, osx, sunos, windows]
    -u --update         Update the local cache
    -c --clear-cache    Clear the local cache
    -p --pager          Use a pager to page output
    -m --markdown       Display the raw markdown instead of rendering it
    -q --quiet          Suppress informational messages
    --config-path       Show config file path
    --seed-config       Create a basic config
    --color <when>      Control when to use color [always, auto, never] [default: auto]

Examples:

    $ tldr tar
    $ tldr --list

To control the cache:

    $ tldr --update
    $ tldr --clear-cache

To render a local file (for testing):

    $ tldr --render /path/to/file.md
";
const ARCHIVE_URL: &str = "https://github.com/tldr-pages/tldr/archive/master.tar.gz";
#[cfg(not(target_os = "windows"))]
const PAGER_COMMAND: &str = "less -R";

#[derive(Debug, Deserialize)]
#[allow(clippy::struct_excessive_bools)]
struct Args {
    arg_command: Option<Vec<String>>,
    flag_help: bool,
    flag_version: bool,
    flag_list: bool,
    flag_render: Option<String>,
    flag_os: Option<OsType>,
    flag_update: bool,
    flag_clear_cache: bool,
    flag_pager: bool,
    flag_quiet: bool,
    flag_config_path: bool,
    flag_seed_config: bool,
    flag_markdown: bool,
    flag_color: ColorOptions,
}

/// Print page by path
fn print_page(path: &Path, enable_markdown: bool, config: &Config) -> Result<(), String> {
    // Open file
    let file = File::open(path).map_err(|msg| format!("Could not open file: {}", msg))?;
    let reader = BufReader::new(file);

    if enable_markdown {
        // Print the raw markdown of the file.
        for line in reader.lines() {
            println!("{}", line.unwrap());
        }
    } else {
        // Create tokenizer and print output
        let mut tokenizer = Tokenizer::new(reader);
        print_lines(&mut tokenizer, &config);
    };

    Ok(())
}

/// Set up display pager
#[cfg(not(target_os = "windows"))]
fn configure_pager() {
    Pager::with_default_pager(PAGER_COMMAND).setup();
}

#[cfg(target_os = "windows")]
fn configure_pager() {
    eprintln!("Warning: -p / --pager flag not available on Windows!");
}

fn should_update_cache(args: &Args, config: &Config) -> bool {
    args.flag_update
        || (config.updates.auto_update
            && Cache::last_update().map_or(true, |ago| ago >= config.updates.auto_update_interval))
}

/// Check the cache for freshness
fn check_cache(args: &Args, enable_styles: bool) {
    match Cache::last_update() {
        Some(ago) if ago > MAX_CACHE_AGE => {
            if args.flag_quiet {
                return;
            }

            // Only use color if enabled
            let warning_style = if enable_styles {
                Style::new().fg(Color::Yellow)
            } else {
                Style::default()
            };

            eprintln!(
                "{}",
                warning_style.paint(format!(
                    "The cache hasn't been updated for more than {} days.\n\
                         You should probably run `tldr --update` soon.",
                    MAX_CACHE_AGE.as_secs() / 24 / 3600
                ))
            );
        }
        Some(_) => {}
        None => {
            eprintln!("Cache not found. Please run `tldr --update`.");
            process::exit(1);
        }
    };
}

/// Clear the cache
fn clear_cache(quietly: bool) {
    Cache::clear().unwrap_or_else(|e| {
        match e {
            CacheError(msg) | ConfigError(msg) | UpdateError(msg) => {
                eprintln!("Could not delete cache: {}", msg)
            }
        };
        process::exit(1);
    });
    if !quietly {
        println!("Successfully deleted cache.");
    }
}

/// Update the cache
fn update_cache(cache: &Cache, quietly: bool) {
    cache.update().unwrap_or_else(|e| {
        match e {
            CacheError(msg) | ConfigError(msg) | UpdateError(msg) => {
                eprintln!("Could not update cache: {}", msg)
            }
        };
        process::exit(1);
    });
    if !quietly {
        println!("Successfully updated cache.");
    }
}

/// Show the config path
fn show_config_path() {
    match get_config_path() {
        Ok(config_file_path) => {
            println!("Config path is: {}", config_file_path.to_str().unwrap());
        }
        Err(ConfigError(msg)) => {
            eprintln!("Could not look up config_path: {}", msg);
            process::exit(1);
        }
        Err(_) => {
            eprintln!("Unknown error");
            process::exit(1);
        }
    }
}

/// Create seed config file and exit
fn create_config_and_exit() {
    match make_default_config() {
        Ok(config_file_path) => {
            println!(
                "Successfully created seed config file here: {}",
                config_file_path.to_str().unwrap()
            );
            process::exit(0);
        }
        Err(ConfigError(msg)) => {
            eprintln!("Could not create seed config: {}", msg);
            process::exit(1);
        }
        Err(_) => {
            eprintln!("Unknown error");
            process::exit(1);
        }
    }
}

#[cfg(feature = "logging")]
fn init_log() {
    env_logger::init();
}

#[cfg(not(feature = "logging"))]
fn init_log() {}

#[cfg(target_os = "linux")]
fn get_os() -> OsType {
    OsType::Linux
}

#[cfg(any(
    target_os = "macos",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "dragonfly"
))]
fn get_os() -> OsType {
    OsType::OsX
}

#[cfg(target_os = "windows")]
fn get_os() -> OsType {
    OsType::Windows
}

#[cfg(not(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "dragonfly",
    target_os = "windows"
)))]
fn get_os() -> OsType {
    OsType::Other
}

fn main() {
    // Initialize logger
    init_log();

    // Parse arguments
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.deserialize())
        .unwrap_or_else(|e| e.exit());

    // Show version and exit
    if args.flag_version {
        let os = get_os();
        println!("{} v{} ({})", NAME, VERSION, os);
        process::exit(0);
    }

    // Show config file and path, pass through
    if args.flag_config_path {
        show_config_path();
    }

    // Create a basic config and exit
    if args.flag_seed_config {
        create_config_and_exit();
    }

    // Determine the usage of styles
    #[cfg(target_os = "windows")]
    let ansi_support = ansi_term::enable_ansi_support().is_ok();
    #[cfg(not(target_os = "windows"))]
    let ansi_support = true;

    let enable_styles = match args.flag_color {
        // Always use styling as long as there is `ansi_support`
        ColorOptions::Always => ansi_support,
        // Enable styling if:
        // * There is `ansi_support`
        // * NO_COLOR env var isn't set: https://no-color.org/
        // * The output stream is stdout (not being piped)
        ColorOptions::Auto => {
            ansi_support && env::var_os("NO_COLOR").is_none() && atty::is(Stream::Stdout)
        }
        // Disable styling
        ColorOptions::Never => false,
    };

    // Look up config file, if none is found fall back to default config.
    let config = match Config::load(enable_styles) {
        Ok(config) => config,
        Err(ConfigError(msg)) => {
            eprintln!("Could not load config: {}", msg);
            process::exit(1);
        }
        Err(e) => {
            eprintln!("Could not load config: {}", e);
            process::exit(1);
        }
    };

    if args.flag_pager || config.display.use_pager {
        configure_pager();
    }

    // Specify target OS
    let os: OsType = match args.flag_os {
        Some(os) => os,
        None => get_os(),
    };

    // Initialize cache
    let cache = Cache::new(ARCHIVE_URL, os);

    // Clear cache, pass through
    if args.flag_clear_cache {
        clear_cache(args.flag_quiet);
    }

    // Update cache, pass through
    let cache_updated = if should_update_cache(&args, &config) {
        update_cache(&cache, args.flag_quiet);
        true
    } else {
        false
    };

    // Render local file and exit
    if let Some(ref file) = args.flag_render {
        let path = PathBuf::from(file);
        if let Err(msg) = print_page(&path, args.flag_markdown, &config) {
            eprintln!("{}", msg);
            process::exit(1);
        } else {
            process::exit(0);
        };
    }

    // List cached commands and exit
    if args.flag_list {
        if !cache_updated {
            // Check cache for freshness
            check_cache(&args, enable_styles);
        }

        // Get list of pages
        let pages = cache.list_pages().unwrap_or_else(|e| {
            match e {
                CacheError(msg) | ConfigError(msg) | UpdateError(msg) => {
                    eprintln!("Could not get list of pages: {}", msg)
                }
            }
            process::exit(1);
        });

        // Print pages
        println!("{}", pages.join("\n"));
        process::exit(0);
    }

    // Show command from cache
    if let Some(ref command) = args.arg_command {
        let command = command.join("-");

        if !cache_updated {
            // Check cache for freshness
            check_cache(&args, enable_styles);
        }

        // Search for command in cache
        if let Some(path) = cache.find_page(&command) {
            if let Err(msg) = print_page(&path, args.flag_markdown, &config) {
                eprintln!("{}", msg);
                process::exit(1);
            } else {
                process::exit(0);
            }
        } else {
            if !args.flag_quiet {
                println!("Page {} not found in cache", &command);
                println!("Try updating with `tldr --update`, or submit a pull request to:");
                println!("https://github.com/tldr-pages/tldr");
            }
            process::exit(1);
        }
    }

    // Some flags can be run without a command.
    if !(args.flag_update || args.flag_clear_cache || args.flag_config_path) {
        eprintln!("{}", USAGE);
        process::exit(1);
    }
}

#[cfg(test)]
mod test {
    use crate::{Args, OsType, USAGE};
    use docopt::{Docopt, Error};

    fn test_helper(argv: &[&str]) -> Result<Args, Error> {
        Docopt::new(USAGE).and_then(|d| d.argv(argv.iter()).deserialize())
    }

    #[test]
    fn test_docopt_os_case_insensitive() {
        let argv = vec!["cp", "--os", "LiNuX"];
        let os = test_helper(&argv).unwrap().flag_os.unwrap();
        assert_eq!(OsType::Linux, os);
    }

    #[test]
    fn test_docopt_expect_error() {
        let argv = vec!["cp", "--os", "lindows"];
        assert!(!test_helper(&argv).is_ok());
    }
}
<commit_msg>Switch `--color always` to force styling<commit_after>//! An implementation of [tldr](https://github.com/tldr-pages/tldr) in Rust.
//
// Copyright (c) 2015-2020 tealdeer developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be
// copied, modified, or distributed except according to those terms.

#![deny(clippy::all)]
#![warn(clippy::pedantic)]
#![allow(clippy::similar_names)]
#![allow(clippy::module_name_repetitions)]

#[cfg(feature = "logging")]
extern crate env_logger;

use std::env;
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use std::process;

use ansi_term::{Color, Style};
use app_dirs::AppInfo;
use atty::Stream;
use docopt::Docopt;
#[cfg(not(target_os = "windows"))]
use pager::Pager;
use serde_derive::Deserialize;

mod cache;
mod config;
mod error;
mod formatter;
mod tokenizer;
mod types;

use crate::cache::Cache;
use crate::config::{get_config_path, make_default_config, Config, MAX_CACHE_AGE};
use crate::error::TealdeerError::{CacheError, ConfigError, UpdateError};
use crate::formatter::print_lines;
use crate::tokenizer::Tokenizer;
use crate::types::{ColorOptions, OsType};

const NAME: &str = "tealdeer";
const APP_INFO: AppInfo = AppInfo {
    name: NAME,
    author: NAME,
};
const VERSION: &str = env!("CARGO_PKG_VERSION");
const USAGE: &str = "
Usage:

    tldr [options] <command>...
    tldr [options]

Options:

    -h --help           Show this screen
    -v --version        Show version information
    -l --list           List all commands in the cache
    -f --render <file>  Render a specific markdown file
    -o --os <type>      Override the operating system [linux, osx, sunos, windows]
    -u --update         Update the local cache
    -c --clear-cache    Clear the local cache
    -p --pager          Use a pager to page output
    -m --markdown       Display the raw markdown instead of rendering it
    -q --quiet          Suppress informational messages
    --config-path       Show config file path
    --seed-config       Create a basic config
    --color <when>      Control when to use color [always, auto, never] [default: auto]

Examples:

    $ tldr tar
    $ tldr --list

To control the cache:

    $ tldr --update
    $ tldr --clear-cache

To render a local file (for testing):

    $ tldr --render /path/to/file.md
";
const ARCHIVE_URL: &str = "https://github.com/tldr-pages/tldr/archive/master.tar.gz";
#[cfg(not(target_os = "windows"))]
const PAGER_COMMAND: &str = "less -R";

#[derive(Debug, Deserialize)]
#[allow(clippy::struct_excessive_bools)]
struct Args {
    arg_command: Option<Vec<String>>,
    flag_help: bool,
    flag_version: bool,
    flag_list: bool,
    flag_render: Option<String>,
    flag_os: Option<OsType>,
    flag_update: bool,
    flag_clear_cache: bool,
    flag_pager: bool,
    flag_quiet: bool,
    flag_config_path: bool,
    flag_seed_config: bool,
    flag_markdown: bool,
    flag_color: ColorOptions,
}

/// Print page by path
fn print_page(path: &Path, enable_markdown: bool, config: &Config) -> Result<(), String> {
    // Open file
    let file = File::open(path).map_err(|msg| format!("Could not open file: {}", msg))?;
    let reader = BufReader::new(file);

    if enable_markdown {
        // Print the raw markdown of the file.
        for line in reader.lines() {
            println!("{}", line.unwrap());
        }
    } else {
        // Create tokenizer and print output
        let mut tokenizer = Tokenizer::new(reader);
        print_lines(&mut tokenizer, &config);
    };

    Ok(())
}

/// Set up display pager
#[cfg(not(target_os = "windows"))]
fn configure_pager() {
    Pager::with_default_pager(PAGER_COMMAND).setup();
}

#[cfg(target_os = "windows")]
fn configure_pager() {
    eprintln!("Warning: -p / --pager flag not available on Windows!");
}

fn should_update_cache(args: &Args, config: &Config) -> bool {
    args.flag_update
        || (config.updates.auto_update
            && Cache::last_update().map_or(true, |ago| ago >= config.updates.auto_update_interval))
}

/// Check the cache for freshness
fn check_cache(args: &Args, enable_styles: bool) {
    match Cache::last_update() {
        Some(ago) if ago > MAX_CACHE_AGE => {
            if args.flag_quiet {
                return;
            }

            // Only use color if enabled
            let warning_style = if enable_styles {
                Style::new().fg(Color::Yellow)
            } else {
                Style::default()
            };

            eprintln!(
                "{}",
                warning_style.paint(format!(
                    "The cache hasn't been updated for more than {} days.\n\
                         You should probably run `tldr --update` soon.",
                    MAX_CACHE_AGE.as_secs() / 24 / 3600
                ))
            );
        }
        Some(_) => {}
        None => {
            eprintln!("Cache not found. Please run `tldr --update`.");
            process::exit(1);
        }
    };
}

/// Clear the cache
fn clear_cache(quietly: bool) {
    Cache::clear().unwrap_or_else(|e| {
        match e {
            CacheError(msg) | ConfigError(msg) | UpdateError(msg) => {
                eprintln!("Could not delete cache: {}", msg)
            }
        };
        process::exit(1);
    });
    if !quietly {
        println!("Successfully deleted cache.");
    }
}

/// Update the cache
fn update_cache(cache: &Cache, quietly: bool) {
    cache.update().unwrap_or_else(|e| {
        match e {
            CacheError(msg) | ConfigError(msg) | UpdateError(msg) => {
                eprintln!("Could not update cache: {}", msg)
            }
        };
        process::exit(1);
    });
    if !quietly {
        println!("Successfully updated cache.");
    }
}

/// Show the config path
fn show_config_path() {
    match get_config_path() {
        Ok(config_file_path) => {
            println!("Config path is: {}", config_file_path.to_str().unwrap());
        }
        Err(ConfigError(msg)) => {
            eprintln!("Could not look up config_path: {}", msg);
            process::exit(1);
        }
        Err(_) => {
            eprintln!("Unknown error");
            process::exit(1);
        }
    }
}

/// Create seed config file and exit
fn create_config_and_exit() {
    match make_default_config() {
        Ok(config_file_path) => {
            println!(
                "Successfully created seed config file here: {}",
                config_file_path.to_str().unwrap()
            );
            process::exit(0);
        }
        Err(ConfigError(msg)) => {
            eprintln!("Could not create seed config: {}", msg);
            process::exit(1);
        }
        Err(_) => {
            eprintln!("Unknown error");
            process::exit(1);
        }
    }
}

#[cfg(feature = "logging")]
fn init_log() {
    env_logger::init();
}

#[cfg(not(feature = "logging"))]
fn init_log() {}

#[cfg(target_os = "linux")]
fn get_os() -> OsType {
    OsType::Linux
}

#[cfg(any(
    target_os = "macos",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "dragonfly"
))]
fn get_os() -> OsType {
    OsType::OsX
}

#[cfg(target_os = "windows")]
fn get_os() -> OsType {
    OsType::Windows
}

#[cfg(not(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "freebsd",
    target_os = "netbsd",
    target_os = "openbsd",
    target_os = "dragonfly",
    target_os = "windows"
)))]
fn get_os() -> OsType {
    OsType::Other
}

fn main() {
    // Initialize logger
    init_log();

    // Parse arguments
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.deserialize())
        .unwrap_or_else(|e| e.exit());

    // Show version and exit
    if args.flag_version {
        let os = get_os();
        println!("{} v{} ({})", NAME, VERSION, os);
        process::exit(0);
    }

    // Show config file and path, pass through
    if args.flag_config_path {
        show_config_path();
    }

    // Create a basic config and exit
    if args.flag_seed_config {
        create_config_and_exit();
    }

    // Determine the usage of styles
    #[cfg(target_os = "windows")]
    let ansi_support = ansi_term::enable_ansi_support().is_ok();
    #[cfg(not(target_os = "windows"))]
    let ansi_support = true;

    let enable_styles = match args.flag_color {
        // Attempt to use styling if instructed
        ColorOptions::Always => true,
        // Enable styling if:
        // * There is `ansi_support`
        // * NO_COLOR env var isn't set: https://no-color.org/
        // * The output stream is stdout (not being piped)
        ColorOptions::Auto => {
            ansi_support && env::var_os("NO_COLOR").is_none() && atty::is(Stream::Stdout)
        }
        // Disable styling
        ColorOptions::Never => false,
    };

    // Look up config file, if none is found fall back to default config.
    let config = match Config::load(enable_styles) {
        Ok(config) => config,
        Err(ConfigError(msg)) => {
            eprintln!("Could not load config: {}", msg);
            process::exit(1);
        }
        Err(e) => {
            eprintln!("Could not load config: {}", e);
            process::exit(1);
        }
    };

    if args.flag_pager || config.display.use_pager {
        configure_pager();
    }

    // Specify target OS
    let os: OsType = match args.flag_os {
        Some(os) => os,
        None => get_os(),
    };

    // Initialize cache
    let cache = Cache::new(ARCHIVE_URL, os);

    // Clear cache, pass through
    if args.flag_clear_cache {
        clear_cache(args.flag_quiet);
    }

    // Update cache, pass through
    let cache_updated = if should_update_cache(&args, &config) {
        update_cache(&cache, args.flag_quiet);
        true
    } else {
        false
    };

    // Render local file and exit
    if let Some(ref file) = args.flag_render {
        let path = PathBuf::from(file);
        if let Err(msg) = print_page(&path, args.flag_markdown, &config) {
            eprintln!("{}", msg);
            process::exit(1);
        } else {
            process::exit(0);
        };
    }

    // List cached commands and exit
    if args.flag_list {
        if !cache_updated {
            // Check cache for freshness
            check_cache(&args, enable_styles);
        }

        // Get list of pages
        let pages = cache.list_pages().unwrap_or_else(|e| {
            match e {
                CacheError(msg) | ConfigError(msg) | UpdateError(msg) => {
                    eprintln!("Could not get list of pages: {}", msg)
                }
            }
            process::exit(1);
        });

        // Print pages
        println!("{}", pages.join("\n"));
        process::exit(0);
    }

    // Show command from cache
    if let Some(ref command) = args.arg_command {
        let command = command.join("-");

        if !cache_updated {
            // Check cache for freshness
            check_cache(&args, enable_styles);
        }

        // Search for command in cache
        if let Some(path) = cache.find_page(&command) {
            if let Err(msg) = print_page(&path, args.flag_markdown, &config) {
                eprintln!("{}", msg);
                process::exit(1);
            } else {
                process::exit(0);
            }
        } else {
            if !args.flag_quiet {
                println!("Page {} not found in cache", &command);
                println!("Try updating with `tldr --update`, or submit a pull request to:");
                println!("https://github.com/tldr-pages/tldr");
            }
            process::exit(1);
        }
    }

    // Some flags can be run without a command.
    if !(args.flag_update || args.flag_clear_cache || args.flag_config_path) {
        eprintln!("{}", USAGE);
        process::exit(1);
    }
}

#[cfg(test)]
mod test {
    use crate::{Args, OsType, USAGE};
    use docopt::{Docopt, Error};

    fn test_helper(argv: &[&str]) -> Result<Args, Error> {
        Docopt::new(USAGE).and_then(|d| d.argv(argv.iter()).deserialize())
    }

    #[test]
    fn test_docopt_os_case_insensitive() {
        let argv = vec!["cp", "--os", "LiNuX"];
        let os = test_helper(&argv).unwrap().flag_os.unwrap();
        assert_eq!(OsType::Linux, os);
    }

    #[test]
    fn test_docopt_expect_error() {
        let argv = vec!["cp", "--os", "lindows"];
        assert!(!test_helper(&argv).is_ok());
    }
}
<|endoftext|>


<commit_before>use std::io::{BufRead, Read, Write, self};
use std::fs::File;
use std::string::ToString;
use std::env;

mod label;
mod parser;
mod interpreter;
mod assembler;
use interpreter::{Interpreter, Program};

#[derive(Debug, Clone)]
struct Args {
    program: String,        // this is where we read the program from.
    input: Option<String>,  // this is where we read input for the program from. if None, stdin
    output: Option<String>, // this is where we output data to. if None, stdin
    format: FileFormat,     // format of input file. default is Whitespace
    action: Action          // output format. translate or execute.
}

#[derive(Debug, Clone)]
enum FileFormat {
    Whitespace,
    Assembly
}

#[derive(Debug, Clone)]
enum Action {
    Translate,
    Execute
}

fn main() {
    match console_main() {
        Ok(()) => (),
        Err(s) => write!(io::stderr(), "{}\n", s).unwrap()
    }
}

fn console_main() -> Result<(), String> {
    let args = try!(parse_args());

    let data = {
        let mut file = try!(File::open(&args.program).map_err(|e| e.to_string()));

        let mut data = String::new();

        try!(file.read_to_string(&mut data).map_err(|e| e.to_string()));

        data
    };

    let program = try!(match args.format {
        FileFormat::Whitespace => Program::parse(data.as_bytes()),
        FileFormat::Assembly => Program::assemble(&data)
    });

    let mut output: Box<Write> = if let Some(path) = args.output {
        Box::new(try!(File::create(&path).map_err(|e| e.to_string())))
    } else {
        Box::new(io::stdout())
    };

    match args.action {
        Action::Translate => try!(
            match args.format {
                FileFormat::Whitespace => output.write_all(program.disassemble().as_bytes()),
                FileFormat::Assembly   => output.write_all(program.dump().as_slice())
            }.map_err(|e| e.to_string())
        ),
        Action::Execute => {
            let input: Box<BufRead> = if let Some(path) = args.input {
                Box::new(io::BufReader::new(
                    try!(File::open(&path).map_err(|e| e.to_string()))
                ))
            } else {
                Box::new(io::BufReader::new(
                    io::stdin()
                ))
            };
            let mut interpreter = Interpreter::new(program, input, output);
            try!(interpreter.run());
        }
    }
    Ok(())
}

macro_rules! try_opt {
    ($o:expr, $e:expr) => (
        match $o {
            Some(x) => x,
            None => return Err($e)
        }
    )
}

fn parse_args() -> Result<Args, String> {;
    let mut input = None;
    let mut output = None;
    let mut format = None;
    let mut action = Action::Execute;

    let mut args = env::args();
    let mut pos_args = Vec::new();
    // discard executable name
    args.next();

    // sort out args and kwargs (also parsing kwargs)
    loop {
        match args.next() {
            Some(arg) => match arg.as_ref() {
                "-i" | "--input" => if let Some(_) = input {
                    return Err("Option --input was specified twice".to_string());
                } else {
                    input = Some(try_opt!(args.next(), "Missing argument to --input".to_string()));
                },
                "-o" | "--output" => if let Some(_) = output {
                    return Err("Option --output was specified twice".to_string());
                } else {
                    output = Some(try_opt!(args.next(), "Missing argument to --output".to_string()));
                },
                "-f" | "--format" => if let Some(_) = format {
                    return Err("Option --format was specified twice".to_string());
                } else {
                    format = match try_opt!(args.next(), "Missing argument to --format".to_string()).as_ref() {
                        "whitespace" | "ws" => Some(FileFormat::Whitespace),
                        "assembly" | "asm"  => Some(FileFormat::Assembly),
                        f => return Err(format!("Unrecognized input format {}", f))
                    };
                },
                "-t" | "--translate" => if let Action::Translate = action {
                    return Err("Option --translate was specified twice".to_string())
                } else {
                    action = Action::Translate;
                },
                "--" => {
                    pos_args.extend(args);
                    break;
                },
                _ => if arg.chars().next() == Some('-') {
                    return Err(format!("Unrecognized option {}", arg));
                } else {
                    pos_args.push(arg);
                }
            },
            None => break
        }
    }

    // parse positional args
    let mut pos_args = pos_args.into_iter();
    let program = try_opt!(pos_args.next(), "Missing required positional argument 'program'".to_string());
    if let Some(x) = pos_args.next() {
        return Err(format!("Unexpected positional argument {}", x));
    }

    return Ok(Args {
        program: program,
        input: input,
        output: output,
        format: format.unwrap_or(FileFormat::Whitespace),
        action: action
    })
}
<commit_msg>Use buffered writers as output to improve performance<commit_after>use std::io::{BufRead, Read, Write, self};
use std::fs::File;
use std::string::ToString;
use std::env;

mod label;
mod parser;
mod interpreter;
mod assembler;
use interpreter::{Interpreter, Program};

#[derive(Debug, Clone)]
struct Args {
    program: String,        // this is where we read the program from.
    input: Option<String>,  // this is where we read input for the program from. if None, stdin
    output: Option<String>, // this is where we output data to. if None, stdin
    format: FileFormat,     // format of input file. default is Whitespace
    action: Action          // output format. translate or execute.
}

#[derive(Debug, Clone)]
enum FileFormat {
    Whitespace,
    Assembly
}

#[derive(Debug, Clone)]
enum Action {
    Translate,
    Execute
}

fn main() {
    match console_main() {
        Ok(()) => (),
        Err(s) => write!(io::stderr(), "{}\n", s).unwrap()
    }
}

fn console_main() -> Result<(), String> {
    let args = try!(parse_args());

    let data = {
        let mut file = try!(File::open(&args.program).map_err(|e| e.to_string()));

        let mut data = String::new();

        try!(file.read_to_string(&mut data).map_err(|e| e.to_string()));

        data
    };

    let program = try!(match args.format {
        FileFormat::Whitespace => Program::parse(data.as_bytes()),
        FileFormat::Assembly => Program::assemble(&data)
    });

    let mut output: Box<Write> = if let Some(path) = args.output {
        Box::new(io::BufWriter::new(
            try!(File::create(&path).map_err(|e| e.to_string()))
        ))
    } else {
        Box::new(io::BufWriter::new(
            io::stdout()
        ))
    };

    match args.action {
        Action::Translate => try!(
            match args.format {
                FileFormat::Whitespace => output.write_all(program.disassemble().as_bytes()),
                FileFormat::Assembly   => output.write_all(program.dump().as_slice())
            }.map_err(|e| e.to_string())
        ),
        Action::Execute => {
            let input: Box<BufRead> = if let Some(path) = args.input {
                Box::new(io::BufReader::new(
                    try!(File::open(&path).map_err(|e| e.to_string()))
                ))
            } else {
                Box::new(io::BufReader::new(
                    io::stdin()
                ))
            };
            let mut interpreter = Interpreter::new(program, input, output);
            try!(interpreter.run());
        }
    }
    Ok(())
}

macro_rules! try_opt {
    ($o:expr, $e:expr) => (
        match $o {
            Some(x) => x,
            None => return Err($e)
        }
    )
}

fn parse_args() -> Result<Args, String> {;
    let mut input = None;
    let mut output = None;
    let mut format = None;
    let mut action = Action::Execute;

    let mut args = env::args();
    let mut pos_args = Vec::new();
    // discard executable name
    args.next();

    // sort out args and kwargs (also parsing kwargs)
    loop {
        match args.next() {
            Some(arg) => match arg.as_ref() {
                "-i" | "--input" => if let Some(_) = input {
                    return Err("Option --input was specified twice".to_string());
                } else {
                    input = Some(try_opt!(args.next(), "Missing argument to --input".to_string()));
                },
                "-o" | "--output" => if let Some(_) = output {
                    return Err("Option --output was specified twice".to_string());
                } else {
                    output = Some(try_opt!(args.next(), "Missing argument to --output".to_string()));
                },
                "-f" | "--format" => if let Some(_) = format {
                    return Err("Option --format was specified twice".to_string());
                } else {
                    format = match try_opt!(args.next(), "Missing argument to --format".to_string()).as_ref() {
                        "whitespace" | "ws" => Some(FileFormat::Whitespace),
                        "assembly" | "asm"  => Some(FileFormat::Assembly),
                        f => return Err(format!("Unrecognized input format {}", f))
                    };
                },
                "-t" | "--translate" => if let Action::Translate = action {
                    return Err("Option --translate was specified twice".to_string())
                } else {
                    action = Action::Translate;
                },
                "--" => {
                    pos_args.extend(args);
                    break;
                },
                _ => if arg.chars().next() == Some('-') {
                    return Err(format!("Unrecognized option {}", arg));
                } else {
                    pos_args.push(arg);
                }
            },
            None => break
        }
    }

    // parse positional args
    let mut pos_args = pos_args.into_iter();
    let program = try_opt!(pos_args.next(), "Missing required positional argument 'program'".to_string());
    if let Some(x) = pos_args.next() {
        return Err(format!("Unexpected positional argument {}", x));
    }

    return Ok(Args {
        program: program,
        input: input,
        output: output,
        format: format.unwrap_or(FileFormat::Whitespace),
        action: action
    })
}
<|endoftext|>