<commit_before>#![feature(phase)]
#[phase(plugin, link)] extern crate log;

const U4_LOW:  u8 = 0b00001111;
const U4_HIGH: u8 = 0b11110000;

enum CpuState {
	Continue,
	Halt,
}

struct P150Cpu {
	ip:  u8,
	ir: u16,

	reg: [u8, ..16],
	mem: [u8, ..256],
}

impl P150Cpu {
	fn new() -> P150Cpu {
		P150Cpu {
			ip:  0x0,
			ir:  0x00,

			reg: [0u8, ..16],
			mem: [0u8, ..256],
		}
	}

	fn dump(&self) {
		println!("IP: {}, IR: {}", self.ip, self.ir);

		println!("Registers")
		for (addr, cell) in self.reg.iter().enumerate() {
			println!("{}: {}", addr, cell)
		}
	}

	// Read an array of instructions into memory
	fn init_mem(&mut self, memory: &[u16]) {
		let mut next_cell = 0x00;

		for op in memory.iter() {
			let byte_1 = (*op >> 8) as u8;
			let byte_2 = *op as u8;

			self.mem[next_cell]     = byte_1;
			self.mem[next_cell + 1] = byte_2;
			next_cell += 2
		}
	}

	fn tick(&mut self) -> CpuState {
		self.fetch();

		// decode
		let op = (self.ir >> 12) as u8;
		match op {
			0x0   => { // ADDB
				let rloc_i0 = ((self.ir >> 8) as u8) & U4_LOW;   // first input: lower nibble of first byte
				let rloc_i1 = ((self.ir as u8) & U4_HIGH) >> 4;  // second input: upper nibble of second byte
				let rloc_o0 = (self.ir as u8) & U4_LOW;          // output: lower nibble of second byte

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] + self.reg[rloc_i1 as uint];
				Continue
			},

			0x9   => { // RSET
				let rloc = ((self.ir >> 8) as u8) & U4_LOW;  // lower nibble of first byte
				let rval = self.ir as u8;                    // value is entire second byte
				self.reg[rloc as uint] = rval;               // store value in register

				Continue
			},

			0xB   => { Halt },
			_     => { debug!("read opcode: {}", op); Continue },
		}
	}

	fn fetch(&mut self) {
		// load PC -> IR
		let byte_1 = self.mem[(self.ip+0) as uint];
		let byte_2 = self.mem[(self.ip+1) as uint];

		self.ir  = (byte_1 as u16 << 8) | (byte_2 as u16);
		self.ip += 2;

		debug!("IR set to {} ({},{})", self.ir, byte_1, byte_2)
	}
}

fn main() {
	let mut cpu = P150Cpu::new();
	let program = [0x911E, 0x920C, 0x0123, 0xB000];
	cpu.init_mem(program);

	// 0x911E => 0x9 (rset), 0x1 (reg), 0x1E (val: 30)
	// 0x920C => 0x9 (rset), 0x2 (reg), 0x0C (val: 12)
	// 0x0123 => 0x0 (addb), 0x1 (in1), 0x2 (in2), 0x3 (out1)

	loop {
		match cpu.tick() {
			Continue => { continue; },
			Halt => { println!("CPU halted."); cpu.dump(); break; },
		}
	}
}

<commit_msg>Cleaner hex formatting<commit_after>#![feature(phase)]
#[phase(plugin, link)] extern crate log;

const U4_LOW:  u8 = 0b00001111;
const U4_HIGH: u8 = 0b11110000;

enum CpuState {
	Continue,
	Halt,
}

struct P150Cpu {
	ip:  u8,
	ir: u16,

	reg: [u8, ..16],
	mem: [u8, ..256],
}

impl P150Cpu {
	fn new() -> P150Cpu {
		P150Cpu {
			ip:  0x00,
			ir:  0x0000,

			reg: [0u8, ..16],
			mem: [0u8, ..256],
		}
	}

	fn dump(&self) {
		println!("IP: 0x{:02X}, IR: 0x{:04X}", self.ip, self.ir);

		println!("Registers")
		for (addr, cell) in self.reg.iter().enumerate() {
			println!("{}: {}", addr, cell)
		}
	}

	// Read an array of instructions into memory
	fn init_mem(&mut self, memory: &[u16]) {
		let mut next_cell = 0x00;

		for op in memory.iter() {
			let byte_1 = (*op >> 8) as u8;
			let byte_2 = *op as u8;

			self.mem[next_cell]     = byte_1;
			self.mem[next_cell + 1] = byte_2;
			next_cell += 2
		}
	}

	fn tick(&mut self) -> CpuState {
		self.fetch();

		// decode
		let op = (self.ir >> 12) as u8;
		match op {
			0x0   => { // ADDB
				let rloc_i0 = ((self.ir >> 8) as u8) & U4_LOW;   // first input: lower nibble of first byte
				let rloc_i1 = ((self.ir as u8) & U4_HIGH) >> 4;  // second input: upper nibble of second byte
				let rloc_o0 = (self.ir as u8) & U4_LOW;          // output: lower nibble of second byte

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] + self.reg[rloc_i1 as uint];
				Continue
			},

			0x9   => { // RSET
				let rloc = ((self.ir >> 8) as u8) & U4_LOW;  // lower nibble of first byte
				let rval = self.ir as u8;                    // value is entire second byte
				self.reg[rloc as uint] = rval;               // store value in register

				Continue
			},

			0xB   => { Halt },
			_     => { debug!("read opcode: {}", op); Continue },
		}
	}

	fn fetch(&mut self) {
		// load PC -> IR
		let byte_1 = self.mem[(self.ip+0) as uint];
		let byte_2 = self.mem[(self.ip+1) as uint];

		self.ir  = (byte_1 as u16 << 8) | (byte_2 as u16);
		self.ip += 2;

		debug!("IR set to 0x{:04X} ({:02X},{:02X})", self.ir, byte_1, byte_2)
	}
}

fn main() {
	let mut cpu = P150Cpu::new();
	let program = [0x911E, 0x920C, 0x0123, 0xB000];
	cpu.init_mem(program);

	// 0x911E => 0x9 (rset), 0x1 (reg), 0x1E (val: 30)
	// 0x920C => 0x9 (rset), 0x2 (reg), 0x0C (val: 12)
	// 0x0123 => 0x0 (addb), 0x1 (in1), 0x2 (in2), 0x3 (out1)

	loop {
		match cpu.tick() {
			Continue => { continue; },
			Halt => { println!("CPU halted."); cpu.dump(); break; },
		}
	}
}

<|endoftext|>


<commit_before>#![feature(convert)]
mod vm;
use vm::{VM, Instruction};
use std::env;
use std::io::prelude::*;
use std::fs::File;
static USAGE: &'static str = "
Usage:
vmach repl
vmach run
vmach -h | --help
vmach --version
Options:
-h, --help      Show this message.
--version   Display the version.
";

fn main() {
	let mut arguments = env::args();
	arguments.next();
	match arguments.next() {
		Some(command) => {
			match command.as_ref() {
				"repl" => {

				},
				"run" => {
					match arguments.next() {
						Some(filename) => {
							let mut s = String::new();
							match File::open(filename) {
								Ok(mut input) => {
									// let mut program = String::new();

									// input.read_to_string(&mut program);

									let mut vm = VM::new();
									let program = vec![Instruction::PSH(6),Instruction::PSH(7),Instruction::ADD, Instruction::OUT, Instruction::HLT];
									vm.run(program);
								},
								Err(error) => panic!("{}", error),
							}
						}
						_ => println!("No file specified\n{}", USAGE),
					}
				}
				_ => println!("Unrecognised command \n{}", USAGE),
			}
		},
		_ => println!("No command specified \n{}", USAGE),
	}
}
<commit_msg>begin work on repl<commit_after>#![feature(convert)]
mod vm;
use vm::{VM, Instruction};
use std::env;
use std::io::prelude::*;
use std::fs::File;
use std::io::{stdin, stdout};
const PROMPT: &'static str = "\x1B[36mvm> \x1B[37m";
static USAGE: &'static str = "
Usage:
vmach repl
vmach run
vmach -h | --help
vmach --version
Options:
-h, --help      Show this message.
--version   Display the version.
";

fn main() {
	let mut arguments = env::args();
	arguments.next();
	match arguments.next() {
		Some(command) => {
			match command.as_ref() {
				"repl" => {
					print!("Welcome to the vmachine repl.\nUse ctrl-c to exit.\n");
					let mut stdin = stdin();
					let mut stdout = stdout();
					loop {
						stdout.write_all(PROMPT.as_bytes());
						stdout.flush().ok();
						let mut input = String::new();
						stdin.read_line(&mut input);

					}
				},
				"run" => {
					match arguments.next() {
						Some(filename) => {
							let mut s = String::new();
							match File::open(filename) {
								Ok(mut input) => {
									// let mut program = String::new();

									// input.read_to_string(&mut program);

									let mut vm = VM::new();
									let program = vec![Instruction::PSH(6),Instruction::PSH(7),Instruction::ADD, Instruction::OUT, Instruction::HLT];
									vm.run(program);
								},
								Err(error) => panic!("{}", error),
							}
						}
						_ => println!("No file specified\n{}", USAGE),
					}
				}
				_ => println!("Unrecognised command \n{}", USAGE),
			}
		},
		_ => println!("No command specified \n{}", USAGE),
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Robert Helmer <rhelmer@rhelmer.org>. See the LICENSE
// file at the top-level directory of this distribution.

/**
  * Symbolapi - a microservice which accepts lists of symbol+addresses, and returns
  * a list of symbolicated functions.
  *
  * The goal is to take an HTTP JSON request such as:
  * {"stacks":[
  *   [
  *     [0,11723767],
  *     [1, 65802]
  *    ]
  *  ],
  *  "memoryMap":[
  *    ["xul.pdb","44E4EC8C2F41492B9369D6B9A059577C2"],
  *    ["wntdll.pdb","D74F79EB1F8D4A45ABCD2F476CCABACC2"]
  *  ],
  *  "version":4
  * }
  *
  * The symbolapi service then downloads the corresponding symbol files (e.g. from S3), and returns
  * the function names for the corresponding addresses (in the "stacks" array) and returns JSON
  * such as:
  * {"symbolicatedStacks": [
  *   [
  *     "XREMain::XRE_mainRun() (in xul.pdb)",
  *     "KiUserCallbackDispatcher (in wntdll.pdb)"]
  *   ],
  *   "knownModules": [true, true]
  * }
  */

extern crate breakpad_symbols;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate rustc_serialize;
extern crate toml;

use std::collections::HashMap;
use std::fs::{File, create_dir_all};
use std::io::{Read, Write};
use std::path::{PathBuf};
use std::thread;

use breakpad_symbols::SymbolFile;
use hyper::Client;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use rustc_serialize::json;

/**
  * Incoming JSON request format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcDecodable)]
pub struct SymbolRequest {
    memoryMap: Vec<(String,String)>,
    // index, offset
    stacks: Vec<Vec<(i8,u64)>>,
    version: u8,
}

/**
  * Outgoing JSON response format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcEncodable)]
pub struct SymbolResponse {
    symbolicatedStacks: Vec<Vec<String>>,
    knownModules: Vec<bool>,
}

fn main() {
    log4rs::init_file("config/log.toml", Default::default()).unwrap();

    let address = "0.0.0.0:8080";

    info!("Listening on {}", address);
    Server::http(address).unwrap().handle(server).unwrap();
}

/**
  * Receives single HTTP requests and demuxes to symbols file fetches from S3 bucket.
  */
fn server(mut req: Request, mut res: Response) {
    info!("incoming connection from {}", req.remote_addr);

    match req.method {
        hyper::Post => {
            let mut res = res.start().unwrap();

            let mut buffer = String::new();
            let _ = req.read_to_string(&mut buffer);
            debug!("raw POST: {:?}", &buffer);

            let decoded: SymbolRequest = json::decode(&buffer).unwrap();

            debug!("decoded memoryMap: {:?}", decoded.memoryMap);
            debug!("decoded stacks: {:?}", decoded.stacks);
            debug!("decoded version: {}", decoded.version);

            let symbol_url = get_config("symbol_urls.public");

            // stacks come in as an array, turn into hashmap
            let mut stack_map: HashMap<i8, Vec<u64>> = HashMap::new();

            debug!("decoded.stacks: {:?}", decoded.stacks);

            let stacks = decoded.stacks[0].clone();
            for stack in &stacks {
                let (index, offset) = *stack;

                let mut offsets = vec!();
                if stack_map.contains_key(&index) {
                    offsets = stack_map.get(&index).unwrap().clone();
                }
                offsets.push(offset);
                stack_map.insert(index, offsets);
            }

            debug!("stack_map: {:?}", stack_map);

            let symbol_response = client(symbol_url, decoded.memoryMap, stack_map.clone());
            let _ = res.write_all(symbol_response.as_bytes());

            res.end().unwrap();
        },
        _ => { *res.status_mut() = StatusCode::MethodNotAllowed },
    }

    debug!("finished serving request");
}

/**
  * Creates multiple client connections and aggregates result.
  */
fn client(url: String, memory_map: Vec<(String,String)>, stack_map: HashMap<i8, Vec<u64>>) -> String {
    let mut handles = vec![];
    let mut counter: i8 = 0;
    for (debug_file, debug_id) in memory_map {
        let pdb = debug_file.find(".pdb").unwrap();
        let (symbol_name, _) = debug_file.split_at(pdb);
        let symbol_file = format!("{}.sym", symbol_name);
        let this_url = format!("{}/{}/{}/{}", url, debug_file, debug_id, symbol_file);

        let mut symbol_path = PathBuf::new();
        // TODO get from config
        symbol_path.push("testdata/symbols");
        symbol_path.push(&debug_file);
        symbol_path.push(&debug_id);
        symbol_path.push(&symbol_file);

        let stack_map_copy = stack_map.clone();

        let _ = create_dir_all(&symbol_path.parent().unwrap()).unwrap();

        // TODO most of the time is probably spent waiting on I/O, maybe async would be more appropriate?
        // TODO decide min/max possible threads, possibly based on number of cores?
        handles.push(thread::spawn(move || {
            // FIXME use Arc<Mutex<File>> to prevent concurrent writes
            // TODO only write contents if server version newer
            if !&symbol_path.exists() {

                let mut body = String::new();
                let c = Client::new();
                let mut res = c.get(&this_url).send().unwrap();
                let _ = res.read_to_string(&mut body);

                let mut f = File::create(&symbol_path).unwrap();
                let _ = f.write_all(body.as_bytes());
            }

            debug!("symbol_path: {:?}", &symbol_path);
            // FIXME this is having problems with CRLF
            // TODO handle error case better here
            let symbol_provider = SymbolFile::from_file(&symbol_path).unwrap();

            let mut symbols = vec!();
            for stacks in stack_map_copy.get(&counter) {
                for address in stacks {
                    //debug!("attempt to symbolicate: {} for: {:?}", *address, &symbol_path);
                    match symbol_provider.functions.lookup(*address) {
                        Some(x) => symbols.push(x.name.clone()),
                        // return the address rather than function name if symbol not found
                        None => symbols.push(format!("0x{:x}", address)),
                    }
                }
            }
            debug!("symbol_file: {:?}, symbols: {:?}", symbol_file, symbols);

            (symbol_file, symbols)
        }));

        counter += 1;
    }

    let mut result = SymbolResponse {
        symbolicatedStacks: vec!(),
        knownModules: vec!(),
    };

    for handle in handles {
        let (symbol_file, symbols) = handle.join().unwrap();

        for symbol in symbols {
            result.symbolicatedStacks.push(
                vec!(format!("{} (in {}))", symbol, symbol_file))
            );
        }
        result.knownModules.push(true);
    }

    json::encode(&result).unwrap()
}

/**
  * Returns individual values from the configuration file.
  */
fn get_config(value_name: &str) -> String {
    // TODO move to actual file, static str for the moment
    let toml: &'static str = r#"
        [symbol_urls]
        public = "https://s3-us-west-2.amazonaws.com/org.mozilla.crash-stats.symbols-public/v1"
    "#;
    // TODO support multiple URLs
    let value: toml::Value = toml.parse().unwrap();

    value.lookup(value_name).unwrap().as_str().unwrap().to_string()
}
<commit_msg>return debug file name and handle symbol provider failure more helpfully<commit_after>// Copyright 2015 Robert Helmer <rhelmer@rhelmer.org>. See the LICENSE
// file at the top-level directory of this distribution.

/**
  * Symbolapi - a microservice which accepts lists of symbol+addresses, and returns
  * a list of symbolicated functions.
  *
  * The goal is to take an HTTP JSON request such as:
  * {"stacks":[
  *   [
  *     [0,11723767],
  *     [1, 65802]
  *    ]
  *  ],
  *  "memoryMap":[
  *    ["xul.pdb","44E4EC8C2F41492B9369D6B9A059577C2"],
  *    ["wntdll.pdb","D74F79EB1F8D4A45ABCD2F476CCABACC2"]
  *  ],
  *  "version":4
  * }
  *
  * The symbolapi service then downloads the corresponding symbol files (e.g. from S3), and returns
  * the function names for the corresponding addresses (in the "stacks" array) and returns JSON
  * such as:
  * {"symbolicatedStacks": [
  *   [
  *     "XREMain::XRE_mainRun() (in xul.pdb)",
  *     "KiUserCallbackDispatcher (in wntdll.pdb)"]
  *   ],
  *   "knownModules": [true, true]
  * }
  */

extern crate breakpad_symbols;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate log4rs;
extern crate rustc_serialize;
extern crate toml;

use std::collections::HashMap;
use std::fs::{File, create_dir_all};
use std::io::{Read, Write};
use std::path::{PathBuf};
use std::thread;

use breakpad_symbols::SymbolFile;
use hyper::Client;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use rustc_serialize::json;

/**
  * Incoming JSON request format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcDecodable)]
pub struct SymbolRequest {
    memoryMap: Vec<(String,String)>,
    // index, offset
    stacks: Vec<Vec<(i8,u64)>>,
    version: u8,
}

/**
  * Outgoing JSON response format.
  */
// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcEncodable)]
pub struct SymbolResponse {
    symbolicatedStacks: Vec<Vec<String>>,
    knownModules: Vec<bool>,
}

fn main() {
    log4rs::init_file("config/log.toml", Default::default()).unwrap();

    let address = "0.0.0.0:8080";

    info!("Listening on {}", address);
    Server::http(address).unwrap().handle(server).unwrap();
}

/**
  * Receives single HTTP requests and demuxes to symbols file fetches from S3 bucket.
  */
fn server(mut req: Request, mut res: Response) {
    info!("incoming connection from {}", req.remote_addr);

    match req.method {
        hyper::Post => {
            let mut res = res.start().unwrap();

            let mut buffer = String::new();
            let _ = req.read_to_string(&mut buffer);
            debug!("raw POST: {:?}", &buffer);

            let decoded: SymbolRequest = json::decode(&buffer).unwrap();

            debug!("decoded memoryMap: {:?}", decoded.memoryMap);
            debug!("decoded stacks: {:?}", decoded.stacks);
            debug!("decoded version: {}", decoded.version);

            let symbol_url = get_config("symbol_urls.public");

            // stacks come in as an array, turn into hashmap
            let mut stack_map: HashMap<i8, Vec<u64>> = HashMap::new();

            debug!("decoded.stacks: {:?}", decoded.stacks);

            let stacks = decoded.stacks[0].clone();
            for stack in &stacks {
                let (index, offset) = *stack;

                let mut offsets = vec!();
                if stack_map.contains_key(&index) {
                    offsets = stack_map.get(&index).unwrap().clone();
                }
                offsets.push(offset);
                stack_map.insert(index, offsets);
            }

            debug!("stack_map: {:?}", stack_map);

            let symbol_response = client(symbol_url, decoded.memoryMap, stack_map.clone());
            let _ = res.write_all(symbol_response.as_bytes());

            res.end().unwrap();
        },
        _ => { *res.status_mut() = StatusCode::MethodNotAllowed },
    }

    debug!("finished serving request");
}

/**
  * Creates multiple client connections and aggregates result.
  */
fn client(url: String, memory_map: Vec<(String,String)>, stack_map: HashMap<i8, Vec<u64>>) -> String {
    let mut handles = vec![];
    let mut counter: i8 = 0;
    for (debug_file, debug_id) in memory_map {
        let debug_file_name = debug_file.clone();
        let pdb = debug_file.find(".pdb").unwrap();
        let (symbol_name, _) = debug_file.split_at(pdb);
        let symbol_file = format!("{}.sym", symbol_name);
        let this_url = format!("{}/{}/{}/{}", url, debug_file, debug_id, symbol_file);

        let mut symbol_path = PathBuf::new();
        // TODO get from config
        symbol_path.push("testdata/symbols");
        symbol_path.push(&debug_file);
        symbol_path.push(&debug_id);
        symbol_path.push(&symbol_file);

        let stack_map_copy = stack_map.clone();

        let _ = create_dir_all(&symbol_path.parent().unwrap()).unwrap();

        // TODO most of the time is probably spent waiting on I/O, maybe async would be more appropriate?
        // TODO decide min/max possible threads, possibly based on number of cores?
        handles.push(thread::spawn(move || {
            // FIXME use Arc<Mutex<File>> to prevent concurrent writes
            // TODO only write contents if server version newer
            if !&symbol_path.exists() {

                let mut body = String::new();
                let c = Client::new();
                let mut res = c.get(&this_url).send().unwrap();
                let _ = res.read_to_string(&mut body);

                let mut f = File::create(&symbol_path).unwrap();
                let _ = f.write_all(body.as_bytes());
            }

            debug!("symbol_path: {:?}", &symbol_path);
            // FIXME this is having problems with CRLF
            let symbol_provider = match SymbolFile::from_file(&symbol_path) {
                Ok(x) => x,
                Err(x) => panic!("symbol provider failed: symbol_path: {:?}, {}", &symbol_path, x),
            };

            let mut symbols = vec!();
            for stacks in stack_map_copy.get(&counter) {
                for address in stacks {
                    //debug!("attempt to symbolicate: {} for: {:?}", *address, &symbol_path);
                    match symbol_provider.functions.lookup(*address) {
                        Some(x) => symbols.push(x.name.clone()),
                        // return the address rather than function name if symbol not found
                        None => symbols.push(format!("0x{:x}", address)),
                    }
                }
            }
            //debug!("debug_file: {:?}, symbols: {:?}", debug_file, symbols);

            (debug_file_name, symbols)
        }));

        counter += 1;
    }

    let mut result = SymbolResponse {
        symbolicatedStacks: vec!(),
        knownModules: vec!(),
    };

    for handle in handles {
        let (debug_file_name, symbols) = handle.join().unwrap();

        for symbol in symbols {
            result.symbolicatedStacks.push(
                vec!(format!("{} (in {}))", symbol, debug_file_name))
            );
        }
        result.knownModules.push(true);
    }

    json::encode(&result).unwrap()
}

/**
  * Returns individual values from the configuration file.
  */
fn get_config(value_name: &str) -> String {
    // TODO move to actual file, static str for the moment
    let toml: &'static str = r#"
        [symbol_urls]
        public = "https://s3-us-west-2.amazonaws.com/org.mozilla.crash-stats.symbols-public/v1"
    "#;
    // TODO support multiple URLs
    let value: toml::Value = toml.parse().unwrap();

    value.lookup(value_name).unwrap().as_str().unwrap().to_string()
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate docopt;

use std::error::Error;
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 that acts like print!, but w/ stderr
macro_rules! print_stderr(
    ($($arg:tt)*) => (
        match write!(&mut stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

// Macro that acts like println!, but w/ stderr
macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

// Enum that captures all of the expected error variants we are likely
// to return.
#[derive(Debug)]
enum WCError {
    IO(IOError),
    Utf8(Utf8Error),
}

// Implement the Display trait so that we can print our errors to the
// user. Also a pre-requisite for implementing the Error trait.
impl Display for WCError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            WCError::IO(ref e) => e.fmt(f),
            WCError::Utf8(ref e) => e.fmt(f),
        }
    }
}

// Implement the Error trait so that callers can treat a WCError as
// they would any other error.
impl std::error::Error for WCError {
    fn description(&self) -> &str {
        match *self {
            WCError::IO(ref e) => e.description(),
            WCError::Utf8(ref e) => e.description()
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            WCError::IO(ref e) => e.cause(),
            WCError::Utf8(ref e) => e.cause()
        }
    }
}

// Make it possible to wrap an IOError as a variant of our WCError enum.
impl From<IOError> for WCError {
    fn from(e: IOError) -> WCError {
        WCError::IO(e)
    }
}

// Make it possible to wrap a Utf8Error as a variant of our WCError enum.
impl From<Utf8Error> for WCError {
    fn from(e: Utf8Error) -> WCError {
        WCError::Utf8(e)
    }
}

// Define the struct which will wrap all of our counts. Derive the
// Debug trait so we can print it out using the "{:?}" pattern for
// debugging purposes.
#[derive(Debug)]
struct FileInfo{
    bytes: usize,
    chars: usize,
    lines: usize,
    words: usize,
    max_line_length: usize,
}

// Implement a convenience constructor that will return a zeroed
// FileInfo struct. I had considered implementing the Zero and Add
// traits and using sum to acquire our "total" instead of a fold, but
// the behavior of max_line_length just doesn't look like add to me,
// and it may be more confusing that it's worth.
impl FileInfo {
    fn new() -> FileInfo {
        FileInfo{bytes: 0,
                 chars: 0,
                 lines: 0,
                 words: 0,
                 max_line_length: 0,
        }
    }
}

// Wrapper around Result that specializes the Error variant to be one
// of our WCErrors.
type WCResult<T> = Result<T, WCError>;

// Print the result of attempting to process a file.
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. Doing this allows us to treat regular
// files and stdin equivalently.
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))))),
    }
}

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();

    // Fold over the FileInfo results which are of the Ok variant to
    // compute the "total".
    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 = if args.flag_files0_from == "-" {
        0
    } else {
        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);
    }
}
<commit_msg>Simplify process_file<commit_after>extern crate rustc_serialize;
extern crate docopt;

use std::error::Error;
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 that acts like print!, but w/ stderr
macro_rules! print_stderr(
    ($($arg:tt)*) => (
        match write!(&mut stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

// Macro that acts like println!, but w/ stderr
macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

// Enum that captures all of the expected error variants we are likely
// to return.
#[derive(Debug)]
enum WCError {
    IO(IOError),
    Utf8(Utf8Error),
}

// Implement the Display trait so that we can print our errors to the
// user. Also a pre-requisite for implementing the Error trait.
impl Display for WCError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            WCError::IO(ref e) => e.fmt(f),
            WCError::Utf8(ref e) => e.fmt(f),
        }
    }
}

// Implement the Error trait so that callers can treat a WCError as
// they would any other error.
impl std::error::Error for WCError {
    fn description(&self) -> &str {
        match *self {
            WCError::IO(ref e) => e.description(),
            WCError::Utf8(ref e) => e.description()
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            WCError::IO(ref e) => e.cause(),
            WCError::Utf8(ref e) => e.cause()
        }
    }
}

// Make it possible to wrap an IOError as a variant of our WCError enum.
impl From<IOError> for WCError {
    fn from(e: IOError) -> WCError {
        WCError::IO(e)
    }
}

// Make it possible to wrap a Utf8Error as a variant of our WCError enum.
impl From<Utf8Error> for WCError {
    fn from(e: Utf8Error) -> WCError {
        WCError::Utf8(e)
    }
}

// Define the struct which will wrap all of our counts. Derive the
// Debug trait so we can print it out using the "{:?}" pattern for
// debugging purposes.
#[derive(Debug)]
struct FileInfo{
    bytes: usize,
    chars: usize,
    lines: usize,
    words: usize,
    max_line_length: usize,
}

// Implement a convenience constructor that will return a zeroed
// FileInfo struct. I had considered implementing the Zero and Add
// traits and using sum to acquire our "total" instead of a fold, but
// the behavior of max_line_length just doesn't look like add to me,
// and it may be more confusing that it's worth.
impl FileInfo {
    fn new() -> FileInfo {
        FileInfo{bytes: 0,
                 chars: 0,
                 lines: 0,
                 words: 0,
                 max_line_length: 0,
        }
    }
}

// Wrapper around Result that specializes the Error variant to be one
// of our WCErrors.
type WCResult<T> = Result<T, WCError>;

// Print the result of attempting to process a file.
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. Doing this allows us to treat regular
// files and stdin equivalently.
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))))),
    }
}

fn process_file(filename: &str, args: &Args) -> WCResult<FileInfo> {
    let mut file = try!(open_file(filename));
    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 no data is specifically requested, default to lines/words/bytes
    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;
    }

    // Determine what "files" to process
    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());
    };

    // Process all of our files
    let results: Vec<WCResult<FileInfo>> = files.iter()
        .map(|f| process_file(f, &args))
        .collect();

    // Fold over the FileInfo results which are of the Ok variant to
    // compute the "total".
    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 = if args.flag_files0_from == "-" {
        0
    } else {
        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::io::{self, stdin, stdout, Write};

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

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

fn parse(line: &str) -> Ast {
    let mut words = line.split_whitespace();

    match words.next() {
        Some(command) => Ast::Call {
            command: String::from(command),
            args: words.map(String::from).collect()
        },
        None => Ast::Empty
    }
}

fn execute(ast: &Ast) -> io::Result<()> {
    match *ast {
        Ast::Empty => Ok(()),
        Ast::Call { ref command, ref args } => {
            std::process::Command::new(command).args(args).status().map(|_| ())
        },
    }
}

fn main() {
    let mut line = String::new();
    loop {
        prompt(&mut line).unwrap();
        let ast = parse(&line);
        execute(&ast).unwrap();
        line.clear();
    }
}
<commit_msg>Don't quit on execution errors.<commit_after>use std::io::{self, stdin, stdout, Write};

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

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

fn parse(line: &str) -> Ast {
    let mut words = line.split_whitespace();

    match words.next() {
        Some(command) => Ast::Call {
            command: String::from(command),
            args: words.map(String::from).collect()
        },
        None => Ast::Empty
    }
}

fn execute(ast: &Ast) -> io::Result<()> {
    match *ast {
        Ast::Empty => Ok(()),
        Ast::Call { ref command, ref args } => {
            std::process::Command::new(command).args(args).status().map(|_| ())
        },
    }
}

fn main() {
    let mut line = String::new();
    loop {
        prompt(&mut line).unwrap();
        let ast = parse(&line);
        if let Err(e) = execute(&ast) {
            println!("shroom: error: {}", e);
        }
        line.clear();
    }
}
<|endoftext|>


<commit_before>#[allow(dead_code)]
mod birl;
mod parser;

fn main() {
    println!("{} {} ─ {}", birl::NAME, birl::VERSION, birl::GREETING);
}
<commit_msg>Printa mensagem de ajuda somente quando pedido, entende algumas flags<commit_after>mod birl;
mod parser;

extern crate getopts;

use getopts::Options;
use parser::PEU;

/// Version of the package
pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");

/// Help/Program usage
pub const USAGE: &'static str = "Ta querendo ajuda, cumpade?\n\t-a ou --ajuda-o-maluco-ta-doente: \
                                 Imprime essa mensagem de ajuda\n\t-c ou --compila-essa-porra      \
                                 : Compile o programa ao invés de interpretar";

fn print_help() {
    println!("BIRLSCRIPT v{} - Rafael R Nakano, Matheus Borella - 2016\n{}",
             VERSION,
             USAGE);
}

/// Return the input files passed to the program
fn get_input_files(args: &[String]) -> Vec<String> {
    let mut buffer: Vec<String> = vec![];
    for arg in args {
        if arg.chars().collect::<Vec<char>>()[0] == '-' {
            // First character is a '-', so is a flag or option
            continue;
        }
        buffer.push(arg.clone());
    }
    buffer
}

fn main() {
    use std::env;
    let arguments = env::args().collect::<Vec<String>>();
    let files = if arguments.len() < 2 {
        // No argument passed.
        vec![] // No files
    } else {
        let mut opts = Options::new();
        opts.optflag("a", "ajuda-o-maluco-ta-doente", "Imprime mensagem de ajuda");
        opts.optflag("c",
                     "compila-essa-porra",
                     "Compile o programa ao invés de interpretar");
        let matches = match opts.parse(&arguments[1..]) {
            Ok(m) => m,
            Err(e) => panic!("Erro interpretando flags do terminal: {}", e),
        };
        if matches.opt_present("a") {
            print_help(); // User asked for help message
        }
        if matches.opt_present("c") {
            // FIXME: Compile flag triggered
        }
        get_input_files(&arguments[1..])
    };
    let mut PEU = PEU::new(); // Creates a new executable unit
    for file in &files {
        PEU.parse_file(file); // Parse each file
    }
    // FIXME: Execute or compile files parsed in PEU
}
<|endoftext|>


<commit_before>// Author: Alex Chernyakhovsky (achernya@mit.edu)

// TODO(achernya): Per the documentation on doc.rust-lang.org, std::io
// is not yet ready, so use old_io until 1.0-final.
#![feature(old_io)]

// std::env contains a lot of nice functions that otherwise would
// require std::os to use; std::os has lots of deprecated functions.
#![feature(env)]

// TODO(achernya): Remove this feature when std::env moves over to
// std::path.
#![feature(old_path)]

use std::env;
use std::old_io as io;

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

// ShellCommand is a trait that defines a runnable POSIX shell
// command. An implementation is an abstract representation of shell
// commands such as simple invocations, invocations with redirection,
// and even shell pipelines.
trait ShellCommand {
    fn run(&self);
}

fn shell_loop() {
    let mut stdin = io::stdin();
    loop {
        print!("$ ");
        let line = stdin.read_line();
        match line {
            Ok(expr) => handle_command(expr),
            Err(_) => break,
        }
    }
}

fn handle_command(user_expr: String) {
    // Clean up the string by removing the newline at the end
    let expr = &user_expr.trim_matches('\n');
    let components: Vec<&str> = expr.split(' ').collect();
    if builtins(components) {
        return;
    }
}

fn builtins(command: Vec<&str>) -> bool {
    match command[0] {
        "cd" => cd(command),
        "pwd" => pwd(),
        _ => return false,
    }
    return true;
}

fn cd(command: Vec<&str>) {
    // cd is the "change directory" command. It can take either 0 or 1
    // arguments. If given no arguments, then the $HOME directory is
    // chosen.
    let mut dir: Option<Path>;
    match command.len() {
        0 => panic!("invalid cd invocation"),
        1 => dir = env::home_dir(),
        _ => dir = Some(Path::new(command[1]))
    }
    if dir.is_none() {
        println_stderr!("cd: no directory to change to");
        return;
    }
    let directory = dir.unwrap();
    let result = env::set_current_dir(&directory);
    if result.is_err() {
        println_stderr!("cd: unable to change directory to {}",
                        directory.display());
    }
}

fn pwd() {
    let p = env::current_dir().unwrap_or(Path::new("/"));
    println!("{}", p.display());
}

fn main() {
    // TODO(achernya): is there any initialization we want to do
    // before we enter the shell loop?
    shell_loop();
}
<commit_msg>Show cd's error messages<commit_after>// Author: Alex Chernyakhovsky (achernya@mit.edu)

// TODO(achernya): Per the documentation on doc.rust-lang.org, std::io
// is not yet ready, so use old_io until 1.0-final.
#![feature(old_io)]

// std::env contains a lot of nice functions that otherwise would
// require std::os to use; std::os has lots of deprecated functions.
#![feature(env)]

// TODO(achernya): Remove this feature when std::env moves over to
// std::path.
#![feature(old_path)]

use std::env;
use std::old_io as io;

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

// ShellCommand is a trait that defines a runnable POSIX shell
// command. An implementation is an abstract representation of shell
// commands such as simple invocations, invocations with redirection,
// and even shell pipelines.
trait ShellCommand {
    fn run(&self);
}

fn shell_loop() {
    let mut stdin = io::stdin();
    loop {
        print!("$ ");
        let line = stdin.read_line();
        match line {
            Ok(expr) => handle_command(expr),
            Err(_) => break,
        }
    }
}

fn handle_command(user_expr: String) {
    // Clean up the string by removing the newline at the end
    let expr = &user_expr.trim_matches('\n');
    let components: Vec<&str> = expr.split(' ').collect();
    if builtins(components) {
        return;
    }
}

fn builtins(command: Vec<&str>) -> bool {
    match command[0] {
        "cd" => cd(command),
        "pwd" => pwd(),
        _ => return false,
    }
    return true;
}

fn cd(command: Vec<&str>) {
    // cd is the "change directory" command. It can take either 0 or 1
    // arguments. If given no arguments, then the $HOME directory is
    // chosen.
    let mut dir: Option<Path>;
    match command.len() {
        0 => panic!("invalid cd invocation"),
        1 => dir = env::home_dir(),
        _ => dir = Some(Path::new(command[1]))
    }
    if dir.is_none() {
        println_stderr!("cd: no directory to change to");
        return;
    }
    let directory = dir.unwrap();
    let result = env::set_current_dir(&directory);
    match result {
        Err(err) => {
            println_stderr!("cd: {}: {}", directory.display(), err);
        },
        _ => (),
    }
}

fn pwd() {
    let p = env::current_dir().unwrap_or(Path::new("/"));
    println!("{}", p.display());
}

fn main() {
    // TODO(achernya): is there any initialization we want to do
    // before we enter the shell loop?
    shell_loop();
}
<|endoftext|>


<commit_before>#![feature(old_io,net,core)]
use std::net::UdpSocket;

static NTP_CLIENT: u8 = 3;

static LEAP_SHIFT: i32 = 6;
static VERSION_SHIFT: i32 = 3;

struct NTPTimestamp {
    seconds: u32,
    fraction: u32
}

struct NTPHeader {
    leap: u8,
    version: u8,
    mode: u8,
    stratum: u8,
    poll: u8,
    precision: u8,
    root_delay: u32,
    root_dispersion: u32,
    reference_id: u32,
    reference_timestamp: NTPTimestamp,
    origin_timestamp: NTPTimestamp,
    receive_timestamp: NTPTimestamp,
    transmit_timestamp: NTPTimestamp,
}

impl NTPHeader {
    pub fn new() -> NTPHeader {
        NTPHeader {
            leap: 0,
            version: 3,
            mode: NTP_CLIENT,
            stratum: 0,
            poll: 0,
            precision: 0,
            root_delay : 0,
            root_dispersion : 0,
            reference_id : 0,
            reference_timestamp : NTPTimestamp{seconds:0, fraction:0},
            origin_timestamp : NTPTimestamp{seconds:0, fraction:0},
            receive_timestamp : NTPTimestamp{seconds:0, fraction:0},
            transmit_timestamp : NTPTimestamp{seconds:0, fraction:0}
        }
    }

    pub fn encode(&self) -> Vec<u8> {
        let mut vec = Vec::<u8>::new();

        vec.write_u8(self.leap << LEAP_SHIFT | self.version << VERSION_SHIFT | self.mode).unwrap();
        vec.write_u8(self.stratum).unwrap();
        vec.write_u8(self.poll).unwrap();
        vec.write_u8(self.precision).unwrap();
        vec.write_be_u32(self.root_delay).unwrap();
        vec.write_be_u32(self.root_dispersion).unwrap();
        vec.write_be_u32(self.reference_id).unwrap();
        vec.write_be_u32(self.reference_timestamp.seconds).unwrap();
        vec.write_be_u32(self.reference_timestamp.fraction).unwrap();
        vec.write_be_u32(self.origin_timestamp.seconds).unwrap();
        vec.write_be_u32(self.origin_timestamp.fraction).unwrap();
        vec.write_be_u32(self.receive_timestamp.seconds).unwrap();
        vec.write_be_u32(self.receive_timestamp.fraction).unwrap();
        vec.write_be_u32(self.transmit_timestamp.seconds).unwrap();
        vec.write_be_u32(self.transmit_timestamp.fraction).unwrap();
        vec
    }
}

fn main() {
    let header = NTPHeader::new();
    let message = header.encode();

    let socket = match UdpSocket::bind("0.0.0.0:35000") {
        Ok(s) => s,
        Err(e) => panic!("couldn't bind socket: {}", e),
    };

    match socket.send_to(message.as_slice(), ("sundial.columbia.edu:123")) {
        Ok(s) => s,
        Err(e) => panic!("Unable to send datagram: {}", e),
    };

    let mut buf = [0u8; 1000];

    match socket.recv_from(buf.as_mut_slice()) {
        Ok((amt, src)) => {
            println!("Got {} bytes from {}.", amt, src);
        },
        Err(e) => panic!("couldn't receive data: {}", e),
    };

    drop(socket);
}
<commit_msg>small improvements<commit_after>#![feature(old_io,net,core)]
use std::net::UdpSocket;

const NTP_SERVER: &'static str = "sundial.columbia.edu:123";
const UDP_LOCAL: &'static str = "0.0.0.0:35000";

const NTP_CLIENT: u8 = 3;

const LEAP_SHIFT: i32 = 6;
const VERSION_SHIFT: i32 = 3;

struct NTPTimestamp {
    seconds: u32,
    fraction: u32
}

struct NTPHeader {
    leap: u8,
    version: u8,
    mode: u8,
    stratum: u8,
    poll: u8,
    precision: u8,
    root_delay: u32,
    root_dispersion: u32,
    reference_id: u32,
    reference_timestamp: NTPTimestamp,
    origin_timestamp: NTPTimestamp,
    receive_timestamp: NTPTimestamp,
    transmit_timestamp: NTPTimestamp,
}

impl NTPHeader {
    pub fn new() -> NTPHeader {
        NTPHeader {
            leap: 0,
            version: 3,
            mode: NTP_CLIENT,
            stratum: 0,
            poll: 0,
            precision: 0,
            root_delay : 0,
            root_dispersion : 0,
            reference_id : 0,
            reference_timestamp : NTPTimestamp{seconds:0, fraction:0},
            origin_timestamp : NTPTimestamp{seconds:0, fraction:0},
            receive_timestamp : NTPTimestamp{seconds:0, fraction:0},
            transmit_timestamp : NTPTimestamp{seconds:0, fraction:0}
        }
    }

    pub fn encode(&self) -> Vec<u8> {
        let mut vec = Vec::<u8>::new();

        vec.write_u8(self.leap << LEAP_SHIFT | self.version << VERSION_SHIFT | self.mode).unwrap();
        vec.write_u8(self.stratum).unwrap();
        vec.write_u8(self.poll).unwrap();
        vec.write_u8(self.precision).unwrap();
        vec.write_be_u32(self.root_delay).unwrap();
        vec.write_be_u32(self.root_dispersion).unwrap();
        vec.write_be_u32(self.reference_id).unwrap();
        vec.write_be_u32(self.reference_timestamp.seconds).unwrap();
        vec.write_be_u32(self.reference_timestamp.fraction).unwrap();
        vec.write_be_u32(self.origin_timestamp.seconds).unwrap();
        vec.write_be_u32(self.origin_timestamp.fraction).unwrap();
        vec.write_be_u32(self.receive_timestamp.seconds).unwrap();
        vec.write_be_u32(self.receive_timestamp.fraction).unwrap();
        vec.write_be_u32(self.transmit_timestamp.seconds).unwrap();
        vec.write_be_u32(self.transmit_timestamp.fraction).unwrap();
        vec
    }
}

fn main() {
    let header = NTPHeader::new();
    let message = header.encode();

    let socket = match UdpSocket::bind(UDP_LOCAL) {
        Ok(s) => s,
        Err(e) => panic!("couldn't bind socket: {}", e),
    };

    match socket.send_to(message.as_slice(), (NTP_SERVER)) {
        Ok(s) => s,
        Err(e) => panic!("Unable to send datagram: {}", e),
    };

    let mut buf = [0u8; 1000];

    match socket.recv_from(buf.as_mut_slice()) {
        Ok((amt, src)) => {
            println!("Got {} bytes from {}.", amt, src);
        },
        Err(e) => panic!("couldn't receive data: {}", e),
    };

    drop(socket);
}
<|endoftext|>


<commit_before>extern crate termion;
extern crate clipboard;
extern crate ropey;

#[macro_use]
mod macros;

mod view;
mod state;
mod command;

use std::env;
use state::{Text, Recorded, Select};
use view::View;
use std::io::stdin;
use termion::input::TermRead;
use command::Command;

fn main() {
    let args = env::args();
    if args.len() > 1 {
        for filename in args.skip(1) {
            edit_file(Some(filename));
        }
    } else {
        edit_file(None);
    }
}

fn edit_file(filename: Option<String>) {

    let mut text = build_text(filename);
    let mut view = View::new().unwrap();
    let mut command = Command::new();

    let stdin = stdin();

    view.render(&text).unwrap();

    let mut events = stdin.events();
    loop {
        if let Some(event) = events.next() {
            if command.treat_event(&mut text, &mut view, event.unwrap()) {
                break;
            }
            view.render(&text).unwrap();
        }
    }
}

fn build_text(filename: Option<String>) -> Select<Recorded<Text>> {
    Select::new(Recorded::new(match filename {
        Some(name) => {
            match Text::open_file(name) {
                Ok(v) => v,
                Err(e) => panic!(e.to_string()),
            }
        }
        None => Text::empty(),
    }))
}
<commit_msg>Fix panic statement<commit_after>extern crate termion;
extern crate clipboard;
extern crate ropey;

#[macro_use]
mod macros;

mod view;
mod state;
mod command;

use std::env;
use state::{Text, Recorded, Select};
use view::View;
use std::io::stdin;
use termion::input::TermRead;
use command::Command;

fn main() {
    let args = env::args();
    if args.len() > 1 {
        for filename in args.skip(1) {
            edit_file(Some(filename));
        }
    } else {
        edit_file(None);
    }
}

fn edit_file(filename: Option<String>) {

    let mut text = build_text(filename);
    let mut view = View::new().unwrap();
    let mut command = Command::new();

    let stdin = stdin();

    view.render(&text).unwrap();

    let mut events = stdin.events();
    loop {
        if let Some(event) = events.next() {
            if command.treat_event(&mut text, &mut view, event.unwrap()) {
                break;
            }
            view.render(&text).unwrap();
        }
    }
}

fn build_text(filename: Option<String>) -> Select<Recorded<Text>> {
    Select::new(Recorded::new(match filename {
        Some(name) => {
            match Text::open_file(name) {
                Ok(v) => v,
                Err(e) => panic!("{}", e),
            }
        }
        None => Text::empty(),
    }))
}
<|endoftext|>


<commit_before>#![deny(bare_trait_objects, anonymous_parameters, elided_lifetimes_in_paths)]

use cargo;
use env_logger;

#[macro_use]
mod macros;
mod cargo_ops;
use crate::cargo_ops::{ElaborateWorkspace, TempProject};

use cargo::core::maybe_allow_nightly_features;
use cargo::core::shell::Verbosity;
use cargo::core::Workspace;
use cargo::util::important_paths::find_root_manifest_for_wd;
use cargo::util::{CargoResult, CliError, Config};
use docopt::Docopt;

pub const USAGE: &str = "
Displays information about project dependency versions

USAGE:
    cargo outdated [options]

Options:
    -a, --aggressive            Ignores channels for latest updates
    -h, --help                  Prints help information
        --format FORMAT         Output formatting [default: list]
                                [values: list, json]
    -q, --quiet                 Suppresses warnings
    -R, --root-deps-only        Only check root dependencies (Equivalent to --depth=1)
    -V, --version               Prints version information
    -v, --verbose ...           Use verbose output
    -w, --workspace             Checks updates for all workspace members rather than
                                only the root package
        --color COLOR           Coloring: auto, always, never [default: auto]
                                [values: auto, always, never]
    -d, --depth NUM             How deep in the dependency chain to search
                                (Defaults to all dependencies when omitted)
        --exit-code NUM         The exit code to return on new versions found [default: 0]
        --features FEATURES     Space-separated list of features
    -m, --manifest-path FILE    An absolute path to the Cargo.toml file to use
                                (Defaults to Cargo.toml in project root)
    -p, --packages PKGS         Packages to inspect for updates
    -r, --root ROOT             Package to treat as the root package
";

/// Options from CLI arguments
#[derive(serde_derive::Deserialize, Debug)]
pub struct Options {
    flag_format: Option<String>,
    flag_color: Option<String>,
    flag_features: Vec<String>,
    flag_manifest_path: Option<String>,
    flag_quiet: bool,
    flag_verbose: u32,
    flag_exit_code: i32,
    flag_packages: Vec<String>,
    flag_root: Option<String>,
    flag_depth: Option<i32>,
    flag_root_deps_only: bool,
    flag_workspace: bool,
    flag_aggressive: bool,
}

impl Options {
    fn all_features(&self) -> bool {
        self.flag_features.is_empty()
    }

    fn no_default_features(&self) -> bool {
        !(self.flag_features.is_empty() || self.flag_features.contains(&"default".to_owned()))
    }

    fn locked(&self) -> bool {
        false
    }

    fn frozen(&self) -> bool {
        false
    }
}

fn main() {
    env_logger::init();
    let options = {
        let mut options: Options = Docopt::new(USAGE)
            .and_then(|d| {
                d.version(Some(
                    concat!(env!("CARGO_PKG_NAME"), " v", env!("CARGO_PKG_VERSION")).to_owned(),
                ))
                .deserialize()
            })
            .unwrap_or_else(|e| e.exit());
        fn flat_split(arg: &[String]) -> Vec<String> {
            arg.iter()
                .flat_map(|s| s.split_whitespace())
                .flat_map(|s| s.split(','))
                .filter(|s| !s.is_empty())
                .map(ToString::to_string)
                .collect()
        }
        options.flag_features = flat_split(&options.flag_features);
        options.flag_packages = flat_split(&options.flag_packages);
        if options.flag_root_deps_only {
            options.flag_depth = Some(1);
        }
        options
    };

    let mut config = match Config::default() {
        Ok(cfg) => cfg,
        Err(e) => {
            let mut shell = cargo::core::Shell::new();
            cargo::exit_with_error(e.into(), &mut shell)
        }
    };
    let exit_code = options.flag_exit_code;
    let result = execute(options, &mut config);
    match result {
        Err(e) => {
            config.shell().set_verbosity(Verbosity::Normal);
            let cli_error = CliError::new(e, 1);
            cargo::exit_with_error(cli_error, &mut *config.shell())
        }
        Ok(i) => {
            if i > 0 {
                std::process::exit(exit_code);
            } else {
                std::process::exit(0);
            }
        }
    }
}

pub fn execute(options: Options, config: &mut Config) -> CargoResult<i32> {
    config.configure(
        options.flag_verbose,
        None,
        &options.flag_color,
        options.frozen(),
        options.locked(),
        false,
        &None,
        &[],
    )?;
    debug!(config, format!("options: {:?}", options));

    // Needed to allow nightly features
    maybe_allow_nightly_features();

    verbose!(config, "Parsing...", "current workspace");
    // the Cargo.toml that we are actually working on
    let curr_manifest = if let Some(ref manifest_path) = options.flag_manifest_path {
        manifest_path.into()
    } else {
        find_root_manifest_for_wd(config.cwd())?
    };
    let curr_workspace = Workspace::new(&curr_manifest, config)?;
    verbose!(config, "Resolving...", "current workspace");
    if options.flag_verbose == 0 {
        config.shell().set_verbosity(Verbosity::Quiet);
    }
    let ela_curr = ElaborateWorkspace::from_workspace(&curr_workspace, &options)?;
    if options.flag_verbose > 0 {
        config.shell().set_verbosity(Verbosity::Verbose);
    } else {
        config.shell().set_verbosity(Verbosity::Normal);
    }

    verbose!(config, "Parsing...", "compat workspace");
    let compat_proj =
        TempProject::from_workspace(&ela_curr, &curr_manifest.to_string_lossy(), &options)?;
    compat_proj.write_manifest_semver(
        curr_workspace.root(),
        compat_proj.temp_dir.path(),
        &ela_curr,
    )?;
    verbose!(config, "Updating...", "compat workspace");
    compat_proj.cargo_update()?;
    verbose!(config, "Resolving...", "compat workspace");
    let compat_workspace = compat_proj.workspace.borrow();
    let ela_compat =
        ElaborateWorkspace::from_workspace(compat_workspace.as_ref().unwrap(), &options)?;

    verbose!(config, "Parsing...", "latest workspace");
    let latest_proj =
        TempProject::from_workspace(&ela_curr, &curr_manifest.to_string_lossy(), &options)?;
    latest_proj.write_manifest_latest(
        curr_workspace.root(),
        compat_proj.temp_dir.path(),
        &ela_curr,
    )?;
    verbose!(config, "Updating...", "latest workspace");
    latest_proj.cargo_update()?;
    verbose!(config, "Resolving...", "latest workspace");
    let latest_workspace = latest_proj.workspace.borrow();
    let ela_latest =
        ElaborateWorkspace::from_workspace(latest_workspace.as_ref().unwrap(), &options)?;

    if ela_curr.workspace_mode {
        let mut sum = 0;
        if options.flag_format == Some("list".to_string()) {
            verbose!(config, "Printing...", "Package status in list format");
        } else if options.flag_format == Some("json".to_string()) {
            verbose!(config, "Printing...", "Package status in json format");
        }

        for member in ela_curr.workspace.members() {
            ela_curr.resolve_status(
                &ela_compat,
                &ela_latest,
                &options,
                config,
                member.package_id(),
            )?;
            if options.flag_format == Some("list".to_string()) {
                sum += ela_curr.print_list(&options, &member.package_id(), sum > 0)?;
            } else if options.flag_format == Some("json".to_string()) {
                sum += ela_curr.print_json(&options, &member.package_id(), sum > 0)?;
            }
        }
        if sum == 0 {
            println!("All dependencies are up to date, yay!");
        }
        Ok(sum)
    } else {
        verbose!(config, "Resolving...", "package status");
        let root = ela_curr.determine_root(&options)?;
        ela_curr.resolve_status(&ela_compat, &ela_latest, &options, config, root)?;
        verbose!(config, "Printing...", "list format");
        let mut count = 0;

        if options.flag_format == Some("list".to_string()) {
            count = ela_curr.print_list(&options, root, false)?;
        } else if options.flag_format == Some("json".to_string()) {
            ela_curr.print_json(&options, &root, false)?;
        } else {
            println!("Error, did not specify list or json output formatting");
            std::process::exit(2);
        }

        Ok(count)
    }
}
<commit_msg>Removed borrow from print_list() that was a mistake that should not have been altered<commit_after>#![deny(bare_trait_objects, anonymous_parameters, elided_lifetimes_in_paths)]

use cargo;
use env_logger;

#[macro_use]
mod macros;
mod cargo_ops;
use crate::cargo_ops::{ElaborateWorkspace, TempProject};

use cargo::core::maybe_allow_nightly_features;
use cargo::core::shell::Verbosity;
use cargo::core::Workspace;
use cargo::util::important_paths::find_root_manifest_for_wd;
use cargo::util::{CargoResult, CliError, Config};
use docopt::Docopt;

pub const USAGE: &str = "
Displays information about project dependency versions

USAGE:
    cargo outdated [options]

Options:
    -a, --aggressive            Ignores channels for latest updates
    -h, --help                  Prints help information
        --format FORMAT         Output formatting [default: list]
                                [values: list, json]
    -q, --quiet                 Suppresses warnings
    -R, --root-deps-only        Only check root dependencies (Equivalent to --depth=1)
    -V, --version               Prints version information
    -v, --verbose ...           Use verbose output
    -w, --workspace             Checks updates for all workspace members rather than
                                only the root package
        --color COLOR           Coloring: auto, always, never [default: auto]
                                [values: auto, always, never]
    -d, --depth NUM             How deep in the dependency chain to search
                                (Defaults to all dependencies when omitted)
        --exit-code NUM         The exit code to return on new versions found [default: 0]
        --features FEATURES     Space-separated list of features
    -m, --manifest-path FILE    An absolute path to the Cargo.toml file to use
                                (Defaults to Cargo.toml in project root)
    -p, --packages PKGS         Packages to inspect for updates
    -r, --root ROOT             Package to treat as the root package
";

/// Options from CLI arguments
#[derive(serde_derive::Deserialize, Debug)]
pub struct Options {
    flag_format: Option<String>,
    flag_color: Option<String>,
    flag_features: Vec<String>,
    flag_manifest_path: Option<String>,
    flag_quiet: bool,
    flag_verbose: u32,
    flag_exit_code: i32,
    flag_packages: Vec<String>,
    flag_root: Option<String>,
    flag_depth: Option<i32>,
    flag_root_deps_only: bool,
    flag_workspace: bool,
    flag_aggressive: bool,
}

impl Options {
    fn all_features(&self) -> bool {
        self.flag_features.is_empty()
    }

    fn no_default_features(&self) -> bool {
        !(self.flag_features.is_empty() || self.flag_features.contains(&"default".to_owned()))
    }

    fn locked(&self) -> bool {
        false
    }

    fn frozen(&self) -> bool {
        false
    }
}

fn main() {
    env_logger::init();
    let options = {
        let mut options: Options = Docopt::new(USAGE)
            .and_then(|d| {
                d.version(Some(
                    concat!(env!("CARGO_PKG_NAME"), " v", env!("CARGO_PKG_VERSION")).to_owned(),
                ))
                .deserialize()
            })
            .unwrap_or_else(|e| e.exit());
        fn flat_split(arg: &[String]) -> Vec<String> {
            arg.iter()
                .flat_map(|s| s.split_whitespace())
                .flat_map(|s| s.split(','))
                .filter(|s| !s.is_empty())
                .map(ToString::to_string)
                .collect()
        }
        options.flag_features = flat_split(&options.flag_features);
        options.flag_packages = flat_split(&options.flag_packages);
        if options.flag_root_deps_only {
            options.flag_depth = Some(1);
        }
        options
    };

    let mut config = match Config::default() {
        Ok(cfg) => cfg,
        Err(e) => {
            let mut shell = cargo::core::Shell::new();
            cargo::exit_with_error(e.into(), &mut shell)
        }
    };
    let exit_code = options.flag_exit_code;
    let result = execute(options, &mut config);
    match result {
        Err(e) => {
            config.shell().set_verbosity(Verbosity::Normal);
            let cli_error = CliError::new(e, 1);
            cargo::exit_with_error(cli_error, &mut *config.shell())
        }
        Ok(i) => {
            if i > 0 {
                std::process::exit(exit_code);
            } else {
                std::process::exit(0);
            }
        }
    }
}

pub fn execute(options: Options, config: &mut Config) -> CargoResult<i32> {
    config.configure(
        options.flag_verbose,
        None,
        &options.flag_color,
        options.frozen(),
        options.locked(),
        false,
        &None,
        &[],
    )?;
    debug!(config, format!("options: {:?}", options));

    // Needed to allow nightly features
    maybe_allow_nightly_features();

    verbose!(config, "Parsing...", "current workspace");
    // the Cargo.toml that we are actually working on
    let curr_manifest = if let Some(ref manifest_path) = options.flag_manifest_path {
        manifest_path.into()
    } else {
        find_root_manifest_for_wd(config.cwd())?
    };
    let curr_workspace = Workspace::new(&curr_manifest, config)?;
    verbose!(config, "Resolving...", "current workspace");
    if options.flag_verbose == 0 {
        config.shell().set_verbosity(Verbosity::Quiet);
    }
    let ela_curr = ElaborateWorkspace::from_workspace(&curr_workspace, &options)?;
    if options.flag_verbose > 0 {
        config.shell().set_verbosity(Verbosity::Verbose);
    } else {
        config.shell().set_verbosity(Verbosity::Normal);
    }

    verbose!(config, "Parsing...", "compat workspace");
    let compat_proj =
        TempProject::from_workspace(&ela_curr, &curr_manifest.to_string_lossy(), &options)?;
    compat_proj.write_manifest_semver(
        curr_workspace.root(),
        compat_proj.temp_dir.path(),
        &ela_curr,
    )?;
    verbose!(config, "Updating...", "compat workspace");
    compat_proj.cargo_update()?;
    verbose!(config, "Resolving...", "compat workspace");
    let compat_workspace = compat_proj.workspace.borrow();
    let ela_compat =
        ElaborateWorkspace::from_workspace(compat_workspace.as_ref().unwrap(), &options)?;

    verbose!(config, "Parsing...", "latest workspace");
    let latest_proj =
        TempProject::from_workspace(&ela_curr, &curr_manifest.to_string_lossy(), &options)?;
    latest_proj.write_manifest_latest(
        curr_workspace.root(),
        compat_proj.temp_dir.path(),
        &ela_curr,
    )?;
    verbose!(config, "Updating...", "latest workspace");
    latest_proj.cargo_update()?;
    verbose!(config, "Resolving...", "latest workspace");
    let latest_workspace = latest_proj.workspace.borrow();
    let ela_latest =
        ElaborateWorkspace::from_workspace(latest_workspace.as_ref().unwrap(), &options)?;

    if ela_curr.workspace_mode {
        let mut sum = 0;
        if options.flag_format == Some("list".to_string()) {
            verbose!(config, "Printing...", "Package status in list format");
        } else if options.flag_format == Some("json".to_string()) {
            verbose!(config, "Printing...", "Package status in json format");
        }

        for member in ela_curr.workspace.members() {
            ela_curr.resolve_status(
                &ela_compat,
                &ela_latest,
                &options,
                config,
                member.package_id(),
            )?;
            if options.flag_format == Some("list".to_string()) {
                sum += ela_curr.print_list(&options, member.package_id(), sum > 0)?;
            } else if options.flag_format == Some("json".to_string()) {
                sum += ela_curr.print_json(&options, &member.package_id(), sum > 0)?;
            }
        }
        if sum == 0 {
            println!("All dependencies are up to date, yay!");
        }
        Ok(sum)
    } else {
        verbose!(config, "Resolving...", "package status");
        let root = ela_curr.determine_root(&options)?;
        ela_curr.resolve_status(&ela_compat, &ela_latest, &options, config, root)?;
        verbose!(config, "Printing...", "list format");
        let mut count = 0;

        if options.flag_format == Some("list".to_string()) {
            count = ela_curr.print_list(&options, root, false)?;
        } else if options.flag_format == Some("json".to_string()) {
            ela_curr.print_json(&options, &root, false)?;
        } else {
            println!("Error, did not specify list or json output formatting");
            std::process::exit(2);
        }

        Ok(count)
    }
}
<|endoftext|>