<commit_before>mod cmd;
mod config;
mod edit;
mod error;
mod fmt;
mod opts;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::io::{self, BufRead, Write};
use std::path::{Path, PathBuf};
use std::process::{self, Command, Stdio};
use std::str::FromStr;

use atty::Stream::{Stderr, Stdout};
use bat::assets::HighlightingAssets;
use bat::PrettyPrinter;
use quote::quote;
use structopt::StructOpt;
use termcolor::{Color::Green, ColorChoice, ColorSpec, StandardStream, WriteColor};

use crate::cmd::Line;
use crate::config::Config;
use crate::error::Result;
use crate::opts::Coloring::*;
use crate::opts::{Args, Coloring, Opts};

fn main() {
    let result = cargo_expand_or_run_nightly();
    process::exit(match result {
        Ok(code) => code,
        Err(err) => {
            let _ = writeln!(io::stderr(), "{}", err);
            1
        }
    });
}

fn cargo_expand_or_run_nightly() -> Result<i32> {
    const NO_RUN_NIGHTLY: &str = "CARGO_EXPAND_NO_RUN_NIGHTLY";

    let maybe_nightly = !definitely_not_nightly();
    if maybe_nightly || env::var_os(NO_RUN_NIGHTLY).is_some() {
        return cargo_expand();
    }

    let mut nightly = Command::new("cargo");
    nightly.arg("+nightly");
    nightly.arg("expand");

    let mut args = env::args_os().peekable();
    args.next().unwrap(); // cargo
    if args.peek().map_or(false, |arg| arg == "expand") {
        args.next().unwrap(); // expand
    }
    nightly.args(args);

    // Hopefully prevent infinite re-run loop.
    nightly.env(NO_RUN_NIGHTLY, "");

    let status = nightly.status()?;

    Ok(match status.code() {
        Some(code) => code,
        None => {
            if status.success() {
                0
            } else {
                1
            }
        }
    })
}

fn definitely_not_nightly() -> bool {
    let mut cmd = Command::new(cargo_binary());
    cmd.arg("--version");

    let output = match cmd.output() {
        Ok(output) => output,
        Err(_) => return false,
    };

    let version = match String::from_utf8(output.stdout) {
        Ok(version) => version,
        Err(_) => return false,
    };

    version.starts_with("cargo 1") && !version.contains("nightly")
}

fn cargo_binary() -> OsString {
    env::var_os("CARGO").unwrap_or_else(|| "cargo".to_owned().into())
}

fn cargo_expand() -> Result<i32> {
    let Opts::Expand(args) = Opts::from_args();
    let config = config::deserialize();

    if args.themes {
        for theme in HighlightingAssets::from_binary().themes() {
            let _ = writeln!(io::stdout(), "{}", theme);
        }
        return Ok(0);
    }

    let rustfmt;
    match (&args.item, args.ugly) {
        (Some(item), true) => {
            let _ = writeln!(
                io::stderr(),
                "ERROR: cannot expand single item ({}) in ugly mode.",
                item,
            );
            return Ok(1);
        }
        (Some(item), false) => {
            rustfmt = which_rustfmt();
            if rustfmt.is_none() {
                let _ = writeln!(
                    io::stderr(),
                    "ERROR: cannot expand single item ({}) without rustfmt.",
                    item,
                );
                let _ = writeln!(
                    io::stderr(),
                    "Install rustfmt by running `rustup component add rustfmt --toolchain nightly`.",
                );
                return Ok(1);
            }
        }
        (None, true) => rustfmt = None,
        (None, false) => rustfmt = which_rustfmt(),
    }

    let mut builder = tempfile::Builder::new();
    builder.prefix("cargo-expand");
    let outdir = builder.tempdir().expect("failed to create tmp file");
    let outfile_path = outdir.path().join("expanded");
    let color = get_color(&args, &config);

    // Run cargo
    let mut cmd = Command::new(cargo_binary());
    apply_args(&mut cmd, &args, &color, &outfile_path);
    let code = filter_err(&mut cmd, ignore_cargo_err)?;

    if !outfile_path.exists() {
        return Ok(1);
    }

    let mut content = fs::read_to_string(&outfile_path)?;
    if content.is_empty() {
        let _ = writeln!(io::stderr(), "ERROR: rustc produced no expanded output");
        return Ok(if code == 0 { 1 } else { code });
    }

    // Run rustfmt
    if let Some(rustfmt) = rustfmt {
        // Work around rustfmt not being able to parse paths containing $crate.
        // This placeholder should be the same width as $crate to preserve
        // alignments.
        const DOLLAR_CRATE_PLACEHOLDER: &str = "Ξcrate";
        content = content.replace("$crate", DOLLAR_CRATE_PLACEHOLDER);

        // Discard comments, which are misplaced by the compiler
        if let Ok(mut syntax_tree) = syn::parse_file(&content) {
            edit::sanitize(&mut syntax_tree);
            if let Some(filter) = args.item {
                syntax_tree.shebang = None;
                syntax_tree.attrs.clear();
                syntax_tree.items = filter.apply_to(&syntax_tree);
                if syntax_tree.items.is_empty() {
                    let _ = writeln!(io::stderr(), "WARNING: no such item: {}", filter);
                    return Ok(1);
                }
            }
            content = quote!(#syntax_tree).to_string();
        }
        fs::write(&outfile_path, content)?;

        fmt::write_rustfmt_config(&outdir)?;

        let output = Command::new(&rustfmt)
            .arg("--edition=2018")
            .arg(&outfile_path)
            .stderr(Stdio::null())
            .output();
        if let Ok(output) = output {
            if !output.status.success() {
                // Probably was the wrong edition.
                let _status = Command::new(&rustfmt)
                    .arg("--edition=2015")
                    .arg(&outfile_path)
                    .stderr(Stdio::null())
                    .status();
            }
        }

        content = fs::read_to_string(&outfile_path)?;
        content = content.replace(DOLLAR_CRATE_PLACEHOLDER, "$crate");
    }

    // Run pretty printer
    let theme = args.theme.or(config.theme);
    let none_theme = theme.as_deref() == Some("none");
    let do_color = match color {
        Always => true,
        Never => false,
        Auto => !none_theme && atty::is(Stdout),
    };
    let _ = writeln!(io::stderr());
    if do_color {
        let mut pretty_printer = PrettyPrinter::new();
        pretty_printer
            .input_from_bytes(content.as_bytes())
            .language("rust")
            .tab_width(Some(4))
            .true_color(false)
            .header(false)
            .line_numbers(false)
            .grid(false);
        if let Some(theme) = theme {
            pretty_printer.theme(theme);
        }

        // Ignore any errors.
        let _ = pretty_printer.print();
    } else {
        let _ = write!(io::stdout(), "{}", content);
    }

    Ok(0)
}

fn which_rustfmt() -> Option<PathBuf> {
    match env::var_os("RUSTFMT") {
        Some(which) => {
            if which.is_empty() {
                None
            } else {
                Some(PathBuf::from(which))
            }
        }
        None => toolchain_find::find_installed_component("rustfmt"),
    }
}

// Based on https://github.com/rsolomo/cargo-check
fn apply_args(cmd: &mut Command, args: &Args, color: &Coloring, outfile: &Path) {
    let mut line = Line::new("cargo");

    line.arg("rustc");

    if args.tests && args.test.is_none() {
        line.arg("--profile=test");
    } else {
        line.arg("--profile=check");
    }

    if let Some(features) = &args.features {
        line.arg("--features");
        line.arg(features);
    }

    if args.all_features {
        line.arg("--all-features");
    }

    if args.no_default_features {
        line.arg("--no-default-features");
    }

    if args.lib {
        line.arg("--lib");
    }

    if let Some(bin) = &args.bin {
        line.arg("--bin");
        line.arg(bin);
    }

    if let Some(example) = &args.example {
        line.arg("--example");
        line.arg(example);
    }

    if let Some(test) = &args.test {
        line.arg("--test");
        line.arg(test);
    }

    if let Some(bench) = &args.bench {
        line.arg("--bench");
        line.arg(bench);
    }

    if let Some(target) = &args.target {
        line.arg("--target");
        line.arg(target);
    }

    if let Some(target_dir) = &args.target_dir {
        line.arg("--target-dir");
        line.arg(target_dir);
    }

    if let Some(manifest_path) = &args.manifest_path {
        line.arg("--manifest-path");
        line.arg(manifest_path);
    }

    if let Some(package) = &args.package {
        line.arg("--package");
        line.arg(package);
    }

    if let Some(jobs) = args.jobs {
        line.arg("--jobs");
        line.arg(jobs.to_string());
    }

    if args.verbose {
        line.arg("--verbose");
    }

    line.arg("--color");
    match color {
        Coloring::Auto => line.arg(if atty::is(Stderr) { "always" } else { "never" }),
        color => line.arg(color.to_string()),
    }

    if args.frozen {
        line.arg("--frozen");
    }

    if args.locked {
        line.arg("--locked");
    }

    for unstable_flag in &args.unstable_flags {
        line.arg("-Z");
        line.arg(unstable_flag);
    }

    line.arg("--");

    line.arg("-o");
    line.arg(outfile);
    line.arg("-Zunstable-options");
    line.arg("--pretty=expanded");

    if args.verbose {
        let mut display = line.clone();
        display.insert(0, "+nightly");
        print_command(display, color);
    }

    cmd.args(line);
}

fn print_command(line: Line, color: &Coloring) {
    let color_choice = match color {
        Coloring::Auto => ColorChoice::Auto,
        Coloring::Always => ColorChoice::Always,
        Coloring::Never => ColorChoice::Never,
    };

    let mut stream = StandardStream::stderr(color_choice);
    let _ = stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Green)));
    let _ = write!(stream, "{:>12}", "Running");
    let _ = stream.reset();
    let _ = writeln!(stream, " `{}`", line);
}

fn filter_err(cmd: &mut Command, ignore: fn(&str) -> bool) -> io::Result<i32> {
    let mut child = cmd.stderr(Stdio::piped()).spawn()?;
    let mut stderr = io::BufReader::new(child.stderr.take().unwrap());
    let mut line = String::new();
    while let Ok(n) = stderr.read_line(&mut line) {
        if n == 0 {
            break;
        }
        if !ignore(&line) {
            let _ = write!(io::stderr(), "{}", line);
        }
        line.clear();
    }
    let code = child.wait()?.code().unwrap_or(1);
    Ok(code)
}

fn ignore_cargo_err(line: &str) -> bool {
    if line.trim().is_empty() {
        return true;
    }

    let blacklist = [
        "ignoring specified output filename because multiple outputs were \
         requested",
        "ignoring specified output filename for 'link' output because multiple \
         outputs were requested",
        "ignoring --out-dir flag due to -o flag",
        "ignoring -C extra-filename flag due to -o flag",
        "due to multiple output types requested, the explicitly specified \
         output file name will be adapted for each output type",
        "warning emitted",
        "warnings emitted",
    ];
    for s in &blacklist {
        if line.contains(s) {
            return true;
        }
    }

    false
}

fn get_color(args: &Args, config: &Config) -> Coloring {
    if let Some(value) = args.color {
        return value;
    }

    if let Some(value) = config.color.as_ref() {
        match Coloring::from_str(value.as_str()) {
            Ok(color) => return color,
            Err(err) => {
                let _ = writeln!(
                    io::stderr(),
                    "WARNING: invalid color in cargo config: {}",
                    err
                );
            }
        }
    }

    Coloring::Auto // default
}
<commit_msg>Replace use of blacklist as variable name<commit_after>mod cmd;
mod config;
mod edit;
mod error;
mod fmt;
mod opts;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::io::{self, BufRead, Write};
use std::path::{Path, PathBuf};
use std::process::{self, Command, Stdio};
use std::str::FromStr;

use atty::Stream::{Stderr, Stdout};
use bat::assets::HighlightingAssets;
use bat::PrettyPrinter;
use quote::quote;
use structopt::StructOpt;
use termcolor::{Color::Green, ColorChoice, ColorSpec, StandardStream, WriteColor};

use crate::cmd::Line;
use crate::config::Config;
use crate::error::Result;
use crate::opts::Coloring::*;
use crate::opts::{Args, Coloring, Opts};

fn main() {
    let result = cargo_expand_or_run_nightly();
    process::exit(match result {
        Ok(code) => code,
        Err(err) => {
            let _ = writeln!(io::stderr(), "{}", err);
            1
        }
    });
}

fn cargo_expand_or_run_nightly() -> Result<i32> {
    const NO_RUN_NIGHTLY: &str = "CARGO_EXPAND_NO_RUN_NIGHTLY";

    let maybe_nightly = !definitely_not_nightly();
    if maybe_nightly || env::var_os(NO_RUN_NIGHTLY).is_some() {
        return cargo_expand();
    }

    let mut nightly = Command::new("cargo");
    nightly.arg("+nightly");
    nightly.arg("expand");

    let mut args = env::args_os().peekable();
    args.next().unwrap(); // cargo
    if args.peek().map_or(false, |arg| arg == "expand") {
        args.next().unwrap(); // expand
    }
    nightly.args(args);

    // Hopefully prevent infinite re-run loop.
    nightly.env(NO_RUN_NIGHTLY, "");

    let status = nightly.status()?;

    Ok(match status.code() {
        Some(code) => code,
        None => {
            if status.success() {
                0
            } else {
                1
            }
        }
    })
}

fn definitely_not_nightly() -> bool {
    let mut cmd = Command::new(cargo_binary());
    cmd.arg("--version");

    let output = match cmd.output() {
        Ok(output) => output,
        Err(_) => return false,
    };

    let version = match String::from_utf8(output.stdout) {
        Ok(version) => version,
        Err(_) => return false,
    };

    version.starts_with("cargo 1") && !version.contains("nightly")
}

fn cargo_binary() -> OsString {
    env::var_os("CARGO").unwrap_or_else(|| "cargo".to_owned().into())
}

fn cargo_expand() -> Result<i32> {
    let Opts::Expand(args) = Opts::from_args();
    let config = config::deserialize();

    if args.themes {
        for theme in HighlightingAssets::from_binary().themes() {
            let _ = writeln!(io::stdout(), "{}", theme);
        }
        return Ok(0);
    }

    let rustfmt;
    match (&args.item, args.ugly) {
        (Some(item), true) => {
            let _ = writeln!(
                io::stderr(),
                "ERROR: cannot expand single item ({}) in ugly mode.",
                item,
            );
            return Ok(1);
        }
        (Some(item), false) => {
            rustfmt = which_rustfmt();
            if rustfmt.is_none() {
                let _ = writeln!(
                    io::stderr(),
                    "ERROR: cannot expand single item ({}) without rustfmt.",
                    item,
                );
                let _ = writeln!(
                    io::stderr(),
                    "Install rustfmt by running `rustup component add rustfmt --toolchain nightly`.",
                );
                return Ok(1);
            }
        }
        (None, true) => rustfmt = None,
        (None, false) => rustfmt = which_rustfmt(),
    }

    let mut builder = tempfile::Builder::new();
    builder.prefix("cargo-expand");
    let outdir = builder.tempdir().expect("failed to create tmp file");
    let outfile_path = outdir.path().join("expanded");
    let color = get_color(&args, &config);

    // Run cargo
    let mut cmd = Command::new(cargo_binary());
    apply_args(&mut cmd, &args, &color, &outfile_path);
    let code = filter_err(&mut cmd, ignore_cargo_err)?;

    if !outfile_path.exists() {
        return Ok(1);
    }

    let mut content = fs::read_to_string(&outfile_path)?;
    if content.is_empty() {
        let _ = writeln!(io::stderr(), "ERROR: rustc produced no expanded output");
        return Ok(if code == 0 { 1 } else { code });
    }

    // Run rustfmt
    if let Some(rustfmt) = rustfmt {
        // Work around rustfmt not being able to parse paths containing $crate.
        // This placeholder should be the same width as $crate to preserve
        // alignments.
        const DOLLAR_CRATE_PLACEHOLDER: &str = "Ξcrate";
        content = content.replace("$crate", DOLLAR_CRATE_PLACEHOLDER);

        // Discard comments, which are misplaced by the compiler
        if let Ok(mut syntax_tree) = syn::parse_file(&content) {
            edit::sanitize(&mut syntax_tree);
            if let Some(filter) = args.item {
                syntax_tree.shebang = None;
                syntax_tree.attrs.clear();
                syntax_tree.items = filter.apply_to(&syntax_tree);
                if syntax_tree.items.is_empty() {
                    let _ = writeln!(io::stderr(), "WARNING: no such item: {}", filter);
                    return Ok(1);
                }
            }
            content = quote!(#syntax_tree).to_string();
        }
        fs::write(&outfile_path, content)?;

        fmt::write_rustfmt_config(&outdir)?;

        let output = Command::new(&rustfmt)
            .arg("--edition=2018")
            .arg(&outfile_path)
            .stderr(Stdio::null())
            .output();
        if let Ok(output) = output {
            if !output.status.success() {
                // Probably was the wrong edition.
                let _status = Command::new(&rustfmt)
                    .arg("--edition=2015")
                    .arg(&outfile_path)
                    .stderr(Stdio::null())
                    .status();
            }
        }

        content = fs::read_to_string(&outfile_path)?;
        content = content.replace(DOLLAR_CRATE_PLACEHOLDER, "$crate");
    }

    // Run pretty printer
    let theme = args.theme.or(config.theme);
    let none_theme = theme.as_deref() == Some("none");
    let do_color = match color {
        Always => true,
        Never => false,
        Auto => !none_theme && atty::is(Stdout),
    };
    let _ = writeln!(io::stderr());
    if do_color {
        let mut pretty_printer = PrettyPrinter::new();
        pretty_printer
            .input_from_bytes(content.as_bytes())
            .language("rust")
            .tab_width(Some(4))
            .true_color(false)
            .header(false)
            .line_numbers(false)
            .grid(false);
        if let Some(theme) = theme {
            pretty_printer.theme(theme);
        }

        // Ignore any errors.
        let _ = pretty_printer.print();
    } else {
        let _ = write!(io::stdout(), "{}", content);
    }

    Ok(0)
}

fn which_rustfmt() -> Option<PathBuf> {
    match env::var_os("RUSTFMT") {
        Some(which) => {
            if which.is_empty() {
                None
            } else {
                Some(PathBuf::from(which))
            }
        }
        None => toolchain_find::find_installed_component("rustfmt"),
    }
}

// Based on https://github.com/rsolomo/cargo-check
fn apply_args(cmd: &mut Command, args: &Args, color: &Coloring, outfile: &Path) {
    let mut line = Line::new("cargo");

    line.arg("rustc");

    if args.tests && args.test.is_none() {
        line.arg("--profile=test");
    } else {
        line.arg("--profile=check");
    }

    if let Some(features) = &args.features {
        line.arg("--features");
        line.arg(features);
    }

    if args.all_features {
        line.arg("--all-features");
    }

    if args.no_default_features {
        line.arg("--no-default-features");
    }

    if args.lib {
        line.arg("--lib");
    }

    if let Some(bin) = &args.bin {
        line.arg("--bin");
        line.arg(bin);
    }

    if let Some(example) = &args.example {
        line.arg("--example");
        line.arg(example);
    }

    if let Some(test) = &args.test {
        line.arg("--test");
        line.arg(test);
    }

    if let Some(bench) = &args.bench {
        line.arg("--bench");
        line.arg(bench);
    }

    if let Some(target) = &args.target {
        line.arg("--target");
        line.arg(target);
    }

    if let Some(target_dir) = &args.target_dir {
        line.arg("--target-dir");
        line.arg(target_dir);
    }

    if let Some(manifest_path) = &args.manifest_path {
        line.arg("--manifest-path");
        line.arg(manifest_path);
    }

    if let Some(package) = &args.package {
        line.arg("--package");
        line.arg(package);
    }

    if let Some(jobs) = args.jobs {
        line.arg("--jobs");
        line.arg(jobs.to_string());
    }

    if args.verbose {
        line.arg("--verbose");
    }

    line.arg("--color");
    match color {
        Coloring::Auto => line.arg(if atty::is(Stderr) { "always" } else { "never" }),
        color => line.arg(color.to_string()),
    }

    if args.frozen {
        line.arg("--frozen");
    }

    if args.locked {
        line.arg("--locked");
    }

    for unstable_flag in &args.unstable_flags {
        line.arg("-Z");
        line.arg(unstable_flag);
    }

    line.arg("--");

    line.arg("-o");
    line.arg(outfile);
    line.arg("-Zunstable-options");
    line.arg("--pretty=expanded");

    if args.verbose {
        let mut display = line.clone();
        display.insert(0, "+nightly");
        print_command(display, color);
    }

    cmd.args(line);
}

fn print_command(line: Line, color: &Coloring) {
    let color_choice = match color {
        Coloring::Auto => ColorChoice::Auto,
        Coloring::Always => ColorChoice::Always,
        Coloring::Never => ColorChoice::Never,
    };

    let mut stream = StandardStream::stderr(color_choice);
    let _ = stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Green)));
    let _ = write!(stream, "{:>12}", "Running");
    let _ = stream.reset();
    let _ = writeln!(stream, " `{}`", line);
}

fn filter_err(cmd: &mut Command, ignore: fn(&str) -> bool) -> io::Result<i32> {
    let mut child = cmd.stderr(Stdio::piped()).spawn()?;
    let mut stderr = io::BufReader::new(child.stderr.take().unwrap());
    let mut line = String::new();
    while let Ok(n) = stderr.read_line(&mut line) {
        if n == 0 {
            break;
        }
        if !ignore(&line) {
            let _ = write!(io::stderr(), "{}", line);
        }
        line.clear();
    }
    let code = child.wait()?.code().unwrap_or(1);
    Ok(code)
}

fn ignore_cargo_err(line: &str) -> bool {
    if line.trim().is_empty() {
        return true;
    }

    let discarded_lines = [
        "ignoring specified output filename because multiple outputs were \
         requested",
        "ignoring specified output filename for 'link' output because multiple \
         outputs were requested",
        "ignoring --out-dir flag due to -o flag",
        "ignoring -C extra-filename flag due to -o flag",
        "due to multiple output types requested, the explicitly specified \
         output file name will be adapted for each output type",
        "warning emitted",
        "warnings emitted",
    ];
    for s in &discarded_lines {
        if line.contains(s) {
            return true;
        }
    }

    false
}

fn get_color(args: &Args, config: &Config) -> Coloring {
    if let Some(value) = args.color {
        return value;
    }

    if let Some(value) = config.color.as_ref() {
        match Coloring::from_str(value.as_str()) {
            Ok(color) => return color,
            Err(err) => {
                let _ = writeln!(
                    io::stderr(),
                    "WARNING: invalid color in cargo config: {}",
                    err
                );
            }
        }
    }

    Coloring::Auto // default
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

// import local modules
extern crate doppler;
use doppler::usage;
use doppler::usage::Mode::{ConstMode, TrackMode};
use doppler::usage::InputType::{I16, F32};
use doppler::dsp;

// import external modules
use std::process::exit;
use std::io;
use std::io::Read;
use std::io::Write;

extern crate time;
extern crate gpredict;
use gpredict::predict;
use gpredict::tle;

const SPEED_OF_LIGHT_M_S: f64 = 299792458.;
const BUFFER_SIZE: usize = 8192;

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

fn main() {
    let args = usage::args();

    println_stderr!("doppler {} andres.vahter@gmail.com\n\n", env!("CARGO_PKG_VERSION"));

    let mut stdin = io::stdin();
    let mut stdout = io::stdout();
    let mut inbuf: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
    let mut outbuf: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
    let mut samplenr: u32 = 0;

    let mut shift = |intype: doppler::usage::InputType, shift_hz: f64, samplerate: u32| {
        let mut count_and_buflen: (usize, usize) = (0, 0);
        match stdin.read(&mut inbuf) {
            Ok(size) => {
                match intype {
                    I16 => {
                        count_and_buflen = dsp::shift_frequency_i16(&inbuf[0 .. size],
                                                    &mut samplenr,
                                                    shift_hz,
                                                    samplerate,
                                                    &mut outbuf);
                    },

                    F32 => {
                        count_and_buflen = dsp::shift_frequency_f32(&inbuf[0 .. size],
                                                    &mut samplenr,
                                                    shift_hz,
                                                    samplerate,
                                                    &mut outbuf);
                    },
                }

                let sample_count = count_and_buflen.0;
                let buflen = count_and_buflen.1;

                stdout.write(&outbuf[0 .. buflen]).unwrap();

                if size < BUFFER_SIZE {
                    return (true, sample_count);
                }
            }
            Err(e) => {
                println_stderr!("err: {:?}", e);
                return (true, 0);
            }
        }
        return (false, count_and_buflen.0);
    };

    match *args.mode.as_ref().unwrap() {
        ConstMode => {
            println_stderr!("constant shift mode");
            println_stderr!("\tIQ samplerate   : {}", args.samplerate.as_ref().unwrap());
            println_stderr!("\tIQ input type   : {}", args.inputtype.as_ref().unwrap());
            println_stderr!("\tIQ output type  : i16\n");
            println_stderr!("\tfrequency shift : {} Hz", args.constargs.shift.as_ref().unwrap());

            let intype = args.inputtype.unwrap();
            let shift_hz = args.constargs.shift.unwrap() as f64;
            let samplerate = args.samplerate.unwrap();

            loop {
                let stop_and_count: (bool, usize) = shift(intype, shift_hz, samplerate);
                if stop_and_count.0 {
                    break;
                }
            }
        }

        TrackMode => {
            println_stderr!("tracking mode");
            println_stderr!("\tIQ samplerate   : {}", args.samplerate.as_ref().unwrap());
            println_stderr!("\tIQ input type   : {}", args.inputtype.as_ref().unwrap());
            println_stderr!("\tIQ output type  : i16\n");
            println_stderr!("\tTLE file        : {}", args.trackargs.tlefile.as_ref().unwrap());
            println_stderr!("\tTLE name        : {}", args.trackargs.tlename.as_ref().unwrap());
            println_stderr!("\tlocation        : {:?}", args.trackargs.location.as_ref().unwrap());
            if args.trackargs.time.is_some() {
                println_stderr!("\ttime            : {:.3}", args.trackargs.time.unwrap().to_utc().rfc3339());
            }
            println_stderr!("\tfrequency       : {} Hz", args.trackargs.frequency.as_ref().unwrap());
            println_stderr!("\toffset          : {} Hz\n\n\n", args.trackargs.offset.unwrap_or(0));

            let l = args.trackargs.location.unwrap();
            let location: predict::Location = predict::Location{lat_deg: l.lat, lon_deg: l.lon, alt_m: l.alt};
            let tlename = args.trackargs.tlename.as_ref().unwrap();
            let tlefile = args.trackargs.tlefile.as_ref().unwrap();

            let tle = match tle::create_tle_from_file(&tlename, &tlefile) {
                Ok(t) => {t},
                Err(e) => {
                    println_stderr!("{}", e);
                    exit(1);
                }
            };

            let mut predict: predict::Predict = predict::Predict::new(tle, location);
            let intype = args.inputtype.unwrap();

            let samplerate = args.samplerate.unwrap();
            let mut last_time: time::Tm = time::now_utc();

            match args.trackargs.time {
                Some(start_time) => {
                    let mut sample_count = 0;
                    let mut dt = time::Duration::seconds(0);
                    last_time = start_time;

                    loop {
                        predict.update(Some(start_time + dt));
                        let doppler_hz = (predict.sat.range_rate_km_sec * 1000 as f64 / SPEED_OF_LIGHT_M_S as f64) * args.trackargs.frequency.unwrap() as f64 * (-1.0);

                        // advance time based on how many samples are read in
                        dt = time::Duration::seconds((sample_count as f32 / samplerate as f32) as i64);
                        if start_time + dt - last_time >= time::Duration::seconds(5) {
                            last_time = start_time + dt;
                            println_stderr!("time                : {:}", (start_time + dt).to_utc().rfc3339());
                            println_stderr!("az                  : {:.2}°", predict.sat.az_deg);
                            println_stderr!("el                  : {:.2}°", predict.sat.el_deg);
                            println_stderr!("range               : {:.0} km", predict.sat.range_km);
                            println_stderr!("range rate          : {:.3} km/sec", predict.sat.range_rate_km_sec);
                            println_stderr!("doppler@{:.3} MHz : {:.2} Hz\n", args.trackargs.frequency.unwrap() as f64 / 1000_000_f64, doppler_hz);
                        }

                        let (stop, count): (bool, usize) = shift(intype, doppler_hz, samplerate);
                        if stop {
                            break;
                        }

                        sample_count += count;
                    }
                }

                None => {
                    loop {
                        predict.update(None);
                        let doppler_hz = (predict.sat.range_rate_km_sec * 1000 as f64 / SPEED_OF_LIGHT_M_S as f64) * args.trackargs.frequency.unwrap() as f64 * (-1.0);

                        if time::now_utc() - last_time >= time::Duration::seconds(1) {
                            last_time = time::now_utc();
                            println_stderr!("time                : {:}", time::now_utc().to_utc().rfc3339());
                            println_stderr!("az                  : {:.2}°", predict.sat.az_deg);
                            println_stderr!("el                  : {:.2}°", predict.sat.el_deg);
                            println_stderr!("range               : {:.0} km", predict.sat.range_km);
                            println_stderr!("range rate          : {:.3} km/sec", predict.sat.range_rate_km_sec);
                            println_stderr!("doppler@{:.3} MHz : {:.2} Hz\n", args.trackargs.frequency.unwrap() as f64 / 1000_000_f64, doppler_hz);
                        }

                        let (stop, count): (bool, usize) = shift(intype, doppler_hz, samplerate);
                        if stop {
                            break;
                        }
                    }
                }
            };
        }
    }
}
<commit_msg>more concise shift closure<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

// import local modules
extern crate doppler;
use doppler::usage;
use doppler::usage::Mode::{ConstMode, TrackMode};
use doppler::usage::InputType::{I16, F32};
use doppler::dsp;

// import external modules
use std::process::exit;
use std::io;
use std::io::Read;
use std::io::Write;

extern crate time;
extern crate gpredict;
use gpredict::predict;
use gpredict::tle;

const SPEED_OF_LIGHT_M_S: f64 = 299792458.;
const BUFFER_SIZE: usize = 8192;

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

fn main() {
    let args = usage::args();

    println_stderr!("doppler {} andres.vahter@gmail.com\n\n", env!("CARGO_PKG_VERSION"));

    let mut stdin = io::stdin();
    let mut stdout = io::stdout();
    let mut inbuf: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
    let mut outbuf: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
    let mut samplenr: u32 = 0;

    let mut shift = |intype: doppler::usage::InputType, shift_hz: f64, samplerate: u32| {
        match stdin.read(&mut inbuf) {
            Ok(size) => {
                let freq_shift_fn: fn(&[u8], &mut u32, f64, u32, &mut[u8]) -> (usize, usize) =
                    match intype {
                        I16 => { dsp::shift_frequency_i16},
                        F32 => { dsp::shift_frequency_f32},
                };
                let (sample_count,buflen)  = freq_shift_fn(&inbuf[0 .. size],
                                                           &mut samplenr,
                                                           shift_hz,
                                                           samplerate,
                                                           &mut outbuf);
                stdout.write(&outbuf[0 .. buflen]).unwrap();
                (size<BUFFER_SIZE, sample_count)
            }
            Err(e) => {
                println_stderr!("err: {:?}", e);
                (true, 0)
            }
        }
    };

    match *args.mode.as_ref().unwrap() {
        ConstMode => {
            println_stderr!("constant shift mode");
            println_stderr!("\tIQ samplerate   : {}", args.samplerate.as_ref().unwrap());
            println_stderr!("\tIQ input type   : {}", args.inputtype.as_ref().unwrap());
            println_stderr!("\tIQ output type  : i16\n");
            println_stderr!("\tfrequency shift : {} Hz", args.constargs.shift.as_ref().unwrap());

            let intype = args.inputtype.unwrap();
            let shift_hz = args.constargs.shift.unwrap() as f64;
            let samplerate = args.samplerate.unwrap();

            loop {
                let stop_and_count: (bool, usize) = shift(intype, shift_hz, samplerate);
                if stop_and_count.0 {
                    break;
                }
            }
        }

        TrackMode => {
            println_stderr!("tracking mode");
            println_stderr!("\tIQ samplerate   : {}", args.samplerate.as_ref().unwrap());
            println_stderr!("\tIQ input type   : {}", args.inputtype.as_ref().unwrap());
            println_stderr!("\tIQ output type  : i16\n");
            println_stderr!("\tTLE file        : {}", args.trackargs.tlefile.as_ref().unwrap());
            println_stderr!("\tTLE name        : {}", args.trackargs.tlename.as_ref().unwrap());
            println_stderr!("\tlocation        : {:?}", args.trackargs.location.as_ref().unwrap());
            if args.trackargs.time.is_some() {
                println_stderr!("\ttime            : {:.3}", args.trackargs.time.unwrap().to_utc().rfc3339());
            }
            println_stderr!("\tfrequency       : {} Hz", args.trackargs.frequency.as_ref().unwrap());
            println_stderr!("\toffset          : {} Hz\n\n\n", args.trackargs.offset.unwrap_or(0));

            let l = args.trackargs.location.unwrap();
            let location: predict::Location = predict::Location{lat_deg: l.lat, lon_deg: l.lon, alt_m: l.alt};
            let tlename = args.trackargs.tlename.as_ref().unwrap();
            let tlefile = args.trackargs.tlefile.as_ref().unwrap();

            let tle = match tle::create_tle_from_file(&tlename, &tlefile) {
                Ok(t) => {t},
                Err(e) => {
                    println_stderr!("{}", e);
                    exit(1);
                }
            };

            let mut predict: predict::Predict = predict::Predict::new(tle, location);
            let intype = args.inputtype.unwrap();

            let samplerate = args.samplerate.unwrap();
            let mut last_time: time::Tm = time::now_utc();

            match args.trackargs.time {
                Some(start_time) => {
                    let mut sample_count = 0;
                    let mut dt = time::Duration::seconds(0);
                    last_time = start_time;

                    loop {
                        predict.update(Some(start_time + dt));
                        let doppler_hz = (predict.sat.range_rate_km_sec * 1000 as f64 / SPEED_OF_LIGHT_M_S as f64) * args.trackargs.frequency.unwrap() as f64 * (-1.0);

                        // advance time based on how many samples are read in
                        dt = time::Duration::seconds((sample_count as f32 / samplerate as f32) as i64);
                        if start_time + dt - last_time >= time::Duration::seconds(5) {
                            last_time = start_time + dt;
                            println_stderr!("time                : {:}", (start_time + dt).to_utc().rfc3339());
                            println_stderr!("az                  : {:.2}°", predict.sat.az_deg);
                            println_stderr!("el                  : {:.2}°", predict.sat.el_deg);
                            println_stderr!("range               : {:.0} km", predict.sat.range_km);
                            println_stderr!("range rate          : {:.3} km/sec", predict.sat.range_rate_km_sec);
                            println_stderr!("doppler@{:.3} MHz : {:.2} Hz\n", args.trackargs.frequency.unwrap() as f64 / 1000_000_f64, doppler_hz);
                        }

                        let (stop, count): (bool, usize) = shift(intype, doppler_hz, samplerate);
                        if stop {
                            break;
                        }

                        sample_count += count;
                    }
                }

                None => {
                    loop {
                        predict.update(None);
                        let doppler_hz = (predict.sat.range_rate_km_sec * 1000 as f64 / SPEED_OF_LIGHT_M_S as f64) * args.trackargs.frequency.unwrap() as f64 * (-1.0);

                        if time::now_utc() - last_time >= time::Duration::seconds(1) {
                            last_time = time::now_utc();
                            println_stderr!("time                : {:}", time::now_utc().to_utc().rfc3339());
                            println_stderr!("az                  : {:.2}°", predict.sat.az_deg);
                            println_stderr!("el                  : {:.2}°", predict.sat.el_deg);
                            println_stderr!("range               : {:.0} km", predict.sat.range_km);
                            println_stderr!("range rate          : {:.3} km/sec", predict.sat.range_rate_km_sec);
                            println_stderr!("doppler@{:.3} MHz : {:.2} Hz\n", args.trackargs.frequency.unwrap() as f64 / 1000_000_f64, doppler_hz);
                        }

                        let (stop, count): (bool, usize) = shift(intype, doppler_hz, samplerate);
                        if stop {
                            break;
                        }
                    }
                }
            };
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "XBTVEd"]
#![feature(collections, unboxed_closures)]

extern crate conrod;
extern crate piston;
extern crate opengl_graphics;
extern crate glutin_window;

use conrod::{Background,
             Button,
             Callable,
             Color,
             Colorable,
             Drawable,
             Frameable,
             Label,
             Labelable,
             Point,
             Positionable,
             Shapeable,
             TextBox,
             Theme,
             Ui,
             WidgetMatrix
};
use opengl_graphics::{GlGraphics, OpenGL};
use opengl_graphics::glyph_cache::GlyphCache;
use glutin_window::GlutinWindow;
use piston::window::{WindowSettings, Size};
use piston::event::{Event, Events};
use std::sync::mpsc::channel;
use std::thread;
use std::rc::Rc;
use std::cell::RefCell;
use std::convert::AsRef;
use std::path::Path;
use schedule::{Schedule, Source, Program, Instruction};
use tags::Tags;

pub mod parse;
pub mod schedule;
pub mod tags;
pub mod blocks;

pub struct XBTVEd {
    pub schedules: Vec<Schedule>,
    bg_color: Color,
    frame_width: f64,
    current_schedule: usize
}

impl XBTVEd {
    pub fn new() -> XBTVEd {
        XBTVEd {
            schedules: vec!(Schedule::new("Example",
                                          vec!(Program::new(Source::Pathname("example.schedule".to_string()),
                                                            Tags::new(),
                                                            vec!(Instruction::Play(0, 0)))))),
            bg_color: Color::new(0.2, 0.2, 0.2, 1.0),
            frame_width: 1.0,
            current_schedule: 0
        }
    }

    pub fn get_schedule<'a>(&'a self, idx: usize) -> Option<&'a Schedule> {
        self.schedules.get(idx)
    }

    pub fn prev_schedule(&mut self) {
        if self.current_schedule == 0 {
            ()
        } else {
            self.current_schedule -= 1
        }
    }

    pub fn next_schedule(&mut self) {
        if self.current_schedule + 1 == self.schedules.len() {
            ()
        } else {
            self.current_schedule += 1
        }
    }

    pub fn change_current_schedule(&mut self, idx: usize) -> Result<(), String> {
        if idx >= self.schedules.len() {
            Err("Out of bounds".to_string())
        } else {
            self.current_schedule = idx;
            Ok(())
        }
    }
}

pub fn add_schedule() -> Option<Schedule> {
    let opengl = OpenGL::_3_2;
    let window = GlutinWindow::new(
        opengl,
        WindowSettings::new(
            "Add Schedule".to_string(),
            Size { width: 600, height: 200 }
            ).exit_on_esc(true).samples(4));

    let window_ref = Rc::new(RefCell::new(window));
    let mut gl = GlGraphics::new(opengl);

    let font_path = Path::new("./assets/NotoSans-Regular.ttf");
    let theme = Theme::default();
    let glyph_cache = GlyphCache::new(&font_path).unwrap();
    let mut ui = Ui::<GlyphCache>::new(glyph_cache, theme);

    let light_bg = Color::new(0.8, 0.8, 0.8, 1.0);

    let ref mut sched_name = "name".to_string();

    for event in Events::new(window_ref).ups(180).max_fps(60) {
        ui.handle_event(&event);
        if let Event::Render(args) = event {
            gl.draw([0, 0, args.width as i32, args.height as i32], |_, gl| {
                Background::new().color(light_bg.clone()).draw(&mut ui, gl);

                Label::new("Schedule Name").position(5.0, 10.0)
                    .size(18).color(light_bg.plain_contrast()).draw(&mut ui, gl);

                TextBox::new(0, sched_name)
                    .font_size(14)
                    .dimensions(100.0, 20.0)
                    .position(5.0, 35.0)
                    .frame(1.0)
                    .frame_color(light_bg.invert().plain_contrast())
                    .color(light_bg.clone())
                    .callback(|_string: &mut String| {})
                    .draw(&mut ui, gl);

                Button::new(1)
                    .dimensions(50.0, 60.0)
                    .position(5.0, 100.0)
                    .rgba(0.25, 0.25, 0.25, 1.0)
                    .frame(1.0)
                    .label("Ok")
                    .callback(|| {
                        let tags = Tags::new();
                        let instrs = vec!(Instruction::Play(0, 0));
                        let program = Program::new(Source::Pathname("foo".to_string()), tags, instrs);
                        return Some(Schedule::new(&sched_name, vec!(program)))
                    });

                Button::new(2)
                    .dimensions(50.0, 60.0)
                    .position(60.0, 100.0)
                    .rgba(0.25, 0.25, 0.25, 1.0)
                    .frame(1.0)
                    .label("Cancel")
                    .callback(|| { return None });

            });
        }
    }

    None
}

pub fn draw_ui(gl: &mut GlGraphics, ui: &mut Ui<GlyphCache>, xbtved: &mut XBTVEd) {
    let add_sched_uiid = 10;
    let buff_display_uiid = 144;

    let ref mut buffer = xbtved.get_schedule(xbtved.current_schedule).unwrap().to_string();

    Background::new().color(xbtved.bg_color).draw(ui, gl);

    Button::new(add_sched_uiid)
        .dimensions(200.0, 60.0)
        .position(50.0, 50.0)
        .rgba(0.25, 0.25, 0.25, 1.0)
        .frame(xbtved.frame_width)
        .label("Add Schedule")
        .callback(|| {
            let (tx, rx) = channel();
            thread::spawn(move || {
                          tx.send(add_schedule()).unwrap();
                          });
            if let Some(sched) = rx.recv().unwrap() {
                xbtved.schedules.push(sched)
            };
            println!("{}", xbtved.get_schedule(1).unwrap());
        }).draw(ui, gl);

    TextBox::new(buff_display_uiid, buffer)
        .font_size(16)
        .dimensions(500.0, 400.0)
        .position(50.0, 120.0)
        .frame(1.0)
        .frame_color(xbtved.bg_color.invert().plain_contrast())
        .color(xbtved.bg_color.invert())
        .callback(|_string: &mut String| {})
        .draw(ui, gl);

}

fn main () {
    schedule::test();

    let opengl = OpenGL::_3_2;
    let window = GlutinWindow::new(
        opengl,
        WindowSettings::new(
            "XBTVEd".to_string(),
            Size { width: 800, height: 600 }
        ).exit_on_esc(true).samples(4));

    let window_ref = Rc::new(RefCell::new(window));
    let mut gl = GlGraphics::new(opengl);

    let font_path = Path::new("./assets/NotoSans-Regular.ttf");
    let theme = Theme::default();
    let glyph_cache = GlyphCache::new(&font_path).unwrap();
    let mut ui = Ui::<GlyphCache>::new(glyph_cache, theme);
    let mut xbtved = XBTVEd::new();

    for event in Events::new(window_ref).ups(180).max_fps(60) {
        ui.handle_event(&event);
        if let Event::Render(args) = event {
            gl.draw([0, 0, args.width as i32, args.height as i32], |_, gl| {
                draw_ui(gl, &mut ui, &mut xbtved);
            });
        }
    }
}
<commit_msg>more work on the gui<commit_after>#![crate_name = "XBTVEd"]
#![feature(collections, unboxed_closures)]

extern crate conrod;
extern crate piston;
extern crate opengl_graphics;
extern crate glutin_window;

use conrod::{Background,
             Button,
             Callable,
             Color,
             Colorable,
             Drawable,
             Frameable,
             Label,
             Labelable,
             Point,
             Positionable,
             Shapeable,
             TextBox,
             Theme,
             Ui,
             WidgetMatrix
};
use opengl_graphics::{GlGraphics, OpenGL};
use opengl_graphics::glyph_cache::GlyphCache;
use glutin_window::GlutinWindow;
use piston::window::{WindowSettings, Size};
use piston::event::{Event, Events};
use std::sync::mpsc::channel;
use std::thread;
use std::rc::Rc;
use std::cell::RefCell;
use std::convert::AsRef;
use std::path::Path;
use schedule::{Schedule, Source, Program, Instruction};
use tags::Tags;

pub mod parse;
pub mod schedule;
pub mod tags;
pub mod blocks;

pub struct XBTVEd {
    pub schedules: Vec<Schedule>,
    bg_color: Color,
    frame_width: f64,
    current_schedule: usize
}

impl XBTVEd {
    pub fn new() -> XBTVEd {
        XBTVEd {
            schedules: vec!(Schedule::new("Example",
                                          vec!(Program::new(Source::Pathname("example.schedule".to_string()),
                                                            Tags::new(),
                                                            vec!(Instruction::Play(0, 0)))))),
            bg_color: Color::new(0.2, 0.2, 0.2, 1.0),
            frame_width: 1.0,
            current_schedule: 0
        }
    }

    pub fn get_schedule<'a>(&'a self, idx: usize) -> Option<&'a Schedule> {
        self.schedules.get(idx)
    }

    pub fn prev_schedule(&mut self) {
        if self.current_schedule == 0 {
            ()
        } else {
            self.current_schedule -= 1
        }
    }

    pub fn next_schedule(&mut self) {
        if self.current_schedule + 1 == self.schedules.len() {
            ()
        } else {
            self.current_schedule += 1
        }
    }

    pub fn change_current_schedule(&mut self, idx: usize) -> Result<(), String> {
        if idx >= self.schedules.len() {
            Err("Out of bounds".to_string())
        } else {
            self.current_schedule = idx;
            Ok(())
        }
    }
}

pub fn make_window(title: &str, width: u32, height: u32) -> (GlutinWindow, GlGraphics, Ui<GlyphCache>) {
    let opengl = OpenGL::_3_2;
    let window = GlutinWindow::new(
        opengl,
        WindowSettings::new(
            title.to_string(),
            Size { width: width, height: height }
            ).exit_on_esc(true).samples(4));
    let gl = GlGraphics::new(opengl);

    let font_path = Path::new("./assets/NotoSans-Regular.ttf");
    let theme = Theme::default();
    let glyph_cache = GlyphCache::new(&font_path).unwrap();
    let ui = Ui::<GlyphCache>::new(glyph_cache, theme);

    (window, gl, ui)
}

pub fn add_schedule() -> Option<Schedule> {
    let (window, mut gl, mut ui) = make_window("Add Schedule", 600, 200);
    let window_ref = Rc::new(RefCell::new(window));

    let light_bg = Color::new(0.8, 0.8, 0.8, 1.0);

    let ref mut sched_name = "name".to_string();

    for event in Events::new(window_ref).ups(180).max_fps(60) {
        let (mut clicked, mut val) = (false, None);

        ui.handle_event(&event);
        if let Event::Render(args) = event {
            gl.draw([0, 0, args.width as i32, args.height as i32], |_, gl| {
                Background::new().color(light_bg.clone()).draw(&mut ui, gl);

                Label::new("Schedule Name").position(5.0, 10.0)
                    .size(18).color(light_bg.plain_contrast()).draw(&mut ui, gl);

                TextBox::new(0, sched_name)
                    .font_size(14)
                    .dimensions(100.0, 20.0)
                    .position(5.0, 35.0)
                    .frame(1.0)
                    .frame_color(light_bg.invert().plain_contrast())
                    .color(light_bg.clone())
                    .callback(|_string: &mut String| {})
                    .draw(&mut ui, gl);

                Button::new(1)
                    .dimensions(50.0, 60.0)
                    .position(5.0, 100.0)
                    .rgba(0.25, 0.25, 0.25, 1.0)
                    .frame(1.0)
                    .label("Ok")
                    .callback(|| {
                        let tags = Tags::new();
                        let instrs = vec!(Instruction::Play(0, 0));
                        let program = Program::new(Source::Pathname("foo".to_string()), tags, instrs);

                        clicked = true;
                        val = Some(Schedule::new(&sched_name, vec!(program)));
                    }).draw(&mut ui, gl);

                Button::new(2)
                    .dimensions(50.0, 60.0)
                    .position(60.0, 100.0)
                    .rgba(0.25, 0.25, 0.25, 1.0)
                    .frame(1.0)
                    .label("Cancel")
                    .callback(|| {
                        clicked = true;
                        val = None;
                    }).draw(&mut ui, gl);

            });
        }

        if clicked {
            return val
        }
    }

    None
}

pub fn draw_ui(gl: &mut GlGraphics, ui: &mut Ui<GlyphCache>, xbtved: &mut XBTVEd) {
    let add_sched_uiid = 10;
    let buff_display_uiid = 144;

    let ref mut buffer = xbtved.get_schedule(xbtved.current_schedule).unwrap().to_string();

    Background::new().color(xbtved.bg_color).draw(ui, gl);

    Button::new(add_sched_uiid)
        .dimensions(200.0, 60.0)
        .position(50.0, 50.0)
        .rgba(0.25, 0.25, 0.25, 1.0)
        .frame(xbtved.frame_width)
        .label("Add Schedule")
        .callback(|| {
            let (tx, rx) = channel();
            thread::spawn(move || {
                          tx.send(add_schedule()).unwrap();
                          });
            if let Some(sched) = rx.recv().unwrap() {
                xbtved.schedules.push(sched)
            };
            println!("{}", xbtved.get_schedule(1).unwrap());
        }).draw(ui, gl);

    TextBox::new(buff_display_uiid, buffer)
        .font_size(16)
        .dimensions(500.0, 400.0)
        .position(50.0, 120.0)
        .frame(1.0)
        .frame_color(xbtved.bg_color.invert().plain_contrast())
        .color(xbtved.bg_color.invert())
        .callback(|_string: &mut String| {})
        .draw(ui, gl);

}

fn main () {
    schedule::test();

    let (window, mut gl, mut ui) = make_window("XBTVEd", 800, 600);

//    let opengl = OpenGL::_3_2;
//    let window = GlutinWindow::new(
//        opengl,
//        WindowSettings::new(
//            "XBTVEd".to_string(),
//            Size { width: 800, height: 600 }
//        ).exit_on_esc(true).samples(4));

    let window_ref = Rc::new(RefCell::new(window));
//    let mut gl = GlGraphics::new(opengl);

//    let font_path = Path::new("./assets/NotoSans-Regular.ttf");
//    let theme = Theme::default();
//    let glyph_cache = GlyphCache::new(&font_path).unwrap();
//    let mut ui = Ui::<GlyphCache>::new(glyph_cache, theme);
    let mut xbtved = XBTVEd::new();

    for event in Events::new(window_ref).ups(180).max_fps(60) {
        ui.handle_event(&event);
        if let Event::Render(args) = event {
            gl.draw([0, 0, args.width as i32, args.height as i32], |_, gl| {
                draw_ui(gl, &mut ui, &mut xbtved);
            });
        }
    }
}
<|endoftext|>


<commit_before>extern crate serde;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate exonum;
extern crate router;
extern crate bodyparser;
extern crate iron;

use exonum::blockchain::{self, Blockchain, Service, GenesisConfig, Transaction, ApiContext};
use exonum::messages::{RawTransaction, FromRaw, Message};
use exonum::node::{Node, NodeConfig, NodeApiConfig, TransactionSend};
use exonum::storage::{Fork, MemoryDB, MapIndex};
use exonum::crypto::{PublicKey, Hash};
use exonum::encoding::{self, Field};
use exonum::api::{Api, ApiError};
use iron::prelude::*;
use iron::Handler;
use router::Router;

// // // // // // // // // // PERSISTENT DATA // // // // // // // // // //

encoding_struct! {
    struct Wallet {
        const SIZE = 48;

        field pub_key:            &PublicKey  [00 => 32]
        field name:               &str        [32 => 40]
        field balance:            u64         [40 => 48]
    }
}

impl Wallet {
    pub fn increase(&mut self, amount: u64) {
        let balance = self.balance() + amount;
        Field::write(&balance, &mut self.raw, 40, 48);
    }

    pub fn decrease(&mut self, amount: u64) {
        let balance = self.balance() - amount;
        Field::write(&balance, &mut self.raw, 40, 48);
    }
}

// // // // // // // // // // TRANSACTIONS // // // // // // // // // //

pub const TX_WALLET_ID: u16 = 1;

message! {
    struct TxCreateWallet {
        const TYPE = SERVICE_ID;
        const ID = TX_WALLET_ID;
        const SIZE = 40;

        field pub_key:     &PublicKey  [00 => 32]
        field name:        &str        [32 => 40]
    }
}

pub const TX_TRANSFER_ID: u16 = 3;

message! {
    struct TxTransfer {
        const TYPE = SERVICE_ID;
        const ID = TX_TRANSFER_ID;
        const SIZE = 80;

        field from:        &PublicKey  [00 => 32]
        field to:          &PublicKey  [32 => 64]
        field amount:      u64         [64 => 72]
        field seed:        u64         [72 => 80]
    }
}

// // // // // // // // // // CONTRACTS // // // // // // // // // //

impl Transaction for TxCreateWallet {
    fn verify(&self) -> bool {
        self.verify_signature(self.pub_key())
    }

    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema { view };
        if let None = schema.wallet(self.pub_key()) {
            let wallet = Wallet::new(self.pub_key(), self.name(), 100);
            println!("Create the wallet: {:?}", wallet);
            schema.wallets().put(self.pub_key(), wallet)
        }
    }
}

impl Transaction for TxTransfer {
    fn verify(&self) -> bool {
        (*self.from() != *self.to()) && self.verify_signature(self.from())
    }

    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema { view };
        let sender = schema.wallet(self.from());
        let receiver = schema.wallet(self.to());
        if let (Some(mut sender), Some(mut receiver)) = (sender, receiver) {
            let amount = self.amount();
            if sender.balance() >= amount {
                sender.decrease(amount);
                receiver.increase(amount);
                println!("Transfer between wallets: {:?} => {:?}", sender, receiver);
                let mut wallets = schema.wallets();
                wallets.put(self.from(), sender);
                wallets.put(self.to(), receiver);
            }
        }
    }
}

// // // // // // // // // // REST API // // // // // // // // // //

#[derive(Clone)]
struct CryptocurrencyApi<T> {
    channel: T,
}

impl<T: TransactionSend + Clone + 'static> Api for CryptocurrencyApi<T> {
    fn wire(&self, router: &mut Router) {

        #[serde(untagged)]
        #[derive(Clone, Serialize, Deserialize)]
        enum TransactionRequest {
            CreateWallet(TxCreateWallet),
            Transfer(TxTransfer),
        }

        impl Into<Box<Transaction>> for TransactionRequest {
            fn into(self) -> Box<Transaction> {
                match self {
                    TransactionRequest::CreateWallet(trans) => Box::new(trans),
                    TransactionRequest::Transfer(trans) => Box::new(trans),
                }
            }
        }

        #[derive(Serialize, Deserialize)]
        struct TransactionResponse {
            tx_hash: Hash,
        }

        let self_ = self.clone();
        let transaction = move |req: &mut Request| -> IronResult<Response> {
            match req.get::<bodyparser::Struct<TransactionRequest>>() {
                Ok(Some(transaction)) => {
                    let transaction: Box<Transaction> = transaction.into();
                    let tx_hash = transaction.hash();
                    self_.channel.send(transaction).map_err(|e| ApiError::Events(e))?;
                    let json = TransactionResponse { tx_hash };
                    self_.ok_response(&serde_json::to_value(&json).unwrap())
                }
                Ok(None) => Err(ApiError::IncorrectRequest("Empty request body".into()))?,
                Err(e) => Err(ApiError::IncorrectRequest(Box::new(e)))?,
            }
        };
        let route_post = "/v1/wallets/transaction";
        router.post(&route_post, transaction, "transaction");
    }
}

// // // // // // // // // // STORAGE DATA LAYOUT // // // // // // // // // //

pub struct CurrencySchema<'a> {
    view: &'a mut Fork,
}

impl<'a> CurrencySchema<'a> {
    pub fn wallets(&mut self) -> MapIndex<&mut Fork, PublicKey, Wallet> {
        let prefix = blockchain::gen_prefix(SERVICE_ID, 0, &());
        MapIndex::new(prefix, self.view)
    }

    pub fn wallet(&mut self, pub_key: &PublicKey) -> Option<Wallet> {
        self.wallets().get(pub_key)
    }
}

// // // // // // // // // // SERVICE DECLARATION // // // // // // // // // //

pub const SERVICE_ID: u16 = 1;

struct CurrencyService;

impl Service for CurrencyService {
    fn service_name(&self) -> &'static str { "cryptocurrency" }

    fn service_id(&self) -> u16 { SERVICE_ID }

    fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, encoding::Error> {
        let trans: Box<Transaction> = match raw.message_type() {
            TX_TRANSFER_ID => Box::new(TxTransfer::from_raw(raw)?),
            TX_WALLET_ID => Box::new(TxCreateWallet::from_raw(raw)?),
            _ => {
                return Err(encoding::Error::IncorrectMessageType { message_type: raw.message_type() });
            },
        };
        Ok(trans)
    }

    fn public_api_handler(&self, ctx: &ApiContext) -> Option<Box<Handler>> {
        let mut router = Router::new();
        let api = CryptocurrencyApi {
            channel: ctx.node_channel().clone(),
        };
        api.wire(&mut router);
        Some(Box::new(router))
    }
}

// // // // // // // // // // ENTRY POINT // // // // // // // // // //

fn main() {
    exonum::helpers::init_logger().unwrap();

    println!("Creating in-memory database...");
    let db = MemoryDB::new();
    let services: Vec<Box<Service>> = vec![
        Box::new(CurrencyService),
    ];
    let blockchain = Blockchain::new(Box::new(db), services);

    let (public_key, secret_key) = exonum::crypto::gen_keypair();

    let peer_address = "0.0.0.0:2000".parse().unwrap();
    let api_address = "0.0.0.0:8000".parse().unwrap();

    let genesis = GenesisConfig::new(vec![public_key].into_iter());

    let api_cfg = NodeApiConfig {
        enable_blockchain_explorer: true,
        public_api_address: Some(api_address),
        private_api_address: None,
    };

    let node_cfg = NodeConfig {
        listen_address: peer_address,
        peers: vec![],
        public_key,
        secret_key,
        genesis,
        network: Default::default(),
        whitelist: Default::default(),
        api: api_cfg,
        mempool: Default::default(),
    };

    println!("Starting a single node...");
    let mut node = Node::new(blockchain, node_cfg);

    println!("Blockchain in ready for transactions!");
    node.run().unwrap();
}
<commit_msg>Change transfer transaction ID to 2<commit_after>extern crate serde;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate exonum;
extern crate router;
extern crate bodyparser;
extern crate iron;

use exonum::blockchain::{self, Blockchain, Service, GenesisConfig, Transaction, ApiContext};
use exonum::messages::{RawTransaction, FromRaw, Message};
use exonum::node::{Node, NodeConfig, NodeApiConfig, TransactionSend};
use exonum::storage::{Fork, MemoryDB, MapIndex};
use exonum::crypto::{PublicKey, Hash};
use exonum::encoding::{self, Field};
use exonum::api::{Api, ApiError};
use iron::prelude::*;
use iron::Handler;
use router::Router;

// // // // // // // // // // PERSISTENT DATA // // // // // // // // // //

encoding_struct! {
    struct Wallet {
        const SIZE = 48;

        field pub_key:            &PublicKey  [00 => 32]
        field name:               &str        [32 => 40]
        field balance:            u64         [40 => 48]
    }
}

impl Wallet {
    pub fn increase(&mut self, amount: u64) {
        let balance = self.balance() + amount;
        Field::write(&balance, &mut self.raw, 40, 48);
    }

    pub fn decrease(&mut self, amount: u64) {
        let balance = self.balance() - amount;
        Field::write(&balance, &mut self.raw, 40, 48);
    }
}

// // // // // // // // // // TRANSACTIONS // // // // // // // // // //

pub const TX_WALLET_ID: u16 = 1;

message! {
    struct TxCreateWallet {
        const TYPE = SERVICE_ID;
        const ID = TX_WALLET_ID;
        const SIZE = 40;

        field pub_key:     &PublicKey  [00 => 32]
        field name:        &str        [32 => 40]
    }
}

pub const TX_TRANSFER_ID: u16 = 2;

message! {
    struct TxTransfer {
        const TYPE = SERVICE_ID;
        const ID = TX_TRANSFER_ID;
        const SIZE = 80;

        field from:        &PublicKey  [00 => 32]
        field to:          &PublicKey  [32 => 64]
        field amount:      u64         [64 => 72]
        field seed:        u64         [72 => 80]
    }
}

// // // // // // // // // // CONTRACTS // // // // // // // // // //

impl Transaction for TxCreateWallet {
    fn verify(&self) -> bool {
        self.verify_signature(self.pub_key())
    }

    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema { view };
        if let None = schema.wallet(self.pub_key()) {
            let wallet = Wallet::new(self.pub_key(), self.name(), 100);
            println!("Create the wallet: {:?}", wallet);
            schema.wallets().put(self.pub_key(), wallet)
        }
    }
}

impl Transaction for TxTransfer {
    fn verify(&self) -> bool {
        (*self.from() != *self.to()) && self.verify_signature(self.from())
    }

    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema { view };
        let sender = schema.wallet(self.from());
        let receiver = schema.wallet(self.to());
        if let (Some(mut sender), Some(mut receiver)) = (sender, receiver) {
            let amount = self.amount();
            if sender.balance() >= amount {
                sender.decrease(amount);
                receiver.increase(amount);
                println!("Transfer between wallets: {:?} => {:?}", sender, receiver);
                let mut wallets = schema.wallets();
                wallets.put(self.from(), sender);
                wallets.put(self.to(), receiver);
            }
        }
    }
}

// // // // // // // // // // REST API // // // // // // // // // //

#[derive(Clone)]
struct CryptocurrencyApi<T> {
    channel: T,
}

impl<T: TransactionSend + Clone + 'static> Api for CryptocurrencyApi<T> {
    fn wire(&self, router: &mut Router) {

        #[serde(untagged)]
        #[derive(Clone, Serialize, Deserialize)]
        enum TransactionRequest {
            CreateWallet(TxCreateWallet),
            Transfer(TxTransfer),
        }

        impl Into<Box<Transaction>> for TransactionRequest {
            fn into(self) -> Box<Transaction> {
                match self {
                    TransactionRequest::CreateWallet(trans) => Box::new(trans),
                    TransactionRequest::Transfer(trans) => Box::new(trans),
                }
            }
        }

        #[derive(Serialize, Deserialize)]
        struct TransactionResponse {
            tx_hash: Hash,
        }

        let self_ = self.clone();
        let transaction = move |req: &mut Request| -> IronResult<Response> {
            match req.get::<bodyparser::Struct<TransactionRequest>>() {
                Ok(Some(transaction)) => {
                    let transaction: Box<Transaction> = transaction.into();
                    let tx_hash = transaction.hash();
                    self_.channel.send(transaction).map_err(|e| ApiError::Events(e))?;
                    let json = TransactionResponse { tx_hash };
                    self_.ok_response(&serde_json::to_value(&json).unwrap())
                }
                Ok(None) => Err(ApiError::IncorrectRequest("Empty request body".into()))?,
                Err(e) => Err(ApiError::IncorrectRequest(Box::new(e)))?,
            }
        };
        let route_post = "/v1/wallets/transaction";
        router.post(&route_post, transaction, "transaction");
    }
}

// // // // // // // // // // STORAGE DATA LAYOUT // // // // // // // // // //

pub struct CurrencySchema<'a> {
    view: &'a mut Fork,
}

impl<'a> CurrencySchema<'a> {
    pub fn wallets(&mut self) -> MapIndex<&mut Fork, PublicKey, Wallet> {
        let prefix = blockchain::gen_prefix(SERVICE_ID, 0, &());
        MapIndex::new(prefix, self.view)
    }

    pub fn wallet(&mut self, pub_key: &PublicKey) -> Option<Wallet> {
        self.wallets().get(pub_key)
    }
}

// // // // // // // // // // SERVICE DECLARATION // // // // // // // // // //

pub const SERVICE_ID: u16 = 1;

struct CurrencyService;

impl Service for CurrencyService {
    fn service_name(&self) -> &'static str { "cryptocurrency" }

    fn service_id(&self) -> u16 { SERVICE_ID }

    fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, encoding::Error> {
        let trans: Box<Transaction> = match raw.message_type() {
            TX_TRANSFER_ID => Box::new(TxTransfer::from_raw(raw)?),
            TX_WALLET_ID => Box::new(TxCreateWallet::from_raw(raw)?),
            _ => {
                return Err(encoding::Error::IncorrectMessageType { message_type: raw.message_type() });
            },
        };
        Ok(trans)
    }

    fn public_api_handler(&self, ctx: &ApiContext) -> Option<Box<Handler>> {
        let mut router = Router::new();
        let api = CryptocurrencyApi {
            channel: ctx.node_channel().clone(),
        };
        api.wire(&mut router);
        Some(Box::new(router))
    }
}

// // // // // // // // // // ENTRY POINT // // // // // // // // // //

fn main() {
    exonum::helpers::init_logger().unwrap();

    println!("Creating in-memory database...");
    let db = MemoryDB::new();
    let services: Vec<Box<Service>> = vec![
        Box::new(CurrencyService),
    ];
    let blockchain = Blockchain::new(Box::new(db), services);

    let (public_key, secret_key) = exonum::crypto::gen_keypair();

    let peer_address = "0.0.0.0:2000".parse().unwrap();
    let api_address = "0.0.0.0:8000".parse().unwrap();

    let genesis = GenesisConfig::new(vec![public_key].into_iter());

    let api_cfg = NodeApiConfig {
        enable_blockchain_explorer: true,
        public_api_address: Some(api_address),
        private_api_address: None,
    };

    let node_cfg = NodeConfig {
        listen_address: peer_address,
        peers: vec![],
        public_key,
        secret_key,
        genesis,
        network: Default::default(),
        whitelist: Default::default(),
        api: api_cfg,
        mempool: Default::default(),
    };

    println!("Starting a single node...");
    let mut node = Node::new(blockchain, node_cfg);

    println!("Blockchain in ready for transactions!");
    node.run().unwrap();
}
<|endoftext|>


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

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

use std::fs;
use std::path;

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

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

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

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

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

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

fn ignore (path: &path::PathBuf) -> bool {
    let fname = path.file_name();
    if fname == None {
        return false
    }

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

    false
}

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

impl Misc for path::PathBuf {
    fn is_dir(&self) -> bool {
        fs::metadata(self).unwrap().is_dir()
    }

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

        if self.is_dir() {
            Colour::Yellow.bold().paint(s).to_string()
        } else {
            s.to_string()
        }
    }

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

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

fn explore(path: &path::PathBuf, pattern: &String) -> () {
    if !path.is_dir() || ignore(&path) {
        return;
    }

    let mut q: Vec<path::PathBuf> = Vec::new();
    for item in fs::read_dir(path).unwrap() {
        let f = item.unwrap(); // f is a DirEntry
        if f.path().is_dir() {
            q.push(f.path());
        };
        if f.path().matches(&pattern) {
            println!("{}", f.path().display_colour());
        }
    }

    for d in q {
        explore(&d, &pattern);
    }
}
<commit_msg>Return result from explore()<commit_after>extern crate ansi_term;
extern crate docopt;
extern crate rustc_serialize;

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

use std::fs;
use std::path;

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

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

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

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

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

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

fn ignore (path: &path::PathBuf) -> bool {
    let fname = path.file_name();
    if fname == None {
        return false
    }

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

    false
}

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

impl Misc for path::PathBuf {
    fn is_dir(&self) -> bool {
        fs::metadata(self).unwrap().is_dir()
    }

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

        if self.is_dir() {
            Colour::Yellow.bold().paint(s).to_string()
        } else {
            s.to_string()
        }
    }

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

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

fn explore(path: &path::PathBuf, pattern: &String) -> std::io::Result<()> {
    if !path.is_dir() || ignore(&path) {
        return Ok(())
    }

    let mut q: Vec<path::PathBuf> = Vec::new();
    for item in try!(fs::read_dir(path)) {
        let f = try!(item); // f is a DirEntry
        if f.path().is_dir() {
            q.push(f.path());
        };
        if f.path().matches(&pattern) {
            println!("{}", f.path().display_colour());
        }
    }

    for d in q {
        try!(explore(&d, &pattern));
    }
    Ok(())
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use zip::write::FileOptions;
use std::fs::File;

extern crate zip;

fn main() {
    if let Err(err) = create_archive() {
        //If there was a problem creating the zip archive,
        //then print the error and exit(1).
        println!("Error: {}", err);
        std::process::exit(1);
    }
}

/*
 * This function creates a zip archive, and returns a Result
 * that indicates if all operations were successful.
 *
 * The first command-line argument is the name and path of the zip file to be created,
 * and all the other arguments are the names and paths of the files to be archived
 *
 */
fn create_archive() -> Result<(), String> {
    //If there are less than 3 command-line arguments, return an error
    if std::env::args().count() < 3 {
        return Err("Usage: zipper <zip file> <file to archive> <file to archive> ...".to_string());
    }

    //The 1st command line argument is the name of the zip file.
    //It's not necessary to error check because we already checked
    //the number of command-line arguments earlier
    let zipfile_name = std::env::args().nth(1).unwrap();

    let path_to_zipfile = std::path::Path::new(&zipfile_name);
    let zipfile = match std::fs::File::create(&path_to_zipfile) {
        Err(e) => return Err(format!("Error creating {}: {}", zipfile_name, e)),
        Ok(f)  => f,
    };
    let mut zip = zip::ZipWriter::new(zipfile);

    //Iterate over the command-line arguments for the names of the
    //files we wish to archive. Skip the first two arguments.
    for arg in std::env::args().skip(2) {
        let filename = &arg;

        //Extract the raw filename out of the full path entered by the user
        //This returns the file name as a type &OsStr slice instead of a &str slice
        let name_of_file = match std::path::Path::new(filename).file_name() {
            Some(c) => c,
            None    => return Err(format!("{}: Invalid file name", filename)),
        };

        //Redefine and convert the &OsStr slice to a standard &str slice.
        //Checks if the filename is valid unicode.
        let name_of_file = match name_of_file.to_str() {
            Some(c) => c,
            None    => return Err(format!("{}: Invalid file name", filename)),
        };

        //Open the file and check for errors
        let mut f = match File::open(filename) {
            Err(e) => return Err(format!("{}: {}", filename, e)),
            Ok(f)  => f,
        };

        //Get the file metadata so we can get the file size. Also check for errors
        let file_metadata = match f.metadata() {
            Err(e) => return Err(format!("{}: {}", filename, e)),
            Ok(f)  => f,
        };

        //Get the exact size of the file from the file metadata
        let file_size = file_metadata.len() as usize;

        //Create a buffer to store the file contents that is exactly the size of the file + 1
        let mut contents: Vec<u8> = Vec::with_capacity(file_size + 1);

        //Read the file and check for errors
        f.read_to_end(&mut contents).map_err(|e| e.to_string())?;

        //Now compress the file and write it into the zip archive
        zip.start_file(name_of_file, FileOptions::default())
            .map_err(|e| e.to_string())?;
        zip.write_all(contents.as_slice())
            .map_err(|e| e.to_string())?;

    } //end for loop

    //Finish the zip file
    //try!(zip.finish().map_err(|e| e.to_string()));
    zip.finish().map_err(|e| e.to_string())?;

    //Return an empty Ok tuple because we had no errors.
    Ok(())
}
<commit_msg>Comment clean up<commit_after>use std::io::prelude::*;
use zip::write::FileOptions;
use std::fs::File;

extern crate zip;

fn main() {
    if let Err(err) = create_archive() {
        //If there was a problem creating the zip
        //archive, print the error and exit(1).
        println!("Error: {}", err);
        std::process::exit(1);
    }
}

/*
 * This function creates a zip archive, and returns a Result
 * that indicates if all operations were successful.
 *
 * The first command-line argument is the name and path of the zip file to be created,
 * and all the other arguments are the names and paths of the files to be archived
 *
 */
fn create_archive() -> Result<(), String> {
    //If there are less than 3 command-line arguments, return an error
    if std::env::args().count() < 3 {
        return Err("Usage: zipper <zip file> <file to archive> <file to archive> ...".to_string());
    }

    //The 1st command line argument is the name of the zip file.
    //It's not necessary to error check because we already checked
    //the number of command-line arguments earlier
    let zipfile_name = std::env::args().nth(1).unwrap();

    let path_to_zipfile = std::path::Path::new(&zipfile_name);
    let zipfile = match std::fs::File::create(&path_to_zipfile) {
        Err(e) => return Err(format!("Error creating {}: {}", zipfile_name, e)),
        Ok(f)  => f,
    };
    let mut zip = zip::ZipWriter::new(zipfile);

    //Iterate over the command-line arguments for the names of the
    //files we wish to archive. Skip the first two arguments.
    for arg in std::env::args().skip(2) {
        let filename = &arg;

        //Extract the raw filename out of the full path entered by the user
        //This returns the file name as a type &OsStr slice instead of a &str slice
        let name_of_file = match std::path::Path::new(filename).file_name() {
            Some(c) => c,
            None    => return Err(format!("{}: Invalid file name", filename)),
        };

        //Redefine and convert the &OsStr slice to a standard &str slice.
        //Checks if the filename is valid unicode.
        let name_of_file = match name_of_file.to_str() {
            Some(c) => c,
            None    => return Err(format!("{}: Invalid file name", filename)),
        };

        //Open the file and check for errors
        let mut f = match File::open(filename) {
            Err(e) => return Err(format!("{}: {}", filename, e)),
            Ok(f)  => f,
        };

        //Get the file metadata so we can get the file size. Also check for errors
        let file_metadata = match f.metadata() {
            Err(e) => return Err(format!("{}: {}", filename, e)),
            Ok(f)  => f,
        };

        //Get the exact size of the file from the file metadata
        let file_size = file_metadata.len() as usize;

        //Create a buffer to store the file contents that is exactly the size of the file + 1
        let mut contents: Vec<u8> = Vec::with_capacity(file_size + 1);

        //Read the file and check for errors
        f.read_to_end(&mut contents).map_err(|e| e.to_string())?;

        //Now compress the file and write it into the zip archive
        zip.start_file(name_of_file, FileOptions::default())
            .map_err(|e| e.to_string())?;
        zip.write_all(contents.as_slice())
            .map_err(|e| e.to_string())?;

    } //end for loop

    //Finish the zip file
    //try!(zip.finish().map_err(|e| e.to_string()));
    zip.finish().map_err(|e| e.to_string())?;

    //Return an empty Ok tuple because we had no errors.
    Ok(())
}
<|endoftext|>