<commit_before>// Basic types
pub type Color = usize; // 0 or 1
pub type File = usize;  // from 0 to 7
pub type Rank = usize;  // from 0 to 7
pub type Square = usize;  // from 0 to 63
pub type PieceType = usize;  // from 0 to 5
pub type MoveType = usize;  // from 0 to 3
pub type Value = i16;

// Color
pub const WHITE: Color = 0;
pub const BLACK: Color = 1;

// Piece types
pub const KING: PieceType = 0;
pub const QUEEN: PieceType = 1;
pub const ROOK: PieceType = 2;
pub const BISHOP: PieceType = 3;
pub const KNIGHT: PieceType = 4;
pub const PAWN: PieceType = 5;
pub const NO_PIECE: PieceType = 6;

// Move types
pub const MOVE_NORMAL: MoveType = 0;
pub const MOVE_ENPASSANT: MoveType = 1;
pub const MOVE_PROMOTION: MoveType = 2;
pub const MOVE_CASTLING: MoveType = 3;

// Castling rights
pub const CASTLE_WHITE_QUEENSIDE: u8 = 1 << 0;
pub const CASTLE_WHITE_KINGSIDE: u8 = 1 << 1;
pub const CASTLE_BLACK_QUEENSIDE: u8 = 1 << 2;
pub const CASTLE_BLACK_KINGSIDE: u8 = 1 << 3;
pub const CASTLE_BOTH: [u8; 2] = [CASTLE_WHITE_QUEENSIDE | CASTLE_WHITE_KINGSIDE,
                                  CASTLE_BLACK_QUEENSIDE | CASTLE_BLACK_KINGSIDE];

// Ranks
pub const RANK_1: Rank = 0;
pub const RANK_2: Rank = 1;
pub const RANK_3: Rank = 2;
pub const RANK_4: Rank = 3;
pub const RANK_5: Rank = 4;
pub const RANK_6: Rank = 5;
pub const RANK_7: Rank = 6;
pub const RANK_8: Rank = 7;

// Files
pub const FILE_A: Rank = 0;
pub const FILE_B: Rank = 1;
pub const FILE_C: Rank = 2;
pub const FILE_D: Rank = 3;
pub const FILE_E: Rank = 4;
pub const FILE_F: Rank = 5;
pub const FILE_G: Rank = 6;
pub const FILE_H: Rank = 7;

// Squares
pub const A1: Square = 0 + 0 * 8;
pub const B1: Square = 1 + 0 * 8;
pub const C1: Square = 2 + 0 * 8;
pub const D1: Square = 3 + 0 * 8;
pub const E1: Square = 4 + 0 * 8;
pub const F1: Square = 5 + 0 * 8;
pub const G1: Square = 6 + 0 * 8;
pub const H1: Square = 7 + 0 * 8;

pub const A2: Square = 0 + 1 * 8;
pub const B2: Square = 1 + 1 * 8;
pub const C2: Square = 2 + 1 * 8;
pub const D2: Square = 3 + 1 * 8;
pub const E2: Square = 4 + 1 * 8;
pub const F2: Square = 5 + 1 * 8;
pub const G2: Square = 6 + 1 * 8;
pub const H2: Square = 7 + 1 * 8;

pub const A3: Square = 0 + 2 * 8;
pub const B3: Square = 1 + 2 * 8;
pub const C3: Square = 2 + 2 * 8;
pub const D3: Square = 3 + 2 * 8;
pub const E3: Square = 4 + 2 * 8;
pub const F3: Square = 5 + 2 * 8;
pub const G3: Square = 6 + 2 * 8;
pub const H3: Square = 7 + 2 * 8;

pub const A4: Square = 0 + 3 * 8;
pub const B4: Square = 1 + 3 * 8;
pub const C4: Square = 2 + 3 * 8;
pub const D4: Square = 3 + 3 * 8;
pub const E4: Square = 4 + 3 * 8;
pub const F4: Square = 5 + 3 * 8;
pub const G4: Square = 6 + 3 * 8;
pub const H4: Square = 7 + 3 * 8;

pub const A5: Square = 0 + 4 * 8;
pub const B5: Square = 1 + 4 * 8;
pub const C5: Square = 2 + 4 * 8;
pub const D5: Square = 3 + 4 * 8;
pub const E5: Square = 4 + 4 * 8;
pub const F5: Square = 5 + 4 * 8;
pub const G5: Square = 6 + 4 * 8;
pub const H5: Square = 7 + 4 * 8;

pub const A6: Square = 0 + 5 * 8;
pub const B6: Square = 1 + 5 * 8;
pub const C6: Square = 2 + 5 * 8;
pub const D6: Square = 3 + 5 * 8;
pub const E6: Square = 4 + 5 * 8;
pub const F6: Square = 5 + 5 * 8;
pub const G6: Square = 6 + 5 * 8;
pub const H6: Square = 7 + 5 * 8;

pub const A7: Square = 0 + 6 * 8;
pub const B7: Square = 1 + 6 * 8;
pub const C7: Square = 2 + 6 * 8;
pub const D7: Square = 3 + 6 * 8;
pub const E7: Square = 4 + 6 * 8;
pub const F7: Square = 5 + 6 * 8;
pub const G7: Square = 6 + 6 * 8;
pub const H7: Square = 7 + 6 * 8;

pub const A8: Square = 0 + 7 * 8;
pub const B8: Square = 1 + 7 * 8;
pub const C8: Square = 2 + 7 * 8;
pub const D8: Square = 3 + 7 * 8;
pub const E8: Square = 4 + 7 * 8;
pub const F8: Square = 5 + 7 * 8;
pub const G8: Square = 6 + 7 * 8;
pub const H8: Square = 7 + 7 * 8;

// We use "u64" bit-sets called bitboards (BB) to represent a set of
// squares on the board. Here are some useful square-sets.
pub const UNIVERSAL_SET: u64 = 0xffffffffffffffff;
pub const EMPTY_SET: u64 = 0;

pub const BB_RANK_1: u64 = 0b11111111;
pub const BB_RANK_2: u64 = BB_RANK_1 << 8;
pub const BB_RANK_3: u64 = BB_RANK_2 << 8;
pub const BB_RANK_4: u64 = BB_RANK_3 << 8;
pub const BB_RANK_5: u64 = BB_RANK_4 << 8;
pub const BB_RANK_6: u64 = BB_RANK_5 << 8;
pub const BB_RANK_7: u64 = BB_RANK_6 << 8;
pub const BB_RANK_8: u64 = BB_RANK_7 << 8;

pub const BB_FILE_A: u64 = 1 << A1 | 1 << A2 | 1 << A3 | 1 << A4 | 1 << A5 | 1 << A6 | 1 << A7 |
                           1 << A8;
pub const BB_FILE_B: u64 = BB_FILE_A << 1;
pub const BB_FILE_C: u64 = BB_FILE_B << 1;
pub const BB_FILE_D: u64 = BB_FILE_C << 1;
pub const BB_FILE_E: u64 = BB_FILE_D << 1;
pub const BB_FILE_F: u64 = BB_FILE_E << 1;
pub const BB_FILE_G: u64 = BB_FILE_F << 1;
pub const BB_FILE_H: u64 = BB_FILE_G << 1;

// The maximum number of moves in the move stack. It should be large
// enough so we that never overrun it.
pub const MOVE_STACK_SIZE: usize = 32 * 256;

#[derive(Debug)]
#[derive(Clone, Copy)]
pub struct CastlingRights(u8);

impl CastlingRights {
    #[inline(always)]
    pub fn new() -> CastlingRights {
        CastlingRights(0)
    }

    pub fn set(&mut self, mask: u8) -> bool {
        let before = self.0;
        self.0 |= mask;
        self.0 != before
    }

    #[inline(always)]
    pub fn clear(&mut self, mask: u8) {
        self.0 &= !mask;
    }

    #[inline(always)]
    pub fn obstacles(&self, color: Color, side: usize) -> u64 {
        assert!(color <= 1);
        assert!(side <= 1);
        if (1 << (color << 1) << side) & self.0 == 0 {
            // castling is not allowed, therefore every piece on every
            // square on the board is an obstacle
            return UNIVERSAL_SET;
        }
        let obstacles = match side {
            0 => 1 << B1 | 1 << C1 | 1 << D1,
            _ => 1 << F1 | 1 << G1,
        };
        match color {
            WHITE => obstacles,
            _ => obstacles << 56,
        }
    }

    #[inline]
    pub fn rook_mask(&self, color: Color, side: usize) -> u64 {
        let mask = match side {
            0 => 1 << A1 | 1 << D1,
            1 => 1 << H1 | 1 << G1,
            _ => panic!("invalid castling side"),
        };
        match color {
            WHITE => mask,
            BLACK => mask << 56,
            _ => panic!("invalid color"),
        }
    }
}

#[derive(Debug)]
#[derive(Clone, Copy)]
pub struct Move(u16);

impl Move {
    #[inline(always)]
    pub fn new(move_type: MoveType, orig: Square, dest: Square, pp_code: usize) -> Move {
        assert!(move_type <= 3);
        assert!(orig <= 63);
        assert!(dest <= 63);
        assert!(pp_code <= 3);
        Move(((move_type << 14) | (pp_code << 12) | (orig << 6) | dest) as u16)
    }

    #[inline]
    pub fn move_type(&self) -> MoveType {
        ((self.0 & (0b11 << 14)) >> 14) as MoveType
    }

    #[inline]
    pub fn orig_square(&self) -> Square {
        ((self.0 & (0b111111 << 6)) >> 6) as Square
    }

    #[inline]
    pub fn dest_square(&self) -> Square {
        (self.0 & 0b111111) as Square
    }

    #[inline]
    pub fn promoted_piece(&self) -> PieceType {
        Move::piece_type_from_pp_code(((self.0 & (0b11 << 12)) >> 12) as usize)
    }

    #[inline(always)]
    pub fn piece_type_from_pp_code(piece_code: usize) -> PieceType {
        match piece_code {
            0 => QUEEN,
            1 => ROOK,
            2 => BISHOP,
            3 => KNIGHT,
            _ => panic!("invalid promoted piece code"),
        }
    }
}

#[derive(Debug)]
#[derive(Clone, Copy)]
#[derive(PartialOrd, Ord, PartialEq, Eq)]
pub struct MoveScore(u16);

impl MoveScore {
    #[inline(always)]
    pub fn new(attacking_piece: PieceType, target_piece: PieceType) -> MoveScore {
        assert!(attacking_piece < NO_PIECE);
        assert!(target_piece != KING && target_piece <= NO_PIECE);
        MoveScore((((!target_piece & 0b111) << 3) | attacking_piece) as u16)
    }

    #[inline]
    pub fn target_piece(&self) -> PieceType {
        ((!self.0 & (0b111 << 3)) >> 3) as PieceType
    }

    #[inline]
    pub fn attacking_piece(&self) -> PieceType {
        (self.0 & 0b111) as PieceType
    }

    #[inline]
    pub fn set_bit(&mut self, i: u16) {
        assert!(i >= 6);
        self.0 |= 1 << i;
    }

    #[inline]
    pub fn clear_bit(&mut self, i: u16) {
        assert!(i >= 6);
        self.0 &= !(1 << i);
    }
}

pub struct MoveAndMoveScore {
    pub m: Move,
    pub score: MoveScore,
}

pub struct MoveStack {
    stack: [MoveAndMoveScore; MOVE_STACK_SIZE],
    top_index: usize,
}

impl MoveStack {
    pub fn new() -> MoveStack {
        use std::mem::uninitialized;
        unsafe {
            MoveStack {
                stack: uninitialized(),
                top_index: 0,
            }
        }
    }

    #[inline(always)]
    pub fn push(&mut self, m: Move, score: MoveScore) {
        self.stack[self.top_index] = MoveAndMoveScore {
            m: m,
            score: score,
        };
        self.top_index += 1;
    }
}

#[inline]
pub fn square(file: File, rank: Rank) -> Square {
    assert!(file < 8);
    assert!(rank < 8);
    rank * 8 + file
}

#[inline]
pub fn rank(square: Square) -> Rank {
    square / 8
}

#[inline]
pub fn file(square: Square) -> File {
    square % 8
}
<commit_msg>revert castle_both<commit_after>// Basic types
pub type Color = usize; // 0 or 1
pub type File = usize;  // from 0 to 7
pub type Rank = usize;  // from 0 to 7
pub type Square = usize;  // from 0 to 63
pub type PieceType = usize;  // from 0 to 5
pub type MoveType = usize;  // from 0 to 3
pub type Value = i16;

// Color
pub const WHITE: Color = 0;
pub const BLACK: Color = 1;

// Piece types
pub const KING: PieceType = 0;
pub const QUEEN: PieceType = 1;
pub const ROOK: PieceType = 2;
pub const BISHOP: PieceType = 3;
pub const KNIGHT: PieceType = 4;
pub const PAWN: PieceType = 5;
pub const NO_PIECE: PieceType = 6;

// Move types
pub const MOVE_NORMAL: MoveType = 0;
pub const MOVE_ENPASSANT: MoveType = 1;
pub const MOVE_PROMOTION: MoveType = 2;
pub const MOVE_CASTLING: MoveType = 3;

// Castling rights
pub const CASTLE_WHITE_QUEENSIDE: u8 = 1 << 0;
pub const CASTLE_WHITE_KINGSIDE: u8 = 1 << 1;
pub const CASTLE_BLACK_QUEENSIDE: u8 = 1 << 2;
pub const CASTLE_BLACK_KINGSIDE: u8 = 1 << 3;

// Ranks
pub const RANK_1: Rank = 0;
pub const RANK_2: Rank = 1;
pub const RANK_3: Rank = 2;
pub const RANK_4: Rank = 3;
pub const RANK_5: Rank = 4;
pub const RANK_6: Rank = 5;
pub const RANK_7: Rank = 6;
pub const RANK_8: Rank = 7;

// Files
pub const FILE_A: Rank = 0;
pub const FILE_B: Rank = 1;
pub const FILE_C: Rank = 2;
pub const FILE_D: Rank = 3;
pub const FILE_E: Rank = 4;
pub const FILE_F: Rank = 5;
pub const FILE_G: Rank = 6;
pub const FILE_H: Rank = 7;

// Squares
pub const A1: Square = 0 + 0 * 8;
pub const B1: Square = 1 + 0 * 8;
pub const C1: Square = 2 + 0 * 8;
pub const D1: Square = 3 + 0 * 8;
pub const E1: Square = 4 + 0 * 8;
pub const F1: Square = 5 + 0 * 8;
pub const G1: Square = 6 + 0 * 8;
pub const H1: Square = 7 + 0 * 8;

pub const A2: Square = 0 + 1 * 8;
pub const B2: Square = 1 + 1 * 8;
pub const C2: Square = 2 + 1 * 8;
pub const D2: Square = 3 + 1 * 8;
pub const E2: Square = 4 + 1 * 8;
pub const F2: Square = 5 + 1 * 8;
pub const G2: Square = 6 + 1 * 8;
pub const H2: Square = 7 + 1 * 8;

pub const A3: Square = 0 + 2 * 8;
pub const B3: Square = 1 + 2 * 8;
pub const C3: Square = 2 + 2 * 8;
pub const D3: Square = 3 + 2 * 8;
pub const E3: Square = 4 + 2 * 8;
pub const F3: Square = 5 + 2 * 8;
pub const G3: Square = 6 + 2 * 8;
pub const H3: Square = 7 + 2 * 8;

pub const A4: Square = 0 + 3 * 8;
pub const B4: Square = 1 + 3 * 8;
pub const C4: Square = 2 + 3 * 8;
pub const D4: Square = 3 + 3 * 8;
pub const E4: Square = 4 + 3 * 8;
pub const F4: Square = 5 + 3 * 8;
pub const G4: Square = 6 + 3 * 8;
pub const H4: Square = 7 + 3 * 8;

pub const A5: Square = 0 + 4 * 8;
pub const B5: Square = 1 + 4 * 8;
pub const C5: Square = 2 + 4 * 8;
pub const D5: Square = 3 + 4 * 8;
pub const E5: Square = 4 + 4 * 8;
pub const F5: Square = 5 + 4 * 8;
pub const G5: Square = 6 + 4 * 8;
pub const H5: Square = 7 + 4 * 8;

pub const A6: Square = 0 + 5 * 8;
pub const B6: Square = 1 + 5 * 8;
pub const C6: Square = 2 + 5 * 8;
pub const D6: Square = 3 + 5 * 8;
pub const E6: Square = 4 + 5 * 8;
pub const F6: Square = 5 + 5 * 8;
pub const G6: Square = 6 + 5 * 8;
pub const H6: Square = 7 + 5 * 8;

pub const A7: Square = 0 + 6 * 8;
pub const B7: Square = 1 + 6 * 8;
pub const C7: Square = 2 + 6 * 8;
pub const D7: Square = 3 + 6 * 8;
pub const E7: Square = 4 + 6 * 8;
pub const F7: Square = 5 + 6 * 8;
pub const G7: Square = 6 + 6 * 8;
pub const H7: Square = 7 + 6 * 8;

pub const A8: Square = 0 + 7 * 8;
pub const B8: Square = 1 + 7 * 8;
pub const C8: Square = 2 + 7 * 8;
pub const D8: Square = 3 + 7 * 8;
pub const E8: Square = 4 + 7 * 8;
pub const F8: Square = 5 + 7 * 8;
pub const G8: Square = 6 + 7 * 8;
pub const H8: Square = 7 + 7 * 8;

// We use "u64" bit-sets called bitboards (BB) to represent a set of
// squares on the board. Here are some useful square-sets.
pub const UNIVERSAL_SET: u64 = 0xffffffffffffffff;
pub const EMPTY_SET: u64 = 0;

pub const BB_RANK_1: u64 = 0b11111111;
pub const BB_RANK_2: u64 = BB_RANK_1 << 8;
pub const BB_RANK_3: u64 = BB_RANK_2 << 8;
pub const BB_RANK_4: u64 = BB_RANK_3 << 8;
pub const BB_RANK_5: u64 = BB_RANK_4 << 8;
pub const BB_RANK_6: u64 = BB_RANK_5 << 8;
pub const BB_RANK_7: u64 = BB_RANK_6 << 8;
pub const BB_RANK_8: u64 = BB_RANK_7 << 8;

pub const BB_FILE_A: u64 = 1 << A1 | 1 << A2 | 1 << A3 | 1 << A4 | 1 << A5 | 1 << A6 | 1 << A7 |
                           1 << A8;
pub const BB_FILE_B: u64 = BB_FILE_A << 1;
pub const BB_FILE_C: u64 = BB_FILE_B << 1;
pub const BB_FILE_D: u64 = BB_FILE_C << 1;
pub const BB_FILE_E: u64 = BB_FILE_D << 1;
pub const BB_FILE_F: u64 = BB_FILE_E << 1;
pub const BB_FILE_G: u64 = BB_FILE_F << 1;
pub const BB_FILE_H: u64 = BB_FILE_G << 1;

// The maximum number of moves in the move stack. It should be large
// enough so we that never overrun it.
pub const MOVE_STACK_SIZE: usize = 32 * 256;

#[derive(Debug)]
#[derive(Clone, Copy)]
pub struct CastlingRights(u8);

impl CastlingRights {
    #[inline(always)]
    pub fn new() -> CastlingRights {
        CastlingRights(0)
    }

    pub fn set(&mut self, mask: u8) -> bool {
        let before = self.0;
        self.0 |= mask;
        self.0 != before
    }

    #[inline(always)]
    pub fn clear(&mut self, mask: u8) {
        self.0 &= !mask;
    }

    #[inline(always)]
    pub fn obstacles(&self, color: Color, side: usize) -> u64 {
        assert!(color <= 1);
        assert!(side <= 1);
        if (1 << (color << 1) << side) & self.0 == 0 {
            // castling is not allowed, therefore every piece on every
            // square on the board is an obstacle
            return UNIVERSAL_SET;
        }
        let obstacles = match side {
            0 => 1 << B1 | 1 << C1 | 1 << D1,
            _ => 1 << F1 | 1 << G1,
        };
        match color {
            WHITE => obstacles,
            _ => obstacles << 56,
        }
    }

    #[inline]
    pub fn rook_mask(&self, color: Color, side: usize) -> u64 {
        let mask = match side {
            0 => 1 << A1 | 1 << D1,
            1 => 1 << H1 | 1 << G1,
            _ => panic!("invalid castling side"),
        };
        match color {
            WHITE => mask,
            BLACK => mask << 56,
            _ => panic!("invalid color"),
        }
    }
}

#[derive(Debug)]
#[derive(Clone, Copy)]
pub struct Move(u16);

impl Move {
    #[inline(always)]
    pub fn new(move_type: MoveType, orig: Square, dest: Square, pp_code: usize) -> Move {
        assert!(move_type <= 3);
        assert!(orig <= 63);
        assert!(dest <= 63);
        assert!(pp_code <= 3);
        Move(((move_type << 14) | (pp_code << 12) | (orig << 6) | dest) as u16)
    }

    #[inline]
    pub fn move_type(&self) -> MoveType {
        ((self.0 & (0b11 << 14)) >> 14) as MoveType
    }

    #[inline]
    pub fn orig_square(&self) -> Square {
        ((self.0 & (0b111111 << 6)) >> 6) as Square
    }

    #[inline]
    pub fn dest_square(&self) -> Square {
        (self.0 & 0b111111) as Square
    }

    #[inline]
    pub fn promoted_piece(&self) -> PieceType {
        Move::piece_type_from_pp_code(((self.0 & (0b11 << 12)) >> 12) as usize)
    }

    #[inline(always)]
    pub fn piece_type_from_pp_code(piece_code: usize) -> PieceType {
        match piece_code {
            0 => QUEEN,
            1 => ROOK,
            2 => BISHOP,
            3 => KNIGHT,
            _ => panic!("invalid promoted piece code"),
        }
    }
}

#[derive(Debug)]
#[derive(Clone, Copy)]
#[derive(PartialOrd, Ord, PartialEq, Eq)]
pub struct MoveScore(u16);

impl MoveScore {
    #[inline(always)]
    pub fn new(attacking_piece: PieceType, target_piece: PieceType) -> MoveScore {
        assert!(attacking_piece < NO_PIECE);
        assert!(target_piece != KING && target_piece <= NO_PIECE);
        MoveScore((((!target_piece & 0b111) << 3) | attacking_piece) as u16)
    }

    #[inline]
    pub fn target_piece(&self) -> PieceType {
        ((!self.0 & (0b111 << 3)) >> 3) as PieceType
    }

    #[inline]
    pub fn attacking_piece(&self) -> PieceType {
        (self.0 & 0b111) as PieceType
    }

    #[inline]
    pub fn set_bit(&mut self, i: u16) {
        assert!(i >= 6);
        self.0 |= 1 << i;
    }

    #[inline]
    pub fn clear_bit(&mut self, i: u16) {
        assert!(i >= 6);
        self.0 &= !(1 << i);
    }
}

pub struct MoveAndMoveScore {
    pub m: Move,
    pub score: MoveScore,
}

pub struct MoveStack {
    stack: [MoveAndMoveScore; MOVE_STACK_SIZE],
    top_index: usize,
}

impl MoveStack {
    pub fn new() -> MoveStack {
        use std::mem::uninitialized;
        unsafe {
            MoveStack {
                stack: uninitialized(),
                top_index: 0,
            }
        }
    }

    #[inline(always)]
    pub fn push(&mut self, m: Move, score: MoveScore) {
        self.stack[self.top_index] = MoveAndMoveScore {
            m: m,
            score: score,
        };
        self.top_index += 1;
    }
}

#[inline]
pub fn square(file: File, rank: Rank) -> Square {
    assert!(file < 8);
    assert!(rank < 8);
    rank * 8 + file
}

#[inline]
pub fn rank(square: Square) -> Rank {
    square / 8
}

#[inline]
pub fn file(square: Square) -> File {
    square % 8
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;

use std::env;
use std::io::{self, Write};
use std::thread;
use std::time::Duration;

use coreutils::extra::{OptionalExt};

const MAN_PAGE: &'static str = r#"NAME
    sleep - delay for a specified amount of time

SYNOPSIS
    sleep [-h | --help] NUMBER[SUFFIX]...

DESCRIPTION
    Pause the shell for NUMBER seconds. An optional SUFFIX may be applied, such as 's' for seconds (default), 'm' for minutes, 'h' for hours or 'd' for day. Given multiple arguments, it will pause for the amount of time specified by the sum of their values. This implementation supports floating point numbers as input.

EXAMPLE
    The following are three possible arguments with the same effect:

    sleep {90, 1.5m, 1m 30s}

OPTIONS
    -h
    --help
        display this help and exit

AUTHOR
    Written by Michael Murphy.
"#;

const MISSING_OPERAND: &'static str = "missing operand\n";
const HELP_INFO:       &'static str = "Try 'sleep --help' for more information.\n";

fn main() {
    let stdout     = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    let mut args   = env::args().skip(1);

    if let Some(arg) = args.next() {
        match arg.as_str() {
            "-h" | "--help" => {
                stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
            },
            _ => {
                thread::sleep(Duration::from_millis(argument_to_ms(&arg)));
                for argument in args {
                    thread::sleep(Duration::from_millis(argument_to_ms(&argument)));
                }
            }
        }
    } else {
        stderr.write(MISSING_OPERAND.as_bytes()).try(&mut stderr);
        stdout.write(HELP_INFO.as_bytes()).try(&mut stderr);
    }
}

/// Check if the argument uses a time suffix and convert the time accordingly.
fn argument_to_ms(argument: &str) -> u64 {
    // If the argument is a number, the duration is in seconds, so multiply it by 1000.
    if let Ok(number) = argument.parse::<f64>() {
        return (number * 1000f64) as u64;
    }

    let mut stderr = io::stderr();

    // Split the argument into two strings at the last character. The first string should be the
    // number while the second string should be the duration unit:
    // s = seconds; m = minutes; h = hours; d = days
    let (prefix, suffix) = argument.split_at(argument.len()-1);
    if let Ok(number) = prefix.parse::<f64>() {
        match suffix {
            "s" => (number * 1000f64) as u64,
            "m" => (number * 60000f64) as u64,
            "h" => (number * 3600000f64) as u64,
            "d" => (number * 86400000f64) as u64,
            _   => {
                stderr.write(b"invalid time interval '").try(&mut stderr);
                stderr.write(argument.as_bytes()).try(&mut stderr);
                stderr.write(b"\'\n").try(&mut stderr);
                stderr.flush().try(&mut stderr);
                std::process::exit(1);
            }
        }
    } else {
        stderr.write(b"invalid time interval '").try(&mut stderr);
        stderr.write(argument.as_bytes()).try(&mut stderr);
        stderr.write(b"\'\n").try(&mut stderr);
        stderr.flush().try(&mut stderr);
        std::process::exit(1);
    }
}
<commit_msg>Amend #28 to avoid possible deadlock<commit_after>#![deny(warnings)]

extern crate coreutils;

use std::env;
use std::io::{self, Write, Stderr};
use std::process::exit;
use std::thread;
use std::time::Duration;

use coreutils::extra::OptionalExt;

const MAN_PAGE: &'static str = r#"NAME
    sleep - delay for a specified amount of time.

SYNOPSIS
    sleep [-h | --help] NUMBER[SUFFIX]...

DESCRIPTION
    Pause the shell for NUMBER seconds. An optional SUFFIX may be applied, such as 's' for seconds (default), 'm' for minutes, 'h' for hours or 'd' for day. Given multiple arguments, it will pause for the amount of time specified by the sum of their values. This implementation supports floating point numbers as input.

EXAMPLE
    The following are three possible arguments with the same effect:

    sleep {90, 1.5m, 1m 30s}

OPTIONS
    -h
    --help
        display this help and exit

AUTHOR
    Written by Michael Murphy.
"#;

const MISSING_OPERAND: &'static str = "missing operand\n";
const HELP_INFO:       &'static str = "Try 'sleep --help' for more information.\n";

fn main() {
    let stdout     = io::stdout();
    let mut stdout = stdout.lock();
    let mut stderr = io::stderr();
    let mut args   = env::args().skip(1);

    if let Some(arg) = args.next() {
        match arg.as_str() {
            "-h" | "--help" => {
                stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
            },
            _ => {
                thread::sleep(Duration::from_millis(argument_to_ms(&arg, &mut stderr)));
                for argument in args {
                    thread::sleep(Duration::from_millis(argument_to_ms(&argument, &mut stderr)));
                }
            }
        }
    } else {
        stderr.write(MISSING_OPERAND.as_bytes()).try(&mut stderr);
        stderr.write(HELP_INFO.as_bytes()).try(&mut stderr);
        stderr.flush().try(&mut stderr);
        exit(1);
    }
}

/// Check if the argument uses a time suffix and convert the time accordingly.
fn argument_to_ms(argument: &str, stderr: &mut Stderr) -> u64 {
    // If the argument is a number, the duration is in seconds, so multiply it by 1000.
    if let Ok(number) = argument.parse::<f64>() {
        return (number * 1000f64) as u64;
    }

    // Split the argument into two strings at the last character. The first string should be the
    // number while the second string should be the duration unit:
    // s = seconds; m = minutes; h = hours; d = days
    let (prefix, suffix) = argument.split_at(argument.len()-1);
    if let Ok(number) = prefix.parse::<f64>() {
        match suffix {
            "s" => (number * 1000f64) as u64,
            "m" => (number * 60000f64) as u64,
            "h" => (number * 3600000f64) as u64,
            "d" => (number * 86400000f64) as u64,
            _   => {
                stderr.write(b"invalid time interval '").try(&mut *stderr);
                stderr.write(argument.as_bytes()).try(&mut *stderr);
                stderr.write(b"\'\n").try(&mut *stderr);
                stderr.flush().try(&mut *stderr);
                exit(1);
            }
        }
    } else {
        stderr.write(b"invalid time interval '").try(&mut *stderr);
        stderr.write(argument.as_bytes()).try(&mut *stderr);
        stderr.write(b"\'\n").try(&mut *stderr);
        stderr.flush().try(&mut *stderr);
        exit(1);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Private callback support functions.

use libc::{c_double, c_int, c_uint};
use std::mem;

use super::*;

macro_rules! callback(
    (
        type Args = ($($arg:ident: $arg_ty:ty),*);
        type Callback = $Callback:ident;
        let ext_set = $ext_set:expr;
        fn callback($($ext_arg:ident: $ext_arg_ty:ty),*) $call:expr
    ) => (
        local_data_key!(CALLBACK_KEY: Box<Object<Args> + 'static>)

        type Args = ($($arg_ty),*,);

        trait Object<T> {
            fn call(&self, args: T);
        }

        impl<UserData> Object<Args> for ::Callback<fn($($arg_ty),*, &UserData), UserData> {
            fn call(&self, ($($arg),*,): Args) {
                (self.f)($($arg),*, &self.data);
            }
        }

        pub fn set<UserData: 'static>(f: ::$Callback<UserData>) {
            CALLBACK_KEY.replace(Some(box f as Box<Object<Args> + 'static>));
            ($ext_set)(Some(callback));
        }

        pub fn unset() {
            CALLBACK_KEY.replace(None);
            ($ext_set)(None);
        }

        extern "C" fn callback($($ext_arg: $ext_arg_ty),*) {
            match CALLBACK_KEY.get() {
                Some(cb) => unsafe { cb.call($call) },
                _ => {}
            }
        }
    )
)

pub mod error {
    use libc::{c_int, c_char};
    use std::mem;
    use std::str;

    callback!(
        type Args = (error: ::Error, description: String);
        type Callback = ErrorCallback;
        let ext_set = |cb| unsafe { ::ffi::glfwSetErrorCallback(cb) };
        fn callback(error: c_int, description: *const c_char) {
            (mem::transmute(error), str::raw::from_c_str(description))
        }
    )
}

pub mod monitor {
    use libc::{c_int};
    use std::mem;
    use std::kinds::marker;

    callback!(
        type Args = (monitor: ::Monitor, event: ::MonitorEvent);
        type Callback = MonitorCallback;
        let ext_set = |cb| unsafe { ::ffi::glfwSetMonitorCallback(cb) };
        fn callback(monitor: *mut ::ffi::GLFWmonitor, event: c_int) {
            let monitor = ::Monitor {
                ptr: monitor,
                no_copy: marker::NoCopy,
                no_send: marker::NoSend,
                no_share: marker::NoSync,
            };
            (monitor, mem::transmute(event))
        }
    )
}

unsafe fn get_sender<'a>(window: &'a *mut ffi::GLFWwindow) -> &'a Sender<(f64, WindowEvent)> {
    mem::transmute(ffi::glfwGetWindowUserPointer(*window))
}

macro_rules! window_callback(
    (fn $name:ident () => $event:ident) => (
        pub extern "C" fn $name(window: *mut ffi::GLFWwindow) {
            unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, $event)); }
        }
     );
    (fn $name:ident ($($ext_arg:ident: $ext_arg_ty:ty),*) => $event:ident($($arg_conv:expr),*)) => (
        pub extern "C" fn $name(window: *mut ffi::GLFWwindow $(, $ext_arg: $ext_arg_ty)*) {
            unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, $event($($arg_conv),*))); }
        }
     );
)

window_callback!(fn window_pos_callback(xpos: c_int, ypos: c_int)                           => PosEvent(xpos as i32, ypos as i32))
window_callback!(fn window_size_callback(width: c_int, height: c_int)                       => SizeEvent(width as i32, height as i32))
window_callback!(fn window_close_callback()                                                 => CloseEvent)
window_callback!(fn window_refresh_callback()                                               => RefreshEvent)
window_callback!(fn window_focus_callback(focused: c_int)                                   => FocusEvent(focused == ffi::TRUE))
window_callback!(fn window_iconify_callback(iconified: c_int)                               => IconifyEvent(iconified == ffi::TRUE))
window_callback!(fn framebuffer_size_callback(width: c_int, height: c_int)                  => FramebufferSizeEvent(width as i32, height as i32))
window_callback!(fn mouse_button_callback(button: c_int, action: c_int, mods: c_int)        => MouseButtonEvent(mem::transmute(button), mem::transmute(action), Modifiers::from_bits(mods).unwrap()))
window_callback!(fn cursor_pos_callback(xpos: c_double, ypos: c_double)                     => CursorPosEvent(xpos as f64, ypos as f64))
window_callback!(fn cursor_enter_callback(entered: c_int)                                   => CursorEnterEvent(entered == ffi::TRUE))
window_callback!(fn scroll_callback(xpos: c_double, ypos: c_double)                         => ScrollEvent(xpos as f64, ypos as f64))
window_callback!(fn key_callback(key: c_int, scancode: c_int, action: c_int, mods: c_int)   => KeyEvent(mem::transmute(key), scancode, mem::transmute(action), Modifiers::from_bits(mods).unwrap()))
window_callback!(fn char_callback(character: c_uint)                                        => CharEvent(::std::char::from_u32(character).unwrap()))
<commit_msg>Use str::raw::from_buf rather than the deprecated str::raw::from_c_str.<commit_after>// Copyright 2013 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Private callback support functions.

use libc::{c_double, c_int, c_uint};
use std::mem;

use super::*;

macro_rules! callback(
    (
        type Args = ($($arg:ident: $arg_ty:ty),*);
        type Callback = $Callback:ident;
        let ext_set = $ext_set:expr;
        fn callback($($ext_arg:ident: $ext_arg_ty:ty),*) $call:expr
    ) => (
        local_data_key!(CALLBACK_KEY: Box<Object<Args> + 'static>)

        type Args = ($($arg_ty),*,);

        trait Object<T> {
            fn call(&self, args: T);
        }

        impl<UserData> Object<Args> for ::Callback<fn($($arg_ty),*, &UserData), UserData> {
            fn call(&self, ($($arg),*,): Args) {
                (self.f)($($arg),*, &self.data);
            }
        }

        pub fn set<UserData: 'static>(f: ::$Callback<UserData>) {
            CALLBACK_KEY.replace(Some(box f as Box<Object<Args> + 'static>));
            ($ext_set)(Some(callback));
        }

        pub fn unset() {
            CALLBACK_KEY.replace(None);
            ($ext_set)(None);
        }

        extern "C" fn callback($($ext_arg: $ext_arg_ty),*) {
            match CALLBACK_KEY.get() {
                Some(cb) => unsafe { cb.call($call) },
                _ => {}
            }
        }
    )
)

pub mod error {
    use libc::{c_int, c_char};
    use std::mem;
    use std::str;

    callback!(
        type Args = (error: ::Error, description: String);
        type Callback = ErrorCallback;
        let ext_set = |cb| unsafe { ::ffi::glfwSetErrorCallback(cb) };
        fn callback(error: c_int, description: *const c_char) {
            (mem::transmute(error), str::raw::from_buf(description as *const u8))
        }
    )
}

pub mod monitor {
    use libc::{c_int};
    use std::mem;
    use std::kinds::marker;

    callback!(
        type Args = (monitor: ::Monitor, event: ::MonitorEvent);
        type Callback = MonitorCallback;
        let ext_set = |cb| unsafe { ::ffi::glfwSetMonitorCallback(cb) };
        fn callback(monitor: *mut ::ffi::GLFWmonitor, event: c_int) {
            let monitor = ::Monitor {
                ptr: monitor,
                no_copy: marker::NoCopy,
                no_send: marker::NoSend,
                no_share: marker::NoSync,
            };
            (monitor, mem::transmute(event))
        }
    )
}

unsafe fn get_sender<'a>(window: &'a *mut ffi::GLFWwindow) -> &'a Sender<(f64, WindowEvent)> {
    mem::transmute(ffi::glfwGetWindowUserPointer(*window))
}

macro_rules! window_callback(
    (fn $name:ident () => $event:ident) => (
        pub extern "C" fn $name(window: *mut ffi::GLFWwindow) {
            unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, $event)); }
        }
     );
    (fn $name:ident ($($ext_arg:ident: $ext_arg_ty:ty),*) => $event:ident($($arg_conv:expr),*)) => (
        pub extern "C" fn $name(window: *mut ffi::GLFWwindow $(, $ext_arg: $ext_arg_ty)*) {
            unsafe { get_sender(&window).send((ffi::glfwGetTime() as f64, $event($($arg_conv),*))); }
        }
     );
)

window_callback!(fn window_pos_callback(xpos: c_int, ypos: c_int)                           => PosEvent(xpos as i32, ypos as i32))
window_callback!(fn window_size_callback(width: c_int, height: c_int)                       => SizeEvent(width as i32, height as i32))
window_callback!(fn window_close_callback()                                                 => CloseEvent)
window_callback!(fn window_refresh_callback()                                               => RefreshEvent)
window_callback!(fn window_focus_callback(focused: c_int)                                   => FocusEvent(focused == ffi::TRUE))
window_callback!(fn window_iconify_callback(iconified: c_int)                               => IconifyEvent(iconified == ffi::TRUE))
window_callback!(fn framebuffer_size_callback(width: c_int, height: c_int)                  => FramebufferSizeEvent(width as i32, height as i32))
window_callback!(fn mouse_button_callback(button: c_int, action: c_int, mods: c_int)        => MouseButtonEvent(mem::transmute(button), mem::transmute(action), Modifiers::from_bits(mods).unwrap()))
window_callback!(fn cursor_pos_callback(xpos: c_double, ypos: c_double)                     => CursorPosEvent(xpos as f64, ypos as f64))
window_callback!(fn cursor_enter_callback(entered: c_int)                                   => CursorEnterEvent(entered == ffi::TRUE))
window_callback!(fn scroll_callback(xpos: c_double, ypos: c_double)                         => ScrollEvent(xpos as f64, ypos as f64))
window_callback!(fn key_callback(key: c_int, scancode: c_int, action: c_int, mods: c_int)   => KeyEvent(mem::transmute(key), scancode, mem::transmute(action), Modifiers::from_bits(mods).unwrap()))
window_callback!(fn char_callback(character: c_uint)                                        => CharEvent(::std::char::from_u32(character).unwrap()))
<|endoftext|>


<commit_before>extern crate rustbox;

use self::rustbox::{Color, Style, RustBox};

use super::board::{Board, HEIGHT, WIDTH};
use super::tetromino::{Tetromino, TetrominoType};
use super::window::Window;

// Default values for styling terminal output
const DEFAULT_STYLE: Style = rustbox::RB_NORMAL;
const DEFAULT_FG: Color = Color::White;
const DEFAULT_BG: Color = Color::Black;

// Default character and color pairs
const I: (char, Color) = ('@', Color::Cyan);
const J: (char, Color) = ('#', Color::Blue);
const L: (char, Color) = ('&', Color::White);
const O: (char, Color) = ('%', Color::Yellow);
const S: (char, Color) = ('$', Color::Green);
const T: (char, Color) = ('*', Color::Magenta);
const Z: (char, Color) = ('O', Color::Red);

/// A collection of Window structs representing the user interface
pub struct Ui<'a> {
    board: Window<'a>,
    score: Window<'a>,
    level: Window<'a>,
    lines: Window<'a>,
    next_piece: Window<'a>,
}

impl<'a> Ui<'a> {

    /// Initializes a new Ui struct
    pub fn new(rb: &'a RustBox) -> Self {
        Ui {
            board: Window::new(0, 0, 11, 21, rb),
            score: Window::new(12, 0, 11, 2, rb),
            level: Window::new(12, 4, 11, 2, rb),
            lines: Window::new(12, 8, 11, 2, rb),
            next_piece: Window::new(12, 12, 11, 6, rb)
        }
    }

    /// Setup the default elements of the user interface
    pub fn setup(&self) {

        // Print out the borders for the player stats
        self.board.print_borders(DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG);
        self.score.print_borders(DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG);
        self.level.print_borders(DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG);
        self.lines.print_borders(DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG);
        self.next_piece.print_borders(DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG);

        // Print out the initial values for the player stats
        self.print_score(0);
        self.print_level(0);
        self.print_lines(0);
    }

    /// Print the state of the board
    pub fn print_board(&self, board: &Board) {

        // Start at 2 because only 20 of the board's rows should be displayed
        for y in 2..HEIGHT {
            for x in 0..WIDTH {
                match board.field[y][x] {

                    // When printing the board, offset x and y to compensate
                    // for the Window's borders and showing only 20 rows
                    Some(ref mino) =>  {
                        let (rune, color) = self.get_style(mino);
                        self.board.print_char(x + 1, y - 1, DEFAULT_STYLE, color, DEFAULT_BG, rune);
                    }

                    None => self.board.print_char(x + 1, y - 1, DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG, ' '),
                }
            }
        }
    }

    /// Get the print style for a Mino
    fn get_style(&self, mino: &TetrominoType) -> (char, Color) {
        match *mino {
            TetrominoType::I => I,
            TetrominoType::J => J,
            TetrominoType::L => L,
            TetrominoType::O => O,
            TetrominoType::S => S,
            TetrominoType::T => T,
            TetrominoType::Z => Z,
        }
    }

    /// Print the next Tetromino
    pub fn print_next(&self, tetromino: Tetromino) {
        for i in 1..self.next_piece.w {
            for j in 1..self.next_piece.h {
                self.next_piece.print_char(i, j, DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG, ' ');
            }
        }

        for &mino in tetromino.minos.iter() {
            let (rune, color) = self.get_style(&tetromino.tetro_type);
            self.next_piece.print_char((mino.x + 4) as usize, (mino.y + 2) as usize, DEFAULT_STYLE, color, DEFAULT_BG, rune);
        }
    }

    /// Print the player's score
    pub fn print_score(&self, score: u32) {
        self.score.print(1, 1, DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG, &format!("{:010}", score));
    }

    /// Print the difficulty level
    pub fn print_level(&self, level: u8) {
        self.level.print(1, 1, DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG, &format!("{:}", level));
    }

    /// Print the number of lines cleared
    pub fn print_lines(&self, lines: u8) {
        self.lines.print(1, 1, DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG, &format!("{:}", lines));
    }
}<commit_msg>Add rough version of scaling in the x-axis<commit_after>extern crate rustbox;

use self::rustbox::{Color, Style, RustBox};

use super::board::{Board, HEIGHT, WIDTH};
use super::tetromino::{Tetromino, TetrominoType};
use super::window::Window;

// Default scaling factor for the board
const SCALE: usize = 2;

// Default values for styling terminal output
const DEFAULT_STYLE: Style = rustbox::RB_NORMAL;
const DEFAULT_FG: Color = Color::White;
const DEFAULT_BG: Color = Color::Black;

// Default character and color pairs
const I: (char, Color) = ('@', Color::Cyan);
const J: (char, Color) = ('#', Color::Blue);
const L: (char, Color) = ('&', Color::White);
const O: (char, Color) = ('%', Color::Yellow);
const S: (char, Color) = ('$', Color::Green);
const T: (char, Color) = ('*', Color::Magenta);
const Z: (char, Color) = ('O', Color::Red);

/// A collection of Window structs representing the user interface
pub struct Ui<'a> {
    board: Window<'a>,
    score: Window<'a>,
    level: Window<'a>,
    lines: Window<'a>,
    next_piece: Window<'a>,
}

impl<'a> Ui<'a> {

    /// Initializes a new Ui struct
    pub fn new(rb: &'a RustBox) -> Self {
        Ui {
            board: Window::new(0, 0, (11 * SCALE) - 1, 21, rb),
            score: Window::new(12 * SCALE, 0, 11, 2, rb),
            level: Window::new(12 * SCALE, 4, 11, 2, rb),
            lines: Window::new(12 * SCALE, 8, 11, 2, rb),
            next_piece: Window::new(12 * SCALE, 12, 11, 6, rb)
        }
    }

    /// Setup the default elements of the user interface
    pub fn setup(&self) {

        // Print out the borders for the player stats
        self.board.print_borders(DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG);
        self.score.print_borders(DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG);
        self.level.print_borders(DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG);
        self.lines.print_borders(DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG);
        self.next_piece.print_borders(DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG);

        // Print out the initial values for the player stats
        self.print_score(0);
        self.print_level(0);
        self.print_lines(0);
    }

    /// Print the state of the board
    pub fn print_board(&self, board: &Board) {

        // Start at 2 because only 20 of the board's rows should be displayed
        for y in 2..HEIGHT {
            for x in 0..WIDTH {
                match board.field[y][x] {

                    // When printing the board, offset x and y to compensate
                    // for the Window's borders and showing only 20 rows
                    Some(ref mino) =>  {
                        let (rune, color) = self.get_style(mino);
                        self.board.print_char((x * SCALE) + 1, y - 1, DEFAULT_STYLE, color, DEFAULT_BG, rune);
                        self.board.print_char((x * SCALE) + 2, y - 1, DEFAULT_STYLE, color, DEFAULT_BG, rune);
                    }

                    None => {
                        self.board.print_char((x * SCALE) + 1, y - 1, DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG, ' ');
                        self.board.print_char((x * SCALE) + 2, y - 1, DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG, '.');
                    },
                }
            }
        }
    }

    /// Get the print style for a Mino
    fn get_style(&self, mino: &TetrominoType) -> (char, Color) {
        match *mino {
            TetrominoType::I => I,
            TetrominoType::J => J,
            TetrominoType::L => L,
            TetrominoType::O => O,
            TetrominoType::S => S,
            TetrominoType::T => T,
            TetrominoType::Z => Z,
        }
    }

    /// Print the next Tetromino
    pub fn print_next(&self, tetromino: Tetromino) {
        for i in 1..self.next_piece.w {
            for j in 1..self.next_piece.h {
                self.next_piece.print_char(i, j, DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG, ' ');
            }
        }

        for &mino in tetromino.minos.iter() {
            let (rune, color) = self.get_style(&tetromino.tetro_type);
            self.next_piece.print_char((mino.x + 4) as usize, (mino.y + 2) as usize, DEFAULT_STYLE, color, DEFAULT_BG, rune);
        }
    }

    /// Print the player's score
    pub fn print_score(&self, score: u32) {
        self.score.print(1, 1, DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG, &format!("{:010}", score));
    }

    /// Print the difficulty level
    pub fn print_level(&self, level: u8) {
        self.level.print(1, 1, DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG, &format!("{:}", level));
    }

    /// Print the number of lines cleared
    pub fn print_lines(&self, lines: u8) {
        self.lines.print(1, 1, DEFAULT_STYLE, DEFAULT_FG, DEFAULT_BG, &format!("{:}", lines));
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use y4m;

#[macro_use]
extern crate scan_fmt;

mod common;
mod decoder;
mod muxer;
use crate::common::*;
use crate::muxer::*;
use rav1e::*;

use std::io;
use std::io::Write;
use std::io::Read;
use std::path::Path;
use std::sync::Arc;
use crate::decoder::Decoder;
use crate::decoder::VideoDetails;
use std::fs::File;
use std::io::BufWriter;

struct Source<D: Decoder> {
 limit: usize,
 count: usize,
 input: D,
}

impl<D: Decoder> Source<D> {
  fn read_frame<T: Pixel>(&mut self, ctx: &mut Context<T>, video_info: VideoDetails) {
    if self.limit != 0 && self.count == self.limit {
      ctx.flush();
      return;
    }
    match self.input.read_frame(&video_info) {
      Ok(frame) => {
        match video_info.bit_depth {
          8 | 10 | 12 => {}
          _ => panic!("unknown input bit depth!")
        }
        self.count += 1;
        let _ = ctx.send_frame(Some(Arc::new(frame)));
      }
      _ => {
        ctx.flush();
      }
    };
  }
}

// Encode and write a frame.
// Returns frame information in a `Result`.
fn process_frame<T: Pixel, D: Decoder>(
  ctx: &mut Context<T>,
  output_file: &mut dyn Write,
  source: &mut Source<D>,
  mut y4m_enc: Option<&mut y4m::Encoder<'_, Box<dyn Write>>>,
) -> Option<Vec<FrameSummary>> {
  let y4m_details = source.input.get_video_details();
  let mut frame_summaries = Vec::new();
  let pkt_wrapped = ctx.receive_packet();
  match pkt_wrapped {
    Ok(pkt) => {
      write_ivf_frame(output_file, pkt.number as u64, pkt.data.as_ref());
      if let (Some(ref mut y4m_enc_uw), Some(ref rec)) = (y4m_enc.as_mut(), &pkt.rec) {
        write_y4m_frame(y4m_enc_uw, rec, y4m_details);
      }
      frame_summaries.push(pkt.into());
    }
    Err(EncoderStatus::NeedMoreData) => {
      source.read_frame(ctx, y4m_details);
    }
    Err(EncoderStatus::EnoughData) => {
      unreachable!();
    }
    Err(EncoderStatus::LimitReached) => {
      return None;
    }
    Err(EncoderStatus::Failure) => {
      panic!("Failed to encode video");
    }
    Err(EncoderStatus::Encoded) => {}
  }
  Some(frame_summaries)
}

fn write_stats_file<T: Pixel>(ctx: &Context<T>, filename: &Path) -> Result<(), io::Error> {
  let file = File::create(filename)?;
  let writer = BufWriter::new(file);
  serde_json::to_writer(writer, ctx.get_first_pass_data()).expect("Serialization should not fail");
  Ok(())
}

fn do_encode<T: Pixel, D: Decoder>(
  cfg: Config, verbose: bool, mut progress: ProgressInfo,
  mut err: std::io::StderrLock, mut output: &mut dyn Write,
  source: &mut Source<D>,
  mut y4m_enc: Option<y4m::Encoder<'_, Box<dyn Write>>>
) {
  let mut ctx: Context<T> = cfg.new_context();

  while let Some(frame_info) =
    process_frame(&mut ctx, &mut output, source, y4m_enc.as_mut())
  {
    for frame in frame_info {
      progress.add_frame(frame);
      let _ = if verbose {
        writeln!(err, "{} - {}", frame, progress)
      } else {
        write!(err, "\r{}                    ", progress)
      };
    }

    output.flush().unwrap();
  }

  if cfg.enc.pass == Some(1) {
    if let Err(e) =
      write_stats_file(&ctx, cfg.enc.stats_file.as_ref().unwrap())
    {
      let _ = writeln!(err, "\nError: Failed to write stats file! {}\n", e);
    }
  }
  let _ = write!(err, "\n{}\n", progress.print_summary());
}

fn main() {
  let mut cli = parse_cli();
  let mut y4m_dec = y4m::decode(&mut cli.io.input).expect("input is not a y4m file");
  let video_info = y4m_dec.get_video_details();
  let y4m_enc = match cli.io.rec.as_mut() {
    Some(rec) => Some(
      y4m::encode(
        video_info.width,
        video_info.height,
        y4m::Ratio::new(video_info.time_base.den as usize, video_info.time_base.num as usize)
      ).with_colorspace(y4m_dec.get_colorspace())
        .write_header(rec)
        .unwrap()
    ),
    None => None
  };

  cli.enc.width = video_info.width;
  cli.enc.height = video_info.height;
  cli.enc.bit_depth = video_info.bit_depth;
  cli.enc.chroma_sampling = video_info.chroma_sampling;
  cli.enc.chroma_sample_position = video_info.chroma_sample_position;
  cli.enc.time_base = video_info.time_base;
  let cfg = Config {
    enc: cli.enc,
    threads: cli.threads,
  };

  let stderr = io::stderr();
  let mut err = stderr.lock();

  let _ = writeln!(
    err,
    "{}x{} @ {}/{} fps",
    video_info.width,
    video_info.height,
    video_info.time_base.den,
    video_info.time_base.num
  );

  write_ivf_header(
    &mut cli.io.output,
    video_info.width,
    video_info.height,
    video_info.time_base.den as usize,
    video_info.time_base.num as usize
  );

  let progress = ProgressInfo::new(
    Rational { num: video_info.time_base.den, den: video_info.time_base.num },
    if cli.limit == 0 { None } else { Some(cli.limit) },
      cfg.enc.show_psnr
  );

  for _ in 0..cli.skip {
    y4m_dec.read_frame().expect("Skipped more frames than in the input");
  }

  let mut source = Source { limit: cli.limit, input: y4m_dec, count: 0 };

  if video_info.bit_depth == 8 {
    do_encode::<u8, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg, cli.verbose, progress, err, &mut cli.io.output, &mut source, y4m_enc
    )
  } else {
    do_encode::<u16, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg, cli.verbose, progress, err, &mut cli.io.output, &mut source, y4m_enc
    )
  }
}
<commit_msg>Do not hold the stderr lock<commit_after>// Copyright (c) 2017-2018, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use y4m;

#[macro_use]
extern crate scan_fmt;

mod common;
mod decoder;
mod muxer;
use crate::common::*;
use crate::muxer::*;
use rav1e::*;

use std::io;
use std::io::Write;
use std::io::Read;
use std::path::Path;
use std::sync::Arc;
use crate::decoder::Decoder;
use crate::decoder::VideoDetails;
use std::fs::File;
use std::io::BufWriter;

struct Source<D: Decoder> {
 limit: usize,
 count: usize,
 input: D,
}

impl<D: Decoder> Source<D> {
  fn read_frame<T: Pixel>(&mut self, ctx: &mut Context<T>, video_info: VideoDetails) {
    if self.limit != 0 && self.count == self.limit {
      ctx.flush();
      return;
    }
    match self.input.read_frame(&video_info) {
      Ok(frame) => {
        match video_info.bit_depth {
          8 | 10 | 12 => {}
          _ => panic!("unknown input bit depth!")
        }
        self.count += 1;
        let _ = ctx.send_frame(Some(Arc::new(frame)));
      }
      _ => {
        ctx.flush();
      }
    };
  }
}

// Encode and write a frame.
// Returns frame information in a `Result`.
fn process_frame<T: Pixel, D: Decoder>(
  ctx: &mut Context<T>,
  output_file: &mut dyn Write,
  source: &mut Source<D>,
  mut y4m_enc: Option<&mut y4m::Encoder<'_, Box<dyn Write>>>,
) -> Option<Vec<FrameSummary>> {
  let y4m_details = source.input.get_video_details();
  let mut frame_summaries = Vec::new();
  let pkt_wrapped = ctx.receive_packet();
  match pkt_wrapped {
    Ok(pkt) => {
      write_ivf_frame(output_file, pkt.number as u64, pkt.data.as_ref());
      if let (Some(ref mut y4m_enc_uw), Some(ref rec)) = (y4m_enc.as_mut(), &pkt.rec) {
        write_y4m_frame(y4m_enc_uw, rec, y4m_details);
      }
      frame_summaries.push(pkt.into());
    }
    Err(EncoderStatus::NeedMoreData) => {
      source.read_frame(ctx, y4m_details);
    }
    Err(EncoderStatus::EnoughData) => {
      unreachable!();
    }
    Err(EncoderStatus::LimitReached) => {
      return None;
    }
    Err(EncoderStatus::Failure) => {
      panic!("Failed to encode video");
    }
    Err(EncoderStatus::Encoded) => {}
  }
  Some(frame_summaries)
}

fn write_stats_file<T: Pixel>(ctx: &Context<T>, filename: &Path) -> Result<(), io::Error> {
  let file = File::create(filename)?;
  let writer = BufWriter::new(file);
  serde_json::to_writer(writer, ctx.get_first_pass_data()).expect("Serialization should not fail");
  Ok(())
}

fn do_encode<T: Pixel, D: Decoder>(
  cfg: Config, verbose: bool, mut progress: ProgressInfo,
  mut output: &mut dyn Write,
  source: &mut Source<D>,
  mut y4m_enc: Option<y4m::Encoder<'_, Box<dyn Write>>>
) {
  let mut ctx: Context<T> = cfg.new_context();

  while let Some(frame_info) =
    process_frame(&mut ctx, &mut output, source, y4m_enc.as_mut())
  {
    for frame in frame_info {
      progress.add_frame(frame);
      if verbose {
        eprintln!("{} - {}", frame, progress);
      } else {
        eprint!("\r{}                    ", progress);
      };
    }

    output.flush().unwrap();
  }

  if cfg.enc.pass == Some(1) {
    if let Err(e) =
      write_stats_file(&ctx, cfg.enc.stats_file.as_ref().unwrap())
    {
      eprintln!("\nError: Failed to write stats file! {}\n", e);
    }
  }
  eprint!("\n{}\n", progress.print_summary());
}

fn main() {
  let mut cli = parse_cli();
  let mut y4m_dec = y4m::decode(&mut cli.io.input).expect("input is not a y4m file");
  let video_info = y4m_dec.get_video_details();
  let y4m_enc = match cli.io.rec.as_mut() {
    Some(rec) => Some(
      y4m::encode(
        video_info.width,
        video_info.height,
        y4m::Ratio::new(video_info.time_base.den as usize, video_info.time_base.num as usize)
      ).with_colorspace(y4m_dec.get_colorspace())
        .write_header(rec)
        .unwrap()
    ),
    None => None
  };

  cli.enc.width = video_info.width;
  cli.enc.height = video_info.height;
  cli.enc.bit_depth = video_info.bit_depth;
  cli.enc.chroma_sampling = video_info.chroma_sampling;
  cli.enc.chroma_sample_position = video_info.chroma_sample_position;
  cli.enc.time_base = video_info.time_base;
  let cfg = Config {
    enc: cli.enc,
    threads: cli.threads,
  };

  eprintln!("{}x{} @ {}/{} fps",
    video_info.width,
    video_info.height,
    video_info.time_base.den,
    video_info.time_base.num
  );

  write_ivf_header(
    &mut cli.io.output,
    video_info.width,
    video_info.height,
    video_info.time_base.den as usize,
    video_info.time_base.num as usize
  );

  let progress = ProgressInfo::new(
    Rational { num: video_info.time_base.den, den: video_info.time_base.num },
    if cli.limit == 0 { None } else { Some(cli.limit) },
      cfg.enc.show_psnr
  );

  for _ in 0..cli.skip {
    y4m_dec.read_frame().expect("Skipped more frames than in the input");
  }

  let mut source = Source { limit: cli.limit, input: y4m_dec, count: 0 };

  if video_info.bit_depth == 8 {
    do_encode::<u8, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg, cli.verbose, progress, &mut cli.io.output, &mut source, y4m_enc
    )
  } else {
    do_encode::<u16, y4m::Decoder<'_, Box<dyn Read>>>(
      cfg, cli.verbose, progress, &mut cli.io.output, &mut source, y4m_enc
    )
  }
}
<|endoftext|>


<commit_before>#![cfg_attr(test, deny(warnings))]
// While we're getting used to 2018:
#![warn(rust_2018_idioms)]
// Clippy isn't enforced by CI (@alexcrichton isn't a fan).
#![allow(clippy::blacklisted_name)] // frequently used in tests
#![allow(clippy::cognitive_complexity)] // large project
#![allow(clippy::derive_hash_xor_eq)] // there's an intentional incoherence
#![allow(clippy::explicit_into_iter_loop)] // explicit loops are clearer
#![allow(clippy::explicit_iter_loop)] // explicit loops are clearer
#![allow(clippy::identity_op)] // used for vertical alignment
#![allow(clippy::implicit_hasher)] // large project
#![allow(clippy::large_enum_variant)] // large project
#![allow(clippy::new_without_default)] // explicit is maybe clearer
#![allow(clippy::redundant_closure)] // closures can be less verbose
#![allow(clippy::redundant_closure_call)] // closures over try catch blocks
#![allow(clippy::too_many_arguments)] // large project
#![allow(clippy::type_complexity)] // there's an exceptionally complex type
#![allow(clippy::wrong_self_convention)] // perhaps `Rc` should be special-cased in Clippy?
#![allow(clippy::write_with_newline)] // too pedantic
#![allow(clippy::inefficient_to_string)] // this causes suggestions that result in `(*s).to_string()`
#![warn(clippy::needless_borrow)]
#![warn(clippy::redundant_clone)]
// Unit is now interned, and would probably be better as pass-by-copy, but
// doing so causes a lot of & and * shenanigans that makes the code arguably
// less clear and harder to read.
#![allow(clippy::trivially_copy_pass_by_ref)]
// exhaustively destructuring ensures future fields are handled
#![allow(clippy::unneeded_field_pattern)]
// false positives in target-specific code, for details see
// https://github.com/rust-lang/cargo/pull/7251#pullrequestreview-274914270
#![allow(clippy::useless_conversion)]

use crate::core::shell::Verbosity::Verbose;
use crate::core::Shell;
use anyhow::Error;
use log::debug;
use std::fmt;

pub use crate::util::errors::{InternalError, VerboseError};
pub use crate::util::{CargoResult, CliError, CliResult, Config};

pub const CARGO_ENV: &str = "CARGO";

#[macro_use]
mod macros;

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub struct CommitInfo {
    pub short_commit_hash: String,
    pub commit_hash: String,
    pub commit_date: String,
}

pub struct CfgInfo {
    // Information about the Git repository we may have been built from.
    pub commit_info: Option<CommitInfo>,
    // The release channel we were built for.
    pub release_channel: String,
}

pub struct VersionInfo {
    pub major: u8,
    pub minor: u8,
    pub patch: u8,
    pub pre_release: Option<String>,
    // Information that's only available when we were built with
    // configure/make, rather than Cargo itself.
    pub cfg_info: Option<CfgInfo>,
}

impl fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "cargo {}.{}.{}", self.major, self.minor, self.patch)?;
        if let Some(channel) = self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
            if channel != "stable" {
                write!(f, "-{}", channel)?;
                let empty = String::new();
                write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
            }
        };

        if let Some(ref cfg) = self.cfg_info {
            if let Some(ref ci) = cfg.commit_info {
                write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?;
            }
        };
        Ok(())
    }
}

pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! {
    debug!("exit_with_error; err={:?}", err);
    if let Some(ref err) = err.error {
        if let Some(clap_err) = err.downcast_ref::<clap::Error>() {
            clap_err.exit()
        }
    }

    let CliError { error, exit_code } = err;
    if let Some(error) = error {
        display_error(&error, shell);
    }

    std::process::exit(exit_code)
}

/// Displays an error, and all its causes, to stderr.
pub fn display_error(err: &Error, shell: &mut Shell) {
    debug!("display_error; err={:?}", err);
    let has_verbose = _display_error(err, shell, true);
    if has_verbose {
        drop(writeln!(
            shell.err(),
            "\nTo learn more, run the command again with --verbose."
        ));
    }
    if err
        .chain()
        .any(|e| e.downcast_ref::<InternalError>().is_some())
    {
        drop(shell.note("this is an unexpected cargo internal error"));
        drop(
            shell.note(
                "we would appreciate a bug report: https://github.com/rust-lang/cargo/issues/",
            ),
        );
        drop(shell.note(format!("{}", version())));
        // Once backtraces are stabilized, this should print out a backtrace
        // if it is available.
    }
}

/// Displays a warning, with an error object providing detailed information
/// and context.
pub fn display_warning_with_error(warning: &str, err: &Error, shell: &mut Shell) {
    drop(shell.warn(warning));
    drop(writeln!(shell.err()));
    _display_error(err, shell, false);
}

fn _display_error(err: &Error, shell: &mut Shell, as_err: bool) -> bool {
    let verbosity = shell.verbosity();
    let is_verbose = |e: &(dyn std::error::Error + 'static)| -> bool {
        verbosity != Verbose && e.downcast_ref::<VerboseError>().is_some()
    };
    // Generally the top error shouldn't be verbose, but check it anyways.
    if is_verbose(err.as_ref()) {
        return true;
    }
    if as_err {
        drop(shell.error(&err));
    } else {
        drop(writeln!(shell.err(), "{}", err));
    }
    for cause in err.chain().skip(1) {
        // If we're not in verbose mode then print remaining errors until one
        // marked as `VerboseError` appears.
        if is_verbose(cause) {
            return true;
        }
        drop(writeln!(shell.err(), "\nCaused by:"));
        for line in cause.to_string().lines() {
            if line.is_empty() {
                drop(writeln!(shell.err(), ""));
            } else {
                drop(writeln!(shell.err(), "  {}", line));
            }
        }
    }
    false
}

pub fn version() -> VersionInfo {
    macro_rules! option_env_str {
        ($name:expr) => {
            option_env!($name).map(|s| s.to_string())
        };
    }

    // So this is pretty horrible...
    // There are two versions at play here:
    //   - version of cargo-the-binary, which you see when you type `cargo --version`
    //   - version of cargo-the-library, which you download from crates.io for use
    //     in your packages.
    //
    // We want to make the `binary` version the same as the corresponding Rust/rustc release.
    // At the same time, we want to keep the library version at `0.x`, because Cargo as
    // a library is (and probably will always be) unstable.
    //
    // Historically, Cargo used the same version number for both the binary and the library.
    // Specifically, rustc 1.x.z was paired with cargo 0.x+1.w.
    // We continue to use this scheme for the library, but transform it to 1.x.w for the purposes
    // of `cargo --version`.
    let major = 1;
    let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap() - 1;
    let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u8>().unwrap();

    match option_env!("CFG_RELEASE_CHANNEL") {
        // We have environment variables set up from configure/make.
        Some(_) => {
            let commit_info = option_env!("CFG_COMMIT_HASH").map(|s| CommitInfo {
                commit_hash: s.to_string(),
                short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
                commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
            });
            VersionInfo {
                major,
                minor,
                patch,
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: Some(CfgInfo {
                    release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
                    commit_info,
                }),
            }
        }
        // We are being compiled by Cargo itself.
        None => VersionInfo {
            major,
            minor,
            patch,
            pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
            cfg_info: None,
        },
    }
}
<commit_msg>clippy lints: redundant_clone is on by default, allow clippy::collapsible_if<commit_after>#![cfg_attr(test, deny(warnings))]
// While we're getting used to 2018:
#![warn(rust_2018_idioms)]
// Clippy isn't enforced by CI (@alexcrichton isn't a fan).
#![allow(clippy::blacklisted_name)] // frequently used in tests
#![allow(clippy::cognitive_complexity)] // large project
#![allow(clippy::derive_hash_xor_eq)] // there's an intentional incoherence
#![allow(clippy::explicit_into_iter_loop)] // explicit loops are clearer
#![allow(clippy::explicit_iter_loop)] // explicit loops are clearer
#![allow(clippy::identity_op)] // used for vertical alignment
#![allow(clippy::implicit_hasher)] // large project
#![allow(clippy::large_enum_variant)] // large project
#![allow(clippy::new_without_default)] // explicit is maybe clearer
#![allow(clippy::redundant_closure)] // closures can be less verbose
#![allow(clippy::redundant_closure_call)] // closures over try catch blocks
#![allow(clippy::too_many_arguments)] // large project
#![allow(clippy::type_complexity)] // there's an exceptionally complex type
#![allow(clippy::wrong_self_convention)] // perhaps `Rc` should be special-cased in Clippy?
#![allow(clippy::write_with_newline)] // too pedantic
#![allow(clippy::inefficient_to_string)] // this causes suggestions that result in `(*s).to_string()`
#![allow(clippy::collapsible_if)] // too pedantic
#![warn(clippy::needless_borrow)]
// Unit is now interned, and would probably be better as pass-by-copy, but
// doing so causes a lot of & and * shenanigans that makes the code arguably
// less clear and harder to read.
#![allow(clippy::trivially_copy_pass_by_ref)]
// exhaustively destructuring ensures future fields are handled
#![allow(clippy::unneeded_field_pattern)]
// false positives in target-specific code, for details see
// https://github.com/rust-lang/cargo/pull/7251#pullrequestreview-274914270
#![allow(clippy::useless_conversion)]

use crate::core::shell::Verbosity::Verbose;
use crate::core::Shell;
use anyhow::Error;
use log::debug;
use std::fmt;

pub use crate::util::errors::{InternalError, VerboseError};
pub use crate::util::{CargoResult, CliError, CliResult, Config};

pub const CARGO_ENV: &str = "CARGO";

#[macro_use]
mod macros;

pub mod core;
pub mod ops;
pub mod sources;
pub mod util;

pub struct CommitInfo {
    pub short_commit_hash: String,
    pub commit_hash: String,
    pub commit_date: String,
}

pub struct CfgInfo {
    // Information about the Git repository we may have been built from.
    pub commit_info: Option<CommitInfo>,
    // The release channel we were built for.
    pub release_channel: String,
}

pub struct VersionInfo {
    pub major: u8,
    pub minor: u8,
    pub patch: u8,
    pub pre_release: Option<String>,
    // Information that's only available when we were built with
    // configure/make, rather than Cargo itself.
    pub cfg_info: Option<CfgInfo>,
}

impl fmt::Display for VersionInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "cargo {}.{}.{}", self.major, self.minor, self.patch)?;
        if let Some(channel) = self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
            if channel != "stable" {
                write!(f, "-{}", channel)?;
                let empty = String::new();
                write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
            }
        };

        if let Some(ref cfg) = self.cfg_info {
            if let Some(ref ci) = cfg.commit_info {
                write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?;
            }
        };
        Ok(())
    }
}

pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! {
    debug!("exit_with_error; err={:?}", err);
    if let Some(ref err) = err.error {
        if let Some(clap_err) = err.downcast_ref::<clap::Error>() {
            clap_err.exit()
        }
    }

    let CliError { error, exit_code } = err;
    if let Some(error) = error {
        display_error(&error, shell);
    }

    std::process::exit(exit_code)
}

/// Displays an error, and all its causes, to stderr.
pub fn display_error(err: &Error, shell: &mut Shell) {
    debug!("display_error; err={:?}", err);
    let has_verbose = _display_error(err, shell, true);
    if has_verbose {
        drop(writeln!(
            shell.err(),
            "\nTo learn more, run the command again with --verbose."
        ));
    }
    if err
        .chain()
        .any(|e| e.downcast_ref::<InternalError>().is_some())
    {
        drop(shell.note("this is an unexpected cargo internal error"));
        drop(
            shell.note(
                "we would appreciate a bug report: https://github.com/rust-lang/cargo/issues/",
            ),
        );
        drop(shell.note(format!("{}", version())));
        // Once backtraces are stabilized, this should print out a backtrace
        // if it is available.
    }
}

/// Displays a warning, with an error object providing detailed information
/// and context.
pub fn display_warning_with_error(warning: &str, err: &Error, shell: &mut Shell) {
    drop(shell.warn(warning));
    drop(writeln!(shell.err()));
    _display_error(err, shell, false);
}

fn _display_error(err: &Error, shell: &mut Shell, as_err: bool) -> bool {
    let verbosity = shell.verbosity();
    let is_verbose = |e: &(dyn std::error::Error + 'static)| -> bool {
        verbosity != Verbose && e.downcast_ref::<VerboseError>().is_some()
    };
    // Generally the top error shouldn't be verbose, but check it anyways.
    if is_verbose(err.as_ref()) {
        return true;
    }
    if as_err {
        drop(shell.error(&err));
    } else {
        drop(writeln!(shell.err(), "{}", err));
    }
    for cause in err.chain().skip(1) {
        // If we're not in verbose mode then print remaining errors until one
        // marked as `VerboseError` appears.
        if is_verbose(cause) {
            return true;
        }
        drop(writeln!(shell.err(), "\nCaused by:"));
        for line in cause.to_string().lines() {
            if line.is_empty() {
                drop(writeln!(shell.err(), ""));
            } else {
                drop(writeln!(shell.err(), "  {}", line));
            }
        }
    }
    false
}

pub fn version() -> VersionInfo {
    macro_rules! option_env_str {
        ($name:expr) => {
            option_env!($name).map(|s| s.to_string())
        };
    }

    // So this is pretty horrible...
    // There are two versions at play here:
    //   - version of cargo-the-binary, which you see when you type `cargo --version`
    //   - version of cargo-the-library, which you download from crates.io for use
    //     in your packages.
    //
    // We want to make the `binary` version the same as the corresponding Rust/rustc release.
    // At the same time, we want to keep the library version at `0.x`, because Cargo as
    // a library is (and probably will always be) unstable.
    //
    // Historically, Cargo used the same version number for both the binary and the library.
    // Specifically, rustc 1.x.z was paired with cargo 0.x+1.w.
    // We continue to use this scheme for the library, but transform it to 1.x.w for the purposes
    // of `cargo --version`.
    let major = 1;
    let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u8>().unwrap() - 1;
    let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u8>().unwrap();

    match option_env!("CFG_RELEASE_CHANNEL") {
        // We have environment variables set up from configure/make.
        Some(_) => {
            let commit_info = option_env!("CFG_COMMIT_HASH").map(|s| CommitInfo {
                commit_hash: s.to_string(),
                short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
                commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
            });
            VersionInfo {
                major,
                minor,
                patch,
                pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
                cfg_info: Some(CfgInfo {
                    release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
                    commit_info,
                }),
            }
        }
        // We are being compiled by Cargo itself.
        None => VersionInfo {
            major,
            minor,
            patch,
            pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
            cfg_info: None,
        },
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use std::fmt;
use std::rc::{Rc, Weak};
use entity::{Vec3f64, Entity};

struct Address {
    x: u64,
    y: u64,
    z: u64,
}

struct Element {
    name: String,
}

pub enum ChunkOption {
    Local(Rc<LocalChunk>),
    Remote(Rc<RemoteChunk>)
}

pub enum ChildOption {
    Local(Rc<LocalChunk>),
    Remote(Rc<RemoteChunk>),
    None
}

pub enum ParentOption {
    Local(Weak<LocalChunk>),
    Remote(Rc<RemoteChunk>),
    None
}

pub struct LocalChunk {
    address: Address,
    center: Vec3f64,
    //children: [ChildOption; 8],
    //FIXME: remove these and uncomment above
    child0: ChildOption,
    child1: ChildOption,
    child2: ChildOption,
    child3: ChildOption,
    child4: ChildOption,
    child5: ChildOption,
    child6: ChildOption,
    child7: ChildOption,
    //END FIXME
    child_number: Option<u8>,
    entities: Vec<Rc<Entity>>,
    mass: f64,
    parent: ParentOption,
    scale: u8,
    structure: u64,
    summary: Rc<Element>,
}

pub struct RemoteChunk {
    connection: i32,
}

impl Address {
    fn from_string(address: String) -> Option<Address> {
        let mut xyz: (u64, u64, u64) = (1, 1, 1);
        let mut xyz_add: (u64, u64, u64);

        for (i, c) in address.chars().enumerate() {
            if i > 63 {
                break;
            }
            xyz_add =  match c.to_digit(8) {
                Some(0) => (0, 0, 0),
                Some(1) => (0, 0, 1),
                Some(2) => (0, 1, 0),
                Some(3) => (0, 1, 1),
                Some(4) => (1, 0, 0),
                Some(5) => (1, 0, 1),
                Some(6) => (1, 1, 0),
                Some(7) => (1, 1, 1),
                _ => return None,
            };
            xyz = (xyz.0 << 1, xyz.1 << 1, xyz.2 << 1);
            xyz = (xyz.0 + xyz_add.0, xyz.1 + xyz_add.1, xyz.2 + xyz_add.2);
        }
        Some(Address {x: xyz.0, y: xyz.1, z: xyz.2})
    }
}

impl ToString for Address {
    fn to_string(&self) -> String {
        String::from_str("")
    }
}

impl PartialEq for Address {
    fn eq(&self, other: &Self) -> bool {
        (((self.x == other.x) && (self.y == other.y)) && (self.z == other.z))
    }
}

impl fmt::Show for Address {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Address({}, {}, {})", self.x, self.y, self.z)
    }
}

pub trait Chunk {
    fn get_child(&self, x: u8, y: u8, z: u8) -> ChildOption;
    fn tick(&self, time_delta: f64);
}

impl Chunk for LocalChunk {
    fn get_child(&self, x: u8, y: u8, z: u8) -> ChildOption {

        /* FIXME: remove
        let index = match (x, y, z) {
            (0, 0, 0) => Some(0),
            (0, 0, 1) => Some(1),
            (0, 1, 0) => Some(2),
            (0, 1, 1) => Some(3),
            (1, 0, 0) => Some(4),
            (1, 0, 1) => Some(5),
            (1, 1, 0) => Some(6),
            (1, 1, 1) => Some(7),
            _ => None,
        };

        if index == None {
            return ChildOption::None
        }

        match self.children[index] {
            ChildOption::Local(ref chunk) => ChildOption::Local(*chunk),
            ChildOption::Remote(ref chunk) => ChildOption::Remote(*chunk),
            ChildOption::None => ChildOption::None
        }*/
        //SLOP
        let child = match (x, y, z) {
            (0, 0, 0) => Some(self.child0),
            (0, 0, 1) => Some(self.child1),
            (0, 1, 0) => Some(self.child2),
            (0, 1, 1) => Some(self.child3),
            (1, 0, 0) => Some(self.child4),
            (1, 0, 1) => Some(self.child5),
            (1, 1, 0) => Some(self.child6),
            (1, 1, 1) => Some(self.child7),
            _ => None,
        };
        match child {
            Some(ChildOption::Local(ref chunk)) => ChildOption::Local(*chunk),
            Some(ChildOption::Remote(ref chunk)) => ChildOption::Remote(*chunk),
            _ => ChildOption::None
        }
        //ENDSLOP
    }

    fn tick(&self, time_delta: f64) {
    }
}

impl Chunk for RemoteChunk {
    fn get_child(&self, x: u8, y: u8, z: u8) -> ChildOption {
        ChildOption::None
    }
    fn tick (&self, time_delta: f64) {
    }
}

#[test]
fn test_address_from_string() {
    let known = Option::Some(Address {x: 0b11, y: 0b11, z: 0b11});
    let unknown = Address::from_string(String::from_str("7"));
    assert_eq!(known, unknown)
}
<commit_msg>Flailing wildly at the CI server<commit_after>#![allow(dead_code)]
use std::fmt;
use std::rc::{Rc, Weak};
use entity::{Vec3f64, Entity};

struct Address {
    x: u64,
    y: u64,
    z: u64,
}

struct Element {
    name: String,
}

pub enum ChunkOption {
    Local(Rc<LocalChunk>),
    Remote(Rc<RemoteChunk>)
}

pub enum ChildOption {
    Local(Rc<LocalChunk>),
    Remote(Rc<RemoteChunk>),
    None
}

pub enum ParentOption {
    Local(Weak<LocalChunk>),
    Remote(Rc<RemoteChunk>),
    None
}

pub struct LocalChunk {
    address: Address,
    center: Vec3f64,
    //children: [ChildOption; 8],
    //FIXME: remove these and uncomment above
    child0: ChildOption,
    child1: ChildOption,
    child2: ChildOption,
    child3: ChildOption,
    child4: ChildOption,
    child5: ChildOption,
    child6: ChildOption,
    child7: ChildOption,
    //END FIXME
    child_number: Option<u8>,
    entities: Vec<Rc<Entity>>,
    mass: f64,
    parent: ParentOption,
    scale: u8,
    structure: u64,
    summary: Rc<Element>,
}

pub struct RemoteChunk {
    connection: i32,
}

impl Address {
    fn from_string(address: String) -> Option<Address> {
        let mut xyz: (u64, u64, u64) = (1, 1, 1);
        let mut xyz_add: (u64, u64, u64);

        for (i, c) in address.chars().enumerate() {
            if i > 63 {
                break;
            }
            xyz_add =  match c.to_digit(8) {
                Some(0) => (0, 0, 0),
                Some(1) => (0, 0, 1),
                Some(2) => (0, 1, 0),
                Some(3) => (0, 1, 1),
                Some(4) => (1, 0, 0),
                Some(5) => (1, 0, 1),
                Some(6) => (1, 1, 0),
                Some(7) => (1, 1, 1),
                _ => return None,
            };
            xyz = (xyz.0 << 1, xyz.1 << 1, xyz.2 << 1);
            xyz = (xyz.0 + xyz_add.0, xyz.1 + xyz_add.1, xyz.2 + xyz_add.2);
        }
        Some(Address {x: xyz.0, y: xyz.1, z: xyz.2})
    }
}

impl ToString for Address {
    fn to_string(&self) -> String {
        String::from_str("")
    }
}

impl PartialEq for Address {
    fn eq(&self, other: &Self) -> bool {
        (((self.x == other.x) && (self.y == other.y)) && (self.z == other.z))
    }
}

impl fmt::Show for Address {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Address({}, {}, {})", self.x, self.y, self.z)
    }
}

pub trait Chunk {
    fn get_child(&self, x: u8, y: u8, z: u8) -> ChildOption;
    fn tick(&self, time_delta: f64);
}

impl Chunk for LocalChunk {
    fn get_child(&self, x: u8, y: u8, z: u8) -> ChildOption {

        /* FIXME: remove
        let index = match (x, y, z) {
            (0, 0, 0) => Some(0),
            (0, 0, 1) => Some(1),
            (0, 1, 0) => Some(2),
            (0, 1, 1) => Some(3),
            (1, 0, 0) => Some(4),
            (1, 0, 1) => Some(5),
            (1, 1, 0) => Some(6),
            (1, 1, 1) => Some(7),
            _ => None,
        };

        if index == None {
            return ChildOption::None
        }

        match self.children[index] {
            ChildOption::Local(ref chunk) => ChildOption::Local(*chunk),
            ChildOption::Remote(ref chunk) => ChildOption::Remote(*chunk),
            ChildOption::None => ChildOption::None
        }*/
        //SLOP
        let child = match (x, y, z) {
            (0, 0, 0) => Some(ref self.child0),
            (0, 0, 1) => Some(ref self.child1),
            (0, 1, 0) => Some(ref self.child2),
            (0, 1, 1) => Some(ref self.child3),
            (1, 0, 0) => Some(ref self.child4),
            (1, 0, 1) => Some(ref self.child5),
            (1, 1, 0) => Some(ref self.child6),
            (1, 1, 1) => Some(ref self.child7),
            _ => None,
        };
        match child {
            Some(ChildOption::Local(ref chunk)) => ChildOption::Local(*chunk),
            Some(ChildOption::Remote(ref chunk)) => ChildOption::Remote(*chunk),
            _ => ChildOption::None
        }
        //ENDSLOP
    }

    fn tick(&self, time_delta: f64) {
    }
}

impl Chunk for RemoteChunk {
    fn get_child(&self, x: u8, y: u8, z: u8) -> ChildOption {
        ChildOption::None
    }
    fn tick (&self, time_delta: f64) {
    }
}

#[test]
fn test_address_from_string() {
    let known = Option::Some(Address {x: 0b11, y: 0b11, z: 0b11});
    let unknown = Address::from_string(String::from_str("7"));
    assert_eq!(known, unknown)
}
<|endoftext|>


<commit_before>extern crate libc;

use std::env;

use ArgMatches;
use Arg;
use args::OptArg;
use args::FlagArg;
use args::PosArg;

pub struct App {
	pub name: &'static str,
	pub author: Option<&'static str>,
	pub version: Option<&'static str>,
	pub about: Option<&'static str>,
	// raw_args: Vec<Arg>,
	flags: Vec<FlagArg>,
	opts: Vec<OptArg>,
	positionals: Vec<PosArg>,
	needs_long_help: bool,
	needs_long_version: bool,
	needs_short_help: bool,
	needs_short_version: bool
}

impl App {
	pub fn new(n: &'static str) -> App {
		App {
			name: n,
			author: None,
			about: None,
			version: None,
			// raw_args: vec![],
			flags: vec![],
			opts: vec![],
			needs_long_version: true,
			needs_long_help: true,
			positionals: vec![],
			needs_short_help: true,
			needs_short_version: true
		}
	}

	pub fn author(&mut self, a: &'static str) -> &mut App {
		self.author = Some(a);
		self
	}

	pub fn about(&mut self, a: &'static str) -> &mut App {
		self.about = Some(a);
		self
	}

	pub fn version(&mut self, v: &'static str)-> &mut App  {
		self.version = Some(v);
		self
	}

	pub fn arg(&mut self, a: &Arg) -> &mut App {
		if let Some(i) = a.index {
			self.positionals.push(PosArg {
				name: a.name,
				index: i,
				required: a.required,
				help: a.help,
				value: None

			});
		} else if a.takes_value {
			self.opts.push(OptArg {
				name: a.name,
				short: a.short,
				long: a.long,
				help: a.help,
				required: a.required,
				value: None
			});
		} else {
			if let Some(l) = a.long {
				if l == "help" {
					self.needs_long_help = false;
				} else if l == "version" {
					self.needs_long_version = false;
				}
			}
			if let Some(s) = a.short {
				if s == 'h' {
					self.needs_short_help = false;
				} else if s == 'v' {
					self.needs_short_version = false;
				}
			}
			self.flags.push(FlagArg{
				name: a.name,
				short: a.short,
				long: a.long,
				help: a.help,
				multiple: a.multiple,
				occurrences: 1
			});
		}
		self
	}

	fn print_help(&self) {
		println!("Help info!");
		unsafe { libc::exit(0); }
	}

	fn print_version(&self) {
		let ver = match self.version {
			Some(v) => v,
			None => ""
		};
		println!("{} {}", self.name, ver);
		unsafe { libc::exit(0); }
	}

	fn validate_short_flag(&self, matches: &mut ArgMatches, arg: char) -> bool {
		let mut found = false;
		for f in self.flags.iter() {
			if let Some(s) = f.short {
				if s == arg {
					found = true;
					let mut mult = false;
					for ff in matches.flags.iter_mut() {
						if ff.name == f.name {
							// already in matches
							ff.occurrences = if ff.multiple { ff.occurrences + 1 } else { 1 };
							mult = true;
							break;
						}
					}
					if ! mult {
						matches.flags.push(f.clone())
					}
				}
				break;
			}
		}
		found
	}

	fn parse_long_arg(&self, matches: &mut ArgMatches, arg: &str) -> &'static str {
		let mut p_arg = arg.trim_left_matches(|c| c == '-');
		let mut found = false;
		let mut needs_val = false;

		if p_arg == "help" && self.needs_long_help {
			self.print_help();
		} else if p_arg == "version" && self.needs_long_version {
			self.print_version();
		}
		for f in self.flags.iter() {
			if let Some(l) = f.long {
				if l == p_arg {
					found = true;
					let mut mult = false;
					for ff in matches.flags.iter_mut() {
						if ff.name == f.name {
							// already in matches
							ff.occurrences = if ff.multiple { ff.occurrences + 1 } else { 1 };
							mult = true;
						}
					}
					if ! mult {
						matches.flags.push(f.clone())
					}
					return "";
				}
			}
		}
		if p_arg.contains("=") {
			let p_argv: Vec<&str> = p_arg.split_str("=").collect();
			p_arg = p_argv[0];
			for o in self.opts.iter() {
				if let Some(l) = o.long {
					if l == p_arg {
						found = true;
						matches.opts.push(OptArg{
							name: o.name,
						    short: o.short,
						    long: o.long,
						    help: o.help,
						    required: o.required,
						    value: Some(p_argv[1].to_string())
						});
						break;
					}
				}
			}
		} else {
			for o in self.opts.iter() {
				if let Some(l) = o.long {
					if l == p_arg {
						return o.name;
					}
				}
			}
		}

		// Fails if argument supplied to binary isn't valid
		assert!(found == false);

		""
	}

	fn parse_short_arg(&self, matches: &mut ArgMatches, arg: &str) -> &'static str {
		let mut found = false;
		if arg.len() > 2 {
			// Multiple flags using short i.e. -bgHlS
			let p_arg = arg.trim_left_matches(|c| c == '-');
			for c in p_arg.chars() {
				if c == 'h' && self.needs_short_help {
					self.print_help();
				} else if c == 'v' && self.needs_short_version {
					self.print_version();
				}
				found = self.validate_short_flag(matches, c);
				// Fails if argument supplied to binary isn't valid
				assert!(found == false);
				return "";
			}
		} else {
			// Short flag or opt
			let p_arg = arg.char_at(1);
			if p_arg == 'h' && self.needs_short_help {
				self.print_help();
			} else if p_arg == 'v' && self.needs_short_version {
				self.print_version();
			}
			found = self.validate_short_flag(matches, p_arg);
			if ! found {
				for o in self.opts.iter() {
					if let Some(s) = o.short {
						if s == p_arg {
							return o.name;
						}
					}
				}
			}
		}
		// Fails if argument supplied to binary isn't valid
		assert!(found == false);

		""
	}

	pub fn get_matches(&mut self) -> ArgMatches {

		let mut matches = ArgMatches::new(self);

		// let mut needs_val = false;
		let mut needs_val_of = "".to_string();
		let mut pos_counter = 1;
		for arg in env::args().collect::<Vec<String>>().tail() {
			let arg_slice = arg.as_slice();
			if ! needs_val_of.is_empty() {
				for o in self.opts.iter() {
					if needs_val_of == o.name.to_string() {
						matches.opts.push(OptArg{
							name: o.name,
						    short: o.short,
						    long: o.long,
						    help: o.help,
						    required: o.required,
						    value: Some(arg.clone())
						});
						needs_val_of.clear();
						break;
					}
				}
				continue;
			}
			if arg_slice.starts_with("--") {
				// Single flag, or option
				needs_val_of = self.parse_long_arg(&mut matches, arg_slice).to_string();

			} else if arg_slice.starts_with("-") {
				needs_val_of = self.parse_short_arg(&mut matches, arg_slice).to_string();
			} else {
				// Positional

				// Fails if no positionals are expected/possible
				assert!(self.positionals.is_empty() == false);

				for p in self.positionals.iter() {
					matches.positionals.push(PosArg{
						name: p.name,
						help: p.help,
						required: p.required,
						value: Some(arg.clone()),
						index: pos_counter
					});
					pos_counter += 1;
				}
			}

		}

		// Fails if we reached the end of args() but were still
		// expecting a value, such as ./fake -c
		// where -c takes a value
		assert!(needs_val_of.is_empty());

		matches
	}
}<commit_msg>v0.0.4.5<commit_after>extern crate libc;

use std::env;

use ArgMatches;
use Arg;
use args::OptArg;
use args::FlagArg;
use args::PosArg;

pub struct App {
	pub name: &'static str,
	pub author: Option<&'static str>,
	pub version: Option<&'static str>,
	pub about: Option<&'static str>,
	// raw_args: Vec<Arg>,
	flags: Vec<FlagArg>,
	opts: Vec<OptArg>,
	positionals: Vec<PosArg>,
	needs_long_help: bool,
	needs_long_version: bool,
	needs_short_help: bool,
	needs_short_version: bool
}

impl App {
	pub fn new(n: &'static str) -> App {
		App {
			name: n,
			author: None,
			about: None,
			version: None,
			// raw_args: vec![],
			flags: vec![],
			opts: vec![],
			needs_long_version: true,
			needs_long_help: true,
			positionals: vec![],
			needs_short_help: true,
			needs_short_version: true
		}
	}

	pub fn author(&mut self, a: &'static str) -> &mut App {
		self.author = Some(a);
		self
	}

	pub fn about(&mut self, a: &'static str) -> &mut App {
		self.about = Some(a);
		self
	}

	pub fn version(&mut self, v: &'static str)-> &mut App  {
		self.version = Some(v);
		self
	}

	pub fn arg(&mut self, a: &Arg) -> &mut App {
		if let Some(i) = a.index {
			self.positionals.push(PosArg {
				name: a.name,
				index: i,
				required: a.required,
				help: a.help,
				value: None

			});
		} else if a.takes_value {
			self.opts.push(OptArg {
				name: a.name,
				short: a.short,
				long: a.long,
				help: a.help,
				required: a.required,
				value: None
			});
		} else {
			if let Some(l) = a.long {
				if l == "help" {
					self.needs_long_help = false;
				} else if l == "version" {
					self.needs_long_version = false;
				}
			}
			if let Some(s) = a.short {
				if s == 'h' {
					self.needs_short_help = false;
				} else if s == 'v' {
					self.needs_short_version = false;
				}
			}
			self.flags.push(FlagArg{
				name: a.name,
				short: a.short,
				long: a.long,
				help: a.help,
				multiple: a.multiple,
				occurrences: 1
			});
		}
		self
	}

	fn print_help(&self) {
		println!("Help info!");
		unsafe { libc::exit(0); }
	}

	fn print_version(&self) {
		let ver = match self.version {
			Some(v) => v,
			None => ""
		};
		println!("{} {}", self.name, ver);
		unsafe { libc::exit(0); }
	}

	fn validate_short_flag(&self, matches: &mut ArgMatches, arg: char) -> bool {
		let mut found = false;
		for f in self.flags.iter() {
			if let Some(s) = f.short {
				if s == arg {
					found = true;
					let mut mult = false;
					for ff in matches.flags.iter_mut() {
						if ff.name == f.name {
							// already in matches
							ff.occurrences = if ff.multiple { ff.occurrences + 1 } else { 1 };
							mult = true;
							break;
						}
					}
					if ! mult {
						matches.flags.push(f.clone())
					}
				}
				break;
			}
		}
		found
	}

	fn parse_long_arg(&self, matches: &mut ArgMatches, arg: &str) -> &'static str {
		let mut p_arg = arg.trim_left_matches(|c| c == '-');
		let mut found = false;
		let mut needs_val = false;

		if p_arg == "help" && self.needs_long_help {
			self.print_help();
		} else if p_arg == "version" && self.needs_long_version {
			self.print_version();
		}
		for f in self.flags.iter() {
			if let Some(l) = f.long {
				if l == p_arg {
					found = true;
					let mut mult = false;
					for ff in matches.flags.iter_mut() {
						if ff.name == f.name {
							// already in matches
							ff.occurrences = if ff.multiple { ff.occurrences + 1 } else { 1 };
							mult = true;
						}
					}
					if ! mult {
						matches.flags.push(f.clone())
					}
					return "";
				}
			}
		}
		if p_arg.contains("=") {
			let p_argv: Vec<&str> = p_arg.split_str("=").collect();
			p_arg = p_argv[0];
			for o in self.opts.iter() {
				if let Some(l) = o.long {
					if l == p_arg {
						found = true;
						matches.opts.push(OptArg{
							name: o.name,
						    short: o.short,
						    long: o.long,
						    help: o.help,
						    required: o.required,
						    value: Some(p_argv[1].to_string())
						});
						break;
					}
				}
			}
		} else {
			for o in self.opts.iter() {
				if let Some(l) = o.long {
					if l == p_arg {
						return o.name;
					}
				}
			}
		}

		// Fails if argument supplied to binary isn't valid
		assert!(found == false);

		""
	}

	fn parse_short_arg(&self, matches: &mut ArgMatches, arg: &str) -> &'static str {
		let mut found = false;
		if arg.len() > 2 {
			// Multiple flags using short i.e. -bgHlS
			let p_arg = arg.trim_left_matches(|c| c == '-');
			for c in p_arg.chars() {
				if c == 'h' && self.needs_short_help {
					self.print_help();
				} else if c == 'v' && self.needs_short_version {
					self.print_version();
				}
				found = self.validate_short_flag(matches, c);
				// Fails if argument supplied to binary isn't valid
				assert!(found == false);
				return "";
			}
		} else {
			// Short flag or opt
			let p_arg = arg.char_at(1);
			if p_arg == 'h' && self.needs_short_help {
				self.print_help();
			} else if p_arg == 'v' && self.needs_short_version {
				self.print_version();
			}
			found = self.validate_short_flag(matches, p_arg);
			if ! found {
				for o in self.opts.iter() {
					if let Some(s) = o.short {
						if s == p_arg {
							return o.name;
						}
					}
				}
			}
		}
		// Fails if argument supplied to binary isn't valid
		assert!(found == true);

		""
	}

	pub fn get_matches(&mut self) -> ArgMatches {

		let mut matches = ArgMatches::new(self);

		// let mut needs_val = false;
		let mut needs_val_of = "".to_string();
		let mut pos_counter = 1;
		for arg in env::args().collect::<Vec<String>>().tail() {
			let arg_slice = arg.as_slice();
			if ! needs_val_of.is_empty() {
				for o in self.opts.iter() {
					if needs_val_of == o.name.to_string() {
						matches.opts.push(OptArg{
							name: o.name,
						    short: o.short,
						    long: o.long,
						    help: o.help,
						    required: o.required,
						    value: Some(arg.clone())
						});
						needs_val_of.clear();
						break;
					}
				}
				continue;
			}
			if arg_slice.starts_with("--") {
				// Single flag, or option
				needs_val_of = self.parse_long_arg(&mut matches, arg_slice).to_string();

			} else if arg_slice.starts_with("-") {
				needs_val_of = self.parse_short_arg(&mut matches, arg_slice).to_string();
			} else {
				// Positional

				// Fails if no positionals are expected/possible
				assert!(self.positionals.is_empty() == false);

				for p in self.positionals.iter() {
					matches.positionals.push(PosArg{
						name: p.name,
						help: p.help,
						required: p.required,
						value: Some(arg.clone()),
						index: pos_counter
					});
					pos_counter += 1;
				}
			}

		}

		// Fails if we reached the end of args() but were still
		// expecting a value, such as ./fake -c
		// where -c takes a value
		assert!(needs_val_of.is_empty());

		matches
	}
}<|endoftext|>