<commit_before>#[macro_use] extern crate log;
extern crate env_logger;
extern crate futures;
extern crate getopts;
extern crate librespot;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_signal;

use env_logger::LogBuilder;
use futures::{Future, Async, Poll, Stream};
use std::env;
use std::io::{self, stderr, Write};
use std::path::PathBuf;
use std::process::exit;
use std::str::FromStr;
use tokio_core::reactor::{Handle, Core};
use tokio_io::IoStream;
use std::mem;

use librespot::core::authentication::{get_credentials, Credentials};
use librespot::core::cache::Cache;
use librespot::core::config::{Bitrate, DeviceType, PlayerConfig, SessionConfig, ConnectConfig};
use librespot::core::session::Session;
use librespot::core::version;

use librespot::audio_backend::{self, Sink, BACKENDS};
use librespot::discovery::{discovery, DiscoveryStream};
use librespot::mixer::{self, Mixer};
use librespot::player::Player;
use librespot::spirc::{Spirc, SpircTask};

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

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

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

fn list_backends() {
    println!("Available Backends : ");
    for (&(name, _), idx) in BACKENDS.iter().zip(0..) {
        if idx == 0 {
            println!("- {} (default)", name);
        } else {
            println!("- {}", name);
        }
    }
}

#[derive(Clone)]
struct Setup {
    backend: fn(Option<String>) -> Box<Sink>,
    device: Option<String>,

    mixer: fn() -> Box<Mixer>,

    cache: Option<Cache>,
    player_config: PlayerConfig,
    session_config: SessionConfig,
    connect_config: ConnectConfig,
    credentials: Option<Credentials>,
    enable_discovery: bool,
}

fn setup(args: &[String]) -> Setup {
    let mut opts = getopts::Options::new();
    opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
        .optflag("", "disable-audio-cache", "Disable caching of the audio data.")
        .reqopt("n", "name", "Device name", "NAME")
        .optopt("", "device-type", "Displayed device type", "DEVICE_TYPE")
        .optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE")
        .optopt("", "onstart", "Run PROGRAM when playback is about to begin.", "PROGRAM")
        .optopt("", "onstop", "Run PROGRAM when playback has ended.", "PROGRAM")
        .optflag("v", "verbose", "Enable verbose output")
        .optopt("u", "username", "Username to sign in with", "USERNAME")
        .optopt("p", "password", "Password", "PASSWORD")
        .optflag("", "disable-discovery", "Disable discovery mode")
        .optopt("", "backend", "Audio backend to use. Use '?' to list options", "BACKEND")
        .optopt("", "device", "Audio device to use. Use '?' to list options", "DEVICE")
        .optopt("", "mixer", "Mixer to use", "MIXER")
        .optopt("", "initial-volume", "Initial volume in %, once connected (must be from 0 to 100)", "VOLUME");

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

    let verbose = matches.opt_present("verbose");
    setup_logging(verbose);

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

    let backend_name = matches.opt_str("backend");
    if backend_name == Some("?".into()) {
        list_backends();
        exit(0);
    }

    let backend = audio_backend::find(backend_name)
        .expect("Invalid backend");

    let device = matches.opt_str("device");

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

    let initial_volume;
        if matches.opt_present("initial-volume") && matches.opt_str("initial-volume").unwrap().parse::<i32>().is_ok() {
            let iv = matches.opt_str("zeroconf-port").unwrap().parse::<u16>().unwrap();
            if iv => 0 && iv <= 100 {
                initial_volume = iv * 0xFFFF as i32 / 100 ;
            } else {
                debug!("Volume needs to be a value from 0-100; set as 50%");
                initial_volume = 0x8000 as i32;
            }
        } else {
            initial_volume = 0x8000 as i32;
        }

    let name = matches.opt_str("name").unwrap();
    let use_audio_cache = !matches.opt_present("disable-audio-cache");

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

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

        get_credentials(
            matches.opt_str("username"),
            matches.opt_str("password"),
            cached_credentials
        )
    };

    let session_config = {
        let device_id = librespot::core::session::device_id(&name);

        SessionConfig {
            user_agent: version::version_string(),
            device_id: device_id,
        }
    };

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

        PlayerConfig {
            bitrate: bitrate,
            onstart: matches.opt_str("onstart"),
            onstop: matches.opt_str("onstop"),
        }
    };

    let connect_config = {
        let device_type = matches.opt_str("device-type").as_ref()
            .map(|device_type| DeviceType::from_str(device_type).expect("Invalid device type"))
            .unwrap_or(DeviceType::default());

        ConnectConfig {
            name: name,
            device_type: device_type,
            volume: initial_volume,
        }
    };

    let enable_discovery = !matches.opt_present("disable-discovery");

    Setup {
        backend: backend,
        cache: cache,
        session_config: session_config,
        player_config: player_config,
        connect_config: connect_config,
        credentials: credentials,
        device: device,
        enable_discovery: enable_discovery,
        mixer: mixer,
    }
}

struct Main {
    cache: Option<Cache>,
    player_config: PlayerConfig,
    session_config: SessionConfig,
    connect_config: ConnectConfig,
    backend: fn(Option<String>) -> Box<Sink>,
    device: Option<String>,
    mixer: fn() -> Box<Mixer>,
    handle: Handle,

    discovery: Option<DiscoveryStream>,
    signal: IoStream<()>,

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

    shutdown: bool,
}

impl Main {
    fn new(handle: Handle, setup: Setup) -> Main {
        let mut task = Main {
            handle: handle.clone(),
            cache: setup.cache,
            session_config: setup.session_config,
            player_config: setup.player_config,
            connect_config: setup.connect_config,
            backend: setup.backend,
            device: setup.device,
            mixer: setup.mixer,

            connect: Box::new(futures::future::empty()),
            discovery: None,
            spirc: None,
            spirc_task: None,
            shutdown: false,
            signal: Box::new(tokio_signal::ctrl_c(&handle).flatten_stream()),
        };

        if setup.enable_discovery {
            let config = task.connect_config.clone();
            let device_id = task.session_config.device_id.clone();

            task.discovery = Some(discovery(&handle, config, device_id).unwrap());
        }

        if let Some(credentials) = setup.credentials {
            task.credentials(credentials);
        }

        task
    }

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

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

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

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

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

            if let Some(Async::Ready(Some(creds))) = self.discovery.as_mut().map(|d| d.poll().unwrap()) {
                if let Some(ref spirc) = self.spirc {
                    spirc.shutdown();
                }
                self.credentials(creds);

                progress = true;
            }

            if let Async::Ready(session) = self.connect.poll().unwrap() {
                self.connect = Box::new(futures::future::empty());
                let device = self.device.clone();
                let mixer = (self.mixer)();
                let player_config = self.player_config.clone();
                let connect_config = self.connect_config.clone();

                let audio_filter = mixer.get_audio_filter();
                let backend = self.backend;
                let player = Player::new(player_config, session.clone(), audio_filter, move || {
                    (backend)(device)
                });

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

                progress = true;
            }

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

                progress = true;
            }

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

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

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

    let args: Vec<String> = std::env::args().collect();

    core.run(Main::new(handle, setup(&args))).unwrap()
}
<commit_msg>Thats what I get for copypasta<commit_after>#[macro_use] extern crate log;
extern crate env_logger;
extern crate futures;
extern crate getopts;
extern crate librespot;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_signal;

use env_logger::LogBuilder;
use futures::{Future, Async, Poll, Stream};
use std::env;
use std::io::{self, stderr, Write};
use std::path::PathBuf;
use std::process::exit;
use std::str::FromStr;
use tokio_core::reactor::{Handle, Core};
use tokio_io::IoStream;
use std::mem;

use librespot::core::authentication::{get_credentials, Credentials};
use librespot::core::cache::Cache;
use librespot::core::config::{Bitrate, DeviceType, PlayerConfig, SessionConfig, ConnectConfig};
use librespot::core::session::Session;
use librespot::core::version;

use librespot::audio_backend::{self, Sink, BACKENDS};
use librespot::discovery::{discovery, DiscoveryStream};
use librespot::mixer::{self, Mixer};
use librespot::player::Player;
use librespot::spirc::{Spirc, SpircTask};

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

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

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

fn list_backends() {
    println!("Available Backends : ");
    for (&(name, _), idx) in BACKENDS.iter().zip(0..) {
        if idx == 0 {
            println!("- {} (default)", name);
        } else {
            println!("- {}", name);
        }
    }
}

#[derive(Clone)]
struct Setup {
    backend: fn(Option<String>) -> Box<Sink>,
    device: Option<String>,

    mixer: fn() -> Box<Mixer>,

    cache: Option<Cache>,
    player_config: PlayerConfig,
    session_config: SessionConfig,
    connect_config: ConnectConfig,
    credentials: Option<Credentials>,
    enable_discovery: bool,
}

fn setup(args: &[String]) -> Setup {
    let mut opts = getopts::Options::new();
    opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
        .optflag("", "disable-audio-cache", "Disable caching of the audio data.")
        .reqopt("n", "name", "Device name", "NAME")
        .optopt("", "device-type", "Displayed device type", "DEVICE_TYPE")
        .optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE")
        .optopt("", "onstart", "Run PROGRAM when playback is about to begin.", "PROGRAM")
        .optopt("", "onstop", "Run PROGRAM when playback has ended.", "PROGRAM")
        .optflag("v", "verbose", "Enable verbose output")
        .optopt("u", "username", "Username to sign in with", "USERNAME")
        .optopt("p", "password", "Password", "PASSWORD")
        .optflag("", "disable-discovery", "Disable discovery mode")
        .optopt("", "backend", "Audio backend to use. Use '?' to list options", "BACKEND")
        .optopt("", "device", "Audio device to use. Use '?' to list options", "DEVICE")
        .optopt("", "mixer", "Mixer to use", "MIXER")
        .optopt("", "initial-volume", "Initial volume in %, once connected (must be from 0 to 100)", "VOLUME");

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

    let verbose = matches.opt_present("verbose");
    setup_logging(verbose);

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

    let backend_name = matches.opt_str("backend");
    if backend_name == Some("?".into()) {
        list_backends();
        exit(0);
    }

    let backend = audio_backend::find(backend_name)
        .expect("Invalid backend");

    let device = matches.opt_str("device");

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

    let initial_volume;
        if matches.opt_present("initial-volume") && matches.opt_str("initial-volume").unwrap().parse::<i32>().is_ok() {
            let matches.opt_str("initial-volume").unwrap().parse::<i32>().unwrap();
            if 0 <= iv && iv <= 100 {
                initial_volume = iv * 0xFFFF as i32 / 100 ;
            } else {
                debug!("Volume needs to be a value from 0-100; set as 50%");
                initial_volume = 0x8000 as i32;
            }
        } else {
            initial_volume = 0x8000 as i32;
        }

    let name = matches.opt_str("name").unwrap();
    let use_audio_cache = !matches.opt_present("disable-audio-cache");

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

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

        get_credentials(
            matches.opt_str("username"),
            matches.opt_str("password"),
            cached_credentials
        )
    };

    let session_config = {
        let device_id = librespot::core::session::device_id(&name);

        SessionConfig {
            user_agent: version::version_string(),
            device_id: device_id,
        }
    };

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

        PlayerConfig {
            bitrate: bitrate,
            onstart: matches.opt_str("onstart"),
            onstop: matches.opt_str("onstop"),
        }
    };

    let connect_config = {
        let device_type = matches.opt_str("device-type").as_ref()
            .map(|device_type| DeviceType::from_str(device_type).expect("Invalid device type"))
            .unwrap_or(DeviceType::default());

        ConnectConfig {
            name: name,
            device_type: device_type,
            volume: initial_volume,
        }
    };

    let enable_discovery = !matches.opt_present("disable-discovery");

    Setup {
        backend: backend,
        cache: cache,
        session_config: session_config,
        player_config: player_config,
        connect_config: connect_config,
        credentials: credentials,
        device: device,
        enable_discovery: enable_discovery,
        mixer: mixer,
    }
}

struct Main {
    cache: Option<Cache>,
    player_config: PlayerConfig,
    session_config: SessionConfig,
    connect_config: ConnectConfig,
    backend: fn(Option<String>) -> Box<Sink>,
    device: Option<String>,
    mixer: fn() -> Box<Mixer>,
    handle: Handle,

    discovery: Option<DiscoveryStream>,
    signal: IoStream<()>,

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

    shutdown: bool,
}

impl Main {
    fn new(handle: Handle, setup: Setup) -> Main {
        let mut task = Main {
            handle: handle.clone(),
            cache: setup.cache,
            session_config: setup.session_config,
            player_config: setup.player_config,
            connect_config: setup.connect_config,
            backend: setup.backend,
            device: setup.device,
            mixer: setup.mixer,

            connect: Box::new(futures::future::empty()),
            discovery: None,
            spirc: None,
            spirc_task: None,
            shutdown: false,
            signal: Box::new(tokio_signal::ctrl_c(&handle).flatten_stream()),
        };

        if setup.enable_discovery {
            let config = task.connect_config.clone();
            let device_id = task.session_config.device_id.clone();

            task.discovery = Some(discovery(&handle, config, device_id).unwrap());
        }

        if let Some(credentials) = setup.credentials {
            task.credentials(credentials);
        }

        task
    }

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

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

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

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

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

            if let Some(Async::Ready(Some(creds))) = self.discovery.as_mut().map(|d| d.poll().unwrap()) {
                if let Some(ref spirc) = self.spirc {
                    spirc.shutdown();
                }
                self.credentials(creds);

                progress = true;
            }

            if let Async::Ready(session) = self.connect.poll().unwrap() {
                self.connect = Box::new(futures::future::empty());
                let device = self.device.clone();
                let mixer = (self.mixer)();
                let player_config = self.player_config.clone();
                let connect_config = self.connect_config.clone();

                let audio_filter = mixer.get_audio_filter();
                let backend = self.backend;
                let player = Player::new(player_config, session.clone(), audio_filter, move || {
                    (backend)(device)
                });

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

                progress = true;
            }

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

                progress = true;
            }

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

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

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

    let args: Vec<String> = std::env::args().collect();

    core.run(Main::new(handle, setup(&args))).unwrap()
}
<|endoftext|>


<commit_before>mod error;

// My IP address providers
mod myip;

// DNS providers
mod dns;

// Configuration
mod config;

mod gandi;

mod xmlrpc;

#[macro_use]
extern crate clap;

#[macro_use]
extern crate log;
extern crate env_logger;

extern crate rustc_serialize;
extern crate regex;
extern crate hyper;

extern crate time;

extern crate xml;

use clap::{Arg, App};
use config::Config;
use dns::DNSProvider;
use dns::DNSProviderFactory;
use dns::Record;
use env_logger::LogBuilder;
use error::Result;
use log::{LogRecord, LogLevelFilter};
use myip::GetMyIpAddr;
use myip::IpProvider;
use std::process;

fn main() {
    let config = build_config();

    match main_with_errors(&config) {
        Ok(_) => info!("Process ends with success"),
        Err(err) => {
            error!("Process failed with result: {}", err);
            process::exit(-1);
        }
    }
}

fn build_config() -> Config {
    let matches = App::new("gdu")
        .version(&crate_version!()[..])
        .author("Damien Lecan <dev@dlecan.com>")
        .about("Generic DNS update, useful to update your dynamic IP address into your DNS provider zone file, e.g. Gandi or Go Daddy.\n\
            GDU detects if your ip address is IPv4 or v6 and and will create a record with type 'A' or 'AAAA' accordingly.\n\n\
            IP address can be read from several HTTP providers or from stdin.\n\
            Only Gandi DNS provider is implemented in this version.")
        .args_from_usage(
            "-a --apikey=<apikey> 'Your API key provided by Gandi'
            -d --domain=<domain> 'The domain name whose active zonefile will be updated, e.g. \"domain.com\"'
            -n --dry-run 'Dry run, don't really update Gandi zone file'
            -f --force 'Force new zonefile creation even if IP address isn\'t modified'
            -r --record-name=<record_name> 'Name of the A or AAAA record to update or create (without domain)'
            [verbose]... -v 'Verbose mode'")
        .arg(Arg::with_name("ip_provider")
            .help("IP address provider to use to get your own IP address.\n                                       \
                Available values for <ip-provider>:\n                                        \
                 opendns       : OpenDNS\n                                        \
                 -             : read IP address from stdin\n                                        \
                 sfrlaboxfibre : French 'SFR Labox Fibre' subscribers")
            .short("i")
            .long("ip-provider")
            .takes_value(true)
            .multiple(false)
            .required(true))
        .get_matches();

    // Init logger
    let format = |record: &LogRecord| {
        let t = time::now();
        format!("{},{:03} - {} - {}",
            time::strftime("%Y-%m-%d %H:%M:%S", &t).unwrap(),
            t.tm_nsec / 1000_000,
            record.level(),
            record.args()
        )
    };

    // Init logging to DEBUG only if user requires it
    let log_level_filter = match matches.occurrences_of("verbose") {
        0 => LogLevelFilter::Info,
        1 => {
            println!("Verbose mode");
            LogLevelFilter::Debug
        }
        2 | _=> {
            println!("More verbose mode");
            LogLevelFilter::Trace
        }
    };

    let mut builder = LogBuilder::new();
    builder.format(format).filter(None, log_level_filter);
    builder.init().unwrap();

    // Read parameters
    let apikey = matches.value_of("apikey").unwrap();
    debug!("Using apikey: {}", apikey);

    let domain = matches.value_of("domain").unwrap();
    debug!("Using domain: {}", domain);

    let record_name = matches.value_of("record_name").unwrap();
    debug!("Using record name: {}", record_name);

    let dry_run = matches.is_present("dry-run");
    debug!("Dry run: {}", dry_run);

    let force = matches.is_present("force");
    debug!("Force: {}", force);

    let ip_provider = value_t_or_exit!(matches.value_of("ip_provider"), IpProvider);
    debug!("IP address provider: {:?}", ip_provider);

    Config {
        apikey: apikey.to_owned(),
        domain: domain.to_owned(),
        record_name: record_name.to_owned(),
        force: force,
        ip_provider: ip_provider,
    }
}

fn main_with_errors(config: &Config) -> Result<()> {

    let my_ip = try!(config.ip_provider.get_my_ip_addr());

    info!("My IP address: {:?}", my_ip);

    let mut dns_provider = dns::DNSProviderFactory::build(config);

    match my_ip {
        std::net::IpAddr::V6(_)
            if !dns_provider.handle_ipv6_addr() => panic!("You cannot use IP v6 addresses with the selected DNS provider"),
        _ => (),
    }

    let record = Record::new(&config.record_name, &my_ip);

    try!(dns_provider.init(&config.domain));

    let maybe_checked = try!(dns_provider.is_record_already_declared(&record));

    match maybe_checked {
        Some(ip_addr) => {
            debug!("Record already declared, with IP address: {}", &ip_addr);

            if !config.force && (&ip_addr == &my_ip) {
                info!("IP address not modified, no record to update");
                Ok(())
            } else {
                info!("Update record '{:?}' with IP address '{:?}'", &record, &my_ip);
                Ok(try!(dns_provider.update_record(&record, &my_ip)))
            }
        }
        None => Ok(try!(dns_provider.create_record(&record, &my_ip)))
    }
}
<commit_msg>Fix regression with CLI parameter parsing<commit_after>mod error;

// My IP address providers
mod myip;

// DNS providers
mod dns;

// Configuration
mod config;

mod gandi;

mod xmlrpc;

#[macro_use]
extern crate clap;

#[macro_use]
extern crate log;
extern crate env_logger;

extern crate rustc_serialize;
extern crate regex;
extern crate hyper;

extern crate time;

extern crate xml;

use clap::{Arg, App};
use config::Config;
use dns::DNSProvider;
use dns::DNSProviderFactory;
use dns::Record;
use env_logger::LogBuilder;
use error::Result;
use log::{LogRecord, LogLevelFilter};
use myip::GetMyIpAddr;
use myip::IpProvider;
use std::process;

fn main() {
    let config = build_config();

    match main_with_errors(&config) {
        Ok(_) => info!("Process ends with success"),
        Err(err) => {
            error!("Process failed with result: {}", err);
            process::exit(-1);
        }
    }
}

fn build_config() -> Config {
    let matches = App::new("gdu")
        .version(&crate_version!()[..])
        .author("Damien Lecan <dev@dlecan.com>")
        .about("Generic DNS update, useful to update your dynamic IP address into your DNS provider zone file, e.g. Gandi or Go Daddy.\n\
            GDU detects if your ip address is IPv4 or v6 and and will create a record with type 'A' or 'AAAA' accordingly.\n\n\
            IP address can be read from several HTTP providers or from stdin.\n\
            Only Gandi DNS provider is implemented in this version.")
        .args_from_usage(
            "-a --apikey=<apikey> 'Your API key provided by Gandi'
            -d --domain=<domain> 'The domain name whose active zonefile will be updated, e.g. \"domain.com\"'
            -n --dry-run 'Dry run, don't really update Gandi zone file'
            -f --force 'Force new zonefile creation even if IP address isn\'t modified'
            -r --record-name=<record_name> 'Name of the A or AAAA record to update or create (without domain)'
            [verbose]... -v 'Verbose mode'")
        .arg(Arg::with_name("ip_provider")
            .help("IP address provider to use to get your own IP address.\n                                       \
                Available values for <ip-provider>:\n                                        \
                 opendns       : OpenDNS\n                                        \
                 -             : read IP address from stdin\n                                        \
                 sfrlaboxfibre : French 'SFR Labox Fibre' subscribers")
            .short("i")
            .long("ip-provider")
            .takes_value(true)
            .multiple(false)
            .required(true))
        .get_matches();

    // Init logger
    let format = |record: &LogRecord| {
        let t = time::now();
        format!("{},{:03} - {} - {}",
            time::strftime("%Y-%m-%d %H:%M:%S", &t).unwrap(),
            t.tm_nsec / 1000_000,
            record.level(),
            record.args()
        )
    };

    // Init logging to DEBUG only if user requires it
    let log_level_filter = match matches.occurrences_of("verbose") {
        0 => LogLevelFilter::Info,
        1 => {
            println!("Verbose mode");
            LogLevelFilter::Debug
        }
        2 | _=> {
            println!("More verbose mode");
            LogLevelFilter::Trace
        }
    };

    let mut builder = LogBuilder::new();
    builder.format(format).filter(None, log_level_filter);
    builder.init().unwrap();

    // Read parameters
    let apikey = matches.value_of("apikey").unwrap();
    debug!("Using apikey: {}", apikey);

    let domain = matches.value_of("domain").unwrap();
    debug!("Using domain: {}", domain);

    let record_name = matches.value_of("record-name").unwrap();
    debug!("Using record name: {}", record_name);

    let dry_run = matches.is_present("dry-run");
    debug!("Dry run: {}", dry_run);

    let force = matches.is_present("force");
    debug!("Force: {}", force);

    let ip_provider = value_t_or_exit!(matches.value_of("ip_provider"), IpProvider);
    debug!("IP address provider: {:?}", ip_provider);

    Config {
        apikey: apikey.to_owned(),
        domain: domain.to_owned(),
        record_name: record_name.to_owned(),
        force: force,
        ip_provider: ip_provider,
    }
}

fn main_with_errors(config: &Config) -> Result<()> {

    let my_ip = try!(config.ip_provider.get_my_ip_addr());

    info!("My IP address: {:?}", my_ip);

    let mut dns_provider = dns::DNSProviderFactory::build(config);

    match my_ip {
        std::net::IpAddr::V6(_)
            if !dns_provider.handle_ipv6_addr() => panic!("You cannot use IP v6 addresses with the selected DNS provider"),
        _ => (),
    }

    let record = Record::new(&config.record_name, &my_ip);

    try!(dns_provider.init(&config.domain));

    let maybe_checked = try!(dns_provider.is_record_already_declared(&record));

    match maybe_checked {
        Some(ip_addr) => {
            debug!("Record already declared, with IP address: {}", &ip_addr);

            if !config.force && (&ip_addr == &my_ip) {
                info!("IP address not modified, no record to update");
                Ok(())
            } else {
                info!("Update record '{:?}' with IP address '{:?}'", &record, &my_ip);
                Ok(try!(dns_provider.update_record(&record, &my_ip)))
            }
        }
        None => Ok(try!(dns_provider.create_record(&record, &my_ip)))
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::fs::{self, DirEntry};
use std::path::Path;

fn main() {
    let p = Path::new(".");
    let entries = match fs::read_dir(p) {
        Err(err) => panic!(err),
        Ok(e) => e
    };
    for entry in entries {
        let entry = entry.unwrap();
        let entry_path = entry.path();
        let meta = match fs::metadata(entry_path) {
            Err(err) => panic!(err),
            Ok(meta) => meta
        };
        if meta.is_file() {
            println!("{}", entry.file_name().to_str().unwrap());
        }
    }
}
<commit_msg>Walk all directories recursively<commit_after>use std::io;
use std::fs::{self, DirEntry};
use std::path::Path;

fn walk_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
    if try!(fs::metadata(dir)).is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            if try!(fs::metadata(entry.path())).is_dir() {
                try!(walk_dirs(&entry.path(), cb));
            } else {
                cb(&entry);
            }
        }
    }
    Ok(())
}

fn do_something(entry: &DirEntry) {
    println!("{}", entry.file_name().to_str().unwrap());
}

fn main() {
    let p = Path::new(".");
    let _ = walk_dirs(p, &do_something);
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

extern crate ansi_term;
extern crate atty;
#[macro_use]
extern crate clap;
extern crate ignore;
#[macro_use]
extern crate lazy_static;
#[cfg(all(unix, not(target_os = "redox")))]
extern crate libc;
extern crate num_cpus;
extern crate regex;
extern crate regex_syntax;
extern crate shell_escape;

pub mod fshelper;
pub mod lscolors;
mod app;
mod exec;
mod internal;
mod output;
mod walk;

#[cfg(windows)]
mod windows;

use std::env;
use std::error::Error;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time;

use atty::Stream;
use regex::RegexBuilder;

use exec::TokenizedCommand;
use internal::{error, pattern_has_uppercase_char, FdOptions, PathDisplay};
use lscolors::LsColors;
use walk::FileType;

fn main() {
    let matches = app::build_app().get_matches();

    // Get the search pattern
    let empty_pattern = String::new();
    let pattern = matches.value_of("pattern").unwrap_or(&empty_pattern);

    // Get the current working directory
    let current_dir = Path::new(".");
    if !fshelper::is_dir(current_dir) {
        error("Error: could not get current directory.");
    }

    // Get the root directory for the search
    let mut root_dir_buf = match matches.value_of("path") {
        Some(path) => {
            #[cfg(windows)]
            let path = path.replace('/', "\\");

            PathBuf::from(path)
        }
        None => current_dir.to_path_buf(),
    };
    if !fshelper::is_dir(&root_dir_buf) {
        error(&format!(
            "Error: '{}' is not a directory.",
            root_dir_buf.to_string_lossy()
        ));
    }

    let path_display = if matches.is_present("absolute-path") || root_dir_buf.is_absolute() {
        PathDisplay::Absolute
    } else {
        PathDisplay::Relative
    };

    if path_display == PathDisplay::Absolute && root_dir_buf.is_relative() {
        root_dir_buf = fshelper::absolute_path(root_dir_buf.as_path()).unwrap();
    }
    let root_dir = root_dir_buf.as_path();

    // The search will be case-sensitive if the command line flag is set or
    // if the pattern has an uppercase character (smart case).
    let case_sensitive = !matches.is_present("ignore-case") &&
        (matches.is_present("case-sensitive") || pattern_has_uppercase_char(pattern));

    let colored_output = match matches.value_of("color") {
        Some("always") => true,
        Some("never") => false,
        _ => atty::is(Stream::Stdout),
    };

    #[cfg(windows)]
    let colored_output = colored_output && windows::enable_colored_output();

    let ls_colors = if colored_output {
        Some(
            env::var("LS_COLORS")
                .ok()
                .map(|val| LsColors::from_string(&val))
                .unwrap_or_default(),
        )
    } else {
        None
    };

    let command = matches.value_of("exec").map(|x| TokenizedCommand::new(x));

    let config = FdOptions {
        case_sensitive,
        search_full_path: matches.is_present("full-path"),
        ignore_hidden: !(matches.is_present("hidden") ||
                             matches.occurrences_of("rg-alias-hidden-ignore") >= 2),
        read_ignore: !(matches.is_present("no-ignore") ||
                           matches.is_present("rg-alias-hidden-ignore")),
        follow_links: matches.is_present("follow"),
        null_separator: matches.is_present("null_separator"),
        max_depth: matches.value_of("depth").and_then(|n| {
            usize::from_str_radix(n, 10).ok()
        }),
        threads: std::cmp::max(
            matches
                .value_of("threads")
                .and_then(|n| usize::from_str_radix(n, 10).ok())
                .unwrap_or_else(num_cpus::get),
            1,
        ),
        max_buffer_time: matches
            .value_of("max-buffer-time")
            .and_then(|n| u64::from_str_radix(n, 10).ok())
            .map(time::Duration::from_millis),
        path_display,
        ls_colors,
        file_type: match matches.value_of("file-type") {
            Some("f") | Some("file") => FileType::RegularFile,
            Some("d") |
            Some("directory") => FileType::Directory,
            Some("l") | Some("symlink") => FileType::SymLink,
            _ => FileType::Any,
        },
        extension: matches.value_of("extension").map(|e| {
            e.trim_left_matches('.').to_lowercase()
        }),
        command,
        exclude_patterns: matches
            .values_of("exclude")
            .map(|v| v.map(|p| String::from("!") + p).collect())
            .unwrap_or_else(|| vec![]),
    };

    match RegexBuilder::new(pattern)
        .case_insensitive(!config.case_sensitive)
        .dot_matches_new_line(true)
        .build() {
        Ok(re) => walk::scan(root_dir, Arc::new(re), Arc::new(config)),
        Err(err) => error(err.description()),
    }
}
<commit_msg>Remove superfluous path.replace<commit_after>// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

extern crate ansi_term;
extern crate atty;
#[macro_use]
extern crate clap;
extern crate ignore;
#[macro_use]
extern crate lazy_static;
#[cfg(all(unix, not(target_os = "redox")))]
extern crate libc;
extern crate num_cpus;
extern crate regex;
extern crate regex_syntax;
extern crate shell_escape;

pub mod fshelper;
pub mod lscolors;
mod app;
mod exec;
mod internal;
mod output;
mod walk;

#[cfg(windows)]
mod windows;

use std::env;
use std::error::Error;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time;

use atty::Stream;
use regex::RegexBuilder;

use exec::TokenizedCommand;
use internal::{error, pattern_has_uppercase_char, FdOptions, PathDisplay};
use lscolors::LsColors;
use walk::FileType;

fn main() {
    let matches = app::build_app().get_matches();

    // Get the search pattern
    let empty_pattern = String::new();
    let pattern = matches.value_of("pattern").unwrap_or(&empty_pattern);

    // Get the current working directory
    let current_dir = Path::new(".");
    if !fshelper::is_dir(current_dir) {
        error("Error: could not get current directory.");
    }

    // Get the root directory for the search
    let mut root_dir_buf = match matches.value_of("path") {
        Some(path) => PathBuf::from(path),
        None => current_dir.to_path_buf(),
    };
    if !fshelper::is_dir(&root_dir_buf) {
        error(&format!(
            "Error: '{}' is not a directory.",
            root_dir_buf.to_string_lossy()
        ));
    }

    let path_display = if matches.is_present("absolute-path") || root_dir_buf.is_absolute() {
        PathDisplay::Absolute
    } else {
        PathDisplay::Relative
    };

    if path_display == PathDisplay::Absolute && root_dir_buf.is_relative() {
        root_dir_buf = fshelper::absolute_path(root_dir_buf.as_path()).unwrap();
    }
    let root_dir = root_dir_buf.as_path();

    // The search will be case-sensitive if the command line flag is set or
    // if the pattern has an uppercase character (smart case).
    let case_sensitive = !matches.is_present("ignore-case") &&
        (matches.is_present("case-sensitive") || pattern_has_uppercase_char(pattern));

    let colored_output = match matches.value_of("color") {
        Some("always") => true,
        Some("never") => false,
        _ => atty::is(Stream::Stdout),
    };

    #[cfg(windows)]
    let colored_output = colored_output && windows::enable_colored_output();

    let ls_colors = if colored_output {
        Some(
            env::var("LS_COLORS")
                .ok()
                .map(|val| LsColors::from_string(&val))
                .unwrap_or_default(),
        )
    } else {
        None
    };

    let command = matches.value_of("exec").map(|x| TokenizedCommand::new(x));

    let config = FdOptions {
        case_sensitive,
        search_full_path: matches.is_present("full-path"),
        ignore_hidden: !(matches.is_present("hidden") ||
                             matches.occurrences_of("rg-alias-hidden-ignore") >= 2),
        read_ignore: !(matches.is_present("no-ignore") ||
                           matches.is_present("rg-alias-hidden-ignore")),
        follow_links: matches.is_present("follow"),
        null_separator: matches.is_present("null_separator"),
        max_depth: matches.value_of("depth").and_then(|n| {
            usize::from_str_radix(n, 10).ok()
        }),
        threads: std::cmp::max(
            matches
                .value_of("threads")
                .and_then(|n| usize::from_str_radix(n, 10).ok())
                .unwrap_or_else(num_cpus::get),
            1,
        ),
        max_buffer_time: matches
            .value_of("max-buffer-time")
            .and_then(|n| u64::from_str_radix(n, 10).ok())
            .map(time::Duration::from_millis),
        path_display,
        ls_colors,
        file_type: match matches.value_of("file-type") {
            Some("f") | Some("file") => FileType::RegularFile,
            Some("d") |
            Some("directory") => FileType::Directory,
            Some("l") | Some("symlink") => FileType::SymLink,
            _ => FileType::Any,
        },
        extension: matches.value_of("extension").map(|e| {
            e.trim_left_matches('.').to_lowercase()
        }),
        command,
        exclude_patterns: matches
            .values_of("exclude")
            .map(|v| v.map(|p| String::from("!") + p).collect())
            .unwrap_or_else(|| vec![]),
    };

    match RegexBuilder::new(pattern)
        .case_insensitive(!config.case_sensitive)
        .dot_matches_new_line(true)
        .build() {
        Ok(re) => walk::scan(root_dir, Arc::new(re), Arc::new(config)),
        Err(err) => error(err.description()),
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Write;

#[derive(Debug, PartialEq, Clone)]
pub enum Token {
    Unknown(String), // Invalid test (basically non-ascii)
    Literal(String), // Numeric literal number
    Func(Function), // Pre-defined function (like cos() )
    Const(Constant), // Constant like pi or e
    Var(String), // str arbitrary single char variable name
    Op(Operator), // Any of the 4 operators (+-*/)
    Open, // Open parens '('
    Close, // Closing parens ')'
    Set(Vec<Token>), // [ (, tokens..., ) ]
}

#[derive(Debug, PartialEq, Clone)]
pub enum Function {
    Sqrt(Vec<Token>),
    Ln(Vec<Token>),
    Log(f64, Vec<Token>),
    Sin(Vec<Token>),
    Cos(Vec<Token>),
    Tan(Vec<Token>),
    Asin(Vec<Token>),
    Acos(Vec<Token>),
    Atan(Vec<Token>),
    Sinh(Vec<Token>),
    Cosh(Vec<Token>),
    Tanh(Vec<Token>),
    Asinh(Vec<Token>),
    Acosh(Vec<Token>),
    Atanh(Vec<Token>),
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Constant {
	Pi,
	E,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Operator {
    Add,
    Sub,
    Div,
    Mul,
    Pow,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
pub enum Assoc {
    Left,
    Right,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
pub enum Order {
    AddSub = 1,
    MulDiv = 2,
    IMul = 3, // Implicit multiplication
    Pow = 4,
    Paren = 5,
}

#[derive(Debug, PartialEq, Clone)]
struct Expression {
    tokens: Vec<Token>,
    constant: f64,
}

struct ExpressionIter<'a> {
	expr: &'a Expression,
	count: usize,
}

impl<'a> Iterator for ExpressionIter<'a> {
	type Item = &'a Token;
    fn next(&mut self) -> Option<&'a Token> {
    	let token = self.expr.get_tokens().get(self.count);
    	self.count += 1;
    	token
    }
}

#[allow(dead_code)]
impl Expression {
	fn new(tokens: Vec<Token>, constant: f64) -> Self {
		Expression {tokens: tokens, constant: constant}
	}

	fn push(&mut self, token: Token) {
		self.tokens.push(token);
	}

	fn update_constant(&mut self, constant: &f64) {
		self.constant += *constant;
	}

	fn get_constant(&self) -> f64 {
		self.constant
	}

	fn get_tokens(&self) -> &[Token] {
		self.tokens.as_slice()
	}

	fn get_mut_tokens(&mut self) -> &mut [Token] {
		self.tokens.as_mut_slice()
	}

	fn replace_token(&mut self, index: usize, new_token: Token) {
		self.tokens.remove(index);
		self.tokens.insert(index, new_token);
	}

	fn replace_all_tokens(&mut self, new_token: Vec<Token>) {
		self.tokens = new_token
	}

	fn find_first(&self, token: &Token) -> Option<usize> {
		for i in 0..self.tokens.len() {
			if self.tokens.get(i).unwrap() == token {
				return Some(i);
			}
		}
		None
	}

	fn find_last(&self, token: &Token) -> Option<usize> {
		for i in (0..self.tokens.len()).rev() {
			if self.tokens.get(i).unwrap() == token {
				return Some(i);
			}
		}
		None
	}

	fn split_at(&self, index: usize) -> (&[Token], &[Token]) {
		self.tokens.split_at(index)
	}

	fn len(&self) -> usize {
		self.tokens.len()
	}

	fn iter(&self) -> ExpressionIter {
		ExpressionIter {expr: &self, count: 0}
	}
}

fn main() {
    println!("Welcome to Rust-Calculus!");
    println!("To evaluate an expression, simply type one in and hit RETURN.");
    println!("To set a variable, simply type VAR_NAME=EXPRESSION and hit RETURN.");
    println!("Valid commands are: sym_int, int, sym_def, and def.");
    println!("Type 'quit' to exit.");
    let mut input = String::new();
    let stdin = io::stdin();
    let mut stdout = io::stdout();
    loop {
    	input.clear();
    	print!(">>>> ");
    	stdout.flush().ok();
        stdin.read_line(&mut input).unwrap();
        input = strip_white_space(&input);
        input = input.to_lowercase();
        if input == "quit" {
        	print!("Exiting...");
        	break;
        }
        let expr = parse_input(&input).unwrap();
        println!("{:?}", &expr);
    }
}

fn strip_white_space(input: &String) -> String {
	input.split_whitespace().collect::<Vec<&str>>().join("")
}

fn parse_input(input: &String) -> Result<Expression, ()> {
	let mut expr: Expression = Expression::new(Vec::new(), 0.0);
	for c in input.chars() {
		match c {
			'-' => {
				expr.push(Token::Op(Operator::Sub));
			},
			'+' => {
				expr.push(Token::Op(Operator::Add));
			},
			'/' => {
				expr.push(Token::Op(Operator::Div));
			},
			'*' => {
				expr.push(Token::Op(Operator::Mul));
			},
			'^' => {
				expr.push(Token::Op(Operator::Pow));
			},
			'(' => {
				expr.push(Token::Open);
			},
			')' => {
				expr.push(Token::Close);
			},
			_ => continue,
		}
	}
	// Once we find an outermost (), split the rest of the expression after that off into a new vector
	//let mut expr_vecs: Vec<Vec<Token>> = Vec::new();
	while let Some(index) = expr.find_first(&Token::Open) { // If we find an index of an Open
		let end_set: usize = expr.find_last(&Token::Close).unwrap(); // Finds the last Close, need to find the one that actually matches the proper Open (if two Sets are on same depth)
		let mut lhs: Vec<Token> = Vec::new();
		{
			let (temp_lhs, temp_rhs) = expr.split_at(index); // [0, where set should be placed)
			lhs = temp_lhs.to_vec();
			let mut rhs = temp_rhs.to_vec(); // [where set should be placed, len)
			rhs.remove(0);
			let (left_rhs, right_rhs) = rhs.split_at(end_set-1);
			let (left_rhs, mut right_rhs) = (left_rhs.to_vec(), right_rhs.to_vec());
			right_rhs.remove(0);
			lhs.push(Token::Set(left_rhs));
			lhs.append(&mut right_rhs);
		}
		for i in (0..lhs.len()).rev() {
			if lhs.get(i).unwrap() == &Token::Close {
				lhs.remove(i);
				break;
			}
		}
		expr.replace_all_tokens(lhs);
	}
	Ok(expr)
}

#[test]
fn test_parse() {
	let input: String = String::from("+");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Add)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("-");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Sub)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("/");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Div)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("*");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Mul)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("^");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Pow)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("()");
	assert_eq!(Expression::new(vec![Token::Set(Vec::new())], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(+)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Add)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(-)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Sub)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(*)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Mul)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(/)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Div)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(^)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Pow)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(())");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Set(Vec::new())])], 0.0), parse_input(&input).unwrap());
}<commit_msg>Adding Error handling for some .unwrap() calls in the io loop<commit_after>use std::io;
use std::io::Write;

#[derive(Debug, PartialEq, Clone)]
pub enum Token {
    Unknown(String), // Invalid test (basically non-ascii)
    Literal(String), // Numeric literal number
    Func(Function), // Pre-defined function (like cos() )
    Const(Constant), // Constant like pi or e
    Var(String), // str arbitrary single char variable name
    Op(Operator), // Any of the 4 operators (+-*/)
    Open, // Open parens '('
    Close, // Closing parens ')'
    Set(Vec<Token>), // [ (, tokens..., ) ]
}

#[derive(Debug, PartialEq, Clone)]
pub enum Function {
    Sqrt(Vec<Token>),
    Ln(Vec<Token>),
    Log(f64, Vec<Token>),
    Sin(Vec<Token>),
    Cos(Vec<Token>),
    Tan(Vec<Token>),
    Asin(Vec<Token>),
    Acos(Vec<Token>),
    Atan(Vec<Token>),
    Sinh(Vec<Token>),
    Cosh(Vec<Token>),
    Tanh(Vec<Token>),
    Asinh(Vec<Token>),
    Acosh(Vec<Token>),
    Atanh(Vec<Token>),
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Constant {
	Pi,
	E,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Operator {
    Add,
    Sub,
    Div,
    Mul,
    Pow,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
pub enum Assoc {
    Left,
    Right,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
pub enum Order {
    AddSub = 1,
    MulDiv = 2,
    IMul = 3, // Implicit multiplication
    Pow = 4,
    Paren = 5,
}

#[derive(Debug, PartialEq, Clone)]
struct Expression {
    tokens: Vec<Token>,
    constant: f64,
}

struct ExpressionIter<'a> {
	expr: &'a Expression,
	count: usize,
}

impl<'a> Iterator for ExpressionIter<'a> {
	type Item = &'a Token;
    fn next(&mut self) -> Option<&'a Token> {
    	let token = self.expr.get_tokens().get(self.count);
    	self.count += 1;
    	token
    }
}

#[allow(dead_code)]
impl Expression {
	fn new(tokens: Vec<Token>, constant: f64) -> Self {
		Expression {tokens: tokens, constant: constant}
	}

	fn push(&mut self, token: Token) {
		self.tokens.push(token);
	}

	fn update_constant(&mut self, constant: &f64) {
		self.constant += *constant;
	}

	fn get_constant(&self) -> f64 {
		self.constant
	}

	fn get_tokens(&self) -> &[Token] {
		self.tokens.as_slice()
	}

	fn get_mut_tokens(&mut self) -> &mut [Token] {
		self.tokens.as_mut_slice()
	}

	fn replace_token(&mut self, index: usize, new_token: Token) {
		self.tokens.remove(index);
		self.tokens.insert(index, new_token);
	}

	fn replace_all_tokens(&mut self, new_token: Vec<Token>) {
		self.tokens = new_token
	}

	fn find_first(&self, token: &Token) -> Option<usize> {
		for i in 0..self.tokens.len() {
			if self.tokens.get(i).unwrap() == token {
				return Some(i);
			}
		}
		None
	}

	fn find_last(&self, token: &Token) -> Option<usize> {
		for i in (0..self.tokens.len()).rev() {
			if self.tokens.get(i).unwrap() == token {
				return Some(i);
			}
		}
		None
	}

	fn split_at(&self, index: usize) -> (&[Token], &[Token]) {
		self.tokens.split_at(index)
	}

	fn len(&self) -> usize {
		self.tokens.len()
	}

	fn iter(&self) -> ExpressionIter {
		ExpressionIter {expr: &self, count: 0}
	}
}

fn main() {
    println!("Welcome to Rust-Calculus!");
    println!("To evaluate an expression, simply type one in and hit RETURN.");
    println!("To set a variable, simply type VAR_NAME=EXPRESSION and hit RETURN.");
    println!("Valid commands are: sym_int, int, sym_def, and def.");
    println!("Type 'quit' to exit.");
    let mut input = String::new();
    let stdin = io::stdin();
    let mut stdout = io::stdout();
    loop {
    	input.clear();
    	print!(">>>> ");
    	stdout.flush().ok();
        if let Err(x) = stdin.read_line(&mut input) {
        	println!("There was a problem reading stdin: {:?}", x);
        	print!("Exiting...");;
        	break;
        }
        input = strip_white_space(&input);
        input = input.to_lowercase();
        if input == "quit" {
        	print!("Exiting...");
        	break;
        }
        let expr = match parse_input(&input) {
        		Ok(x) => x,
        		Err(x) => {println!("Encountered an error while parsing: {:?}", x); print!("Exiting..."); break;},
        	};
        println!("{:?}", &expr);
    }
}

fn strip_white_space(input: &String) -> String {
	input.split_whitespace().collect::<Vec<&str>>().join("")
}

fn parse_input(input: &String) -> Result<Expression, String> {
	let mut expr: Expression = Expression::new(Vec::new(), 0.0);
	for c in input.chars() {
		match c {
			'-' => {
				expr.push(Token::Op(Operator::Sub));
			},
			'+' => {
				expr.push(Token::Op(Operator::Add));
			},
			'/' => {
				expr.push(Token::Op(Operator::Div));
			},
			'*' => {
				expr.push(Token::Op(Operator::Mul));
			},
			'^' => {
				expr.push(Token::Op(Operator::Pow));
			},
			'(' => {
				expr.push(Token::Open);
			},
			')' => {
				expr.push(Token::Close);
			},
			_ => continue,
		}
	}
	// Once we find an outermost (), split the rest of the expression after that off into a new vector
	//let mut expr_vecs: Vec<Vec<Token>> = Vec::new();
	while let Some(index) = expr.find_first(&Token::Open) { // If we find an index of an Open
		let end_set: usize = expr.find_last(&Token::Close).unwrap(); // Finds the last Close, need to find the one that actually matches the proper Open (if two Sets are on same depth)
		let mut lhs: Vec<Token> = Vec::new();
		{
			let (temp_lhs, temp_rhs) = expr.split_at(index); // [0, where set should be placed)
			lhs = temp_lhs.to_vec();
			let mut rhs = temp_rhs.to_vec(); // [where set should be placed, len)
			rhs.remove(0);
			let (left_rhs, right_rhs) = rhs.split_at(end_set-1);
			let (left_rhs, mut right_rhs) = (left_rhs.to_vec(), right_rhs.to_vec());
			right_rhs.remove(0);
			lhs.push(Token::Set(left_rhs));
			lhs.append(&mut right_rhs);
		}
		for i in (0..lhs.len()).rev() {
			if lhs.get(i).unwrap() == &Token::Close {
				lhs.remove(i);
				break;
			}
		}
		expr.replace_all_tokens(lhs);
	}
	Ok(expr)
}

#[test]
fn test_parse() {
	let input: String = String::from("+");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Add)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("-");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Sub)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("/");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Div)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("*");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Mul)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("^");
	assert_eq!(Expression::new(vec![Token::Op(Operator::Pow)], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("()");
	assert_eq!(Expression::new(vec![Token::Set(Vec::new())], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(+)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Add)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(-)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Sub)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(*)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Mul)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(/)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Div)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(^)");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Op(Operator::Pow)])], 0.0), parse_input(&input).unwrap());
	let input: String = String::from("(())");
	assert_eq!(Expression::new(vec![Token::Set(vec![Token::Set(Vec::new())])], 0.0), parse_input(&input).unwrap());
}<|endoftext|>


<commit_before>//! The elements of an Openstreetmap XML file.
//!
//! For now, the types only cotain a limited set of the most important
//! attributes.

use std::{borrow, hash, str};
use std::collections::{HashMap, HashSet};

//------------ Osm ----------------------------------------------------------

/// An OSM data set.
///
/// Contains a set each for nodes, ways, and relations.
pub struct Osm {
    nodes: HashSet<Node>,
    ways: HashSet<Way>,
    relations: HashSet<Relation>,
}

impl Osm {
    pub fn new() -> Self {
        Osm {
            nodes: HashSet::new(),
            ways: HashSet::new(),
            relations: HashSet::new(),
        }
    }

    pub fn add_node(&mut self, node: Node) -> bool {
        self.nodes.insert(node)
    }

    pub fn add_way(&mut self, way: Way) -> bool {
        self.ways.insert(way)
    }

    pub fn add_relation(&mut self, rel: Relation) -> bool {
        self.relations.insert(rel)
    }

    pub fn into_inner(self)
                      -> (HashSet<Node>, HashSet<Way>, HashSet<Relation>) {
        (self.nodes, self.ways, self.relations)
    }
}

impl Osm {
    pub fn nodes(&self) -> &HashSet<Node> {
        &self.nodes
    }

    pub fn has_node(&self, id: i64) -> bool {
        self.nodes.contains(&id)
    }

    pub fn get_node(&self, id: i64) -> Option<&Node> {
        self.nodes.get(&id)
    }

    pub fn ways(&self) -> &HashSet<Way> {
        &self.ways
    }

    pub fn has_way(&self, id: i64) -> bool {
        self.ways.contains(&id)
    }

    pub fn get_way(&self, id: i64) -> Option<&Way> {
        self.ways.get(&id)
    }

    pub fn relations(&self) -> &HashSet<Relation> {
        &self.relations
    }

    pub fn relations_mut(&mut self) -> &mut HashSet<Relation> {
        &mut self.relations
    }

    pub fn has_relation(&self, id: i64) -> bool {
        self.relations.contains(&id)
    }

    pub fn get_relation(&self, id: i64) -> Option<&Relation> {
        self.relations.get(&id)
    }
}

//------------ Node ---------------------------------------------------------

pub struct Node {
    id: i64,
    lat: f64,
    lon: f64,
    tags: Tags,
}

impl Node {
    pub fn new(id: i64, lat: f64, lon: f64) -> Self {
        Node {
            id: id,
            lat: lat,
            lon: lon,
            tags: Tags::new()
        }
    }

    pub fn set_lat(&mut self, lat: f64) {
        self.lat = lat
    }

    pub fn set_lon(&mut self, lon: f64) {
        self.lon = lon
    }

    pub fn insert_tag(&mut self, key: String, value: String) {
        self.tags.insert(key, value);
    }
}

impl Node {
    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn lat(&self) -> f64 {
        self.lat
    }

    pub fn lon(&self) -> f64 {
        self.lon
    }

    pub fn tags(&self) -> &Tags {
        &self.tags
    }
}

impl borrow::Borrow<i64> for Node {
    fn borrow(&self) -> &i64 {
        &self.id
    }
}

impl PartialEq for Node {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for Node { }

impl hash::Hash for Node {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state)
    }
}

//------------ Way ----------------------------------------------------------

pub struct Way {
    id: i64,
    nodes: Vec<i64>,
    tags: Tags,
}

impl Way {
    pub fn new(id: i64) -> Self {
        Way {
            id: id,
            nodes: Vec::new(),
            tags: Tags::new(),
        }
    }

    pub fn push_node(&mut self, id: i64) {
        self.nodes.push(id)
    }

    pub fn insert_tag(&mut self, key: String, value: String) {
        self.tags.insert(key, value);
    }
}

impl Way {
    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn nodes(&self) -> &[i64] {
        &self.nodes
    }

    pub fn tags(&self) -> &Tags {
        &self.tags
    }
}

impl borrow::Borrow<i64> for Way {
    fn borrow(&self) -> &i64 {
        &self.id
    }
}

impl PartialEq for Way {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for Way { }

impl hash::Hash for Way {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state)
    }
}

//------------ Relation ------------------------------------------------------

pub struct Relation {
    id: i64,
    members: Vec<Member>,
    tags: Tags,
}

impl Relation {
    pub fn new(id: i64) -> Self {
        Relation {
            id: id,
            members: Vec::new(),
            tags: Tags::new(),
        }
    }

    pub fn push_member(&mut self, member: Member) {
        self.members.push(member)
    }

    pub fn insert_tag(&mut self, key: String, value: String) {
        self.tags.insert(key, value)
    }
}

impl Relation {
    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn members(&self) -> &[Member] {
        &self.members
    }

    pub fn tags(&self) -> &Tags {
        &self.tags
    }

    pub fn tags_mut(&mut self) ->&mut Tags {
        &mut self.tags
    }
}

impl borrow::Borrow<i64> for Relation {
    fn borrow(&self) -> &i64 {
        &self.id
    }
}

impl PartialEq for Relation {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for Relation { }

impl hash::Hash for Relation {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state)
    }
}

//------------ Member --------------------------------------------------------

pub struct Member {
    mtype: MemberType,
    id: i64,
    role: String
}

impl Member {
    pub fn new(mtype: MemberType, id: i64, role: String) -> Self {
        Member {
            mtype: mtype,
            id: id,
            role: role
        }
    }
}

impl Member {
    pub fn mtype(&self) -> MemberType {
        self.mtype
    }

    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn role(&self) -> &str {
        &self.role
    }
}

//------------ MemberType ----------------------------------------------------

#[derive(Clone, Copy, Debug)]
pub enum MemberType {
    Way,
    Node,
    Relation
}

impl str::FromStr for MemberType {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "way" => Ok(MemberType::Way),
            "node" => Ok(MemberType::Node),
            "relation" => Ok(MemberType::Relation),
            _ => Err(format!("invalid member type '{}'", s))
        }
    }
}

//------------ Tags ----------------------------------------------------------

pub struct Tags(HashMap<String, String>);

impl Tags {
    pub fn new() -> Self {
        Tags(HashMap::new())
    }

    pub fn insert(&mut self, key: String, value: String) {
        self.0.insert(key, value);
    }

    pub fn remove(&mut self, key: &str) -> Option<String> {
        self.0.remove(key)
    }
}

impl Tags {
    pub fn has(&self, key: &str) -> bool {
        self.0.contains_key(key)
    }

    pub fn get(&self, key: &str) -> Option<&str> {
        self.0.get(key).map(AsRef::as_ref)
    }
}

<commit_msg>Add PartialEq and Eq for MemberType.<commit_after>//! The elements of an Openstreetmap XML file.
//!
//! For now, the types only cotain a limited set of the most important
//! attributes.

use std::{borrow, hash, str};
use std::collections::{HashMap, HashSet};

//------------ Osm ----------------------------------------------------------

/// An OSM data set.
///
/// Contains a set each for nodes, ways, and relations.
pub struct Osm {
    nodes: HashSet<Node>,
    ways: HashSet<Way>,
    relations: HashSet<Relation>,
}

impl Osm {
    pub fn new() -> Self {
        Osm {
            nodes: HashSet::new(),
            ways: HashSet::new(),
            relations: HashSet::new(),
        }
    }

    pub fn add_node(&mut self, node: Node) -> bool {
        self.nodes.insert(node)
    }

    pub fn add_way(&mut self, way: Way) -> bool {
        self.ways.insert(way)
    }

    pub fn add_relation(&mut self, rel: Relation) -> bool {
        self.relations.insert(rel)
    }

    pub fn into_inner(self)
                      -> (HashSet<Node>, HashSet<Way>, HashSet<Relation>) {
        (self.nodes, self.ways, self.relations)
    }
}

impl Osm {
    pub fn nodes(&self) -> &HashSet<Node> {
        &self.nodes
    }

    pub fn has_node(&self, id: i64) -> bool {
        self.nodes.contains(&id)
    }

    pub fn get_node(&self, id: i64) -> Option<&Node> {
        self.nodes.get(&id)
    }

    pub fn ways(&self) -> &HashSet<Way> {
        &self.ways
    }

    pub fn has_way(&self, id: i64) -> bool {
        self.ways.contains(&id)
    }

    pub fn get_way(&self, id: i64) -> Option<&Way> {
        self.ways.get(&id)
    }

    pub fn relations(&self) -> &HashSet<Relation> {
        &self.relations
    }

    pub fn relations_mut(&mut self) -> &mut HashSet<Relation> {
        &mut self.relations
    }

    pub fn has_relation(&self, id: i64) -> bool {
        self.relations.contains(&id)
    }

    pub fn get_relation(&self, id: i64) -> Option<&Relation> {
        self.relations.get(&id)
    }
}

//------------ Node ---------------------------------------------------------

pub struct Node {
    id: i64,
    lat: f64,
    lon: f64,
    tags: Tags,
}

impl Node {
    pub fn new(id: i64, lat: f64, lon: f64) -> Self {
        Node {
            id: id,
            lat: lat,
            lon: lon,
            tags: Tags::new()
        }
    }

    pub fn set_lat(&mut self, lat: f64) {
        self.lat = lat
    }

    pub fn set_lon(&mut self, lon: f64) {
        self.lon = lon
    }

    pub fn insert_tag(&mut self, key: String, value: String) {
        self.tags.insert(key, value);
    }
}

impl Node {
    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn lat(&self) -> f64 {
        self.lat
    }

    pub fn lon(&self) -> f64 {
        self.lon
    }

    pub fn tags(&self) -> &Tags {
        &self.tags
    }
}

impl borrow::Borrow<i64> for Node {
    fn borrow(&self) -> &i64 {
        &self.id
    }
}

impl PartialEq for Node {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for Node { }

impl hash::Hash for Node {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state)
    }
}

//------------ Way ----------------------------------------------------------

pub struct Way {
    id: i64,
    nodes: Vec<i64>,
    tags: Tags,
}

impl Way {
    pub fn new(id: i64) -> Self {
        Way {
            id: id,
            nodes: Vec::new(),
            tags: Tags::new(),
        }
    }

    pub fn push_node(&mut self, id: i64) {
        self.nodes.push(id)
    }

    pub fn insert_tag(&mut self, key: String, value: String) {
        self.tags.insert(key, value);
    }
}

impl Way {
    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn nodes(&self) -> &[i64] {
        &self.nodes
    }

    pub fn tags(&self) -> &Tags {
        &self.tags
    }
}

impl borrow::Borrow<i64> for Way {
    fn borrow(&self) -> &i64 {
        &self.id
    }
}

impl PartialEq for Way {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for Way { }

impl hash::Hash for Way {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state)
    }
}

//------------ Relation ------------------------------------------------------

pub struct Relation {
    id: i64,
    members: Vec<Member>,
    tags: Tags,
}

impl Relation {
    pub fn new(id: i64) -> Self {
        Relation {
            id: id,
            members: Vec::new(),
            tags: Tags::new(),
        }
    }

    pub fn push_member(&mut self, member: Member) {
        self.members.push(member)
    }

    pub fn insert_tag(&mut self, key: String, value: String) {
        self.tags.insert(key, value)
    }
}

impl Relation {
    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn members(&self) -> &[Member] {
        &self.members
    }

    pub fn tags(&self) -> &Tags {
        &self.tags
    }

    pub fn tags_mut(&mut self) ->&mut Tags {
        &mut self.tags
    }
}

impl borrow::Borrow<i64> for Relation {
    fn borrow(&self) -> &i64 {
        &self.id
    }
}

impl PartialEq for Relation {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for Relation { }

impl hash::Hash for Relation {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state)
    }
}

//------------ Member --------------------------------------------------------

pub struct Member {
    mtype: MemberType,
    id: i64,
    role: String
}

impl Member {
    pub fn new(mtype: MemberType, id: i64, role: String) -> Self {
        Member {
            mtype: mtype,
            id: id,
            role: role
        }
    }
}

impl Member {
    pub fn mtype(&self) -> MemberType {
        self.mtype
    }

    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn role(&self) -> &str {
        &self.role
    }
}

//------------ MemberType ----------------------------------------------------

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum MemberType {
    Way,
    Node,
    Relation
}

impl str::FromStr for MemberType {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "way" => Ok(MemberType::Way),
            "node" => Ok(MemberType::Node),
            "relation" => Ok(MemberType::Relation),
            _ => Err(format!("invalid member type '{}'", s))
        }
    }
}

//------------ Tags ----------------------------------------------------------

pub struct Tags(HashMap<String, String>);

impl Tags {
    pub fn new() -> Self {
        Tags(HashMap::new())
    }

    pub fn insert(&mut self, key: String, value: String) {
        self.0.insert(key, value);
    }

    pub fn remove(&mut self, key: &str) -> Option<String> {
        self.0.remove(key)
    }
}

impl Tags {
    pub fn has(&self, key: &str) -> bool {
        self.0.contains_key(key)
    }

    pub fn get(&self, key: &str) -> Option<&str> {
        self.0.get(key).map(AsRef::as_ref)
    }
}

<|endoftext|>


<commit_before>extern crate libc;

use std::io;
use std::thread;
use std::time::Duration;
use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
use std::ptr::{ self, read_volatile, write_volatile };

const GPIO_ADDR : libc::off_t      = 0x3F200000; // BCM2836 and BCM2837 GPIO address
const MEM_BLK_SIZE : libc::size_t  = 0xB0;       // GPIO register total size

const GPFSEL2_OFFSET_ADDR : isize  = 0x02;       // 0x08 / 4
const GPSET0_OFFSET_ADDR : isize   = 0x07;       // 0x1C / 4
const GPCLR0_OFFSET_ADDR : isize   = 0x0A;       // 0x28 / 4
const GPLEV0_OFFSET_ADDR : isize   = 0x0D;       // 0x34 / 4

const FSEL27_BIT : isize    = 21;
const SET27_BIT : isize     = 27;
const CLR27_BIT : isize     = 27;
const LEV27_BIT : isize     = 27;

const GPFSEL_INPUT : u32    = 0;
const GPFSEL_OUTPUT : u32   = 1;
const FSEL27_MASK : u32     = 0xFF1FFFFF;

const GPLEV_HIGH : u32      = 1;
const ON : u32              = 1;

const SLEEP_DELAY : u64     = 1;

fn main() {
    let mut blink_cnt : i32 = 0;

    let gpio_ptr : *mut u32 = map_gpio().expect( "failed to gpio mapping" );
    let fsel2_reg : *mut u32 = gpio_ptr.wrapping_offset( GPFSEL2_OFFSET_ADDR );
    let clr0_reg : *mut u32 = gpio_ptr.wrapping_offset( GPCLR0_OFFSET_ADDR );

    unsafe {
        write_volatile( fsel2_reg, ( *fsel2_reg & FSEL27_MASK ) | ( GPFSEL_OUTPUT << FSEL27_BIT ) );
    }

    while blink_cnt < 10 {
        blink_led( gpio_ptr );
        thread::sleep( Duration::from_secs( SLEEP_DELAY ) );
        blink_cnt = blink_cnt + 1;
    }

    unsafe {
        write_volatile( clr0_reg, *clr0_reg | ( ( ON << CLR27_BIT ) ) );
        write_volatile( fsel2_reg, ( *fsel2_reg & FSEL27_MASK ) | ( GPFSEL_INPUT << FSEL27_BIT ) );
    }
}

fn map_gpio() -> io::Result<*mut u32>  {
    let mem_file = OpenOptions::new()
                .read( true )
                .write( true )
                .custom_flags( libc::O_SYNC )
                .open( "/dev/gpiomem" )
                .expect( "can't open /dev/gpiomem" );

    unsafe {
        let gpio_ptr = libc::mmap( ptr::null_mut(),
                                   MEM_BLK_SIZE,
                                   libc::PROT_READ | libc::PROT_WRITE,
                                   libc::MAP_SHARED,
                                   mem_file.as_raw_fd(),
                                   GPIO_ADDR );

        if gpio_ptr == libc::MAP_FAILED {
             Err( io::Error::last_os_error() )
        }
        else
        {
            Ok( gpio_ptr as *mut u32 )
        }
    }
}

fn blink_led( gpio_ptr : *mut u32 ) {
    let set0_reg : *mut u32 = gpio_ptr.wrapping_offset( GPSET0_OFFSET_ADDR );
    let clr0_reg : *mut u32 = gpio_ptr.wrapping_offset( GPCLR0_OFFSET_ADDR );
    let lev0_reg : *mut u32 = gpio_ptr.wrapping_offset( GPLEV0_OFFSET_ADDR );
    let level : u32;

    unsafe {
       level = ( read_volatile( lev0_reg ) >> LEV27_BIT ) & 0x00000001;
    }

    if level == GPLEV_HIGH {
        unsafe {
            write_volatile( clr0_reg, *clr0_reg | ( ON << CLR27_BIT ) );
        }
    }
    else
    {
        unsafe {
            write_volatile( set0_reg, *set0_reg | ( ON << SET27_BIT ) );
        }
    }
}
<commit_msg>Revert memory size for memory mapping<commit_after>extern crate libc;

use std::io;
use std::thread;
use std::time::Duration;
use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
use std::ptr::{ self, read_volatile, write_volatile };

const GPIO_ADDR : libc::off_t      = 0x3F200000; // BCM2836 and BCM2837 GPIO address
const MEM_BLK_SIZE : libc::size_t  = 4096;       // page size(4KB)

const GPFSEL2_OFFSET_ADDR : isize  = 0x02;       // 0x08 / 4
const GPSET0_OFFSET_ADDR : isize   = 0x07;       // 0x1C / 4
const GPCLR0_OFFSET_ADDR : isize   = 0x0A;       // 0x28 / 4
const GPLEV0_OFFSET_ADDR : isize   = 0x0D;       // 0x34 / 4

const FSEL27_BIT : isize    = 21;
const SET27_BIT : isize     = 27;
const CLR27_BIT : isize     = 27;
const LEV27_BIT : isize     = 27;

const GPFSEL_INPUT : u32    = 0;
const GPFSEL_OUTPUT : u32   = 1;
const FSEL27_MASK : u32     = 0xFF1FFFFF;

const GPLEV_HIGH : u32      = 1;
const ON : u32              = 1;

const SLEEP_DELAY : u64     = 1;

fn main() {
    let mut blink_cnt : i32 = 0;

    let gpio_ptr : *mut u32 = map_gpio().expect( "failed to gpio mapping" );
    let fsel2_reg : *mut u32 = gpio_ptr.wrapping_offset( GPFSEL2_OFFSET_ADDR );
    let clr0_reg : *mut u32 = gpio_ptr.wrapping_offset( GPCLR0_OFFSET_ADDR );

    unsafe {
        write_volatile( fsel2_reg, ( *fsel2_reg & FSEL27_MASK ) | ( GPFSEL_OUTPUT << FSEL27_BIT ) );
    }

    while blink_cnt < 10 {
        blink_led( gpio_ptr );
        thread::sleep( Duration::from_secs( SLEEP_DELAY ) );
        blink_cnt = blink_cnt + 1;
    }

    unsafe {
        write_volatile( clr0_reg, *clr0_reg | ( ( ON << CLR27_BIT ) ) );
        write_volatile( fsel2_reg, ( *fsel2_reg & FSEL27_MASK ) | ( GPFSEL_INPUT << FSEL27_BIT ) );
    }
}

fn map_gpio() -> io::Result<*mut u32>  {
    let mem_file = OpenOptions::new()
                .read( true )
                .write( true )
                .custom_flags( libc::O_SYNC )
                .open( "/dev/gpiomem" )
                .expect( "can't open /dev/gpiomem" );

    unsafe {
        let gpio_ptr = libc::mmap( ptr::null_mut(),
                                   MEM_BLK_SIZE,
                                   libc::PROT_READ | libc::PROT_WRITE,
                                   libc::MAP_SHARED,
                                   mem_file.as_raw_fd(),
                                   GPIO_ADDR );

        if gpio_ptr == libc::MAP_FAILED {
             Err( io::Error::last_os_error() )
        }
        else
        {
            Ok( gpio_ptr as *mut u32 )
        }
    }
}

fn blink_led( gpio_ptr : *mut u32 ) {
    let set0_reg : *mut u32 = gpio_ptr.wrapping_offset( GPSET0_OFFSET_ADDR );
    let clr0_reg : *mut u32 = gpio_ptr.wrapping_offset( GPCLR0_OFFSET_ADDR );
    let lev0_reg : *mut u32 = gpio_ptr.wrapping_offset( GPLEV0_OFFSET_ADDR );
    let level : u32;

    unsafe {
       level = ( read_volatile( lev0_reg ) >> LEV27_BIT ) & 0x00000001;
    }

    if level == GPLEV_HIGH {
        unsafe {
            write_volatile( clr0_reg, *clr0_reg | ( ON << CLR27_BIT ) );
        }
    }
    else
    {
        unsafe {
            write_volatile( set0_reg, *set0_reg | ( ON << SET27_BIT ) );
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::clone::Clone;
use std::str::Lines;
use std::io::prelude::*;
use std::io::BufReader;

// Device Tree stucture
/*
struct DeviceTree<'a> {
	version: u32,
	boot_cpuid: u32,
	reserved_mem: Vec<(u64, u64)>,
	root: Node<'a, 'a>,
}

struct DeviceNode<'a, 'b> {
	name: String,
	props: Vec<(String, Property<'a>)>,
	children: Vec<DeviceNode<'b, 'b>>,
}

enum Property<'a> {
	Empty,
	Cells(Vec<u32>),
	String(String),
	ByteString(Vec<u8>),
	Combo(Vec<&'a Property<'a>>),
}
*/

// File tracking
#[derive(Debug)]
struct ParsedFile<'a> {
	path: &'a Path,
	file: File,
	method: IncludeMethod<'a>,
	included_files: Vec<ParsedFile<'a>>,
}

#[derive(Debug)]
enum IncludeMethod<'a> {
	DTS,
	CPP(&'a File, Vec<FileMapping>),
}

#[derive(Debug)]
struct FileMapping {
	parent_start: usize,
	child_start: usize,
	len: usize,
}

#[derive(Debug)]
enum LinemarkerFlag {
	Start,
	Return,
	System,
	Extern,
}

// Change tracking
/*
struct Change<'a> {
	file: File,
	line: usize,
	// maybe point to node?
	name: String,
	value: Property<'a>,
}
*/

impl<'a> ParsedFile<'a> {
	fn new(path: &'a Path, method: IncludeMethod<'a>) -> ParsedFile<'a> {
		ParsedFile {
			path: path,
			file: File::open(path).unwrap(),
			method: method,
			included_files: vec![],
		}
	}
}
/*
impl<'a> fmt::Display for ParsedFile<'a> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{:?}: {}", self.file, self.method)
		//Name: method
		//|- Next one
	}
}
*/

const CPP_OUTPUT_NAME: &'static str = "dts_viewer_tmp.dts";

fn main() {
	// let file_name = "am335x-boneblack.dts";
	let file_name = match env::args().nth(1) {
		None => {
			println!("You forgot the dts file, you dummy");
			return;
		}
		Some(x) => x,
	};

	let arch = "arm";

	let dts_folder = PathBuf::from("arch").join(arch).join("boot/dts/");
	let file_path = dts_folder.join(file_name);

	let include_output = Command::new("arm-linux-gnueabi-gcc")
		.args(&["-H", "-E", "-nostdinc"])
		.args(&["-I", dts_folder.to_str().unwrap()])
		.args(&["-I", dts_folder.join("include/").to_str().unwrap()])
		.args(&["-undef", "-D__DTS__", "-x", "assembler-with-cpp"])
		.args(&["-o", CPP_OUTPUT_NAME])
		.arg(&file_path)
		.output()
		.expect("failed to execute process"); //TODO: properly handle errors

	let global_file = File::open(CPP_OUTPUT_NAME).unwrap();

	let cpp_output = String::from_utf8_lossy(&include_output.stderr);
	println!("{}", cpp_output);

	let mut main_file = ParsedFile::new(&Path::new(&file_path),
										IncludeMethod::CPP(&global_file, vec![]));

	parse_cpp_output(&mut cpp_output.lines(), &mut main_file, &global_file, 0);

	let global_buffer = BufReader::new(File::open(CPP_OUTPUT_NAME).unwrap());
	let mut parsed_lines = global_buffer.lines()
		.enumerate()
		.filter(|&(_, ref line)| match *line {
			Ok(ref l) => l.starts_with('#'),
			Err(_) => false,
		})
		.map(|(line_num, line)| {
			let line = line.unwrap();
			let tokens: Vec<&str> = line.split('"').map(|s| s.trim_matches('#').trim()).collect();
			let child_num: usize = tokens[0].parse().unwrap();
			let flag = match tokens[2].parse().unwrap_or(0) { //TODO: make conversion function
				1 => Some(LinemarkerFlag::Start),
				2 => Some(LinemarkerFlag::Return),
				3 => Some(LinemarkerFlag::System),
				4 => Some(LinemarkerFlag::Extern),
				_ => None,
			};
			(line_num + 1, child_num, PathBuf::from(tokens[1]), flag)
		})
		.peekable();

	while let Some((path, mapping)) =
		parse_cpp_linemarkers(&parsed_lines.next(), &parsed_lines.peek()) {
		if mapping.len > 1 {
			println!("{:?} {:?}", path, mapping);
			// find file in ParsedFile tree
			// add mapping to vec
		}
	}
}

fn count_begining_chars(s: &str, c: char) -> usize {
	let mut count: usize = 0;
	for sc in s.chars() {
		if sc == c {
			count += 1;
		} else {
			break;
		}
	}

	count
}

fn parse_cpp_output<'a>(lines: &mut Lines<'a>,
						parrent_file: &mut ParsedFile<'a>,
						global_file: &'a File,
						depth: usize) {
	while let Some(line) = lines.clone().next() { //TODO: try to use Peekable again. Had problems with recursion before
		let count = count_begining_chars(line, '.');

		if count == 0 {
			return;
		} else if count < depth {
			return;
		} else if count == depth {
			return;
		} else if count > depth && (count - depth) == 1 {
			parrent_file.included_files.push(
					ParsedFile::new(
							&Path::new(lines.next()
								.unwrap()
								.trim_left_matches('.')
								.trim_left()),
							IncludeMethod::CPP(&global_file, vec![])
			));
			parse_cpp_output(lines,
							 parrent_file.included_files.last_mut().unwrap(),
							 global_file,
							 depth + 1);
		} else {
			panic!("Match that should not have been reached.");
		}
	}
}

fn parse_cpp_linemarkers<'a>(current: &'a Option<(usize, usize, PathBuf, Option<LinemarkerFlag>)>,
						next: &Option<&(usize, usize, PathBuf, Option<LinemarkerFlag>)>)
						-> Option<(&'a Path, FileMapping)> {
	if let Some((c_line_num, c_child_num, ref c_path, _)) = *current {
		if let Some(&(n_line_num, _, _, _)) = *next {
			Some((c_path,
				FileMapping {
					parent_start: c_line_num + 1,
					child_start: c_child_num,
					len: n_line_num - c_line_num,
			}))
		} else {
			let last_line = BufReader::new(File::open(CPP_OUTPUT_NAME).unwrap())
				.lines()
				.count(); //TODO: don't use lines() as that allocates new Strings on the heap
			Some((c_path,
				FileMapping {
					parent_start: c_line_num + 1,
					child_start: c_child_num,
					len: last_line - c_line_num, // TODO: find length of file
			}))
		}
	} else {
		None
	}
}
<commit_msg>Mappings are now given to the correct ParsedFile<commit_after>use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::clone::Clone;
use std::str::Lines;
use std::io::prelude::*;
use std::io::BufReader;

// Device Tree stucture
/*
struct DeviceTree<'a> {
	version: u32,
	boot_cpuid: u32,
	reserved_mem: Vec<(u64, u64)>,
	root: Node<'a, 'a>,
}

struct DeviceNode<'a, 'b> {
	name: String,
	props: Vec<(String, Property<'a>)>,
	children: Vec<DeviceNode<'b, 'b>>,
}

enum Property<'a> {
	Empty,
	Cells(Vec<u32>),
	String(String),
	ByteString(Vec<u8>),
	Combo(Vec<&'a Property<'a>>),
}
*/

// File tracking
#[derive(Debug)]
struct ParsedFile<'a> {
	path: &'a Path,
	file: File,
	method: IncludeMethod,
	included_files: Vec<ParsedFile<'a>>,
}

#[derive(Debug)]
enum IncludeMethod {
	DTS,
	CPP(File, Vec<FileMapping>),
}

#[derive(Debug, Clone, Copy)]
struct FileMapping {
	parent_start: usize,
	child_start: usize,
	len: usize,
}

#[derive(Debug)]
enum LinemarkerFlag {
	Start,
	Return,
	System,
	Extern,
}

// Change tracking
/*
struct Change<'a> {
	file: File,
	line: usize,
	// maybe point to node?
	name: String,
	value: Property<'a>,
}
*/

impl<'a> ParsedFile<'a> {
	fn new(path: &'a Path, method: IncludeMethod) -> ParsedFile<'a> {
		ParsedFile {
			path: path,
			file: File::open(path).unwrap(),
			method: method,
			included_files: vec![],
		}
	}

	fn assign_mapping(&mut self, path: &Path, mapping: FileMapping) -> Result<(), String> { //TODO: error propogation
		if self.path == path {
			match self.method {
				IncludeMethod::CPP(_, ref mut mappings) => mappings.push(mapping),
				IncludeMethod::DTS => unreachable!(),
			};
			Ok(())
		} else {
			for file in self.included_files.iter_mut() {
				if file.assign_mapping(path, mapping).is_ok() {
					return Ok(());
				}
			}
			Err(format!("Did not find file: {:?}", path))
		}
	}
}
/*
impl<'a> fmt::Display for ParsedFile<'a> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{:?}: {}", self.file, self.method)
		//Name: method
		//|- Next one
	}
}
*/

const CPP_OUTPUT_NAME: &'static str = "dts_viewer_tmp.dts";

fn main() {
	// let file_name = "am335x-boneblack.dts";
	let file_name = match env::args().nth(1) {
		None => {
			println!("You forgot the dts file, you dummy");
			return;
		}
		Some(x) => x,
	};

	let arch = "arm";

	let dts_folder = PathBuf::from("arch").join(arch).join("boot/dts/");
	let file_path = dts_folder.join(file_name);

	let include_output = Command::new("arm-linux-gnueabi-gcc")
		.args(&["-H", "-E", "-nostdinc"])
		.args(&["-I", dts_folder.to_str().unwrap()])
		.args(&["-I", dts_folder.join("include/").to_str().unwrap()])
		.args(&["-undef", "-D__DTS__", "-x", "assembler-with-cpp"])
		.args(&["-o", CPP_OUTPUT_NAME])
		.arg(&file_path)
		.output()
		.expect("failed to execute process"); //TODO: properly handle errors

	let cpp_output = String::from_utf8_lossy(&include_output.stderr);
	println!("{}", cpp_output);

	let mut root_file = ParsedFile::new(&Path::new(&file_path),
										IncludeMethod::CPP(File::open(CPP_OUTPUT_NAME).unwrap(), vec![]));

	parse_cpp_output(&mut cpp_output.lines(), &mut root_file, 0);

	let global_buffer = BufReader::new(File::open(CPP_OUTPUT_NAME).unwrap());
	let mut parsed_lines = global_buffer.lines()
		.enumerate()
		.filter(|&(_, ref line)| match *line {
			Ok(ref l) => l.starts_with('#'),
			Err(_) => false,
		})
		.map(|(line_num, line)| {
			let line = line.unwrap();
			let tokens: Vec<&str> = line.split('"').map(|s| s.trim_matches('#').trim()).collect();
			let child_num: usize = tokens[0].parse().unwrap();
			let flag = match tokens[2].parse().unwrap_or(0) { //TODO: make conversion function
				1 => Some(LinemarkerFlag::Start),
				2 => Some(LinemarkerFlag::Return),
				3 => Some(LinemarkerFlag::System),
				4 => Some(LinemarkerFlag::Extern),
				_ => None,
			};
			(line_num + 1, child_num, PathBuf::from(tokens[1]), flag)
		})
		.peekable();

	while let Some((path, mapping)) =
		parse_cpp_linemarkers(&parsed_lines.next(), &parsed_lines.peek()) {
		if mapping.len > 1 {
			root_file.assign_mapping(path, mapping).unwrap();
		}
	}
}

fn count_begining_chars(s: &str, c: char) -> usize {
	let mut count: usize = 0;
	for sc in s.chars() {
		if sc == c {
			count += 1;
		} else {
			break;
		}
	}

	count
}

fn parse_cpp_output<'a>(lines: &mut Lines<'a>,
						parrent_file: &mut ParsedFile<'a>,
						depth: usize) {
	while let Some(line) = lines.clone().next() { //TODO: try to use Peekable again. Had problems with recursion before
		let count = count_begining_chars(line, '.');

		if count == 0 {
			return;
		} else if count < depth {
			return;
		} else if count == depth {
			return;
		} else if count > depth && (count - depth) == 1 {
			parrent_file.included_files.push(
					ParsedFile::new(
							&Path::new(lines.next()
								.unwrap()
								.trim_left_matches('.')
								.trim_left()),
							IncludeMethod::CPP(File::open(CPP_OUTPUT_NAME).unwrap(), Vec::new())
			));
			parse_cpp_output(lines,
							 parrent_file.included_files.last_mut().unwrap(),
							 depth + 1);
		} else {
			unreachable!();
		}
	}
}

fn parse_cpp_linemarkers<'a>(current: &'a Option<(usize, usize, PathBuf, Option<LinemarkerFlag>)>,
						next: &Option<&(usize, usize, PathBuf, Option<LinemarkerFlag>)>)
						-> Option<(&'a Path, FileMapping)> {
	if let Some((c_line_num, c_child_num, ref c_path, _)) = *current {
		if let Some(&(n_line_num, _, _, _)) = *next {
			Some((c_path,
				FileMapping {
					parent_start: c_line_num + 1,
					child_start: c_child_num,
					len: n_line_num - c_line_num,
			}))
		} else {
			let last_line = BufReader::new(File::open(CPP_OUTPUT_NAME).unwrap())
				.lines()
				.count(); //TODO: don't use lines() as that allocates new Strings on the heap
			Some((c_path,
				FileMapping {
					parent_start: c_line_num + 1,
					child_start: c_child_num,
					len: last_line - c_line_num,
			}))
		}
	} else {
		None
	}
}
<|endoftext|>