<commit_before>/* Stones esoteric programming language
 * (c) 2016 Zack Hixon - see LICENSE.txt */

static VERSION: &'static str = "0.3.0";

extern crate argparse;
extern crate stones;

use stones::*;

use argparse::{ArgumentParser, StoreTrue, Store, Print};

use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::error::Error;

fn main() {
    // arguments
    let mut debug = false;
    let mut show_field = false;
    let mut show_stack = false;
    let mut show_frames = false;
    let mut create_print = false;
    let mut filename: String = "".into();

    {
        let mut args = ArgumentParser::new();
        args.set_description("Run a stones language file");
        args.refer(&mut debug)
            .add_option(&["-d", "--debug"], StoreTrue, "Run debugging");
        args.refer(&mut show_field)
            .add_option(&["-f", "--field"], StoreTrue, "Show field");
        args.refer(&mut show_frames)
            .add_option(&["-r", "--frames"], StoreTrue, "Show frames");
        args.refer(&mut show_stack)
            .add_option(&["-s", "--stack"], StoreTrue, "Show stack");
        args.refer(&mut create_print)
            .add_option(&["-p", "--print"], StoreTrue, "Create print");
        args.refer(&mut filename)
            .add_argument("file", Store, "File to run/output to")
            .required();
        args.add_option(&["-V", "--version"],
                        Print("stones version ".to_string() + VERSION), "Show version");
        args.parse_args_or_exit();
    }

    if create_print {
        //do_print(filename);
        std::process::exit(0);
    }

    // open file
    let path = Path::new(&filename);
    let display = path.display();
    //{{
    let mut file = match File::open(&path) {
        Ok(file) => file,
        Err(_) => {
                println!("File doesn't exist: {}", display);
                std::process::exit(1);
            }
    };

    let mut s = String::new();
    match file.read_to_string(&mut s) {
        Ok(_) => {},
        Err(e) => panic!("Couldn't read {}: {}", display, e.description()),
    }

    // split file into tokens
    let tlist: Vec<&str> = s.split_whitespace().collect();

    let tokens = lex(tlist);
    let stmts = parse(tokens);

    for stmt in stmts {
        println!("{:?}", stmt);
    }
}
    /*

    // parse tokens into tokens... yes
    let mut tokens_nop: Vec<Token> = vec![];
    for token in &tlist {
        tokens_nop.push(match *token {
            "red" => Token::Red,
            "orange" => Token::Orange,
            "yellow" => Token::Yellow,
            "green" => Token::Green,
            "blue" => Token::Blue,
            "purple" => Token::Purple,
            "up" => Token::Up,
            "down" => Token::Down,
            "left" => Token::Left,
            "right" => Token::Right,
            "1" => Token::One,
            "2" => Token::Two,
            "3" => Token::Three,
            _ => Token::Nop
        });
    }

    let mut tokens: Vec<Token> = tokens_nop.into_iter().filter(|t| *t != Token::Nop).collect::<Vec<Token>>();

    // field vector, represents stone field
    let mut field: Vec<Vec<Color>> = // so much for 80 columns
        vec![vec![Color::Blue,  Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Orange,Color::Invis, Color::Invis, Color::Invis, Color::Invis ],
             vec![Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis ],
             vec![Color::Invis, Color::Invis, Color::Red,   Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Green, Color::Invis, Color::Invis ],
             vec![Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis ],
             vec![Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Yellow,Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Purple],
             vec![Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis, Color::Invis ]];

    // stack vector, pretty ezpz
    let mut stack: Vec<i64> = vec![];

    // store scopes/whether or not to execute
    let mut frame: Vec<bool> = vec![true];
    let mut current_frame = 0;

    // execute program
    let mut count = 0; // track token counter
    let mut current_stone = Color::Invis; // keep track of current stone
    let mut current_direction = Direction::None; // track direction
    let mut current_number = Number::None; // used for red movement

    // loop through tokens
    while count < tokens.len() {
        if show_field {
            for row in &field {
                for color in row {
                    match *color {
                        Color::Red => print!("{:?}... ", color),
                        Color::Orange => print!("{:?} ", color),
                        Color::Yellow => print!("{:?} ", color),
                        Color::Green => print!("{:?}. ", color),
                        Color::Blue => print!("{:?}.. ", color),
                        Color::Purple => print!("{:?} ", color),
                        Color::Invis => print!("...... "), // oh.
                    }
                }
                println!("");
            }
            println!("");
        }

        match tokens[count] {
            // colors
            Token::Red => {
                current_stone = Color::Red;
                current_direction = Direction::None;
                current_number = Number::None;
                if count != 0 && is_color(tokens[count - 1]) {
                    println!("Unexpected color!");
                }
                if count != tokens.len() - 2 &&
                   tokens[count + 2] != Token::One &&
                   tokens[count + 2] != Token::Two &&
                   tokens[count + 2] != Token::Three {
                    println!("Expected number!");
                }
            },
            Token::Orange => {
                current_stone = Color::Orange;
                current_direction = Direction::None;
                current_number = Number::None;
                if count != 0 && is_color(tokens[count - 1]) {
                    println!("Unexpected color!");
                }
                if count != tokens.len() - 2 &&
                   tokens[count + 2] != Token::One &&
                   tokens[count + 2] != Token::Two {
                        println!("Expected number!");
                }
            },
            Token::Yellow => {
                current_stone = Color::Yellow;
                current_direction = Direction::None;
                current_number = Number::None;
                if count != 0 && is_color(tokens[count - 1]) {
                    println!("Unexpected color!");
                }
            },
            Token::Green => {
                current_stone = Color::Green;
                current_direction = Direction::None;
                current_number = Number::None;
                if count != 0 && is_color(tokens[count - 1]) {
                    println!("Unexpected color!");
                }
            },
            Token::Blue => {
                current_stone = Color::Blue;
                current_direction = Direction::None;
                current_number = Number::None;
                if count != 0 && is_color(tokens[count - 1]) {
                    println!("Unexpected color!");
                }
            },
            Token::Purple => {
                current_stone = Color::Purple;
                current_direction = Direction::None;
                current_number = Number::None;
                if count != 0 && is_color(tokens[count - 1]) {
                    println!("Unexpected color!");
                }
            },

            // directions
            Token::Up => {
                current_direction = Direction::Up;
                // red stone is handled in number area
                if current_stone != Color::Red && current_stone != Color::Orange {
                    match current_stone {
                        Color::Yellow => { // multiply
                            // may use let = match later
                            if frame[current_frame] {
                                let tmp1 = stack.pop().expect("Stack is empty!");
                                let tmp2 = stack.pop().expect("Stack is empty!");
                                stack.push(tmp1 * tmp2);
                                // move stones
                                field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                            }
                        },
                        //Color::Green => { // roll },
                        Color::Blue => { // print as number
                            if frame[current_frame] {
                                print!("{}\n", stack.pop().expect("Stack is empty!"));
                                field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                            }
                        },
                        Color::Purple => { // if
                            if frame[current_frame] {
                                let tmp = stack.pop().expect("Stack is empty!");
                                if tmp == 1 {
                                    // condition is met, will execute
                                    current_frame += 1;
                                    frame.push(true);
                                } else {
                                    // condition not met, will not execute
                                    current_frame += 1;
                                    frame.push(false);
                                }
                                field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                            }
                        },
                        _ => {}
                    }
                    current_stone = Color::Invis;
                    current_direction = Direction::None;
                }
            },
            Token::Down => {
                current_direction = Direction::Down;
                if current_stone != Color::Red && current_stone != Color::Orange {
                    match current_stone {
                        Color::Yellow => { // add
                            if frame[current_frame] {
                                let tmp1 = stack.pop().expect("Stack is empty!");
                                let tmp2 = stack.pop().expect("Stack is empty!");
                                stack.push(tmp1 + tmp2);
                                field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                            }
                        },
                        Color::Green => { // dup
                            if frame[current_frame] {
                                let tmp = stack.pop().expect("Stack is empty!");
                                stack.push(tmp);
                                stack.push(tmp);
                            }
                        },
                        //Color::Blue => { // input },
                        Color::Purple => { // else
                            frame[current_frame] = !frame[current_frame];
                            field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                        },
                        _ => {}
                    }
                    current_stone = Color::Invis;
                    current_direction = Direction::None;
                }
            },
            Token::Left => {
                current_direction = Direction::Left;
                if current_stone != Color::Red && current_stone != Color::Orange {
                    match current_stone {
                        Color::Yellow => { // subtract
                            if frame[current_frame] {
                                let tmp1 = stack.pop().expect("Stack is empty!");
                                let tmp2 = stack.pop().expect("Stack is empty!");
                                stack.push(tmp1 - tmp2);
                                field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                            }
                        },
                        Color::Green => { // drop
                            stack.pop().expect("Stack is empty!");
                        },
                        Color::Blue => { // print as character
                            if frame[current_frame] {
                                print!("{}", stack.pop().expect("Stack is empty!") as u8 as char);
                                field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                            }
                        },
                        //Color::Purple => { // while },
                        _ => {}
                    }
                    current_stone = Color::Invis;
                    current_direction = Direction::None;
                }
            },
            Token::Right => {
                current_direction = Direction::Right;
                if current_stone != Color::Red && current_stone != Color::Orange {
                    match current_stone {
                        //Color::Orange => {},
                        Color::Yellow => { // divide
                            if frame[current_frame] {
                                let tmp1 = stack.pop().expect("Stack is empty!");
                                let tmp2 = stack.pop().expect("Stack is empty!");
                                stack.push(tmp1 / tmp2);
                                field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                            }
                        },
                        //Color::Green => {},
                        Color::Blue => { // quine :)
                            if tokens.len() == 2 {
                                print!("blue right");
                            } else {
                                // muahahaha
                                std::process::exit(0);
                            }
                        },
                        Color::Purple => { // end
                            if current_frame == 0 { panic!("Mismatching purple up/down/right"); }
                            frame.pop();
                            current_frame -= 1;
                        },
                        _ => {}
                    }
                    current_stone = Color::Invis;
                    current_direction = Direction::None;
                }
            },

            // numbers
            Token::One => {
                current_number = Number::One;
                if frame[current_frame] {
                    match current_stone {
                        Color::Red => {
                            match current_direction {
                                Direction::Up => stack.push(0),
                                Direction::Down => stack.push(1),
                                Direction::Left => stack.push(2),
                                Direction::Right => stack.push(3),
                                _ => panic!("Unexpected reserved word!"),
                            }
                            field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                        },
                        Color::Orange => { // array stuff
                            match current_direction {
                                _ => {}
                            }
                            field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                        },
                        _ => println!("That {:?} stone is too heavy!", &current_stone)
                    }
                }
            },
            Token::Two => {
                current_number = Number::Two;
                if frame[current_frame] {
                    match current_stone {
                        Color::Red => {
                            match current_direction {
                                Direction::Up => stack.push(4),
                                Direction::Down => stack.push(5),
                                Direction::Left => stack.push(6),
                                Direction::Right => stack.push(7),
                                _ => panic!("Unexpected reserved word!"),
                            }
                            field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                            field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                        },
                        Color::Orange => { // equality stuff
                            match current_direction {
                                Direction::Up => {
                                    let tmp1 = stack.pop();
                                    let tmp2 = stack.pop();
                                    if tmp1 == tmp2 {
                                        stack.push(1);
                                    } else {
                                        stack.push(0);
                                    }
                                },
                                Direction::Down => {
                                    let tmp1 = stack.pop();
                                    let tmp2 = stack.pop();
                                    if tmp1 < tmp2 {
                                        stack.push(1);
                                    } else {
                                        stack.push(0);
                                    }
                                },
                                Direction::Left => {
                                    let tmp1 = stack.pop();
                                    let tmp2 = stack.pop();
                                    if tmp1 > tmp2 {
                                        stack.push(1);
                                    } else {
                                        stack.push(0);
                                    }
                                },
                                _ => {}
                            }
                            field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                            field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                        },
                        _ => println!("That {:?} stone is too heavy!", &current_stone)
                    }
                }
            },
            Token::Three => {
                current_number = Number::Three;
                if frame[current_frame] {
                    match current_stone {
                        Color::Red => {
                            match current_direction {
                                Direction::Up => stack.push(8),
                                Direction::Down => stack.push(9),
                                Direction::Left => stack.push(1),
                                Direction::Right => stack.push(0),
                                _ => panic!("Unexpected reserved word!"),
                            }
                            field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                            field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                            field = move_stone(current_stone, current_direction, field, &mut tokens, count as usize);
                        },
                        _ => println!("That {:?} stone is too heavy!", &current_stone)
                    }
                }
            },
            _ => { }
        }

        if debug {
            println!("Token:     {:?}", tokens[count]);
            println!("Color:     {:?}", current_stone);
            println!("Direction: {:?}", current_direction);
            println!("Number:    {:?}", current_number);
            println!("Frame:     {}", current_frame);
            println!("Current:   {}", frame[current_frame]);
            println!("-----------");
        }

        if show_stack {
            println!("stack: {}", stack.len());
            for item in &stack {
                println!("{}", item);
            }
        }

        if show_frames {
            println!("frames: {}", frame.len());
            for item in &frame {
                println!("{}", item);
            }
        }

        count += 1;
    }
}

fn is_color(c: Token) -> bool {
    match c {
        Token::Red | Token::Orange | Token::Yellow | Token::Green | Token::Blue | Token::Purple => true,
        _ => false
    }
}

// I wasn't aware that there was a way to enumerate a Vec without moving it
// it's too late to change it right now, but I might consider fixing it later.
#[allow(unknown_lints)]
#[allow(needless_range_loop)]
fn move_stone(stone: Color, dir: Direction, _field: Vec<Vec<Color>>, tokens: &mut Vec<Token>, count: usize)
        -> Vec<Vec<Color>> {
    let mut field = _field; // FIXME: really not sure why
    let field_height = field.len() - 1;   // == 5
    let field_width = field[0].len() - 1; // == 10

    // go through vertical rows first
    'y: for y in 0..(field_height + 1) {
        // columns left to right
        for x in 0..(field_width + 1) {
            // find a match
            if field[y][x] == stone {
                match dir {
                    Direction::Up => {
                        // set color to invisible
                        field[y][x] = Color::Invis;
                        // protect overflow crashes
                        if y != 0 {
                            // check for stone in the way
                            if field[y - 1][x] != Color::Invis {
                                // move it up
                                tokens.insert(count, Token::from_stone(field[y - 1][x]));
                                tokens.insert(count + 1, Token::from_direction(dir));
                                tokens.insert(count + 2, Token::One);
                                field = move_stone(field[y - 1][x], dir, field, tokens, count);
                            }
                            // move stone up one
                            field[y - 1][x] = stone;
                        } else {
                            // check for stone in the way
                            if field[field_height][x] != Color::Invis {
                                tokens.insert(count, Token::from_stone(field[field_height][x]));
                                tokens.insert(count + 1, Token::from_direction(dir));
                                tokens.insert(count + 2, Token::One);
                                field = move_stone(field[field_height][x], dir, field, tokens, count);
                            }
                            // wrap around to bottom
                            field[field_height][x] = stone;
                        }
                        // break loop - put this at the end of every direction
                        break 'y;
                    },
                    Direction::Down => {
                        field[y][x] = Color::Invis;
                        if y != field_height {
                            if field[y + 1][x] != Color::Invis {
                                tokens.insert(count, Token::from_stone(field[y + 1][x]));
                                tokens.insert(count + 1, Token::from_direction(dir));
                                tokens.insert(count + 2, Token::One);
                                field = move_stone(field[y + 1][x], dir, field, tokens, count);
                            }
                            // move stone down one
                            field[y + 1][x] = stone;
                        } else {
                            if field[0][x] != Color::Invis {
                                tokens.insert(count, Token::from_stone(field[0][x]));
                                tokens.insert(count + 1, Token::from_direction(dir));
                                tokens.insert(count + 2, Token::One);
                                field = move_stone(field[0][x], dir, field, tokens, count);
                            }
                            // wrap to bottom
                            field[0][x] = stone;
                        }
                        break 'y;
                    },
                    Direction::Left => {
                        field[y][x] = Color::Invis;
                        if x != 0 {
                            if field[y][x - 1] != Color::Invis {
                                tokens.insert(count, Token::from_stone(field[y][x - 1]));
                                tokens.insert(count + 1, Token::from_direction(dir));
                                tokens.insert(count + 2, Token::One);
                                field = move_stone(field[y][x - 1], dir, field, tokens, count);
                            }
                            field[y][x - 1] = stone;
                        } else {
                            if field[y][field_width] != Color::Invis {
                                tokens.insert(count, Token::from_stone(field[y][field_width]));
                                tokens.insert(count + 1, Token::from_direction(dir));
                                tokens.insert(count + 2, Token::One);
                                field = move_stone(field[y][field_width], dir, field, tokens, count);
                            }
                            field[y][field_width] = stone;
                        }
                        break 'y;
                    },
                    Direction::Right => {
                        field[y][x] = Color::Invis;
                        if x != field_width {
                            if field[y][x + 1] != Color::Invis {
                                tokens.insert(count, Token::from_stone(field[y][x + 1]));
                                tokens.insert(count + 1, Token::from_direction(dir));
                                tokens.insert(count + 2, Token::One);
                                field = move_stone(field[y][x + 1], dir, field, tokens, count);
                            }
                            field[y][x + 1] = stone;
                        } else {
                            if field[y][0] != Color::Invis {
                                tokens.insert(count, Token::from_stone(field[y][0]));
                                tokens.insert(count + 1, Token::from_direction(dir));
                                tokens.insert(count + 2, Token::One);
                                field = move_stone(field[y][0], dir, field, tokens, count);
                            }
                            field[y][0] = stone;
                        }
                        break 'y;
                    },
                    _ => {
                        //println!("can't move {:?} {:?} yet", stone, dir);
                        break 'y;
                    }
                }
            }
        }
    }

    field
}

// read from a file, convert text to stones commands
#[allow(unknown_lints)]
#[allow(match_same_arms)]
fn do_print(filename: String) { // {{{1
    let path = Path::new(&filename);
    let display = path.display();

    let mut file = match File::open(&path) {
        Ok(file) => file,
        Err(_) => {
            println!("File doesn't exist: {}", display);
            std::process::exit(1);
        }
    };

    let mut contents = String::new();
    match file.read_to_string(&mut contents) {
        Ok(_) => {},
        Err(e) => panic!("Couldn't read {}: {}", display, e.description()),
    }

    let chars = contents.chars();

    let mut output = String::new();

    for c in chars {
        output.push_str(
            match c {
                '\t' => "red down 3\nblue left\n\n",
                '\n' => "red down 2\nred down 2\nyellow down\nblue left\n\n",
                '\r' => "red down 3\nred up 2\nyellow down\nblue left\n\n",
                ' ' => "red up 2\nred up 2\nred left 1\nyellow up\nyellow up\nblue left\n\n",
                '!' => "red right 1\nred left 1\nred down 3\nyellow down\nyellow up\nblue left\n\n",
                '\"' => "red down 2\nred down 2\nred right 2\nyellow down\nyellow down \nred left 1\nyellow up\nred right 1\nyellow down\nblue left\n\n",
                '#' => "red right 2\nred down 2\nyellow up\nblue left\n\n",
                '$' => "red left 2\nred left 2\nyellow up\nblue left\n\n",
                '%' => "red down 2\nred down 2\nyellow down\nred right 1\nyellow up\nred right 2\nyellow down\nblue left\n\n",
                '&' => "red down 3\nred up 3\nyellow down\nred left 1\nyellow down\nred left 1\nyellow up\nblue left\n\n",
                '\'' => "red up 2\nred down 3\nyellow down\nred right 1\nyellow up\nblue left\n\n",
                '(' => "red down 2\nred down 2\nyellow down\nred up 2\nyellow up\nblue left\n\n",
                ')' => "red down 2\nred down 2\nyellow down\nred up 2\nyellow up\nred down 1\nyellow down\nblue left\n\n",
                '*' => "red left 2\nred right 2\nyellow up\nblue left\n\n",
                '+' => "red left 2\nred right 2\nyellow up\nred down 1\nyellow down\nblue left\n\n",
                ',' => "red left 1\nred down 3\nyellow down\nred up 2\nyellow up\nblue left\n\n",
                '-' => "red down 3\nred down 2\nyellow up\nblue left\n\n",
                '.' => "red down 3\nred down 2\nyellow up\nred down 1\nyellow down\nblue left\n\n",
                '/' => "red down 3\nred down 2\nyellow up\nred left 1\nyellow down\nblue left\n\n",
                '0' => "red left 2\nred up 3\nyellow up\nblue left\n\n",
                '1' => "red left 2\nred up 3\nyellow up\nred down 1\nyellow down\nblue left\n\n",
                '2' => "red down 2\nred left 1\nred down 2\nyellow up\nyellow up\nblue left\n\n",
                '3' => "\n", // yeah, this is awful
                '4' => "\n",
                '5' => "\n",
                '6' => "\n",
                '7' => "\n",
                '8' => "\n",
                '9' => "\n",
                ':' => "\n",
                ';' => "\n",
                '<' => "\n",
                '=' => "\n",
                '>' => "\n",
                '?' => "\n",
                '@' => "\n",
                'A' => "\n",
                'B' => "\n",
                'C' => "\n",
                'D' => "\n",
                'E' => "\n",
                'F' => "\n",
                'G' => "\n",
                'H' => "\n",
                'I' => "\n",
                'J' => "\n",
                'K' => "\n",
                'L' => "\n",
                'M' => "\n",
                'N' => "\n",
                'O' => "\n",
                'P' => "\n",
                'Q' => "\n",
                'R' => "\n",
                'S' => "\n",
                'T' => "\n",
                'U' => "\n",
                'V' => "\n",
                'W' => "\n",
                'X' => "\n",
                'Y' => "\n",
                'Z' => "\n",
                '[' => "\n",
                '\\' => "\n",
                ']' => "\n",
                '^' => "\n",
                '_' => "\n",
                '`' => "\n",
                'a' => "\n",
                'b' => "\n",
                'c' => "\n",
                'd' => "\n",
                'e' => "\n",
                'f' => "\n",
                'g' => "\n",
                'h' => "\n",
                'i' => "\n",
                'j' => "\n",
                'k' => "\n",
                'l' => "\n",
                'm' => "\n",
                'n' => "\n",
                'o' => "\n",
                'p' => "\n",
                'q' => "\n",
                'r' => "\n",
                's' => "\n",
                't' => "\n",
                'u' => "\n",
                'v' => "\n",
                'w' => "\n",
                'x' => "\n",
                'y' => "\n",
                'z' => "\n",
                '{' => "\n",
                '|' => "\n",
                '}' => "\n",
                '~' => "\n",
                _ => "\n",
        });
    }

    println!("{}", output);
}
// }}}1
*/
<commit_msg>remove commented stuff [ci skip]<commit_after>/* Stones esoteric programming language
 * (c) 2016 Zack Hixon - see LICENSE.txt */

static VERSION: &'static str = "0.3.0";

extern crate argparse;
extern crate stones;

use stones::*;

use argparse::{ArgumentParser, StoreTrue, Store, Print};

use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::error::Error;

fn main() {
    // arguments
    let mut debug = false;
    let mut show_field = false;
    let mut show_stack = false;
    let mut show_frames = false;
    let mut create_print = false;
    let mut filename: String = "".into();

    {
        let mut args = ArgumentParser::new();
        args.set_description("Run a stones language file");
        args.refer(&mut debug)
            .add_option(&["-d", "--debug"], StoreTrue, "Run debugging");
        args.refer(&mut show_field)
            .add_option(&["-f", "--field"], StoreTrue, "Show field");
        args.refer(&mut show_frames)
            .add_option(&["-r", "--frames"], StoreTrue, "Show frames");
        args.refer(&mut show_stack)
            .add_option(&["-s", "--stack"], StoreTrue, "Show stack");
        args.refer(&mut create_print)
            .add_option(&["-p", "--print"], StoreTrue, "Create print");
        args.refer(&mut filename)
            .add_argument("file", Store, "File to run/output to")
            .required();
        args.add_option(&["-V", "--version"],
                        Print("stones version ".to_string() + VERSION), "Show version");
        args.parse_args_or_exit();
    }

    if create_print {
        //do_print(filename);
        std::process::exit(0);
    }

    // open file
    let path = Path::new(&filename);
    let display = path.display();
    let mut file = match File::open(&path) {
        Ok(file) => file,
        Err(_) => {
                println!("File doesn't exist: {}", display);
                std::process::exit(1);
            }
    };

    let mut s = String::new();
    match file.read_to_string(&mut s) {
        Ok(_) => {},
        Err(e) => panic!("Couldn't read {}: {}", display, e.description()),
    }

    // split file into tokens
    let tlist: Vec<&str> = s.split_whitespace().collect();

    let tokens = lex(tlist);
    let stmts = parse(tokens);

    for stmt in stmts {
        println!("{:?}", stmt);
    }
}
<|endoftext|>


<commit_before>
#[derive(Debug)]
struct Point2 {
    x:i32,
    y:i32,
}

#[derive(Debug)]
struct World {
    shutDown: bool,

    // entities
    things:Vec<usize>,

    // components
    positions:Vec<Point2>,

    // systems / events
    systems_to_run: Vec<SystemTypes>,
    next_cycle_systems: Vec<SystemTypes>,

    // resources
    delta_time: f32,
    // total_time: f32,
}

impl World {
    fn new() -> Self {
        World {
            shutDown: false,
            things: vec![0],
            positions: vec![Point2{x:0, y:0}],
            systems_to_run: Vec::new(),
            next_cycle_systems:Vec::new(),
            delta_time: 0.001,
        }
    }

    fn run_systems(&mut self, systems: &mut Systems) {
        println!("start run_systems");
        let tmp_systems: Vec<SystemTypes> = self.systems_to_run.drain(..).collect();
        for sys_type in tmp_systems {
            systems.test(self, sys_type)
        }

        self.systems_to_run = self.next_cycle_systems.drain(..).collect();
        self.next_cycle_systems = Vec::new();
        println!("end run_systems");
    }

    fn enqueue_system(&mut self, sys_type: SystemTypes) {
        self.next_cycle_systems.push(sys_type);
    }

    fn intial_systems(&mut self, sys_type: SystemTypes) {
        self.systems_to_run.push(sys_type);
    }
}

#[derive(Debug)]
enum SystemTypes {
    PlayerInputType,
    CloseAppType,
    WalkType,
}

struct Systems {
    player_input: PlayerInput,
    walk: Walk,
    close: CloseApp,
}
impl Systems {
    fn new() -> Self {
        Systems {
            player_input: PlayerInput{},
            walk: Walk{},
            close: CloseApp{},
        }
    }
    fn test(&mut self, world: &mut World, sys_type: SystemTypes) {
        println!("running test...");
        match sys_type {
            SystemTypes::PlayerInputType => self.player_input.process(world),
            SystemTypes::CloseAppType => self.close.process(world),
            SystemTypes::WalkType => self.walk.process(world),
        }
    }
}

trait System {
    fn process(&self, world: &mut World);
}

#[derive(Debug)]
struct PlayerInput;
impl System for PlayerInput {
    fn process(&self, world: &mut World) {
        let mut line = String::new();
        std::io::stdin().read_line(&mut line).expect("Failed to read line");
        let trimed = line.trim();
        println!("You entered: {} ---", trimed);

        // use std::io::Read;
        // let input: Option<i32> = std::io::stdin()
        //     .bytes()
        //     .next()
        //     .and_then(|result| result.ok())
        //     .map(|byte| byte as i32);
        // println!("Byte: {:?}", input);
        // world.enqueue_system(SystemTypes::PlayerInputType);

        match trimed.as_ref() {
            "qq"  => world.enqueue_system(SystemTypes::CloseAppType),
            "exit"=> world.enqueue_system(SystemTypes::CloseAppType),
            "2"|"4"|"6"|"8" => {
                println!("You pressed a direction");
                world.enqueue_system(SystemTypes::PlayerInputType);
            },
            _ => world.enqueue_system(SystemTypes::PlayerInputType),
        };

    }
}

#[derive(Debug)]
struct CloseApp;
impl System for CloseApp {
    fn process(&self, world: &mut World) {
        world.shutDown = true;
        println!("Shutting it down!");
    }
}

#[derive(Debug)]
struct Walk {
    ids: Vec<usize>,
};
impl System for Walk {
    fn process(&self, world: &mut World) {
        // this needs to know WHO is trying to walk
        println!("do walk...");
    }
}

fn main() {
    let mut w = World::new();
    let mut s = Systems::new();

    w.intial_systems(SystemTypes::PlayerInputType);

    while w.shutDown == false {
        println!("main loop");
        w.run_systems(&mut s);
    }
}

/*
    player update {
        input match
        move
        menu
            menus
            abilities
            inventory
            help
    }
*/

<commit_msg>getting things sync'd<commit_after>#[derive(Debug, PartialEq)]
enum Event {
    Render,
}

trait System {
    fn process(&self);
    fn listening(&self, event: &Event) -> bool;
}

#[derive(Debug)]
struct Renderer {
    who:i32,
    listens_to: Event,
}

impl Renderer {
    fn create() -> Self {
        Renderer {
            who: 0,
            listens_to: Event::Render,
        }
    }
}

impl System for Renderer {
    fn process(&self) {
        println!("Rendering {:?}!", self);
    }

    fn listening(&self, event: &Event) -> bool
    {
        self.listens_to == *event
    }
}

// find a way to pass in a RenderData, which is a datatype that has different properties
type SystemVec<'a> = Vec<Box<System + 'a>>;
struct World<'a> {
    systems: SystemVec<'a>,
    events: Vec<Event>,

    // components

}
impl<'a> World<'a> {
    fn new() -> Self {
        World {
            systems: Vec::new(),
            events: Vec::new(),
        }
    }

    fn add_event(&mut self, event: Event) {
        self.events.push(event);
    }

    fn add_system<S: System + 'a>(&mut self, system: S) {
        self.systems.push(Box::new(system));
    }

    fn run(&self) {
        for evt in &self.events {
            for sys in &self.systems {
                if sys.listening(evt) {
                    sys.process();
                }
            }
        }
    }

    fn clear(&mut self) {
        self.systems = Vec::new();
        self.events = Vec::new();
    }
}

fn main() {
    let mut w = World::new();

    w.add_event(Event::Render);

    w.add_system(Renderer::create());

    w.run();
    w.clear();
}
<|endoftext|>


<commit_before>fn main() {
    let home = std::env::var("HOME").unwrap();
    use std::os::unix::process::CommandExt;
    let err = std::process::Command::new("java")
        .args(&["-Xms512m", "-Xmx1536m", "-Xss2m"])
        .args(&["-jar", &format!("{}/.sbt/launchers/0.13.13/sbt-launch.jar", home)])
        .arg("shell")
        .exec();
    println!("error: {}", err);
    if let Some(err) = err.raw_os_error() {
        std::process::exit(err);
    }
    std::process::exit(-1)
}
<commit_msg>Favour Path over String for paths<commit_after>fn main() {
    let home = std::env::home_dir().unwrap();
    let sbt_jar;
    {
        let mut p = std::path::PathBuf::from(home);
        p.push(".sbt/launchers/0.13.13/sbt-launch.jar");
        sbt_jar = p;
    }
    use std::os::unix::process::CommandExt;
    let err = std::process::Command::new("java")
        .args(&["-Xms512m", "-Xmx1536m", "-Xss2m"])
        .args(&[&"-jar".as_ref(), &sbt_jar.as_os_str()])
        .arg("shell")
        .exec();
    println!("error: {}", err);
    if let Some(err) = err.raw_os_error() {
        std::process::exit(err);
    }
    std::process::exit(-1)
}
<|endoftext|>


<commit_before>#![feature(globs,macro_rules)]

use internal::IResult;
use internal::IResult::*;
use map::Mapper;
use producer::{Producer, FileProducer};
use producer::ProducerState::*;
use nom::print;

mod internal;
mod map;
mod producer;
mod nom;

fn main() {
  println!("Hello world!");

  fn pr<'a>(res: IResult<(),&'a[u8]>) -> IResult<&'a[u8], ()> {
    //par.m2(print)
    Error(0)
  }

  FileProducer::new("links.txt", 1024).map(|producer: FileProducer| {
    let mut p = producer;
    //p.push(|par| par.map(accline).mapf(|v2: &[u8]| str::from_utf8(v2.as_slice())).map(print));
    /*p.push(|res| {
      //let p2:IResult<&[u8],&str> = res.mapf(|v2: &[u8]| str::from_utf8(v2.as_slice()));
      Done((), ())
    });*/
    fn pr2(par: IResult<(),&[u8]>) -> IResult<&[u8],()> {
      par.flat_map(print)
    }
    pusher!(ps, pr);
    ps(&mut p);

    //p.push(|res| { res.flat_map(print) });
    //p.push(|par| {println!("par: {}", par); par});
    //p.push(pr);
    //p.push(|par| { par.map(tag!("https://".as_bytes())).map(print) });
  });

}
<commit_msg>remove main<commit_after><|endoftext|>


<commit_before>
extern crate mprovision;
extern crate clap;

use std::fs;
use clap::{Arg, App, SubCommand};

fn main() {
    let count_subcommand = SubCommand::with_name("count")
        .about("Counts provisioning profiles in a directory.")
        .arg(Arg::with_name("DIRECTORY")
            .short("d")
            .long("directory")
            .help("Directory where to count provisioning profiles.")
            .required(false)
            .takes_value(true));

    let matches = App::new("myapp")
        .version("0.1.0")
        .about("A tool that helps iOS developers to manage mobileprovision files.")
        .subcommand(count_subcommand)
        .get_matches();

    if let Some(matches) = matches.subcommand_matches("count") {
        handle_count_subcommand(matches)
    }
}

fn handle_count_subcommand(matches: &clap::ArgMatches) {

    fn show(result: mprovision::Result<Box<Iterator<Item=fs::DirEntry>>>) {
        match result {
            Ok(files) => println!("Found {} files.", files.count()),
            Err(err) => println!("Error: {}", err),
        }
    }

    if let Some(directory) = matches.value_of("DIRECTORY") {
        show(mprovision::files(directory));
    } else {
        match mprovision::directory() {
            Ok(directory) => show(mprovision::files(directory)),
            Err(err) => println!("Error: {}", err),
        }
    }
}
<commit_msg>Change name of the app.<commit_after>
extern crate mprovision;
extern crate clap;

use std::fs;
use clap::{Arg, App, SubCommand};

fn main() {
    let count_subcommand = SubCommand::with_name("count")
        .about("Counts provisioning profiles in a directory.")
        .arg(Arg::with_name("DIRECTORY")
            .short("d")
            .long("directory")
            .help("Directory where to count provisioning profiles.")
            .required(false)
            .takes_value(true));

    let matches = App::new("mprovision")
        .version("0.1.0")
        .about("A tool that helps iOS developers to manage mobileprovision files.")
        .subcommand(count_subcommand)
        .get_matches();

    if let Some(matches) = matches.subcommand_matches("count") {
        handle_count_subcommand(matches)
    }
}

fn handle_count_subcommand(matches: &clap::ArgMatches) {

    fn show(result: mprovision::Result<Box<Iterator<Item=fs::DirEntry>>>) {
        match result {
            Ok(files) => println!("Found {} files.", files.count()),
            Err(err) => println!("Error: {}", err),
        }
    }

    if let Some(directory) = matches.value_of("DIRECTORY") {
        show(mprovision::files(directory));
    } else {
        match mprovision::directory() {
            Ok(directory) => show(mprovision::files(directory)),
            Err(err) => println!("Error: {}", err),
        }
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![feature(question_mark)]
extern crate iron;
extern crate mount;
extern crate persistent;
extern crate router;
extern crate rustorm;
extern crate rustc_serialize;
extern crate rand;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate env_logger;
extern crate unicase;
extern crate uuid;
extern crate inquerest;
extern crate chrono;

use iron::status;
use router::Router;
use std::str::FromStr;
use std::env;
use iron::prelude::*;
use persistent::State;
use std::net::SocketAddrV4;
use std::net::Ipv4Addr;
use global::GlobalPools;
use iron::method::Method::*;
use iron::AfterMiddleware;
use unicase::UniCase;
use iron::headers;

mod global;
mod data_service;
mod from_query;
mod validator;
mod app_service;
mod window_service;
mod lookup_service;
mod error;
mod config;

fn say_hello(req: &mut Request) -> IronResult<Response> {
    println!("Running send_hello handler, URL path: {}",
             req.url.path.connect("/"));
    let mut response = Response::with((status::Ok, "This request was routed!"));
    Ok(response)
}

fn main() {
    //env_logger::init().unwrap();
    log4rs::init_file("config/log4rs.yaml", Default::default()).unwrap();
    info!("starting up");
    warn!("warning example...");
    const VERSION: &'static str = env!("CARGO_PKG_VERSION");
    println!("Curtain v{}", VERSION);

    let mut router = Router::new();
    router.get("/", say_hello);
    router.get("/window", window_service::window_http::http_list_window);
    router.get("/window/:table",
               window_service::window_http::http_get_window);
    router.get("/data/:table", data_service::data_http::http_data_query);
    router.get("/app/:main_table",
               app_service::app_http::http_complex_query);
    router.get("/app/focus/:main_table",
               app_service::app_http::http_focused_record);
    router.post("/app/:main_table", app_service::app_http::http_update_data);
    router.get("/lookup_data/:main_table",
               lookup_service::lookup_http::http_get_lookup_data);
    router.get("/lookup_tabs/:main_table",
               lookup_service::lookup_http::http_get_lookup_tabs);//get the lookup tabs for each lookup on this main_table
    router.delete("/cache", global::http_reset_cache);
    router.get("/connection", global::http_can_db_url_connect);

    let mut middleware = Chain::new(router);
    middleware.link(State::<GlobalPools>::both(GlobalPools::new()));
    middleware.link_after(CORS);
    let host = get_server_host();
    let listen = Iron::new(middleware).http(host);
    match listen{
        Ok(listen) => {
                println!("listensing on {:?}", listen)
            }
        Err(e) => {
                println!("Initialization error {}", e)
            }
    }

}

struct CORS;

impl AfterMiddleware for CORS {
    fn after(&self, req: &mut Request, mut res: Response) -> IronResult<Response> {
        let path = req.url.path.connect("/");
        warn!("warning has the request been served? {}", path);
        error!("an error has occured {}", path);
        trace!("tracing..{}",path);
        debug!("Debugging... {}",path);
        res.headers.set(headers::AccessControlAllowOrigin::Any);
        res.headers.set(headers::AccessControlAllowHeaders(vec![UniCase("accept".to_owned()),
                                                                UniCase("content-type"
                                                                    .to_owned()),
                                                                UniCase("db_url".to_owned()),
                                                                UniCase("*".to_owned())]));
        res.headers
            .set(headers::AccessControlAllowMethods(vec![Get, Head, Post, Delete, Options, Put,
                                                         Patch]));
        Ok(res)
    }
}

fn get_server_port() -> u16 {
    let port_str = env::var("PORT").unwrap_or(String::new());
    FromStr::from_str(&port_str).unwrap_or(3224)
}
#[cfg(feature = "webserver")]
fn get_server_host()-> SocketAddrV4 {
    SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), get_server_port())
}

/// when compiling for stand-alone, port will be decided by the OS, by sending arg 0
/// and the host will be 127.3.3.2 as opposed to common 127.0.0.1
#[cfg(feature = "standalone")]
fn get_server_host()-> SocketAddrV4 {
    SocketAddrV4::new(Ipv4Addr::new(127,0 ,0, 1), 0)
}

<commit_msg>no unwrap()<commit_after>#![feature(plugin)]
#![feature(question_mark)]
extern crate iron;
extern crate mount;
extern crate persistent;
extern crate router;
extern crate rustorm;
extern crate rustc_serialize;
extern crate rand;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate env_logger;
extern crate unicase;
extern crate uuid;
extern crate inquerest;
extern crate chrono;

use iron::status;
use router::Router;
use std::str::FromStr;
use std::env;
use iron::prelude::*;
use persistent::State;
use std::net::SocketAddrV4;
use std::net::Ipv4Addr;
use global::GlobalPools;
use iron::method::Method::*;
use iron::AfterMiddleware;
use unicase::UniCase;
use iron::headers;

mod global;
mod data_service;
mod from_query;
mod validator;
mod app_service;
mod window_service;
mod lookup_service;
mod error;
mod config;

fn say_hello(req: &mut Request) -> IronResult<Response> {
    println!("Running send_hello handler, URL path: {}",
             req.url.path.connect("/"));
    let mut response = Response::with((status::Ok, "This request was routed!"));
    Ok(response)
}

fn main() {
    //env_logger::init().unwrap();
    match log4rs::init_file("config/log4rs.yaml", Default::default()){
        Ok(_) => {println!("Loggin initiated..");}
        Err(e) => {println!("Something wrong in loggin.. {:?}", e);}
    }
    info!("starting up");
    warn!("warning example...");
    const VERSION: &'static str = env!("CARGO_PKG_VERSION");
    println!("Curtain v{}", VERSION);

    let mut router = Router::new();
    router.get("/", say_hello);
    router.get("/window", window_service::window_http::http_list_window);
    router.get("/window/:table",
               window_service::window_http::http_get_window);
    router.get("/data/:table", data_service::data_http::http_data_query);
    router.get("/app/:main_table",
               app_service::app_http::http_complex_query);
    router.get("/app/focus/:main_table",
               app_service::app_http::http_focused_record);
    router.post("/app/:main_table", app_service::app_http::http_update_data);
    router.get("/lookup_data/:main_table",
               lookup_service::lookup_http::http_get_lookup_data);
    router.get("/lookup_tabs/:main_table",
               lookup_service::lookup_http::http_get_lookup_tabs);//get the lookup tabs for each lookup on this main_table
    router.delete("/cache", global::http_reset_cache);
    router.get("/connection", global::http_can_db_url_connect);

    let mut middleware = Chain::new(router);
    middleware.link(State::<GlobalPools>::both(GlobalPools::new()));
    middleware.link_after(CORS);
    let host = get_server_host();
    let listen = Iron::new(middleware).http(host);
    match listen{
        Ok(listen) => {
                println!("listensing on {:?}", listen)
            }
        Err(e) => {
                println!("Initialization error {}", e)
            }
    }

}

struct CORS;

impl AfterMiddleware for CORS {
    fn after(&self, req: &mut Request, mut res: Response) -> IronResult<Response> {
        let path = req.url.path.connect("/");
        warn!("warning has the request been served? {}", path);
        error!("an error has occured {}", path);
        trace!("tracing..{}",path);
        debug!("Debugging... {}",path);
        res.headers.set(headers::AccessControlAllowOrigin::Any);
        res.headers.set(headers::AccessControlAllowHeaders(vec![UniCase("accept".to_owned()),
                                                                UniCase("content-type"
                                                                    .to_owned()),
                                                                UniCase("db_url".to_owned()),
                                                                UniCase("*".to_owned())]));
        res.headers
            .set(headers::AccessControlAllowMethods(vec![Get, Head, Post, Delete, Options, Put,
                                                         Patch]));
        Ok(res)
    }
}

fn get_server_port() -> u16 {
    let port_str = env::var("PORT").unwrap_or(String::new());
    FromStr::from_str(&port_str).unwrap_or(3224)
}
#[cfg(feature = "webserver")]
fn get_server_host()-> SocketAddrV4 {
    SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), get_server_port())
}

/// when compiling for stand-alone, port will be decided by the OS, by sending arg 0
/// and the host will be 127.3.3.2 as opposed to common 127.0.0.1
#[cfg(feature = "standalone")]
fn get_server_host()-> SocketAddrV4 {
    SocketAddrV4::new(Ipv4Addr::new(127,0 ,0, 1), 0)
}

<|endoftext|>


<commit_before>extern crate yaml_rust;
extern crate regex;

use std::fs::File;
use std::io::prelude::*;
use std::net::TcpListener;
use std::time::Duration;
use std::sync::Arc;
use std::thread;
use std::process::exit;
use yaml_rust::YamlLoader;
use regex::bytes::RegexSetBuilder;

#[derive(Copy, Clone)]
struct App {
  print_ascii: bool,
  print_binary: bool
}

fn main() {
  let mut app = App { print_ascii: false, print_binary: false };
  let binary_matches = [
    ("SSL3.0 Record Protocol", r"^\x16\x03\x00..\x01"),
    ("TLS1.0 Record Protocol", r"^\x16\x03\x01..\x01"),
    ("TLS1.1 Record Protocol", r"^\x16\x03\x02..\x01"),
    ("TLS1.2 Record Protocol", r"^\x16\x03\x03..\x01"),
    ("SSL3.0 CLIENT_HELLO", r"^\x16....\x01...\x03\x00"),
    ("TLS1.0 CLIENT_HELLO", r"^\x16....\x01...\x03\x01"),
    ("TLS1.1 CLIENT_HELLO", r"^\x16....\x01...\x03\x02"),
    ("TLS1.2 CLIENT_HELLO", r"^\x16....\x01...\x03\x03")
  ];
  let io_timeout = Duration::new(300, 0); // 5 minutes

  let mut file = File::open("config.yml").unwrap();
  let mut config_str = String::new();
  file.read_to_string(&mut config_str).unwrap();
  let docs = YamlLoader::load_from_str(&config_str).unwrap();
  let config = &docs[0];
  //println!("{:?}", config);
  if config["general"].is_badvalue() {
    println!("No 'general' section found in configuration file");
    exit(-1);
  }
  if config["ports"].is_badvalue() {
    println!("No 'ports' section found in configuration file");
    exit(-1);
  }
  if !config["general"]["print_ascii"].is_badvalue() {
    if config["general"]["print_ascii"].as_bool().unwrap() {
      app.print_ascii = true;
      println!("Printing ascii");
    }
  }
  if !config["general"]["print_binary"].is_badvalue() {
    if config["general"]["print_binary"].as_bool().unwrap() {
      app.print_binary = true;
      println!("Printing binary");
    }
  }
  let app = app; // Revert to immutable

  let mut patterns = Vec::with_capacity(binary_matches.len());
  for &(_, pattern) in binary_matches.into_iter() {
    patterns.push(pattern);
  }
  let regexset = RegexSetBuilder::new(patterns)
    .unicode(false)
    .dot_matches_new_line(false)
    .build().unwrap();

  for port in config["ports"].as_vec().unwrap() {
    if !port["tcp"].is_badvalue() {
      let portno = port["tcp"].as_i64().unwrap();
      println!("TCP port {}", portno);
      let mut banner = Arc::new(String::new());
      if let Some(x) = port["banner"].as_str() {
        Arc::get_mut(& mut banner).unwrap().push_str(x);
        println!("  with banner: {}", *banner);
      }
      let regexset = regexset.clone();
      thread::spawn(move || {
        let server = TcpListener::bind(("0.0.0.0", portno as u16)).unwrap();
        for res in server.incoming() {
          let mut stream = res.unwrap();
          stream.set_read_timeout(Some(io_timeout)).expect("Failed to set read timeout on TcpStream");
          stream.set_write_timeout(Some(io_timeout)).expect("Failed to set write timeout on TcpStream");
          let addr = stream.peer_addr().unwrap();
          println!("CONNECT TCP {} from {}", portno, addr);
          let regexset = regexset.clone();
          let banner = banner.clone();
          thread::spawn(move || {
            if banner.len() > 0 {
              match stream.write((*banner).as_bytes()) {
                Ok(_) => {
                  for line in (*banner).lines() {
                    println!("> {}", line);
                  }
                }
                Err(e) => {
                  println!("WRITE ERROR TCP {} from {}: {}", portno, addr, e.to_string());
                  return;
                }
              }
            }
            let mut buf: [u8; 2048] = [0; 2048];
            loop {
              match stream.read(&mut buf) {
                Ok(c) => {
                  if c == 0 {
                    println!("CLOSE TCP {} from {}", portno, addr);
                    break;
                  }
                  let mut printables = Vec::new();
                  let mut found = false;
                  let mut start = 0;
                  for i in 0..buf.len() {
                    if (buf[i] > 31 && buf[i] < 127) || buf[i] == 10 || buf[i] == 13 {
                      if !found {
                        start = i;
                        found = true;
                      }
                    }
                    else {
                      if found {
                        printables.push(&buf[start..i]);
                        found = false;
                      }
                    }
                  }
                  if printables.len() == 1 && printables[0].len() == c {
                    if app.print_ascii {
                      let data = String::from_utf8_lossy(printables[0]);
                      for line in data.lines() {
                        println!("| {}", line);
                      }
                    }
                    else { println!("! Read {} bytes of printable ascii", c); }
                    if app.print_binary { println!("! {:?}", &buf[..c]); }
                  }
                  else {
                    println!("! Read {} bytes of binary", c);
                    if app.print_binary { println!("! {:?}", &buf[..c]); }
                    for id in regexset.matches(&buf[..c]).into_iter() {
                      println!("! Matches pattern {}", binary_matches[id].0);
                    }
                    for printable in printables {
                      if printable.len() > 3 {
                        let data = String::from_utf8_lossy(printable);
                        for line in data.lines() {
                          println!("$ {}", line);
                        }
                      }
                    }
                  }
                }
                Err(e) => {
                  println!("READ ERROR TCP {} from {}: {}", portno, addr, e.to_string());
                  break;
                }
              }
              match stream.take_error() {
                Ok(opt) => {
                  if opt.is_some() {
                    println!("ERROR TCP {} from {}: {}", portno, addr, opt.unwrap().to_string());
                    break;
                  }
                }
                Err(_) => {
                  println!("This shouldn't happen...");
                  break;
                }
              }
            }
          });
        }
      });
    }
    else if !port["udp"].is_badvalue() {
      println!("UDP port {}", port["udp"].as_i64().unwrap());
    }
    else {
      println!("Invalid port specification in configuration file");
    }
  }

  loop { thread::sleep(Duration::new(60, 0)); }
}
<commit_msg>Add binary matches for SMB1<commit_after>extern crate yaml_rust;
extern crate regex;

use std::fs::File;
use std::io::prelude::*;
use std::net::TcpListener;
use std::time::Duration;
use std::sync::Arc;
use std::thread;
use std::process::exit;
use yaml_rust::YamlLoader;
use regex::bytes::RegexSetBuilder;

#[derive(Copy, Clone)]
struct App {
  print_ascii: bool,
  print_binary: bool
}

fn main() {
  let mut app = App { print_ascii: false, print_binary: false };
  let binary_matches = [
    ("SSL3.0 Record Protocol", r"^\x16\x03\x00..\x01"),
    ("TLS1.0 Record Protocol", r"^\x16\x03\x01..\x01"),
    ("TLS1.1 Record Protocol", r"^\x16\x03\x02..\x01"),
    ("TLS1.2 Record Protocol", r"^\x16\x03\x03..\x01"),
    ("SSL3.0 CLIENT_HELLO", r"^\x16....\x01...\x03\x00"),
    ("TLS1.0 CLIENT_HELLO", r"^\x16....\x01...\x03\x01"),
    ("TLS1.1 CLIENT_HELLO", r"^\x16....\x01...\x03\x02"),
    ("TLS1.2 CLIENT_HELLO", r"^\x16....\x01...\x03\x03"),
    ("SMB1 COMMAND NEGOTIATE", r"^....\xffSMB\x72"),
    ("SMB1 NT_STATUS Success", r"^....\xffSMB.[\x00-\x0f]"),
    ("SMB1 NT_STATUS Information", r"^....\xffSMB.[\x40-\x4f]"),
    ("SMB1 NT_STATUS Warning", r"^....\xffSMB.[\x80-\x8f]"),
    ("SMB1 NT_STATUS Error", r"^....\xffSMB.[\xc0-\xcf]")
  ];
  let io_timeout = Duration::new(300, 0); // 5 minutes

  let mut file = File::open("config.yml").unwrap();
  let mut config_str = String::new();
  file.read_to_string(&mut config_str).unwrap();
  let docs = YamlLoader::load_from_str(&config_str).unwrap();
  let config = &docs[0];
  //println!("{:?}", config);
  if config["general"].is_badvalue() {
    println!("No 'general' section found in configuration file");
    exit(-1);
  }
  if config["ports"].is_badvalue() {
    println!("No 'ports' section found in configuration file");
    exit(-1);
  }
  if !config["general"]["print_ascii"].is_badvalue() {
    if config["general"]["print_ascii"].as_bool().unwrap() {
      app.print_ascii = true;
      println!("Printing ascii");
    }
  }
  if !config["general"]["print_binary"].is_badvalue() {
    if config["general"]["print_binary"].as_bool().unwrap() {
      app.print_binary = true;
      println!("Printing binary");
    }
  }
  let app = app; // Revert to immutable

  let mut patterns = Vec::with_capacity(binary_matches.len());
  for &(_, pattern) in binary_matches.into_iter() {
    patterns.push(pattern);
  }
  let regexset = RegexSetBuilder::new(patterns)
    .unicode(false)
    .dot_matches_new_line(false)
    .build().unwrap();

  for port in config["ports"].as_vec().unwrap() {
    if !port["tcp"].is_badvalue() {
      let portno = port["tcp"].as_i64().unwrap();
      println!("TCP port {}", portno);
      let mut banner = Arc::new(String::new());
      if let Some(x) = port["banner"].as_str() {
        Arc::get_mut(& mut banner).unwrap().push_str(x);
        println!("  with banner: {}", *banner);
      }
      let regexset = regexset.clone();
      thread::spawn(move || {
        let server = TcpListener::bind(("0.0.0.0", portno as u16)).unwrap();
        for res in server.incoming() {
          let mut stream = res.unwrap();
          stream.set_read_timeout(Some(io_timeout)).expect("Failed to set read timeout on TcpStream");
          stream.set_write_timeout(Some(io_timeout)).expect("Failed to set write timeout on TcpStream");
          let addr = stream.peer_addr().unwrap();
          println!("CONNECT TCP {} from {}", portno, addr);
          let regexset = regexset.clone();
          let banner = banner.clone();
          thread::spawn(move || {
            if banner.len() > 0 {
              match stream.write((*banner).as_bytes()) {
                Ok(_) => {
                  for line in (*banner).lines() {
                    println!("> {}", line);
                  }
                }
                Err(e) => {
                  println!("WRITE ERROR TCP {} from {}: {}", portno, addr, e.to_string());
                  return;
                }
              }
            }
            let mut buf: [u8; 2048] = [0; 2048];
            loop {
              match stream.read(&mut buf) {
                Ok(c) => {
                  if c == 0 {
                    println!("CLOSE TCP {} from {}", portno, addr);
                    break;
                  }
                  let mut printables = Vec::new();
                  let mut found = false;
                  let mut start = 0;
                  for i in 0..buf.len() {
                    if (buf[i] > 31 && buf[i] < 127) || buf[i] == 10 || buf[i] == 13 {
                      if !found {
                        start = i;
                        found = true;
                      }
                    }
                    else {
                      if found {
                        printables.push(&buf[start..i]);
                        found = false;
                      }
                    }
                  }
                  if printables.len() == 1 && printables[0].len() == c {
                    if app.print_ascii {
                      let data = String::from_utf8_lossy(printables[0]);
                      for line in data.lines() {
                        println!("| {}", line);
                      }
                    }
                    else { println!("! Read {} bytes of printable ascii", c); }
                    if app.print_binary { println!("! {:?}", &buf[..c]); }
                  }
                  else {
                    println!("! Read {} bytes of binary", c);
                    if app.print_binary { println!("! {:?}", &buf[..c]); }
                    for id in regexset.matches(&buf[..c]).into_iter() {
                      println!("! Matches pattern {}", binary_matches[id].0);
                    }
                    for printable in printables {
                      if printable.len() > 3 {
                        let data = String::from_utf8_lossy(printable);
                        for line in data.lines() {
                          println!("$ {}", line);
                        }
                      }
                    }
                  }
                }
                Err(e) => {
                  println!("READ ERROR TCP {} from {}: {}", portno, addr, e.to_string());
                  break;
                }
              }
              match stream.take_error() {
                Ok(opt) => {
                  if opt.is_some() {
                    println!("ERROR TCP {} from {}: {}", portno, addr, opt.unwrap().to_string());
                    break;
                  }
                }
                Err(_) => {
                  println!("This shouldn't happen...");
                  break;
                }
              }
            }
          });
        }
      });
    }
    else if !port["udp"].is_badvalue() {
      println!("UDP port {}", port["udp"].as_i64().unwrap());
    }
    else {
      println!("Invalid port specification in configuration file");
    }
  }

  loop { thread::sleep(Duration::new(60, 0)); }
}
<|endoftext|>


<commit_before>// TODO: many items from tokio-core::io have been deprecated in favour of tokio-io
#![allow(deprecated)]

#[macro_use] extern crate log;
#[cfg(debug_assertions)]
extern crate env_logger;
extern crate futures;
extern crate getopts;
extern crate librespot;
extern crate tokio_core;
extern crate tokio_signal;

#[cfg(debug_assertions)]
use env_logger::LogBuilder;
use futures::{Future, Async, Poll, Stream};
#[cfg(debug_assertions)]
use std::env;
use std::io::{self, stderr, Write};
use std::path::PathBuf;
use std::process::exit;
use std::str::FromStr;
use tokio_core::reactor::{Handle, Core};
use tokio_core::io::IoStream;
use std::mem;

use librespot::spirc::{Spirc, SpircTask};
use librespot::authentication::{get_credentials, Credentials};
#[cfg(not(target_os="windows"))]
use librespot::authentication::discovery::{discovery, DiscoveryStream};
use librespot::audio_backend;
use librespot::cache::Cache;
use librespot::player::Player;
use librespot::session::{Bitrate, Config, Session};
use librespot::mixer::{self, Mixer};
use librespot::util::SpotifyId;

use librespot::version;

fn usage(program: &str, opts: &getopts::Options) -> String {
    let brief = format!("Usage: {} [options]", program);
    opts.usage(&brief)
}

#[cfg(debug_assertions)]
fn setup_logging(verbose: bool) {
    let mut builder = LogBuilder::new();
    match env::var("RUST_LOG") {
        Ok(config) => {
            builder.parse(&config);
            builder.init().unwrap();

            if verbose {
                warn!("`--verbose` flag overidden by `RUST_LOG` environment variable");
            }
        }
        Err(_) => {
            if verbose {
                builder.parse("mdns=info,librespot=trace");
            } else {
                builder.parse("mdns=error,librespot=warn");
            }
            builder.init().unwrap();
        }
    }
}

#[derive(Clone)]
struct Setup {
    mixer: fn() -> Box<Mixer>,

	name: String,
    cache: Option<Cache>,
    config: Config,
    credentials: Option<Credentials>,
    authenticate: bool,
    enable_discovery: bool,

    single_track: Option<String>,
    start_position: u32,
}

fn setup(args: &[String]) -> Setup {
    let mut opts = getopts::Options::new();
    opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
        .reqopt("n", "name", "Device name", "NAME")
        .optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE")
        .optopt("", "onstart", "Run PROGRAM when playback is about to begin.", "PROGRAM")
        .optopt("", "onstop", "Run PROGRAM when playback has ended.", "PROGRAM")
        .optopt("", "single-track", "Play a single track ID and exit.", "ID")
        .optopt("", "start-position", "Position (in ms) where playback should be started. Only valid with the --single-track option.", "STARTPOSITION")
        .optopt("u", "username", "Username to sign in with", "USERNAME")
        .optopt("p", "password", "Password", "PASSWORD")
        .optflag("a", "authenticate", "Authenticate given username and password. Make sure you define a cache folder to store credentials.")
        .optflag("", "disable-discovery", "Disable discovery mode")
        .optflag("x", "check", "Run quick internal check")
        .optopt("", "mixer", "Mixer to use", "MIXER");

	#[cfg(debug_assertions)]
    opts.optflag("v", "verbose", "Enable verbose output");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            writeln!(stderr(), "error: {}\n{}", f.to_string(), usage(&args[0], &opts)).unwrap();
            exit(1);
        }
    };

    if matches.opt_present("check") {
    	println!("ok");
    	exit(1);
    }

	#[cfg(debug_assertions)]
	{
	    let verbose = matches.opt_present("verbose");
	    setup_logging(verbose);
	}

    info!("librespot {} ({}). Built on {}.",
             version::short_sha(),
             version::commit_date(),
             version::short_now());

    let mixer_name = matches.opt_str("mixer");
    let mixer = mixer::find(mixer_name.as_ref())
        .expect("Invalid mixer");

    let bitrate = matches.opt_str("b").as_ref()
        .map(|bitrate| Bitrate::from_str(bitrate).expect("Invalid bitrate"))
        .unwrap_or(Bitrate::Bitrate160);

    let name = matches.opt_str("name").unwrap();
    let device_id = librespot::session::device_id(&name);

    let cache = matches.opt_str("c").map(|cache_location| {
        Cache::new(PathBuf::from(cache_location))
    });

    let cached_credentials = cache.as_ref().and_then(Cache::credentials);

    let credentials = get_credentials(matches.opt_str("username"),
                                      matches.opt_str("password"),
                                      cached_credentials);

    let authenticate = matches.opt_present("authenticate");

#[cfg(not(target_os="windows"))]
    let enable_discovery = !matches.opt_present("disable-discovery");
#[cfg(target_os="windows")]
    let enable_discovery = false;

    let start_position = matches.opt_str("start-position")
    	.unwrap_or("0".to_string())
    	.parse().unwrap_or(0);

    let config = Config {
        user_agent: version::version_string(),
        device_id: device_id,
        bitrate: bitrate,
        onstart: matches.opt_str("onstart"),
        onstop: matches.opt_str("onstop"),
    };

    Setup {
		name: name,
        cache: cache,
        config: config,
        credentials: credentials,
        authenticate: authenticate,
        enable_discovery: enable_discovery,
        mixer: mixer,

        single_track: matches.opt_str("single-track"),
        start_position: start_position * 1000,
    }
}

struct Main {
	name: String,
    cache: Option<Cache>,
    config: Config,
    mixer: fn() -> Box<Mixer>,
    handle: Handle,

#[cfg(not(target_os="windows"))]
    discovery: Option<DiscoveryStream>,
#[cfg(target_os="windows")]
    discovery: Option<String>,
    signal: IoStream<()>,

    spirc: Option<Spirc>,
    spirc_task: Option<SpircTask>,
    connect: Box<Future<Item=Session, Error=io::Error>>,

    player: Option<Player>,

    shutdown: bool,
    authenticate: bool,
}

impl Main {
    fn new(handle: Handle,
           name: String,
           config: Config,
           cache: Option<Cache>,
           mixer: fn() -> Box<Mixer>,
           authenticate: bool,
    ) -> Main
    {
        Main {
            handle: handle.clone(),
            name: name,
            cache: cache,
            config: config,
            mixer: mixer,

            connect: Box::new(futures::future::empty()),
            discovery: None,
            spirc: None,
            spirc_task: None,

            player: None,

            shutdown: false,
            authenticate: authenticate,
            signal: tokio_signal::ctrl_c(&handle).flatten_stream().boxed(),
        }
    }

#[cfg(not(target_os="windows"))]
    fn discovery(&mut self) {
        let device_id = self.config.device_id.clone();
        let name = self.name.clone();

        self.discovery = Some(discovery(&self.handle, name, device_id).unwrap());
    }

    fn credentials(&mut self, credentials: Credentials) {
        let config = self.config.clone();
        let handle = self.handle.clone();

        let connection = Session::connect(config, credentials, self.cache.clone(), handle);

        self.connect = connection;
        self.spirc = None;
        let task = mem::replace(&mut self.spirc_task, None);
        if let Some(task) = task {
            self.handle.spawn(task);
        }
    }
}

impl Future for Main {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        loop {
            let mut progress = false;

#[cfg(not(target_os="windows"))] {
            if let Some(Async::Ready(Some(creds))) = self.discovery.as_mut().map(|d| d.poll().unwrap()) {
                if let Some(ref spirc) = self.spirc {
                    spirc.shutdown();
                }
                self.credentials(creds);

                progress = true;
            }
}

            if let Async::Ready(session) = self.connect.poll().unwrap() {
            	if self.authenticate {
					if !self.shutdown {
						if let Some(ref spirc) = self.spirc {
							spirc.shutdown();
						}
						self.shutdown = true;
					} else {
						return Ok(Async::Ready(()));
					}
            	}
            	else {
					self.connect = Box::new(futures::future::empty());
					let mixer = (self.mixer)();

					let audio_filter = mixer.get_audio_filter();
					let backend = audio_backend::find(None).unwrap();
					let player = Player::new(session.clone(), audio_filter, move || {
						(backend)(None)
					});

					self.player = Some(player.clone());

					let (spirc, spirc_task) = Spirc::new(self.name.clone(), session, player, mixer);
					self.spirc = Some(spirc);
					self.spirc_task = Some(spirc_task);
				}

                progress = true;
            }

            if let Async::Ready(Some(())) = self.signal.poll().unwrap() {
                if !self.shutdown {
                    if let Some(ref spirc) = self.spirc {
                        spirc.shutdown();
                    }
                    self.shutdown = true;
                } else {
                    return Ok(Async::Ready(()));
                }

                progress = true;
            }

            if let Some(ref mut spirc_task) = self.spirc_task {
                if let Async::Ready(()) = spirc_task.poll().unwrap() {
                    if self.shutdown {
                        return Ok(Async::Ready(()));
                    } else {
                        panic!("Spirc shut down unexpectedly");
                    }
                }
            }

            if !progress {
                return Ok(Async::NotReady);
            }
        }
    }
}

fn main() {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let args: Vec<String> = std::env::args().collect();
    let Setup { name, config, cache, enable_discovery, credentials, authenticate, mixer, single_track, start_position } = setup(&args);

	if let Some(ref track_id) = single_track {
		match credentials {
			Some(credentials) => {
				let backend = audio_backend::find(None).unwrap();

				let track = SpotifyId::from_base62(
									track_id.replace("spotty://", "")
									.replace("spotify://", "")
									.replace("track:", "")
									.as_str());

				let session = core.run(Session::connect(config, credentials, None, handle)).unwrap();

				let player = Player::new(session.clone(), None, move || (backend)(None));

				core.run(player.load(track, true, start_position)).unwrap();
			}
			None => {
				println!("Missing credentials");
			}
	    }
	}
	else if authenticate && !enable_discovery {
        core.run(Session::connect(config, credentials.unwrap(), cache.clone(), handle)).unwrap();
		println!("authorized");
	}
	else {
		let mut task = Main::new(handle, name, config, cache, mixer, authenticate);
		if enable_discovery {
#[cfg(not(target_os="windows"))]
			task.discovery();
		}
		if let Some(credentials) = credentials {
			task.credentials(credentials);
		}

		core.run(task).unwrap()
    }
}

<commit_msg>LMS would send the start position in fractions of a second. Let's make sure we parse the parameter as float.<commit_after>// TODO: many items from tokio-core::io have been deprecated in favour of tokio-io
#![allow(deprecated)]

#[macro_use] extern crate log;
#[cfg(debug_assertions)]
extern crate env_logger;
extern crate futures;
extern crate getopts;
extern crate librespot;
extern crate tokio_core;
extern crate tokio_signal;

#[cfg(debug_assertions)]
use env_logger::LogBuilder;
use futures::{Future, Async, Poll, Stream};
#[cfg(debug_assertions)]
use std::env;
use std::io::{self, stderr, Write};
use std::path::PathBuf;
use std::process::exit;
use std::str::FromStr;
use tokio_core::reactor::{Handle, Core};
use tokio_core::io::IoStream;
use std::mem;

use librespot::spirc::{Spirc, SpircTask};
use librespot::authentication::{get_credentials, Credentials};
#[cfg(not(target_os="windows"))]
use librespot::authentication::discovery::{discovery, DiscoveryStream};
use librespot::audio_backend;
use librespot::cache::Cache;
use librespot::player::Player;
use librespot::session::{Bitrate, Config, Session};
use librespot::mixer::{self, Mixer};
use librespot::util::SpotifyId;

use librespot::version;

fn usage(program: &str, opts: &getopts::Options) -> String {
    let brief = format!("Usage: {} [options]", program);
    opts.usage(&brief)
}

#[cfg(debug_assertions)]
fn setup_logging(verbose: bool) {
    let mut builder = LogBuilder::new();
    match env::var("RUST_LOG") {
        Ok(config) => {
            builder.parse(&config);
            builder.init().unwrap();

            if verbose {
                warn!("`--verbose` flag overidden by `RUST_LOG` environment variable");
            }
        }
        Err(_) => {
            if verbose {
                builder.parse("mdns=info,librespot=trace");
            } else {
                builder.parse("mdns=error,librespot=warn");
            }
            builder.init().unwrap();
        }
    }
}

#[derive(Clone)]
struct Setup {
    mixer: fn() -> Box<Mixer>,

	name: String,
    cache: Option<Cache>,
    config: Config,
    credentials: Option<Credentials>,
    authenticate: bool,
    enable_discovery: bool,

    single_track: Option<String>,
    start_position: u32,
}

fn setup(args: &[String]) -> Setup {
    let mut opts = getopts::Options::new();
    opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
        .reqopt("n", "name", "Device name", "NAME")
        .optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE")
        .optopt("", "onstart", "Run PROGRAM when playback is about to begin.", "PROGRAM")
        .optopt("", "onstop", "Run PROGRAM when playback has ended.", "PROGRAM")
        .optopt("", "single-track", "Play a single track ID and exit.", "ID")
        .optopt("", "start-position", "Position (in ms) where playback should be started. Only valid with the --single-track option.", "STARTPOSITION")
        .optopt("u", "username", "Username to sign in with", "USERNAME")
        .optopt("p", "password", "Password", "PASSWORD")
        .optflag("a", "authenticate", "Authenticate given username and password. Make sure you define a cache folder to store credentials.")
        .optflag("", "disable-discovery", "Disable discovery mode")
        .optflag("x", "check", "Run quick internal check")
        .optopt("", "mixer", "Mixer to use", "MIXER");

	#[cfg(debug_assertions)]
    opts.optflag("v", "verbose", "Enable verbose output");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            writeln!(stderr(), "error: {}\n{}", f.to_string(), usage(&args[0], &opts)).unwrap();
            exit(1);
        }
    };

    if matches.opt_present("check") {
    	println!("ok");
    	exit(1);
    }

	#[cfg(debug_assertions)]
	{
	    let verbose = matches.opt_present("verbose");
	    setup_logging(verbose);
	}

    info!("librespot {} ({}). Built on {}.",
             version::short_sha(),
             version::commit_date(),
             version::short_now());

    let mixer_name = matches.opt_str("mixer");
    let mixer = mixer::find(mixer_name.as_ref())
        .expect("Invalid mixer");

    let bitrate = matches.opt_str("b").as_ref()
        .map(|bitrate| Bitrate::from_str(bitrate).expect("Invalid bitrate"))
        .unwrap_or(Bitrate::Bitrate160);

    let name = matches.opt_str("name").unwrap();
    let device_id = librespot::session::device_id(&name);

    let cache = matches.opt_str("c").map(|cache_location| {
        Cache::new(PathBuf::from(cache_location))
    });

    let cached_credentials = cache.as_ref().and_then(Cache::credentials);

    let credentials = get_credentials(matches.opt_str("username"),
                                      matches.opt_str("password"),
                                      cached_credentials);

    let authenticate = matches.opt_present("authenticate");

#[cfg(not(target_os="windows"))]
    let enable_discovery = !matches.opt_present("disable-discovery");
#[cfg(target_os="windows")]
    let enable_discovery = false;

    let start_position = matches.opt_str("start-position")
    	.unwrap_or("0".to_string())
    	.parse().unwrap_or(0.0);

    let config = Config {
        user_agent: version::version_string(),
        device_id: device_id,
        bitrate: bitrate,
        onstart: matches.opt_str("onstart"),
        onstop: matches.opt_str("onstop"),
    };

    Setup {
		name: name,
        cache: cache,
        config: config,
        credentials: credentials,
        authenticate: authenticate,
        enable_discovery: enable_discovery,
        mixer: mixer,

        single_track: matches.opt_str("single-track"),
        start_position: (start_position * 1000.0) as u32,
    }
}

struct Main {
	name: String,
    cache: Option<Cache>,
    config: Config,
    mixer: fn() -> Box<Mixer>,
    handle: Handle,

#[cfg(not(target_os="windows"))]
    discovery: Option<DiscoveryStream>,
#[cfg(target_os="windows")]
    discovery: Option<String>,
    signal: IoStream<()>,

    spirc: Option<Spirc>,
    spirc_task: Option<SpircTask>,
    connect: Box<Future<Item=Session, Error=io::Error>>,

    player: Option<Player>,

    shutdown: bool,
    authenticate: bool,
}

impl Main {
    fn new(handle: Handle,
           name: String,
           config: Config,
           cache: Option<Cache>,
           mixer: fn() -> Box<Mixer>,
           authenticate: bool,
    ) -> Main
    {
        Main {
            handle: handle.clone(),
            name: name,
            cache: cache,
            config: config,
            mixer: mixer,

            connect: Box::new(futures::future::empty()),
            discovery: None,
            spirc: None,
            spirc_task: None,

            player: None,

            shutdown: false,
            authenticate: authenticate,
            signal: tokio_signal::ctrl_c(&handle).flatten_stream().boxed(),
        }
    }

#[cfg(not(target_os="windows"))]
    fn discovery(&mut self) {
        let device_id = self.config.device_id.clone();
        let name = self.name.clone();

        self.discovery = Some(discovery(&self.handle, name, device_id).unwrap());
    }

    fn credentials(&mut self, credentials: Credentials) {
        let config = self.config.clone();
        let handle = self.handle.clone();

        let connection = Session::connect(config, credentials, self.cache.clone(), handle);

        self.connect = connection;
        self.spirc = None;
        let task = mem::replace(&mut self.spirc_task, None);
        if let Some(task) = task {
            self.handle.spawn(task);
        }
    }
}

impl Future for Main {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        loop {
            let mut progress = false;

#[cfg(not(target_os="windows"))] {
            if let Some(Async::Ready(Some(creds))) = self.discovery.as_mut().map(|d| d.poll().unwrap()) {
                if let Some(ref spirc) = self.spirc {
                    spirc.shutdown();
                }
                self.credentials(creds);

                progress = true;
            }
}

            if let Async::Ready(session) = self.connect.poll().unwrap() {
            	if self.authenticate {
					if !self.shutdown {
						if let Some(ref spirc) = self.spirc {
							spirc.shutdown();
						}
						self.shutdown = true;
					} else {
						return Ok(Async::Ready(()));
					}
            	}
            	else {
					self.connect = Box::new(futures::future::empty());
					let mixer = (self.mixer)();

					let audio_filter = mixer.get_audio_filter();
					let backend = audio_backend::find(None).unwrap();
					let player = Player::new(session.clone(), audio_filter, move || {
						(backend)(None)
					});

					self.player = Some(player.clone());

					let (spirc, spirc_task) = Spirc::new(self.name.clone(), session, player, mixer);
					self.spirc = Some(spirc);
					self.spirc_task = Some(spirc_task);
				}

                progress = true;
            }

            if let Async::Ready(Some(())) = self.signal.poll().unwrap() {
                if !self.shutdown {
                    if let Some(ref spirc) = self.spirc {
                        spirc.shutdown();
                    }
                    self.shutdown = true;
                } else {
                    return Ok(Async::Ready(()));
                }

                progress = true;
            }

            if let Some(ref mut spirc_task) = self.spirc_task {
                if let Async::Ready(()) = spirc_task.poll().unwrap() {
                    if self.shutdown {
                        return Ok(Async::Ready(()));
                    } else {
                        panic!("Spirc shut down unexpectedly");
                    }
                }
            }

            if !progress {
                return Ok(Async::NotReady);
            }
        }
    }
}

fn main() {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let args: Vec<String> = std::env::args().collect();
    let Setup { name, config, cache, enable_discovery, credentials, authenticate, mixer, single_track, start_position } = setup(&args);

	if let Some(ref track_id) = single_track {
		match credentials {
			Some(credentials) => {
				let backend = audio_backend::find(None).unwrap();

				let track = SpotifyId::from_base62(
									track_id.replace("spotty://", "")
									.replace("spotify://", "")
									.replace("track:", "")
									.as_str());

				let session = core.run(Session::connect(config, credentials, None, handle)).unwrap();

				let player = Player::new(session.clone(), None, move || (backend)(None));

				core.run(player.load(track, true, start_position)).unwrap();
			}
			None => {
				println!("Missing credentials");
			}
	    }
	}
	else if authenticate && !enable_discovery {
        core.run(Session::connect(config, credentials.unwrap(), cache.clone(), handle)).unwrap();
		println!("authorized");
	}
	else {
		let mut task = Main::new(handle, name, config, cache, mixer, authenticate);
		if enable_discovery {
#[cfg(not(target_os="windows"))]
			task.discovery();
		}
		if let Some(credentials) = credentials {
			task.credentials(credentials);
		}

		core.run(task).unwrap()
    }
}

<|endoftext|>


<commit_before>extern crate ansi_term;
extern crate docopt;
extern crate rustc_serialize;

use ansi_term::Colour;
use docopt::Docopt;

use std::collections;
use std::fs;
use std::io;
use std::path;

use std::os::unix::fs::FileTypeExt;

const USAGE: &'static str = "
srch, a command-line file search utility written in Rust.

Usage:
    srch [options] <pattern>
    srch --help
    srch --version

Options:
    -h, --help      Show this help screen
    -v, --version   Show this program's version
";

#[derive(RustcDecodable)]
struct Args {
    arg_pattern: String,
}

fn main() {
    let args: Args = Docopt::new(USAGE).unwrap()
                            .help(true)
                            .version(Some(String::from("srch, version ") + option_env!("CARGO_PKG_VERSION").unwrap_or("unknown")))
                            .decode()
                            .unwrap_or_else(|e| e.exit());

    let curdir = path::PathBuf::from("./");
    handle(&curdir, &args.arg_pattern);
}

fn ignore (path: &path::PathBuf) -> io::Result<bool> {
    if !try!(path.is_dir()) {
        return Ok(true)
    }

    let m = try!(fs::symlink_metadata(path)).file_type();
    if m.is_symlink() || m.is_block_device() || m.is_char_device() || m.is_fifo() || m.is_socket() {
        return Ok(true)
    }

    let fname = path.file_name();
    if fname == None {
        return Ok(false)
    }

    let fname = fname.unwrap().to_str().unwrap();
    if fname.chars().next().unwrap() == '.' {
        return Ok(true)
    }

    Ok(false)
}

trait Misc {
    fn is_dir(&self) -> io::Result<bool>;
    fn display_colour(&self) -> io::Result<String>;
    fn matches(&self, pattern: &String) -> bool;
}

impl Misc for path::PathBuf {
    fn is_dir(&self) -> io::Result<bool> {
        let m = try!(fs::metadata(self));
        Ok(m.is_dir())
    }

    fn display_colour(&self) -> io::Result<String> {
        let s: &str = self.to_str().unwrap();

        if try!(self.is_dir()) {
            Ok(Colour::Purple.paint(s).to_string())
        } else {
            Ok(s.to_string())
        }
    }

    fn matches(&self, pattern: &String) -> bool {
        let fname = self.file_name();
        if fname == None {
            return false
        }

        let fname = fname.unwrap().to_str().unwrap().to_string();
        if fname == *pattern {
            return true
        }
        false
    }
}

fn handle(path: &path::PathBuf, pattern: &String) -> () {
    let mut q: collections::VecDeque<path::PathBuf> = collections::VecDeque::new();
    let mut results = (0, 0);

    q.push_back(path.clone());
    while q.len() > 0 {
        let p = q.pop_front().unwrap();
        let r = explore(&mut q, &p, pattern);
        match r {
            Ok(n) => {
                results.0 += n.0;
                results.1 += n.1;
            },
            Err(_) => (),
        };
    }

    let (directories, files) = results;
    println!("Search results: {} directories, {} files", Colour::Cyan.bold().paint(directories.to_string()), Colour::Blue.bold().paint(files.to_string()));
}

fn explore(q: &mut collections::VecDeque<path::PathBuf>, path: &path::PathBuf, pattern: &String) -> std::io::Result<(i32, i32)> {
    if try!(ignore(path)) {
        return Ok((0, 0))
    }

    let mut directories = 0;
    let mut files = 0;

    for item in try!(fs::read_dir(path)) {
        let f = try!(item); // f is a DirEntry
        let dir: bool;
        if try!(f.path().is_dir()) {
            q.push_back(f.path());
            dir = true;
        } else {
            dir = false;
        }

        if f.path().matches(&pattern) {
            println!("{}", try!(f.path().display_colour()));
            if dir {
                directories += 1;
            } else {
                files += 1;
            }
        }
    }

    Ok((directories, files))
}
<commit_msg>Use PathBuf methods<commit_after>extern crate ansi_term;
extern crate docopt;
extern crate rustc_serialize;

use ansi_term::Colour;
use docopt::Docopt;

use std::collections;
use std::io;
use std::path;

use std::os::unix::fs::FileTypeExt;

const USAGE: &'static str = "
srch, a command-line file search utility written in Rust.

Usage:
    srch [options] <pattern>
    srch --help
    srch --version

Options:
    -h, --help      Show this help screen
    -v, --version   Show this program's version
";

#[derive(RustcDecodable)]
struct Args {
    arg_pattern: String,
}

fn main() {
    let args: Args = Docopt::new(USAGE).unwrap()
                            .help(true)
                            .version(Some(String::from("srch, version ") + option_env!("CARGO_PKG_VERSION").unwrap_or("unknown")))
                            .decode()
                            .unwrap_or_else(|e| e.exit());

    let curdir = path::PathBuf::from("./");
    handle(&curdir, &args.arg_pattern);
}

fn ignore (path: &path::PathBuf) -> io::Result<bool> {
    if !path.is_dir() {
        return Ok(true)
    }

    let m = try!(path.symlink_metadata()).file_type();
    if m.is_symlink() || m.is_block_device() || m.is_char_device() || m.is_fifo() || m.is_socket() {
        return Ok(true)
    }

    let fname = path.file_name();
    if fname == None {
        return Ok(false)
    }

    let fname = fname.unwrap().to_str().unwrap();
    if fname.chars().next().unwrap() == '.' {
        return Ok(true)
    }

    Ok(false)
}

trait Misc {
    fn display_colour(&self) -> io::Result<String>;
    fn matches(&self, pattern: &String) -> bool;
}

impl Misc for path::PathBuf {
    fn display_colour(&self) -> io::Result<String> {
        let s: &str = self.to_str().unwrap();

        if self.is_dir() {
            Ok(Colour::Purple.paint(s).to_string())
        } else {
            Ok(s.to_string())
        }
    }

    fn matches(&self, pattern: &String) -> bool {
        let fname = self.file_name();
        if fname == None {
            return false
        }

        let fname = fname.unwrap().to_str().unwrap().to_string();
        if fname == *pattern {
            return true
        }
        false
    }
}

fn handle(path: &path::PathBuf, pattern: &String) -> () {
    let mut q: collections::VecDeque<path::PathBuf> = collections::VecDeque::new();
    let mut results = (0, 0);

    q.push_back(path.clone());
    while q.len() > 0 {
        let p = q.pop_front().unwrap();
        let r = explore(&mut q, &p, pattern);
        match r {
            Ok(n) => {
                results.0 += n.0;
                results.1 += n.1;
            },
            Err(_) => (),
        };
    }

    let (directories, files) = results;
    println!("Search results: {} directories, {} files", Colour::Cyan.bold().paint(directories.to_string()), Colour::Blue.bold().paint(files.to_string()));
}

fn explore(q: &mut collections::VecDeque<path::PathBuf>, path: &path::PathBuf, pattern: &String) -> std::io::Result<(i32, i32)> {
    if try!(ignore(path)) {
        return Ok((0, 0))
    }

    let mut directories = 0;
    let mut files = 0;

    for item in try!(path.read_dir()) {
        let f = try!(item); // f is a DirEntry
        let dir: bool;
        if f.path().is_dir() {
            q.push_back(f.path());
            dir = true;
        } else {
            dir = false;
        }

        if f.path().matches(&pattern) {
            println!("{}", try!(f.path().display_colour()));
            if dir {
                directories += 1;
            } else {
                files += 1;
            }
        }
    }

    Ok((directories, files))
}
<|endoftext|>