<commit_before>use std::collections::HashMap;
use std::fmt;
use std::io::{self, Write};
use std::iter::Peekable;
use std::process::{Command, ExitStatus};
use std::str::CharIndices;

// TODO(tsion): Use the readline library.
fn prompt(line: &mut String) -> io::Result<usize> {
    let current_dir = try!(std::env::current_dir());
    print!("{}> ", current_dir.display());
    try!(io::stdout().flush());
    io::stdin().read_line(line)
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum Ast {
    Empty,
    Call { command: String, args: Vec<String> }
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum Token {
    Newline,
    Whitespace,
    Text(String),
}

#[derive(Clone)]
struct Lexer<'a> {
    input: &'a str,
    iter: Peekable<CharIndices<'a>>,
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum ParseError {
    UnclosedDelimiter(char),
    UnexpectedChar(char),
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ParseError::UnclosedDelimiter(c) => write!(f, "unclosed delimiter: {}", c),
            ParseError::UnexpectedChar(c) => write!(f, "unexpected character {}", c),
        }
    }
}

impl<'a> Lexer<'a> {
    fn new(input: &str) -> Lexer {
        Lexer {
            input: input,
            iter: input.char_indices().peekable(),
        }
    }

    fn pos(&mut self) -> usize {
        self.iter.peek().map(|p| p.0).unwrap_or(self.input.len())
    }

    fn peek_char(&mut self) -> Option<char> {
        self.iter.peek().map(|p| p.1)
    }

    fn is_whitespace(c: char) -> bool {
        c == ' ' || c == '\t'
    }

    fn lex_whitespace(&mut self) -> Result<Token, ParseError> {
        while let Some(c) = self.peek_char() {
            if !Lexer::is_whitespace(c) { break; }
            self.iter.next();
        }

        Ok(Token::Whitespace)
    }

    fn lex_unquoted_text(&mut self) -> Result<Token, ParseError> {
        let start = self.pos();

        while let Some(c) = self.peek_char() {
            if Lexer::is_whitespace(c) || c == '\r' || c == '\n' { break; }
            self.iter.next();
        }

        let end = self.pos();

        Ok(Token::Text(String::from(&self.input[start..end])))
    }

    fn lex_quoted_text(&mut self) -> Result<Token, ParseError> {
        let delimiter = self.peek_char().unwrap();
        self.iter.next();

        let mut text = String::new();

        loop {
            if let Some(c) = self.peek_char() {
                self.iter.next();
                match c {
                    '\\' => { unimplemented!() },
                    c if c == delimiter => break,
                    c => { text.push(c) },
                }
            } else {
                return Err(ParseError::UnclosedDelimiter(delimiter))
            }
        }

        Ok(Token::Text(text))
    }
}

impl<'a> Iterator for Lexer<'a> {
    type Item = Result<Token, ParseError>;

    fn next(&mut self) -> Option<Result<Token, ParseError>> {
        self.peek_char().map(|peek_char| {
            match peek_char {
                '\r' | '\n'                  => { self.iter.next(); Ok(Token::Newline) },
                '"' | '\''                   => self.lex_quoted_text(),
                c if Lexer::is_whitespace(c) => self.lex_whitespace(),
                _                            => self.lex_unquoted_text(),
            }
        })
    }
}

#[derive(Clone)]
struct Parser<'a> {
    lexer: Lexer<'a>,
}

impl<'a> Parser<'a> {
    fn new(input: &str) -> Parser {
        Parser { lexer: Lexer::new(input) }
    }

    fn parse(&mut self) -> Result<Ast, ParseError> {
        if let Some(token_result) = self.lexer.next() {
            let token = try!(token_result);
            match token {
                Token::Whitespace | Token::Newline => self.parse(),
                Token::Text(command) => self.parse_call(command),
            }
        } else {
            Ok(Ast::Empty)
        }
    }

    fn parse_call(&mut self, command: String) -> Result<Ast, ParseError> {
        let mut args = vec![];

        for token_result in &mut self.lexer {
            let token = try!(token_result);
            match token {
                Token::Newline    => break,
                Token::Whitespace => {},
                Token::Text(arg)  => { args.push(arg); },
            }
        }

        Ok(Ast::Call { command: command, args: args })
    }
}

struct Builtin {
    name: &'static str,
    min_args: usize,
    max_args: usize,
    func: fn(&[String]) -> i32,
}

fn result_to_exit_code(cmd: &'static str, result: io::Result<()>) -> i32 {
    match result {
        Ok(()) => 0,
        Err(e) => {
            writeln!(&mut io::stderr(), "shroom: {}: {}", cmd, e).unwrap();
            1
        },
    }
}

fn builtin_cd(args: &[String]) -> i32 {
    if let Some(path) = args.get(0) {
        result_to_exit_code("cd", std::env::set_current_dir(path))
    } else if let Some(home) = std::env::home_dir() {
        result_to_exit_code("cd", std::env::set_current_dir(home))
    } else {
        writeln!(&mut io::stderr(), "shroom: cd: couldn't find home dir").unwrap();
        1
    }
}

fn builtin_exit(args: &[String]) -> i32 {
    if let Some(exit_code_str) = args.get(0) {
        match exit_code_str.parse() {
            Ok(exit_code) => std::process::exit(exit_code),
            Err(e) => {
                writeln!(&mut io::stderr(), "shroom: exit: can't parse exit code: {}", e).unwrap();
                1
            },
        }
    } else {
        std::process::exit(0);
    }
}

fn execute(ast: &Ast) -> i32 {
    let mut builtins = HashMap::new();

    builtins.insert("cd", Builtin {
        name: "cd",
        min_args: 0,
        max_args: 1,
        func: builtin_cd,
    });

    builtins.insert("exit", Builtin {
        name: "exit",
        min_args: 0,
        max_args: 1,
        func: builtin_exit,
    });

    match *ast {
        Ast::Empty => 0,

        Ast::Call { ref command, ref args } => {
            if let Some(builtin) = builtins.get(&command[..]) {
                if args.len() < builtin.min_args {
                    writeln!(&mut io::stderr(), "shroom: {}: not enough arguments",
                             builtin.name).unwrap();
                    1
                } else if args.len() > builtin.max_args {
                    writeln!(&mut io::stderr(), "shroom: {}: too many arguments",
                             builtin.name).unwrap();
                    1
                } else {
                    (builtin.func)(args)
                }
            } else {
                match Command::new(command).args(args).status() {
                    Ok(exit_status) => {
                        #[cfg(unix)]
                        fn exit_signal(exit_status: &ExitStatus) -> Option<i32> {
                            use std::os::unix::process::ExitStatusExt;
                            exit_status.signal()
                        }

                        #[cfg(not(unix))]
                        fn exit_signal(_exit_status: &ExitStatus) -> Option<i32> {
                            None
                        }

                        if let Some(code) = exit_status.code() {
                            code
                        } else if let Some(signal) = exit_signal(&exit_status) {
                            128 + signal
                        } else {
                            127
                        }
                    },

                    Err(e) => {
                        writeln!(&mut io::stderr(), "shroom: {}: {}", command, e).unwrap();
                        127
                    },
                }
            }
        },
    }
}

fn main() {
    let mut line = String::new();
    loop {
        prompt(&mut line).unwrap();

        match Parser::new(&line).parse() {
            Ok(ast) => {
                let exit_code = execute(&ast);
                if exit_code != 0 {
                    println!("shroom: exit code: {}", exit_code);
                }
            },

            Err(parse_error) => {
                println!("shroom: parse error: {}", parse_error);
            },
        }

        line.clear();
    }
}
<commit_msg>Switch from CharIndices to Chars.<commit_after>use std::collections::HashMap;
use std::fmt;
use std::io::{self, Write};
use std::iter::Peekable;
use std::process::{Command, ExitStatus};
use std::str::Chars;

// TODO(tsion): Use the readline library.
fn prompt(line: &mut String) -> io::Result<usize> {
    let current_dir = try!(std::env::current_dir());
    print!("{}> ", current_dir.display());
    try!(io::stdout().flush());
    io::stdin().read_line(line)
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum Ast {
    Empty,
    Call { command: String, args: Vec<String> }
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum Token {
    Newline,
    Whitespace,
    Text(String),
}

#[derive(Clone)]
struct Lexer<'a> {
    input: &'a str,
    iter: Peekable<Chars<'a>>,
}

#[derive(Clone, Debug, Eq, PartialEq)]
enum ParseError {
    UnclosedDelimiter(char),
    UnexpectedChar(char),
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ParseError::UnclosedDelimiter(c) => write!(f, "unclosed delimiter: {}", c),
            ParseError::UnexpectedChar(c) => write!(f, "unexpected character {}", c),
        }
    }
}

impl<'a> Lexer<'a> {
    fn new(input: &str) -> Lexer {
        Lexer {
            input: input,
            iter: input.chars().peekable(),
        }
    }

    fn peek_char(&mut self) -> Option<char> {
        self.iter.peek().cloned()
    }

    fn is_whitespace(c: char) -> bool {
        c == ' ' || c == '\t'
    }

    fn lex_whitespace(&mut self) -> Result<Token, ParseError> {
        while let Some(c) = self.peek_char() {
            if !Lexer::is_whitespace(c) { break; }
            self.iter.next();
        }

        Ok(Token::Whitespace)
    }

    fn lex_unquoted_text(&mut self) -> Result<Token, ParseError> {
        let mut text = String::new();

        while let Some(c) = self.peek_char() {
            if Lexer::is_whitespace(c) || c == '\r' || c == '\n' { break; }
            text.push(c);
            self.iter.next();
        }

        Ok(Token::Text(text))
    }

    fn lex_quoted_text(&mut self) -> Result<Token, ParseError> {
        let delimiter = self.peek_char().unwrap();
        self.iter.next();

        let mut text = String::new();

        loop {
            if let Some(c) = self.peek_char() {
                self.iter.next();
                match c {
                    '\\' => { unimplemented!() },
                    c if c == delimiter => break,
                    c => { text.push(c) },
                }
            } else {
                return Err(ParseError::UnclosedDelimiter(delimiter))
            }
        }

        Ok(Token::Text(text))
    }
}

impl<'a> Iterator for Lexer<'a> {
    type Item = Result<Token, ParseError>;

    fn next(&mut self) -> Option<Result<Token, ParseError>> {
        self.peek_char().map(|peek_char| {
            match peek_char {
                '\r' | '\n'                  => { self.iter.next(); Ok(Token::Newline) },
                '"' | '\''                   => self.lex_quoted_text(),
                c if Lexer::is_whitespace(c) => self.lex_whitespace(),
                _                            => self.lex_unquoted_text(),
            }
        })
    }
}

#[derive(Clone)]
struct Parser<'a> {
    lexer: Lexer<'a>,
}

impl<'a> Parser<'a> {
    fn new(input: &str) -> Parser {
        Parser { lexer: Lexer::new(input) }
    }

    fn parse(&mut self) -> Result<Ast, ParseError> {
        if let Some(token_result) = self.lexer.next() {
            let token = try!(token_result);
            match token {
                Token::Whitespace | Token::Newline => self.parse(),
                Token::Text(command) => self.parse_call(command),
            }
        } else {
            Ok(Ast::Empty)
        }
    }

    fn parse_call(&mut self, command: String) -> Result<Ast, ParseError> {
        let mut args = vec![];

        for token_result in &mut self.lexer {
            let token = try!(token_result);
            match token {
                Token::Newline    => break,
                Token::Whitespace => {},
                Token::Text(arg)  => { args.push(arg); },
            }
        }

        Ok(Ast::Call { command: command, args: args })
    }
}

struct Builtin {
    name: &'static str,
    min_args: usize,
    max_args: usize,
    func: fn(&[String]) -> i32,
}

fn result_to_exit_code(cmd: &'static str, result: io::Result<()>) -> i32 {
    match result {
        Ok(()) => 0,
        Err(e) => {
            writeln!(&mut io::stderr(), "shroom: {}: {}", cmd, e).unwrap();
            1
        },
    }
}

fn builtin_cd(args: &[String]) -> i32 {
    if let Some(path) = args.get(0) {
        result_to_exit_code("cd", std::env::set_current_dir(path))
    } else if let Some(home) = std::env::home_dir() {
        result_to_exit_code("cd", std::env::set_current_dir(home))
    } else {
        writeln!(&mut io::stderr(), "shroom: cd: couldn't find home dir").unwrap();
        1
    }
}

fn builtin_exit(args: &[String]) -> i32 {
    if let Some(exit_code_str) = args.get(0) {
        match exit_code_str.parse() {
            Ok(exit_code) => std::process::exit(exit_code),
            Err(e) => {
                writeln!(&mut io::stderr(), "shroom: exit: can't parse exit code: {}", e).unwrap();
                1
            },
        }
    } else {
        std::process::exit(0);
    }
}

fn execute(ast: &Ast) -> i32 {
    let mut builtins = HashMap::new();

    builtins.insert("cd", Builtin {
        name: "cd",
        min_args: 0,
        max_args: 1,
        func: builtin_cd,
    });

    builtins.insert("exit", Builtin {
        name: "exit",
        min_args: 0,
        max_args: 1,
        func: builtin_exit,
    });

    match *ast {
        Ast::Empty => 0,

        Ast::Call { ref command, ref args } => {
            if let Some(builtin) = builtins.get(&command[..]) {
                if args.len() < builtin.min_args {
                    writeln!(&mut io::stderr(), "shroom: {}: not enough arguments",
                             builtin.name).unwrap();
                    1
                } else if args.len() > builtin.max_args {
                    writeln!(&mut io::stderr(), "shroom: {}: too many arguments",
                             builtin.name).unwrap();
                    1
                } else {
                    (builtin.func)(args)
                }
            } else {
                match Command::new(command).args(args).status() {
                    Ok(exit_status) => {
                        #[cfg(unix)]
                        fn exit_signal(exit_status: &ExitStatus) -> Option<i32> {
                            use std::os::unix::process::ExitStatusExt;
                            exit_status.signal()
                        }

                        #[cfg(not(unix))]
                        fn exit_signal(_exit_status: &ExitStatus) -> Option<i32> {
                            None
                        }

                        if let Some(code) = exit_status.code() {
                            code
                        } else if let Some(signal) = exit_signal(&exit_status) {
                            128 + signal
                        } else {
                            127
                        }
                    },

                    Err(e) => {
                        writeln!(&mut io::stderr(), "shroom: {}: {}", command, e).unwrap();
                        127
                    },
                }
            }
        },
    }
}

fn main() {
    let mut line = String::new();
    loop {
        prompt(&mut line).unwrap();

        match Parser::new(&line).parse() {
            Ok(ast) => {
                let exit_code = execute(&ast);
                if exit_code != 0 {
                    println!("shroom: exit code: {}", exit_code);
                }
            },

            Err(parse_error) => {
                println!("shroom: parse error: {}", parse_error);
            },
        }

        line.clear();
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::net::TcpStream;
use std::fs::File;
use std::env;

extern crate chrono;
use chrono::*;

#[macro_use]
extern crate clap;

extern crate env_logger;
#[macro_use]
extern crate log;

extern crate stats;

mod analyzer;
mod args;
mod filter;
mod log_parser;
use log_parser::log_events::*;
mod render;
mod request_response_matcher;
use request_response_matcher::*;

fn main() {
    env_logger::init().expect("Failed to initialize logging.");

    let args = args::parse_args(env::args()).expect("Failed to parse arguments.");

    let input: Box<io::Read> = match args.filename.as_ref() {
        "-" => Box::new(io::stdin()),
        _ => Box::new(File::open(&args.filename).expect("Failed to open file.")),
    };

    let timings = extract_timings(input, &args.conditions);
    let result = analyzer::analyze(&timings);

    let mut stream;
    let mut renderer: Box<render::Renderer>;

    renderer = match args.graphite_server {
        Some(graphite_server) => {
            stream = TcpStream::connect((graphite_server.as_ref(), args.graphite_port.unwrap()))
                .expect("Could not connect to the Graphite server");

            Box::new(render::GraphiteRenderer::new(UTC::now(), args.graphite_prefix, &mut stream))
        }
        None => Box::new(render::TerminalRenderer::new()),
    };

    match result {
        Some(result) => {
            renderer.render(result);
        }
        None => warn!("No matching log lines in file."),
    }
}

fn extract_timings(input: Box<io::Read>, conditions: &filter::FilterConditions) -> Vec<i64> {
    let reader = io::BufReader::new(input);

    let mut requests: Vec<Request> = Vec::new();
    let mut responses: Vec<Response> = Vec::new();
    let mut timings: Vec<i64> = Vec::new();

    for line in reader.lines() {
        let parsed_line = log_parser::parse_line(&line.expect("Failed to read line."));

        match parsed_line {
            Ok(event) => {
                match event {
                    LogEvent::Request(request) => requests.push(request),
                    LogEvent::Response(response) => responses.push(response),
                }

                let pairs = extract_matching_request_response_pairs(&mut requests, &mut responses);

                let mut new_timings: Vec<i64> = pairs.iter()
                    .filter(|pair| filter::matches_filter(&pair, conditions))
                    .map(|pair| pair.response.response_time.num_milliseconds())
                    .collect();

                timings.append(&mut new_timings);
            }
            Err(err) => warn!("{}", err),
        }
    }
    timings
}

#[test]
fn test_extract_timings() {
    let conditions = filter::FilterConditions {
        include_terms: None,
        exclude_terms: None,
        latest_time: None,
    };

    let timings = extract_timings(Box::new(File::open("src/test/simple-1.log").unwrap()),
                                  &conditions);

    assert_eq!(timings, vec![7, 10]);
}

#[test]
fn test_extract_timings_ignore_broken_lines() {
    let conditions = filter::FilterConditions {
        include_terms: None,
        exclude_terms: None,
        latest_time: None,
    };

    let timings = extract_timings(Box::new(File::open("src/test/broken.log").unwrap()),
                                  &conditions);

    assert_eq!(timings, vec![7]);
}
<commit_msg>Put actual running into separate function<commit_after>use std::io;
use std::io::prelude::*;
use std::net::TcpStream;
use std::fs::File;
use std::env;

extern crate chrono;
use chrono::*;

#[macro_use]
extern crate clap;

extern crate env_logger;
#[macro_use]
extern crate log;

extern crate stats;

mod analyzer;
mod args;
mod filter;
mod log_parser;
use log_parser::log_events::*;
mod render;
mod request_response_matcher;
use request_response_matcher::*;

fn main() {
    env_logger::init().expect("Failed to initialize logging.");

    let args = args::parse_args(env::args()).expect("Failed to parse arguments.");

    fn run(args: &args::RequestLogAnalyzerArgs) {
        let input: Box<io::Read> = match args.filename.as_ref() {
            "-" => Box::new(io::stdin()),
            _ => Box::new(File::open(&args.filename).expect("Failed to open file.")),
        };

        let timings = extract_timings(input, &args.conditions);
        let result = analyzer::analyze(&timings);

        let mut stream;
        let mut renderer: Box<render::Renderer>;

        renderer = match args.graphite_server {
            Some(ref graphite_server) => {
                stream = TcpStream::connect((graphite_server.as_ref(),
                                             args.graphite_port.unwrap()))
                    .expect("Could not connect to the Graphite server");

                Box::new(render::GraphiteRenderer::new(UTC::now(),
                                                       args.graphite_prefix.clone(),
                                                       &mut stream))
            }
            None => Box::new(render::TerminalRenderer::new()),
        };

        match result {
            Some(result) => {
                renderer.render(result);
            }
            None => warn!("No matching log lines in file."),
        }
    };

    run(&args);
    run(&args);
}

fn extract_timings(input: Box<io::Read>, conditions: &filter::FilterConditions) -> Vec<i64> {
    let reader = io::BufReader::new(input);

    let mut requests: Vec<Request> = Vec::new();
    let mut responses: Vec<Response> = Vec::new();
    let mut timings: Vec<i64> = Vec::new();

    for line in reader.lines() {
        let parsed_line = log_parser::parse_line(&line.expect("Failed to read line."));

        match parsed_line {
            Ok(event) => {
                match event {
                    LogEvent::Request(request) => requests.push(request),
                    LogEvent::Response(response) => responses.push(response),
                }

                let pairs = extract_matching_request_response_pairs(&mut requests, &mut responses);

                let mut new_timings: Vec<i64> = pairs.iter()
                    .filter(|pair| filter::matches_filter(&pair, conditions))
                    .map(|pair| pair.response.response_time.num_milliseconds())
                    .collect();

                timings.append(&mut new_timings);
            }
            Err(err) => warn!("{}", err),
        }
    }
    timings
}

#[test]
fn test_extract_timings() {
    let conditions = filter::FilterConditions {
        include_terms: None,
        exclude_terms: None,
        latest_time: None,
    };

    let timings = extract_timings(Box::new(File::open("src/test/simple-1.log").unwrap()),
                                  &conditions);

    assert_eq!(timings, vec![7, 10]);
}

#[test]
fn test_extract_timings_ignore_broken_lines() {
    let conditions = filter::FilterConditions {
        include_terms: None,
        exclude_terms: None,
        latest_time: None,
    };

    let timings = extract_timings(Box::new(File::open("src/test/broken.log").unwrap()),
                                  &conditions);

    assert_eq!(timings, vec![7]);
}
<|endoftext|>


<commit_before>use cargo::core::{Package, Workspace};
use cargo::ops;
use cargo::util::Config;

use std::collections::BTreeSet;
use std::fmt;
use std::io::prelude::*;
use std::io;
use std::path;
use std::str;

#[derive(Debug)]
enum Licenses<'a> {
    Licenses(BTreeSet<&'a str>),
    File(&'a str),
    Missing,
}

impl<'a> fmt::Display for Licenses<'a> {
    fn fmt(self: &Self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match *self {
            Licenses::File(_) => write!(f, "Specified in license file"),
            Licenses::Missing => write!(f, "Missing"),
            Licenses::Licenses(ref lic_names) => {
                let lics: Vec<String> = lic_names.iter().map(|s| String::from(*s)).collect();
                write!(f, "{}", lics.join(", "))
            }
        }
    }
}

fn main() -> Result<(), Error> {
    let config = Config::default()?;
    let manifest = config.cwd().join("Cargo.toml");
    let ws = Workspace::new(&manifest, &config)?;
    let members: Vec<&Package> = ws.members().collect();
    let (package_ids, resolve) = ops::resolve_ws(&ws)?;

    let mut packages = Vec::new();
    for package_id in resolve.iter() {
        let package = package_ids.get_one(package_id)?;
        if members.contains(&package) {
            // Skip listing our own packages in our workspace
            continue;
        }
        let name = package.name().to_owned();
        let version = format!("{}", package.version());
        let licenses = format!("{}", package_licenses(package));
        let license_files = package_license_files(package)?;
        packages.push((name, version, licenses, license_files));
    }

    packages.sort();

    let stdout = io::stdout();
    let mut out = stdout.lock();

    {
        let mut tw = tabwriter::TabWriter::new(&mut out);
        writeln!(tw, "Name\t| Version\t| Licenses")?;
        writeln!(tw, "----\t| -------\t| --------")?;
        for (name, version, licenses, _) in &packages {
            writeln!(tw, "{}\t| {}\t| {}", &name, &version, &licenses)?;
        }

        // TabWriter flush() makes the actual write to stdout.
        tw.flush()?;
    }

    println!();

    for (name, version, _, license_files) in packages {
        if license_files.is_empty() {
            continue;
        }

        println!("-----BEGIN {} {} LICENSES-----", name, version);

        let mut buf = Vec::new();
        for file in license_files {
            let mut fs = std::fs::File::open(file)?;
            fs.read_to_end(&mut buf)?;
            out.write_all(&buf)?;
            buf.clear();
        }

        println!("-----END {} {} LICENSES-----", name, version);
        println!();
    }

    Ok(())
}

fn package_licenses(package: &Package) -> Licenses<'_> {
    let metadata = package.manifest().metadata();

    if let Some(ref license_str) = metadata.license {
        let licenses: BTreeSet<&str> = license_str
            .split('/')
            .map(str::trim)
            .collect();
        return Licenses::Licenses(licenses);
    }

    if let Some(ref license_file) = metadata.license_file {
        return Licenses::File(license_file);
    }

    Licenses::Missing
}

fn package_license_files(package: &Package) -> io::Result<Vec<path::PathBuf>> {
    let mut result = Vec::new();

    if let Some(path) = package.manifest_path().parent() {
        for entry in path.read_dir()? {
            if let Ok(entry) = entry {
                if let Ok(name) = entry.file_name().into_string() {
                    if name.starts_with("LICENSE") {
                        result.push(entry.path())
                    }
                }
            }
        }
    }

    Ok(result)
}

#[derive(Debug)]
struct Error;

impl From<failure::Error> for Error {
    fn from(err: failure::Error) -> Self {
        cargo_exit(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        let failure = failure::Error::from_boxed_compat(Box::new(err));
        cargo_exit(failure)
    }
}

fn cargo_exit<E: Into<cargo::CliError>>(err: E) -> ! {
    let mut shell = cargo::core::shell::Shell::new();
    cargo::exit_with_error(err.into(), &mut shell)
}
<commit_msg>Improve license file printing<commit_after>use cargo::core::{Package, Workspace};
use cargo::ops;
use cargo::util::Config;

use std::collections::BTreeSet;
use std::fmt;
use std::io;
use std::io::prelude::*;
use std::path;
use std::str;

#[derive(Debug)]
enum Licenses<'a> {
    Licenses(BTreeSet<&'a str>),
    File(&'a str),
    Missing,
}

impl<'a> fmt::Display for Licenses<'a> {
    fn fmt(self: &Self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match *self {
            Licenses::File(_) => write!(f, "Specified in license file"),
            Licenses::Missing => write!(f, "Missing"),
            Licenses::Licenses(ref lic_names) => {
                let lics: Vec<String> = lic_names.iter().map(|s| String::from(*s)).collect();
                write!(f, "{}", lics.join(", "))
            }
        }
    }
}

fn main() -> Result<(), Error> {
    let config = Config::default()?;
    let manifest = config.cwd().join("Cargo.toml");
    let ws = Workspace::new(&manifest, &config)?;
    let members: Vec<&Package> = ws.members().collect();
    let (package_ids, resolve) = ops::resolve_ws(&ws)?;

    let mut packages = Vec::new();
    for package_id in resolve.iter() {
        let package = package_ids.get_one(package_id)?;
        if members.contains(&package) {
            // Skip listing our own packages in our workspace
            continue;
        }
        let name = package.name().to_owned();
        let version = format!("{}", package.version());
        let licenses = format!("{}", package_licenses(package));
        let license_files = package_license_files(package)?;
        packages.push((name, version, licenses, license_files));
    }

    packages.sort();

    let stdout = io::stdout();
    let mut out = stdout.lock();

    {
        let mut tw = tabwriter::TabWriter::new(&mut out);
        writeln!(tw, "Name\t| Version\t| Licenses")?;
        writeln!(tw, "----\t| -------\t| --------")?;
        for (name, version, licenses, _) in &packages {
            writeln!(tw, "{}\t| {}\t| {}", &name, &version, &licenses)?;
        }

        // TabWriter flush() makes the actual write to stdout.
        tw.flush()?;
    }

    println!();

    for (name, version, _, license_files) in packages {
        if license_files.is_empty() {
            continue;
        }

        println!("-----BEGIN {} {} LICENSES-----", name, version);

        let mut buf = Vec::new();
        let mut licenses_to_print = license_files.len();
        for file in license_files {
            let mut fs = std::fs::File::open(file)?;
            fs.read_to_end(&mut buf)?;
            out.write_all(&buf)?;
            buf.clear();
            if licenses_to_print > 1 {
                out.write_all(b"\n-----NEXT LICENSE-----\n")?;
                licenses_to_print -= 1;
            }
        }

        println!("-----END {} {} LICENSES-----", name, version);
        println!();
    }

    Ok(())
}

fn package_licenses(package: &Package) -> Licenses<'_> {
    let metadata = package.manifest().metadata();

    if let Some(ref license_str) = metadata.license {
        let licenses: BTreeSet<&str> = license_str
            .split('/')
            .map(str::trim)
            .collect();
        return Licenses::Licenses(licenses);
    }

    if let Some(ref license_file) = metadata.license_file {
        return Licenses::File(license_file);
    }

    Licenses::Missing
}

static LICENCE_FILE_NAMES: &[&str] = &[
    "LICENSE",
    "UNLICENSE",
];

fn package_license_files(package: &Package) -> io::Result<Vec<path::PathBuf>> {
    let mut result = Vec::new();

    if let Some(path) = package.manifest_path().parent() {
        for entry in path.read_dir()? {
            if let Ok(entry) = entry {
                if let Ok(name) = entry.file_name().into_string() {
                    for license_name in LICENCE_FILE_NAMES {
                        if name.starts_with(license_name) {
                            result.push(entry.path())
                        }
                    }
                }
            }
        }
    }

    Ok(result)
}

#[derive(Debug)]
struct Error;

impl From<failure::Error> for Error {
    fn from(err: failure::Error) -> Self {
        cargo_exit(err)
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        let failure = failure::Error::from_boxed_compat(Box::new(err));
        cargo_exit(failure)
    }
}

fn cargo_exit<E: Into<cargo::CliError>>(err: E) -> ! {
    let mut shell = cargo::core::shell::Shell::new();
    cargo::exit_with_error(err.into(), &mut shell)
}
<|endoftext|>


<commit_before><commit_msg>Add a FIXME to mark a very dubious spot<commit_after><|endoftext|>


<commit_before>use num::BigUint;
use num::traits::{Zero, One, FromPrimitive};
use digit_slice::{DigitSlice, FromDigits};
use {Shape, Noun, NockError, NockResult, FromNoun};

/// Evaluate the nock `*[subject formula]`
pub fn nock_on(mut subject: Noun, mut formula: Noun) -> NockResult {
    loop {
        if let Shape::Cell(ops, tail) = formula.clone().get() {
            match ops.as_u32() {
                // Axis
                Some(0) => return get_axis(&tail, &subject),

                // Just
                Some(1) => return Ok(tail.clone()),

                // Fire
                Some(2) => {
                    match tail.get() {
                        Shape::Cell(ref b, ref c) => {
                            let p = try!(nock_on(subject.clone(),
                                                 (*b).clone()));
                            let q = try!(nock_on(subject, (*c).clone()));
                            subject = p;
                            formula = q;
                            continue;
                        }
                        _ => return Err(NockError),
                    }
                }

                // Depth
                Some(3) => {
                    let p = try!(nock_on(subject.clone(), (*tail).clone()));
                    return match p.get() {
                        Shape::Cell(_, _) => Ok(Noun::from(0u32)),
                        _ => Ok(Noun::from(1u32)),
                    };
                }

                // Bump
                Some(4) => {
                    let p = try!(nock_on(subject.clone(), (*tail).clone()));
                    return match p.get() {
                        Shape::Atom(ref x) => {
                            // TODO: Non-bignum optimization
                            Ok(Noun::from(BigUint::from_digits(x).unwrap() +
                                          BigUint::one()))
                        }
                        _ => Err(NockError),
                    };
                }

                // Same
                Some(5) => {
                    let p = try!(nock_on(subject.clone(), (*tail).clone()));
                    return match p.get() {
                        Shape::Cell(ref a, ref b) => {
                            if a == b {
                                // Yes.
                                return Ok(Noun::from(0u32));
                            } else {
                                // No.
                                return Ok(Noun::from(1u32));
                            }
                        }
                        _ => return Err(NockError),
                    };
                }

                // If
                Some(6) => {
                    if let Some((b, c, d)) = tail.get_122() {
                        let p = try!(nock_on(subject.clone(), (*b).clone()));
                        match p.get() {
                            Shape::Atom(ref x) => {
                                if x == &0u32.as_digits() {
                                    formula = (*c).clone();
                                } else if x == &1u32.as_digits() {
                                    formula = (*d).clone();
                                } else {
                                    return Err(NockError);
                                }
                            }
                            _ => return Err(NockError),
                        }
                        continue;
                    } else {
                        return Err(NockError);
                    }
                }

                // Compose
                Some(7) => {
                    match tail.get() {
                        Shape::Cell(ref b, ref c) => {
                            let p = try!(nock_on(subject.clone(),
                                                 (*b).clone()));
                            subject = p;
                            formula = (*c).clone();
                            continue;
                        }
                        _ => return Err(NockError),
                    }
                }

                // Push
                Some(8) => {
                    match tail.get() {
                        Shape::Cell(ref b, ref c) => {
                            let p = try!(nock_on(subject.clone(),
                                                 (*b).clone()));
                            subject = Noun::cell(p, subject);
                            formula = (*c).clone();
                            continue;
                        }
                        _ => return Err(NockError),
                    }
                }

                // Call
                Some(9) => {
                    match tail.get() {
                        Shape::Cell(ref axis, ref c) => {
                            // Construct core.
                            subject = try!(nock_on(subject.clone(),
                                                   (*c).clone()));
                            // Fetch from core using axis.
                            formula = try!(get_axis(axis, &subject));
                            continue;
                        }
                        _ => return Err(NockError),
                    }
                }

                // Hint
                Some(10) => {
                    match tail.get() {
                        Shape::Cell(ref hint, ref c) => {
                            let (id, clue) = match hint.get() {
                                Shape::Cell(ref p, ref q) => {
                                    (p.clone(), try!(nock_on(subject.clone(), (*q).clone())))
                                }
                                Shape::Atom(_) => {
                                    (hint.clone(), Noun::from(0u32))
                                }
                            };

                            // TODO: Handle other hint types than %fast.
                            if String::from_noun(id).unwrap() == "fast" {
                                let core = try!(nock_on(subject.clone(), (*c).clone()));
                                let stuff = parse_fast_clue(&clue);

                                // TODO: Register core with info

                                return Ok(core);
                            }

                            formula = (*c).clone();
                            continue;
                        }
                        _ => return Err(NockError),
                    }
                }

                // Unhandled opcode
                Some(_) => {
                    return Err(NockError);
                }

                None => {
                    if let Shape::Cell(_, _) = ops.get() {
                        // Autocons
                        let a = try!(nock_on(subject.clone(), ops.clone()));
                        let b = try!(nock_on(subject, tail.clone()));
                        return Ok(Noun::cell(a, b));
                    } else {
                        return Err(NockError);
                    }
                }
            }
        } else {
            return Err(NockError);
        }
    }
}

fn get_axis(axis: &Noun, subject: &Noun) -> NockResult {
    // TODO: Optimize for small atoms.
    fn fas(x: BigUint, n: &Noun) -> NockResult {
        let two = BigUint::from_u32(2).unwrap();
        let three = BigUint::from_u32(3).unwrap();
        if x == BigUint::zero() {
            return Err(NockError);
        }
        if x == BigUint::one() {
            return Ok(n.clone());
        }
        if let Shape::Cell(ref a, ref b) = n.get() {
            if x == two {
                return Ok((*a).clone());
            } else if x == three {
                return Ok((*b).clone());
            } else {
                let half = x.clone() >> 1;
                let p = try!(fas(half, n));

                if x % two.clone() == BigUint::zero() {
                    fas(two, &p)
                } else {
                    fas(three, &p)
                }
            }
        } else {
            return Err(NockError);
        }
    }

    match axis.get() {
        Shape::Atom(ref x) => fas(BigUint::from_digits(x).unwrap(), subject),
        _ => Err(NockError)
    }
}

fn parse_fast_clue(clue: &Noun) -> Result<(String, u32, Vec<(String, Noun)>), NockError> {
    if let Some((ref name, ref axis_formula, ref hooks)) = clue.get_122() {
        let chum = try!(String::from_noun(name).map_err(|_| NockError));

        let axis = if let Shape::Cell(ref a, ref b) = axis_formula.get() {
            if let (Some(1), Some(0)) = (a.as_u32(), b.as_u32()) {
                0
            } else if let (Some(0), Some(axis)) = (a.as_u32(), b.as_u32()) {
                axis
            } else {
                return Err(NockError);
            }
        } else {
            return Err(NockError);
        };

        let hooks: Vec<(String, Noun)> = try!(FromNoun::from_noun(hooks).map_err(|_| NockError));

        Ok((chum, axis, hooks))
    } else {
        Err(NockError)
    }
}
<commit_msg>Diagnostics<commit_after>use num::BigUint;
use num::traits::{Zero, One, FromPrimitive};
use digit_slice::{DigitSlice, FromDigits};
use {Shape, Noun, NockError, NockResult, FromNoun};

/// Evaluate the nock `*[subject formula]`
pub fn nock_on(mut subject: Noun, mut formula: Noun) -> NockResult {
    loop {
        if let Shape::Cell(ops, tail) = formula.clone().get() {
            match ops.as_u32() {
                // Axis
                Some(0) => return get_axis(&tail, &subject),

                // Just
                Some(1) => return Ok(tail.clone()),

                // Fire
                Some(2) => {
                    match tail.get() {
                        Shape::Cell(ref b, ref c) => {
                            let p = try!(nock_on(subject.clone(),
                                                 (*b).clone()));
                            let q = try!(nock_on(subject, (*c).clone()));
                            subject = p;
                            formula = q;
                            continue;
                        }
                        _ => return Err(NockError),
                    }
                }

                // Depth
                Some(3) => {
                    let p = try!(nock_on(subject.clone(), (*tail).clone()));
                    return match p.get() {
                        Shape::Cell(_, _) => Ok(Noun::from(0u32)),
                        _ => Ok(Noun::from(1u32)),
                    };
                }

                // Bump
                Some(4) => {
                    let p = try!(nock_on(subject.clone(), (*tail).clone()));
                    return match p.get() {
                        Shape::Atom(ref x) => {
                            // TODO: Non-bignum optimization
                            Ok(Noun::from(BigUint::from_digits(x).unwrap() +
                                          BigUint::one()))
                        }
                        _ => Err(NockError),
                    };
                }

                // Same
                Some(5) => {
                    let p = try!(nock_on(subject.clone(), (*tail).clone()));
                    return match p.get() {
                        Shape::Cell(ref a, ref b) => {
                            if a == b {
                                // Yes.
                                return Ok(Noun::from(0u32));
                            } else {
                                // No.
                                return Ok(Noun::from(1u32));
                            }
                        }
                        _ => return Err(NockError),
                    };
                }

                // If
                Some(6) => {
                    if let Some((b, c, d)) = tail.get_122() {
                        let p = try!(nock_on(subject.clone(), (*b).clone()));
                        match p.get() {
                            Shape::Atom(ref x) => {
                                if x == &0u32.as_digits() {
                                    formula = (*c).clone();
                                } else if x == &1u32.as_digits() {
                                    formula = (*d).clone();
                                } else {
                                    return Err(NockError);
                                }
                            }
                            _ => return Err(NockError),
                        }
                        continue;
                    } else {
                        return Err(NockError);
                    }
                }

                // Compose
                Some(7) => {
                    match tail.get() {
                        Shape::Cell(ref b, ref c) => {
                            let p = try!(nock_on(subject.clone(),
                                                 (*b).clone()));
                            subject = p;
                            formula = (*c).clone();
                            continue;
                        }
                        _ => return Err(NockError),
                    }
                }

                // Push
                Some(8) => {
                    match tail.get() {
                        Shape::Cell(ref b, ref c) => {
                            let p = try!(nock_on(subject.clone(),
                                                 (*b).clone()));
                            subject = Noun::cell(p, subject);
                            formula = (*c).clone();
                            continue;
                        }
                        _ => return Err(NockError),
                    }
                }

                // Call
                Some(9) => {
                    match tail.get() {
                        Shape::Cell(ref axis, ref c) => {
                            // Construct core.
                            subject = try!(nock_on(subject.clone(),
                                                   (*c).clone()));
                            // Fetch from core using axis.
                            formula = try!(get_axis(axis, &subject));
                            /*
                            let core = try!(get_axis(&Noun::from(2u32), &subject));
                            println!("{} call {}", ::symhash(&core), ::symhash(&formula));
                            */

                            continue;
                        }
                        _ => return Err(NockError),
                    }
                }

                // Hint
                Some(10) => {
                    match tail.get() {
                        Shape::Cell(ref hint, ref c) => {
                            let (id, clue) = match hint.get() {
                                Shape::Cell(ref p, ref q) => {
                                    (p.clone(), try!(nock_on(subject.clone(), (*q).clone())))
                                }
                                Shape::Atom(_) => {
                                    (hint.clone(), Noun::from(0u32))
                                }
                            };

                            // TODO: Handle other hint types than %fast.
                            if String::from_noun(id).unwrap() == "fast" {
                                let core = try!(nock_on(subject.clone(), (*c).clone()));
                                if let Ok((_name, _axis, _hooks)) = parse_fast_clue(&clue) {
                                    /*
                                    if let Shape::Cell(ref bat, _) = core.get() {
                                        println!("{} register {} {} {:?}", ::symhash(bat), name, axis, hooks);
                                    }
                                    */
                                } else {
                                    //println!("Error parsing clue {:?}", &clue);
                                }

                                // TODO: Register core with info

                                return Ok(core);
                            }

                            formula = (*c).clone();
                            continue;
                        }
                        _ => return Err(NockError),
                    }
                }

                // Unhandled opcode
                Some(_) => {
                    return Err(NockError);
                }

                None => {
                    if let Shape::Cell(_, _) = ops.get() {
                        // Autocons
                        let a = try!(nock_on(subject.clone(), ops.clone()));
                        let b = try!(nock_on(subject, tail.clone()));
                        return Ok(Noun::cell(a, b));
                    } else {
                        return Err(NockError);
                    }
                }
            }
        } else {
            return Err(NockError);
        }
    }
}

fn get_axis(axis: &Noun, subject: &Noun) -> NockResult {
    // TODO: Optimize for small atoms.
    fn fas(x: BigUint, n: &Noun) -> NockResult {
        let two = BigUint::from_u32(2).unwrap();
        let three = BigUint::from_u32(3).unwrap();
        if x == BigUint::zero() {
            return Err(NockError);
        }
        if x == BigUint::one() {
            return Ok(n.clone());
        }
        if let Shape::Cell(ref a, ref b) = n.get() {
            if x == two {
                return Ok((*a).clone());
            } else if x == three {
                return Ok((*b).clone());
            } else {
                let half = x.clone() >> 1;
                let p = try!(fas(half, n));

                if x % two.clone() == BigUint::zero() {
                    fas(two, &p)
                } else {
                    fas(three, &p)
                }
            }
        } else {
            return Err(NockError);
        }
    }

    match axis.get() {
        Shape::Atom(ref x) => fas(BigUint::from_digits(x).unwrap(), subject),
        _ => Err(NockError)
    }
}

fn parse_fast_clue(clue: &Noun) -> Result<(String, u32, Vec<(String, Noun)>), NockError> {
    if let Some((ref name, ref axis_formula, ref hooks)) = clue.get_122() {
        let chum = try!(String::from_noun(name).map_err(|_| NockError));

        let axis = if let Shape::Cell(ref a, ref b) = axis_formula.get() {
            if let (Some(1), Some(0)) = (a.as_u32(), b.as_u32()) {
                0
            } else if let (Some(0), Some(axis)) = (a.as_u32(), b.as_u32()) {
                axis
            } else {
                return Err(NockError);
            }
        } else {
            return Err(NockError);
        };

        let hooks: Vec<(String, Noun)> = try!(FromNoun::from_noun(hooks).map_err(|_| NockError));

        Ok((chum, axis, hooks))
    } else {
        Err(NockError)
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;

fn main() {
    let mut n = 5;
    let stdin = io::stdin();
    let stdin = stdin.lock().lines();
    for line in stdin {
        let line = line.unwrap();
        for c in line.chars() {
            n = match c {
                'U' if n > 3 => n - 3,
                'D' if n < 7 => n + 3,
                'L' if n % 3 != 1 => n - 1,
                'R' if n % 3 != 0 => n + 1,
                _ => n,
           }
        }
        print!("{}", n);
    }
    print!("\n");
}
<commit_msg>rust day02 part2 cookie cutter solution :|<commit_after>use std::io;
use std::io::prelude::*;
use std::char;

fn part1_next(n: u32, d: char) -> u32 {
    match d {
        'U' if n > 3 => n - 3,
        'D' if n < 7 => n + 3,
        'L' if n % 3 != 1 => n - 1,
        'R' if n % 3 != 0 => n + 1,
        _ => n,
    }
}

// i feel dirty
fn part2_next(n: char, d: char) -> char {
    match d {
        'U' => match n {
            '3' => '1',
            '6' | '7' | '8' => char::from_digit(n.to_digit(10).unwrap() - 4, 10).unwrap(),
            'A' => '6',
            'B' => '7',
            'C' => '8',
            'D' => 'B',
            _ => n
         },
        'D' => match n {
            '1' => '3',
            '2' | '3' | '4' => char::from_digit(n.to_digit(10).unwrap() + 4, 10).unwrap(),
            '6' => 'A',
            '7' => 'B',
            '8' => 'C',
            'B' => 'D',
            _ => n,
        },
        'L' => match n {
            '3' | '4' | '6' | '7' | '8' | '9' => char::from_digit(n.to_digit(10).unwrap() - 1, 10).unwrap(),
            'B' => 'A',
            'C' => 'B',
            _ => n
        },
        'R' => match n {
            '2' | '3' | '5' | '6' | '7' | '8' => char::from_digit(n.to_digit(10).unwrap() + 1, 10).unwrap(),
            'A' => 'B',
            'B' => 'C',
            _ => n,
        },
        _ => panic!("invalid input"),
    }
}

fn main() {
    let mut part1 = String::new();
    let mut part2 = String::new();
    let mut p1 = 5;
    let mut p2 = '5';

    let stdin = io::stdin();
    let stdin = stdin.lock().lines();

    for line in stdin {
        let line = line.unwrap();
        for c in line.chars() {
            p1 = part1_next(p1, c);
            p2 = part2_next(p2, c);
        }
        part1.push(char::from_digit(p1, 10).unwrap());
        part2.push(p2);
    }

    println!("part1: {}", part1);
    println!("part2: {}", part2);
}
<|endoftext|>


<commit_before>use common::slice::GetSlice;

use alloc::boxed::Box;

use arch::memory::Memory;

use collections::slice;
use collections::string::{String, ToString};
use collections::vec::Vec;

use common::debug;

use core::cmp;

use disk::Disk;
use disk::ide::Extent;

use fs::redoxfs::{FileSystem, Node, NodeData};

use fs::{KScheme, Resource, ResourceSeek, Url, VecResource};

use syscall::{Error, Result, O_CREAT, ENOENT, EIO};

/// A file resource
pub struct FileResource {
    pub scheme: *mut FileScheme,
    pub node: Node,
    pub vec: Vec<u8>,
    pub seek: usize,
    pub dirty: bool,
}

impl Resource for FileResource {
    fn dup(&self) -> Result<Box<Resource>> {
        Ok(box FileResource {
            scheme: self.scheme,
            node: self.node.clone(),
            vec: self.vec.clone(),
            seek: self.seek,
            dirty: self.dirty,
        })
    }

    fn path(&self, buf: &mut [u8]) -> Result<usize> {
        let path_a = b"file:/";
        for (b, p) in buf.iter_mut().zip(path_a.iter()) {
            *b = *p;
        }

        let path_b = self.node.name.as_bytes();
        for (b, p) in buf.iter_mut().skip(path_a.len()).zip(path_b.iter()) {
            *b = *p;
        }

        Ok(cmp::min(buf.len(), path_a.len() + path_b.len()))
    }

    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            match self.vec.get(self.seek) {
                Some(b) => buf[i] = *b,
                None => (),
            }
            self.seek += 1;
            i += 1;
        }
        Ok(i)
    }

    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            self.vec[self.seek] = buf[i];
            self.seek += 1;
            i += 1;
        }
        while i < buf.len() {
            self.vec.push(buf[i]);
            self.seek += 1;
            i += 1;
        }
        if i > 0 {
            self.dirty = true;
        }
        Ok(i)
    }

    fn seek(&mut self, pos: ResourceSeek) -> Result<usize> {
        match pos {
            ResourceSeek::Start(offset) => self.seek = offset,
            ResourceSeek::Current(offset) =>
                self.seek = cmp::max(0, self.seek as isize + offset) as usize,
            ResourceSeek::End(offset) =>
                self.seek = cmp::max(0, self.vec.len() as isize + offset) as usize,
        }
        while self.vec.len() < self.seek {
            self.vec.push(0);
        }
        Ok(self.seek)
    }

    // TODO: Check to make sure proper amount of bytes written. See Disk::write
    // TODO: Allow reallocation
    fn sync(&mut self) -> Result<()> {
        if self.dirty {
            let mut node_dirty = false;
            let mut pos = 0;
            let mut remaining = self.vec.len() as isize;
            for ref mut extent in &mut self.node.extents {
                if remaining > 0 && extent.empty() {
                    debug::d("Reallocate file, extra: ");
                    debug::ds(remaining);
                    debug::dl();

                    unsafe {
                        let sectors = ((remaining + 511) / 512) as u64;
                        if (*self.scheme).fs.header.free_space.length >= sectors * 512 {
                            extent.block = (*self.scheme).fs.header.free_space.block;
                            extent.length = remaining as u64;
                            (*self.scheme).fs.header.free_space.block = (*self.scheme)
                                                                            .fs
                                                                            .header
                                                                            .free_space
                                                                            .block +
                                                                        sectors;
                            (*self.scheme).fs.header.free_space.length = (*self.scheme)
                                                                             .fs
                                                                             .header
                                                                             .free_space
                                                                             .length -
                                                                         sectors * 512;

                            node_dirty = true;
                        }
                    }
                }

                // Make sure it is a valid extent
                if !extent.empty() {
                    let current_sectors = (extent.length as usize + 511) / 512;
                    let max_size = current_sectors * 512;

                    let size = cmp::min(remaining as usize, max_size);

                    if size as u64 != extent.length {
                        extent.length = size as u64;
                        node_dirty = true;
                    }

                    while self.vec.len() < pos + max_size {
                        self.vec.push(0);
                    }

                    unsafe {
                        let _ = (*self.scheme).fs.disk.write(extent.block, &self.vec[pos .. pos + max_size]);
                    }

                    self.vec.truncate(pos + size);

                    pos += size;
                    remaining -= size as isize;
                }
            }

            if node_dirty {
                debug::d("Node dirty, rewrite\n");

                if self.node.block > 0 {
                    unsafe {
                        if let Some(mut node_data) = Memory::<NodeData>::new(1) {
                            node_data.write(0, self.node.data());

                            let mut buffer = slice::from_raw_parts(node_data.address() as *mut u8, 512);
                            let _ = (*self.scheme).fs.disk.write(self.node.block, &mut buffer);

                            debug::d("Renode\n");

                            for mut node in (*self.scheme).fs.nodes.iter_mut() {
                                if node.block == self.node.block {
                                    *node = self.node.clone();
                                }
                            }
                        }
                    }
                } else {
                    debug::d("Need to place Node block\n");
                }
            }

            self.dirty = false;

            if remaining > 0 {
                debug::d("Need to defragment file, extra: ");
                debug::ds(remaining);
                debug::dl();
                return Err(Error::new(EIO));
            }
        }
        Ok(())
    }

    fn truncate(&mut self, len: usize) -> Result<()> {
        while len > self.vec.len() {
            self.vec.push(0);
        }
        self.vec.truncate(len);
        self.seek = cmp::min(self.seek, self.vec.len());
        self.dirty = true;
        Ok(())
    }
}

impl Drop for FileResource {
    fn drop(&mut self) {
        let _ = self.sync();
    }
}

/// A file scheme (pci + fs)
pub struct FileScheme {
    fs: FileSystem,
}

impl FileScheme {
    /// Create a new file scheme from an array of Disks
    pub fn new(mut disks: Vec<Box<Disk>>) -> Option<Box<Self>> {
        while ! disks.is_empty() {
            if let Some(fs) = FileSystem::from_disk(disks.remove(0)) {
                return Some(box FileScheme { fs: fs });
            }
        }

        None
    }
}

impl KScheme for FileScheme {
    fn on_irq(&mut self, _irq: u8) {
        /*if irq == self.fs.disk.irq {
        }*/
    }

    fn scheme(&self) -> &str {
        "file"
    }

    fn open(&mut self, url: &Url, flags: usize) -> Result<Box<Resource>> {
        let mut path = url.reference();
        while path.starts_with('/') {
            path = &path[1..];
        }
        if path.is_empty() || path.ends_with('/') {
            let mut list = String::new();
            let mut dirs: Vec<String> = Vec::new();

            for file in self.fs.list(path).iter() {
                let mut line = String::new();
                match file.find('/') {
                    Some(index) => {
                        let dirname = file.get_slice(..index + 1).to_string();
                        let mut found = false;
                        for dir in dirs.iter() {
                            if dirname == *dir {
                                found = true;
                                break;
                            }
                        }
                        if found {
                            line.clear();
                        } else {
                            line = dirname.clone();
                            dirs.push(dirname);
                        }
                    }
                    None => line = file.clone(),
                }
                if !line.is_empty() {
                    if !list.is_empty() {
                        list = list + "\n" + &line;
                    } else {
                        list = line;
                    }
                }
            }

            if list.len() > 0 {
                Ok(box VecResource::new(&url.string, list.into_bytes()))
            } else {
                Err(Error::new(ENOENT))
            }
        } else {
            match self.fs.node(path) {
                Some(node) => {
                    let mut vec: Vec<u8> = Vec::new();
                    for extent in &node.extents {
                        if extent.block > 0 && extent.length > 0 {
                            let current_sectors = (extent.length as usize + 511) / 512;
                            let max_size = current_sectors * 512;

                            let size = cmp::min(extent.length as usize, max_size);

                            let pos = vec.len();

                            while vec.len() < pos + max_size {
                                vec.push(0);
                            }

                            let _ = self.fs.disk.read(extent.block, &mut vec[pos..pos + max_size]);

                            vec.truncate(pos + size);
                        }
                    }

                    Ok(box FileResource {
                        scheme: self,
                        node: node,
                        vec: vec,
                        seek: 0,
                        dirty: false,
                    })
                }
                None => {
                    if flags & O_CREAT == O_CREAT {
                        // TODO: Create file
                        let mut node = Node {
                            block: 0,
                            name: path.to_string(),
                            extents: [Extent {
                                block: 0,
                                length: 0,
                            }; 16],
                        };

                        if self.fs.header.free_space.length >= 512 {
                            node.block = self.fs.header.free_space.block;
                            self.fs.header.free_space.block = self.fs.header.free_space.block + 1;
                            self.fs.header.free_space.length = self.fs.header.free_space.length -
                                                               512;
                        }

                        self.fs.nodes.push(node.clone());

                        Ok(box FileResource {
                            scheme: self,
                            node: node,
                            vec: Vec::new(),
                            seek: 0,
                            dirty: false,
                        })
                    } else {
                        Err(Error::new(ENOENT))
                    }
                }
            }
        }
    }

    fn unlink(&mut self, url: &Url) -> Result<()> {
        let mut ret = Err(Error::new(ENOENT));

        let mut path = url.reference();
        while path.starts_with('/') {
            path = &path[1..];
        }

        let mut i = 0;
        while i < self.fs.nodes.len() {
            let mut remove = false;

            if let Some(node) = self.fs.nodes.get(i) {
                remove = node.name == path;
            }

            if remove {
                self.fs.nodes.remove(i);
                ret = Ok(());
            } else {
                i += 1;
            }
        }

        ret
    }
}
<commit_msg>Chain both `path_a` and `path_b` iterators to combine both loops<commit_after>use common::slice::GetSlice;

use alloc::boxed::Box;

use arch::memory::Memory;

use collections::slice;
use collections::string::{String, ToString};
use collections::vec::Vec;

use common::debug;

use core::cmp;

use disk::Disk;
use disk::ide::Extent;

use fs::redoxfs::{FileSystem, Node, NodeData};

use fs::{KScheme, Resource, ResourceSeek, Url, VecResource};

use syscall::{Error, Result, O_CREAT, ENOENT, EIO};

/// A file resource
pub struct FileResource {
    pub scheme: *mut FileScheme,
    pub node: Node,
    pub vec: Vec<u8>,
    pub seek: usize,
    pub dirty: bool,
}

impl Resource for FileResource {
    fn dup(&self) -> Result<Box<Resource>> {
        Ok(box FileResource {
            scheme: self.scheme,
            node: self.node.clone(),
            vec: self.vec.clone(),
            seek: self.seek,
            dirty: self.dirty,
        })
    }

    fn path(&self, buf: &mut [u8]) -> Result<usize> {
        let path_a = b"file:/";
        let path_b = self.node.name.as_bytes();
        for (b, p) in buf.iter_mut().zip(path_a.iter().chain(path_b.iter())) {
            *b = *p;
        }

        Ok(cmp::min(buf.len(), path_a.len() + path_b.len()))
    }

    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            match self.vec.get(self.seek) {
                Some(b) => buf[i] = *b,
                None => (),
            }
            self.seek += 1;
            i += 1;
        }
        Ok(i)
    }

    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            self.vec[self.seek] = buf[i];
            self.seek += 1;
            i += 1;
        }
        while i < buf.len() {
            self.vec.push(buf[i]);
            self.seek += 1;
            i += 1;
        }
        if i > 0 {
            self.dirty = true;
        }
        Ok(i)
    }

    fn seek(&mut self, pos: ResourceSeek) -> Result<usize> {
        match pos {
            ResourceSeek::Start(offset) => self.seek = offset,
            ResourceSeek::Current(offset) =>
                self.seek = cmp::max(0, self.seek as isize + offset) as usize,
            ResourceSeek::End(offset) =>
                self.seek = cmp::max(0, self.vec.len() as isize + offset) as usize,
        }
        while self.vec.len() < self.seek {
            self.vec.push(0);
        }
        Ok(self.seek)
    }

    // TODO: Check to make sure proper amount of bytes written. See Disk::write
    // TODO: Allow reallocation
    fn sync(&mut self) -> Result<()> {
        if self.dirty {
            let mut node_dirty = false;
            let mut pos = 0;
            let mut remaining = self.vec.len() as isize;
            for ref mut extent in &mut self.node.extents {
                if remaining > 0 && extent.empty() {
                    debug::d("Reallocate file, extra: ");
                    debug::ds(remaining);
                    debug::dl();

                    unsafe {
                        let sectors = ((remaining + 511) / 512) as u64;
                        if (*self.scheme).fs.header.free_space.length >= sectors * 512 {
                            extent.block = (*self.scheme).fs.header.free_space.block;
                            extent.length = remaining as u64;
                            (*self.scheme).fs.header.free_space.block = (*self.scheme)
                                                                            .fs
                                                                            .header
                                                                            .free_space
                                                                            .block +
                                                                        sectors;
                            (*self.scheme).fs.header.free_space.length = (*self.scheme)
                                                                             .fs
                                                                             .header
                                                                             .free_space
                                                                             .length -
                                                                         sectors * 512;

                            node_dirty = true;
                        }
                    }
                }

                // Make sure it is a valid extent
                if !extent.empty() {
                    let current_sectors = (extent.length as usize + 511) / 512;
                    let max_size = current_sectors * 512;

                    let size = cmp::min(remaining as usize, max_size);

                    if size as u64 != extent.length {
                        extent.length = size as u64;
                        node_dirty = true;
                    }

                    while self.vec.len() < pos + max_size {
                        self.vec.push(0);
                    }

                    unsafe {
                        let _ = (*self.scheme).fs.disk.write(extent.block, &self.vec[pos .. pos + max_size]);
                    }

                    self.vec.truncate(pos + size);

                    pos += size;
                    remaining -= size as isize;
                }
            }

            if node_dirty {
                debug::d("Node dirty, rewrite\n");

                if self.node.block > 0 {
                    unsafe {
                        if let Some(mut node_data) = Memory::<NodeData>::new(1) {
                            node_data.write(0, self.node.data());

                            let mut buffer = slice::from_raw_parts(node_data.address() as *mut u8, 512);
                            let _ = (*self.scheme).fs.disk.write(self.node.block, &mut buffer);

                            debug::d("Renode\n");

                            for mut node in (*self.scheme).fs.nodes.iter_mut() {
                                if node.block == self.node.block {
                                    *node = self.node.clone();
                                }
                            }
                        }
                    }
                } else {
                    debug::d("Need to place Node block\n");
                }
            }

            self.dirty = false;

            if remaining > 0 {
                debug::d("Need to defragment file, extra: ");
                debug::ds(remaining);
                debug::dl();
                return Err(Error::new(EIO));
            }
        }
        Ok(())
    }

    fn truncate(&mut self, len: usize) -> Result<()> {
        while len > self.vec.len() {
            self.vec.push(0);
        }
        self.vec.truncate(len);
        self.seek = cmp::min(self.seek, self.vec.len());
        self.dirty = true;
        Ok(())
    }
}

impl Drop for FileResource {
    fn drop(&mut self) {
        let _ = self.sync();
    }
}

/// A file scheme (pci + fs)
pub struct FileScheme {
    fs: FileSystem,
}

impl FileScheme {
    /// Create a new file scheme from an array of Disks
    pub fn new(mut disks: Vec<Box<Disk>>) -> Option<Box<Self>> {
        while ! disks.is_empty() {
            if let Some(fs) = FileSystem::from_disk(disks.remove(0)) {
                return Some(box FileScheme { fs: fs });
            }
        }

        None
    }
}

impl KScheme for FileScheme {
    fn on_irq(&mut self, _irq: u8) {
        /*if irq == self.fs.disk.irq {
        }*/
    }

    fn scheme(&self) -> &str {
        "file"
    }

    fn open(&mut self, url: &Url, flags: usize) -> Result<Box<Resource>> {
        let mut path = url.reference();
        while path.starts_with('/') {
            path = &path[1..];
        }
        if path.is_empty() || path.ends_with('/') {
            let mut list = String::new();
            let mut dirs: Vec<String> = Vec::new();

            for file in self.fs.list(path).iter() {
                let mut line = String::new();
                match file.find('/') {
                    Some(index) => {
                        let dirname = file.get_slice(..index + 1).to_string();
                        let mut found = false;
                        for dir in dirs.iter() {
                            if dirname == *dir {
                                found = true;
                                break;
                            }
                        }
                        if found {
                            line.clear();
                        } else {
                            line = dirname.clone();
                            dirs.push(dirname);
                        }
                    }
                    None => line = file.clone(),
                }
                if !line.is_empty() {
                    if !list.is_empty() {
                        list = list + "\n" + &line;
                    } else {
                        list = line;
                    }
                }
            }

            if list.len() > 0 {
                Ok(box VecResource::new(&url.string, list.into_bytes()))
            } else {
                Err(Error::new(ENOENT))
            }
        } else {
            match self.fs.node(path) {
                Some(node) => {
                    let mut vec: Vec<u8> = Vec::new();
                    for extent in &node.extents {
                        if extent.block > 0 && extent.length > 0 {
                            let current_sectors = (extent.length as usize + 511) / 512;
                            let max_size = current_sectors * 512;

                            let size = cmp::min(extent.length as usize, max_size);

                            let pos = vec.len();

                            while vec.len() < pos + max_size {
                                vec.push(0);
                            }

                            let _ = self.fs.disk.read(extent.block, &mut vec[pos..pos + max_size]);

                            vec.truncate(pos + size);
                        }
                    }

                    Ok(box FileResource {
                        scheme: self,
                        node: node,
                        vec: vec,
                        seek: 0,
                        dirty: false,
                    })
                }
                None => {
                    if flags & O_CREAT == O_CREAT {
                        // TODO: Create file
                        let mut node = Node {
                            block: 0,
                            name: path.to_string(),
                            extents: [Extent {
                                block: 0,
                                length: 0,
                            }; 16],
                        };

                        if self.fs.header.free_space.length >= 512 {
                            node.block = self.fs.header.free_space.block;
                            self.fs.header.free_space.block = self.fs.header.free_space.block + 1;
                            self.fs.header.free_space.length = self.fs.header.free_space.length -
                                                               512;
                        }

                        self.fs.nodes.push(node.clone());

                        Ok(box FileResource {
                            scheme: self,
                            node: node,
                            vec: Vec::new(),
                            seek: 0,
                            dirty: false,
                        })
                    } else {
                        Err(Error::new(ENOENT))
                    }
                }
            }
        }
    }

    fn unlink(&mut self, url: &Url) -> Result<()> {
        let mut ret = Err(Error::new(ENOENT));

        let mut path = url.reference();
        while path.starts_with('/') {
            path = &path[1..];
        }

        let mut i = 0;
        while i < self.fs.nodes.len() {
            let mut remove = false;

            if let Some(node) = self.fs.nodes.get(i) {
                remove = node.name == path;
            }

            if remove {
                self.fs.nodes.remove(i);
                ret = Ok(());
            } else {
                i += 1;
            }
        }

        ret
    }
}
<|endoftext|>