<commit_before>use rustc_serialize::json;

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Chapter {
    title: String,
    files: Vec<String>
}

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Part {
    title: String,
    chapters: Vec<Chapter>
}

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Structure {
    title: String,
    parts: Vec<Part>
}

impl Structure {
    pub fn from_json(js: &str) -> Structure {
        json::decode::<Structure>(js).unwrap()
    }

    pub fn get_all_files(&self) -> Vec<String> {
        self.parts.iter().map(|ref part| {
            part.chapters.iter().map(|ref chap| {
                &chap.files
            }).fold(Vec::new(), |mut acc, f| {
                acc.extend_from_slice(&f[..]); acc
            })
        }).fold(Vec::new(), |mut acc, f| {
            acc.extend_from_slice(&f[..]); acc
        })
    }
}

#[test]
fn test_structure_1() {
    let js = r#"
    {
        "title": "My Book",
        "parts": [{
            "title": "Part 1",
            "chapters": [{
                "title": "Chap 1",
                "files": ["alpha", "beta"]
            }, {
                "title": "Chap 2",
                "files": ["gamma"]
            }]
        }, {
            "title": "Part 2",
            "chapters": [{
                "title": "Chap 3",
                "files": ["delta"]
            }, {
                "title": "Chap 4",
                "files": ["epsilon", "eta"]
            }]
        }]
    }"#;
    let st = Structure::from_json(&js);
    let fs = st.get_all_files();
    assert!(fs.len() == 6);
}
<commit_msg>Starting to code the content generation<commit_after>use rustc_serialize::json;

use std::io::prelude::*;
use std::fs::File;

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Chapter {
    title: String,
    files: Vec<String>
}

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Part {
    title: String,
    chapters: Vec<Chapter>
}

#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Structure {
    title: String,
    parts: Vec<Part>
}

impl Structure {
    pub fn from_json(js: &str) -> Structure {
        json::decode::<Structure>(js).unwrap()
    }
}

pub struct Content {
    toc: String,
    chunks: Vec<String>
}

impl Content {
    fn build_toc(st: &Structure) -> Result<String, String> {
        let mut toc = String::new();
        toc = toc + r#"
"# + "\n\n";
        let mut part_index = 1;
        for part in st.parts.iter() {
            let part_link = format!(
                "**[{0} {1}](#kos_ref_part_{0})**\n\n", part_index, part.title);
            toc = toc + &part_link;
            let mut chap_index = 1;
            for chap in part.chapters.iter() {
                let chap_link = format!(
                    "*[{0}.{1} {2}](#kos_ref_chap_{0}_{1})*\n\n",
                    part_index, chap_index, chap.title);
                toc = toc + &chap_link;
                chap_index += 1;
            }
            part_index += 1;
        }
        toc = toc + "
\n\n";
        Ok(toc)
    }

    fn build_chunks(st: &Structure) -> Result<Vec<String>, String> {
        let mut chunks = Vec::new();
        let book_header =
                r#"
"#.to_string() +
                r#"
"# +
                &st.title +
                "

\n\n";
            chunks.push(book_header);
        let mut part_index = 1;
        for part in st.parts.iter() {
            let part_header =
                r#"
"#.to_string() +
                r#"
"# +
                &part.title +
                "

\n\n";
            chunks.push(part_header);
            let mut chap_index = 1;
            for chap in part.chapters.iter() {
                let chap_header =
                    r#"
"#.to_string() +
                    r#"
"# +
                    &chap.title +
                    "

\n\n";
                chunks.push(chap_header);
                for f in chap.files.iter() {
                    let file_content = match File::open(f) {
                        Ok(mut fread) => {
                            let mut res = String::new();
                            match fread.read_to_string(&mut res) {
                                Ok(_) => (),
                                Err(_) => {
                                    return Err(
                                        "Error reading file ".to_string() +
                                        f + "!\n");
                                }
                            }
                            res
                        },
                        Err(_) => {
                            return Err(
                                "Error reading file ".to_string() + f + "!\n");
                        }
                    };
                    chunks.push(file_content);
                }
                chap_index += 1;
            }
            part_index += 1;
        }
        Ok(chunks)
    }

    pub fn from_structure(st: &Structure) -> Result<Content, String> {
        let toc = Content::build_toc(st);
        let chunks = Content::build_chunks(st);
        Ok(Content {
            toc: match toc {
                Ok(t) => t,
                Err(e) => { return Err(e); }
            },
            chunks: match chunks {
                Ok(c) => c,
                Err(e) => { return Err(e); }
            }
        })
    }
}
<|endoftext|>


<commit_before>#![crate_name = "uu_tail"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Morten Olsen Lysgaard <morten@lysgaard.no>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 */

extern crate getopts;

#[macro_use]
extern crate uucore;

use std::collections::VecDeque;
use std::error::Error;
use std::fmt;
use std::fs::File;
use std::io::{BufRead, BufReader, Read, Seek, SeekFrom, stdin, stdout, Write};
use std::path::Path;
use std::str::from_utf8;
use std::thread::sleep;
use std::time::Duration;

static NAME: &'static str = "tail";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

enum FilterMode {
    Bytes(u64),
    Lines(u64, u8), // (number of lines, delimiter)
}

struct Settings {
    mode: FilterMode,
    sleep_msec: u32,
    beginning: bool,
    follow: bool,
}

impl Default for Settings {
    fn default() -> Settings {
        Settings {
            mode: FilterMode::Lines(10, '\n' as u8),
            sleep_msec: 1000,
            beginning: false,
            follow: false,
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut settings: Settings = Default::default();

    // handle obsolete -number syntax
    let options = match obsolete(&args[1..]) {
        (args, Some(n)) => { settings.mode = FilterMode::Lines(n, '\n' as u8); args },
        (args, None) => args
    };

    let args = options;

    let mut opts = getopts::Options::new();

    opts.optopt("c", "bytes", "Number of bytes to print", "k");
    opts.optopt("n", "lines", "Number of lines to print", "k");
    opts.optflag("f", "follow", "Print the file as it grows");
    opts.optopt("s", "sleep-interval", "Number or seconds to sleep between polling the file when running with -f", "n");
    opts.optflag("z", "zero-terminated", "Line delimiter is NUL, not newline");
    opts.optflag("h", "help", "help");
    opts.optflag("V", "version", "version");

    let given_options = match opts.parse(&args) {
        Ok (m) => { m }
        Err(_) => {
            println!("{}", opts.usage(""));
            return 1;
        }
    };

    if given_options.opt_present("h") {
        println!("{}", opts.usage(""));
        return 0;
    }
    if given_options.opt_present("V") { version(); return 0 }

    settings.follow = given_options.opt_present("f");
    if settings.follow {
        match given_options.opt_str("s") {
            Some(n) => {
                let parsed: Option<u32> = n.parse().ok();
                match parsed {
                    Some(m) => { settings.sleep_msec = m * 1000 }
                    None => {}
                }
            }
            None => {}
        };
    }

    match given_options.opt_str("n") {
        Some(n) => {
            let mut slice: &str = n.as_ref();
            if slice.chars().next().unwrap_or('_') == '+' {
                settings.beginning = true;
                slice = &slice[1..];
            }
            match parse_size(slice) {
                Ok(m) => settings.mode = FilterMode::Lines(m, '\n' as u8),
                Err(e) => {
                    show_error!("{}", e.description());
                    return 1;
                }
            }
        }
        None => match given_options.opt_str("c") {
            Some(n) => {
                let mut slice: &str = n.as_ref();
                if slice.chars().next().unwrap_or('_') == '+' {
                    settings.beginning = true;
                    slice = &slice[1..];
                }
                match parse_size(slice) {
                    Ok(m) => settings.mode = FilterMode::Bytes(m),
                    Err(e) => {
                        show_error!("{}", e.description());
                        return 1;
                    }
                }
            }
            None => { }
        }
    };

    if given_options.opt_present("z") {
        if let FilterMode::Lines(count, _) = settings.mode {
            settings.mode = FilterMode::Lines(count, 0);
        }
    }

    let files = given_options.free;

    if files.is_empty() {
        let buffer = BufReader::new(stdin());
        unbounded_tail(buffer, &settings);
    } else {
        let mut multiple = false;
        let mut readers = Vec::new();

        if files.len() > 1 {
            multiple = true;
        }

        for filename in &files {
            if multiple {
                println!("==> {} <==", filename);
            }

            let path = Path::new(filename);
            let file = File::open(&path).unwrap();
            bounded_tail(&file, &settings);

            if settings.follow {
                let reader = BufReader::new(file);
                readers.push(reader);
            }
        }

        if settings.follow {
            follow(readers, &files, &settings);
        }
    }

    0
}

#[derive(Debug, PartialEq, Eq)]
pub enum ParseSizeErr {
    ParseFailure(String),
    SizeTooBig(String),
}

impl Error for ParseSizeErr {
    fn description(&self) -> &str {
        match *self {
            ParseSizeErr::ParseFailure(ref s) => &*s,
            ParseSizeErr::SizeTooBig(ref s) => &*s,
        }
    }
}

impl fmt::Display for ParseSizeErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}", Error::description(self))
    }
}

impl ParseSizeErr {
    fn parse_failure(s: &str) -> ParseSizeErr {
        ParseSizeErr::ParseFailure(format!("invalid size: '{}'", s))
    }

    fn size_too_big(s: &str) -> ParseSizeErr {
        ParseSizeErr::SizeTooBig(
            format!("invalid size: '{}': Value too large to be stored in data type", s))
    }
}

pub type ParseSizeResult = Result<u64, ParseSizeErr>;

pub fn parse_size(mut size_slice: &str) -> Result<u64, ParseSizeErr> {
    let mut base =
        if size_slice.chars().last().unwrap_or('_') == 'B' {
            size_slice = &size_slice[..size_slice.len() - 1];
            1000u64
        } else {
            1024u64
        };

    let exponent =
        if size_slice.len() > 0 {
            let mut has_suffix = true;
            let exp = match size_slice.chars().last().unwrap_or('_') {
                'K' | 'k' => 1u64,
                'M' => 2u64,
                'G' => 3u64,
                'T' => 4u64,
                'P' => 5u64,
                'E' => 6u64,
                'Z' | 'Y' => {
                    return Err(ParseSizeErr::size_too_big(size_slice));
                },
                'b' => {
                    base = 512u64;
                    1u64
                }
                _ => {
                    has_suffix = false;
                    0u64
                }
            };
            if has_suffix {
                size_slice = &size_slice[..size_slice.len() - 1];
            }
            exp
        } else {
            0u64
        };

    let mut multiplier = 1u64;
    for _ in 0u64 .. exponent {
        multiplier *= base;
    }
    if base == 1000u64 && exponent == 0u64 {
        // sole B is not a valid suffix
        Err(ParseSizeErr::parse_failure(size_slice))
    } else {
        let value: Option<u64> = size_slice.parse().ok();
        value.map(|v| Ok(multiplier * v))
             .unwrap_or(Err(ParseSizeErr::parse_failure(size_slice)))
    }
}

// It searches for an option in the form of -123123
//
// In case is found, the options vector will get rid of that object so that
// getopts works correctly.
fn obsolete(options: &[String]) -> (Vec<String>, Option<u64>) {
    let mut options: Vec<String> = options.to_vec();
    let mut a = 0;
    let b = options.len();

    while a < b {
        let current = options[a].clone();
        let current = current.as_bytes();

        if current.len() > 1 && current[0] == '-' as u8 {
            let len = current.len();
            for pos in 1 .. len {
                // Ensure that the argument is only made out of digits
                if !(current[pos] as char).is_numeric() { break; }

                // If this is the last number
                if pos == len - 1 {
                    options.remove(a);
                    let number: Option<u64> = from_utf8(&current[1..len]).unwrap().parse().ok();
                    return (options, Some(number.unwrap()));
                }
            }
        }

        a += 1;
    };

    (options, None)
}

/// When reading files in reverse in `bounded_tail`, this is the size of each
/// block read at a time.
const BLOCK_SIZE: u64 = 1 << 16;

fn follow<T: Read>(mut readers: Vec<BufReader<T>>, filenames: &Vec<String>, settings: &Settings) {
    assert!(settings.follow);
    let mut last = readers.len() - 1;

    loop {
        sleep(Duration::new(0, settings.sleep_msec*1000));

        for (i, reader) in readers.iter_mut().enumerate() {
            // Print all new content since the last pass
            loop {
                let mut datum = String::new();
                match reader.read_line(&mut datum) {
                    Ok(0) => break,
                    Ok(_) => {
                        if i != last {
                            println!("");
                            println!("==> {} <==", filenames[i]);
                            last = i;
                        }
                        print!("{}", datum);
                    },
                    Err(err) => panic!(err)
                }
            }
        }
    }
}

/// Iterate over bytes in the file, in reverse, until `should_stop` returns
/// true. The `file` is left seek'd to the position just after the byte that
/// `should_stop` returned true for.
fn backwards_thru_file<F>(mut file: &File, size: u64, buf: &mut Vec<u8>, delimiter: u8, should_stop: &mut F)
    where F: FnMut(u8) -> bool
{
    assert!(buf.len() >= BLOCK_SIZE as usize);

    let max_blocks_to_read = (size as f64 / BLOCK_SIZE as f64).ceil() as usize;

    for block_idx in 0..max_blocks_to_read {
        let block_size = if block_idx == max_blocks_to_read - 1 {
            size % BLOCK_SIZE
        } else {
            BLOCK_SIZE
        };

        // Seek backwards by the next block, read the full block into
        // `buf`, and then seek back to the start of the block again.
        let pos = file.seek(SeekFrom::Current(-(block_size as i64))).unwrap();
        file.read_exact(&mut buf[0..(block_size as usize)]).unwrap();
        let pos2 = file.seek(SeekFrom::Current(-(block_size as i64))).unwrap();
        assert_eq!(pos, pos2);

        // Iterate backwards through the bytes, calling `should_stop` on each
        // one.
        let slice = &buf[0..(block_size as usize)];
        for (i, ch) in slice.iter().enumerate().rev() {
            // Ignore one trailing newline.
            if block_idx == 0 && i as u64 == block_size - 1 && *ch == delimiter {
                continue;
            }

            if should_stop(*ch) {
                file.seek(SeekFrom::Current((i + 1) as i64)).unwrap();
                return;
            }
        }
    }
}

/// When tail'ing a file, we do not need to read the whole file from start to
/// finish just to find the last n lines or bytes. Instead, we can seek to the
/// end of the file, and then read the file "backwards" in blocks of size
/// `BLOCK_SIZE` until we find the location of the first line/byte. This ends up
/// being a nice performance win for very large files.
fn bounded_tail(mut file: &File, settings: &Settings) {
    let size = file.seek(SeekFrom::End(0)).unwrap();
    let mut buf = vec![0; BLOCK_SIZE as usize];

    // Find the position in the file to start printing from.
    match settings.mode {
        FilterMode::Lines(mut count, delimiter) => {
            backwards_thru_file(&mut file, size, &mut buf, delimiter, &mut |byte| {
                if byte == delimiter {
                    count -= 1;
                    count == 0
                } else {
                    false
                }
            });
        },
        FilterMode::Bytes(count) => {
            file.seek(SeekFrom::End(-(count as i64))).unwrap();
        },
    }

    // Print the target section of the file.
    loop {
        let bytes_read = file.read(&mut buf).unwrap();

        let mut stdout = stdout();
        for b in &buf[0..bytes_read] {
            print_byte(&mut stdout, b);
        }

        if bytes_read == 0 {
            break;
        }
    }
}

fn unbounded_tail<T: Read>(mut reader: BufReader<T>, settings: &Settings) {
    // Read through each line/char and store them in a ringbuffer that always
    // contains count lines/chars. When reaching the end of file, output the
    // data in the ringbuf.
    match settings.mode {
        FilterMode::Lines(mut count, _delimiter) => {
            let mut ringbuf: VecDeque<String> = VecDeque::new();
            let mut skip = if settings.beginning {
                let temp = count;
                count = ::std::u64::MAX;
                temp - 1
            } else {
                0
            };
            loop {
                let mut datum = String::new();
                match reader.read_line(&mut datum) {
                    Ok(0) => break,
                    Ok(_) => {
                        if skip > 0 {
                            skip -= 1;
                        } else {
                            if count <= ringbuf.len() as u64 {
                                ringbuf.pop_front();
                            }
                            ringbuf.push_back(datum);
                        }
                    },
                    Err(err) => panic!(err)
                }
            }
            let mut stdout = stdout();
            for datum in &ringbuf {
                print_string(&mut stdout, datum);
            }
        },
        FilterMode::Bytes(mut count) => {
            let mut ringbuf: VecDeque<u8> = VecDeque::new();
            let mut skip = if settings.beginning {
                let temp = count;
                count = ::std::u64::MAX;
                temp - 1
            } else {
                0
            };
            loop {
                let mut datum = [0; 1];
                match reader.read(&mut datum) {
                    Ok(0) => break,
                    Ok(_) => {
                        if skip > 0 {
                            skip -= 1;
                        } else {
                            if count <= ringbuf.len() as u64 {
                                ringbuf.pop_front();
                            }
                            ringbuf.push_back(datum[0]);
                        }
                    },
                    Err(err) => panic!(err)
                }
            }
            let mut stdout = stdout();
            for datum in &ringbuf {
                print_byte(&mut stdout, datum);
            }
        }
    }

    // TODO: make following stdin work with the new follow() signature
    // maybe wrap stdin in a 1-element vec?
    if settings.follow {
        //follow(reader, settings);
    }
}

#[inline]
fn print_byte<T: Write>(stdout: &mut T, ch: &u8) {
    if let Err(err) = stdout.write(&[*ch]) {
        crash!(1, "{}", err);
    }
}

#[inline]
fn print_string<T: Write>(_: &mut T, s: &str) {
    print!("{}", s);
}

fn version() {
    println!("{} {}", NAME, VERSION);
}
<commit_msg>tail: print empty line between headers<commit_after>#![crate_name = "uu_tail"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Morten Olsen Lysgaard <morten@lysgaard.no>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 */

extern crate getopts;

#[macro_use]
extern crate uucore;

use std::collections::VecDeque;
use std::error::Error;
use std::fmt;
use std::fs::File;
use std::io::{BufRead, BufReader, Read, Seek, SeekFrom, stdin, stdout, Write};
use std::path::Path;
use std::str::from_utf8;
use std::thread::sleep;
use std::time::Duration;

static NAME: &'static str = "tail";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

enum FilterMode {
    Bytes(u64),
    Lines(u64, u8), // (number of lines, delimiter)
}

struct Settings {
    mode: FilterMode,
    sleep_msec: u32,
    beginning: bool,
    follow: bool,
}

impl Default for Settings {
    fn default() -> Settings {
        Settings {
            mode: FilterMode::Lines(10, '\n' as u8),
            sleep_msec: 1000,
            beginning: false,
            follow: false,
        }
    }
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut settings: Settings = Default::default();

    // handle obsolete -number syntax
    let options = match obsolete(&args[1..]) {
        (args, Some(n)) => { settings.mode = FilterMode::Lines(n, '\n' as u8); args },
        (args, None) => args
    };

    let args = options;

    let mut opts = getopts::Options::new();

    opts.optopt("c", "bytes", "Number of bytes to print", "k");
    opts.optopt("n", "lines", "Number of lines to print", "k");
    opts.optflag("f", "follow", "Print the file as it grows");
    opts.optopt("s", "sleep-interval", "Number or seconds to sleep between polling the file when running with -f", "n");
    opts.optflag("z", "zero-terminated", "Line delimiter is NUL, not newline");
    opts.optflag("h", "help", "help");
    opts.optflag("V", "version", "version");

    let given_options = match opts.parse(&args) {
        Ok (m) => { m }
        Err(_) => {
            println!("{}", opts.usage(""));
            return 1;
        }
    };

    if given_options.opt_present("h") {
        println!("{}", opts.usage(""));
        return 0;
    }
    if given_options.opt_present("V") { version(); return 0 }

    settings.follow = given_options.opt_present("f");
    if settings.follow {
        match given_options.opt_str("s") {
            Some(n) => {
                let parsed: Option<u32> = n.parse().ok();
                match parsed {
                    Some(m) => { settings.sleep_msec = m * 1000 }
                    None => {}
                }
            }
            None => {}
        };
    }

    match given_options.opt_str("n") {
        Some(n) => {
            let mut slice: &str = n.as_ref();
            if slice.chars().next().unwrap_or('_') == '+' {
                settings.beginning = true;
                slice = &slice[1..];
            }
            match parse_size(slice) {
                Ok(m) => settings.mode = FilterMode::Lines(m, '\n' as u8),
                Err(e) => {
                    show_error!("{}", e.description());
                    return 1;
                }
            }
        }
        None => match given_options.opt_str("c") {
            Some(n) => {
                let mut slice: &str = n.as_ref();
                if slice.chars().next().unwrap_or('_') == '+' {
                    settings.beginning = true;
                    slice = &slice[1..];
                }
                match parse_size(slice) {
                    Ok(m) => settings.mode = FilterMode::Bytes(m),
                    Err(e) => {
                        show_error!("{}", e.description());
                        return 1;
                    }
                }
            }
            None => { }
        }
    };

    if given_options.opt_present("z") {
        if let FilterMode::Lines(count, _) = settings.mode {
            settings.mode = FilterMode::Lines(count, 0);
        }
    }

    let files = given_options.free;

    if files.is_empty() {
        let buffer = BufReader::new(stdin());
        unbounded_tail(buffer, &settings);
    } else {
        let mut multiple = false;
        let mut first_header = true;
        let mut readers = Vec::new();

        if files.len() > 1 {
            multiple = true;
        }

        for filename in &files {
            if multiple {
                if !first_header { println!(""); }
                println!("==> {} <==", filename);
            }
            first_header = false;

            let path = Path::new(filename);
            let file = File::open(&path).unwrap();
            bounded_tail(&file, &settings);

            if settings.follow {
                let reader = BufReader::new(file);
                readers.push(reader);
            }
        }

        if settings.follow {
            follow(readers, &files, &settings);
        }
    }

    0
}

#[derive(Debug, PartialEq, Eq)]
pub enum ParseSizeErr {
    ParseFailure(String),
    SizeTooBig(String),
}

impl Error for ParseSizeErr {
    fn description(&self) -> &str {
        match *self {
            ParseSizeErr::ParseFailure(ref s) => &*s,
            ParseSizeErr::SizeTooBig(ref s) => &*s,
        }
    }
}

impl fmt::Display for ParseSizeErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}", Error::description(self))
    }
}

impl ParseSizeErr {
    fn parse_failure(s: &str) -> ParseSizeErr {
        ParseSizeErr::ParseFailure(format!("invalid size: '{}'", s))
    }

    fn size_too_big(s: &str) -> ParseSizeErr {
        ParseSizeErr::SizeTooBig(
            format!("invalid size: '{}': Value too large to be stored in data type", s))
    }
}

pub type ParseSizeResult = Result<u64, ParseSizeErr>;

pub fn parse_size(mut size_slice: &str) -> Result<u64, ParseSizeErr> {
    let mut base =
        if size_slice.chars().last().unwrap_or('_') == 'B' {
            size_slice = &size_slice[..size_slice.len() - 1];
            1000u64
        } else {
            1024u64
        };

    let exponent =
        if size_slice.len() > 0 {
            let mut has_suffix = true;
            let exp = match size_slice.chars().last().unwrap_or('_') {
                'K' | 'k' => 1u64,
                'M' => 2u64,
                'G' => 3u64,
                'T' => 4u64,
                'P' => 5u64,
                'E' => 6u64,
                'Z' | 'Y' => {
                    return Err(ParseSizeErr::size_too_big(size_slice));
                },
                'b' => {
                    base = 512u64;
                    1u64
                }
                _ => {
                    has_suffix = false;
                    0u64
                }
            };
            if has_suffix {
                size_slice = &size_slice[..size_slice.len() - 1];
            }
            exp
        } else {
            0u64
        };

    let mut multiplier = 1u64;
    for _ in 0u64 .. exponent {
        multiplier *= base;
    }
    if base == 1000u64 && exponent == 0u64 {
        // sole B is not a valid suffix
        Err(ParseSizeErr::parse_failure(size_slice))
    } else {
        let value: Option<u64> = size_slice.parse().ok();
        value.map(|v| Ok(multiplier * v))
             .unwrap_or(Err(ParseSizeErr::parse_failure(size_slice)))
    }
}

// It searches for an option in the form of -123123
//
// In case is found, the options vector will get rid of that object so that
// getopts works correctly.
fn obsolete(options: &[String]) -> (Vec<String>, Option<u64>) {
    let mut options: Vec<String> = options.to_vec();
    let mut a = 0;
    let b = options.len();

    while a < b {
        let current = options[a].clone();
        let current = current.as_bytes();

        if current.len() > 1 && current[0] == '-' as u8 {
            let len = current.len();
            for pos in 1 .. len {
                // Ensure that the argument is only made out of digits
                if !(current[pos] as char).is_numeric() { break; }

                // If this is the last number
                if pos == len - 1 {
                    options.remove(a);
                    let number: Option<u64> = from_utf8(&current[1..len]).unwrap().parse().ok();
                    return (options, Some(number.unwrap()));
                }
            }
        }

        a += 1;
    };

    (options, None)
}

/// When reading files in reverse in `bounded_tail`, this is the size of each
/// block read at a time.
const BLOCK_SIZE: u64 = 1 << 16;

fn follow<T: Read>(mut readers: Vec<BufReader<T>>, filenames: &Vec<String>, settings: &Settings) {
    assert!(settings.follow);
    let mut last = readers.len() - 1;

    loop {
        sleep(Duration::new(0, settings.sleep_msec*1000));

        for (i, reader) in readers.iter_mut().enumerate() {
            // Print all new content since the last pass
            loop {
                let mut datum = String::new();
                match reader.read_line(&mut datum) {
                    Ok(0) => break,
                    Ok(_) => {
                        if i != last {
                            println!("");
                            println!("==> {} <==", filenames[i]);
                            last = i;
                        }
                        print!("{}", datum);
                    },
                    Err(err) => panic!(err)
                }
            }
        }
    }
}

/// Iterate over bytes in the file, in reverse, until `should_stop` returns
/// true. The `file` is left seek'd to the position just after the byte that
/// `should_stop` returned true for.
fn backwards_thru_file<F>(mut file: &File, size: u64, buf: &mut Vec<u8>, delimiter: u8, should_stop: &mut F)
    where F: FnMut(u8) -> bool
{
    assert!(buf.len() >= BLOCK_SIZE as usize);

    let max_blocks_to_read = (size as f64 / BLOCK_SIZE as f64).ceil() as usize;

    for block_idx in 0..max_blocks_to_read {
        let block_size = if block_idx == max_blocks_to_read - 1 {
            size % BLOCK_SIZE
        } else {
            BLOCK_SIZE
        };

        // Seek backwards by the next block, read the full block into
        // `buf`, and then seek back to the start of the block again.
        let pos = file.seek(SeekFrom::Current(-(block_size as i64))).unwrap();
        file.read_exact(&mut buf[0..(block_size as usize)]).unwrap();
        let pos2 = file.seek(SeekFrom::Current(-(block_size as i64))).unwrap();
        assert_eq!(pos, pos2);

        // Iterate backwards through the bytes, calling `should_stop` on each
        // one.
        let slice = &buf[0..(block_size as usize)];
        for (i, ch) in slice.iter().enumerate().rev() {
            // Ignore one trailing newline.
            if block_idx == 0 && i as u64 == block_size - 1 && *ch == delimiter {
                continue;
            }

            if should_stop(*ch) {
                file.seek(SeekFrom::Current((i + 1) as i64)).unwrap();
                return;
            }
        }
    }
}

/// When tail'ing a file, we do not need to read the whole file from start to
/// finish just to find the last n lines or bytes. Instead, we can seek to the
/// end of the file, and then read the file "backwards" in blocks of size
/// `BLOCK_SIZE` until we find the location of the first line/byte. This ends up
/// being a nice performance win for very large files.
fn bounded_tail(mut file: &File, settings: &Settings) {
    let size = file.seek(SeekFrom::End(0)).unwrap();
    let mut buf = vec![0; BLOCK_SIZE as usize];

    // Find the position in the file to start printing from.
    match settings.mode {
        FilterMode::Lines(mut count, delimiter) => {
            backwards_thru_file(&mut file, size, &mut buf, delimiter, &mut |byte| {
                if byte == delimiter {
                    count -= 1;
                    count == 0
                } else {
                    false
                }
            });
        },
        FilterMode::Bytes(count) => {
            file.seek(SeekFrom::End(-(count as i64))).unwrap();
        },
    }

    // Print the target section of the file.
    loop {
        let bytes_read = file.read(&mut buf).unwrap();

        let mut stdout = stdout();
        for b in &buf[0..bytes_read] {
            print_byte(&mut stdout, b);
        }

        if bytes_read == 0 {
            break;
        }
    }
}

fn unbounded_tail<T: Read>(mut reader: BufReader<T>, settings: &Settings) {
    // Read through each line/char and store them in a ringbuffer that always
    // contains count lines/chars. When reaching the end of file, output the
    // data in the ringbuf.
    match settings.mode {
        FilterMode::Lines(mut count, _delimiter) => {
            let mut ringbuf: VecDeque<String> = VecDeque::new();
            let mut skip = if settings.beginning {
                let temp = count;
                count = ::std::u64::MAX;
                temp - 1
            } else {
                0
            };
            loop {
                let mut datum = String::new();
                match reader.read_line(&mut datum) {
                    Ok(0) => break,
                    Ok(_) => {
                        if skip > 0 {
                            skip -= 1;
                        } else {
                            if count <= ringbuf.len() as u64 {
                                ringbuf.pop_front();
                            }
                            ringbuf.push_back(datum);
                        }
                    },
                    Err(err) => panic!(err)
                }
            }
            let mut stdout = stdout();
            for datum in &ringbuf {
                print_string(&mut stdout, datum);
            }
        },
        FilterMode::Bytes(mut count) => {
            let mut ringbuf: VecDeque<u8> = VecDeque::new();
            let mut skip = if settings.beginning {
                let temp = count;
                count = ::std::u64::MAX;
                temp - 1
            } else {
                0
            };
            loop {
                let mut datum = [0; 1];
                match reader.read(&mut datum) {
                    Ok(0) => break,
                    Ok(_) => {
                        if skip > 0 {
                            skip -= 1;
                        } else {
                            if count <= ringbuf.len() as u64 {
                                ringbuf.pop_front();
                            }
                            ringbuf.push_back(datum[0]);
                        }
                    },
                    Err(err) => panic!(err)
                }
            }
            let mut stdout = stdout();
            for datum in &ringbuf {
                print_byte(&mut stdout, datum);
            }
        }
    }

    // TODO: make following stdin work with the new follow() signature
    // maybe wrap stdin in a 1-element vec?
    if settings.follow {
        //follow(reader, settings);
    }
}

#[inline]
fn print_byte<T: Write>(stdout: &mut T, ch: &u8) {
    if let Err(err) = stdout.write(&[*ch]) {
        crash!(1, "{}", err);
    }
}

#[inline]
fn print_string<T: Write>(_: &mut T, s: &str) {
    print!("{}", s);
}

fn version() {
    println!("{} {}", NAME, VERSION);
}
<|endoftext|>


<commit_before>extern crate clap;
use clap::{Arg, App};

extern crate rusqlite;
use rusqlite::{Connection, Rows, Row};
use rusqlite::types::{ToSql};

extern crate sqlcmdlutils;
use sqlcmdlutils::dbpath::{DbPath, db_path_help, parse_db_path};

fn main() {
    let arg_matches =
        App::new("sqls - list SQLite database contents")
            .version(env!("CARGO_PKG_VERSION"))
            .arg(Arg::with_name("schema")
                .short("s")
                .long("schema")
                .help("List schema. For use with a root or table path."))
            .arg(Arg::with_name("path")
                .help(db_path_help())
                .required(true)
                .index(1))
            .arg(Arg::with_name("db_file")
                .help("Absolute or relative path to an SQLite database file.")
                .value_name("database")
                .required(true)
                .index(2))
            .get_matches();

    let db_path = arg_matches.value_of("path").unwrap();

    let db_file = arg_matches.value_of("db_file").unwrap();
    let conn = Connection::open(db_file).unwrap();

    match parse_db_path(db_path) {
        DbPath::Error(msg) => println!("{}", msg),

        DbPath::Root => {
            let query: &str = match arg_matches.occurrences_of("schema") {
                0 => "SELECT tbl_name FROM sqlite_master WHERE type = 'table' AND length(sql) > 0",
                _ => "SELECT sql FROM sqlite_master WHERE length(sql) > 0",
            };
            compose_results(conn, query, &[], &output_column);
        }

        DbPath::Table(table) => {
            match arg_matches.occurrences_of("schema") {
                1 => {
                    let query = "SELECT sql FROM sqlite_master WHERE tbl_name = $1 AND length(sql) > 0";
                    compose_results(conn, query, &[&table], &output_column);
                }
                _ => {
                    let query = format!("SELECT * FROM {}", table);
                    compose_results(conn, query.as_str(), &[], &output_rows);
                }
            };
        }

        DbPath::TableFilter {table, filter} => {
            let query = format!("SELECT * FROM {} WHERE {}", table, filter);
            compose_results(conn, query.as_str(), &[], &output_rows);
        }

        DbPath::TableSelect {table, select} => {
            let query = format!("SELECT {} FROM {}", select, table);
            compose_results(conn, query.as_str(), &[], &output_rows);
        }

        DbPath::TableFilterSelect {table, filter, select} => {
            let query = format!("SELECT {} FROM {} WHERE {}", select, table, filter);
            compose_results(conn, query.as_str(), &[], &output_rows);
        }
    }
}

fn compose_results(conn: Connection, query: &str, params: &[&ToSql], output: &Fn(Rows) -> ()) -> () {
    let mut stmt = conn.prepare(query).unwrap();
    let rows = stmt.query(params).unwrap();
    output(rows);
}

fn output_column(mut rows: Rows) -> () {
    while let Some(result_row) = rows.next() {
        match result_row {
            Ok(row) => println!("{}", convert_value(&row, 0)),
            Err(msg) => println!("{}", msg)
        }
    }
}

fn output_rows(mut rows: Rows) -> () {
    while let Some(result_row) = rows.next() {
        match result_row {
            Ok(row) => {
                let cc = row.column_count();
                for col_idx in 0..cc {
                    print!("{}{}"
                        , convert_value(&row, col_idx)
                        , if col_idx < cc - 1 { "|" } else { "" }
                    );
                }
                println!("");
            },
            Err(msg) => println!("{}", msg)
        }
    }
}

// this seems way too crazy ... just to print stuff to console regardless of type
fn convert_value(row: &Row, col_idx: i32) -> String {
    match row.get_checked::<i32, String>(col_idx) {
        Ok(s) => s,
        Err(_) => match row.get_checked::<i32, i64>(col_idx) {
            Ok(i) => i.to_string(),
            Err(_) => match row.get_checked::<i32, f64>(col_idx) {
                Ok(f) => f.to_string(),
                Err(_) => match row.get_checked::<i32, Vec<u8>>(col_idx) {
                    Ok(b) => match String::from_utf8(b) {
                        Ok(s) => s,
                        Err(_) => "".to_string()
                    },
                    Err(_) => "".to_string()
                }
            }
        }
    }
}<commit_msg>Better implementation of sqls's convert_value via rusqlite::types::Value.<commit_after>extern crate clap;
use clap::{Arg, App};

extern crate rusqlite;
use rusqlite::{Connection, Rows, Row};
use rusqlite::types::{ToSql, Value};

extern crate sqlcmdlutils;
use sqlcmdlutils::dbpath::{DbPath, db_path_help, parse_db_path};

fn main() {
    let arg_matches =
        App::new("sqls - list SQLite database contents")
            .version(env!("CARGO_PKG_VERSION"))
            .arg(Arg::with_name("schema")
                .short("s")
                .long("schema")
                .help("List schema. For use with a root or table path."))
            .arg(Arg::with_name("path")
                .help(db_path_help())
                .required(true)
                .index(1))
            .arg(Arg::with_name("db_file")
                .help("Absolute or relative path to an SQLite database file.")
                .value_name("database")
                .required(true)
                .index(2))
            .get_matches();

    let db_path = arg_matches.value_of("path").unwrap();

    let db_file = arg_matches.value_of("db_file").unwrap();
    let conn = Connection::open(db_file).unwrap();

    match parse_db_path(db_path) {
        DbPath::Error(msg) => println!("{}", msg),

        DbPath::Root => {
            let query: &str = match arg_matches.occurrences_of("schema") {
                0 => "SELECT tbl_name FROM sqlite_master WHERE type = 'table' AND length(sql) > 0",
                _ => "SELECT sql FROM sqlite_master WHERE length(sql) > 0",
            };
            compose_results(conn, query, &[], &output_column);
        }

        DbPath::Table(table) => {
            match arg_matches.occurrences_of("schema") {
                1 => {
                    let query = "SELECT sql FROM sqlite_master WHERE tbl_name = $1 AND length(sql) > 0";
                    compose_results(conn, query, &[&table], &output_column);
                }
                _ => {
                    let query = format!("SELECT * FROM {}", table);
                    compose_results(conn, query.as_str(), &[], &output_rows);
                }
            };
        }

        DbPath::TableFilter {table, filter} => {
            let query = format!("SELECT * FROM {} WHERE {}", table, filter);
            compose_results(conn, query.as_str(), &[], &output_rows);
        }

        DbPath::TableSelect {table, select} => {
            let query = format!("SELECT {} FROM {}", select, table);
            compose_results(conn, query.as_str(), &[], &output_rows);
        }

        DbPath::TableFilterSelect {table, filter, select} => {
            let query = format!("SELECT {} FROM {} WHERE {}", select, table, filter);
            compose_results(conn, query.as_str(), &[], &output_rows);
        }
    }
}

fn compose_results(conn: Connection, query: &str, params: &[&ToSql], output: &Fn(Rows) -> ()) -> () {
    let mut stmt = conn.prepare(query).unwrap();
    let rows = stmt.query(params).unwrap();
    output(rows);
}

fn output_column(mut rows: Rows) -> () {
    while let Some(result_row) = rows.next() {
        match result_row {
            Ok(row) => println!("{}", convert_value(&row, 0)),
            Err(msg) => println!("{}", msg)
        }
    }
}

fn output_rows(mut rows: Rows) -> () {
    while let Some(result_row) = rows.next() {
        match result_row {
            Ok(row) => {
                let cc = row.column_count();
                for col_idx in 0..cc {
                    print!("{}{}"
                        , convert_value(&row, col_idx)
                        , if col_idx < cc - 1 { "|" } else { "" }
                    );
                }
                println!("");
            },
            Err(msg) => println!("{}", msg)
        }
    }
}

fn convert_value(row: &Row, col_idx: i32) -> String {
    match row.get_checked::<i32, Value>(col_idx) {
        Ok(v) => {
            match v {
                Value::Null => "<null>".to_string(),
                Value::Integer(i) => i.to_string(),
                Value::Real(f) => f.to_string(),
                Value::Text(t) => t.to_string(),
                Value::Blob(_) => "<blob>".to_string()
            }
        }
        Err(_) => "<type_fail>".to_string()
    }
}<|endoftext|>


<commit_before>use std::error;
use std::fs;
use std::io;
use std::io::{Read,Write,SeekFrom,Seek};
use std::mem;
use std::str;
use std::path::Path;

use fat::RootEntry;
use fat::BIOSParam;

// Always the same
const SECTORS_PER_ROOT: usize = 14;
const BYTES_PER_ROOT_ENTRY: usize = 32;

#[test]
fn test_root_entry_size() {
    assert_eq!(mem::size_of::<RootEntry>(), BYTES_PER_ROOT_ENTRY);
}

#[derive(Debug)]
pub struct Image {
    boot_sector: Vec<u8>,
    fat_1: Vec<u8>,
    fat_2: Vec<u8>,
    root_dir: Vec<u8>,
    data_area: Vec<u8>,
    bpb_data: BIOSParam,
}

#[allow(dead_code)]
impl Image {
    /// Create a new blank FAT Image from a defined BPB
    fn new(bpb: BIOSParam, length: usize) -> Image {
        let boot_sector_size = bpb.bytes_per_sector as usize
            * bpb.reserved_sectors as usize;
        let bytes_per_fat = (bpb.sectors_per_fat
            * bpb.bytes_per_sector as u32) as usize;
        let bytes_per_root = SECTORS_PER_ROOT * bpb.bytes_per_sector as usize;
        let data_offset = boot_sector_size as usize
            + (bytes_per_fat * 2) as usize + bytes_per_root as usize;
        let bytes_per_data_area = length - data_offset;
        Image {
            boot_sector: vec![0; boot_sector_size],
            fat_1: vec![0; bytes_per_fat],
            fat_2: vec![0; bytes_per_fat],
            root_dir: vec![0; bytes_per_root],
            data_area: vec![0; bytes_per_data_area],
            bpb_data: bpb,
        }
    }

    /// Create a new FAT Image from the specified file.
    pub fn from_file<P: AsRef<Path>>(image_fn: P)
        -> Result<Image, Box<error::Error>>
    {
        let metadata = fs::metadata(image_fn.as_ref())?;
        let bpb = BIOSParam::from_file(image_fn.as_ref(), 0)?;

        let mut file = fs::File::open(image_fn.as_ref())?;
        let mut image = Image::new(bpb, metadata.len() as usize);

        try!(file.read_exact(&mut image.boot_sector));
        try!(file.read_exact(&mut image.fat_1));
        try!(file.read_exact(&mut image.fat_2));
        try!(file.read_exact(&mut image.root_dir));
        try!(file.read_exact(&mut image.data_area));

        Ok(image)
    }

    /// Create a new FAT Image from the specified file and offset.
    pub fn from_file_offset<P: AsRef<Path>>(image_fn: P, start: usize, length: usize)
        -> Result<Image, Box<error::Error>>
    {
        let metadata = fs::metadata(image_fn.as_ref())?;
        let bpb = BIOSParam::from_file(image_fn.as_ref(), start)?;

        if metadata.is_file() && (start + length > (metadata.len() as usize)) {
            return Err(From::from(format!("start + offset outside image bounds")));
        }

        let mut file = fs::File::open(image_fn.as_ref())?;
        file.seek(SeekFrom::Start(start as u64))?;

        let mut image = Image::new(bpb, length);

        try!(file.read_exact(&mut image.boot_sector));
        try!(file.read_exact(&mut image.fat_1));
        try!(file.read_exact(&mut image.fat_2));
        try!(file.read_exact(&mut image.root_dir));
        try!(file.read_exact(&mut image.data_area));

        Ok(image)
    }

    /// Save the FAT filesystem image to the specified file.
    pub fn save<P: AsRef<Path>>(&self, image_fn: P)
        -> Result<(), io::Error>
    {
        let mut file = fs::File::create(image_fn.as_ref())?;

        try!(file.write_all(&self.boot_sector));
        try!(file.write_all(&self.fat_1));
        try!(file.write_all(&self.fat_2));
        try!(file.write_all(&self.root_dir));
        try!(file.write_all(&self.data_area));

        Ok(())
    }

    /// Extract the BIOS Parameter Block (BPB) from the FAT filesystem.
    pub fn bios_parameter(&self) -> BIOSParam {
        self.bpb_data.clone()
    }

    /// FAT sector size in bytes.
    pub fn sector_size(&self) -> usize {
        self.bpb_data.bytes_per_sector as usize
    }

    /// FAT volume label
    pub fn volume_label(&self) -> Result<String, Box<error::Error>> {
        let entries = self.root_entries();
        for entry in entries {
            if !entry.is_volume_label() {
                continue;
            }
            let label = format!("{}{}",
                str::from_utf8(&entry.filename)?,
                str::from_utf8(&entry.extension)?);
            return Ok(label);
        }
        return Ok("has no label".to_string());
    }

    // TODO: Make iterator once "impl Trait" is stable.
    /// Return all FAT root entries (including unused)
    pub fn root_entries_all(&self) -> Vec<RootEntry> {
        self.root_dir
            .chunks(BYTES_PER_ROOT_ENTRY)
            .map(|chunk| {
                let mut entry_bytes = [0; BYTES_PER_ROOT_ENTRY];
                entry_bytes.clone_from_slice(chunk);

                let entry: RootEntry;
                unsafe { entry = mem::transmute(entry_bytes); }
                entry
            })
            .collect::<Vec<RootEntry>>()
    }

    // TODO: Make iterator once "impl Trait" is stable.
    /// Return used FAT root entries
    pub fn root_entries(&self) -> Vec<RootEntry> {
        self.root_dir
            .chunks(BYTES_PER_ROOT_ENTRY)
            .map(|chunk| {
                let mut entry_bytes = [0; BYTES_PER_ROOT_ENTRY];
                entry_bytes.clone_from_slice(chunk);

                let entry: RootEntry;
                unsafe { entry = mem::transmute(entry_bytes); }
                entry
            })
            .filter(|entry| { entry.filename[0] != 0xe5 })
            .take_while(|entry| { entry.filename[0] != 0 })
            .collect::<Vec<RootEntry>>()
    }

    /// Get the RootEntry for the specified file within the Image.
    pub fn get_file_entry(&self, filename: String)
        -> Result<RootEntry, Box<error::Error>>
    {
        let entries = self.root_entries();
        for entry in entries {
            let entry_name: String;
            match entry.filename() {
                Ok(name) => entry_name = name,
                Err(_) => continue,
            }

            if entry_name.to_lowercase() == filename.to_lowercase() {
                return Ok(entry);
            }
        }

        Err(From::from(format!("file {} not found", filename)))
    }

    /// Create a new RootEntry within the Image with the specified filename.
    pub fn create_file_entry(&self, filename: String, bytes: u32)
        -> Result<(RootEntry, u16), Box<error::Error>>
    {
        match self.get_file_entry(filename.clone()) {
            Ok(_) => return Err(From::from("entry already exists")),
            Err(_) => {}
        }

        for (index, e) in self.root_entries_all().iter().enumerate() {
            if !e.is_free() { continue; }

            let mut entry = RootEntry::new();
            entry.set_filename(filename)?;
            entry.set_size(bytes)?;
            return Ok((entry.clone(), index as u16));
        }

        Err(From::from("no free entries"))
    }

    pub fn save_file_entry(&mut self, entry: RootEntry, index: u16)
        -> Result<(), Box<error::Error>>
    {
        let entry_bytes: [u8; BYTES_PER_ROOT_ENTRY];
        unsafe { entry_bytes = mem::transmute(entry); }

        self.root_dir[
            index as usize * BYTES_PER_ROOT_ENTRY ..
            (index as usize + 1) * BYTES_PER_ROOT_ENTRY
        ].clone_from_slice(&entry_bytes[..]);
        Ok(())
    }

    pub fn fat_entries<'a>(&'a self)
        -> Box<Iterator<Item=(usize, u16)> + 'a>
    {
        Box::new(
            self.fat_1
            .windows(2)
            .enumerate()
            .filter_map(|(i, w)|
                if i % 3 == 2 {
                    None
                } else {
                    let val = if i % 3 == 0 {
                        ((w[1] as u16 & 0xf) << 8) | w[0] as u16
                    } else {
                        (w[1] as u16 & 0xf0) | ((w[1] as u16) << 4)
                    };
                    Some((i, val))
                }
            )
        )
    }

    pub fn get_fat_entry(&self, cluster_num: u16) -> u16 {
        let offset: usize = cluster_num as usize * 3 / 2;
        let byte_1: u16 = self.fat_1[offset] as u16;
        let byte_2: u16 = self.fat_1[offset + 1] as u16;

        if cluster_num % 2 == 0 { byte_1 | ((byte_2 & 0x0f) << 8) }
        else                    { (byte_1 >> 4) | (byte_2 << 4) }
    }

    pub fn get_free_fat_entry(&self) -> Option<usize> {
        self.fat_entries()
            .filter(|&(_, e)| e == 0)
            .map(|(i, _)| i + 2)
            .nth(0)
    }

    pub fn write_data_sector(&mut self, sector: usize, data: &[u8])
        -> Result<(), Box<error::Error>>
    {
        let sector = sector - 2;
        let bytes_per_sector = self.bpb_data.bytes_per_sector as usize;
        let start_byte = bytes_per_sector * sector;

        if start_byte >= self.data_area.len() {
            return Err(From::from(format!("sector {} too high to write to", sector)))
        }

        let mut target_slice = &mut self.data_area[start_byte..start_byte + data.len()];
        target_slice.copy_from_slice(data);
        Ok(())
    }
}
<commit_msg>fat/image: Fix image structure due to tiny root area (#6)<commit_after>use std::error;
use std::fs;
use std::io;
use std::io::{Read,Write,SeekFrom,Seek};
use std::mem;
use std::str;
use std::path::Path;

use fat::RootEntry;
use fat::BIOSParam;

// Always the same
const BYTES_PER_ROOT_ENTRY: usize = 32;

#[test]
fn test_root_entry_size() {
    assert_eq!(mem::size_of::<RootEntry>(), BYTES_PER_ROOT_ENTRY);
}

#[derive(Debug)]
pub struct Image {
    boot_sector: Vec<u8>,
    fat_1: Vec<u8>,
    fat_2: Vec<u8>,
    root_dir: Vec<u8>,
    data_area: Vec<u8>,
    bpb_data: BIOSParam,
}

#[allow(dead_code)]
impl Image {
    /// Create a new blank FAT Image from a defined BPB
    fn new(bpb: BIOSParam, length: usize) -> Image {
        let boot_sector_size = bpb.bytes_per_sector as usize
            * bpb.reserved_sectors as usize;
        let bytes_per_fat = (bpb.sectors_per_fat
            * bpb.bytes_per_sector as u32) as usize;
        let bytes_of_roots =
            (bpb.max_roots as usize * BYTES_PER_ROOT_ENTRY) as usize;
        let data_offset = boot_sector_size as usize
            + (bytes_per_fat * 2) as usize + bytes_of_roots as usize;
        let bytes_per_data_area = length - data_offset;
        Image {
            boot_sector: vec![0; boot_sector_size],
            fat_1: vec![0; bytes_per_fat],
            fat_2: vec![0; bytes_per_fat],
            root_dir: vec![0; bytes_of_roots],
            data_area: vec![0; bytes_per_data_area],
            bpb_data: bpb,
        }
    }

    /// Create a new FAT Image from the specified file.
    pub fn from_file<P: AsRef<Path>>(image_fn: P)
        -> Result<Image, Box<error::Error>>
    {
        let metadata = fs::metadata(image_fn.as_ref())?;
        let bpb = BIOSParam::from_file(image_fn.as_ref(), 0)?;

        let mut file = fs::File::open(image_fn.as_ref())?;
        let mut image = Image::new(bpb, metadata.len() as usize);

        try!(file.read_exact(&mut image.boot_sector));
        try!(file.read_exact(&mut image.fat_1));
        try!(file.read_exact(&mut image.fat_2));
        try!(file.read_exact(&mut image.root_dir));
        try!(file.read_exact(&mut image.data_area));

        Ok(image)
    }

    /// Create a new FAT Image from the specified file and offset.
    pub fn from_file_offset<P: AsRef<Path>>(image_fn: P, start: usize, length: usize)
        -> Result<Image, Box<error::Error>>
    {
        let metadata = fs::metadata(image_fn.as_ref())?;
        let bpb = BIOSParam::from_file(image_fn.as_ref(), start)?;

        if metadata.is_file() && (start + length > (metadata.len() as usize)) {
            return Err(From::from(format!("start + offset outside image bounds")));
        }

        let mut file = fs::File::open(image_fn.as_ref())?;
        file.seek(SeekFrom::Start(start as u64))?;

        let mut image = Image::new(bpb, length);

        try!(file.read_exact(&mut image.boot_sector));
        try!(file.read_exact(&mut image.fat_1));
        try!(file.read_exact(&mut image.fat_2));
        try!(file.read_exact(&mut image.root_dir));
        try!(file.read_exact(&mut image.data_area));

        Ok(image)
    }

    /// Save the FAT filesystem image to the specified file.
    pub fn save<P: AsRef<Path>>(&self, image_fn: P)
        -> Result<(), io::Error>
    {
        let mut file = fs::File::create(image_fn.as_ref())?;

        try!(file.write_all(&self.boot_sector));
        try!(file.write_all(&self.fat_1));
        try!(file.write_all(&self.fat_2));
        try!(file.write_all(&self.root_dir));
        try!(file.write_all(&self.data_area));

        Ok(())
    }

    /// Extract the BIOS Parameter Block (BPB) from the FAT filesystem.
    pub fn bios_parameter(&self) -> BIOSParam {
        self.bpb_data.clone()
    }

    /// FAT sector size in bytes.
    pub fn sector_size(&self) -> usize {
        self.bpb_data.bytes_per_sector as usize
    }

    /// FAT volume label
    pub fn volume_label(&self) -> Result<String, Box<error::Error>> {
        let entries = self.root_entries();
        for entry in entries {
            if !entry.is_volume_label() {
                continue;
            }
            let label = format!("{}{}",
                str::from_utf8(&entry.filename)?,
                str::from_utf8(&entry.extension)?);
            return Ok(label);
        }
        return Ok("has no label".to_string());
    }

    // TODO: Make iterator once "impl Trait" is stable.
    /// Return all FAT root entries (including unused)
    pub fn root_entries_all(&self) -> Vec<RootEntry> {
        self.root_dir
            .chunks(BYTES_PER_ROOT_ENTRY)
            .map(|chunk| {
                let mut entry_bytes = [0; BYTES_PER_ROOT_ENTRY];
                entry_bytes.clone_from_slice(chunk);

                let entry: RootEntry;
                unsafe { entry = mem::transmute(entry_bytes); }
                entry
            })
            .collect::<Vec<RootEntry>>()
    }

    // TODO: Make iterator once "impl Trait" is stable.
    /// Return used FAT root entries
    pub fn root_entries(&self) -> Vec<RootEntry> {
        self.root_dir
            .chunks(BYTES_PER_ROOT_ENTRY)
            .map(|chunk| {
                let mut entry_bytes = [0; BYTES_PER_ROOT_ENTRY];
                entry_bytes.clone_from_slice(chunk);

                let entry: RootEntry;
                unsafe { entry = mem::transmute(entry_bytes); }
                entry
            })
            .filter(|entry| { entry.filename[0] != 0xe5 })
            .take_while(|entry| { entry.filename[0] != 0 })
            .collect::<Vec<RootEntry>>()
    }

    /// Get the RootEntry for the specified file within the Image.
    pub fn get_file_entry(&self, filename: String)
        -> Result<RootEntry, Box<error::Error>>
    {
        let entries = self.root_entries();
        for entry in entries {
            let entry_name: String;
            match entry.filename() {
                Ok(name) => entry_name = name,
                Err(_) => continue,
            }

            if entry_name.to_lowercase() == filename.to_lowercase() {
                return Ok(entry);
            }
        }

        Err(From::from(format!("file {} not found", filename)))
    }

    /// Create a new RootEntry within the Image with the specified filename.
    pub fn create_file_entry(&self, filename: String, bytes: u32)
        -> Result<(RootEntry, u16), Box<error::Error>>
    {
        match self.get_file_entry(filename.clone()) {
            Ok(_) => return Err(From::from("entry already exists")),
            Err(_) => {}
        }

        for (index, e) in self.root_entries_all().iter().enumerate() {
            if !e.is_free() { continue; }

            let mut entry = RootEntry::new();
            entry.set_filename(filename)?;
            entry.set_size(bytes)?;
            return Ok((entry.clone(), index as u16));
        }

        Err(From::from("no free entries"))
    }

    pub fn save_file_entry(&mut self, entry: RootEntry, index: u16)
        -> Result<(), Box<error::Error>>
    {
        let entry_bytes: [u8; BYTES_PER_ROOT_ENTRY];
        unsafe { entry_bytes = mem::transmute(entry); }

        self.root_dir[
            index as usize * BYTES_PER_ROOT_ENTRY ..
            (index as usize + 1) * BYTES_PER_ROOT_ENTRY
        ].clone_from_slice(&entry_bytes[..]);
        Ok(())
    }

    pub fn fat_entries<'a>(&'a self)
        -> Box<Iterator<Item=(usize, u16)> + 'a>
    {
        Box::new(
            self.fat_1
            .windows(2)
            .enumerate()
            .filter_map(|(i, w)|
                if i % 3 == 2 {
                    None
                } else {
                    let val = if i % 3 == 0 {
                        ((w[1] as u16 & 0xf) << 8) | w[0] as u16
                    } else {
                        (w[1] as u16 & 0xf0) | ((w[1] as u16) << 4)
                    };
                    Some((i, val))
                }
            )
        )
    }

    pub fn get_fat_entry(&self, cluster_num: u16) -> u16 {
        let offset: usize = cluster_num as usize * 3 / 2;
        let byte_1: u16 = self.fat_1[offset] as u16;
        let byte_2: u16 = self.fat_1[offset + 1] as u16;

        if cluster_num % 2 == 0 { byte_1 | ((byte_2 & 0x0f) << 8) }
        else                    { (byte_1 >> 4) | (byte_2 << 4) }
    }

    pub fn get_free_fat_entry(&self) -> Option<usize> {
        self.fat_entries()
            .filter(|&(_, e)| e == 0)
            .map(|(i, _)| i + 2)
            .nth(0)
    }

    pub fn write_data_sector(&mut self, sector: usize, data: &[u8])
        -> Result<(), Box<error::Error>>
    {
        let sector = sector - 2;
        let bytes_per_sector = self.bpb_data.bytes_per_sector as usize;
        let start_byte = bytes_per_sector * sector;

        if start_byte >= self.data_area.len() {
            return Err(From::from(format!("sector {} too high to write to", sector)))
        }

        let mut target_slice = &mut self.data_area[start_byte..start_byte + data.len()];
        target_slice.copy_from_slice(data);
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Generic 'microcode' implementations of the operations.

use types::*;
use instruction::{Dest, Instruction, Src};
use fonts;
use config::Config;

pub fn add(exec: &mut Execute, dest: Dest, lhs: Src, rhs: Src) -> Chip8Result<()> {
    let l = try!(exec.load(lhs));
    let r = try!(exec.load(rhs));
    let total = l + r;
    exec.set_flag(total > 0xFF);  //set vF if result overflows
    exec.store(dest, total)
}

pub fn sub(exec: &mut Execute, dest: Dest, lhs: Src, rhs: Src) -> Chip8Result<()> {
    let l = try!(exec.load(lhs));
    let r = try!(exec.load(rhs));
    let total = (l - r) & 0xFF;
    //set vF if NOT borrow
    exec.set_flag(l > r);
    exec.store(dest, total)
}

pub fn load(exec: &mut Execute, dest: Dest, src: Src) -> Chip8Result<()> {
    let data = try!(exec.load(src));
    println!("{:?}", data);
    exec.store(dest, data)
}

// Stores registers v0.. to ram[I]
pub fn stash(exec: &mut Execute, first: Src, last: Src) -> Chip8Result<()> {
    let first_reg = if let Src::Register(r) = first { r } else { return Err(Chip8Error::InvalidOperand) };
    let last_reg = if let Src::Register(r) = last { r } else { return Err(Chip8Error::InvalidOperand) };

    println!("stash {:?}-{:?}", first_reg, last_reg);

    let i = try!(exec.load(Src::I));
    let mut offset = 0;
    for r in first_reg...last_reg {
        let value = try!(exec.load(Src::Register(r)));
        try!(exec.store(Dest::Address12(i + offset), value));
        offset += 1;
    }
    exec.store(Dest::I, i + offset)
}

// Fetches several bytes, pointed to by I, into v0..
pub fn fetch(exec: &mut Execute, first: Src, last: Src) -> Chip8Result<()> {
    println!("fetch {:?} {:?}", first, last);
    let first_reg = match first {
        Src::Register(r) => r,
        Src::Const(n) => n,
        _ => { return Err(Chip8Error::InvalidOperand) },
    };

    let last_reg = match last {
        Src::Register(r) => r,
        Src::Const(n) => n,
        _ => { return Err(Chip8Error::InvalidOperand) },
    };

    println!("fetch {:?}-{:?}", first_reg, last_reg);
    let i = try!(exec.load(Src::I));
    for r in 0...last_reg {
        let value = try!(exec.load(Src::Address12(i + r)));
        try!(exec.store(Dest::Register(r), value));
    }
    exec.store(Dest::I, i + last_reg + 1)
}

pub fn jump(exec: &mut Execute, addr: Src) -> Chip8Result<()> {
    if let Src::Address12(a) = addr {
        exec.jump(a as Address)
    } else {
        Err(Chip8Error::InvalidOperand)
    }
}

pub fn jump_v0(exec: &mut Execute, addr: Src) -> Chip8Result<()> {
    let v0 = try!(exec.load(Src::Register(0)));
    if let Src::Address12(a) = addr {
        exec.jump((a + v0) as Address)
    } else {
        Err(Chip8Error::InvalidOperand)
    }
}

pub fn call(exec: &mut Execute, addr: Src) -> Chip8Result<()> {
    if let Src::Address12(a) = addr {
        let pc = exec.pc();
        exec.stack_push(pc);
        exec.jump(a as Address)
    } else {
        Err(Chip8Error::InvalidOperand)
    }
}

pub fn ret(exec: &mut Execute) -> Chip8Result<()> {
    if let Some(a) = exec.stack_pop() {
        exec.jump(a)
    } else {
        Err(Chip8Error::PopEmptyStack)
    }
}

pub fn or(exec: &mut Execute, dest: Dest, lhs: Src, rhs: Src) -> Chip8Result<()> {
    let lhs = exec.load(lhs)?;
    let rhs = exec.load(rhs)?;
    let result = lhs | rhs;
    exec.store(dest, result)
}

pub fn and(exec: &mut Execute, dest: Dest, lhs: Src, rhs: Src) -> Chip8Result<()> {
    let lhs = exec.load(lhs)?;
    let rhs = exec.load(rhs)?;
    let result = lhs & rhs;
    exec.store(dest, result)
}

pub fn xor(exec: &mut Execute, dest: Dest, lhs: Src, rhs: Src) -> Chip8Result<()> {
    let lhs = exec.load(lhs)?;
    let rhs = exec.load(rhs)?;
    let result = lhs ^ rhs;
    exec.store(dest, result)
}

// Shifts the source right 1 bit, and stores in dest. vF set to old LSB
pub fn shr(exec: &mut Execute, dest: Dest, src: Src) -> Chip8Result<()> {
    let value = try!(exec.load(src));
    let carry = (value & 1) == 1;
    let result = value >> 1;
    exec.store(dest, result);
    exec.set_flag(carry);
    Ok(())
}

// Shifts the source left 1 bit, and stores in dest. vF set to old MSB
pub fn shl(exec: &mut Execute, dest: Dest, src: Src) -> Chip8Result<()> {
    let value = try!(exec.load(src));
    let carry = (value & 0x80) == 0x80;
    let result = value << 1;
    try!(exec.store(dest, result));
    exec.set_flag(carry);
    Ok(())
}

pub fn font(exec: &mut Execute, glyph: Src, font: Src) -> Chip8Result<()> {
    let font_code = try!(exec.load(font));
    let addr;
    if font_code == fonts::CODE_SMALL {
        addr = exec.config().addr_font + try!(exec.load(glyph)) * 5;
    } else {
        addr = exec.config().addr_font_big + try!(exec.load(glyph)) * 10;
    }
    exec.store(Dest::I, addr)
}

pub fn bcd(exec: &mut Execute, src: Src) -> Chip8Result<()> {
    let mut val = try!(exec.load(src));
    let hundreds = val / 100;
    val -= hundreds * 100;
    let tens = val / 10;
    let ones = val - tens * 10;
    let i = try!(exec.load(Src::I));
    try!(exec.store(Dest::Address12(i), hundreds));
    try!(exec.store(Dest::Address12(i + 1), tens));
    try!(exec.store(Dest::Address12(i + 2), ones));
    Ok(())
}

// Skips the next instruction if src == dest.
pub fn skip_eq(exec: &mut Execute, lhs: Src, rhs: Src) -> Chip8Result<()> {
    let l = try!(exec.load(lhs));
    let r = try!(exec.load(rhs));
    if l == r { exec.advance_pc(); }
    Ok(())
}

pub fn skip_not_eq(exec: &mut Execute, lhs: Src, rhs: Src) -> Chip8Result<()> {
    let l = try!(exec.load(lhs));
    let r = try!(exec.load(rhs));
    if l != r { exec.advance_pc(); }
    Ok(())
}

pub fn skip_key_pressed(exec: &mut Execute, key: Src) -> Chip8Result<()> {
    let key_state = false;
    if key_state { exec.advance_pc(); }
    Ok(())
}

pub fn skip_key_not_pressed(exec: &mut Execute, key: Src) -> Chip8Result<()> {
    let key_state = false;
    if !key_state { exec.advance_pc(); }
    Ok(())
}

/// Halt execution until a key is pressed.
pub fn wait_key(exec: &mut Execute, dest: Dest, key: Src) -> Chip8Result<()> {
    Ok(())
}

pub fn clear_screen(exec: &mut Execute) -> Chip8Result<()> {
    Ok(())
}

pub fn sprite(exec: &mut Execute, x: Src, y: Src, n: Src) -> Chip8Result<()> {
    let mut x = try!(exec.load(x));
    let mut y = try!(exec.load(y));
    let n = try!(exec.load(n));

    let mut addr = try!(exec.load(Src::I));

    let mut flag = false;

    for x in x..n+x {
        let data = try!(exec.load(Src::Address12(addr)));
        for bit in 0..8 {
            flag |= try!(exec.set_pixel(x, y+(7-bit), ((data >> bit) & 1) as Pixel));
        }
    }
    Ok(())
}

pub fn random(exec: &mut Execute, dest: Dest, src: Src, mask: Src) -> Chip8Result<()> {
    let data = try!(exec.load(src));
    let mask = try!(exec.load(mask));
    let result = data & mask;
    exec.store(dest, result)
}
<commit_msg>Improve sprite<commit_after>//! Generic 'microcode' implementations of the operations.

use types::*;
use instruction::{Dest, Instruction, Src};
use fonts;
use config::Config;

pub fn add(exec: &mut Execute, dest: Dest, lhs: Src, rhs: Src) -> Chip8Result<()> {
    let l = try!(exec.load(lhs));
    let r = try!(exec.load(rhs));
    let total = l + r;
    exec.set_flag(total > 0xFF);  //set vF if result overflows
    exec.store(dest, total)
}

pub fn sub(exec: &mut Execute, dest: Dest, lhs: Src, rhs: Src) -> Chip8Result<()> {
    let l = try!(exec.load(lhs));
    let r = try!(exec.load(rhs));
    let total = (l - r) & 0xFF;
    //set vF if NOT borrow
    exec.set_flag(l > r);
    exec.store(dest, total)
}

pub fn load(exec: &mut Execute, dest: Dest, src: Src) -> Chip8Result<()> {
    let data = try!(exec.load(src));
    println!("{:?}", data);
    exec.store(dest, data)
}

// Stores registers v0.. to ram[I]
pub fn stash(exec: &mut Execute, first: Src, last: Src) -> Chip8Result<()> {
    let first_reg = if let Src::Register(r) = first { r } else { return Err(Chip8Error::InvalidOperand) };
    let last_reg = if let Src::Register(r) = last { r } else { return Err(Chip8Error::InvalidOperand) };

    println!("stash {:?}-{:?}", first_reg, last_reg);

    let i = try!(exec.load(Src::I));
    let mut offset = 0;
    for r in first_reg...last_reg {
        let value = try!(exec.load(Src::Register(r)));
        try!(exec.store(Dest::Address12(i + offset), value));
        offset += 1;
    }
    exec.store(Dest::I, i + offset)
}

// Fetches several bytes, pointed to by I, into v0..
pub fn fetch(exec: &mut Execute, first: Src, last: Src) -> Chip8Result<()> {
    println!("fetch {:?} {:?}", first, last);
    let first_reg = match first {
        Src::Register(r) => r,
        Src::Const(n) => n,
        _ => { return Err(Chip8Error::InvalidOperand) },
    };

    let last_reg = match last {
        Src::Register(r) => r,
        Src::Const(n) => n,
        _ => { return Err(Chip8Error::InvalidOperand) },
    };

    println!("fetch {:?}-{:?}", first_reg, last_reg);
    let i = try!(exec.load(Src::I));
    for r in 0...last_reg {
        let value = try!(exec.load(Src::Address12(i + r)));
        try!(exec.store(Dest::Register(r), value));
    }
    exec.store(Dest::I, i + last_reg + 1)
}

pub fn jump(exec: &mut Execute, addr: Src) -> Chip8Result<()> {
    if let Src::Address12(a) = addr {
        exec.jump(a as Address)
    } else {
        Err(Chip8Error::InvalidOperand)
    }
}

pub fn jump_v0(exec: &mut Execute, addr: Src) -> Chip8Result<()> {
    let v0 = try!(exec.load(Src::Register(0)));
    if let Src::Address12(a) = addr {
        exec.jump((a + v0) as Address)
    } else {
        Err(Chip8Error::InvalidOperand)
    }
}

pub fn call(exec: &mut Execute, addr: Src) -> Chip8Result<()> {
    if let Src::Address12(a) = addr {
        let pc = exec.pc();
        exec.stack_push(pc);
        exec.jump(a as Address)
    } else {
        Err(Chip8Error::InvalidOperand)
    }
}

pub fn ret(exec: &mut Execute) -> Chip8Result<()> {
    if let Some(a) = exec.stack_pop() {
        exec.jump(a)
    } else {
        Err(Chip8Error::PopEmptyStack)
    }
}

pub fn or(exec: &mut Execute, dest: Dest, lhs: Src, rhs: Src) -> Chip8Result<()> {
    let lhs = exec.load(lhs)?;
    let rhs = exec.load(rhs)?;
    let result = lhs | rhs;
    exec.store(dest, result)
}

pub fn and(exec: &mut Execute, dest: Dest, lhs: Src, rhs: Src) -> Chip8Result<()> {
    let lhs = exec.load(lhs)?;
    let rhs = exec.load(rhs)?;
    let result = lhs & rhs;
    exec.store(dest, result)
}

pub fn xor(exec: &mut Execute, dest: Dest, lhs: Src, rhs: Src) -> Chip8Result<()> {
    let lhs = exec.load(lhs)?;
    let rhs = exec.load(rhs)?;
    let result = lhs ^ rhs;
    exec.store(dest, result)
}

// Shifts the source right 1 bit, and stores in dest. vF set to old LSB
pub fn shr(exec: &mut Execute, dest: Dest, src: Src) -> Chip8Result<()> {
    let value = try!(exec.load(src));
    let carry = (value & 1) == 1;
    let result = value >> 1;
    exec.store(dest, result);
    exec.set_flag(carry);
    Ok(())
}

// Shifts the source left 1 bit, and stores in dest. vF set to old MSB
pub fn shl(exec: &mut Execute, dest: Dest, src: Src) -> Chip8Result<()> {
    let value = try!(exec.load(src));
    let carry = (value & 0x80) == 0x80;
    let result = value << 1;
    try!(exec.store(dest, result));
    exec.set_flag(carry);
    Ok(())
}

pub fn font(exec: &mut Execute, glyph: Src, font: Src) -> Chip8Result<()> {
    let font_code = try!(exec.load(font));
    let addr;
    if font_code == fonts::CODE_SMALL {
        addr = exec.config().addr_font + try!(exec.load(glyph)) * 5;
    } else {
        addr = exec.config().addr_font_big + try!(exec.load(glyph)) * 10;
    }
    exec.store(Dest::I, addr)
}

pub fn bcd(exec: &mut Execute, src: Src) -> Chip8Result<()> {
    let mut val = try!(exec.load(src));
    let hundreds = val / 100;
    val -= hundreds * 100;
    let tens = val / 10;
    let ones = val - tens * 10;
    let i = try!(exec.load(Src::I));
    try!(exec.store(Dest::Address12(i), hundreds));
    try!(exec.store(Dest::Address12(i + 1), tens));
    try!(exec.store(Dest::Address12(i + 2), ones));
    Ok(())
}

// Skips the next instruction if src == dest.
pub fn skip_eq(exec: &mut Execute, lhs: Src, rhs: Src) -> Chip8Result<()> {
    let l = try!(exec.load(lhs));
    let r = try!(exec.load(rhs));
    if l == r { exec.advance_pc(); }
    Ok(())
}

pub fn skip_not_eq(exec: &mut Execute, lhs: Src, rhs: Src) -> Chip8Result<()> {
    let l = try!(exec.load(lhs));
    let r = try!(exec.load(rhs));
    if l != r { exec.advance_pc(); }
    Ok(())
}

pub fn skip_key_pressed(exec: &mut Execute, key: Src) -> Chip8Result<()> {
    let key_state = false;
    if key_state { exec.advance_pc(); }
    Ok(())
}

pub fn skip_key_not_pressed(exec: &mut Execute, key: Src) -> Chip8Result<()> {
    let key_state = false;
    if !key_state { exec.advance_pc(); }
    Ok(())
}

/// Halt execution until a key is pressed.
pub fn wait_key(exec: &mut Execute, dest: Dest, key: Src) -> Chip8Result<()> {
    Ok(())
}

pub fn clear_screen(exec: &mut Execute) -> Chip8Result<()> {
    Ok(())
}

pub fn sprite(exec: &mut Execute, x: Src, y: Src, n: Src) -> Chip8Result<()> {
    let mut x = try!(exec.load(x));
    let mut y = try!(exec.load(y));
    let n = try!(exec.load(n));

    let mut addr = try!(exec.load(Src::I));

    let mut flag = false;

    for y in y..n+y {
        let data = try!(exec.load(Src::Address12(addr)));
        for bit in 0..8 {
            flag |= try!(exec.set_pixel(x+(7-bit), y, ((data >> bit) & 1) as Pixel));
        }
    }
    Ok(())
}

pub fn random(exec: &mut Execute, dest: Dest, src: Src, mask: Src) -> Chip8Result<()> {
    let data = try!(exec.load(src));
    let mask = try!(exec.load(mask));
    let result = data & mask;
    exec.store(dest, result)
}
<|endoftext|>


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

use languageserver_types::TextDocumentContentChangeEvent;

use gluon::base::source;
use gluon::base::pos::Span;

use rpc::ServerError;
use range_to_byte_span;

struct VersionedChange {
    version: u64,
    content_changes: Vec<TextDocumentContentChangeEvent>,
}

/// Type which applies text changes in the order that the client sends them.
/// Out of order changes are stored until all earlier changes have been received after which they
/// are applied all at once.
pub struct TextChanges {
    changes: VecDeque<VersionedChange>,
}

impl TextChanges {
    pub fn new() -> Self {
        TextChanges {
            changes: VecDeque::new(),
        }
    }

    pub fn add(&mut self, version: u64, content_changes: Vec<TextDocumentContentChangeEvent>) {
        let i = self.changes
            .iter()
            .position(|change| change.version > version)
            .unwrap_or(self.changes.len());
        self.changes.insert(
            i,
            VersionedChange {
                version,
                content_changes,
            },
        );
    }

    pub fn apply_changes(
        &mut self,
        source: &mut String,
        mut version: u64,
    ) -> Result<u64, ServerError<()>> {
        while let Some(change) = self.changes.pop_front() {
            assert!(
                change.version > version,
                "BUG: Attempt to apply old change on newer contents"
            );
            if version + 1 != change.version {
                self.changes.push_front(change);
                break;
            }
            version += 1;
            apply_changes(source, &change.content_changes)?
        }
        Ok(version)
    }
}

fn apply_changes(
    source: &mut String,
    content_changes: &[TextDocumentContentChangeEvent],
) -> Result<(), ServerError<()>> {
    for change in content_changes {
        let lines = source::Lines::new(source.as_bytes().iter().cloned());
        apply_change(source, &lines, change)?;
    }
    Ok(())
}

fn apply_change(
    source: &mut String,
    lines: &source::Lines,
    change: &TextDocumentContentChangeEvent,
) -> Result<(), ServerError<()>> {
    info!("Applying change: {:?}", change);
    let span = match (change.range, change.range_length) {
        (None, None) => Span::new(0.into(), source.len().into()),
        (Some(range), None) | (Some(range), Some(_)) => range_to_byte_span(lines, &range)?,
        (None, Some(_)) => return Err("Invalid change".into()),
    };
    source.drain(span.start.to_usize()..span.end.to_usize());
    source.insert_str(span.start.to_usize(), &change.text);
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    use languageserver_types::{Position, Range};

    #[test]
    fn apply_changes_test() {
        let mut source = String::new();
        apply_changes(
            &mut source,
            &[
                TextDocumentContentChangeEvent {
                    range: Some(Range {
                        start: Position {
                            line: 0,
                            character: 0,
                        },
                        end: Position {
                            line: 0,
                            character: 0,
                        },
                    }),
                    range_length: None,
                    text: "test".to_string(),
                },
            ],
        ).unwrap();

        assert_eq!(source, "test");

        apply_changes(
            &mut source,
            &[
                TextDocumentContentChangeEvent {
                    range: Some(Range {
                        start: Position {
                            line: 0,
                            character: 2,
                        },
                        end: Position {
                            line: 0,
                            character: 3,
                        },
                    }),
                    range_length: Some(1),
                    text: "".to_string(),
                },
            ],
        ).unwrap();

        assert_eq!(source, "tet");

        apply_changes(
            &mut source,
            &[
                TextDocumentContentChangeEvent {
                    range: Some(Range {
                        start: Position {
                            line: 0,
                            character: 2,
                        },
                        end: Position {
                            line: 0,
                            character: 3,
                        },
                    }),
                    range_length: Some(2),
                    text: "ab".to_string(),
                },
            ],
        ).unwrap();

        assert_eq!(source, "teab");
    }
}
<commit_msg>Let VS Code send empty changes<commit_after>use std::collections::VecDeque;

use languageserver_types::TextDocumentContentChangeEvent;

use gluon::base::source;
use gluon::base::pos::Span;

use rpc::ServerError;
use range_to_byte_span;

struct VersionedChange {
    version: u64,
    content_changes: Vec<TextDocumentContentChangeEvent>,
}

/// Type which applies text changes in the order that the client sends them.
/// Out of order changes are stored until all earlier changes have been received after which they
/// are applied all at once.
pub struct TextChanges {
    changes: VecDeque<VersionedChange>,
}

impl TextChanges {
    pub fn new() -> Self {
        TextChanges {
            changes: VecDeque::new(),
        }
    }

    pub fn add(&mut self, version: u64, content_changes: Vec<TextDocumentContentChangeEvent>) {
        let i = self.changes
            .iter()
            .position(|change| change.version > version)
            .unwrap_or(self.changes.len());
        self.changes.insert(
            i,
            VersionedChange {
                version,
                content_changes,
            },
        );
    }

    pub fn apply_changes(
        &mut self,
        source: &mut String,
        mut version: u64,
    ) -> Result<u64, ServerError<()>> {
        while let Some(change) = self.changes.pop_front() {
            assert!(
                (change.version == version && change.content_changes.is_empty())
                    || change.version > version,
                "BUG: Attempt to apply old change on newer contents"
            );
            if version + 1 != change.version {
                self.changes.push_front(change);
                break;
            }
            version += 1;
            apply_changes(source, &change.content_changes)?
        }
        Ok(version)
    }
}

fn apply_changes(
    source: &mut String,
    content_changes: &[TextDocumentContentChangeEvent],
) -> Result<(), ServerError<()>> {
    for change in content_changes {
        let lines = source::Lines::new(source.as_bytes().iter().cloned());
        apply_change(source, &lines, change)?;
    }
    Ok(())
}

fn apply_change(
    source: &mut String,
    lines: &source::Lines,
    change: &TextDocumentContentChangeEvent,
) -> Result<(), ServerError<()>> {
    info!("Applying change: {:?}", change);
    let span = match (change.range, change.range_length) {
        (None, None) => Span::new(0.into(), source.len().into()),
        (Some(range), None) | (Some(range), Some(_)) => range_to_byte_span(lines, &range)?,
        (None, Some(_)) => return Err("Invalid change".into()),
    };
    source.drain(span.start.to_usize()..span.end.to_usize());
    source.insert_str(span.start.to_usize(), &change.text);
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    use languageserver_types::{Position, Range};

    #[test]
    fn apply_changes_test() {
        let mut source = String::new();
        apply_changes(
            &mut source,
            &[
                TextDocumentContentChangeEvent {
                    range: Some(Range {
                        start: Position {
                            line: 0,
                            character: 0,
                        },
                        end: Position {
                            line: 0,
                            character: 0,
                        },
                    }),
                    range_length: None,
                    text: "test".to_string(),
                },
            ],
        ).unwrap();

        assert_eq!(source, "test");

        apply_changes(
            &mut source,
            &[
                TextDocumentContentChangeEvent {
                    range: Some(Range {
                        start: Position {
                            line: 0,
                            character: 2,
                        },
                        end: Position {
                            line: 0,
                            character: 3,
                        },
                    }),
                    range_length: Some(1),
                    text: "".to_string(),
                },
            ],
        ).unwrap();

        assert_eq!(source, "tet");

        apply_changes(
            &mut source,
            &[
                TextDocumentContentChangeEvent {
                    range: Some(Range {
                        start: Position {
                            line: 0,
                            character: 2,
                        },
                        end: Position {
                            line: 0,
                            character: 3,
                        },
                    }),
                    range_length: Some(2),
                    text: "ab".to_string(),
                },
            ],
        ).unwrap();

        assert_eq!(source, "teab");
    }
}
<|endoftext|>


<commit_before>// FIXME: The doctest doesn't run on `cargo test`, why?
/// Splits string into a vector of words. A word is any sequence of alphanumeric
/// characters. Non-words get into the vector one and one.
///
/// ```rust
/// assert_eq!(tokenize("Adam, Bea"), ["Adam", ", ", " ", "Bea"]);
/// ```
pub fn tokenize(input: &str) -> Vec<&str> {
    let mut first_alphanumeric_byte_index = 0;
    let mut last_was_alphanumeric = false;
    let mut result: Vec<&str> = Vec::new();
    let mut byte_index = 0;
    for character in input.chars() {
        let current_is_alphanumeric = character.is_alphanumeric();
        if current_is_alphanumeric {
            if last_was_alphanumeric {
                // Do nothing, keep working on the current word.
            } else {
                // Last was something else, we just started a new word.
                first_alphanumeric_byte_index = byte_index;
            }
        } else {
            // Current is something else
            if last_was_alphanumeric {
                // Push the word that just ended
                result.push(&input[first_alphanumeric_byte_index..byte_index]);
            }

            // Push current char
            result.push(&input[byte_index..(byte_index + character.len_utf8())]);
        }

        last_was_alphanumeric = current_is_alphanumeric;
        byte_index += character.len_utf8();
    }

    if last_was_alphanumeric {
        // Push the ending word
        result.push(&input[first_alphanumeric_byte_index..]);
    }

    return result;
}

#[cfg(test)]
mod tests {
    use super::*;

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_empty() {
        let no_strings: Vec<String> = Vec::new();
        assert_eq!(tokenize(""), no_strings);
    }

    #[test]
    fn test_words() {
        assert_eq!(tokenize("word"), ["word"]);
        assert_eq!(tokenize("Adam Bea"), ["Adam", " ", "Bea"]);
    }

    #[test]
    fn test_numbers() {
        assert_eq!(tokenize("123"), ["123"]);
        assert_eq!(tokenize("123 456"), ["123", " ", "456"]);
    }

    #[test]
    fn test_alphanumeric() {
        assert_eq!(tokenize("0xC0deCafe"), ["0xC0deCafe"]);
    }

    #[test]
    fn test_others() {
        assert_eq!(tokenize("+!,"), ["+", "!", ","]);
    }

    #[test]
    fn test_non_breaking_space() {
        assert_eq!(tokenize("\u{00a0}"), ["\u{00a0}"]);
        assert_eq!(tokenize("\u{00a0}s"), ["\u{00a0}", "s"]);
    }
}
<commit_msg>Optimize away some realloc()s<commit_after>// FIXME: The doctest doesn't run on `cargo test`, why?
/// Splits string into a vector of words. A word is any sequence of alphanumeric
/// characters. Non-words get into the vector one and one.
///
/// ```rust
/// assert_eq!(tokenize("Adam, Bea"), ["Adam", ", ", " ", "Bea"]);
/// ```
pub fn tokenize(input: &str) -> Vec<&str> {
    let mut first_alphanumeric_byte_index = 0;
    let mut last_was_alphanumeric = false;
    let mut result: Vec<&str> = Vec::with_capacity(input.len());
    let mut byte_index = 0;
    for character in input.chars() {
        let current_is_alphanumeric = character.is_alphanumeric();
        if current_is_alphanumeric {
            if last_was_alphanumeric {
                // Do nothing, keep working on the current word.
            } else {
                // Last was something else, we just started a new word.
                first_alphanumeric_byte_index = byte_index;
            }
        } else {
            // Current is something else
            if last_was_alphanumeric {
                // Push the word that just ended
                result.push(&input[first_alphanumeric_byte_index..byte_index]);
            }

            // Push current char
            result.push(&input[byte_index..(byte_index + character.len_utf8())]);
        }

        last_was_alphanumeric = current_is_alphanumeric;
        byte_index += character.len_utf8();
    }

    if last_was_alphanumeric {
        // Push the ending word
        result.push(&input[first_alphanumeric_byte_index..]);
    }

    return result;
}

#[cfg(test)]
mod tests {
    use super::*;

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_empty() {
        let no_strings: Vec<String> = Vec::new();
        assert_eq!(tokenize(""), no_strings);
    }

    #[test]
    fn test_words() {
        assert_eq!(tokenize("word"), ["word"]);
        assert_eq!(tokenize("Adam Bea"), ["Adam", " ", "Bea"]);
    }

    #[test]
    fn test_numbers() {
        assert_eq!(tokenize("123"), ["123"]);
        assert_eq!(tokenize("123 456"), ["123", " ", "456"]);
    }

    #[test]
    fn test_alphanumeric() {
        assert_eq!(tokenize("0xC0deCafe"), ["0xC0deCafe"]);
    }

    #[test]
    fn test_others() {
        assert_eq!(tokenize("+!,"), ["+", "!", ","]);
    }

    #[test]
    fn test_non_breaking_space() {
        assert_eq!(tokenize("\u{00a0}"), ["\u{00a0}"]);
        assert_eq!(tokenize("\u{00a0}s"), ["\u{00a0}", "s"]);
    }
}
<|endoftext|>