<commit_before>//! # Hexdino
//!
//! A hex editor with vim like keybindings written in Rust.

#![doc(html_logo_url = "https://raw.githubusercontent.com/Luz/hexdino/master/logo.png")]

#![deny(trivial_casts)]

use std::io::prelude::*;
use std::fs::OpenOptions;
use std::io::SeekFrom;
use std::path::Path;
use std::error::Error;
use std::env;
use std::cmp;

mod draw;
use draw::draw;
use draw::get_absolute_draw_indices;
mod find;
use find::FindOptSubset;

extern crate ncurses;
use ncurses::*;

extern crate getopts;
use getopts::Options;

extern crate pest;
#[macro_use]
extern crate pest_derive;

use pest::Parser;

#[derive(Parser)]
#[grammar = "cmd.pest"]
struct IdentParser;

extern crate memmem;
use memmem::{Searcher, TwoWaySearcher};

#[derive(PartialEq, Copy, Clone)]
pub enum Cursorstate {
    Leftnibble,
    Rightnibble,
    Asciichar,
}

fn main() {
    const VERSION: &str = env!("CARGO_PKG_VERSION");
    let mut buf = vec![];
    let mut cursorpos: usize = 0;
    let mut cstate: Cursorstate = Cursorstate::Leftnibble;
    // 0 = display data from first line of file
    let mut screenoffset: usize = 0;
    const SPALTEN: usize = 16;
    let mut command = String::new();
    let mut lastcommand = String::new();
    let mut debug = String::new();

    // start ncursesw
    initscr();
    let screenheight = getmaxy(stdscr()) as usize;
    // ctrl+z and fg works with this
    cbreak();
    noecho();
    start_color();
    init_pair(1, COLOR_GREEN, COLOR_BLACK);

    let args: Vec<_> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");
    opts.optflag("v", "version", "print the version");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            endwin();
            println!("{}", f.to_string());
            println!("Usage: {} FILE [options]", program);
            return;
        }
    };
    if matches.opt_present("v") {
        endwin();
        println!("Version: {}", VERSION);
        return;
    }
    if matches.opt_present("h") {
        endwin();
        println!("Usage: {} FILE [options]", program);
        return;
    }

    if !has_colors() {
        endwin();
        println!("Your terminal does not support color!\n");
        return;
    }

    let patharg = match matches.free.is_empty() {
        true => String::new(),
        false => matches.free[0].clone(),
    };
    let path = Path::new(&patharg);

    if patharg.is_empty() {
        endwin();
        println!("Patharg is empty!\n");
        return;
    }

    let mut file = match OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(&path) {
        Err(why) => {
            endwin();
            println!("Could not open {}: {}", path.display(), why.to_string());
            return;
        }
        Ok(file) => file,
    };
    file.read_to_end(&mut buf).ok().expect(
        "File could not be read.",
    );

    let draw_range = get_absolute_draw_indices(buf.len(), SPALTEN, screenoffset);
    draw(&buf[draw_range.0 .. draw_range.1], cursorpos, SPALTEN, &command, &mut debug, cstate, screenoffset);

    let mut quitnow = false;
    let mut autoparse = false;
    while quitnow == false {
        if !autoparse {
            let key = std::char::from_u32(getch() as u32).unwrap();
            command.push_str(&key.clone().to_string());
        }
        autoparse = false;

        let parsethisstring = command.clone();
        let commands = IdentParser::parse(Rule::cmd_list, &parsethisstring)
            .unwrap_or_else(|e| panic!("{}", e));

        let mut clear = true;
        let mut save = false;
        for cmd in commands {
            match cmd.as_rule() {
                Rule::down => {
                    // debug.push_str(&format!("{:?}", cmd.as_rule()));
                    if cursorpos + SPALTEN < buf.len() {
                        // not at end
                        cursorpos += SPALTEN;
                    } else {
                        // when at end
                        if buf.len() != 0 {
                            // Suppress underflow
                            cursorpos = buf.len() - 1;
                        }
                    }
                }
                Rule::up => {
                    if cursorpos >= SPALTEN {
                        cursorpos -= SPALTEN;
                    }
                }
                Rule::left => {
                    if cstate == Cursorstate::Asciichar {
                        if cursorpos > 0 {
                            cursorpos -= 1;
                        }
                    } else if cstate == Cursorstate::Rightnibble {
                        cstate = Cursorstate::Leftnibble;
                    } else if cstate == Cursorstate::Leftnibble {
                        if cursorpos > 0 {
                            // not at start
                            cstate = Cursorstate::Rightnibble;
                            cursorpos -= 1;
                        }
                    }
                }
                Rule::right => {
                    if cstate == Cursorstate::Asciichar {
                        if cursorpos + 1 < buf.len() {
                            // not at end
                            cursorpos += 1;
                        }
                    } else if cstate == Cursorstate::Leftnibble {
                        cstate = Cursorstate::Rightnibble;
                    } else if cstate == Cursorstate::Rightnibble {
                        if cursorpos + 1 < buf.len() {
                            // not at end
                            cstate = Cursorstate::Leftnibble;
                            cursorpos += 1;
                        }
                    }
                }
                Rule::start => {
                    cursorpos -= cursorpos % SPALTEN; // jump to start of line
                    if cstate == Cursorstate::Rightnibble {
                        cstate = Cursorstate::Leftnibble;
                    }
                }
                Rule::end => {
                    // check if no overflow
                    if cursorpos - (cursorpos % SPALTEN) + (SPALTEN - 1) < buf.len() {
                        // jump to end of line
                        cursorpos = cursorpos - (cursorpos % SPALTEN) + (SPALTEN - 1);
                    } else {
                        // jump to end of line
                        cursorpos = buf.len() - 1
                    }
                    if cstate == Cursorstate::Leftnibble {
                        cstate = Cursorstate::Rightnibble;
                    }
                }
                Rule::bottom => {
                    cursorpos = buf.len() - 1;
                    cursorpos -= cursorpos % SPALTEN; // jump to start of line
                }
                Rule::replace => {
                    // debug.push_str("next char will be the replacement!");
                    clear = false;
                }
                Rule::remove => {
                    // check if in valid range
                    if buf.len() > 0 && cursorpos < buf.len() {
                        // remove the current char
                        buf.remove(cursorpos);
                    }
                    // always perform the movement if possible
                    if cursorpos > 0 && cursorpos >= buf.len() {
                        cursorpos -= 1;
                    }
                    lastcommand = command.clone();
                }
                Rule::insert => {
                    // debug.push_str("next chars will be inserted!");
                    clear = false;
                }
                Rule::jumpascii => {
                    if cstate == Cursorstate::Asciichar {
                        cstate = Cursorstate::Leftnibble;
                    } else {
                        cstate = Cursorstate::Asciichar;
                    }
                }
                Rule::helpfile => {
                    command.push_str("No helpfile yet");
                }
                Rule::repeat => {
                    command = lastcommand.clone();
                    clear = false;
                    autoparse = true;
                }
                Rule::backspace => {
                    command.pop();
                    command.pop();
                    clear = false;
                }
                Rule::saveandexit => {
                    save = true;
                    quitnow = true;
                }
                Rule::exit => quitnow = true,
                Rule::save => save = true,

                _ => (),
            }

            for inner_cmd in cmd.into_inner() {
                match inner_cmd.as_rule() {
                    Rule::replacement => {
                        let key = inner_cmd.as_str().chars().nth(0).unwrap_or('x');
                        if cstate == Cursorstate::Asciichar {
                            if cursorpos >= buf.len() {
                                buf.insert(cursorpos, 0);
                            }
                            // buf[cursorpos] = inner_cmd.as_str();
                            buf[cursorpos] = key as u8;
                        } else {
                            let mask = if cstate == Cursorstate::Leftnibble {
                                0x0F
                            } else {
                                0xF0
                            };
                            let shift = if cstate == Cursorstate::Leftnibble {
                                4
                            } else {
                                0
                            };
                            if cursorpos >= buf.len() {
                                buf.insert(cursorpos, 0);
                            }
                            // Change the selected nibble
                            if let Some(c) = key.to_digit(16) {
                                buf[cursorpos] = buf[cursorpos] & mask | (c as u8) << shift;
                            }
                        }
                        lastcommand.clear();
                        lastcommand.push_str(&format!("Command repeation for {:?} not yet implemented.", inner_cmd.as_rule()));
                    }
                    Rule::dd_lines => {
                        let amount: usize = inner_cmd.as_str().parse().unwrap_or(1);
                        // check if in valid range
                        if buf.len() > 0 && cursorpos < buf.len() {
                            let startofline = cursorpos - cursorpos % SPALTEN;
                            let mut endofline = cursorpos - (cursorpos % SPALTEN) + (SPALTEN * amount ) ;
                            endofline = cmp::min( endofline, buf.len() );
                            buf.drain(startofline..endofline);
                        }
                        lastcommand = command.clone();
                    }
                    Rule::insertment => {
                        let key = inner_cmd.as_str().chars().nth(0).unwrap_or('x');
                        lastcommand = command.clone();
                        // debug.push_str(&format!("Inserted: {:?}", inner_cmd.as_str()));
                        command.pop(); // remove the just inserted thing
                        clear = false;

                        if cstate == Cursorstate::Leftnibble {
                            // Left nibble
                            if let Some(c) = key.to_digit(16) {
                                buf.insert(cursorpos, (c as u8) << 4);
                                cstate = Cursorstate::Rightnibble;
                            }
                        } else if cstate == Cursorstate::Rightnibble {
                            // Right nibble
                            if cursorpos == buf.len() {
                                buf.insert(cursorpos, 0);
                            }
                            if let Some(c) = key.to_digit(16) {
                                buf[cursorpos] = buf[cursorpos] & 0xF0 | c as u8;
                                cstate = Cursorstate::Leftnibble;
                                cursorpos += 1;
                            }
                        } else if cstate == Cursorstate::Asciichar {
                            buf.insert(cursorpos, key as u8);
                            cursorpos += 1;
                        }
                        lastcommand.clear();
                        lastcommand.push_str(&format!("Command repeation for {:?} not yet implemented.", inner_cmd.as_rule()));
                    }
                    Rule::searchstr => {
                        let search = inner_cmd.as_str().as_bytes();
                        let foundpos = TwoWaySearcher::new(&search);
                        cursorpos = foundpos.search_in(&buf).unwrap_or(cursorpos);
                    }
                    Rule::searchbytes => {
                        let search = inner_cmd.as_str().as_bytes();
                        let mut needle = vec![];
                        for i in 0..search.len() {
                            let nibble = match search[i] as u8 {
                                c @ 48...57 => c - 48, // Numbers from 0 to 9
                                b'x' => 0x10, // x is the wildcard
                                b'X' => 0x10, // X is the wildcard
                                c @ b'a'...b'f' => c - 87,
                                c @ b'A'...b'F' => c - 55,
                                _ => panic!("Should not get to this position!"),
                            };
                            needle.push(nibble);
                        }
                        cursorpos = buf.find_subset(&needle).unwrap_or(cursorpos);
                        // debug.push_str(&format!("Searching for: {:?}", needle ));
                    }
                    Rule::gg_line => {
                        let linenr: usize = inner_cmd.as_str().parse().unwrap_or(0);
                        cursorpos = linenr * SPALTEN; // jump to the line
                        if cursorpos > buf.len() { // detect file end
                            cursorpos = buf.len();
                        }
                        cursorpos -= cursorpos % SPALTEN; // jump to start of line
                    }
                    Rule::escape => (),
                    Rule::gatherone => clear = false,
                    _ => {
                        command.push_str(&format!("no rule for {:?} ", inner_cmd.as_rule()));
                        clear = false;
                    }
                };
            }
            if save {
                if path.exists() {
                    let mut file = match OpenOptions::new()
                        .read(true)
                        .write(true)
                        .create(true)
                        .open(&path) {
                        Err(why) => {
                            panic!(
                                "Could not open {}: {}",
                                path.display(),
                                Error::description(&why)
                            )
                        }
                        Ok(file) => file,
                    };
                    file.seek(SeekFrom::Start(0)).ok().expect(
                        "Filepointer could not be set to 0",
                    );
                    file.write_all(&mut buf).ok().expect(
                        "File could not be written.",
                    );
                    file.set_len(buf.len() as u64).ok().expect(
                        "File could not be set to correct lenght.",
                    );
                    command.push_str("File saved!");
                } else {
                    command.push_str("Careful, file could not be saved!");
                }
                // TODO: define filename during runtime
                save = false;
            }
            if clear {
                command.clear();
            }

            // Always move screen when cursor leaves screen
            if cursorpos > (screenheight + screenoffset - 1) * SPALTEN - 1 {
                screenoffset = 2 + cursorpos / SPALTEN - screenheight;
            }
            if cursorpos < screenoffset * SPALTEN {
                screenoffset = cursorpos / SPALTEN;
            }

        }

    let draw_range = get_absolute_draw_indices(buf.len(), SPALTEN, screenoffset);
        draw(&buf[draw_range.0 .. draw_range.1], cursorpos, SPALTEN, &command, &mut debug, cstate, screenoffset);
    }

    refresh();
    endwin();
}
<commit_msg>Implement repeation of 'r'<commit_after>//! # Hexdino
//!
//! A hex editor with vim like keybindings written in Rust.

#![doc(html_logo_url = "https://raw.githubusercontent.com/Luz/hexdino/master/logo.png")]

#![deny(trivial_casts)]

use std::io::prelude::*;
use std::fs::OpenOptions;
use std::io::SeekFrom;
use std::path::Path;
use std::error::Error;
use std::env;
use std::cmp;

mod draw;
use draw::draw;
use draw::get_absolute_draw_indices;
mod find;
use find::FindOptSubset;

extern crate ncurses;
use ncurses::*;

extern crate getopts;
use getopts::Options;

extern crate pest;
#[macro_use]
extern crate pest_derive;

use pest::Parser;

#[derive(Parser)]
#[grammar = "cmd.pest"]
struct IdentParser;

extern crate memmem;
use memmem::{Searcher, TwoWaySearcher};

#[derive(PartialEq, Copy, Clone)]
pub enum Cursorstate {
    Leftnibble,
    Rightnibble,
    Asciichar,
}

fn main() {
    const VERSION: &str = env!("CARGO_PKG_VERSION");
    let mut buf = vec![];
    let mut cursorpos: usize = 0;
    let mut cstate: Cursorstate = Cursorstate::Leftnibble;
    // 0 = display data from first line of file
    let mut screenoffset: usize = 0;
    const SPALTEN: usize = 16;
    let mut command = String::new();
    let mut lastcommand = String::new();
    let mut debug = String::new();

    // start ncursesw
    initscr();
    let screenheight = getmaxy(stdscr()) as usize;
    // ctrl+z and fg works with this
    cbreak();
    noecho();
    start_color();
    init_pair(1, COLOR_GREEN, COLOR_BLACK);

    let args: Vec<_> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");
    opts.optflag("v", "version", "print the version");
    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            endwin();
            println!("{}", f.to_string());
            println!("Usage: {} FILE [options]", program);
            return;
        }
    };
    if matches.opt_present("v") {
        endwin();
        println!("Version: {}", VERSION);
        return;
    }
    if matches.opt_present("h") {
        endwin();
        println!("Usage: {} FILE [options]", program);
        return;
    }

    if !has_colors() {
        endwin();
        println!("Your terminal does not support color!\n");
        return;
    }

    let patharg = match matches.free.is_empty() {
        true => String::new(),
        false => matches.free[0].clone(),
    };
    let path = Path::new(&patharg);

    if patharg.is_empty() {
        endwin();
        println!("Patharg is empty!\n");
        return;
    }

    let mut file = match OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(&path) {
        Err(why) => {
            endwin();
            println!("Could not open {}: {}", path.display(), why.to_string());
            return;
        }
        Ok(file) => file,
    };
    file.read_to_end(&mut buf).ok().expect(
        "File could not be read.",
    );

    let draw_range = get_absolute_draw_indices(buf.len(), SPALTEN, screenoffset);
    draw(&buf[draw_range.0 .. draw_range.1], cursorpos, SPALTEN, &command, &mut debug, cstate, screenoffset);

    let mut quitnow = false;
    let mut autoparse = false;
    while quitnow == false {
        if !autoparse {
            let key = std::char::from_u32(getch() as u32).unwrap();
            command.push_str(&key.clone().to_string());
        }
        autoparse = false;

        let parsethisstring = command.clone();
        let commands = IdentParser::parse(Rule::cmd_list, &parsethisstring)
            .unwrap_or_else(|e| panic!("{}", e));

        let mut clear = true;
        let mut save = false;
        for cmd in commands {
            match cmd.as_rule() {
                Rule::down => {
                    // debug.push_str(&format!("{:?}", cmd.as_rule()));
                    if cursorpos + SPALTEN < buf.len() {
                        // not at end
                        cursorpos += SPALTEN;
                    } else {
                        // when at end
                        if buf.len() != 0 {
                            // Suppress underflow
                            cursorpos = buf.len() - 1;
                        }
                    }
                }
                Rule::up => {
                    if cursorpos >= SPALTEN {
                        cursorpos -= SPALTEN;
                    }
                }
                Rule::left => {
                    if cstate == Cursorstate::Asciichar {
                        if cursorpos > 0 {
                            cursorpos -= 1;
                        }
                    } else if cstate == Cursorstate::Rightnibble {
                        cstate = Cursorstate::Leftnibble;
                    } else if cstate == Cursorstate::Leftnibble {
                        if cursorpos > 0 {
                            // not at start
                            cstate = Cursorstate::Rightnibble;
                            cursorpos -= 1;
                        }
                    }
                }
                Rule::right => {
                    if cstate == Cursorstate::Asciichar {
                        if cursorpos + 1 < buf.len() {
                            // not at end
                            cursorpos += 1;
                        }
                    } else if cstate == Cursorstate::Leftnibble {
                        cstate = Cursorstate::Rightnibble;
                    } else if cstate == Cursorstate::Rightnibble {
                        if cursorpos + 1 < buf.len() {
                            // not at end
                            cstate = Cursorstate::Leftnibble;
                            cursorpos += 1;
                        }
                    }
                }
                Rule::start => {
                    cursorpos -= cursorpos % SPALTEN; // jump to start of line
                    if cstate == Cursorstate::Rightnibble {
                        cstate = Cursorstate::Leftnibble;
                    }
                }
                Rule::end => {
                    // check if no overflow
                    if cursorpos - (cursorpos % SPALTEN) + (SPALTEN - 1) < buf.len() {
                        // jump to end of line
                        cursorpos = cursorpos - (cursorpos % SPALTEN) + (SPALTEN - 1);
                    } else {
                        // jump to end of line
                        cursorpos = buf.len() - 1
                    }
                    if cstate == Cursorstate::Leftnibble {
                        cstate = Cursorstate::Rightnibble;
                    }
                }
                Rule::bottom => {
                    cursorpos = buf.len() - 1;
                    cursorpos -= cursorpos % SPALTEN; // jump to start of line
                }
                Rule::replace => {
                    // debug.push_str("next char will be the replacement!");
                    clear = false;
                }
                Rule::remove => {
                    // check if in valid range
                    if buf.len() > 0 && cursorpos < buf.len() {
                        // remove the current char
                        buf.remove(cursorpos);
                    }
                    // always perform the movement if possible
                    if cursorpos > 0 && cursorpos >= buf.len() {
                        cursorpos -= 1;
                    }
                    lastcommand = command.clone();
                }
                Rule::insert => {
                    // debug.push_str("next chars will be inserted!");
                    clear = false;
                }
                Rule::jumpascii => {
                    if cstate == Cursorstate::Asciichar {
                        cstate = Cursorstate::Leftnibble;
                    } else {
                        cstate = Cursorstate::Asciichar;
                    }
                }
                Rule::helpfile => {
                    command.push_str("No helpfile yet");
                }
                Rule::repeat => {
                    command = lastcommand.clone();
                    clear = false;
                    autoparse = true;
                }
                Rule::backspace => {
                    command.pop();
                    command.pop();
                    clear = false;
                }
                Rule::saveandexit => {
                    save = true;
                    quitnow = true;
                }
                Rule::exit => quitnow = true,
                Rule::save => save = true,

                _ => (),
            }

            for inner_cmd in cmd.into_inner() {
                match inner_cmd.as_rule() {
                    Rule::replacement => {
                        let key = inner_cmd.as_str().chars().nth(0).unwrap_or('x');
                        if cstate == Cursorstate::Asciichar {
                            if cursorpos >= buf.len() {
                                buf.insert(cursorpos, 0);
                            }
                            // buf[cursorpos] = inner_cmd.as_str();
                            buf[cursorpos] = key as u8;
                        } else {
                            let mask = if cstate == Cursorstate::Leftnibble {
                                0x0F
                            } else {
                                0xF0
                            };
                            let shift = if cstate == Cursorstate::Leftnibble {
                                4
                            } else {
                                0
                            };
                            if cursorpos >= buf.len() {
                                buf.insert(cursorpos, 0);
                            }
                            // Change the selected nibble
                            if let Some(c) = key.to_digit(16) {
                                buf[cursorpos] = buf[cursorpos] & mask | (c as u8) << shift;
                            }
                        }
                        lastcommand.clear();
                        lastcommand.push_str(&format!("{}{}", command.chars().nth(0).unwrap_or('?'), key ));
                    }
                    Rule::dd_lines => {
                        let amount: usize = inner_cmd.as_str().parse().unwrap_or(1);
                        // check if in valid range
                        if buf.len() > 0 && cursorpos < buf.len() {
                            let startofline = cursorpos - cursorpos % SPALTEN;
                            let mut endofline = cursorpos - (cursorpos % SPALTEN) + (SPALTEN * amount ) ;
                            endofline = cmp::min( endofline, buf.len() );
                            buf.drain(startofline..endofline);
                        }
                        lastcommand = command.clone();
                    }
                    Rule::insertment => {
                        let key = inner_cmd.as_str().chars().nth(0).unwrap_or('x');
                        lastcommand = command.clone();
                        // debug.push_str(&format!("Inserted: {:?}", inner_cmd.as_str()));
                        command.pop(); // remove the just inserted thing
                        clear = false;

                        if cstate == Cursorstate::Leftnibble {
                            // Left nibble
                            if let Some(c) = key.to_digit(16) {
                                buf.insert(cursorpos, (c as u8) << 4);
                                cstate = Cursorstate::Rightnibble;
                            }
                        } else if cstate == Cursorstate::Rightnibble {
                            // Right nibble
                            if cursorpos == buf.len() {
                                buf.insert(cursorpos, 0);
                            }
                            if let Some(c) = key.to_digit(16) {
                                buf[cursorpos] = buf[cursorpos] & 0xF0 | c as u8;
                                cstate = Cursorstate::Leftnibble;
                                cursorpos += 1;
                            }
                        } else if cstate == Cursorstate::Asciichar {
                            buf.insert(cursorpos, key as u8);
                            cursorpos += 1;
                        }
                        lastcommand.clear();
                        lastcommand.push_str(&format!("Command repeation for {:?} not yet implemented.", inner_cmd.as_rule()));
                    }
                    Rule::searchstr => {
                        let search = inner_cmd.as_str().as_bytes();
                        let foundpos = TwoWaySearcher::new(&search);
                        cursorpos = foundpos.search_in(&buf).unwrap_or(cursorpos);
                    }
                    Rule::searchbytes => {
                        let search = inner_cmd.as_str().as_bytes();
                        let mut needle = vec![];
                        for i in 0..search.len() {
                            let nibble = match search[i] as u8 {
                                c @ 48...57 => c - 48, // Numbers from 0 to 9
                                b'x' => 0x10, // x is the wildcard
                                b'X' => 0x10, // X is the wildcard
                                c @ b'a'...b'f' => c - 87,
                                c @ b'A'...b'F' => c - 55,
                                _ => panic!("Should not get to this position!"),
                            };
                            needle.push(nibble);
                        }
                        cursorpos = buf.find_subset(&needle).unwrap_or(cursorpos);
                        // debug.push_str(&format!("Searching for: {:?}", needle ));
                    }
                    Rule::gg_line => {
                        let linenr: usize = inner_cmd.as_str().parse().unwrap_or(0);
                        cursorpos = linenr * SPALTEN; // jump to the line
                        if cursorpos > buf.len() { // detect file end
                            cursorpos = buf.len();
                        }
                        cursorpos -= cursorpos % SPALTEN; // jump to start of line
                    }
                    Rule::escape => (),
                    Rule::gatherone => clear = false,
                    _ => {
                        command.push_str(&format!("no rule for {:?} ", inner_cmd.as_rule()));
                        clear = false;
                    }
                };
            }
            if save {
                if path.exists() {
                    let mut file = match OpenOptions::new()
                        .read(true)
                        .write(true)
                        .create(true)
                        .open(&path) {
                        Err(why) => {
                            panic!(
                                "Could not open {}: {}",
                                path.display(),
                                Error::description(&why)
                            )
                        }
                        Ok(file) => file,
                    };
                    file.seek(SeekFrom::Start(0)).ok().expect(
                        "Filepointer could not be set to 0",
                    );
                    file.write_all(&mut buf).ok().expect(
                        "File could not be written.",
                    );
                    file.set_len(buf.len() as u64).ok().expect(
                        "File could not be set to correct lenght.",
                    );
                    command.push_str("File saved!");
                } else {
                    command.push_str("Careful, file could not be saved!");
                }
                // TODO: define filename during runtime
                save = false;
            }
            if clear {
                command.clear();
            }

            // Always move screen when cursor leaves screen
            if cursorpos > (screenheight + screenoffset - 1) * SPALTEN - 1 {
                screenoffset = 2 + cursorpos / SPALTEN - screenheight;
            }
            if cursorpos < screenoffset * SPALTEN {
                screenoffset = cursorpos / SPALTEN;
            }

        }

    let draw_range = get_absolute_draw_indices(buf.len(), SPALTEN, screenoffset);
        draw(&buf[draw_range.0 .. draw_range.1], cursorpos, SPALTEN, &command, &mut debug, cstate, screenoffset);
    }

    refresh();
    endwin();
}
<|endoftext|>


<commit_before>extern crate polish;

use polish::test_case::{TestCaseStatus, TestCase, Testable, run_tests_from_class, statify};
use polish::logger::{Logger};

fn main () {
	struct MyTestCase;
	impl Testable for MyTestCase {
		fn tests (self) -> Vec<TestCase> {
			vec![
				TestCase::new("Some Title #1", "Testing Criteria", Box::new(|logger: &mut Logger| -> TestCaseStatus {
					logger.pass(format!("Good to go"));
					TestCaseStatus::PASSED
				})),
				TestCase::new("Some Title #2", "Testing Criteria", Box::new(|logger: &mut Logger| -> TestCaseStatus {
					logger.info(format!("Skipping this one"));
					TestCaseStatus::SKIPPED
				}))
			]
		}
	}
	let res = run_tests_from_class(MyTestCase{});
	statify(&res);
}
<commit_msg>removed main function<commit_after><|endoftext|>


<commit_before>extern crate rff;
extern crate clap;
extern crate rayon;

use std::io::{self, Write, BufWriter};
use rff::{stdin, match_and_score};
use rff::interface::{Interface, Error};
use clap::{App, Arg};
use rayon::prelude::*;

fn main() {
    let status_code = run();
    std::process::exit(status_code);
}

fn run() -> i32 {
    let matches = App::new("rff").
        version(env!("CARGO_PKG_VERSION")).
        author("Andrew S. <andrew@stwrt.ca>").
        about("A fuzzy finder.").
        arg(
            Arg::with_name("query").
                short("s").
                long("search").
                value_name("QUERY").
                help("Term to search for")
        ).
        arg(
            Arg::with_name("benchmark").
                long("benchmark").
                help("Run rff in benchmark mode")
        ).
        get_matches();

    let has_query = matches.is_present("query");
    let has_benchmark = matches.is_present("benchmark");

    if has_benchmark && !has_query {
        println!("Must specifiy -s/--search with --benchmark");
        return 1
    }

    if has_query {
        let query = matches.value_of("query").unwrap();

        if has_benchmark {
            benchmark(query);
        } else {
            search(query);
        }

        return 0
    } else {
        return interactive();
    }
}

fn benchmark(needle: &str) {
    let lines = stdin::slurp();

    // in benchmark mode, we run the match/score/sort loop 100 times
    for _ in 0..100 {
        lines
            .par_iter()
            .filter_map(|line| match_and_score(needle, line))
            .collect::<Vec<_>>()
            .sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());
    }
}

fn search(needle: &str) {
    let lines = stdin::slurp();
    let mut lines: Vec<_> = lines
        .par_iter()
        .filter_map(|line| match_and_score(needle, line))
        .collect();

    lines.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());

    let stdout = io::stdout();
    let mut stdout = BufWriter::new(stdout.lock());

    for line in &lines {
        writeln!(stdout, "{}", line.0).unwrap();
    }
}

fn interactive() -> i32 {
    let lines = stdin::slurp();

    match Interface::new(&lines).run() {
        Ok(result) => println!("{}", result),
        Err(Error::Exit) => { return 1 },
        Err(error) => {
            println!("{:?}", error);
            return 1
        },
    }

    return 0
}
<commit_msg>Print Interface errors to stderr<commit_after>extern crate rff;
extern crate clap;
extern crate rayon;

use std::io::{self, Write, BufWriter};
use rff::{stdin, match_and_score};
use rff::interface::{Interface, Error};
use clap::{App, Arg};
use rayon::prelude::*;

fn main() {
    let status_code = run();
    std::process::exit(status_code);
}

fn run() -> i32 {
    let matches = App::new("rff").
        version(env!("CARGO_PKG_VERSION")).
        author("Andrew S. <andrew@stwrt.ca>").
        about("A fuzzy finder.").
        arg(
            Arg::with_name("query").
                short("s").
                long("search").
                value_name("QUERY").
                help("Term to search for")
        ).
        arg(
            Arg::with_name("benchmark").
                long("benchmark").
                help("Run rff in benchmark mode")
        ).
        get_matches();

    let has_query = matches.is_present("query");
    let has_benchmark = matches.is_present("benchmark");

    if has_benchmark && !has_query {
        println!("Must specifiy -s/--search with --benchmark");
        return 1
    }

    if has_query {
        let query = matches.value_of("query").unwrap();

        if has_benchmark {
            benchmark(query);
        } else {
            search(query);
        }

        return 0
    } else {
        return interactive();
    }
}

fn benchmark(needle: &str) {
    let lines = stdin::slurp();

    // in benchmark mode, we run the match/score/sort loop 100 times
    for _ in 0..100 {
        lines
            .par_iter()
            .filter_map(|line| match_and_score(needle, line))
            .collect::<Vec<_>>()
            .sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());
    }
}

fn search(needle: &str) {
    let lines = stdin::slurp();
    let mut lines: Vec<_> = lines
        .par_iter()
        .filter_map(|line| match_and_score(needle, line))
        .collect();

    lines.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());

    let stdout = io::stdout();
    let mut stdout = BufWriter::new(stdout.lock());

    for line in &lines {
        writeln!(stdout, "{}", line.0).unwrap();
    }
}

fn interactive() -> i32 {
    let lines = stdin::slurp();

    match Interface::new(&lines).run() {
        Ok(result) => println!("{}", result),
        Err(Error::Exit) => { return 1 },
        Err(error) => {
            eprintln!("{:?}", error);
            return 1
        },
    }

    return 0
}
<|endoftext|>


<commit_before>#[macro_use]
mod macros;

mod agents;
mod bridges;
mod config;
mod crypto;
mod email_address;
mod error;
mod handlers;
mod router;
mod utils;
mod validation;
mod web;
mod webfinger;

use crate::config::{ConfigBuilder, ConfigRc};
use crate::utils::BoxError;
use crate::web::Service;
use futures_util::future;
use hyper::{server::Server, service::make_service_fn};
use log::info;
use serde_derive::Deserialize;
use std::net::SocketAddr;

/// Defines the program's version, as set by Cargo at compile time.
const VERSION: &str = env!("CARGO_PKG_VERSION");

/// Defines the program's usage string.
///
/// [Docopt](http://docopt.org) parses this and generates a custom argv parser.
const USAGE: &str = r#"
Portier Broker

Usage:
  portier-broker [CONFIG]
  portier-broker --version
  portier-broker --help

Options:
  --version       Print version information and exit
  --help          Print this help message and exit
"#;

/// Holds parsed command line parameters.
#[derive(Deserialize)]
#[allow(non_snake_case)]
struct Args {
    arg_CONFIG: Option<String>,
}

/// The `main()` method. Will loop forever to serve HTTP requests.
#[tokio::main]
async fn main() {
    env_logger::init();

    let args: Args = docopt::Docopt::new(USAGE)
        .map(|docopt| docopt.version(Some(VERSION.to_owned())))
        .and_then(|docopt| docopt.deserialize())
        .unwrap_or_else(|e| e.exit());

    let mut builder = ConfigBuilder::new();
    if let Some(ref path) = args.arg_CONFIG {
        builder.update_from_file(path);
    }
    builder.update_from_common_env();
    builder.update_from_broker_env();
    let app = ConfigRc::new(
        builder
            .done()
            .await
            .unwrap_or_else(|err| panic!(format!("failed to build configuration: {}", err))),
    );

    // TODO: Add unix socket support.
    let builder = match listenfd::ListenFd::from_env().take_tcp_listener(0) {
        Ok(Some(tcp_listener)) => {
            let builder = Server::from_tcp(tcp_listener).expect("Socket activation failed");
            info!("Listening on the socket received from the service manager");
            builder
        }
        Ok(None) => {
            let ip_addr = app
                .listen_ip
                .parse()
                .expect("Unable to parse listen address");
            let addr = SocketAddr::new(ip_addr, app.listen_port);
            let builder = Server::bind(&addr);
            info!("Listening on {}", addr);
            builder
        }
        Err(err) => {
            panic!("Socket activation failed: {}", err);
        }
    };

    #[cfg(unix)]
    sd_notify::notify(true, &[sd_notify::NotifyState::Ready])
        .expect("Failed to signal ready to the service manager");

    let make_service = make_service_fn(|stream| {
        let app = ConfigRc::clone(&app);
        future::ok::<_, BoxError>(Service::new(app, stream))
    });
    builder.serve(make_service).await.expect("Server error");
}
<commit_msg>Ensure panics cause the entire process to exit.<commit_after>#[macro_use]
mod macros;

mod agents;
mod bridges;
mod config;
mod crypto;
mod email_address;
mod error;
mod handlers;
mod router;
mod utils;
mod validation;
mod web;
mod webfinger;

use crate::config::{ConfigBuilder, ConfigRc};
use crate::utils::BoxError;
use crate::web::Service;
use futures_util::future;
use hyper::{server::Server, service::make_service_fn};
use log::info;
use serde_derive::Deserialize;
use std::net::SocketAddr;

/// Defines the program's version, as set by Cargo at compile time.
const VERSION: &str = env!("CARGO_PKG_VERSION");

/// Defines the program's usage string.
///
/// [Docopt](http://docopt.org) parses this and generates a custom argv parser.
const USAGE: &str = r#"
Portier Broker

Usage:
  portier-broker [CONFIG]
  portier-broker --version
  portier-broker --help

Options:
  --version       Print version information and exit
  --help          Print this help message and exit
"#;

/// Holds parsed command line parameters.
#[derive(Deserialize)]
#[allow(non_snake_case)]
struct Args {
    arg_CONFIG: Option<String>,
}

/// The `main()` method. Will loop forever to serve HTTP requests.
#[tokio::main]
async fn main() {
    env_logger::init();

    // We spawn a bunch of background tasks on the Tokio executor. If these panic, we want to exit
    // instead of continuing on without the task.
    let next_panic_hook = std::panic::take_hook();
    std::panic::set_hook(Box::new(move |info| {
        next_panic_hook(info);
        std::process::exit(1);
    }));

    let args: Args = docopt::Docopt::new(USAGE)
        .map(|docopt| docopt.version(Some(VERSION.to_owned())))
        .and_then(|docopt| docopt.deserialize())
        .unwrap_or_else(|e| e.exit());

    let mut builder = ConfigBuilder::new();
    if let Some(ref path) = args.arg_CONFIG {
        builder.update_from_file(path);
    }
    builder.update_from_common_env();
    builder.update_from_broker_env();
    let app = ConfigRc::new(
        builder
            .done()
            .await
            .unwrap_or_else(|err| panic!(format!("failed to build configuration: {}", err))),
    );

    // TODO: Add unix socket support.
    let builder = match listenfd::ListenFd::from_env().take_tcp_listener(0) {
        Ok(Some(tcp_listener)) => {
            let builder = Server::from_tcp(tcp_listener).expect("Socket activation failed");
            info!("Listening on the socket received from the service manager");
            builder
        }
        Ok(None) => {
            let ip_addr = app
                .listen_ip
                .parse()
                .expect("Unable to parse listen address");
            let addr = SocketAddr::new(ip_addr, app.listen_port);
            let builder = Server::bind(&addr);
            info!("Listening on {}", addr);
            builder
        }
        Err(err) => {
            panic!("Socket activation failed: {}", err);
        }
    };

    #[cfg(unix)]
    sd_notify::notify(true, &[sd_notify::NotifyState::Ready])
        .expect("Failed to signal ready to the service manager");

    let make_service = make_service_fn(|stream| {
        let app = ConfigRc::clone(&app);
        future::ok::<_, BoxError>(Service::new(app, stream))
    });
    builder.serve(make_service).await.expect("Server error");
}
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate assimp;
extern crate cgmath;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;
use cgmath::InnerSpace;
use cgmath::Vector3;
use cgmath::Vector4;
use cgmath::Zero;
use cgmath::Matrix4;
use cgmath::SquareMatrix;

static WIDTH: u32 = 700;
static HEIGHT: u32 = 700;
static mut Z_BUFFER: [f32; 800 * 800] = [-1.; 800 * 800];

fn sort_points_by_y(points: &mut Vec<Vector3<f32>>) {
    for _ in 0..(points.len() - 1) {
        for j in 0..(points.len() - 1) {
            if points[j].y > points[j + 1].y {
                points.swap(j, j + 1);
            }
        }
    }
}

fn clamp<N>(a: N, min: N, max: N) -> N where N: PartialOrd {
    if a < min { return min }
    if a > max { return max }
    a
}

fn interpolate(min: f32, max: f32, gradient: f32) -> f32 {
    min + (max - min) * clamp(gradient, 0., 1.)
}

fn get_line_points(start: Point, end: Point) -> Vec<Point> {
    let mut x0 = start.x();
    let mut y0 = start.y();
    let mut x1 = end.x();
    let mut y1 = end.y();

    let steep = (y1 - y0).abs() > (x1 - x0).abs();

    if steep {
        std::mem::swap(&mut x0, &mut y0);
        std::mem::swap(&mut x1, &mut y1);
    }

    let reverse = x0 > x1;

    if reverse {
        std::mem::swap(&mut x0, &mut x1);
        std::mem::swap(&mut y0, &mut y1);
    }

    let dx = x1 - x0;
    let dy = (y1 - y0).abs();

    let mut err = dx / 2;
    let mut y = y0;
    let ystep = match y0.cmp(&y1) {
        Ordering::Less => 1,
        _ => -1
    };

    let mut points: Vec<Point> = vec![];

    for x in x0..x1 {
        if steep {
            points.push(Point::new(y, x));
        } else {
            points.push(Point::new(x, y));
        }

        err -= dy;

        if err < 0 {
            y += ystep;
            err += dx;
        }
    }

    points
}

trait TinyRenderer {
    fn pixel(&mut self, i32, i32, f32, Color);
    fn point(&mut self, Vector3<f32>, Color);
    fn line(&mut self, Point, Point, Color);
    fn process_scan_line(&mut self, i32, Vector3<f32>, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
    fn triangle(&mut self, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, x: i32, y: i32, z: f32, c: Color, ) {
        let index = (x + y * WIDTH as i32) as usize;

        if unsafe { Z_BUFFER[index] < z } {
            let current_color = self.draw_color();
            self.set_draw_color(c);

            self.draw_point(Point::new(x, y)).unwrap();

            unsafe {
                Z_BUFFER[index] = z;
            }

            self.set_draw_color(current_color);
        }
    }

    fn point(&mut self, p: Vector3<f32>, c: Color) {
        if p.x >= 0. && p.y >= 0. && p.x < WIDTH as f32 && p.y < HEIGHT as f32 {
            self.pixel(p.x as i32, p.y as i32, p.z, c);
        }
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let points = get_line_points(start, end);

        for p in 0..points.len() {
            self.draw_point(points[p]).unwrap();
        }

        self.set_draw_color(current_color);
    }

    fn process_scan_line(&mut self, y: i32, pa: Vector3<f32>, pb: Vector3<f32>, pc: Vector3<f32>, pd: Vector3<f32>, c: Color) {
        let grad1 = match (pa.y as i32).cmp(&(pb.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pa.y) / (pb.y - pa.y)
        };

        let grad2 = match (pc.y as i32).cmp(&(pd.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pc.y) / (pd.y - pc.y)
        };

        let mut sx = interpolate(pa.x, pb.x, grad1) as i32;
        let mut ex = interpolate(pc.x, pd.x, grad2) as i32;

        if sx > ex {
            std::mem::swap(&mut sx, &mut ex);
        }

        let z1 = interpolate(pa.z, pb.z, grad1);
        let z2 = interpolate(pc.z, pd.z, grad2);

        for x in sx..ex {
            let gradient = (x - sx) as f32 / (ex - sx) as f32;

            let z = interpolate(z1, z2, gradient);
            self.point(Vector3::<f32>::new(x as f32, y as f32, z), c);
        }
    }

    fn triangle(&mut self, p0: Vector3<f32>, p1: Vector3<f32>, p2: Vector3<f32>, c: Color) {
        let mut points = vec![p0, p1, p2];
        sort_points_by_y(&mut points);

        let dp0p1 = match ((points[1].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[1].x - points[0].x) / (points[1].y - points[0].y),
            _ => 0.
        };

        let dp0p2 = match ((points[2].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[2].x - points[0].x) / (points[2].y - points[0].y),
            _ => 0.
        };

        for y in points[0].y as i32..points[2].y as i32 {
            if y < points[1].y as i32 {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[0], points[1], c);
                } else {
                    self.process_scan_line(y, points[0], points[1], points[0], points[2], c);
                }
            } else {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[1], points[2], c);
                } else {
                    self.process_scan_line(y, points[1], points[2], points[0], points[2], c);
                }
            }
        }
    }
}

fn viewport(x: f32, y: f32, w: f32, h: f32) -> Matrix4<f32> {
    let mut viewport = Matrix4::<f32>::identity();
    viewport[3][0] = x + w / 2.;
    viewport[3][1] = y + h / 2.;
    viewport[3][2] = 255. / 2.; //depth

    viewport[0][0] = w / 2.;
    viewport[1][1] = h / 2.;
    viewport[2][2] = 255. / 2.;
    return viewport;
}

// Matrix lookat(Vec3f eye, Vec3f center, Vec3f up) {
//     Vec3f z = (eye-center).normalize();
//     Vec3f x = (up^z).normalize();
//     Vec3f y = (z^x).normalize();
//     Matrix res = Matrix::identity(4);
//     for (int i=0; i<3; i++) {
//         res[0][i] = x[i];
//         res[1][i] = y[i];
//         res[2][i] = z[i];
//         res[i][3] = -center[i];
//     }
//     return res;
// }

fn main() {
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", WIDTH, HEIGHT)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    let camera = Vector3::new(0., 0., 3.);
    let light_dir = Vector3::new(0., 0., -1.).normalize();
    let mut projection = Matrix4::<f32>::identity();
    let (x, y, w, h) = (WIDTH as f32 / 8., HEIGHT as f32 / 8., WIDTH as f32 * 3. / 4., HEIGHT as f32 * 3. / 4.);
    let viewport = viewport(x, y, w, h);

    projection[2][3] = -1. / camera.z;

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            let mut screen_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];
            let mut world_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];

            for j in 0..3 {
                let v: Vector3<f32> = match mesh.get_vertex(face[j]) {
                    Some(x) => x.into(),
                    None => Vector3::<f32>::new(0., 0., 0.)
                };

                //let (p1, p2) = ((v.x + 1.) * WIDTH as f32 / 2., (v.y + 1.) * HEIGHT as f32 / 2.);
                // m2v(ViewPort*Projection*ModelView*Matrix(v));
                let m = viewport * projection * Vector4::<f32>::new(v.x, v.y, v.z, 1.);
                let result_vector = Vector3::<f32>::new(m.x / m.w, HEIGHT as f32 - (m.y / m.w), m.z / m.w);

                screen_coords[j as usize] = result_vector;

                world_coords[j as usize] = v;
            }

            let n = (world_coords[2] - world_coords[0]).cross(world_coords[1] - world_coords[0]).normalize();
            let intensity = n.dot(light_dir);

            if intensity > 0.0 { // back-face culling
                renderer.triangle(
                    screen_coords[0],
                    screen_coords[1],
                    screen_coords[2],
                    Color::RGB(
                        (intensity * 255.) as u8,
                        (intensity * 255.) as u8,
                        (intensity * 255.) as u8
                    )
                );
            }
        }
    }

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<commit_msg>Implemented camera moving projection features && meshe's normal based intensity calc<commit_after>extern crate sdl2;
extern crate assimp;
extern crate cgmath;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;
use cgmath::InnerSpace;
use cgmath::Vector3;
use cgmath::Vector4;
use cgmath::Zero;
use cgmath::Matrix4;
use cgmath::SquareMatrix;

static WIDTH: u32 = 700;
static HEIGHT: u32 = 700;
static mut Z_BUFFER: [f32; 800 * 800] = [-1.; 800 * 800];

fn sort_points_by_y(points: &mut Vec<Vector3<f32>>) {
    for _ in 0..(points.len() - 1) {
        for j in 0..(points.len() - 1) {
            if points[j].y > points[j + 1].y {
                points.swap(j, j + 1);
            }
        }
    }
}

fn clamp<N>(a: N, min: N, max: N) -> N where N: PartialOrd {
    if a < min { return min }
    if a > max { return max }
    a
}

fn interpolate(min: f32, max: f32, gradient: f32) -> f32 {
    min + (max - min) * clamp(gradient, 0., 1.)
}

fn get_line_points(start: Point, end: Point) -> Vec<Point> {
    let mut x0 = start.x();
    let mut y0 = start.y();
    let mut x1 = end.x();
    let mut y1 = end.y();

    let steep = (y1 - y0).abs() > (x1 - x0).abs();

    if steep {
        std::mem::swap(&mut x0, &mut y0);
        std::mem::swap(&mut x1, &mut y1);
    }

    let reverse = x0 > x1;

    if reverse {
        std::mem::swap(&mut x0, &mut x1);
        std::mem::swap(&mut y0, &mut y1);
    }

    let dx = x1 - x0;
    let dy = (y1 - y0).abs();

    let mut err = dx / 2;
    let mut y = y0;
    let ystep = match y0.cmp(&y1) {
        Ordering::Less => 1,
        _ => -1
    };

    let mut points: Vec<Point> = vec![];

    for x in x0..x1 {
        if steep {
            points.push(Point::new(y, x));
        } else {
            points.push(Point::new(x, y));
        }

        err -= dy;

        if err < 0 {
            y += ystep;
            err += dx;
        }
    }

    points
}

trait TinyRenderer {
    fn pixel(&mut self, i32, i32, f32, Color);
    fn point(&mut self, Vector3<f32>, Color);
    fn line(&mut self, Point, Point, Color);
    fn process_scan_line(&mut self, i32, Vector3<f32>, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
    fn triangle(&mut self, Vector3<f32>, Vector3<f32>, Vector3<f32>, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, x: i32, y: i32, z: f32, c: Color, ) {
        let index = (x + y * WIDTH as i32) as usize;

        if unsafe { Z_BUFFER[index] < z } {
            let current_color = self.draw_color();
            self.set_draw_color(c);

            self.draw_point(Point::new(x, y)).unwrap();

            unsafe {
                Z_BUFFER[index] = z;
            }

            self.set_draw_color(current_color);
        }
    }

    fn point(&mut self, p: Vector3<f32>, c: Color) {
        if p.x >= 0. && p.y >= 0. && p.x < WIDTH as f32 && p.y < HEIGHT as f32 {
            self.pixel(p.x as i32, p.y as i32, p.z, c);
        }
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let points = get_line_points(start, end);

        for p in 0..points.len() {
            self.draw_point(points[p]).unwrap();
        }

        self.set_draw_color(current_color);
    }

    fn process_scan_line(&mut self, y: i32, pa: Vector3<f32>, pb: Vector3<f32>, pc: Vector3<f32>, pd: Vector3<f32>, c: Color) {
        let grad1 = match (pa.y as i32).cmp(&(pb.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pa.y) / (pb.y - pa.y)
        };

        let grad2 = match (pc.y as i32).cmp(&(pd.y as i32)) {
            Ordering::Equal => 1.,
            _ => (y as f32 - pc.y) / (pd.y - pc.y)
        };

        let mut sx = interpolate(pa.x, pb.x, grad1) as i32;
        let mut ex = interpolate(pc.x, pd.x, grad2) as i32;

        if sx > ex {
            std::mem::swap(&mut sx, &mut ex);
        }

        let z1 = interpolate(pa.z, pb.z, grad1);
        let z2 = interpolate(pc.z, pd.z, grad2);

        for x in sx..ex {
            let gradient = (x - sx) as f32 / (ex - sx) as f32;

            let z = interpolate(z1, z2, gradient);
            self.point(Vector3::<f32>::new(x as f32, y as f32, z), c);
        }
    }

    fn triangle(&mut self, p0: Vector3<f32>, p1: Vector3<f32>, p2: Vector3<f32>, c: Color) {
        let mut points = vec![p0, p1, p2];
        sort_points_by_y(&mut points);

        let dp0p1 = match ((points[1].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[1].x - points[0].x) / (points[1].y - points[0].y),
            _ => 0.
        };

        let dp0p2 = match ((points[2].y - points[0].y) as i32).cmp(&0) {
            Ordering::Greater => (points[2].x - points[0].x) / (points[2].y - points[0].y),
            _ => 0.
        };

        for y in points[0].y as i32..points[2].y as i32 {
            if y < points[1].y as i32 {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[0], points[1], c);
                } else {
                    self.process_scan_line(y, points[0], points[1], points[0], points[2], c);
                }
            } else {
                if dp0p1 > dp0p2 {
                    self.process_scan_line(y, points[0], points[2], points[1], points[2], c);
                } else {
                    self.process_scan_line(y, points[1], points[2], points[0], points[2], c);
                }
            }
        }
    }
}

fn viewport(x: f32, y: f32, w: f32, h: f32) -> Matrix4<f32> {
    let mut viewport = Matrix4::<f32>::identity();
    viewport[3][0] = x + w / 2.;
    viewport[3][1] = y + h / 2.;
    viewport[3][2] = 255. / 2.; //depth

    viewport[0][0] = w / 2.;
    viewport[1][1] = h / 2.;
    viewport[2][2] = 255. / 2.;
    return viewport;
}

fn lookat(eye: Vector3<f32>, center: Vector3<f32>, up: Vector3<f32>) -> Matrix4<f32> {
    let z = (eye - center).normalize();
    let x = up.cross(z).normalize();
    let y = z.cross(x).normalize();
    let mut res = Matrix4::<f32>::identity();

    for i in 0..3 {
        res[i][0] = x[i];
        res[i][1] = y[i];
        res[i][2] = z[i];
        res[3][i] = -center[i];
    }

    return res;
}

fn normal(v: Vector3<f32>) -> f32 {
    (v.x * v.x + v.y * v.y + v.z * v.z).sqrt()
}

fn main() {
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", WIDTH, HEIGHT)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();
    // front: ( 0,  0,  3)
    // back:  ( 0,  0, -3)
    // left:  (-3,  0,  0)
    // right: ( 3,  0,  0)
    // top:   ( 0,  3,  0.1) ?
    // down:  ( 0, -3,  0.1) ?
    let eye = Vector3::new(1., 1., 3.);
    let center = Vector3::new(0., 0., 0.);

    let model_view = lookat(eye, center, Vector3::new(0., 1., 0.));
    let light_dir = Vector3::new(0., -1., -3.).normalize();
    let mut projection = Matrix4::<f32>::identity();
    let (x, y, w, h) = (WIDTH as f32 / 8., HEIGHT as f32 / 8., WIDTH as f32 * 3. / 4., HEIGHT as f32 * 3. / 4.);
    let viewport = viewport(x, y, w, h);

    projection[2][3] = -1. / normal(eye - center);

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            let mut screen_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];
            let mut world_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];
            let mut intensity: [f32; 3] = [0.; 3];

            for j in 0..3 {
                let v: Vector3<f32> = match mesh.get_vertex(face[j]) {
                    Some(x) => x.into(),
                    None => Vector3::new(0., 0., 0.)
                };

                let mesh_normal: Vector3<f32> = match mesh.get_normal(face[j]) {
                    Some(x) => x.into(),
                    None => Vector3::new(0., 0., 0.)
                };

                let m = viewport * projection * model_view * Vector4::<f32>::new(v.x, v.y, v.z, 1.);
                let result_vector = Vector3::new(m.x / m.w, HEIGHT as f32 - (m.y / m.w), m.z / m.w);

                screen_coords[j as usize] = result_vector;
                world_coords[j as usize] = v;
                intensity[j as usize] = mesh_normal.dot(light_dir);
            }

            renderer.triangle(
                screen_coords[0],
                screen_coords[1],
                screen_coords[2],
                Color::RGB(
                    (intensity[0] * 255.) as u8,
                    (intensity[1] * 255.) as u8,
                    (intensity[2] * 255.) as u8
                )
            );
        }
    }

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate docopt;

use std::cmp::max;
use std::fmt::Result as FmtResult;
use std::fmt::{Display, Formatter};
use std::fs::File;
use std::io::Error as IOError;
use std::io::{BufReader, stderr, stdin};
use std::io::{Write, BufRead, Read};
use std::process::exit;
use std::str::{Utf8Error, from_utf8};
use docopt::Docopt;

static LF: char = '\n';
static NULL: char = '\0';
static VERSION: &'static str = "0.0.1";
static USAGE: &'static str = "
Usage: wc [options] FILE...
       wc [options] --files0-from=F
       wc (-h|--help)
       wc (-v|--version)

Print newline, word, and byte counts for each FILE, and a total line if
more than one FILE is specified. With no FILE, or when FILE is -,
read standard input. A word is a non-zero-length sequence of characters
delimited by white space.
The options below may be used to select which counts are printed, always in
the following order: newline, word, character, byte, maximum line length.

Options:
   -c, --bytes            print the byte counts
   -m, --chars            print the character counts
   -l, --lines            print the newline counts
   --files0-from=F        read input from the files specified by NUL-terminated
                          names in file F; If F is - then read names from
                          standard input
   -L, --max-line-length  print the length of the longest line
   -w, --words            print the word counts
   -h, --help             display this help and quit
   -v, --version          output version information and exit
";

#[allow(non_snake_case)]
#[derive(RustcDecodable, Debug)]
struct Args {
    arg_FILE: Vec<String>,
    flag_bytes: bool,
    flag_chars: bool,
    flag_lines: bool,
    flag_max_line_length: bool,
    flag_words: bool,
    flag_help: bool,
    flag_version: bool,
    flag_files0_from: String,
}

macro_rules! print_stderr(
    ($($arg:tt)*) => (
        match write!(&mut stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
        )
        );

macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
        )
        );

#[derive(Debug)]
enum WCError {
    IO(IOError),
    Utf8(Utf8Error),
}

type WCResult<T> = Result<T, WCError>;

impl Display for WCError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            WCError::IO(ref e) => write!(f, "{}", e),
            WCError::Utf8(ref e) => write!(f, "{}", e),
        }
    }
}

impl From<IOError> for WCError {
    fn from(e: IOError) -> WCError {
        WCError::IO(e)
    }
}
impl From<Utf8Error> for WCError {
    fn from(e: Utf8Error) -> WCError {
        WCError::Utf8(e)
    }
}

#[derive(Debug)]
struct FileInfo{
    bytes: usize,
    chars: usize,
    lines: usize,
    words: usize,
    max_line_length: usize,
}

impl FileInfo {
    fn new() -> FileInfo {
        FileInfo{bytes: 0,
                 chars: 0,
                 lines: 0,
                 words: 0,
                 max_line_length: 0,
        }
    }
}

fn display(args: &Args, filename: &str, result: &WCResult<FileInfo>,
           field_size: usize) -> bool {
    match *result {
        Ok(ref r) => {
            if args.flag_lines {
                print!("{:1$} ", r.lines, field_size);
            }
            if args.flag_words {
                print!("{:1$} ", r.words, field_size);
            }
            if args.flag_bytes {
                print!("{:1$} ", r.bytes, field_size);
            }
            if args.flag_chars {
                print!("{:1$} ", r.chars, field_size);
            }
            if args.flag_max_line_length {
                print!("{:1$} ", r.max_line_length, field_size);
            }
            println!("{}", filename);
            true
        },
        Err(ref e) => {
            println_stderr!("wc: {}: {}", filename, e);
            false
        },
    }
}

// Return the named file, but opened, and in a result that's usable as
// a buffered reader. In the case of a filename "-", return an
// appropriately wrapped Stdin.
fn open_file(filename: &str) -> WCResult<Box<BufRead>> {
    match filename {
        "-" => Ok(Box::new(BufReader::new(stdin()))),
        _ => Ok(Box::new(BufReader::new(try!(File::open(filename))))),
    }
}

// TODO Only perform minimum processing based on requested data
fn process_file<T: BufRead>(mut file: T, args: &Args) -> WCResult<FileInfo> {
    let mut info = FileInfo::new();
    let mut lbuf = Vec::new();
    loop {
        let size = try!(file.read_until(LF as u8, &mut lbuf));
        info.bytes += size;
        if size == 0 {
            break;
        }
        // If this if statement wasn't here, we would still need to
        // create a scope because we're going to borrow lbuf and the
        // borrow must end before we can clear it.
        if args.flag_lines || args.flag_words || args.flag_chars ||
            args.flag_max_line_length {
                // TODO: Handle files which are not utf8-encoded. Right
                // now we get an error here.
                let line = try!(from_utf8(&lbuf));

                let size = if args.flag_chars || args.flag_max_line_length {
                    line.chars().count()
                } else { 0 };

                let last = if args.flag_lines || args.flag_max_line_length {
                    line.chars().last().unwrap_or(NULL)
                } else { NULL };

                if last == LF {
                    info.lines += 1;
                }

                if args.flag_max_line_length {
                    info.max_line_length = if last == LF {
                        max(info.max_line_length, size - 1)
                    } else {
                        max(info.max_line_length, size)
                    };
                }

                info.chars += size;

                if args.flag_words {
                    let mut words: Vec<&str> = line
                        .split(|c: char| c.is_whitespace())
                        .collect();
                    words.retain(|s: &&str| s.len() > 0);
                    info.words += words.len();
                }
            }
        lbuf.clear()
    }
    Ok(info)
}

// Open the file (possibly - for stdin) and return an array of strings
// reflecting the contents of the file, split on null characters.
fn process_files0_from(filename: &str) -> WCResult<Vec<String>> {
    let mut file = try!(open_file(filename));
    let mut result = Vec::new();
    let mut lbuf = Vec::new();
    loop {
        let size = try!(file.read_until(NULL as u8, &mut lbuf));
        if size == 0 {
            break;
        }
        // Create a scope because we're going to borrow lbuf and
        // the borrow must end before we can clear it.
        {
            let line = try!(from_utf8(&lbuf));
            result.push(line.trim_right_matches(NULL).to_string());
        }
        lbuf.clear()
    }
    Ok(result)
}

fn main() {
    let mut args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("wc v{}", VERSION);
        exit(0);
    }

    if args.flag_files0_from.len() != 0  && args.arg_FILE.len() != 0 {
        print_stderr!("wc: file operands cannot be combined with ");
        println_stderr!("--files0-from");
        println_stderr!("Try 'wc --help' for more information");
        exit(1);
    }

    if !(args.flag_lines || args.flag_words || args.flag_bytes
         || args.flag_chars || args.flag_max_line_length) {
        args.flag_lines = true;
        args.flag_words = true;
        args.flag_bytes = true;
    }
    let mut files: Vec<String> = Vec::new();
    if args.flag_files0_from.len() != 0 {
        match process_files0_from(args.flag_files0_from.as_ref()) {
            Ok(parts) => files.extend(parts),
            Err(e) => {
                println_stderr!("wc: error reading {}: {}",
                                args.flag_files0_from, e);
                exit(1);
            },
        };
        if &args.flag_files0_from == "-" && files.contains(&"-".to_string()) {
            print_stderr!("wc: when reading file names from stdin, no file ");
            println_stderr!("name of '-' allowed");
            exit(1);
        }
    } else {
        files.extend(args.arg_FILE.clone());
    };

    let results: Vec<WCResult<FileInfo>> = files.iter()
        .map(|f| f.as_ref())
        .map(|f|
             match open_file(f) {
                 Ok(f) => process_file(f, &args),
                 Err(e) => Err(e),
             })
        .collect();

    let total: FileInfo = results.iter()
        .filter(|r| r.as_ref().is_ok())
        .map(|r| r.as_ref().unwrap())
        .fold(FileInfo::new(),
              |acc, item|
              FileInfo{
                  bytes: acc.bytes + item.bytes,
                  chars: acc.chars + item.chars,
                  lines: acc.lines + item.lines,
                  words: acc.words + item.words,
                  max_line_length: max(acc.max_line_length,
                                       item.max_line_length),
              });

    // This is used for formatting. The number in the byte count will
    // be the largest, and so will be the widest string, so it's
    // suitable for a field width.
    let field_size = total.bytes.to_string().len();

    // For determining eventual exit code
    let mut ok = true;

    // Present the results
    for data in files.iter().zip(results.iter()) {
        let (filename, result) = data;
        ok &= display(&args, filename, result, field_size)
    }
    if results.len() > 1 {
        display(&args, "-", &Ok(total), field_size);
    }
    if !ok {
        exit(1);
    }
}
<commit_msg>Label the total "total", not "-"<commit_after>extern crate rustc_serialize;
extern crate docopt;

use std::cmp::max;
use std::fmt::Result as FmtResult;
use std::fmt::{Display, Formatter};
use std::fs::File;
use std::io::Error as IOError;
use std::io::{BufReader, stderr, stdin};
use std::io::{Write, BufRead, Read};
use std::process::exit;
use std::str::{Utf8Error, from_utf8};
use docopt::Docopt;

static LF: char = '\n';
static NULL: char = '\0';
static VERSION: &'static str = "0.0.1";
static USAGE: &'static str = "
Usage: wc [options] FILE...
       wc [options] --files0-from=F
       wc (-h|--help)
       wc (-v|--version)

Print newline, word, and byte counts for each FILE, and a total line if
more than one FILE is specified. With no FILE, or when FILE is -,
read standard input. A word is a non-zero-length sequence of characters
delimited by white space.
The options below may be used to select which counts are printed, always in
the following order: newline, word, character, byte, maximum line length.

Options:
   -c, --bytes            print the byte counts
   -m, --chars            print the character counts
   -l, --lines            print the newline counts
   --files0-from=F        read input from the files specified by NUL-terminated
                          names in file F; If F is - then read names from
                          standard input
   -L, --max-line-length  print the length of the longest line
   -w, --words            print the word counts
   -h, --help             display this help and quit
   -v, --version          output version information and exit
";

#[allow(non_snake_case)]
#[derive(RustcDecodable, Debug)]
struct Args {
    arg_FILE: Vec<String>,
    flag_bytes: bool,
    flag_chars: bool,
    flag_lines: bool,
    flag_max_line_length: bool,
    flag_words: bool,
    flag_help: bool,
    flag_version: bool,
    flag_files0_from: String,
}

macro_rules! print_stderr(
    ($($arg:tt)*) => (
        match write!(&mut stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
        )
        );

macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
        )
        );

#[derive(Debug)]
enum WCError {
    IO(IOError),
    Utf8(Utf8Error),
}

type WCResult<T> = Result<T, WCError>;

impl Display for WCError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            WCError::IO(ref e) => write!(f, "{}", e),
            WCError::Utf8(ref e) => write!(f, "{}", e),
        }
    }
}

impl From<IOError> for WCError {
    fn from(e: IOError) -> WCError {
        WCError::IO(e)
    }
}
impl From<Utf8Error> for WCError {
    fn from(e: Utf8Error) -> WCError {
        WCError::Utf8(e)
    }
}

#[derive(Debug)]
struct FileInfo{
    bytes: usize,
    chars: usize,
    lines: usize,
    words: usize,
    max_line_length: usize,
}

impl FileInfo {
    fn new() -> FileInfo {
        FileInfo{bytes: 0,
                 chars: 0,
                 lines: 0,
                 words: 0,
                 max_line_length: 0,
        }
    }
}

fn display(args: &Args, filename: &str, result: &WCResult<FileInfo>,
           field_size: usize) -> bool {
    match *result {
        Ok(ref r) => {
            if args.flag_lines {
                print!("{:1$} ", r.lines, field_size);
            }
            if args.flag_words {
                print!("{:1$} ", r.words, field_size);
            }
            if args.flag_bytes {
                print!("{:1$} ", r.bytes, field_size);
            }
            if args.flag_chars {
                print!("{:1$} ", r.chars, field_size);
            }
            if args.flag_max_line_length {
                print!("{:1$} ", r.max_line_length, field_size);
            }
            println!("{}", filename);
            true
        },
        Err(ref e) => {
            println_stderr!("wc: {}: {}", filename, e);
            false
        },
    }
}

// Return the named file, but opened, and in a result that's usable as
// a buffered reader. In the case of a filename "-", return an
// appropriately wrapped Stdin.
fn open_file(filename: &str) -> WCResult<Box<BufRead>> {
    match filename {
        "-" => Ok(Box::new(BufReader::new(stdin()))),
        _ => Ok(Box::new(BufReader::new(try!(File::open(filename))))),
    }
}

// TODO Only perform minimum processing based on requested data
fn process_file<T: BufRead>(mut file: T, args: &Args) -> WCResult<FileInfo> {
    let mut info = FileInfo::new();
    let mut lbuf = Vec::new();
    loop {
        let size = try!(file.read_until(LF as u8, &mut lbuf));
        info.bytes += size;
        if size == 0 {
            break;
        }
        // If this if statement wasn't here, we would still need to
        // create a scope because we're going to borrow lbuf and the
        // borrow must end before we can clear it.
        if args.flag_lines || args.flag_words || args.flag_chars ||
            args.flag_max_line_length {
                // TODO: Handle files which are not utf8-encoded. Right
                // now we get an error here.
                let line = try!(from_utf8(&lbuf));

                let size = if args.flag_chars || args.flag_max_line_length {
                    line.chars().count()
                } else { 0 };

                let last = if args.flag_lines || args.flag_max_line_length {
                    line.chars().last().unwrap_or(NULL)
                } else { NULL };

                if last == LF {
                    info.lines += 1;
                }

                if args.flag_max_line_length {
                    info.max_line_length = if last == LF {
                        max(info.max_line_length, size - 1)
                    } else {
                        max(info.max_line_length, size)
                    };
                }

                info.chars += size;

                if args.flag_words {
                    let mut words: Vec<&str> = line
                        .split(|c: char| c.is_whitespace())
                        .collect();
                    words.retain(|s: &&str| s.len() > 0);
                    info.words += words.len();
                }
            }
        lbuf.clear()
    }
    Ok(info)
}

// Open the file (possibly - for stdin) and return an array of strings
// reflecting the contents of the file, split on null characters.
fn process_files0_from(filename: &str) -> WCResult<Vec<String>> {
    let mut file = try!(open_file(filename));
    let mut result = Vec::new();
    let mut lbuf = Vec::new();
    loop {
        let size = try!(file.read_until(NULL as u8, &mut lbuf));
        if size == 0 {
            break;
        }
        // Create a scope because we're going to borrow lbuf and
        // the borrow must end before we can clear it.
        {
            let line = try!(from_utf8(&lbuf));
            result.push(line.trim_right_matches(NULL).to_string());
        }
        lbuf.clear()
    }
    Ok(result)
}

fn main() {
    let mut args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("wc v{}", VERSION);
        exit(0);
    }

    if args.flag_files0_from.len() != 0  && args.arg_FILE.len() != 0 {
        print_stderr!("wc: file operands cannot be combined with ");
        println_stderr!("--files0-from");
        println_stderr!("Try 'wc --help' for more information");
        exit(1);
    }

    if !(args.flag_lines || args.flag_words || args.flag_bytes
         || args.flag_chars || args.flag_max_line_length) {
        args.flag_lines = true;
        args.flag_words = true;
        args.flag_bytes = true;
    }
    let mut files: Vec<String> = Vec::new();
    if args.flag_files0_from.len() != 0 {
        match process_files0_from(args.flag_files0_from.as_ref()) {
            Ok(parts) => files.extend(parts),
            Err(e) => {
                println_stderr!("wc: error reading {}: {}",
                                args.flag_files0_from, e);
                exit(1);
            },
        };
        if &args.flag_files0_from == "-" && files.contains(&"-".to_string()) {
            print_stderr!("wc: when reading file names from stdin, no file ");
            println_stderr!("name of '-' allowed");
            exit(1);
        }
    } else {
        files.extend(args.arg_FILE.clone());
    };

    let results: Vec<WCResult<FileInfo>> = files.iter()
        .map(|f| f.as_ref())
        .map(|f|
             match open_file(f) {
                 Ok(f) => process_file(f, &args),
                 Err(e) => Err(e),
             })
        .collect();

    let total: FileInfo = results.iter()
        .filter(|r| r.as_ref().is_ok())
        .map(|r| r.as_ref().unwrap())
        .fold(FileInfo::new(),
              |acc, item|
              FileInfo{
                  bytes: acc.bytes + item.bytes,
                  chars: acc.chars + item.chars,
                  lines: acc.lines + item.lines,
                  words: acc.words + item.words,
                  max_line_length: max(acc.max_line_length,
                                       item.max_line_length),
              });

    // This is used for formatting. The number in the byte count will
    // be the largest, and so will be the widest string, so it's
    // suitable for a field width.
    let field_size = total.bytes.to_string().len();

    // For determining eventual exit code
    let mut ok = true;

    // Present the results
    for data in files.iter().zip(results.iter()) {
        let (filename, result) = data;
        ok &= display(&args, filename, result, field_size)
    }
    if results.len() > 1 {
        display(&args, "total", &Ok(total), field_size);
    }
    if !ok {
        exit(1);
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::process;
use std::{cell::RefCell, str::FromStr};

use getopts::Options;
use hprof::Profiler;
use libgir::{self as gir, Config, Library, WorkMode};

fn print_usage(program: &str, opts: Options) {
    let brief = format!(
        "Usage: {program} [options] [<library> <version>]
       {program} (-h | --help)",
        program = program
    );
    print!("{}", opts.usage(&brief));
}

trait OptionStr {
    fn as_str_ref(&self) -> Option<&str>;
}

impl<S: AsRef<str>> OptionStr for Option<S> {
    fn as_str_ref(&self) -> Option<&str> {
        self.as_ref().map(|string| string.as_ref())
    }
}

fn build_config() -> Result<Config, String> {
    let args: Vec<_> = env::args().collect();
    let program = args[0].clone();

    let mut options = Options::new();
    options.optopt(
        "c",
        "config",
        "Config file path (default: Gir.toml)",
        "CONFIG",
    );
    options.optflag("h", "help", "Show this message");
    options.optopt("d", "gir-directory", "Directory for girs", "GIRSPATH");
    options.optopt(
        "m",
        "mode",
        "Work mode: doc, normal, sys or not_bound",
        "MODE",
    );
    options.optopt("o", "target", "Target path", "PATH");
    options.optopt("p", "doc-target-path", "Doc target path", "PATH");
    options.optflag("b", "make-backup", "Make backup before generating");
    options.optflag("s", "stats", "Show statistics");
    options.optflag("", "disable_format", "Disable formatting generated code");

    let matches = match options.parse(&args[1..]) {
        Ok(matches) => matches,
        Err(e) => return Err(e.to_string()),
    };

    if matches.opt_present("h") {
        print_usage(&program, options);
        process::exit(0);
    }

    let work_mode = match matches.opt_str("m") {
        None => None,
        Some(s) => match WorkMode::from_str(&s) {
            Ok(w) => Some(w),
            Err(e) => {
                eprintln!("Error (switching to default work mode): {}", e);
                None
            }
        },
    };

    Config::new(
        matches.opt_str("c").as_str_ref(),
        work_mode,
        matches.opt_str("d").as_str_ref(),
        matches.free.get(0).as_str_ref(),
        matches.free.get(1).as_str_ref(),
        matches.opt_str("o").as_str_ref(),
        matches.opt_str("doc-target-path").as_str_ref(),
        matches.opt_present("b"),
        matches.opt_present("s"),
        matches.opt_present("disable_format"),
    )
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    if let Err(ref e) = do_main() {
        eprintln!("{}", e);

        ::std::process::exit(1);
    }
}

fn do_main() -> Result<(), String> {
    if std::env::var_os("RUST_LOG").is_none() {
        std::env::set_var("RUST_LOG", "gir=warn");
        std::env::set_var("RUST_LOG", "libgir=warn");
    }
    env_logger::init();

    let mut cfg = match build_config() {
        Ok(cfg) => cfg,
        Err(err) => return Err(err),
    };
    cfg.check_disable_format();

    let statistics = Profiler::new("Gir");
    statistics.start_frame();

    let watcher_total = statistics.enter("Total");

    let mut library;

    {
        let _watcher = statistics.enter("Loading");

        library = Library::new(&cfg.library_name);
        library.read_file(&cfg.girs_dir, &cfg.library_full_name())?;
    }

    {
        let _watcher = statistics.enter("Preprocessing");
        library.preprocessing(cfg.work_mode);
    }

    {
        let _watcher = statistics.enter("Update library by config");
        gir::update_version::apply_config(&mut library, &cfg);
    }

    {
        let _watcher = statistics.enter("Postprocessing");
        library.postprocessing(&cfg);
    }

    {
        let _watcher = statistics.enter("Resolving type ids");
        cfg.resolve_type_ids(&library);
    }

    {
        let _watcher = statistics.enter("Checking versions");
        gir::update_version::check_function_real_version(&mut library);
    }

    let mut env;

    {
        let _watcher = statistics.enter("Namespace/symbol/class analysis");

        let namespaces = gir::namespaces_run(&library);
        let symbols = gir::symbols_run(&library, &namespaces);
        let class_hierarchy = gir::class_hierarchy_run(&library);

        env = gir::Env {
            library,
            config: cfg,
            namespaces,
            symbols: RefCell::new(symbols),
            class_hierarchy,
            analysis: Default::default(),
        };
    }

    if env.config.work_mode != WorkMode::Sys {
        let _watcher = statistics.enter("Analyzing");
        gir::analysis_run(&mut env);
    }

    if env.config.work_mode != WorkMode::DisplayNotBound {
        let _watcher = statistics.enter("Generating");
        gir::codegen_generate(&env);
    }

    if !env.config.disable_format && env.config.work_mode.is_generate_rust_files() {
        let _watcher = statistics.enter("Formatting");
        gir::fmt::format(&env.config.target_path);
    }

    drop(watcher_total);
    statistics.end_frame();

    if env.config.show_statistics {
        statistics.print_timing();
    }
    if env.config.work_mode == WorkMode::DisplayNotBound {
        env.library.show_non_bound_types(&env);
    }

    Ok(())
}
<commit_msg>Change option to `--disable-format`<commit_after>use std::env;
use std::process;
use std::{cell::RefCell, str::FromStr};

use getopts::Options;
use hprof::Profiler;
use libgir::{self as gir, Config, Library, WorkMode};

fn print_usage(program: &str, opts: Options) {
    let brief = format!(
        "Usage: {program} [options] [<library> <version>]
       {program} (-h | --help)",
        program = program
    );
    print!("{}", opts.usage(&brief));
}

trait OptionStr {
    fn as_str_ref(&self) -> Option<&str>;
}

impl<S: AsRef<str>> OptionStr for Option<S> {
    fn as_str_ref(&self) -> Option<&str> {
        self.as_ref().map(|string| string.as_ref())
    }
}

fn build_config() -> Result<Config, String> {
    let args: Vec<_> = env::args().collect();
    let program = args[0].clone();

    let mut options = Options::new();
    options.optopt(
        "c",
        "config",
        "Config file path (default: Gir.toml)",
        "CONFIG",
    );
    options.optflag("h", "help", "Show this message");
    options.optopt("d", "gir-directory", "Directory for girs", "GIRSPATH");
    options.optopt(
        "m",
        "mode",
        "Work mode: doc, normal, sys or not_bound",
        "MODE",
    );
    options.optopt("o", "target", "Target path", "PATH");
    options.optopt("p", "doc-target-path", "Doc target path", "PATH");
    options.optflag("b", "make-backup", "Make backup before generating");
    options.optflag("s", "stats", "Show statistics");
    options.optflag("", "disable-format", "Disable formatting generated code");

    let matches = match options.parse(&args[1..]) {
        Ok(matches) => matches,
        Err(e) => return Err(e.to_string()),
    };

    if matches.opt_present("h") {
        print_usage(&program, options);
        process::exit(0);
    }

    let work_mode = match matches.opt_str("m") {
        None => None,
        Some(s) => match WorkMode::from_str(&s) {
            Ok(w) => Some(w),
            Err(e) => {
                eprintln!("Error (switching to default work mode): {}", e);
                None
            }
        },
    };

    Config::new(
        matches.opt_str("c").as_str_ref(),
        work_mode,
        matches.opt_str("d").as_str_ref(),
        matches.free.get(0).as_str_ref(),
        matches.free.get(1).as_str_ref(),
        matches.opt_str("o").as_str_ref(),
        matches.opt_str("doc-target-path").as_str_ref(),
        matches.opt_present("b"),
        matches.opt_present("s"),
        matches.opt_present("disable-format"),
    )
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    if let Err(ref e) = do_main() {
        eprintln!("{}", e);

        ::std::process::exit(1);
    }
}

fn do_main() -> Result<(), String> {
    if std::env::var_os("RUST_LOG").is_none() {
        std::env::set_var("RUST_LOG", "gir=warn");
        std::env::set_var("RUST_LOG", "libgir=warn");
    }
    env_logger::init();

    let mut cfg = match build_config() {
        Ok(cfg) => cfg,
        Err(err) => return Err(err),
    };
    cfg.check_disable_format();

    let statistics = Profiler::new("Gir");
    statistics.start_frame();

    let watcher_total = statistics.enter("Total");

    let mut library;

    {
        let _watcher = statistics.enter("Loading");

        library = Library::new(&cfg.library_name);
        library.read_file(&cfg.girs_dir, &cfg.library_full_name())?;
    }

    {
        let _watcher = statistics.enter("Preprocessing");
        library.preprocessing(cfg.work_mode);
    }

    {
        let _watcher = statistics.enter("Update library by config");
        gir::update_version::apply_config(&mut library, &cfg);
    }

    {
        let _watcher = statistics.enter("Postprocessing");
        library.postprocessing(&cfg);
    }

    {
        let _watcher = statistics.enter("Resolving type ids");
        cfg.resolve_type_ids(&library);
    }

    {
        let _watcher = statistics.enter("Checking versions");
        gir::update_version::check_function_real_version(&mut library);
    }

    let mut env;

    {
        let _watcher = statistics.enter("Namespace/symbol/class analysis");

        let namespaces = gir::namespaces_run(&library);
        let symbols = gir::symbols_run(&library, &namespaces);
        let class_hierarchy = gir::class_hierarchy_run(&library);

        env = gir::Env {
            library,
            config: cfg,
            namespaces,
            symbols: RefCell::new(symbols),
            class_hierarchy,
            analysis: Default::default(),
        };
    }

    if env.config.work_mode != WorkMode::Sys {
        let _watcher = statistics.enter("Analyzing");
        gir::analysis_run(&mut env);
    }

    if env.config.work_mode != WorkMode::DisplayNotBound {
        let _watcher = statistics.enter("Generating");
        gir::codegen_generate(&env);
    }

    if !env.config.disable_format && env.config.work_mode.is_generate_rust_files() {
        let _watcher = statistics.enter("Formatting");
        gir::fmt::format(&env.config.target_path);
    }

    drop(watcher_total);
    statistics.end_frame();

    if env.config.show_statistics {
        statistics.print_timing();
    }
    if env.config.work_mode == WorkMode::DisplayNotBound {
        env.library.show_non_bound_types(&env);
    }

    Ok(())
}
<|endoftext|>