<commit_before>extern crate pwx;
extern crate docopt;
extern crate rustc_serialize;
extern crate uuid;

use pwx::{Pwx,PwxFieldIterator, Field};
use std::io::{Write,stderr};
use std::process::exit;
use std::path::PathBuf;
use docopt::Docopt;
use uuid::Uuid;
use pwx::util::{fuzzy_eq, from_time_t, abspath, get_password_from_user};
use std::str::from_utf8;

// Get pkg version at compile time
const VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_file: String,
    arg_fieldname: String,
    arg_uuid: String,
    arg_filter: Vec<String>,
    flag_url: String,
    flag_group: String,
    flag_username: String,
    flag_title: String,
    flag_quiet: bool,
    cmd_count: bool,
    cmd_list: bool,
    cmd_get: bool,
    cmd_info: bool,
    flag_version: bool,
    flag_pass_interactive: bool,
    flag_no_pinentry: bool,
}

/// Get password
/// 1. If --pass-interactive read from console
/// 2. If PWX_PASSWORD is set use it
/// 3. Otherwise read from console
///
/// This function may panic on encoding issues
fn get_password(args: &Args, description: &str) -> Option<String> {
    let var = std::env::var("PWX_PASSWORD");
    if args.flag_pass_interactive || !var.is_ok() {
        get_password_from_user(description, args.flag_no_pinentry)
    } else {
        Some(var.unwrap())
    }
}

/// A filter to match multiple keywords
///
/// The default state is for the filter to be unmatched.
/// Push content with 'push()', if it matches the keywords
/// the filter will match.
struct KeywordFilter<'a> {
    m_filter: Vec<bool>,
    args: &'a Args,
}

impl<'a> KeywordFilter<'a> {
    fn new(args: &Args) -> KeywordFilter {
        let mut f = KeywordFilter {
            m_filter: Vec::with_capacity(args.arg_filter.len()),
            args: args,
        };
        f.m_filter.resize(args.arg_filter.len(), false);
        f
    }

    /// Attempt to match this filter against a field
    fn push(&mut self, field: &Field) {
        let utf8 = match *field {
            Field::Group(ref v) => from_utf8(v),
            Field::Title(ref v) => from_utf8(v),
            Field::Username(ref v) => from_utf8(v),
            Field::Notes(ref v) => from_utf8(v),
            Field::Password(_) => return,
            Field::Url(ref v) => from_utf8(v),
            _ => return,
        };

        if let Ok(s) = utf8 {
            for (idx, word) in self.args.arg_filter.iter()
                    .enumerate() {
                self.m_filter[idx] = self.m_filter[idx] || fuzzy_eq(&word, s);
            }
        }
    }

    /// Returns true if all the keywords matched
    fn matched(&self) -> bool {
        self.m_filter.iter().all(|v| *v)
    }
}

fn real_main() -> i32 {

    let args: Args = Docopt::new(include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/doc/pwx.docopt")))
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("pwx {}", VERSION);
        return 0;
    }

    // The password safe is one of
    // 1. Command line [<file>]
    // 2. PWX_DATABASE env var
    // 3. ~/.pwsafe/psafe.psafe3
    let env_db = std::env::var("PWX_DATABASE").unwrap_or(String::new());

    let mut path = if !args.arg_file.is_empty() {
        PathBuf::from(&args.arg_file)
    } else if !env_db.is_empty() {
        PathBuf::from(&env_db)
    } else {
        std::env::home_dir().expect("Cannot find your HOME path")
            .join(".pwsafe").join("pwsafe.psafe3")
    };

    path = match abspath(&path) {
        Ok(abs) => abs,
        Err(_) => path,
    };

    // FIXME: PathBuf::exists is still Unstable, but we need to verify
    // if the file exists before prompting for password
    match std::fs::File::open(&path) {
        Err(err) => {
            let _ = writeln!(stderr(), "{}: {}", path.to_string_lossy(), err);
            return -1;
        },
        _ => (),
    }

    path = match abspath(&path) {
        Ok(abs) => abs,
        Err(_) => path,
    };

    let description = format!("Opening {}", path.to_string_lossy());
    let mut p = match Pwx::open(&path, get_password(&args, &description).expect("Unable to get user password").as_bytes()) {
        Err(f) => {
            let _ = writeln!(stderr(), "Error: {} {}", f, path.to_string_lossy());
            exit(-1);
        },
        Ok(p) => p,
    };

    if !p.is_authentic() {
        return -1;
    }

    if args.cmd_list || args.cmd_count {
        let mut count = 0;

        for record in p.iter().unwrap() {
            let mut uuid = String::new();
            let mut title = String::new();
            let mut username = String::new();

            // Field filters
            let mut f_username = args.flag_username.is_empty();
            let mut f_title = args.flag_title.is_empty();
            let mut f_url = args.flag_url.is_empty();
            let mut f_group = args.flag_group.is_empty();

            // Keyword filters
            let mut f_keywords = KeywordFilter::new(&args);

            for field in record {
                f_keywords.push(&field);
                match field {
                    Field::Uuid(_) => uuid = format!("{}", field),
                    Field::Title(_) => {
                        title = format!("{}", field);
                        f_title = f_title || fuzzy_eq(&args.flag_title, &title);
                    }
                    Field::Username(_) => {
                        username = format!("{}", field);
                        f_username = f_username || fuzzy_eq(&args.flag_username, &username);
                    }
                    Field::Url(_) => {
                        let url = format!("{}", field);
                        f_url = f_url || fuzzy_eq(&args.flag_url, &url);
                    }
                    Field::Group(_) => {
                        let group = format!("{}", field);
                        f_group = f_group || fuzzy_eq(&args.flag_group, &group);
                    }
                    _ => (),
                }
            }

            if !f_username || !f_title || !f_url || !f_group {
                // Skip, record filter did not match
                continue;
            }

            if !f_keywords.matched() {
                // Skip, generic keyword filter did not match
                continue;
            }

            if args.cmd_count {
                count += 1;
            } else {
                println!("{} {}[{}]", uuid, title, username);
            }
        }

        if args.cmd_count {
            println!("{}", count);
        }
    } else if args.cmd_info {

        let fields = PwxFieldIterator::new(&mut p).unwrap();
        for (typ,val) in fields {
            match typ {
                0x01 => print!("{} ", Uuid::from_bytes(val.as_ref())
                               .unwrap_or(Uuid::nil())
                               .hyphenated().to_string()),
                0x04 => print!("{} ", from_time_t(val.as_ref())
                                 .expect("Invalid time_t field contents")),
                0x07 => print!("{} ", String::from_utf8_lossy(val.as_ref())),
                0x08 => println!("@{} ", String::from_utf8_lossy(val.as_ref())),
                0x09 => println!("{} ", String::from_utf8_lossy(val.as_ref())),
                0x0a => println!("\"{}\" ", String::from_utf8_lossy(val.as_ref())),
                0xff => break,
                _ => (),
            }
        }
    } else if args.cmd_get {
        let get_uuid = Field::Uuid(Uuid::parse_str(&args.arg_uuid).expect("Invalid UUID").as_bytes().to_vec());

        for record in p.iter().unwrap() {
            // Find record by UUID
            let mut found = false;
            for field in &record {
                if *field == get_uuid {
                    found = true;
                    break;
                }
            }

            if !found {
                continue;
            }

            // Get field value
            for field in &record {
                if let Some(name) = field.name() {
                    if name == args.arg_fieldname {
                        println!("{}", field);
                        return 0;
                    }
                }
            }
            let _ = writeln!(stderr(), "Unknown field: {}", args.arg_fieldname);
        }

        let _ = writeln!(stderr(), "Unknown record: {}", args.arg_uuid);
        return -1;
    }

    return 0
}

// Rust set_exit_status cannot be used yet, the only way to
// set an exit code to exit using exit(code) so we wrap the
// main function like this
fn main() {
    let exit_code = real_main();
    exit(exit_code);
}

<commit_msg>Correct command about main()<commit_after>extern crate pwx;
extern crate docopt;
extern crate rustc_serialize;
extern crate uuid;

use pwx::{Pwx,PwxFieldIterator, Field};
use std::io::{Write,stderr};
use std::process::exit;
use std::path::PathBuf;
use docopt::Docopt;
use uuid::Uuid;
use pwx::util::{fuzzy_eq, from_time_t, abspath, get_password_from_user};
use std::str::from_utf8;

// Get pkg version at compile time
const VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_file: String,
    arg_fieldname: String,
    arg_uuid: String,
    arg_filter: Vec<String>,
    flag_url: String,
    flag_group: String,
    flag_username: String,
    flag_title: String,
    flag_quiet: bool,
    cmd_count: bool,
    cmd_list: bool,
    cmd_get: bool,
    cmd_info: bool,
    flag_version: bool,
    flag_pass_interactive: bool,
    flag_no_pinentry: bool,
}

/// Get password
/// 1. If --pass-interactive read from console
/// 2. If PWX_PASSWORD is set use it
/// 3. Otherwise read from console
///
/// This function may panic on encoding issues
fn get_password(args: &Args, description: &str) -> Option<String> {
    let var = std::env::var("PWX_PASSWORD");
    if args.flag_pass_interactive || !var.is_ok() {
        get_password_from_user(description, args.flag_no_pinentry)
    } else {
        Some(var.unwrap())
    }
}

/// A filter to match multiple keywords
///
/// The default state is for the filter to be unmatched.
/// Push content with 'push()', if it matches the keywords
/// the filter will match.
struct KeywordFilter<'a> {
    m_filter: Vec<bool>,
    args: &'a Args,
}

impl<'a> KeywordFilter<'a> {
    fn new(args: &Args) -> KeywordFilter {
        let mut f = KeywordFilter {
            m_filter: Vec::with_capacity(args.arg_filter.len()),
            args: args,
        };
        f.m_filter.resize(args.arg_filter.len(), false);
        f
    }

    /// Attempt to match this filter against a field
    fn push(&mut self, field: &Field) {
        let utf8 = match *field {
            Field::Group(ref v) => from_utf8(v),
            Field::Title(ref v) => from_utf8(v),
            Field::Username(ref v) => from_utf8(v),
            Field::Notes(ref v) => from_utf8(v),
            Field::Password(_) => return,
            Field::Url(ref v) => from_utf8(v),
            _ => return,
        };

        if let Ok(s) = utf8 {
            for (idx, word) in self.args.arg_filter.iter()
                    .enumerate() {
                self.m_filter[idx] = self.m_filter[idx] || fuzzy_eq(&word, s);
            }
        }
    }

    /// Returns true if all the keywords matched
    fn matched(&self) -> bool {
        self.m_filter.iter().all(|v| *v)
    }
}

fn real_main() -> i32 {

    let args: Args = Docopt::new(include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/doc/pwx.docopt")))
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("pwx {}", VERSION);
        return 0;
    }

    // The password safe is one of
    // 1. Command line [<file>]
    // 2. PWX_DATABASE env var
    // 3. ~/.pwsafe/psafe.psafe3
    let env_db = std::env::var("PWX_DATABASE").unwrap_or(String::new());

    let mut path = if !args.arg_file.is_empty() {
        PathBuf::from(&args.arg_file)
    } else if !env_db.is_empty() {
        PathBuf::from(&env_db)
    } else {
        std::env::home_dir().expect("Cannot find your HOME path")
            .join(".pwsafe").join("pwsafe.psafe3")
    };

    path = match abspath(&path) {
        Ok(abs) => abs,
        Err(_) => path,
    };

    // FIXME: PathBuf::exists is still Unstable, but we need to verify
    // if the file exists before prompting for password
    match std::fs::File::open(&path) {
        Err(err) => {
            let _ = writeln!(stderr(), "{}: {}", path.to_string_lossy(), err);
            return -1;
        },
        _ => (),
    }

    path = match abspath(&path) {
        Ok(abs) => abs,
        Err(_) => path,
    };

    let description = format!("Opening {}", path.to_string_lossy());
    let mut p = match Pwx::open(&path, get_password(&args, &description).expect("Unable to get user password").as_bytes()) {
        Err(f) => {
            let _ = writeln!(stderr(), "Error: {} {}", f, path.to_string_lossy());
            exit(-1);
        },
        Ok(p) => p,
    };

    if !p.is_authentic() {
        return -1;
    }

    if args.cmd_list || args.cmd_count {
        let mut count = 0;

        for record in p.iter().unwrap() {
            let mut uuid = String::new();
            let mut title = String::new();
            let mut username = String::new();

            // Field filters
            let mut f_username = args.flag_username.is_empty();
            let mut f_title = args.flag_title.is_empty();
            let mut f_url = args.flag_url.is_empty();
            let mut f_group = args.flag_group.is_empty();

            // Keyword filters
            let mut f_keywords = KeywordFilter::new(&args);

            for field in record {
                f_keywords.push(&field);
                match field {
                    Field::Uuid(_) => uuid = format!("{}", field),
                    Field::Title(_) => {
                        title = format!("{}", field);
                        f_title = f_title || fuzzy_eq(&args.flag_title, &title);
                    }
                    Field::Username(_) => {
                        username = format!("{}", field);
                        f_username = f_username || fuzzy_eq(&args.flag_username, &username);
                    }
                    Field::Url(_) => {
                        let url = format!("{}", field);
                        f_url = f_url || fuzzy_eq(&args.flag_url, &url);
                    }
                    Field::Group(_) => {
                        let group = format!("{}", field);
                        f_group = f_group || fuzzy_eq(&args.flag_group, &group);
                    }
                    _ => (),
                }
            }

            if !f_username || !f_title || !f_url || !f_group {
                // Skip, record filter did not match
                continue;
            }

            if !f_keywords.matched() {
                // Skip, generic keyword filter did not match
                continue;
            }

            if args.cmd_count {
                count += 1;
            } else {
                println!("{} {}[{}]", uuid, title, username);
            }
        }

        if args.cmd_count {
            println!("{}", count);
        }
    } else if args.cmd_info {

        let fields = PwxFieldIterator::new(&mut p).unwrap();
        for (typ,val) in fields {
            match typ {
                0x01 => print!("{} ", Uuid::from_bytes(val.as_ref())
                               .unwrap_or(Uuid::nil())
                               .hyphenated().to_string()),
                0x04 => print!("{} ", from_time_t(val.as_ref())
                                 .expect("Invalid time_t field contents")),
                0x07 => print!("{} ", String::from_utf8_lossy(val.as_ref())),
                0x08 => println!("@{} ", String::from_utf8_lossy(val.as_ref())),
                0x09 => println!("{} ", String::from_utf8_lossy(val.as_ref())),
                0x0a => println!("\"{}\" ", String::from_utf8_lossy(val.as_ref())),
                0xff => break,
                _ => (),
            }
        }
    } else if args.cmd_get {
        let get_uuid = Field::Uuid(Uuid::parse_str(&args.arg_uuid).expect("Invalid UUID").as_bytes().to_vec());

        for record in p.iter().unwrap() {
            // Find record by UUID
            let mut found = false;
            for field in &record {
                if *field == get_uuid {
                    found = true;
                    break;
                }
            }

            if !found {
                continue;
            }

            // Get field value
            for field in &record {
                if let Some(name) = field.name() {
                    if name == args.arg_fieldname {
                        println!("{}", field);
                        return 0;
                    }
                }
            }
            let _ = writeln!(stderr(), "Unknown field: {}", args.arg_fieldname);
        }

        let _ = writeln!(stderr(), "Unknown record: {}", args.arg_uuid);
        return -1;
    }

    return 0
}

// We want to make sure we exit only after all the destructors
// are called, wait for real_main() to be done before actually
// calling exit.
fn main() {
    let exit_code = real_main();
    exit(exit_code);
}

<|endoftext|>


<commit_before>pub static BLOCK_BYTES : uint = 64;
pub static OUT_BYTES   : uint = 32;
pub static KEY_BYTES   : uint = 32;

static IV : [u32, ..8] = [
    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
    0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
];

static SIGMA : [[u8, ..16], ..10] = [
    [  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 ],
    [ 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 ],
    [ 11,  8, 12,  0,  5,  2, 15, 13, 10, 14,  3,  6,  7,  1,  9,  4 ],
    [  7,  9,  3,  1, 13, 12, 11, 14,  2,  6,  5, 10,  4,  0, 15,  8 ],
    [  9,  0,  5,  7,  2,  4, 10, 15, 14,  1, 11, 12,  6,  8,  3, 13 ],
    [  2, 12,  6, 10,  0, 11,  8,  3,  4, 13,  7,  5, 15, 14,  1,  9 ],
    [ 12,  5,  1, 15, 14, 13,  4, 10,  0,  7,  6,  3,  9,  2,  8, 11 ],
    [ 13, 11,  7, 14, 12,  1,  3,  9,  5,  0, 15,  4,  8,  6,  2, 10 ],
    [  6, 15, 14,  9, 11,  3,  0,  8, 12,  2, 13,  7,  1,  4, 10,  5 ],
    [ 10,  2,  8,  4,  7,  6,  1,  5, 15, 11,  9, 14,  3, 12, 13 , 0 ],
];

pub struct Blake2s {
    h: [u32, ..8],
    t: [u32, ..2],
    f: [u32, ..2],
    buf: [u8, ..2*BLOCK_BYTES],
    buf_len: uint,
}

impl Blake2s {
    pub fn new(size: uint) -> Blake2s {
        assert!(size > 0 && size <= OUT_BYTES);

        let param = encode_params(size as u8, 0);
        let mut state = IV;

        for i in range(0, state.len()) {
            state[i] ^= load32(param.slice_from(i*4));
        }

        Blake2s{
            h: state,
            t: [0, 0],
            f: [0, 0],
            buf: [0u8, ..2*BLOCK_BYTES],
            buf_len: 0,
        }
    }

    pub fn new_with_key(size: uint, key: &[u8]) -> Blake2s {
        assert!(size > 0 && size <= OUT_BYTES);
        assert!(key.len() > 0 && key.len() <= KEY_BYTES);

        let param = encode_params(size as u8, key.len() as u8);
        let mut state = IV;

        for i in range(0, state.len()) {
            state[i] ^= load32(param.slice_from(i*4));
        }

        let mut b = Blake2s{
            h: state,
            t: [0, 0],
            f: [0, 0],
            buf: [0u8, ..2*BLOCK_BYTES],
            buf_len: 0,
        };

        let mut block = [0u8, ..BLOCK_BYTES];
        for i in range(0, key.len()) {
            block[i] = key[i];
        }
        b.update(block.as_slice());
        b
    }

    pub fn update(&mut self, m: &[u8]) {
        let mut m = m;

        while m.len() > 0 {
            let left = self.buf_len;
            let fill = 2 * BLOCK_BYTES - left;

            if m.len() > fill {
                for i in range(0, fill) {
                    self.buf[left+i] = m[i];
                }
                self.buf_len += fill;
                m = m.slice_from(fill);
                self.increment_counter(BLOCK_BYTES as u32);
                self.compress();
                for i in range(0, BLOCK_BYTES) {
                    self.buf[i] = self.buf[i+BLOCK_BYTES];
                }
                self.buf_len -= BLOCK_BYTES;
            } else {
                for i in range(0, m.len()) {
                    self.buf[left+i] = m[i];
                }
                self.buf_len += m.len();
                m = m.slice_from(m.len());
            }
        }
    }

    pub fn final(&mut self, out: &mut [u8]) {
        let mut buf = [0u8, ..OUT_BYTES];
        if self.buf_len > BLOCK_BYTES {
            self.increment_counter(BLOCK_BYTES as u32);
            self.compress();
            for i in range(0, BLOCK_BYTES) {
                self.buf[i] = self.buf[i+BLOCK_BYTES];
            }
            self.buf_len -= BLOCK_BYTES;
        }
        let n = self.buf_len as u32;
        self.increment_counter(n);
        self.f[0] = !0;
        for i in range(self.buf_len, self.buf.len()) {
            self.buf[i] = 0;
        }
        self.compress();
        for i in range(0, self.h.len()) {
            store32(buf.mut_slice_from(i*4), self.h[i]);
        }

        for i in range(0, ::std::cmp::min(out.len(), OUT_BYTES)) {
            out[i] = buf[i];
        }
    }

    fn increment_counter(&mut self, inc: u32) {
        self.t[0] += inc;
        self.t[1] += if self.t[0] < inc {1} else {0};
    }

    fn compress(&mut self) {
        let mut m = [0u32, ..16];
        let mut v = [0u32, ..16];
        let block = self.buf.as_slice();

        assert!(block.len() >= BLOCK_BYTES);

        for i in range(0, m.len()) {
            m[i] = load32(block.slice_from(i*4));
        }

        for i in range(0, 8) {
            v[i] = self.h[i];
        }

        v[ 8] = IV[0];
        v[ 9] = IV[1];
        v[10] = IV[2];
        v[11] = IV[3];
        v[12] = self.t[0] ^ IV[4];
        v[13] = self.t[1] ^ IV[5];
        v[14] = self.f[0] ^ IV[6];
        v[15] = self.f[1] ^ IV[7];

        macro_rules! g(
            ($r: expr, $i: expr, $a: expr, $b: expr, $c: expr, $d: expr) => ({
                $a = $a + $b + m[SIGMA[$r][2*$i+0] as uint];
                $d = ($d ^ $a).rotate_right(16);
                $c = $c + $d;
                $b = ($b ^ $c).rotate_right(12);
                $a = $a + $b + m[SIGMA[$r][2*$i+1] as uint];
                $d = ($d ^ $a).rotate_right(8);
                $c = $c + $d;
                $b = ($b ^ $c).rotate_right(7);
            });
        )

        macro_rules! round(
            ($r: expr) => ({
                g!($r, 0, v[ 0], v[ 4], v[ 8], v[12]);
                g!($r, 1, v[ 1], v[ 5], v[ 9], v[13]);
                g!($r, 2, v[ 2], v[ 6], v[10], v[14]);
                g!($r, 3, v[ 3], v[ 7], v[11], v[15]);
                g!($r, 4, v[ 0], v[ 5], v[10], v[15]);
                g!($r, 5, v[ 1], v[ 6], v[11], v[12]);
                g!($r, 6, v[ 2], v[ 7], v[ 8], v[13]);
                g!($r, 7, v[ 3], v[ 4], v[ 9], v[14]);
            });
        )

        for i in range(0, 10) {
            round!(i);
        }

        for i in range(0, 8) {
            self.h[i] = self.h[i] ^ v[i] ^ v[i+8];
        }
    }
}

fn encode_params(size: u8, keylen: u8) -> [u8, ..64] {
    let mut param = [0u8, ..64];
    param[0] = size as u8;
    param[1] = keylen as u8;
    param[2] = 1; // fanout
    param[3] = 1; // depth
    param
}

fn load32(b: &[u8]) -> u32{
    let mut v = 0u32;
    for i in range(0, 4) {
        v |= b[i] as u32 << (8*i);
    }
    v
}

fn store32(b: &mut [u8], v: u32) {
    let mut w = v;
    for i in range(0, 4) {
        b[i] = w as u8;
        w >>= 8;
    }
}

#[cfg(test)]
mod tests {
    use super::{Blake2s, KEY_BYTES, OUT_BYTES};

    mod kat;

    #[test]
    fn test_blake2s_kat() {
        let mut input = [0u8, ..256];
        for i in range(0, input.len()) {
            input[i] = i as u8;
        }

        for i in range(0, kat::blake2s_kat.len()) {
            let mut h = Blake2s::new(OUT_BYTES);
            let mut out = [0u8, ..OUT_BYTES];
            h.update(input.slice(0, i));
            h.final(out);
            assert_eq!(out.as_slice(), kat::blake2s_kat[i].as_slice());
        }
    }

    #[test]
    fn test_blake2s_keyed_kat() {
        let mut input = [0u8, ..256];
        let mut key = [0u8, ..KEY_BYTES];

        for i in range(0, input.len()) {
            input[i] = i as u8;
        }

        for i in range(0, key.len()) {
            key[i] = i as u8;
        }

        for i in range(0, kat::blake2s_keyed_kat.len()) {
            let mut h = Blake2s::new_with_key(OUT_BYTES, key.as_slice());
            let mut out = [0u8, ..OUT_BYTES];
            h.update(input.slice(0, i));
            h.final(out);
            assert_eq!(out.as_slice(), kat::blake2s_keyed_kat[i].as_slice());
        }
    }
}
<commit_msg>add blake2s benchmarks<commit_after>pub static BLOCK_BYTES : uint = 64;
pub static OUT_BYTES   : uint = 32;
pub static KEY_BYTES   : uint = 32;

static IV : [u32, ..8] = [
    0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
    0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
];

static SIGMA : [[u8, ..16], ..10] = [
    [  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 ],
    [ 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 ],
    [ 11,  8, 12,  0,  5,  2, 15, 13, 10, 14,  3,  6,  7,  1,  9,  4 ],
    [  7,  9,  3,  1, 13, 12, 11, 14,  2,  6,  5, 10,  4,  0, 15,  8 ],
    [  9,  0,  5,  7,  2,  4, 10, 15, 14,  1, 11, 12,  6,  8,  3, 13 ],
    [  2, 12,  6, 10,  0, 11,  8,  3,  4, 13,  7,  5, 15, 14,  1,  9 ],
    [ 12,  5,  1, 15, 14, 13,  4, 10,  0,  7,  6,  3,  9,  2,  8, 11 ],
    [ 13, 11,  7, 14, 12,  1,  3,  9,  5,  0, 15,  4,  8,  6,  2, 10 ],
    [  6, 15, 14,  9, 11,  3,  0,  8, 12,  2, 13,  7,  1,  4, 10,  5 ],
    [ 10,  2,  8,  4,  7,  6,  1,  5, 15, 11,  9, 14,  3, 12, 13 , 0 ],
];

pub struct Blake2s {
    h: [u32, ..8],
    t: [u32, ..2],
    f: [u32, ..2],
    buf: [u8, ..2*BLOCK_BYTES],
    buf_len: uint,
}

impl Blake2s {
    pub fn new(size: uint) -> Blake2s {
        assert!(size > 0 && size <= OUT_BYTES);

        let param = encode_params(size as u8, 0);
        let mut state = IV;

        for i in range(0, state.len()) {
            state[i] ^= load32(param.slice_from(i*4));
        }

        Blake2s{
            h: state,
            t: [0, 0],
            f: [0, 0],
            buf: [0u8, ..2*BLOCK_BYTES],
            buf_len: 0,
        }
    }

    pub fn new_with_key(size: uint, key: &[u8]) -> Blake2s {
        assert!(size > 0 && size <= OUT_BYTES);
        assert!(key.len() > 0 && key.len() <= KEY_BYTES);

        let param = encode_params(size as u8, key.len() as u8);
        let mut state = IV;

        for i in range(0, state.len()) {
            state[i] ^= load32(param.slice_from(i*4));
        }

        let mut b = Blake2s{
            h: state,
            t: [0, 0],
            f: [0, 0],
            buf: [0u8, ..2*BLOCK_BYTES],
            buf_len: 0,
        };

        let mut block = [0u8, ..BLOCK_BYTES];
        for i in range(0, key.len()) {
            block[i] = key[i];
        }
        b.update(block.as_slice());
        b
    }

    pub fn update(&mut self, m: &[u8]) {
        let mut m = m;

        while m.len() > 0 {
            let left = self.buf_len;
            let fill = 2 * BLOCK_BYTES - left;

            if m.len() > fill {
                for i in range(0, fill) {
                    self.buf[left+i] = m[i];
                }
                self.buf_len += fill;
                m = m.slice_from(fill);
                self.increment_counter(BLOCK_BYTES as u32);
                self.compress();
                for i in range(0, BLOCK_BYTES) {
                    self.buf[i] = self.buf[i+BLOCK_BYTES];
                }
                self.buf_len -= BLOCK_BYTES;
            } else {
                for i in range(0, m.len()) {
                    self.buf[left+i] = m[i];
                }
                self.buf_len += m.len();
                m = m.slice_from(m.len());
            }
        }
    }

    pub fn final(&mut self, out: &mut [u8]) {
        let mut buf = [0u8, ..OUT_BYTES];
        if self.buf_len > BLOCK_BYTES {
            self.increment_counter(BLOCK_BYTES as u32);
            self.compress();
            for i in range(0, BLOCK_BYTES) {
                self.buf[i] = self.buf[i+BLOCK_BYTES];
            }
            self.buf_len -= BLOCK_BYTES;
        }
        let n = self.buf_len as u32;
        self.increment_counter(n);
        self.f[0] = !0;
        for i in range(self.buf_len, self.buf.len()) {
            self.buf[i] = 0;
        }
        self.compress();
        for i in range(0, self.h.len()) {
            store32(buf.mut_slice_from(i*4), self.h[i]);
        }

        for i in range(0, ::std::cmp::min(out.len(), OUT_BYTES)) {
            out[i] = buf[i];
        }
    }

    fn increment_counter(&mut self, inc: u32) {
        self.t[0] += inc;
        self.t[1] += if self.t[0] < inc {1} else {0};
    }

    fn compress(&mut self) {
        let mut m = [0u32, ..16];
        let mut v = [0u32, ..16];
        let block = self.buf.as_slice();

        assert!(block.len() >= BLOCK_BYTES);

        for i in range(0, m.len()) {
            m[i] = load32(block.slice_from(i*4));
        }

        for i in range(0, 8) {
            v[i] = self.h[i];
        }

        v[ 8] = IV[0];
        v[ 9] = IV[1];
        v[10] = IV[2];
        v[11] = IV[3];
        v[12] = self.t[0] ^ IV[4];
        v[13] = self.t[1] ^ IV[5];
        v[14] = self.f[0] ^ IV[6];
        v[15] = self.f[1] ^ IV[7];

        macro_rules! g(
            ($r: expr, $i: expr, $a: expr, $b: expr, $c: expr, $d: expr) => ({
                $a = $a + $b + m[SIGMA[$r][2*$i+0] as uint];
                $d = ($d ^ $a).rotate_right(16);
                $c = $c + $d;
                $b = ($b ^ $c).rotate_right(12);
                $a = $a + $b + m[SIGMA[$r][2*$i+1] as uint];
                $d = ($d ^ $a).rotate_right(8);
                $c = $c + $d;
                $b = ($b ^ $c).rotate_right(7);
            });
        )

        macro_rules! round(
            ($r: expr) => ({
                g!($r, 0, v[ 0], v[ 4], v[ 8], v[12]);
                g!($r, 1, v[ 1], v[ 5], v[ 9], v[13]);
                g!($r, 2, v[ 2], v[ 6], v[10], v[14]);
                g!($r, 3, v[ 3], v[ 7], v[11], v[15]);
                g!($r, 4, v[ 0], v[ 5], v[10], v[15]);
                g!($r, 5, v[ 1], v[ 6], v[11], v[12]);
                g!($r, 6, v[ 2], v[ 7], v[ 8], v[13]);
                g!($r, 7, v[ 3], v[ 4], v[ 9], v[14]);
            });
        )

        for i in range(0, 10) {
            round!(i);
        }

        for i in range(0, 8) {
            self.h[i] = self.h[i] ^ v[i] ^ v[i+8];
        }
    }
}

fn encode_params(size: u8, keylen: u8) -> [u8, ..64] {
    let mut param = [0u8, ..64];
    param[0] = size as u8;
    param[1] = keylen as u8;
    param[2] = 1; // fanout
    param[3] = 1; // depth
    param
}

fn load32(b: &[u8]) -> u32{
    let mut v = 0u32;
    for i in range(0, 4) {
        v |= b[i] as u32 << (8*i);
    }
    v
}

fn store32(b: &mut [u8], v: u32) {
    let mut w = v;
    for i in range(0, 4) {
        b[i] = w as u8;
        w >>= 8;
    }
}

#[cfg(test)]
mod tests {
    use super::{Blake2s, KEY_BYTES, OUT_BYTES};

    mod kat;

    #[test]
    fn test_blake2s_kat() {
        let mut input = [0u8, ..256];
        for i in range(0, input.len()) {
            input[i] = i as u8;
        }

        for i in range(0, kat::blake2s_kat.len()) {
            let mut h = Blake2s::new(OUT_BYTES);
            let mut out = [0u8, ..OUT_BYTES];
            h.update(input.slice(0, i));
            h.final(out);
            assert_eq!(out.as_slice(), kat::blake2s_kat[i].as_slice());
        }
    }

    #[test]
    fn test_blake2s_keyed_kat() {
        let mut input = [0u8, ..256];
        let mut key = [0u8, ..KEY_BYTES];

        for i in range(0, input.len()) {
            input[i] = i as u8;
        }

        for i in range(0, key.len()) {
            key[i] = i as u8;
        }

        for i in range(0, kat::blake2s_keyed_kat.len()) {
            let mut h = Blake2s::new_with_key(OUT_BYTES, key.as_slice());
            let mut out = [0u8, ..OUT_BYTES];
            h.update(input.slice(0, i));
            h.final(out);
            assert_eq!(out.as_slice(), kat::blake2s_keyed_kat[i].as_slice());
        }
    }
}

#[cfg(test)]
mod bench {
    use super::{Blake2s, OUT_BYTES};
    use test::Bencher;

    fn bench_chunk_size(b: &mut Bencher, n: uint) {
        let mut h = Blake2s::new(OUT_BYTES);
        let input = Vec::from_elem(n, 0);
        b.bytes = input.len() as u64;
        b.iter(|| {
            h.update(input.as_slice());
        });
    }

    #[bench]
    fn bench_blake2s_16(b: &mut Bencher) {
        bench_chunk_size(b, 16);
    }

    #[bench]
    fn bench_blake2s_1k(b: &mut Bencher) {
        bench_chunk_size(b, 1 << 10);
    }

    #[bench]
    fn bench_blake2s_64k(b: &mut Bencher) {
        bench_chunk_size(b, 1 << 16);
    }
}
<|endoftext|>


<commit_before>// CIA
#![allow(dead_code)]
use c64::cpu;
use c64::vic;
use c64::memory;
use std::rc::Rc;
use std::cell::RefCell;

pub type CIAShared = Rc<RefCell<CIA>>;

pub enum CIACallbackAction
{
    CIA_NONE,
}

enum TimerState
{
    STOP,
    WAIT_COUNT,
    LOAD_STOP,
    LOAD_COUNT,
    LOAD_WAIT_COUNT,
    COUNT,
    COUNT_STOP
}

pub struct CIA
{
    mem_ref: Option<memory::MemShared>,
    cpu_ref: Option<cpu::CPUShared>,
    vic_ref: Option<vic::VICShared>,

    ta_state: TimerState,  // timer A state
    tb_state: TimerState,  // timer B state
    ta: u16,
    tb: u16,
    ta_cnt_phi2: bool,
    tb_cnt_phi2: bool,
    tb_cnt_ta: bool,
    ta_underflow: bool,
    icr: u8,
    ta_irq_next_cycle: bool,
    tb_irq_next_cycle: bool,
    latch_a: u16,
    latch_b: u16,
    cra: u8,
    crb: u8,
    new_cra: u8,
    new_crb: u8,
    has_new_cra: bool,
    has_new_crb: bool,
}

impl CIA
{
    pub fn new_shared() -> CIAShared
    {
        Rc::new(RefCell::new(CIA
        {
            mem_ref: None,
            cpu_ref: None,
            vic_ref: None,

            ta_state: TimerState::STOP,
            tb_state: TimerState::STOP,
            ta: 0,
            tb: 0,
            ta_cnt_phi2: false,
            tb_cnt_phi2: false,
            tb_cnt_ta: false,
            ta_underflow: false,
            icr: 0,
            ta_irq_next_cycle: false,
            tb_irq_next_cycle: false,
            latch_a: 0,
            latch_b: 0,
            cra: 0,
            crb: 0,
            new_cra: 0,
            new_crb: 0,
            has_new_cra: false,
            has_new_crb: false,
        }))
    }

    pub fn set_references(&mut self, memref: memory::MemShared, cpuref: cpu::CPUShared, vicref: vic::VICShared)
    {
        self.mem_ref = Some(memref);
        self.cpu_ref = Some(cpuref);
        self.vic_ref = Some(vicref);
    }

    pub fn reset(&mut self)
    {
        // TODO
        self.ta_state = TimerState::STOP;
        self.tb_state = TimerState::STOP;
        self.ta = 0;
        self.tb = 0;
        self.ta_cnt_phi2 = false;
        self.tb_cnt_phi2 = false;
        self.tb_cnt_ta = false;
        self.ta_underflow = false;
        self.icr = 0;
        self.ta_irq_next_cycle = false;
        self.tb_irq_next_cycle = false;
        self.latch_a = 0;
        self.latch_b = 0;
        self.cra = 0;
        self.crb = 0;
        self.new_cra = 0;
        self.new_crb = 0;
        self.has_new_cra = false;
        self.has_new_crb = false;
    }

    pub fn read_register(&self, addr: u16) -> u8
    {
        // TODO
        0
    }

    pub fn write_register(&mut self, addr: u16, value: u8, on_cia_write: &mut CIACallbackAction) -> bool
    {
        // TODO
        true
    }

    pub fn update(&mut self)
    {
        self.ta_underflow = false;
        self.update_timer_a();
        self.update_timer_b();
    }

    fn update_timer_a(&mut self)
    {
        match self.ta_state
        {
            TimerState::STOP => (),
            TimerState::WAIT_COUNT => {
                self.ta_state = TimerState::COUNT;
            },
            TimerState::LOAD_STOP => {
                self.ta_state = TimerState::STOP;
                self.ta = self.latch_a;
            },
            TimerState::LOAD_COUNT => {
                self.ta_state = TimerState::COUNT;
                self.ta = self.latch_a;
            },
            TimerState::LOAD_WAIT_COUNT => {
                self.ta_state = TimerState::WAIT_COUNT;

                if self.ta == 1
                {
                    self.ta_irq();
                }
                else
                {
                    self.ta = self.latch_a;
                }
            },
            TimerState::COUNT => {
                self.ta_count();
            },
            TimerState::COUNT_STOP => {
                self.ta_state = TimerState::STOP;
                self.ta_count();
            }
        }

        self.ta_idle();
    }

    fn ta_idle(&mut self)
    {
        if self.has_new_cra
        {
            match self.ta_state
            {
                TimerState::STOP | TimerState::LOAD_STOP =>
                {
                    if (self.new_cra & 1) != 0
                    {
                        if (self.new_cra & 0x10) != 0
                        {
                            self.ta_state = TimerState::LOAD_WAIT_COUNT;
                        }
                        else
                        {
                            self.ta_state = TimerState::WAIT_COUNT;
                        }
                    }
                    else
                    {
                        if (self.new_cra & 0x10) != 0
                        {
                            self.ta_state = TimerState::LOAD_STOP;
                        }
                    }

                },
                TimerState::WAIT_COUNT | TimerState::LOAD_COUNT =>
                {
                    if (self.new_cra & 1) != 0
                    {
                        if (self.new_cra & 8) != 0
                        {
                            self.new_cra &= 0xFE;
                            self.ta_state = TimerState::STOP;
                        }
                        else
                        {
                            if (self.new_cra & 0x10) != 0
                            {
                                self.ta_state = TimerState::LOAD_WAIT_COUNT;
                            }
                        }
                    }
                    else
                    {
                        self.ta_state = TimerState::STOP;
                    }
                },
                TimerState::COUNT =>
                {
                    if (self.new_cra & 1) != 0
                    {
                        if (self.new_cra & 0x10) != 0
                        {
                            self.ta_state = TimerState::LOAD_WAIT_COUNT;
                        }
                    }
                    else
                    {
                        if (self.new_cra & 0x10) != 0
                        {
                            self.ta_state = TimerState::LOAD_STOP;
                        }
                        else
                        {
                            self.ta_state = TimerState::COUNT_STOP;
                        }
                    }
                },
                _ => (),
            }

            self.cra = self.new_cra & 0xEF;
            self.has_new_cra = false;
        }
    }

    fn ta_irq(&mut self)
    {
        self.ta = self.latch_a;
        self.ta_irq_next_cycle = true;
        self.icr |= 1;

        if (self.cra & 8) != 0
        {
            self.cra &= 0xFE;
            self.new_cra &= 0xFE;
            self.ta_state = TimerState::LOAD_STOP;
        }
        else
        {
            self.ta_state = TimerState::LOAD_COUNT;
        }
    }

    fn ta_count(&mut self)
    {
        if self.ta_cnt_phi2
        {
            let curr_ta = self.ta;
            self.ta -= 1;
            if (curr_ta == 0) || (self.ta == 0)
            {
                match self.ta_state
                {
                    TimerState::STOP => (),
                    _ => self.ta_irq(),
                }

                self.ta_underflow = true;
            }
        }
    }

    fn update_timer_b(&mut self)
    {
        match self.tb_state
        {
            TimerState::STOP => (),
            TimerState::WAIT_COUNT => {
                self.tb_state = TimerState::COUNT;
            },
            TimerState::LOAD_STOP => {
                self.tb_state = TimerState::COUNT;
                self.tb = self.latch_b;
            },
            TimerState::LOAD_COUNT => {
                self.tb_state = TimerState::COUNT;
                self.tb = self.latch_b;
            },
            TimerState::LOAD_WAIT_COUNT => {
                self.tb_state = TimerState::WAIT_COUNT;

                if self.tb == 1
                {
                    self.tb_irq();
                }
                else
                {
                    self.tb = self.latch_b;
                }
            }
            TimerState::COUNT => {
                self.tb_count();
            },
            TimerState::COUNT_STOP => {
                self.tb_state = TimerState::STOP;
                self.tb_count();
            }
        }

        self.tb_idle();
    }

    fn tb_idle(&mut self)
    {
        if self.has_new_crb
        {
            match self.tb_state
            {
                TimerState::STOP | TimerState::LOAD_STOP =>
                {
                    if (self.new_crb & 1) != 0
                    {
                        if (self.new_crb & 0x10) != 0
                        {
                            self.tb_state = TimerState::LOAD_WAIT_COUNT;
                        }
                        else
                        {
                            self.tb_state = TimerState::WAIT_COUNT;
                        }
                    }
                    else
                    {
                        if (self.new_crb & 0x10) != 0
                        {
                            self.tb_state = TimerState::LOAD_STOP;
                        }
                    }

                },
                TimerState::WAIT_COUNT | TimerState::LOAD_COUNT =>
                {
                    if (self.new_crb & 1) != 0
                    {
                        if (self.new_crb & 8) != 0
                        {
                            self.new_crb &= 0xFE;
                            self.tb_state = TimerState::STOP;
                        }
                        else
                        {
                            if (self.new_crb & 0x10) != 0
                            {
                                self.tb_state = TimerState::LOAD_WAIT_COUNT;
                            }
                        }
                    }
                    else
                    {
                        self.tb_state = TimerState::STOP;
                    }
                },
                TimerState::COUNT =>
                {
                    if (self.new_crb & 1) != 0
                    {
                        if (self.new_crb & 0x10) != 0
                        {
                            self.tb_state = TimerState::LOAD_WAIT_COUNT;
                        }
                    }
                    else
                    {
                        if (self.new_crb & 0x10) != 0
                        {
                            self.tb_state = TimerState::LOAD_STOP;
                        }
                        else
                        {
                            self.tb_state = TimerState::COUNT_STOP;
                        }
                    }
                },
                _ => (),
            }

            self.crb = self.new_crb & 0xEF;
            self.has_new_crb = false;
        }
    }

    fn tb_irq(&mut self)
    {
        self.tb = self.latch_b;
        self.tb_irq_next_cycle = true;
        self.icr |= 2;

        if (self.crb & 8) != 0
        {
            self.crb &= 0xFE;
            self.new_crb &= 0xFE;
            self.tb_state = TimerState::LOAD_STOP;
        }
        else
        {
            self.tb_state = TimerState::LOAD_COUNT;
        }
    }

    fn tb_count(&mut self)
    {
        if self.tb_cnt_phi2 || (self.tb_cnt_ta && self.ta_underflow)
        {
            let curr_tb = self.tb;
            self.tb -= 1;
            if (curr_tb == 0) || (self.tb == 0)
            {
                match self.tb_state
                {
                    TimerState::STOP => (),
                    _ => self.tb_irq(),
                }
            }
        }
    }
}
<commit_msg>CIATimer struct<commit_after>// CIA
#![allow(dead_code)]
use c64::cpu;
use c64::vic;
use c64::memory;
use std::rc::Rc;
use std::cell::RefCell;

pub type CIAShared = Rc<RefCell<CIA>>;

pub enum CIACallbackAction
{
    CIA_NONE,
}

enum TimerState
{
    STOP,
    WAIT_COUNT,
    LOAD_STOP,
    LOAD_COUNT,
    LOAD_WAIT_COUNT,
    COUNT,
    COUNT_STOP
}
// Struct for CIA timer A/B
struct CIATimer
{
    state: TimerState, // current state of the timer
    is_ta: bool, // is this timer A?
    value: u16,  // timer value (TA/TB)
    latch: u16,  // timer latch
    ctrl: u8,    // control timer (CRA/CRB)
    new_ctrl: u8,
    has_new_ctrl: bool,
    is_cnt_phi2: bool,      // timer is counting phi2
    irq_next_cycle: bool,   // perform timer interrupt next cycle
    underflow: bool,        // timer underflowed
    cnt_ta_underflow: bool, // timer is counting underflows of Timer A
}

impl CIATimer
{
    pub fn new(is_ta: bool) -> CIATimer
    {
        CIATimer
        {
            state: TimerState::STOP,
            is_ta: is_ta,
            value: 0xFFFF,
            latch: 1,
            ctrl:  0,
            new_ctrl: 0,
            has_new_ctrl: false,
            is_cnt_phi2:  false,
            irq_next_cycle:   false,
            underflow:        false,
            cnt_ta_underflow: false,
        }
    }
    pub fn reset(&mut self)
    {
        self.state    = TimerState::STOP;
        self.value    = 0xFFFF;
        self.latch    = 1;
        self.ctrl     = 0;
        self.new_ctrl = 0;
        self.has_new_ctrl     = false;
        self.is_cnt_phi2      = false;
        self.irq_next_cycle   = false;
        self.underflow        = false;
        self.cnt_ta_underflow = false;
    }

    pub fn update(&mut self, cia_icr: &mut u8, ta_underflow: bool)
    {
        match self.state
        {
            TimerState::STOP => (),
            TimerState::WAIT_COUNT => {
                self.state = TimerState::COUNT;
            },
            TimerState::LOAD_STOP => {
                self.state = TimerState::STOP;
                self.value = self.latch;
            },
            TimerState::LOAD_COUNT => {
                self.state = TimerState::COUNT;
                self.value = self.latch;
            },
            TimerState::LOAD_WAIT_COUNT => {
                self.state = TimerState::WAIT_COUNT;

                if self.value == 1
                {
                    self.irq(cia_icr);
                }
                else
                {
                    self.value = self.latch;
                }
            }
            TimerState::COUNT => {
                self.count(cia_icr, ta_underflow);
            },
            TimerState::COUNT_STOP => {
                self.state = TimerState::STOP;
                self.count(cia_icr, ta_underflow);
            }
        }

        self.idle();
    }

    pub fn idle(&mut self)
    {
        if self.has_new_ctrl
        {
            match self.state
            {
                TimerState::STOP | TimerState::LOAD_STOP =>
                {
                    if (self.new_ctrl & 1) != 0
                    {
                        if (self.new_ctrl & 0x10) != 0
                        {
                            self.state = TimerState::LOAD_WAIT_COUNT;
                        }
                        else
                        {
                            self.state = TimerState::WAIT_COUNT;
                        }
                    }
                    else
                    {
                        if (self.new_ctrl & 0x10) != 0
                        {
                            self.state = TimerState::LOAD_STOP;
                        }
                    }

                },
                TimerState::WAIT_COUNT | TimerState::LOAD_COUNT =>
                {
                    if (self.new_ctrl & 1) != 0
                    {
                        if (self.new_ctrl & 8) != 0
                        {
                            self.new_ctrl &= 0xFE;
                            self.state = TimerState::STOP;
                        }
                        else
                        {
                            if (self.new_ctrl & 0x10) != 0
                            {
                                self.state = TimerState::LOAD_WAIT_COUNT;
                            }
                        }
                    }
                    else
                    {
                        self.state = TimerState::STOP;
                    }
                },
                TimerState::COUNT =>
                {
                    if (self.new_ctrl & 1) != 0
                    {
                        if (self.new_ctrl & 0x10) != 0
                        {
                            self.state = TimerState::LOAD_WAIT_COUNT;
                        }
                    }
                    else
                    {
                        if (self.new_ctrl & 0x10) != 0
                        {
                            self.state = TimerState::LOAD_STOP;
                        }
                        else
                        {
                            self.state = TimerState::COUNT_STOP;
                        }
                    }
                },
                _ => (),
            }

            self.ctrl = self.new_ctrl & 0xEF;
            self.has_new_ctrl = false;
        }
    }

    pub fn irq(&mut self, cia_icr: &mut u8)
    {
        self.value = self.latch;
        self.irq_next_cycle = true;
        *cia_icr |= if self.is_ta { 1 } else { 2 };

        if (self.ctrl & 8) != 0
        {
            self.ctrl &= 0xFE;
            self.new_ctrl &= 0xFE;
            self.state = TimerState::LOAD_STOP;
        }
        else
        {
            self.state = TimerState::LOAD_COUNT;
        }
    }

    pub fn count(&mut self, cia_icr: &mut u8, ta_underflow: bool)
    {
        if self.is_cnt_phi2 || (self.cnt_ta_underflow && ta_underflow)
        {
            let curr_val = self.value;
            self.value -= 1;
            if (curr_val == 0) || (self.value == 0)
            {
                match self.state
                {
                    TimerState::STOP => (),
                    _ => self.irq(cia_icr),
                }

                self.underflow = true;
            }
        }
    }
}

pub struct CIA
{
    mem_ref: Option<memory::MemShared>,
    cpu_ref: Option<cpu::CPUShared>,
    vic_ref: Option<vic::VICShared>,

    timer_a: CIATimer,
    timer_b: CIATimer,
    icr: u8,
}

impl CIA
{
    pub fn new_shared() -> CIAShared
    {
        Rc::new(RefCell::new(CIA
        {
            mem_ref: None,
            cpu_ref: None,
            vic_ref: None,

            timer_a: CIATimer::new(true),
            timer_b: CIATimer::new(false),
            icr: 0,
        }))
    }

    pub fn set_references(&mut self, memref: memory::MemShared, cpuref: cpu::CPUShared, vicref: vic::VICShared)
    {
        self.mem_ref = Some(memref);
        self.cpu_ref = Some(cpuref);
        self.vic_ref = Some(vicref);
    }

    pub fn reset(&mut self)
    {
        // TODO
        self.timer_a.reset();
        self.timer_b.reset();
        self.icr = 0;
    }

    pub fn read_register(&self, addr: u16) -> u8
    {
        // TODO
        0
    }

    pub fn write_register(&mut self, addr: u16, value: u8, on_cia_write: &mut CIACallbackAction) -> bool
    {
        // TODO
        true
    }

    pub fn update(&mut self)
    {
        self.timer_a.update(&mut self.icr, false);
        let ta_underflow = self.timer_a.underflow;
        self.timer_b.update(&mut self.icr, ta_underflow);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate gcc;
extern crate build_helper;

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use build_helper::run;

fn main() {
    println!("cargo:rustc-cfg=cargobuild");

    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    if !target.contains("apple") && !target.contains("msvc") && !target.contains("emscripten"){
        build_libbacktrace(&host, &target);
    }

    if target.contains("linux") {
        if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
            println!("cargo:rustc-link-lib=static=unwind");
        } else if target.contains("android") {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=log");
            println!("cargo:rustc-link-lib=gcc");
        } else {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=rt");
            println!("cargo:rustc-link-lib=pthread");
            println!("cargo:rustc-link-lib=gcc_s");
        }
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=execinfo");
        println!("cargo:rustc-link-lib=pthread");
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("dragonfly") || target.contains("bitrig") ||
              target.contains("netbsd") || target.contains("openbsd") {
        println!("cargo:rustc-link-lib=pthread");

        if target.contains("rumprun") {
            println!("cargo:rustc-link-lib=unwind");
        } else if target.contains("netbsd") || target.contains("openbsd") {
            println!("cargo:rustc-link-lib=gcc");
        } else if target.contains("bitrig") {
            println!("cargo:rustc-link-lib=c++abi");
        } else if target.contains("dragonfly") {
            println!("cargo:rustc-link-lib=gcc_pic");
        }
    } else if target.contains("apple-darwin") {
        println!("cargo:rustc-link-lib=System");
    } else if target.contains("apple-ios") {
        println!("cargo:rustc-link-lib=System");
        println!("cargo:rustc-link-lib=objc");
        println!("cargo:rustc-link-lib=framework=Security");
        println!("cargo:rustc-link-lib=framework=Foundation");
    } else if target.contains("windows") {
        if target.contains("windows-gnu") {
            println!("cargo:rustc-link-lib=gcc_eh");
        }
        println!("cargo:rustc-link-lib=advapi32");
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=userenv");
        println!("cargo:rustc-link-lib=shell32");
    }
}

fn build_libbacktrace(host: &str, target: &str) {
    let src_dir = env::current_dir().unwrap().join("../libbacktrace");
    let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    println!("cargo:rustc-link-lib=static=backtrace");
    println!("cargo:rustc-link-search=native={}/.libs", build_dir.display());

    if fs::metadata(&build_dir.join(".libs/libbacktrace.a")).is_ok() {
        return
    }

    let compiler = gcc::Config::new().get_compiler();
    let ar = build_helper::cc2ar(compiler.path(), target);
    let cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
                         .collect::<Vec<_>>().join(" ");
    run(Command::new("sh")
                .current_dir(&build_dir)
                .arg(src_dir.join("configure").to_str().unwrap()
                            .replace("C:\\", "/c/")
                            .replace("\\", "/"))
                .arg("--with-pic")
                .arg("--disable-multilib")
                .arg("--disable-shared")
                .arg("--disable-host-shared")
                .arg(format!("--host={}", build_helper::gnu_target(target)))
                .arg(format!("--build={}", build_helper::gnu_target(host)))
                .env("CC", compiler.path())
                .env("AR", &ar)
                .env("RANLIB", format!("{} s", ar.display()))
                .env("CFLAGS", cflags));
    run(Command::new("make")
                .current_dir(&build_dir)
                .arg(format!("INCDIR={}", src_dir.display()))
                .arg("-j").arg(env::var("NUM_JOBS").unwrap()));
}
<commit_msg>Auto merge of #32407 - alexcrichton:netbsd-gcc-s-link, r=aturon<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate gcc;
extern crate build_helper;

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use build_helper::run;

fn main() {
    println!("cargo:rustc-cfg=cargobuild");

    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    if !target.contains("apple") && !target.contains("msvc") && !target.contains("emscripten"){
        build_libbacktrace(&host, &target);
    }

    if target.contains("linux") {
        if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
            println!("cargo:rustc-link-lib=static=unwind");
        } else if target.contains("android") {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=log");
            println!("cargo:rustc-link-lib=gcc");
        } else {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=rt");
            println!("cargo:rustc-link-lib=pthread");
            println!("cargo:rustc-link-lib=gcc_s");
        }
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=execinfo");
        println!("cargo:rustc-link-lib=pthread");
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("dragonfly") || target.contains("bitrig") ||
              target.contains("netbsd") || target.contains("openbsd") {
        println!("cargo:rustc-link-lib=pthread");

        if target.contains("rumprun") {
            println!("cargo:rustc-link-lib=unwind");
        } else if target.contains("netbsd") {
            println!("cargo:rustc-link-lib=gcc_s");
        } else if target.contains("openbsd") {
            println!("cargo:rustc-link-lib=gcc");
        } else if target.contains("bitrig") {
            println!("cargo:rustc-link-lib=c++abi");
        } else if target.contains("dragonfly") {
            println!("cargo:rustc-link-lib=gcc_pic");
        }
    } else if target.contains("apple-darwin") {
        println!("cargo:rustc-link-lib=System");
    } else if target.contains("apple-ios") {
        println!("cargo:rustc-link-lib=System");
        println!("cargo:rustc-link-lib=objc");
        println!("cargo:rustc-link-lib=framework=Security");
        println!("cargo:rustc-link-lib=framework=Foundation");
    } else if target.contains("windows") {
        if target.contains("windows-gnu") {
            println!("cargo:rustc-link-lib=gcc_eh");
        }
        println!("cargo:rustc-link-lib=advapi32");
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=userenv");
        println!("cargo:rustc-link-lib=shell32");
    }
}

fn build_libbacktrace(host: &str, target: &str) {
    let src_dir = env::current_dir().unwrap().join("../libbacktrace");
    let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    println!("cargo:rustc-link-lib=static=backtrace");
    println!("cargo:rustc-link-search=native={}/.libs", build_dir.display());

    if fs::metadata(&build_dir.join(".libs/libbacktrace.a")).is_ok() {
        return
    }

    let compiler = gcc::Config::new().get_compiler();
    let ar = build_helper::cc2ar(compiler.path(), target);
    let cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
                         .collect::<Vec<_>>().join(" ");
    run(Command::new("sh")
                .current_dir(&build_dir)
                .arg(src_dir.join("configure").to_str().unwrap()
                            .replace("C:\\", "/c/")
                            .replace("\\", "/"))
                .arg("--with-pic")
                .arg("--disable-multilib")
                .arg("--disable-shared")
                .arg("--disable-host-shared")
                .arg(format!("--host={}", build_helper::gnu_target(target)))
                .arg(format!("--build={}", build_helper::gnu_target(host)))
                .env("CC", compiler.path())
                .env("AR", &ar)
                .env("RANLIB", format!("{} s", ar.display()))
                .env("CFLAGS", cflags));
    run(Command::new("make")
                .current_dir(&build_dir)
                .arg(format!("INCDIR={}", src_dir.display()))
                .arg("-j").arg(env::var("NUM_JOBS").unwrap()));
}
<|endoftext|>


<commit_before>
use std::io::Write;
use std::io::Error as IoError;
use std::ascii::AsciiExt;
use super::{Parsable, ParseError, Streamable};
use super::types::{DateTime, MailboxList, Mailbox, AddressList, CFWS};

macro_rules! req_name {
    ($rem:ident, $str:expr, $input:ident) => {
        let len: usize = $str.len();
        if $rem.len() < len || &(&$rem[0..len]).to_ascii_lowercase()!=$str {
            return Err(ParseError::NotFound);
        }
        $rem = &$rem[len..];
    };
}

macro_rules! req_crlf {
    ($rem:ident, $input:ident) => {
        if &$rem[..2] != b"\r\n" {
            return Err(ParseError::NotFound);
        }
        $rem = &$rem[2..];
    }
}

// 3.6.1
// orig-date       =   "Date:" date-time CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct OrigDate(pub DateTime);
impl Parsable for OrigDate {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"date:", input);
        if let Ok(dt) = parse!(DateTime, rem) {
            req_crlf!(rem, input);
            Ok((OrigDate(dt), rem))
        } else {
            Err(ParseError::NotFound)
        }
    }
}
impl Streamable for OrigDate {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Date:"))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.2
// from            =   "From:" mailbox-list CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct From(pub MailboxList);
impl Parsable for From {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"from:", input);
        if let Ok(mbl) = parse!(MailboxList, rem) {
            req_crlf!(rem, input);
            return Ok((From(mbl), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for From {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"From: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.2
// sender          =   "Sender:" mailbox CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct Sender(pub Mailbox);
impl Parsable for Sender {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"sender:", input);
        if let Ok(mb) = parse!(Mailbox, rem) {
            req_crlf!(rem, input);
            return Ok((Sender(mb), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for Sender {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Sender: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.2
// reply-to        =   "Reply-To:" address-list CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct ReplyTo(pub AddressList);
impl Parsable for ReplyTo {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"reply-to:", input);
        if let Ok(x) = parse!(AddressList, rem) {
            req_crlf!(rem, input);
            return Ok((ReplyTo(x), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for ReplyTo {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Reply-To: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.3
// to              =   "To:" address-list CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct To(pub AddressList);
impl Parsable for To {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"to:", input);
        if let Ok(x) = parse!(AddressList, rem) {
            req_crlf!(rem, input);
            return Ok((To(x), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for To {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"To: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.3
// cc              =   "Cc:" address-list CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct Cc(pub AddressList);
impl Parsable for Cc {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"cc:", input);
        if let Ok(x) = parse!(AddressList, rem) {
            req_crlf!(rem, input);
            return Ok((Cc(x), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for Cc {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Cc: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.3
// bcc             =   "Bcc:" [address-list / CFWS] CRLF
#[derive(Debug, Clone, PartialEq)]
pub enum Bcc {
    AddressList(AddressList),
    CFWS(CFWS),
    Empty
}
impl Parsable for Bcc {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"bcc:", input);
        if let Ok(x) = parse!(AddressList, rem) {
            req_crlf!(rem, input);
            return Ok((Bcc::AddressList(x), rem));
        }
        if let Ok(x) = parse!(CFWS, rem) {
            req_crlf!(rem, input);
            return Ok((Bcc::CFWS(x), rem));
        }
        req_crlf!(rem, input);
        return Ok((Bcc::Empty, rem));
    }
}
impl Streamable for Bcc {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        let mut count: usize = 0;
        count += try!(w.write(b"Bcc: "));
        count += match *self {
            Bcc::AddressList(ref al) => try!(al.stream(w)),
            Bcc::CFWS(ref cfws) => try!(cfws.stream(w)),
            Bcc::Empty => 0,
        };
        count += try!(w.write(b"\r\n"));
        Ok(count)
    }
}
<commit_msg>rfc5322: 3.6.4 message-id<commit_after>
use std::io::Write;
use std::io::Error as IoError;
use std::ascii::AsciiExt;
use super::{Parsable, ParseError, Streamable};
use super::types::{DateTime, MailboxList, Mailbox, AddressList, CFWS, MsgId};

macro_rules! req_name {
    ($rem:ident, $str:expr, $input:ident) => {
        let len: usize = $str.len();
        if $rem.len() < len || &(&$rem[0..len]).to_ascii_lowercase()!=$str {
            return Err(ParseError::NotFound);
        }
        $rem = &$rem[len..];
    };
}

macro_rules! req_crlf {
    ($rem:ident, $input:ident) => {
        if &$rem[..2] != b"\r\n" {
            return Err(ParseError::NotFound);
        }
        $rem = &$rem[2..];
    }
}

// 3.6.1
// orig-date       =   "Date:" date-time CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct OrigDate(pub DateTime);
impl Parsable for OrigDate {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"date:", input);
        if let Ok(dt) = parse!(DateTime, rem) {
            req_crlf!(rem, input);
            Ok((OrigDate(dt), rem))
        } else {
            Err(ParseError::NotFound)
        }
    }
}
impl Streamable for OrigDate {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Date:"))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.2
// from            =   "From:" mailbox-list CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct From(pub MailboxList);
impl Parsable for From {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"from:", input);
        if let Ok(mbl) = parse!(MailboxList, rem) {
            req_crlf!(rem, input);
            return Ok((From(mbl), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for From {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"From: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.2
// sender          =   "Sender:" mailbox CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct Sender(pub Mailbox);
impl Parsable for Sender {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"sender:", input);
        if let Ok(mb) = parse!(Mailbox, rem) {
            req_crlf!(rem, input);
            return Ok((Sender(mb), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for Sender {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Sender: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.2
// reply-to        =   "Reply-To:" address-list CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct ReplyTo(pub AddressList);
impl Parsable for ReplyTo {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"reply-to:", input);
        if let Ok(x) = parse!(AddressList, rem) {
            req_crlf!(rem, input);
            return Ok((ReplyTo(x), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for ReplyTo {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Reply-To: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.3
// to              =   "To:" address-list CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct To(pub AddressList);
impl Parsable for To {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"to:", input);
        if let Ok(x) = parse!(AddressList, rem) {
            req_crlf!(rem, input);
            return Ok((To(x), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for To {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"To: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.3
// cc              =   "Cc:" address-list CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct Cc(pub AddressList);
impl Parsable for Cc {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"cc:", input);
        if let Ok(x) = parse!(AddressList, rem) {
            req_crlf!(rem, input);
            return Ok((Cc(x), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for Cc {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Cc: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}

// 3.6.3
// bcc             =   "Bcc:" [address-list / CFWS] CRLF
#[derive(Debug, Clone, PartialEq)]
pub enum Bcc {
    AddressList(AddressList),
    CFWS(CFWS),
    Empty
}
impl Parsable for Bcc {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"bcc:", input);
        if let Ok(x) = parse!(AddressList, rem) {
            req_crlf!(rem, input);
            return Ok((Bcc::AddressList(x), rem));
        }
        if let Ok(x) = parse!(CFWS, rem) {
            req_crlf!(rem, input);
            return Ok((Bcc::CFWS(x), rem));
        }
        req_crlf!(rem, input);
        return Ok((Bcc::Empty, rem));
    }
}
impl Streamable for Bcc {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        let mut count: usize = 0;
        count += try!(w.write(b"Bcc: "));
        count += match *self {
            Bcc::AddressList(ref al) => try!(al.stream(w)),
            Bcc::CFWS(ref cfws) => try!(cfws.stream(w)),
            Bcc::Empty => 0,
        };
        count += try!(w.write(b"\r\n"));
        Ok(count)
    }
}

// 3.6.4
// message-id      =   "Message-ID:" msg-id CRLF
#[derive(Debug, Clone, PartialEq)]
pub struct MessageId(pub MsgId);
impl Parsable for MessageId {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        if input.len() == 0 { return Err(ParseError::Eof); }
        let mut rem = input;
        req_name!(rem, b"message-id:", input);
        if let Ok(x) = parse!(MsgId, rem) {
            req_crlf!(rem, input);
            return Ok((MessageId(x), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for MessageId {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        Ok(try!(w.write(b"Message-ID: "))
           + try!(self.0.stream(w))
           + try!(w.write(b"\r\n")))
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

use rustc_serialize::json::Json;

use search::term::Term;
use search::token::Token;
use search::mapping::Mapping;

#[derive(Debug)]
pub struct Document {
    pub key: String,
    pub fields: BTreeMap<String, Vec<Token>>,
}

#[derive(Debug)]
pub struct DocumentSource {
    pub key: String,
    pub data: Json,
}

impl DocumentSource {
    pub fn prepare(&self, mapping: &Mapping) -> Document {
        let mut fields = BTreeMap::new();
        let mut all_field_tokens: Vec<Token> = Vec::new();

        for (field_name, field_value) in self.data.as_object().unwrap() {
            match mapping.fields.get(field_name) {
                Some(field_mapping) => {
                    let value = field_mapping.process_value_for_index(field_value.clone());

                    match value {
                        Some(value) => {
                            // Copy the field's value into the _all field
                            if field_mapping.is_in_all {
                                // TODO: Should the positions be updated?
                                all_field_tokens.extend(value.iter().cloned());
                            }

                            // Insert the field
                            fields.insert(field_name.clone(), value);
                        }
                        None => {
                            // TODO: Should probably be an error
                            warn!("Unprocessable value: {}", field_value);
                        }
                    }
                }
                None => {
                    // No mapping found, just insert the value as-is
                    // TODO: This should probably be an error
                    if let Some(term) = Term::from_json(field_value) {
                        fields.insert(field_name.clone(), vec![Token{term: term, position: 1}]);
                    }
                }
            }
        }

        // Insert _all field
        fields.insert("_all".to_owned(), all_field_tokens);

        Document {
            key: self.key.clone(),
            fields: fields,
        }
    }
}
<commit_msg>Treat null passed as field value like a missing field<commit_after>use std::collections::BTreeMap;

use rustc_serialize::json::Json;

use search::term::Term;
use search::token::Token;
use search::mapping::Mapping;

#[derive(Debug)]
pub struct Document {
    pub key: String,
    pub fields: BTreeMap<String, Vec<Token>>,
}

#[derive(Debug)]
pub struct DocumentSource {
    pub key: String,
    pub data: Json,
}

impl DocumentSource {
    pub fn prepare(&self, mapping: &Mapping) -> Document {
        let mut fields = BTreeMap::new();
        let mut all_field_tokens: Vec<Token> = Vec::new();

        for (field_name, field_value) in self.data.as_object().unwrap() {
            if *field_value == Json::Null {
                // Treat null like a missing field
                continue;
            }

            match mapping.fields.get(field_name) {
                Some(field_mapping) => {
                    let value = field_mapping.process_value_for_index(field_value.clone());

                    match value {
                        Some(value) => {
                            // Copy the field's value into the _all field
                            if field_mapping.is_in_all {
                                // TODO: Should the positions be updated?
                                all_field_tokens.extend(value.iter().cloned());
                            }

                            // Insert the field
                            fields.insert(field_name.clone(), value);
                        }
                        None => {
                            // TODO: Should probably be an error
                            warn!("Unprocessable value: {}", field_value);
                        }
                    }
                }
                None => {
                    // No mapping found, just insert the value as-is
                    // TODO: This should probably be an error
                    if let Some(term) = Term::from_json(field_value) {
                        fields.insert(field_name.clone(), vec![Token{term: term, position: 1}]);
                    }
                }
            }
        }

        // Insert _all field
        fields.insert("_all".to_owned(), all_field_tokens);

        Document {
            key: self.key.clone(),
            fields: fields,
        }
    }
}
<|endoftext|>


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

use crate::errors::*;
use clap::ValueSource;
use clap::{error::ErrorKind, ArgGroup, IntoApp, Parser};
use std::env;
use std::ffi::OsString;
use std::path::PathBuf;
use which::which_in;

const ENV_VAR_SCCACHE_START_SERVER: &str = "SCCACHE_START_SERVER";

#[derive(clap::ArgEnum, Debug, Clone)]
pub enum StatsFormat {
    Text,
    Json,
}

impl Default for StatsFormat {
    fn default() -> Self {
        Self::Text
    }
}

/// A specific command to run.
pub enum Command {
    /// Show cache statistics and exit.
    ShowStats(StatsFormat),
    /// Run background server.
    InternalStartServer,
    /// Start background server as a subprocess.
    StartServer,
    /// Stop background server.
    StopServer,
    /// Zero cache statistics and exit.
    ZeroStats,
    /// Show the status of the distributed client.
    DistStatus,
    /// Perform a login to authenticate for distributed compilation.
    DistAuth,
    /// Package a toolchain for distributed compilation (executable, out)
    PackageToolchain(PathBuf, PathBuf),
    /// Run a compiler command.
    Compile {
        /// The binary to execute.
        exe: OsString,
        /// The commandline arguments to pass to `exe`.
        cmdline: Vec<OsString>,
        /// The directory in which to execute the command.
        cwd: PathBuf,
        /// The environment variables to use for execution.
        env_vars: Vec<(OsString, OsString)>,
    },
}

#[derive(Parser)]
#[clap(version)]
#[clap(trailing_var_arg = true)]
#[clap(after_help = concat!(
    "Enabled features:\n",
    "    S3:        ", cfg!(feature = "s3"), "\n",
    "    Redis:     ", cfg!(feature = "redis"), "\n",
    "    Memcached: ", cfg!(feature = "memcached"), "\n",
    "    GCS:       ", cfg!(feature = "gcs"), "\n",
    "    Azure:     ", cfg!(feature = "azure"), "\n")
)]
#[clap(group(
    ArgGroup::new("one_and_only_one")
        .args(&[
            "dist-auth",
            "dist-status",
            "show-stats",
            "start-server",
            "stop-server",
            "zero-stats",
            "package-toolchain",
            "cmd",
        ])
        .required(true)
))]
struct Opts {
    /// authenticate for distributed compilation
    #[clap(long)]
    dist_auth: bool,
    /// show status of the distributed client
    #[clap(long)]
    dist_status: bool,
    /// show cache statistics
    #[clap(short, long)]
    show_stats: bool,
    /// start background server
    #[clap(long, hide_env = true, env = ENV_VAR_SCCACHE_START_SERVER)]
    start_server: bool,
    /// stop background server
    #[clap(long)]
    stop_server: bool,
    /// zero statistic counters
    #[clap(short, long)]
    zero_stats: bool,

    /// package toolchain for distributed compilation
    #[clap(long, number_of_values = 2, value_names = &["EXECUTABLE", "OUT"])]
    package_toolchain: Vec<PathBuf>,
    /// set output format of statistics
    #[clap(long, arg_enum, value_name = "FORMAT", default_value_t = StatsFormat::default())]
    stats_format: StatsFormat,

    cmd: Vec<OsString>,
}

/// Parse the commandline into a `Command` to execute.
pub fn parse() -> Command {
    match try_parse() {
        Ok(cmd) => cmd,
        Err(e) => match e.downcast::<clap::error::Error>() {
            // If the error is from clap then let them handle formatting and exiting
            Ok(clap_err) => clap_err.exit(),
            Err(some_other_err) => {
                println!("sccache: {some_other_err}");
                for source in some_other_err.chain().skip(1) {
                    println!("sccache: caused by: {source}");
                }
                std::process::exit(1);
            }
        },
    }
}

fn try_parse() -> Result<Command> {
    trace!("parse");
    let cwd =
        env::current_dir().context("sccache: Couldn't determine current working directory")?;

    // We only if the value is `1` so unset it otherwise
    let internal_start_server = match env::var(ENV_VAR_SCCACHE_START_SERVER).as_deref() {
        Ok("1") => true,
        _ => {
            env::remove_var(ENV_VAR_SCCACHE_START_SERVER);
            false
        }
    };

    let mut args: Vec<_> = env::args_os().collect();
    if !internal_start_server {
        if let Ok(exe) = env::current_exe() {
            match exe
                .file_stem()
                .and_then(|s| s.to_str())
                .map(|s| s.to_lowercase())
            {
                // If the executable has its standard name, do nothing.
                Some(ref e) if e == env!("CARGO_PKG_NAME") => {}
                // Otherwise, if it was copied/hardlinked under a different $name, act
                // as if it were invoked with `sccache $name`, but avoid $name resolving
                // to ourselves again if it's in the PATH.
                _ => {
                    if let (Some(path), Some(exe_filename)) = (env::var_os("PATH"), exe.file_name())
                    {
                        match which_in(exe_filename, Some(&path), &cwd) {
                            Ok(ref full_path)
                                if full_path.canonicalize()? == exe.canonicalize()? =>
                            {
                                if let Some(dir) = full_path.parent() {
                                    let path = env::join_paths(
                                        env::split_paths(&path).filter(|p| p != dir),
                                    )
                                    .ok();
                                    if let Ok(full_path) = which_in(exe_filename, path, &cwd) {
                                        args[0] = full_path.into();
                                    }
                                }
                            }
                            Ok(full_path) => args[0] = full_path.into(),
                            Err(_) => {}
                        }
                        args.insert(0, env!("CARGO_PKG_NAME").into());
                    }
                }
            }
        }
    }

    let opts_result = Opts::try_parse_from(&args);

    // A command can either be from `ENV_VAR_SCCACHE_START_SERVER` being set or from command-line
    // args. Validate things so that error messages are nice and the returned opts are correct
    let opts = match (internal_start_server, opts_result) {
        (true, Err(e)) => {
            // Return a more obvious error message when there is a conflict from
            // `ENV_VAR_SCCACHE_START_SERVER` being used with another command
            if e.kind() == ErrorKind::ArgumentConflict {
                bail!("`{ENV_VAR_SCCACHE_START_SERVER}=1` can't be used with other commands");
            } else {
                return Err(e.into());
            }
        }
        (false, Err(e)) => {
            return Err(e.into());
        }
        (true, Ok(mut opts)) => {
            // `start_server` is used to smuggle `ENV_VAR_SCCACHE_START_SERVER` into the arg group,
            // but they should still conflict, so check the source of `start_server` to see if they
            // were both set or not
            let opts_matches = Opts::command().try_get_matches_from(&args)?;
            if let Some(ValueSource::EnvVariable) = opts_matches.value_source("start-server") {
                opts.start_server = false;
                opts
            } else {
                bail!("`{ENV_VAR_SCCACHE_START_SERVER}=1` can't be used with other commands");
            }
        }
        (false, Ok(opts)) => opts,
    };

    let Opts {
        dist_auth,
        dist_status,
        show_stats,
        start_server,
        stop_server,
        zero_stats,
        package_toolchain,
        stats_format,
        cmd,
    } = opts;

    Ok(if internal_start_server {
        Command::InternalStartServer
    } else if show_stats {
        Command::ShowStats(stats_format)
    } else if start_server {
        Command::StartServer
    } else if stop_server {
        Command::StopServer
    } else if zero_stats {
        Command::ZeroStats
    } else if dist_auth {
        Command::DistAuth
    } else if dist_status {
        Command::DistStatus
    } else if let [executable, out] = package_toolchain.as_slice() {
        Command::PackageToolchain(executable.into(), out.into())
    } else if let [exe, cmdline @ ..] = cmd.as_slice() {
        let mut env_vars: Vec<_> = env::vars_os().collect();

        // If we're running under rr, avoid the `LD_PRELOAD` bits, as it will
        // almost surely do the wrong thing, as the compiler gets executed
        // in a different process tree.
        //
        // FIXME: Maybe we should strip out `LD_PRELOAD` always?
        if env::var_os("RUNNING_UNDER_RR").is_some() {
            env_vars.retain(|(k, _v)| k != "LD_PRELOAD" && k != "RUNNING_UNDER_RR");
        }

        Command::Compile {
            exe: exe.to_owned(),
            cmdline: cmdline.to_owned(),
            cwd,
            env_vars,
        }
    } else {
        unreachable!("`ArgGroup` should enforce a single command to be run");
    })
}
<commit_msg>Small tweaks to condense help output<commit_after>// Copyright 2016 Mozilla Foundation
//
// 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.

use crate::errors::*;
use clap::ValueSource;
use clap::{error::ErrorKind, ArgGroup, IntoApp, Parser};
use std::env;
use std::ffi::OsString;
use std::path::PathBuf;
use which::which_in;

const ENV_VAR_SCCACHE_START_SERVER: &str = "SCCACHE_START_SERVER";

#[derive(clap::ArgEnum, Debug, Clone)]
pub enum StatsFormat {
    Text,
    Json,
}

impl Default for StatsFormat {
    fn default() -> Self {
        Self::Text
    }
}

/// A specific command to run.
pub enum Command {
    /// Show cache statistics and exit.
    ShowStats(StatsFormat),
    /// Run background server.
    InternalStartServer,
    /// Start background server as a subprocess.
    StartServer,
    /// Stop background server.
    StopServer,
    /// Zero cache statistics and exit.
    ZeroStats,
    /// Show the status of the distributed client.
    DistStatus,
    /// Perform a login to authenticate for distributed compilation.
    DistAuth,
    /// Package a toolchain for distributed compilation (executable, out)
    PackageToolchain(PathBuf, PathBuf),
    /// Run a compiler command.
    Compile {
        /// The binary to execute.
        exe: OsString,
        /// The commandline arguments to pass to `exe`.
        cmdline: Vec<OsString>,
        /// The directory in which to execute the command.
        cwd: PathBuf,
        /// The environment variables to use for execution.
        env_vars: Vec<(OsString, OsString)>,
    },
}

#[derive(Parser)]
#[clap(version)]
#[clap(trailing_var_arg = true)]
#[clap(max_term_width = 110)]
#[clap(after_help = concat!(
    "Enabled features:\n",
    "    S3:        ", cfg!(feature = "s3"), "\n",
    "    Redis:     ", cfg!(feature = "redis"), "\n",
    "    Memcached: ", cfg!(feature = "memcached"), "\n",
    "    GCS:       ", cfg!(feature = "gcs"), "\n",
    "    Azure:     ", cfg!(feature = "azure"), "\n")
)]
#[clap(group(
    ArgGroup::new("one_and_only_one")
        .args(&[
            "dist-auth",
            "dist-status",
            "show-stats",
            "start-server",
            "stop-server",
            "zero-stats",
            "package-toolchain",
            "cmd",
        ])
        .required(true)
))]
struct Opts {
    /// authenticate for distributed compilation
    #[clap(long)]
    dist_auth: bool,
    /// show status of the distributed client
    #[clap(long)]
    dist_status: bool,
    /// show cache statistics
    #[clap(short, long)]
    show_stats: bool,
    /// start background server
    #[clap(long, hide_env = true, env = ENV_VAR_SCCACHE_START_SERVER)]
    start_server: bool,
    /// stop background server
    #[clap(long)]
    stop_server: bool,
    /// zero statistic counters
    #[clap(short, long)]
    zero_stats: bool,

    /// package toolchain for distributed compilation
    #[clap(long, number_of_values = 2, value_names = &["EXE", "OUT"])]
    package_toolchain: Vec<PathBuf>,
    /// set output format of statistics
    #[clap(long, arg_enum, value_name = "FORMAT", default_value_t = StatsFormat::default())]
    stats_format: StatsFormat,

    cmd: Vec<OsString>,
}

/// Parse the commandline into a `Command` to execute.
pub fn parse() -> Command {
    match try_parse() {
        Ok(cmd) => cmd,
        Err(e) => match e.downcast::<clap::error::Error>() {
            // If the error is from clap then let them handle formatting and exiting
            Ok(clap_err) => clap_err.exit(),
            Err(some_other_err) => {
                println!("sccache: {some_other_err}");
                for source in some_other_err.chain().skip(1) {
                    println!("sccache: caused by: {source}");
                }
                std::process::exit(1);
            }
        },
    }
}

fn try_parse() -> Result<Command> {
    trace!("parse");
    let cwd =
        env::current_dir().context("sccache: Couldn't determine current working directory")?;

    // We only if the value is `1` so unset it otherwise
    let internal_start_server = match env::var(ENV_VAR_SCCACHE_START_SERVER).as_deref() {
        Ok("1") => true,
        _ => {
            env::remove_var(ENV_VAR_SCCACHE_START_SERVER);
            false
        }
    };

    let mut args: Vec<_> = env::args_os().collect();
    if !internal_start_server {
        if let Ok(exe) = env::current_exe() {
            match exe
                .file_stem()
                .and_then(|s| s.to_str())
                .map(|s| s.to_lowercase())
            {
                // If the executable has its standard name, do nothing.
                Some(ref e) if e == env!("CARGO_PKG_NAME") => {}
                // Otherwise, if it was copied/hardlinked under a different $name, act
                // as if it were invoked with `sccache $name`, but avoid $name resolving
                // to ourselves again if it's in the PATH.
                _ => {
                    if let (Some(path), Some(exe_filename)) = (env::var_os("PATH"), exe.file_name())
                    {
                        match which_in(exe_filename, Some(&path), &cwd) {
                            Ok(ref full_path)
                                if full_path.canonicalize()? == exe.canonicalize()? =>
                            {
                                if let Some(dir) = full_path.parent() {
                                    let path = env::join_paths(
                                        env::split_paths(&path).filter(|p| p != dir),
                                    )
                                    .ok();
                                    if let Ok(full_path) = which_in(exe_filename, path, &cwd) {
                                        args[0] = full_path.into();
                                    }
                                }
                            }
                            Ok(full_path) => args[0] = full_path.into(),
                            Err(_) => {}
                        }
                        args.insert(0, env!("CARGO_PKG_NAME").into());
                    }
                }
            }
        }
    }

    let opts_result = Opts::try_parse_from(&args);

    // A command can either be from `ENV_VAR_SCCACHE_START_SERVER` being set or from command-line
    // args. Validate things so that error messages are nice and the returned opts are correct
    let opts = match (internal_start_server, opts_result) {
        (true, Err(e)) => {
            // Return a more obvious error message when there is a conflict from
            // `ENV_VAR_SCCACHE_START_SERVER` being used with another command
            if e.kind() == ErrorKind::ArgumentConflict {
                bail!("`{ENV_VAR_SCCACHE_START_SERVER}=1` can't be used with other commands");
            } else {
                return Err(e.into());
            }
        }
        (false, Err(e)) => {
            return Err(e.into());
        }
        (true, Ok(mut opts)) => {
            // `start_server` is used to smuggle `ENV_VAR_SCCACHE_START_SERVER` into the arg group,
            // but they should still conflict, so check the source of `start_server` to see if they
            // were both set or not
            let opts_matches = Opts::command().try_get_matches_from(&args)?;
            if let Some(ValueSource::EnvVariable) = opts_matches.value_source("start-server") {
                opts.start_server = false;
                opts
            } else {
                bail!("`{ENV_VAR_SCCACHE_START_SERVER}=1` can't be used with other commands");
            }
        }
        (false, Ok(opts)) => opts,
    };

    let Opts {
        dist_auth,
        dist_status,
        show_stats,
        start_server,
        stop_server,
        zero_stats,
        package_toolchain,
        stats_format,
        cmd,
    } = opts;

    Ok(if internal_start_server {
        Command::InternalStartServer
    } else if show_stats {
        Command::ShowStats(stats_format)
    } else if start_server {
        Command::StartServer
    } else if stop_server {
        Command::StopServer
    } else if zero_stats {
        Command::ZeroStats
    } else if dist_auth {
        Command::DistAuth
    } else if dist_status {
        Command::DistStatus
    } else if let [executable, out] = package_toolchain.as_slice() {
        Command::PackageToolchain(executable.into(), out.into())
    } else if let [exe, cmdline @ ..] = cmd.as_slice() {
        let mut env_vars: Vec<_> = env::vars_os().collect();

        // If we're running under rr, avoid the `LD_PRELOAD` bits, as it will
        // almost surely do the wrong thing, as the compiler gets executed
        // in a different process tree.
        //
        // FIXME: Maybe we should strip out `LD_PRELOAD` always?
        if env::var_os("RUNNING_UNDER_RR").is_some() {
            env_vars.retain(|(k, _v)| k != "LD_PRELOAD" && k != "RUNNING_UNDER_RR");
        }

        Command::Compile {
            exe: exe.to_owned(),
            cmdline: cmdline.to_owned(),
            cwd,
            env_vars,
        }
    } else {
        unreachable!("`ArgGroup` should enforce a single command to be run");
    })
}
<|endoftext|>