<commit_before>#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate rand;

pub mod basetypes;
pub mod chess_move;
pub mod position;
pub mod search;
pub mod uci;

use std::process::exit;
use std::sync::Arc;
use std::time::SystemTime;
use std::collections::VecDeque;
use basetypes::*;
use position::Position;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use search::{TimeManagement, Pv, SearchStatus, MultipvSearch};
use search::tt::*;

// The version of the program.
const VERSION: &'static str = "0.1";

// The name of the program.
const NAME: &'static str = "Alcibiades";

// The author of the program.
const AUTHOR: &'static str = "Evgeni Pandurski";

// The starting position in Forsyth–Edwards notation (FEN).
const STARTING_POSITION: &'static str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 1";

// Represents a condition for terminating the search.
enum PlayWhen {
    TimeManagement(TimeManagement), // Stop when `TimeManagement` says.
    MoveTime(u64), // Stop after the given number of milliseconds.
    Nodes(NodeCount), // Stop when the given number of nodes has been searched.
    Depth(u8), // Stop when the given search depth has been reached.
    Never, // An infinite search.
}

/// Implements `UciEngine` trait.
pub struct Engine {
    tt: Arc<TranspositionTable>,
    position: Position,
    current_depth: u8,

    // `Engine` will hand over the real work to `MultipvSearch`.
    search: MultipvSearch,

    // Tells the engine when it must stop thinking and play the best
    // move it has found.
    play_when: PlayWhen,

    // Tells the engine how many best lines to calculate and send to
    // the GUI (the first move in each line is different). This is the
    // so called "MultiPV" mode.
    pv_count: usize,

    // Tells the engine if it will be allowed to ponder. This option
    // is needed because the engine might change its time management
    // algorithm when pondering is allowed.
    pondering_is_allowed: bool,

    // `true` if the engine is thinking in pondering mode.
    is_pondering: bool,

    // Marks the last time when a message was sent by the engine to
    // the GUI, or if no message has been sent yet -- the time when
    // the search stared.
    silent_since: SystemTime,

    // A queue for the messages send by the engine to the GUI.
    queue: VecDeque<EngineReply>,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt = Arc::new(tt);

        Engine {
            tt: tt.clone(),
            position: Position::from_fen(STARTING_POSITION).ok().unwrap(),
            current_depth: 0,
            search: MultipvSearch::new(tt),
            play_when: PlayWhen::Never,
            pv_count: 1,
            pondering_is_allowed: false,
            is_pondering: false,
            silent_since: SystemTime::now(),
            queue: VecDeque::new(),
        }
    }

    // A helper method. It it adds a progress report message to
    // `self.queue`.
    fn queue_progress_report(&mut self) {
        let &SearchStatus { depth, searched_nodes, nps, .. } = self.search.status();
        self.queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", depth)),
            ("nodes".to_string(), format!("{}", searched_nodes)),
            ("nps".to_string(), format!("{}", nps)),
        ]));
        self.silent_since = SystemTime::now();
    }

    // A helper method. It it adds a message containing the current
    // (multi)PV to `self.queue`.
    fn queue_pv(&mut self) {
        let &SearchStatus { depth, ref multipv, searched_nodes, duration_millis, nps, .. } =
            self.search.status();
        for (i, &Pv { value, bound, ref moves }) in multipv.iter().enumerate() {
            let bound_suffix = match bound {
                BOUND_EXACT => "",
                BOUND_UPPER => " upperbound",
                BOUND_LOWER => " lowerbound",
                _ => panic!("unexpected bound type"),
            };
            let mut moves_string = String::new();
            for m in moves {
                moves_string.push_str(&m.notation());
                moves_string.push(' ');
            }
            self.queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", depth)),
            ("multipv".to_string(), format!("{}", i + 1)),
            ("score".to_string(), format!("cp {}{}", value, bound_suffix)),
            ("time".to_string(), format!("{}", duration_millis)),
            ("nodes".to_string(), format!("{}", searched_nodes)),
            ("nps".to_string(), format!("{}", nps)),
            ("pv".to_string(), moves_string),
        ]));
        }
        self.silent_since = SystemTime::now();
    }

    // A helper method. It it adds a message containing the current
    // best move to `self.queue`.
    fn queue_best_move(&mut self) {
        let &SearchStatus { ref multipv, .. } = self.search.status();
        self.queue.push_back(EngineReply::BestMove {
            best_move: multipv[0].moves.get(0).map_or("0000".to_string(), |m| m.notation()),
            ponder_move: multipv[0].moves.get(1).map(|m| m.notation()),
        });
        self.silent_since = SystemTime::now();
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            "MultiPV" => {
                self.pv_count = value.parse::<usize>().unwrap_or(1);
            }

            // An invalid option. Notice that we do not support
            // re-sizing of the transposition table once the engine
            // had started.
            _ => (),
        }
    }

    fn new_game(&mut self) {
        self.tt.clear();
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if let Ok(p) = Position::from_history(fen, moves) {
            self.position = p;
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        // NOTE: We ignore the "mate" parameter.

        self.search.stop();
        self.tt.new_search();
        self.current_depth = 0;
        self.is_pondering = ponder;
        self.play_when = if infinite {
            PlayWhen::Never
        } else if movetime.is_some() {
            PlayWhen::MoveTime(movetime.unwrap())
        } else if nodes.is_some() {
            PlayWhen::Nodes(nodes.unwrap())
        } else if depth.is_some() {
            PlayWhen::Depth(depth.unwrap() as u8)
        } else {
            PlayWhen::TimeManagement(TimeManagement::new(self.position.board().to_move(),
                                                         self.pondering_is_allowed,
                                                         wtime,
                                                         btime,
                                                         winc,
                                                         binc,
                                                         movestogo))
        };
        self.silent_since = SystemTime::now();
        self.search.start(&self.position, searchmoves, self.pv_count);
    }

    fn ponder_hit(&mut self) {
        if self.search.status().done {
            self.queue_best_move();
        } else {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        self.search.stop();
        self.queue_best_move();
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        if !self.search.status().done {
            // Update the search status.
            self.search.update_status();
            let &SearchStatus { done, depth, searched_nodes, duration_millis, .. } = self.search
                                                                                .status();

            // Send the (multi)PV when changed.
            if depth > self.current_depth {
                self.current_depth = depth;
                self.queue_pv();
            }

            // Send periodic progress reports.
            if self.silent_since.elapsed().unwrap().as_secs() > 10 {
                self.queue_progress_report();
            }

            // Check if we must play now.
            if !self.is_pondering &&
               match self.play_when {
                PlayWhen::TimeManagement(ref tm) => done || tm.must_play(self.search.status()),
                PlayWhen::MoveTime(t) => done || duration_millis >= t,
                PlayWhen::Nodes(n) => done || searched_nodes >= n,
                PlayWhen::Depth(d) => done || depth >= d,
                PlayWhen::Never => false,
            } {
                self.stop();
            }
        }

        self.queue.pop_front()
    }

    fn exit(&mut self) {
        self.search.exit();
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("{} {}", NAME, VERSION)
    }

    fn author(&self) -> String {
        AUTHOR.to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
            ("MultiPV".to_string(), OptionDescription::Spin { min: 1, max: 500, default: 1 }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}

fn main() {
    if let Ok(mut uci_loop) = uci::Server::wait_for_hanshake(EngineFactory) {
        match uci_loop.serve() {
            Ok(_) => {
                exit(0);
            }
            Err(_) => {
                exit(1);
            }
        }
    }
    exit(2);
}
<commit_msg>put limits to pv_count<commit_after>#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate rand;

pub mod basetypes;
pub mod chess_move;
pub mod position;
pub mod search;
pub mod uci;

use std::process::exit;
use std::sync::Arc;
use std::time::SystemTime;
use std::collections::VecDeque;
use basetypes::*;
use position::Position;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use search::{TimeManagement, Pv, SearchStatus, MultipvSearch};
use search::tt::*;

// The version of the program.
const VERSION: &'static str = "0.1";

// The name of the program.
const NAME: &'static str = "Alcibiades";

// The author of the program.
const AUTHOR: &'static str = "Evgeni Pandurski";

// The starting position in Forsyth–Edwards notation (FEN).
const STARTING_POSITION: &'static str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 1";

// Represents a condition for terminating the search.
enum PlayWhen {
    TimeManagement(TimeManagement), // Stop when `TimeManagement` says.
    MoveTime(u64), // Stop after the given number of milliseconds.
    Nodes(NodeCount), // Stop when the given number of nodes has been searched.
    Depth(u8), // Stop when the given search depth has been reached.
    Never, // An infinite search.
}

/// Implements `UciEngine` trait.
pub struct Engine {
    tt: Arc<TranspositionTable>,
    position: Position,
    current_depth: u8,

    // `Engine` will hand over the real work to `MultipvSearch`.
    search: MultipvSearch,

    // Tells the engine when it must stop thinking and play the best
    // move it has found.
    play_when: PlayWhen,

    // Tells the engine how many best lines to calculate and send to
    // the GUI (the first move in each line is different). This is the
    // so called "MultiPV" mode.
    pv_count: usize,

    // Tells the engine if it will be allowed to ponder. This option
    // is needed because the engine might change its time management
    // algorithm when pondering is allowed.
    pondering_is_allowed: bool,

    // `true` if the engine is thinking in pondering mode.
    is_pondering: bool,

    // Marks the last time when a message was sent by the engine to
    // the GUI, or if no message has been sent yet -- the time when
    // the search stared.
    silent_since: SystemTime,

    // A queue for the messages send by the engine to the GUI.
    queue: VecDeque<EngineReply>,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt = Arc::new(tt);

        Engine {
            tt: tt.clone(),
            position: Position::from_fen(STARTING_POSITION).ok().unwrap(),
            current_depth: 0,
            search: MultipvSearch::new(tt),
            play_when: PlayWhen::Never,
            pv_count: 1,
            pondering_is_allowed: false,
            is_pondering: false,
            silent_since: SystemTime::now(),
            queue: VecDeque::new(),
        }
    }

    // A helper method. It it adds a progress report message to
    // `self.queue`.
    fn queue_progress_report(&mut self) {
        let &SearchStatus { depth, searched_nodes, nps, .. } = self.search.status();
        self.queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", depth)),
            ("nodes".to_string(), format!("{}", searched_nodes)),
            ("nps".to_string(), format!("{}", nps)),
        ]));
        self.silent_since = SystemTime::now();
    }

    // A helper method. It it adds a message containing the current
    // (multi)PV to `self.queue`.
    fn queue_pv(&mut self) {
        let &SearchStatus { depth, ref multipv, searched_nodes, duration_millis, nps, .. } =
            self.search.status();
        for (i, &Pv { value, bound, ref moves }) in multipv.iter().enumerate() {
            let bound_suffix = match bound {
                BOUND_EXACT => "",
                BOUND_UPPER => " upperbound",
                BOUND_LOWER => " lowerbound",
                _ => panic!("unexpected bound type"),
            };
            let mut moves_string = String::new();
            for m in moves {
                moves_string.push_str(&m.notation());
                moves_string.push(' ');
            }
            self.queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", depth)),
            ("multipv".to_string(), format!("{}", i + 1)),
            ("score".to_string(), format!("cp {}{}", value, bound_suffix)),
            ("time".to_string(), format!("{}", duration_millis)),
            ("nodes".to_string(), format!("{}", searched_nodes)),
            ("nps".to_string(), format!("{}", nps)),
            ("pv".to_string(), moves_string),
        ]));
        }
        self.silent_since = SystemTime::now();
    }

    // A helper method. It it adds a message containing the current
    // best move to `self.queue`.
    fn queue_best_move(&mut self) {
        let &SearchStatus { ref multipv, .. } = self.search.status();
        self.queue.push_back(EngineReply::BestMove {
            best_move: multipv[0].moves.get(0).map_or("0000".to_string(), |m| m.notation()),
            ponder_move: multipv[0].moves.get(1).map(|m| m.notation()),
        });
        self.silent_since = SystemTime::now();
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            "MultiPV" => {
                let n = value.parse::<usize>().unwrap_or(0);
                self.pv_count = match n {
                    0 => 1,
                    n if n > 500 => 500,
                    n => n,
                };
            }

            // An invalid option. Notice that we do not support
            // re-sizing of the transposition table once the engine
            // had started.
            _ => (),
        }
    }

    fn new_game(&mut self) {
        self.tt.clear();
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if let Ok(p) = Position::from_history(fen, moves) {
            self.position = p;
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        // NOTE: We ignore the "mate" parameter.

        self.search.stop();
        self.tt.new_search();
        self.current_depth = 0;
        self.is_pondering = ponder;
        self.play_when = if infinite {
            PlayWhen::Never
        } else if movetime.is_some() {
            PlayWhen::MoveTime(movetime.unwrap())
        } else if nodes.is_some() {
            PlayWhen::Nodes(nodes.unwrap())
        } else if depth.is_some() {
            PlayWhen::Depth(depth.unwrap() as u8)
        } else {
            PlayWhen::TimeManagement(TimeManagement::new(self.position.board().to_move(),
                                                         self.pondering_is_allowed,
                                                         wtime,
                                                         btime,
                                                         winc,
                                                         binc,
                                                         movestogo))
        };
        self.silent_since = SystemTime::now();
        self.search.start(&self.position, searchmoves, self.pv_count);
    }

    fn ponder_hit(&mut self) {
        if self.search.status().done {
            self.queue_best_move();
        } else {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        self.search.stop();
        self.queue_best_move();
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        if !self.search.status().done {
            // Update the search status.
            self.search.update_status();
            let &SearchStatus { done, depth, searched_nodes, duration_millis, .. } = self.search
                                                                                .status();

            // Send the (multi)PV when changed.
            if depth > self.current_depth {
                self.current_depth = depth;
                self.queue_pv();
            }

            // Send periodic progress reports.
            if self.silent_since.elapsed().unwrap().as_secs() > 10 {
                self.queue_progress_report();
            }

            // Check if we must play now.
            if !self.is_pondering &&
               match self.play_when {
                PlayWhen::TimeManagement(ref tm) => done || tm.must_play(self.search.status()),
                PlayWhen::MoveTime(t) => done || duration_millis >= t,
                PlayWhen::Nodes(n) => done || searched_nodes >= n,
                PlayWhen::Depth(d) => done || depth >= d,
                PlayWhen::Never => false,
            } {
                self.stop();
            }
        }

        self.queue.pop_front()
    }

    fn exit(&mut self) {
        self.search.exit();
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("{} {}", NAME, VERSION)
    }

    fn author(&self) -> String {
        AUTHOR.to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
            ("MultiPV".to_string(), OptionDescription::Spin { min: 1, max: 500, default: 1 }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}

fn main() {
    if let Ok(mut uci_loop) = uci::Server::wait_for_hanshake(EngineFactory) {
        match uci_loop.serve() {
            Ok(_) => {
                exit(0);
            }
            Err(_) => {
                exit(1);
            }
        }
    }
    exit(2);
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2015, Al Poole <netstar@gmail.com>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  PERFORMANCE OF THIS SOFTWARE.
*/

//   This is a HTTP proxy written in Rust!
//   DONE: POST+GET+OPTIONS+CONNECT
//   FIXED A STINKER OF A BUG!

use std::string::{String};
use std::net::{SocketAddrV4,Ipv4Addr,TcpListener,TcpStream};
use std::io::{Write, Read};

const REQUEST_LEN: usize = 65535;

fn substr(buf: [u8;REQUEST_LEN], needle: &str, byte: u8) -> String
{
    let mut i = 0;
    let mut x = 0;
    let mut request = String::new();

    let srch = needle.as_bytes();

    if srch.len() == 0
    {
        return request;
    }

    while buf[i] as char != '\0'
    {
        if buf[i] as char == srch[0] as char
        {
            while x < srch.len() && buf[i] as char  == srch[x] as char
            {
                i = i + 1;
                x = x + 1;
            }
            break;
        } else {
            i = i + 1;
        }
    }

    if x == srch.len()
    {
        //println!("match");
        let mut end = i;
        while buf[end] as char != byte as char && buf[end] as char != '\n'
        {
            end = end + 1;

        }

        for y in (i..end)
        {
            request.push(buf[y] as char);
        }
    }

    return request;
}

const CHUNK: usize = 4096; // PAGESIZEish

fn get_with_content_length(mut instream: &TcpStream, mut outstream: &TcpStream, total: usize) {
    let mut current = 0;
    let mut buf = [0u8; CHUNK];

    while current < total
    {
        let bytes = outstream.read(&mut buf). unwrap();
        if bytes == 0
        {
            break;
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = instream.write(&mut buf[0..bytes]).unwrap();
            if sent <= 0
            {
                break;
            }
            chunk = chunk + sent;
            current = current + chunk;
        }
    }
}

fn get_with_no_content_length(mut instream: &TcpStream, mut outstream: &TcpStream)
{
    loop {
        let mut buf = [0u8; CHUNK];

        let bytes = outstream.read(&mut buf).unwrap();
        if bytes == 0
        {
            break; // please!!!
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = instream.write(&mut buf[0..bytes]).unwrap();
            if sent == 0
            {
                break;
            }

            chunk = chunk + sent;
        }
    }
}

fn http_connect_request(instream: TcpStream, hdr: Header)
{
    let bogus_fix = &format!("{}:{}", hdr.hostname, 80);

    let outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    get_with_no_content_length(&instream, &outstream);
}

fn http_options_request(mut instream: TcpStream)
{
    let allow = "GET,POST,HEAD,CONNECT,OPTIONS";

    let code: String = "HTTP/1.1 200 OK\r\n".to_string();
    let request: String  = "Allow: ".to_string() + allow + "\r\n\r\n";

    let response = format!("{}{}", code, request);

    instream.write(response.as_bytes()).unwrap();
}

fn http_head_request(instream: TcpStream, hdr: Header)
{
    let bogus_fix = &format!("{}:{}", hdr.hostname, 80);

    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("xHEAD /{} HTTP/1.1\r\nHost: {}\r\n\r\n", hdr.resource, hdr.hostname);

    outstream.write(query.as_bytes()).unwrap();
}

fn http_post_request(mut instream: TcpStream, headers: Header)
{
    let bogus_fix = &format!("{}:{}", headers.hostname, 80);
    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("POST {}Host: {}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n", headers.resource, headers.hostname, headers.content, headers.length);
    outstream.write(query.as_bytes()).unwrap();

    println!("QUERY: {}", query);

    let mut buf = [0u8; CHUNK];
    let mut current = 0;

    while current < headers.length
    {
        let bytes = instream.read(&mut buf).unwrap();
        if bytes == 0
        {
            break;
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = outstream.write(&mut buf[0..bytes]).unwrap();
            if sent == 0
            {
                break;
            }

            chunk += sent;
            current = current + chunk;
        }
    }

    let terminate = "\r\n\r\n";

    outstream.write(terminate.as_bytes()).unwrap();

    get_with_no_content_length(&instream, &outstream);
}

fn http_get_request(instream: TcpStream, headers: Header)
{
    let bogus_fix = &format!("{}:{}", headers.hostname, 80);

    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("GET {}Host: {}\r\nConnection: close\r\n\r\n", headers.resource, headers.hostname);
    outstream.write(query.as_bytes()).unwrap();

    println!("QUERY: {}", query);

    if headers.length > 0
    {
        get_with_content_length(&instream, &outstream, headers.length);
    }
    else
    {
        get_with_no_content_length(&instream, &outstream);
    }
}

fn req_resource(buf: [u8;REQUEST_LEN]) -> String
{
    let mut i = 0;
    let bytes = buf;
    let mut request: String = String::new();

    while bytes[i] as char != '\0'
    {
        request.push(bytes[i] as char);
        i += 1;
    }

    return request;
}

fn req_content(buf: [u8;REQUEST_LEN]) -> String
{
    let content = substr(buf, "Content-Type: ", '\r' as u8);

    return content;
}

fn req_hostname(buf: [u8;REQUEST_LEN]) -> String
{
    let hostname: String = substr(buf, "http://", '/' as u8);

    return hostname;
}

fn req_length(buf: [u8;REQUEST_LEN]) -> usize
{
    let request: String = substr(buf, "Content-Length: ", '\r' as u8);
    if ! request.is_empty()
    {
        return request.trim().parse().unwrap();
    }

    return 0;
}

struct Header {
    pub hostname: String,
    pub resource: String,
    pub content: String,
    pub length: usize,
    pub method: String,
}

impl Header {

pub fn new() -> Header
{
    let hostname = String::new();
    let resource = String::new();
    let content  = String::new();
    let method   = String::new();
    let length   = 0;

    let h = Header
        { hostname: hostname, resource: resource , content: content, length: length, method: method};

    return h;
}

}

fn check_headers(buffer: [u8;REQUEST_LEN], headers: &mut Header) -> bool
{

    if headers.hostname.is_empty()
    {
        headers.hostname = req_hostname(buffer);
    }

    if headers.resource.is_empty()
    {
        headers.resource = req_resource(buffer);
    }

    if headers.content.is_empty()
    {
        headers.content = req_content(buffer);
    }

    if headers.length == 0
    {
        headers.length = req_length(buffer);
    }

    if headers.hostname.is_empty() || headers.resource.is_empty() || headers.method.is_empty()
    {
        return false;
    }

    return true;
}

fn request_headers(mut instream: &TcpStream, headers: &mut Header)
{
    let mut have_method = false;
    let mut byte = [0u8;1];
    let mut byte_count = 0;

    while ! have_method && byte_count < 16
    {
        instream.read(&mut byte).unwrap();
        if byte[0] as char != ' '
        {
            headers.method.push(byte[0] as char);
        }

        if byte[0] as char == ' '
        {
            have_method = true;
        }

        byte_count += 1;
    }

    if byte_count == 16 || headers.method.is_empty()
    {
        return;
    }

     loop
     {
	  let mut buffer = [0u8; REQUEST_LEN];
          let mut byte = [0u8; 1];
          let mut len = 0;

          while byte[0] as char != '\n'
          {
              let bytes = instream.read(&mut byte).unwrap();
              buffer[len] = byte[0];
              len += bytes;
          }

          buffer[len] = 0;

          if check_headers(buffer, headers) && len == 2
          {
              return;
          }
     }
}

fn proxy(stream: TcpStream) {
    let mut headers: Header = Header::new();
    request_headers(&stream, &mut headers);

    match headers.method.as_ref() {
            "GET" =>
            {
                http_get_request(stream, headers);
            }

            "POST" =>
            {
                http_post_request(stream, headers);
            }

            "HEAD" =>
            {
                http_head_request(stream, headers);
            }

            "CONNECT" =>
            {
                http_connect_request(stream, headers);
            }

            "OPTIONS" =>
            {
                http_options_request(stream);
            }

            _ =>
            {
                println!("REQUEST UNKNOWN");
            }
        }
}

extern crate threadpool;
use threadpool::ThreadPool;

fn proxy_time(port: u16, threads: usize) {
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let host = SocketAddrV4::new(ip, port);
    let listener = TcpListener::bind(host).unwrap();

    let pool = ThreadPool::new(threads);

    for stream in listener.incoming()
    {
        match stream
        {
            Ok(stream) =>
            {
                pool.execute(move || { proxy(stream); });
            }

            Err(_) =>
            {
                println!("NET error");
                1 << 7;
            }
        }
    }

    drop (listener);
}

fn main () {
    let threads = 128;
    let port: u16 = 9999;

    proxy_time(port, threads);
    println!("Blocking all badness");

}

<commit_msg>get rid of CONNECT bogusness<commit_after>/*
  Copyright (c) 2015, Al Poole <netstar@gmail.com>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  PERFORMANCE OF THIS SOFTWARE.
*/

//   This is a HTTP proxy written in Rust!
//   DONE: POST+GET+OPTIONS+CONNECT
//   FIXED A STINKER OF A BUG!

use std::string::{String};
use std::net::{SocketAddrV4,Ipv4Addr,TcpListener,TcpStream};
use std::io::{Write, Read};

const REQUEST_LEN: usize = 65535;

fn substr(buf: [u8;REQUEST_LEN], needle: &str, byte: u8) -> String
{
    let mut i = 0;
    let mut x = 0;
    let mut request = String::new();

    let srch = needle.as_bytes();

    if srch.len() == 0
    {
        return request;
    }

    while buf[i] as char != '\0'
    {
        if buf[i] as char == srch[0] as char
        {
            while x < srch.len() && buf[i] as char  == srch[x] as char
            {
                i = i + 1;
                x = x + 1;
            }
            break;
        } else {
            i = i + 1;
        }
    }

    if x == srch.len()
    {
        //println!("match");
        let mut end = i;
        while buf[end] as char != byte as char && buf[end] as char != '\n'
        {
            end = end + 1;

        }

        for y in (i..end)
        {
            request.push(buf[y] as char);
        }
    }

    return request;
}

const CHUNK: usize = 4096; // PAGESIZEish

fn get_with_content_length(mut instream: &TcpStream, mut outstream: &TcpStream, total: usize) {
    let mut current = 0;
    let mut buf = [0u8; CHUNK];

    while current < total
    {
        let bytes = outstream.read(&mut buf). unwrap();
        if bytes == 0
        {
            break;
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = instream.write(&mut buf[0..bytes]).unwrap();
            if sent <= 0
            {
                break;
            }
            chunk = chunk + sent;
            current = current + chunk;
        }
    }
}

fn get_with_no_content_length(mut instream: &TcpStream, mut outstream: &TcpStream)
{
    loop {
        let mut buf = [0u8; CHUNK];

        let bytes = outstream.read(&mut buf).unwrap();
        if bytes == 0
        {
            break; // please!!!
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = instream.write(&mut buf[0..bytes]).unwrap();
            if sent == 0
            {
                break;
            }

            chunk = chunk + sent;
        }
    }
}

fn http_connect_request(instream: TcpStream, hdr: Header)
{
    let bogus_fix = &format!("{}:{}", hdr.hostname, 80);

    let outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    get_with_no_content_length(&instream, &outstream);
}

fn http_options_request(mut instream: TcpStream)
{
    let allow = "GET,POST,HEAD,OPTIONS";
    let code: String = "HTTP/1.1 200 OK\r\n".to_string();
    let request: String  = "Allow: ".to_string() + allow + "\r\n\r\n";

    let response = format!("{}{}", code, request);

    instream.write(response.as_bytes()).unwrap();
}

fn http_head_request(instream: TcpStream, hdr: Header)
{
    let bogus_fix = &format!("{}:{}", hdr.hostname, 80);

    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("xHEAD /{} HTTP/1.1\r\nHost: {}\r\n\r\n", hdr.resource, hdr.hostname);

    outstream.write(query.as_bytes()).unwrap();
}

fn http_post_request(mut instream: TcpStream, headers: Header)
{
    let bogus_fix = &format!("{}:{}", headers.hostname, 80);
    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("POST {}Host: {}\r\nContent-Type: {}\r\nContent-Length: {}\r\n\r\n", headers.resource, headers.hostname, headers.content, headers.length);
    outstream.write(query.as_bytes()).unwrap();

    println!("QUERY: {}", query);

    let mut buf = [0u8; CHUNK];
    let mut current = 0;

    while current < headers.length
    {
        let bytes = instream.read(&mut buf).unwrap();
        if bytes == 0
        {
            break;
        }

        let mut chunk = 0;

        while chunk < bytes
        {
            let sent = outstream.write(&mut buf[0..bytes]).unwrap();
            if sent == 0
            {
                break;
            }

            chunk += sent;
            current = current + chunk;
        }
    }

    let terminate = "\r\n\r\n";

    outstream.write(terminate.as_bytes()).unwrap();

    get_with_no_content_length(&instream, &outstream);
}

fn http_get_request(instream: TcpStream, headers: Header)
{
    let bogus_fix = &format!("{}:{}", headers.hostname, 80);

    let mut outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

    let query: String = format!("GET {}Host: {}\r\nConnection: close\r\n\r\n", headers.resource, headers.hostname);
    outstream.write(query.as_bytes()).unwrap();

    println!("QUERY: {}", query);

    if headers.length > 0
    {
        get_with_content_length(&instream, &outstream, headers.length);
    }
    else
    {
        get_with_no_content_length(&instream, &outstream);
    }
}

fn req_resource(buf: [u8;REQUEST_LEN]) -> String
{
    let mut i = 0;
    let bytes = buf;
    let mut request: String = String::new();

    while bytes[i] as char != '\0'
    {
        request.push(bytes[i] as char);
        i += 1;
    }

    return request;
}

fn req_content(buf: [u8;REQUEST_LEN]) -> String
{
    let content = substr(buf, "Content-Type: ", '\r' as u8);

    return content;
}

fn req_hostname(buf: [u8;REQUEST_LEN]) -> String
{
    let hostname: String = substr(buf, "http://", '/' as u8);

    return hostname;
}

fn req_length(buf: [u8;REQUEST_LEN]) -> usize
{
    let request: String = substr(buf, "Content-Length: ", '\r' as u8);
    if ! request.is_empty()
    {
        return request.trim().parse().unwrap();
    }

    return 0;
}

struct Header {
    pub hostname: String,
    pub resource: String,
    pub content: String,
    pub length: usize,
    pub method: String,
}

impl Header {

pub fn new() -> Header
{
    let hostname = String::new();
    let resource = String::new();
    let content  = String::new();
    let method   = String::new();
    let length   = 0;

    let h = Header
        { hostname: hostname, resource: resource , content: content, length: length, method: method};

    return h;
}

}

fn check_headers(buffer: [u8;REQUEST_LEN], headers: &mut Header) -> bool
{

    if headers.hostname.is_empty()
    {
        headers.hostname = req_hostname(buffer);
    }

    if headers.resource.is_empty()
    {
        headers.resource = req_resource(buffer);
    }

    if headers.content.is_empty()
    {
        headers.content = req_content(buffer);
    }

    if headers.length == 0
    {
        headers.length = req_length(buffer);
    }

    if headers.hostname.is_empty() || headers.resource.is_empty() || headers.method.is_empty()
    {
        return false;
    }

    return true;
}

fn request_headers(mut instream: &TcpStream, headers: &mut Header)
{
    let mut have_method = false;
    let mut byte = [0u8;1];
    let mut byte_count = 0;

    while ! have_method && byte_count < 16
    {
        instream.read(&mut byte).unwrap();
        if byte[0] as char != ' '
        {
            headers.method.push(byte[0] as char);
        }

        if byte[0] as char == ' '
        {
            have_method = true;
        }

        byte_count += 1;
    }

    if byte_count == 16 || headers.method.is_empty()
    {
        return;
    }

     loop
     {
	  let mut buffer = [0u8; REQUEST_LEN];
          let mut byte = [0u8; 1];
          let mut len = 0;

          while byte[0] as char != '\n'
          {
              let bytes = instream.read(&mut byte).unwrap();
              buffer[len] = byte[0];
              len += bytes;
          }

          buffer[len] = 0;

          if check_headers(buffer, headers) && len == 2
          {
              return;
          }
     }
}

fn proxy(stream: TcpStream) {
    let mut headers: Header = Header::new();
    request_headers(&stream, &mut headers);

    match headers.method.as_ref() {
            "GET" =>
            {
                http_get_request(stream, headers);
            }

            "POST" =>
            {
                http_post_request(stream, headers);
            }

            "HEAD" =>
            {
                http_head_request(stream, headers);
            }

            "OPTIONS" =>
            {
                http_options_request(stream);
            }

            _ =>
            {
                println!("REQUEST UNKNOWN");
            }
        }
}

extern crate threadpool;
use threadpool::ThreadPool;

fn proxy_time(port: u16, threads: usize) {
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let host = SocketAddrV4::new(ip, port);
    let listener = TcpListener::bind(host).unwrap();

    let pool = ThreadPool::new(threads);

    for stream in listener.incoming()
    {
        match stream
        {
            Ok(stream) =>
            {
                pool.execute(move || { proxy(stream); });
            }

            Err(_) =>
            {
                println!("NET error");
                1 << 7;
            }
        }
    }

    drop (listener);
}

fn main () {
    let threads = 128;
    let port: u16 = 9999;

    proxy_time(port, threads);
    println!("Blocking all badness");

}

<|endoftext|>


<commit_before>extern crate image;
extern crate dungenon;
extern crate cast;

use std::io;
use std::path::PathBuf;

use dungenon::level::Level;
use dungenon::tile::{Tile, Faction};
use dungenon::generator::{MazeGen, RoomGen, DungeonGen, FactionGen};
use dungenon::util::Error;

use image::RgbImage;
use image::Rgb;

use std::collections::HashMap;

fn main() {
    Drawer::new().start();
}

struct Drawer {
    pub dungeon_colors: HashMap<Tile, Rgb<u8>>,
    pub faction_colors: HashMap<Faction, Rgb<u8>>,
}

impl Drawer {
    pub fn new() -> Drawer {
        let mut dungeon_colors = HashMap::new();
        dungeon_colors.insert(Tile::Wall(0), Rgb([127u8, 127u8, 127u8]));
        dungeon_colors.insert(Tile::Floor(0), Rgb([200u8, 200u8, 200u8]));
        dungeon_colors.insert(Tile::Void(0), Rgb([0u8, 0u8, 0u8]));

        let mut faction_colors = HashMap::new();
        faction_colors.insert(Faction::Faction(0), Rgb([200u8, 0u8, 0u8]));
        faction_colors.insert(Faction::Faction(1), Rgb([0u8, 0u8, 127u8]));
        faction_colors.insert(Faction::Neutral, Rgb([127u8, 127u8, 127u8]));
        faction_colors.insert(Faction::Void, Rgb([0u8, 0u8, 0u8]));

        Drawer{
            dungeon_colors: dungeon_colors,
            faction_colors: faction_colors,
        }
    }

    pub fn start(&mut self) {
        loop {
            println!("Choose level type(faction, tile):");
            let t = Self::string_from_cmd();
            match t.trim() {
                "faction" => self.start_faction(),
                "tile" => self.start_tile(),
                _ => continue,
            }
            break;
        }
    }

    pub fn start_faction(&mut self) {
        let mut level = self.init_faction_level();
        let mut simulator = FactionGen::new();

        println!("This is the faction mode of dungenon-drawer.");
        println!("Type Help for list of possible commands.");
        loop {
            println!("Enter command:");
            let command = Self::string_from_cmd();
            match command.trim() {
                "simulate" => Self::simulate_factions(&mut level, &mut simulator),
                "factions" => Self::edit_level(&mut level),
                "colors" => self.change_faction_colors(),
                "export" => self.faction_png_export(&mut level),
                "help" => println!("Options: help, simulate, factions, colors, export and exit"),
                "exit" => break,
                _ => println!("Invalid command.")
            }
        }
    }

    fn change_faction_colors(&mut self) {
        use cast;
        use std::u8;
        loop {
            println!("Which color would you like to change? (faction, neutral, void), Type exit if you're done with modifying colors.");
            let command = Self::string_from_cmd();
            let key = match command.trim() {
                "faction" => {
                    println!("Enter faction number:");
                    Faction::Faction(Self::usize_from_cmd())
                },
                "neutral" => Faction::Neutral,
                "void" => Faction::Void,
                "exit" => break,
                _ => {
                    println!("Invalid command.");
                    continue;
                },
            };
            println!("Input red value for the color:");
            let r = cast::u8(Self::usize_from_cmd()).unwrap_or(u8::MAX);

            println!("Input green value for the color:");
            let g = cast::u8(Self::usize_from_cmd()).unwrap_or(u8::MAX);

            println!("Input blue value for the color:");
            let b = cast::u8(Self::usize_from_cmd()).unwrap_or(u8::MAX);
            self.faction_colors.insert(key, Rgb([r,g,b]));
        }
    }

    fn init_faction_level(&self) -> Level<Faction> {
        println!("Initializing level...");
        println!("Input level width: ");
        let x = Self::usize_from_cmd();

        println!("Input level height: ");
        let y = Self::usize_from_cmd();

        Level::new_filled_with(Faction::Neutral, x, y)
    }

    fn simulate_factions(level: &mut Level<Faction>, simulator: &mut FactionGen) {
        println!("How many simulation steps are iterated?");
        let iterations = Self::u64_from_cmd();
        for _ in 0 .. iterations {
            level.apply(|m| simulator.generate(m));
        }
    }

    fn faction_png_export(&self, level: &mut Level<Faction>) {
        let mut level_image = RgbImage::new(level.get_width() as u32, level.get_height() as u32);
        for x in 0 .. level.get_width() {
            for y in 0 .. level.get_height() {
                level_image.put_pixel(x as u32, y as u32, self.faction_to_color(&level.get_tile_with_tuple((x,y))));
            }
        }
        let mut p = PathBuf::new();
        println!("Enter png name:");
        p.push(Self::string_from_cmd().trim());
        p.set_extension("png");
        level_image.save(p.as_path()).expect("Something went wrong when saving the png.");
    }

    fn edit_level(level: &mut Level<Faction>) {
        loop {
            println!("Input x coordinate:");
            let x = Self::usize_from_cmd();
            println!("Input y coordinate:");
            let y = Self::usize_from_cmd();

            println!("Select type(faction, neutral, void):");
            let faction_type = Self::string_from_cmd();
            let faction = match faction_type.trim() {
                "faction" => {
                    println!("Input faction number:");
                    let faction_number = Self::usize_from_cmd();
                    Faction::Faction(faction_number)
                },
                "neutral" => Faction::Neutral,
                "void" => Faction::Void,
                _ => {
                    println!("Invalid type.");
                    break;
                }
            };
            match level.get_mut_tile(x,y) {
                Ok(tile) => {
                    *tile = faction;
                },
                Err(_) => println!("Index out of bounds"),
            };
            println!("do you want to change another tile? (yes/no)");
            match Self::string_from_cmd().trim() {
                "yes" => continue,
                "no" => break,
                _ => {println!("Invalid input. Interpretting")}
            }
        }
    }

    pub fn start_tile(&mut self) {
        let mut level = self.init_tile_level();

        println!("This is the tile mode of dungenon-drawer. \nType Help for list of commands.");
        loop {
            println!("Enter command:");
            let command = Self::string_from_cmd();
            match command.trim() {
                "dungeon" => Self::carve_dungeon(&mut level),
                "maze" => Self::carve_maze(&mut level),
                "room" => Self::carve_rooms(&mut level),
                "reset" => level = self.init_tile_level(),
                "colors" => self.change_dungeon_colors(),
                "export" => {
                    self.tile_png_export(&mut level);
                },
                "print" => Self::print_level(&level),
                "help" => {
                    println!("Options: dungeon, maze, room, reset, colors, export, print, help, and exit");
                }
                "exit" => break,
                _ => println!("Invalid command."),
            }
        }
    }

    fn faction_to_color(&self, tile: &Result<&Faction, Error>) -> Rgb<u8> {
        match *tile {
            Ok(ref tile) => {
                    match self.faction_colors.get(tile) {
                        Some(color) => color.clone(),
                        None => Rgb([255u8, 0u8, 255u8]),
                    }
            },
            Err(Error::IndexOutOfBounds) => panic!("Tile png import failed. Level indexing went out of bounds."),
        }
    }

    fn change_dungeon_colors(&mut self) {
        use cast;
        use std::u8;
        loop {
            println!("Which color would you like to change? (floor, wall, void), Type exit if you're done with modifying colors.");
            let command = Self::string_from_cmd();
            let key = match command.trim() {
                "floor" => Tile::Floor(0),
                "wall" => Tile::Wall(0),
                "void" => Tile::Void(0),
                "exit" => break,
                _ => {
                    println!("Invalid command.");
                    continue;
                },
            };
            println!("Input red value for the color:");
            let r = cast::u8(Self::usize_from_cmd()).unwrap_or(u8::MAX);

            println!("Input green value for the color:");
            let g = cast::u8(Self::usize_from_cmd()).unwrap_or(u8::MAX);

            println!("Input blue value for the color:");
            let b = cast::u8(Self::usize_from_cmd()).unwrap_or(u8::MAX);
            self.dungeon_colors.insert(key, Rgb([r,g,b]));
        }
    }

    fn init_tile_level(&self) -> Level<Tile> {
        println!("Initializing level...");
        println!("Input level width: ");
        let x = Self::usize_from_cmd();

        println!("Input level height: ");
        let y = Self::usize_from_cmd();

        Level::new_filled_with(Tile::Wall(0), x, y)
    }

    fn carve_dungeon(level: &mut Level<Tile>) {
        println!("Creating DungeonGen...");
        let mazegen = Self::create_mazegen();
        let roomgen = Self::create_roomgen();
        let mut dungeongen = DungeonGen::new(mazegen, roomgen);
        level.apply(|m| dungeongen.generate(m));
    }

    fn create_mazegen() -> MazeGen {
        println!("Input MazeGen startpos x coordinate: ");
        let x = Self::usize_from_cmd();

        println!("Input MazeGen startpos y coordinate: ");
        let y = Self::usize_from_cmd();
        MazeGen::new(x,y)
    }

    fn carve_maze(level: &mut Level<Tile>) {
        let mut mazegen = Self::create_mazegen();
        level.apply(|m| mazegen.generate(m));
    }

    fn create_roomgen() -> RoomGen {
        println!("Input min room size:");
        let min_room_size = Self::usize_from_cmd();

        println!("Input max room size:");
        let max_room_size = Self::usize_from_cmd();

        println!("Input min room distance:");
        let room_distance = Self::usize_from_cmd();

        println!("Input room placement amount (Something high preferably):");
        let attempts = Self::u64_from_cmd();

        RoomGen::new(min_room_size, max_room_size, room_distance, attempts)
    }

    fn carve_rooms(level: &mut Level<Tile>) {
        let mut roomgen = Self::create_roomgen();
        level.apply(|m| roomgen.generate(m));
    }

    fn tile_png_export(&self, level: &mut Level<Tile>) {
        let mut level_image = RgbImage::new(level.get_width() as u32, level.get_height() as u32);
        for x in 0 .. level.get_width() {
            for y in 0 .. level.get_height() {
                level_image.put_pixel(x as u32, y as u32, self.tile_to_color(&level.get_tile_with_tuple((x,y))));
            }
        }
        let mut p = PathBuf::new();
        println!("Enter png name:");
        p.push(Self::string_from_cmd().trim());
        p.set_extension("png");
        level_image.save(p.as_path()).expect("Something went wrong when saving the png.");
    }

    fn tile_to_color(&self, tile: &Result<&Tile, Error>) -> Rgb<u8> {
        match *tile {
            Ok(ref tile) => {
                    match self.dungeon_colors.get(tile) {
                        Some(color) => color.clone(),
                        None => Rgb([255u8, 0u8, 255u8]),
                    }
            },
            Err(Error::IndexOutOfBounds) => panic!("Tile png import failed. Level indexing went out of bounds."),
        }
    }

    fn print_level(level: &Level<Tile>) {
        use dungenon::util::Error;
        let mut string = String::new();
        for y in 0 .. level.get_width() {
            for x in 0 .. level.get_height() {
                match level.get_tile_with_tuple((x,y)) {
                    Ok(tile) => {
                        match tile {
                            &Tile::Wall(_) => string.push('#'),
                            &Tile::Floor(_) => string.push(' '),
                            &Tile::Void(_) => string.push('*'),
                        }
                    },
                    Err(Error::IndexOutOfBounds) => panic!("IndexOutOfBounds occurred. Level printing wasn't implemented properly."),
                }
            }
            string.push('\n');
        }
        println!("{}", &string);
    }

    fn usize_from_cmd() -> usize {
        let mut num = String::new();

        io::stdin().read_line(&mut num)
            .expect("failed to read line");

        let num: usize = num.trim().parse()
            .expect("Please type a number!");
        num
    }

    fn u64_from_cmd() -> u64 {
        let mut num = String::new();

        io::stdin().read_line(&mut num)
            .expect("failed to read line");

        let num: u64 = num.trim().parse()
            .expect("Please type a number!");
        num
    }

    fn string_from_cmd() -> String {
        let mut string = String::new();
        io::stdin().read_line(&mut string)
        .expect("Failed to read line");
        string
    }
}
<commit_msg>added default colors for 8 factions<commit_after>extern crate image;
extern crate dungenon;
extern crate cast;

use std::io;
use std::path::PathBuf;

use dungenon::level::Level;
use dungenon::tile::{Tile, Faction};
use dungenon::generator::{MazeGen, RoomGen, DungeonGen, FactionGen};
use dungenon::util::Error;

use image::RgbImage;
use image::Rgb;

use std::collections::HashMap;

fn main() {
    Drawer::new().start();
}

struct Drawer {
    pub dungeon_colors: HashMap<Tile, Rgb<u8>>,
    pub faction_colors: HashMap<Faction, Rgb<u8>>,
}

impl Drawer {
    pub fn new() -> Drawer {
        let mut dungeon_colors = HashMap::new();
        dungeon_colors.insert(Tile::Wall(0), Rgb([127u8, 127u8, 127u8]));
        dungeon_colors.insert(Tile::Floor(0), Rgb([200u8, 200u8, 200u8]));
        dungeon_colors.insert(Tile::Void(0), Rgb([0u8, 0u8, 0u8]));

        let mut faction_colors = HashMap::new();
        faction_colors.insert(Faction::Faction(0), Rgb([0u8, 0u8, 0u8]));
        faction_colors.insert(Faction::Faction(1), Rgb([255u8, 0u8, 0u8]));
        faction_colors.insert(Faction::Faction(2), Rgb([0u8, 255u8, 0u8]));
        faction_colors.insert(Faction::Faction(3), Rgb([255u8, 255u8, 0u8]));
        faction_colors.insert(Faction::Faction(4), Rgb([0u8, 0u8, 255u8]));
        faction_colors.insert(Faction::Faction(5), Rgb([255u8, 0u8, 255u8]));
        faction_colors.insert(Faction::Faction(6), Rgb([0u8, 255u8, 255u8]));
        faction_colors.insert(Faction::Faction(7), Rgb([255u8, 255u8, 255u8]));
        faction_colors.insert(Faction::Neutral, Rgb([127u8, 127u8, 127u8]));
        faction_colors.insert(Faction::Void, Rgb([0u8, 0u8, 0u8]));

        Drawer{
            dungeon_colors: dungeon_colors,
            faction_colors: faction_colors,
        }
    }

    pub fn start(&mut self) {
        loop {
            println!("Choose level type(faction, tile):");
            let t = Self::string_from_cmd();
            match t.trim() {
                "faction" => self.start_faction(),
                "tile" => self.start_tile(),
                _ => continue,
            }
            break;
        }
    }

    pub fn start_faction(&mut self) {
        let mut level = self.init_faction_level();
        let mut simulator = FactionGen::new();

        println!("This is the faction mode of dungenon-drawer.");
        println!("Type Help for list of possible commands.");
        loop {
            println!("Enter command:");
            let command = Self::string_from_cmd();
            match command.trim() {
                "simulate" => Self::simulate_factions(&mut level, &mut simulator),
                "factions" => Self::edit_level(&mut level),
                "colors" => self.change_faction_colors(),
                "export" => self.faction_png_export(&mut level),
                "help" => println!("Options: help, simulate, factions, colors, export and exit"),
                "exit" => break,
                _ => println!("Invalid command.")
            }
        }
    }

    fn change_faction_colors(&mut self) {
        use cast;
        use std::u8;
        loop {
            println!("Which color would you like to change? (faction, neutral, void), Type exit if you're done with modifying colors.");
            let command = Self::string_from_cmd();
            let key = match command.trim() {
                "faction" => {
                    println!("Enter faction number:");
                    Faction::Faction(Self::usize_from_cmd())
                },
                "neutral" => Faction::Neutral,
                "void" => Faction::Void,
                "exit" => break,
                _ => {
                    println!("Invalid command.");
                    continue;
                },
            };
            println!("Input red value for the color:");
            let r = cast::u8(Self::usize_from_cmd()).unwrap_or(u8::MAX);

            println!("Input green value for the color:");
            let g = cast::u8(Self::usize_from_cmd()).unwrap_or(u8::MAX);

            println!("Input blue value for the color:");
            let b = cast::u8(Self::usize_from_cmd()).unwrap_or(u8::MAX);
            self.faction_colors.insert(key, Rgb([r,g,b]));
        }
    }

    fn init_faction_level(&self) -> Level<Faction> {
        println!("Initializing level...");
        println!("Input level width: ");
        let x = Self::usize_from_cmd();

        println!("Input level height: ");
        let y = Self::usize_from_cmd();

        Level::new_filled_with(Faction::Neutral, x, y)
    }

    fn simulate_factions(level: &mut Level<Faction>, simulator: &mut FactionGen) {
        println!("How many simulation steps are iterated?");
        let iterations = Self::u64_from_cmd();
        for _ in 0 .. iterations {
            level.apply(|m| simulator.generate(m));
        }
    }

    fn faction_png_export(&self, level: &mut Level<Faction>) {
        let mut level_image = RgbImage::new(level.get_width() as u32, level.get_height() as u32);
        for x in 0 .. level.get_width() {
            for y in 0 .. level.get_height() {
                level_image.put_pixel(x as u32, y as u32, self.faction_to_color(&level.get_tile_with_tuple((x,y))));
            }
        }
        let mut p = PathBuf::new();
        println!("Enter png name:");
        p.push(Self::string_from_cmd().trim());
        p.set_extension("png");
        level_image.save(p.as_path()).expect("Something went wrong when saving the png.");
    }

    fn edit_level(level: &mut Level<Faction>) {
        loop {
            println!("Input x coordinate:");
            let x = Self::usize_from_cmd();
            println!("Input y coordinate:");
            let y = Self::usize_from_cmd();

            println!("Select type(faction, neutral, void):");
            let faction_type = Self::string_from_cmd();
            let faction = match faction_type.trim() {
                "faction" => {
                    println!("Input faction number:");
                    let faction_number = Self::usize_from_cmd();
                    Faction::Faction(faction_number)
                },
                "neutral" => Faction::Neutral,
                "void" => Faction::Void,
                _ => {
                    println!("Invalid type.");
                    break;
                }
            };
            match level.get_mut_tile(x,y) {
                Ok(tile) => {
                    *tile = faction;
                },
                Err(_) => println!("Index out of bounds"),
            };
            println!("do you want to change another tile? (yes/no)");
            match Self::string_from_cmd().trim() {
                "yes" => continue,
                "no" => break,
                _ => {println!("Invalid input. Interpretting")}
            }
        }
    }

    pub fn start_tile(&mut self) {
        let mut level = self.init_tile_level();

        println!("This is the tile mode of dungenon-drawer. \nType Help for list of commands.");
        loop {
            println!("Enter command:");
            let command = Self::string_from_cmd();
            match command.trim() {
                "dungeon" => Self::carve_dungeon(&mut level),
                "maze" => Self::carve_maze(&mut level),
                "room" => Self::carve_rooms(&mut level),
                "reset" => level = self.init_tile_level(),
                "colors" => self.change_dungeon_colors(),
                "export" => {
                    self.tile_png_export(&mut level);
                },
                "print" => Self::print_level(&level),
                "help" => {
                    println!("Options: dungeon, maze, room, reset, colors, export, print, help, and exit");
                }
                "exit" => break,
                _ => println!("Invalid command."),
            }
        }
    }

    fn faction_to_color(&self, tile: &Result<&Faction, Error>) -> Rgb<u8> {
        match *tile {
            Ok(ref tile) => {
                    match self.faction_colors.get(tile) {
                        Some(color) => color.clone(),
                        None => Rgb([255u8, 0u8, 255u8]),
                    }
            },
            Err(Error::IndexOutOfBounds) => panic!("Tile png import failed. Level indexing went out of bounds."),
        }
    }

    fn change_dungeon_colors(&mut self) {
        use cast;
        use std::u8;
        loop {
            println!("Which color would you like to change? (floor, wall, void), Type exit if you're done with modifying colors.");
            let command = Self::string_from_cmd();
            let key = match command.trim() {
                "floor" => Tile::Floor(0),
                "wall" => Tile::Wall(0),
                "void" => Tile::Void(0),
                "exit" => break,
                _ => {
                    println!("Invalid command.");
                    continue;
                },
            };
            println!("Input red value for the color:");
            let r = cast::u8(Self::usize_from_cmd()).unwrap_or(u8::MAX);

            println!("Input green value for the color:");
            let g = cast::u8(Self::usize_from_cmd()).unwrap_or(u8::MAX);

            println!("Input blue value for the color:");
            let b = cast::u8(Self::usize_from_cmd()).unwrap_or(u8::MAX);
            self.dungeon_colors.insert(key, Rgb([r,g,b]));
        }
    }

    fn init_tile_level(&self) -> Level<Tile> {
        println!("Initializing level...");
        println!("Input level width: ");
        let x = Self::usize_from_cmd();

        println!("Input level height: ");
        let y = Self::usize_from_cmd();

        Level::new_filled_with(Tile::Wall(0), x, y)
    }

    fn carve_dungeon(level: &mut Level<Tile>) {
        println!("Creating DungeonGen...");
        let mazegen = Self::create_mazegen();
        let roomgen = Self::create_roomgen();
        let mut dungeongen = DungeonGen::new(mazegen, roomgen);
        level.apply(|m| dungeongen.generate(m));
    }

    fn create_mazegen() -> MazeGen {
        println!("Input MazeGen startpos x coordinate: ");
        let x = Self::usize_from_cmd();

        println!("Input MazeGen startpos y coordinate: ");
        let y = Self::usize_from_cmd();
        MazeGen::new(x,y)
    }

    fn carve_maze(level: &mut Level<Tile>) {
        let mut mazegen = Self::create_mazegen();
        level.apply(|m| mazegen.generate(m));
    }

    fn create_roomgen() -> RoomGen {
        println!("Input min room size:");
        let min_room_size = Self::usize_from_cmd();

        println!("Input max room size:");
        let max_room_size = Self::usize_from_cmd();

        println!("Input min room distance:");
        let room_distance = Self::usize_from_cmd();

        println!("Input room placement amount (Something high preferably):");
        let attempts = Self::u64_from_cmd();

        RoomGen::new(min_room_size, max_room_size, room_distance, attempts)
    }

    fn carve_rooms(level: &mut Level<Tile>) {
        let mut roomgen = Self::create_roomgen();
        level.apply(|m| roomgen.generate(m));
    }

    fn tile_png_export(&self, level: &mut Level<Tile>) {
        let mut level_image = RgbImage::new(level.get_width() as u32, level.get_height() as u32);
        for x in 0 .. level.get_width() {
            for y in 0 .. level.get_height() {
                level_image.put_pixel(x as u32, y as u32, self.tile_to_color(&level.get_tile_with_tuple((x,y))));
            }
        }
        let mut p = PathBuf::new();
        println!("Enter png name:");
        p.push(Self::string_from_cmd().trim());
        p.set_extension("png");
        level_image.save(p.as_path()).expect("Something went wrong when saving the png.");
    }

    fn tile_to_color(&self, tile: &Result<&Tile, Error>) -> Rgb<u8> {
        match *tile {
            Ok(ref tile) => {
                    match self.dungeon_colors.get(tile) {
                        Some(color) => color.clone(),
                        None => Rgb([255u8, 0u8, 255u8]),
                    }
            },
            Err(Error::IndexOutOfBounds) => panic!("Tile png import failed. Level indexing went out of bounds."),
        }
    }

    fn print_level(level: &Level<Tile>) {
        use dungenon::util::Error;
        let mut string = String::new();
        for y in 0 .. level.get_width() {
            for x in 0 .. level.get_height() {
                match level.get_tile_with_tuple((x,y)) {
                    Ok(tile) => {
                        match tile {
                            &Tile::Wall(_) => string.push('#'),
                            &Tile::Floor(_) => string.push(' '),
                            &Tile::Void(_) => string.push('*'),
                        }
                    },
                    Err(Error::IndexOutOfBounds) => panic!("IndexOutOfBounds occurred. Level printing wasn't implemented properly."),
                }
            }
            string.push('\n');
        }
        println!("{}", &string);
    }

    fn usize_from_cmd() -> usize {
        let mut num = String::new();

        io::stdin().read_line(&mut num)
            .expect("failed to read line");

        let num: usize = num.trim().parse()
            .expect("Please type a number!");
        num
    }

    fn u64_from_cmd() -> u64 {
        let mut num = String::new();

        io::stdin().read_line(&mut num)
            .expect("failed to read line");

        let num: u64 = num.trim().parse()
            .expect("Please type a number!");
        num
    }

    fn string_from_cmd() -> String {
        let mut string = String::new();
        io::stdin().read_line(&mut string)
        .expect("Failed to read line");
        string
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "deny-warnings", deny(warnings))]
// warn on lints, that are included in `rust-lang/rust`s bootstrap
#![warn(rust_2018_idioms, unused_lifetimes)]

use rustc_tools_util::VersionInfo;
use std::env;
use std::ffi::OsString;
use std::path::PathBuf;
use std::process::{self, Command};

const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    --fix                    Automatically apply lint suggestions
    --no-deps                Run Clippy only on the given crate
    -h, --help               Print this message
    -V, --version            Print version info and exit

Other options are the same as `cargo check`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

You can use tool lints to allow or deny lints from your code, eg.:

    #[allow(clippy::needless_lifetimes)]
"#;

fn show_help() {
    println!("{}", CARGO_CLIPPY_HELP);
}

fn show_version() {
    let version_info = rustc_tools_util::get_version_info!();
    println!("{}", version_info);
}

pub fn main() {
    // Check for version and help flags even when invoked as 'cargo-clippy'
    if env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }

    if env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Err(code) = process(env::args().skip(2)) {
        process::exit(code);
    }
}

struct ClippyCmd {
    cargo_subcommand: &'static str,
    args: Vec<String>,
    clippy_args: Vec<String>,
}

impl ClippyCmd {
    fn new<I>(mut old_args: I) -> Self
    where
        I: Iterator<Item = String>,
    {
        let mut cargo_subcommand = "check";
        let mut args = vec![];

        for arg in old_args.by_ref() {
            match arg.as_str() {
                "--fix" => {
                    cargo_subcommand = "fix";
                    continue;
                },
                "--" => break,
                _ => {},
            }

            args.push(arg);
        }

        let mut clippy_args: Vec<String> = old_args.collect();
        if cargo_subcommand == "fix" && !clippy_args.iter().any(|arg| arg == "--no-deps") {
            clippy_args.push("--no-deps".into());
        }

        ClippyCmd {
            cargo_subcommand,
            args,
            clippy_args,
        }
    }

    fn path() -> PathBuf {
        let mut path = env::current_exe()
            .expect("current executable path invalid")
            .with_file_name("clippy-driver");

        if cfg!(windows) {
            path.set_extension("exe");
        }

        path
    }

    fn target_dir() -> Option<(&'static str, OsString)> {
        env::var_os("CLIPPY_DOGFOOD")
            .map(|_| {
                env::var_os("CARGO_MANIFEST_DIR").map_or_else(
                    || std::ffi::OsString::from("clippy_dogfood"),
                    |d| {
                        std::path::PathBuf::from(d)
                            .join("target")
                            .join("dogfood")
                            .into_os_string()
                    },
                )
            })
            .map(|p| ("CARGO_TARGET_DIR", p))
    }

    fn into_std_cmd(self) -> Command {
        let mut cmd = Command::new("cargo");
        let clippy_args: String = self
            .clippy_args
            .iter()
            .map(|arg| format!("{}__CLIPPY_HACKERY__", arg))
            .collect();

        cmd.env("RUSTC_WORKSPACE_WRAPPER", Self::path())
            .envs(ClippyCmd::target_dir())
            .env("CLIPPY_ARGS", clippy_args)
            .arg(self.cargo_subcommand)
            .args(&self.args);

        cmd
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{
    let cmd = ClippyCmd::new(old_args);

    let mut cmd = cmd.into_std_cmd();

    let exit_status = cmd
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}

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

    #[test]
    fn fix() {
        let args = "cargo clippy --fix".split_whitespace().map(ToString::to_string);
        let cmd = ClippyCmd::new(args);
        assert_eq!("fix", cmd.cargo_subcommand);
        assert!(!cmd.args.iter().any(|arg| arg.ends_with("unstable-options")));
    }

    #[test]
    fn fix_implies_no_deps() {
        let args = "cargo clippy --fix".split_whitespace().map(ToString::to_string);
        let cmd = ClippyCmd::new(args);
        assert!(cmd.clippy_args.iter().any(|arg| arg == "--no-deps"));
    }

    #[test]
    fn no_deps_not_duplicated_with_fix() {
        let args = "cargo clippy --fix -- --no-deps"
            .split_whitespace()
            .map(ToString::to_string);
        let cmd = ClippyCmd::new(args);
        assert_eq!(cmd.clippy_args.iter().filter(|arg| *arg == "--no-deps").count(), 1);
    }

    #[test]
    fn check() {
        let args = "cargo clippy".split_whitespace().map(ToString::to_string);
        let cmd = ClippyCmd::new(args);
        assert_eq!("check", cmd.cargo_subcommand);
    }
}
<commit_msg>Include more information in --help<commit_after>#![cfg_attr(feature = "deny-warnings", deny(warnings))]
// warn on lints, that are included in `rust-lang/rust`s bootstrap
#![warn(rust_2018_idioms, unused_lifetimes)]

use rustc_tools_util::VersionInfo;
use std::env;
use std::ffi::OsString;
use std::path::PathBuf;
use std::process::{self, Command};

const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    --no-deps                Run Clippy only on the given crate, without linting the dependencies
    --fix                    Automatically apply lint suggestions. This flag implies `--no-deps`
    -h, --help               Print this message
    -V, --version            Print version info and exit

Note: --no-deps flag is used with `cargo clippy --`. Example: `cargo clippy -- --no-deps`

Other options are the same as `cargo check`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

You can use tool lints to allow or deny lints from your code, eg.:

    #[allow(clippy::needless_lifetimes)]
"#;

fn show_help() {
    println!("{}", CARGO_CLIPPY_HELP);
}

fn show_version() {
    let version_info = rustc_tools_util::get_version_info!();
    println!("{}", version_info);
}

pub fn main() {
    // Check for version and help flags even when invoked as 'cargo-clippy'
    if env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }

    if env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Err(code) = process(env::args().skip(2)) {
        process::exit(code);
    }
}

struct ClippyCmd {
    cargo_subcommand: &'static str,
    args: Vec<String>,
    clippy_args: Vec<String>,
}

impl ClippyCmd {
    fn new<I>(mut old_args: I) -> Self
    where
        I: Iterator<Item = String>,
    {
        let mut cargo_subcommand = "check";
        let mut args = vec![];

        for arg in old_args.by_ref() {
            match arg.as_str() {
                "--fix" => {
                    cargo_subcommand = "fix";
                    continue;
                },
                "--" => break,
                _ => {},
            }

            args.push(arg);
        }

        let mut clippy_args: Vec<String> = old_args.collect();
        if cargo_subcommand == "fix" && !clippy_args.iter().any(|arg| arg == "--no-deps") {
            clippy_args.push("--no-deps".into());
        }

        ClippyCmd {
            cargo_subcommand,
            args,
            clippy_args,
        }
    }

    fn path() -> PathBuf {
        let mut path = env::current_exe()
            .expect("current executable path invalid")
            .with_file_name("clippy-driver");

        if cfg!(windows) {
            path.set_extension("exe");
        }

        path
    }

    fn target_dir() -> Option<(&'static str, OsString)> {
        env::var_os("CLIPPY_DOGFOOD")
            .map(|_| {
                env::var_os("CARGO_MANIFEST_DIR").map_or_else(
                    || std::ffi::OsString::from("clippy_dogfood"),
                    |d| {
                        std::path::PathBuf::from(d)
                            .join("target")
                            .join("dogfood")
                            .into_os_string()
                    },
                )
            })
            .map(|p| ("CARGO_TARGET_DIR", p))
    }

    fn into_std_cmd(self) -> Command {
        let mut cmd = Command::new("cargo");
        let clippy_args: String = self
            .clippy_args
            .iter()
            .map(|arg| format!("{}__CLIPPY_HACKERY__", arg))
            .collect();

        cmd.env("RUSTC_WORKSPACE_WRAPPER", Self::path())
            .envs(ClippyCmd::target_dir())
            .env("CLIPPY_ARGS", clippy_args)
            .arg(self.cargo_subcommand)
            .args(&self.args);

        cmd
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
where
    I: Iterator<Item = String>,
{
    let cmd = ClippyCmd::new(old_args);

    let mut cmd = cmd.into_std_cmd();

    let exit_status = cmd
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}

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

    #[test]
    fn fix() {
        let args = "cargo clippy --fix".split_whitespace().map(ToString::to_string);
        let cmd = ClippyCmd::new(args);
        assert_eq!("fix", cmd.cargo_subcommand);
        assert!(!cmd.args.iter().any(|arg| arg.ends_with("unstable-options")));
    }

    #[test]
    fn fix_implies_no_deps() {
        let args = "cargo clippy --fix".split_whitespace().map(ToString::to_string);
        let cmd = ClippyCmd::new(args);
        assert!(cmd.clippy_args.iter().any(|arg| arg == "--no-deps"));
    }

    #[test]
    fn no_deps_not_duplicated_with_fix() {
        let args = "cargo clippy --fix -- --no-deps"
            .split_whitespace()
            .map(ToString::to_string);
        let cmd = ClippyCmd::new(args);
        assert_eq!(cmd.clippy_args.iter().filter(|arg| *arg == "--no-deps").count(), 1);
    }

    #[test]
    fn check() {
        let args = "cargo clippy".split_whitespace().map(ToString::to_string);
        let cmd = ClippyCmd::new(args);
        assert_eq!("check", cmd.cargo_subcommand);
    }
}
<|endoftext|>


<commit_before>extern crate ppbert;
#[macro_use] extern crate clap;

use std::io::{self, Read};
use std::fs::File;
use std::process::exit;
use std::time::Instant;

use clap::{Arg, App};

use ppbert::bertterm::{
    self,
    BertTerm,
    DEFAULT_INDENT_WIDTH,
    DEFAULT_MAX_TERMS_PER_LINE
};
use ppbert::error::Result;
use ppbert::parser;

const PROG_NAME: &str = "ppbert";

fn main() {
    let matches = App::new(PROG_NAME)
        .version(crate_version!())
        .author("Vincent Foley")
        .about("Pretty print structure encoded in Erlang's External Term Format")
        .arg(Arg::with_name("input_files")
             .value_name("FILES")
             .multiple(true))
        .arg(Arg::with_name("indent_width")
             .help("Indents with <num> spaces")
             .value_name("num")
             .short("i")
             .long("--indent-width")
             .takes_value(true))
        .arg(Arg::with_name("max_per_line")
             .help("Prints at most <num> basic terms per line")
             .value_name("num")
             .short("m")
             .long("--max-terms-per-line")
             .takes_value(true))
        .arg(Arg::with_name("verbose")
             .help("Enables verbose mode")
             .short("v")
             .long("--verbose"))
        .arg(Arg::with_name("parse")
             .help("Parses the input, doesn't pretty print it")
             .short("p")
             .long("--parse"))
        .arg(Arg::with_name("bert2")
             .help("Parses .bert2 files")
             .short("2")
             .long("bert2"))
        .arg(Arg::with_name("json")
             .help("Outputs in JSON")
             .short("j")
             .long("json"))
        .arg(Arg::with_name("transform-proplists")
             .help("Transforms proplists into JSON objects (only valid with --json)")
             .long("transform-proplists"))
        .get_matches();

    let files: Vec<&str> = match matches.values_of("input_files") {
        Some(files) => files.collect(),
        None => vec!["-"]
    };

    let indent_level = value_t!(matches, "indent_width", usize)
        .unwrap_or(DEFAULT_INDENT_WIDTH);
    let max_per_line = value_t!(matches, "max_per_line", usize)
        .unwrap_or(DEFAULT_MAX_TERMS_PER_LINE);
    let verbose = matches.is_present("verbose");
    let parse_only = matches.is_present("parse");

    let transform_proplists =
        matches.is_present("transform-proplists");
    let parse_fn =
        if matches.is_present("bert2") {parse_bert2} else {parse_bert1};
    let output_fn =
        if matches.is_present("json") {
            if transform_proplists {
                bertterm::pp_json_proplist
            } else {
                bertterm::pp_json
            }
        } else {
            if transform_proplists {
                eprintln!("Warning: --transform-proplists is only valid with the --json flag");
            }
            bertterm::pp_bert
        };

    let mut return_code = 0;
    for file in files {
        let res = handle_file(file, parse_only, verbose,
                              indent_level, max_per_line,
                              parse_fn, output_fn);
        match res {
            Ok(()) => (),
            Err(e) => {
                return_code = 1;
                eprintln!("{}: {}: {}", PROG_NAME, file, e);
            }
        }
    }
    exit(return_code);
}

fn handle_file<T>(
    file: &str,
    parse_only: bool,
    verbose: bool,
    indent: usize,
    terms_per_line: usize,
    parse_fn: fn(Vec<u8>) -> Result<T>,
    pp_fn: fn(T, usize, usize) -> ()
) -> Result<()> {

    // Read file or stdin into buffer
    let mut buf: Vec<u8> = Vec::new();
    let now = Instant::now();
    if file == "-" {
        let mut stdin = io::stdin();
        stdin.read_to_end(&mut buf)?;
    } else {
        let mut f = File::open(file)?;
        f.read_to_end(&mut buf)?;
    }
    let dur0 = now.elapsed();
    if verbose {
        eprintln!("{}: read time: {}.{:09}",
                  PROG_NAME, dur0.as_secs(), dur0.subsec_nanos());
    }

    // Parse input
    let now = Instant::now();
    let parse_output = parse_fn(buf)?;
    let dur1 = now.elapsed();

    if verbose {
        eprintln!("{}: parse time: {}.{:09}",
                  PROG_NAME, dur1.as_secs(), dur1.subsec_nanos());
    }

    // Early exit if parse-only
    if parse_only {
        return Ok(());
    }

    // Pretty print
    let now = Instant::now();
    pp_fn(parse_output, indent, terms_per_line);
    let dur2 = now.elapsed();

    if verbose {
        eprintln!("{}: print time: {}.{:09}",
                  PROG_NAME, dur2.as_secs(), dur2.subsec_nanos());
    }

    return Ok(());
}

fn parse_bert1(buf: Vec<u8>) -> Result<Vec<BertTerm>> {
    let mut parser = parser::Parser::new(buf);
    let term = parser.parse()?;
    return Ok(vec![term]);
}

fn parse_bert2(buf: Vec<u8>) -> Result<Vec<BertTerm>> {
    let mut parser = parser::Parser::new(buf);
    return parser.parse_bert2();
}
<commit_msg>Fix formatting of warning message<commit_after>extern crate ppbert;
#[macro_use] extern crate clap;

use std::io::{self, Read};
use std::fs::File;
use std::process::exit;
use std::time::Instant;

use clap::{Arg, App};

use ppbert::bertterm::{
    self,
    BertTerm,
    DEFAULT_INDENT_WIDTH,
    DEFAULT_MAX_TERMS_PER_LINE
};
use ppbert::error::Result;
use ppbert::parser;

const PROG_NAME: &str = "ppbert";

fn main() {
    let matches = App::new(PROG_NAME)
        .version(crate_version!())
        .author("Vincent Foley")
        .about("Pretty print structure encoded in Erlang's External Term Format")
        .arg(Arg::with_name("input_files")
             .value_name("FILES")
             .multiple(true))
        .arg(Arg::with_name("indent_width")
             .help("Indents with <num> spaces")
             .value_name("num")
             .short("i")
             .long("--indent-width")
             .takes_value(true))
        .arg(Arg::with_name("max_per_line")
             .help("Prints at most <num> basic terms per line")
             .value_name("num")
             .short("m")
             .long("--max-terms-per-line")
             .takes_value(true))
        .arg(Arg::with_name("verbose")
             .help("Enables verbose mode")
             .short("v")
             .long("--verbose"))
        .arg(Arg::with_name("parse")
             .help("Parses the input, doesn't pretty print it")
             .short("p")
             .long("--parse"))
        .arg(Arg::with_name("bert2")
             .help("Parses .bert2 files")
             .short("2")
             .long("bert2"))
        .arg(Arg::with_name("json")
             .help("Outputs in JSON")
             .short("j")
             .long("json"))
        .arg(Arg::with_name("transform-proplists")
             .help("Transforms proplists into JSON objects (only valid with --json)")
             .long("transform-proplists"))
        .get_matches();

    let files: Vec<&str> = match matches.values_of("input_files") {
        Some(files) => files.collect(),
        None => vec!["-"]
    };

    let indent_level = value_t!(matches, "indent_width", usize)
        .unwrap_or(DEFAULT_INDENT_WIDTH);
    let max_per_line = value_t!(matches, "max_per_line", usize)
        .unwrap_or(DEFAULT_MAX_TERMS_PER_LINE);
    let verbose = matches.is_present("verbose");
    let parse_only = matches.is_present("parse");

    let transform_proplists = matches.is_present("transform-proplists");
    let parse_fn = if matches.is_present("bert2") { parse_bert2 } else { parse_bert1 };
    let output_fn =
        if matches.is_present("json") {
            if transform_proplists {
                bertterm::pp_json_proplist
            } else {
                bertterm::pp_json
            }
        } else {
            if transform_proplists {
                eprintln!("{}: warning: --transform-proplists is only valid with the --json flag",
                          PROG_NAME);
            }
            bertterm::pp_bert
        };

    let mut return_code = 0;
    for file in files {
        let res = handle_file(file, parse_only, verbose,
                              indent_level, max_per_line,
                              parse_fn, output_fn);
        match res {
            Ok(()) => (),
            Err(e) => {
                return_code = 1;
                eprintln!("{}: {}: {}", PROG_NAME, file, e);
            }
        }
    }
    exit(return_code);
}

fn handle_file<T>(
    file: &str,
    parse_only: bool,
    verbose: bool,
    indent: usize,
    terms_per_line: usize,
    parse_fn: fn(Vec<u8>) -> Result<T>,
    pp_fn: fn(T, usize, usize) -> ()
) -> Result<()> {

    // Read file or stdin into buffer
    let mut buf: Vec<u8> = Vec::new();
    let now = Instant::now();
    if file == "-" {
        let mut stdin = io::stdin();
        stdin.read_to_end(&mut buf)?;
    } else {
        let mut f = File::open(file)?;
        f.read_to_end(&mut buf)?;
    }
    let dur0 = now.elapsed();
    if verbose {
        eprintln!("{}: read time: {}.{:09}",
                  PROG_NAME, dur0.as_secs(), dur0.subsec_nanos());
    }

    // Parse input
    let now = Instant::now();
    let parse_output = parse_fn(buf)?;
    let dur1 = now.elapsed();

    if verbose {
        eprintln!("{}: parse time: {}.{:09}",
                  PROG_NAME, dur1.as_secs(), dur1.subsec_nanos());
    }

    // Early exit if parse-only
    if parse_only {
        return Ok(());
    }

    // Pretty print
    let now = Instant::now();
    pp_fn(parse_output, indent, terms_per_line);
    let dur2 = now.elapsed();

    if verbose {
        eprintln!("{}: print time: {}.{:09}",
                  PROG_NAME, dur2.as_secs(), dur2.subsec_nanos());
    }

    return Ok(());
}

fn parse_bert1(buf: Vec<u8>) -> Result<Vec<BertTerm>> {
    let mut parser = parser::Parser::new(buf);
    let term = parser.parse()?;
    return Ok(vec![term]);
}

fn parse_bert2(buf: Vec<u8>) -> Result<Vec<BertTerm>> {
    let mut parser = parser::Parser::new(buf);
    return parser.parse_bert2();
}
<|endoftext|>