<commit_before>extern crate num;
extern crate portaudio;
extern crate rtlsdr;

use portaudio as pa;
use rtlsdr::{RTLSDRDevice, RTLSDRError};
use num::complex::Complex;
use std::env;
use std::collections::VecDeque;
use std::f32::consts::PI;
use std::error::Error;

// Make sure that the buffer size is radix-2, otherwise the read_sync function
// will fail with an error code of -8.
const BUF_SIZE: usize = 131072;

// Most other sample rates fail, but this one works for my particular device.
// I will investigate exactly what's happening here and generate a list of
// possible sample rates (if there are others besides this one).
const SAMPLE_RATE: u32 = 1800000;

// Here is the sample rate of the output waveform we'll try to use.
const SAMPLE_RATE_FREQ: f64 = 48000.0;

const CHANNELS: i32 = 2;

const DEVIATION: i32 = 2500;

const BANDWIDTH: u32 = 25000;

fn main() {
    match run() {
        Ok(()) => (),
        Err(e) => println!("ERROR: {}", e),
    }
}

fn run() -> Result<(), Box<Error>> {
    let sdr_index: i32 = env::args().nth(1)
        .expect("Please specify the SDR index")
        .parse::<i32>()?;
    let fm_freq_mhz: f32 = env::args().nth(2)
        .expect("Please specify a center frequency (MHz).")
        .parse::<f32>()?;

    // Initialize the PortAudio class.
    let pa = pa::PortAudio::new()?;
    let settings = pa.default_output_stream_settings(CHANNELS,
                                                     SAMPLE_RATE_FREQ,
                                                     BUF_SIZE as u32)
        .unwrap();
    let mut stream = pa.open_blocking_stream(settings)?;
    try!(stream.start());

    let fm_freq: u32 = (fm_freq_mhz * 1e6) as u32;
    let mut sdr = init_sdr(sdr_index, fm_freq).unwrap();
    let gain = (2.0 * PI * DEVIATION as f32 / SAMPLE_RATE_FREQ as f32).recip();

    loop {
        // Read the samples, convert to copmlex values, and demodulate them.
        let bytes = sdr.read_sync(BUF_SIZE).unwrap();
        let iq_vec = read_samples(bytes).unwrap();
        let mut demod_iq = demod_fm(iq_vec, gain);

        // Get the write stream and write our samples to the stream.
        let out_frames = match stream.write_available() {
            Ok(available) => {
                match available {
                    pa::StreamAvailable::Frames(frames) => frames as u32,
                    _ => return Err(Box::new(pa::error::Error::NullCallback)),
                }
            }
            Err(e) => return Err(Box::new(e)),
        };

        let buffer_frames = (demod_iq.len() / CHANNELS as usize) as u32;
        let write_frames = if buffer_frames >= out_frames {
            out_frames
        } else {
            buffer_frames
        };
        let n_write_samples = write_frames as usize * CHANNELS as usize;

        stream.write(write_frames,
                   |output| for ix in 0..n_write_samples as usize {
                       output[ix] = demod_iq.pop_front().unwrap();
                   })?;
    }
}

fn init_sdr(sdr_index: i32, fm_freq: u32) -> Result<RTLSDRDevice, RTLSDRError> {
    let mut sdr = try!(rtlsdr::open(sdr_index));
    try!(sdr.set_center_freq(fm_freq));
    try!(sdr.set_sample_rate(SAMPLE_RATE));
    try!(sdr.set_tuner_bandwidth(BANDWIDTH));
    try!(sdr.set_agc_mode(true));
    try!(sdr.reset_buffer());
    Ok(sdr)
}

fn read_samples(bytes: Vec<u8>) -> Option<Vec<Complex<f32>>> {
    // The docs tell us that RTL-SDR sends us data in bytes alternating between
    // I and Q. I'm not normalizing here, but I might have to in the future.

    // First, check that we've been given an even number of bytes. Not sure
    // what to do if we don't get I and Q.
    let bytes_len = bytes.len();
    if bytes_len % 2 != 0 {
        println!("Received an odd number of samples.");
        return None;

    }
    let mut iq_vec: Vec<Complex<f32>> = Vec::with_capacity(bytes_len / 2);

    // Write the values to the complex value and normalize from [0, 255] to
    // [-1, 1].
    for iq in bytes.chunks(2) {
        iq_vec.push(Complex::new((iq[0] as f32 - 127.5) / 127.5,
                                 (iq[1] as f32 - 127.5) / 127.5));
    }

    Some(iq_vec)
}

fn demod_fm(iq: Vec<Complex<f32>>, gain: f32) -> VecDeque<f32> {
    let mut demod_queue: VecDeque<f32> = VecDeque::with_capacity(iq.len());
    let mut prev = iq[0];
    for ix in 0..iq.len() {
        let c: Complex<f32> = prev.conj() * iq[ix];
        demod_queue.push_back(c.im.atan2(c.re) * gain);
        prev = iq[ix];
    }
    demod_queue
}
<commit_msg>Getting barely recognizeable sound on 88.7!<commit_after>extern crate num;
extern crate portaudio;
extern crate rtlsdr;

use portaudio as pa;
use rtlsdr::{RTLSDRDevice, RTLSDRError};
use num::complex::Complex;
use std::env;
use std::collections::VecDeque;
use std::f32::consts::PI;
use std::error::Error;

// Make sure that the buffer size is radix-2, otherwise the read_sync function
// will fail with an error code of -8.
const BUF_SIZE: usize = 131072;

// Most other sample rates fail, but this one works for my particular device.
// I will investigate exactly what's happening here and generate a list of
// possible sample rates (if there are others besides this one).
const SAMPLE_RATE: u32 = 1140000;

// Here is the sample rate of the output waveform we'll try to use.
const SAMPLE_RATE_AUDIO: f64 = 44100.0;

const DEVIATION: u32 = 2500;

const BANDWIDTH: u32 = 200000;

const CHANNELS: i32 = 2;

fn main() {
    match run() {
        Ok(()) => (),
        Err(e) => println!("ERROR: {}", e),
    }
}

fn run() -> Result<(), Box<Error>> {
    let sdr_index: i32 = env::args().nth(1)
        .expect("Please specify the SDR index")
        .parse::<i32>()?;
    let fm_freq_mhz: f32 = env::args().nth(2)
        .expect("Please specify a center frequency (MHz).")
        .parse::<f32>()?;

    // Initialize the PortAudio class.
    let audio = try!(pa::PortAudio::new());
    let settings =
        try!(audio.default_output_stream_settings(CHANNELS,
                                                  SAMPLE_RATE_AUDIO,
                                                  BUF_SIZE as u32));
    let mut stream = try!(audio.open_blocking_stream(settings));
    try!(stream.start());

    let fm_freq: u32 = (fm_freq_mhz * 1e6) as u32;
    let mut sdr = init_sdr(sdr_index, fm_freq).unwrap();

    // TODO: does this gain value make sense based on what I'm doing?
    let gain = (2.0 * PI * DEVIATION as f32 / SAMPLE_RATE_AUDIO as f32).recip();

    loop {
        // Read the samples and decimate down to match the sample rate of the
        // audio that'll be going out.
        //
        // TODO: on 88.7 I can make out some instruments, but the audio is still
        // very, very poor. Need to figure out what we need to do here. At a
        // minimum, we need a low-pass filter to filter out the high
        // frequency components that are almost certainly aliasing. In addition,
        // we are underflowing the audio buffer. Not sure if this is a
        // performance issue (release didn't help) or if I need to re-think how
        // I send data to the sound card.
        let bytes = sdr.read_sync(BUF_SIZE).unwrap();
        let mut iq_vec = read_samples(bytes).unwrap();
        let dec_rate = (SAMPLE_RATE as f64/ SAMPLE_RATE_AUDIO) as usize;
        iq_vec = decimate(iq_vec, dec_rate);

        // After decimation, demodulate the signal.
        //
        // TODO: from what I've read there should be some decimation here as
        // well but with narrowband FM, we decimate the signal into
        // nothingness. Need to figure out what we do between wideband and
        // narrowband FM.
        let mut demod_iq = demod_fm(iq_vec, gain);

        // Get the write stream and write our samples to the stream.
        let out_frames = match stream.write_available() {
            Ok(available) => {
                match available {
                    pa::StreamAvailable::Frames(frames) => frames as u32,
                    _ => return Err(Box::new(pa::error::Error::NullCallback)),
                }
            }
            Err(e) => return Err(Box::new(e)),
        };

        let buffer_frames = (demod_iq.len() / CHANNELS as usize) as
                            u32;
        let write_frames = if buffer_frames >= out_frames {
            out_frames
        } else {
            buffer_frames
        };
        let n_write_samples = write_frames as usize * CHANNELS as usize;

        stream.write(write_frames,
                   |output| for ix in 0..n_write_samples as usize {
                       output[ix] = demod_iq.pop_front().unwrap();
                   })?;
    }
}

fn init_sdr(sdr_index: i32, fm_freq: u32) -> Result<RTLSDRDevice, RTLSDRError> {
    let mut sdr = try!(rtlsdr::open(sdr_index));
    try!(sdr.set_center_freq(fm_freq));
    try!(sdr.set_sample_rate(SAMPLE_RATE));
    try!(sdr.set_tuner_bandwidth(BANDWIDTH));
    try!(sdr.set_agc_mode(true));
    try!(sdr.reset_buffer());
    Ok(sdr)
}

fn decimate_queue<T: Copy>(signal: VecDeque<T>, dec_rate: usize) -> VecDeque<T> {
    let mut ix = 0;
    let mut signal_dec = VecDeque::<T>::new();
    while ix < signal.len() {
        signal_dec.push_back(*(signal.get(ix).unwrap()));
        ix += dec_rate;
    }
    signal_dec
}

fn decimate<T: Copy>(signal: Vec<T>, dec_rate: usize) -> Vec<T> {
    let mut ix = 0;
    let mut signal_dec = Vec::<T>::new();
    while ix < signal.len() {
        signal_dec.push(*(signal.get(ix).unwrap()));
        ix += dec_rate;
    }
    signal_dec
}

fn read_samples(bytes: Vec<u8>) -> Option<Vec<Complex<f32>>> {
    // The docs tell us that RTL-SDR sends us data in bytes alternating between
    // I and Q. I'm not normalizing here, but I might have to in the future.

    // First, check that we've been given an even number of bytes. Not sure
    // what to do if we don't get I and Q.
    let bytes_len = bytes.len();
    if bytes_len % 2 != 0 {
        println!("Received an odd number of samples.");
        return None;

    }
    let mut iq_vec: Vec<Complex<f32>> = Vec::with_capacity(bytes_len / 2);

    // Write the values to the complex value and normalize from [0, 255] to
    // [-1, 1].
    for iq in bytes.chunks(2) {
        iq_vec.push(Complex::new((iq[0] as f32 - 127.5) / 127.5,
                                 (iq[1] as f32 - 127.5) / 127.5));
    }

    Some(iq_vec)
}

fn demod_fm(iq: Vec<Complex<f32>>, gain: f32) -> VecDeque<f32> {
    let mut demod_queue: VecDeque<f32> = VecDeque::with_capacity(iq.len());
    let mut prev = iq[0];
    for ix in 0..iq.len() {
        let c: Complex<f32> = prev.conj() * iq[ix];
        demod_queue.push_back(c.re.atan2(c.im) * gain);
        prev = iq[ix];
    }
    demod_queue
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate urlencoded;
extern crate router;
extern crate smtp;
#[macro_use]
extern crate log;

use std::io::Read;
use std::net::TcpStream;
// use std::collections::HashMap;
use iron::prelude::*;
use iron::status;
use urlencoded::UrlEncodedQuery;
use urlencoded::UrlEncodedBody;
// use urlencoded::QueryMap;
use router::Router;
use smtp::sender::{Sender, SenderBuilder};
use smtp::mailer::EmailBuilder;

fn main() {
    info!("Starting up!");
    println!("Hello");
    let mut router = Router::new();

    // ?first_name=Karen&last_name=Rustad&email=karen%40aerofs.com&phone=952-210-6598&org_name=&org_size=&title=&comment=Testing

    router.get("/", hello_world);
    router.post("/sales", post_email);

    fn hello_world(_: &mut Request) -> IronResult<Response> {
        let payload = "Hi!!!!";
        Ok(Response::with((status::Ok, payload)))
    }

    // Receive a message by POST and play it back.
    fn post_email(request: &mut Request) -> IronResult<Response> {
        let mut payload = String::new();
        let mut email = "form".to_string();

        match request.get_ref::<UrlEncodedQuery>() {
            Ok(ref hashmap) => {
                for (name, value) in hashmap.iter() {
                    payload.push_str(name);
                    payload.push_str(": ");
                    payload.push_str(&value[0]);
                    payload.push_str("\n");
                }
                if hashmap.contains_key("email") {
                    email = hashmap["email"][0].clone();
                }
            },
            Err(ref e) => println!("{:?}", e)
        };

        match request.get_ref::<UrlEncodedBody>() {
            Ok(ref hashmap) => println!("Parsed POST request body:\n {:?}", hashmap),
            Err(ref e) => println!("{:?}", e)
        };

        let mut email_builder = EmailBuilder::new();
        email_builder = email_builder.to("karen@aerofs.com");
        let email = email_builder.from("inquiryform@aerofs.com")
                        .body(&payload)
                        .subject(&format!("Inquiry from {}", email))
                        .build();
        let sb = SenderBuilder::new(("devmail.aerofs.com",25)).hello_name("localhost")
                        .enable_connection_reuse(false);

        let mut sender: Sender = sb.build();
        let result = sender.send(email);
        sender.close();

        match result {
            Ok(..) => println!("Email sent successfully"),
            Err(error) => println!("Error: {:?}", error),
        }

        return Ok(Response::with((status::Ok, "")));
    }

    Iron::new(router).http("localhost:3000").unwrap();
}<commit_msg>time to demo<commit_after>extern crate iron;
extern crate urlencoded;
extern crate router;
extern crate smtp;
#[macro_use]
extern crate log;

use std::io::Read;
use std::net::TcpStream;
// use std::collections::HashMap;
use iron::prelude::*;
use iron::status;
use urlencoded::UrlEncodedQuery;
use urlencoded::UrlEncodedBody;
// use urlencoded::QueryMap;
use router::Router;
use smtp::sender::{Sender, SenderBuilder};
use smtp::mailer::EmailBuilder;

// const SEND_DOMAIN: &'static str = "@aerofs.com";

fn main() {
    info!("Starting up!");
    println!("Hello");
    let mut router = Router::new();

    router.get("/", hello_world);
    router.post("/:address", post_email);

    fn hello_world(_: &mut Request) -> IronResult<Response> {
        let payload = "Hi!";
        Ok(Response::with((status::Ok, payload)))
    }

    // Receive a message by POST and play it back.
    fn post_email(request: &mut Request) -> IronResult<Response> {
        let mut payload = String::new();
        let mut email = "form".to_string();
        //println!("{}", request.extensions.get::<Params>());

        match request.get_ref::<UrlEncodedQuery>() {
            Ok(ref hashmap) => {
                for (name, value) in hashmap.iter() {
                    payload.push_str(name);
                    payload.push_str(": ");
                    payload.push_str(&value[0]);
                    payload.push_str("\n");
                }
                if hashmap.contains_key("email") {
                    email = hashmap["email"][0].clone();
                }
            },
            Err(ref e) => println!("{:?}", e)
        };

        match request.get_ref::<UrlEncodedBody>() {
            Ok(ref hashmap) => println!("Parsed POST request body:\n {:?}", hashmap),
            Err(ref e) => println!("{:?}", e)
        };

        let mut recv_email = "karen@aerofs.com";
        let mut email_builder = EmailBuilder::new();
        email_builder = email_builder.to(recv_email);
        let email = email_builder.from("inquiryform@aerofs.com")
                        .body(&payload)
                        .subject(&format!("Inquiry from {}", email))
                        .build();
        let sb = SenderBuilder::new(("devmail.aerofs.com",25)).hello_name("localhost")
                        .enable_connection_reuse(false);

        let mut sender: Sender = sb.build();
        let result = sender.send(email);
        sender.close();

        match result {
            Ok(..) => println!("Email sent successfully"),
            Err(error) => println!("Error: {:?}", error),
        }

        return Ok(Response::with((status::Ok, "")));
    }

    Iron::new(router).http("localhost:3000").unwrap();
}<|endoftext|>


<commit_before>//#![feature(alloc_system)]
//extern crate alloc_system;   // strip down size of binary executable

extern crate id3;
extern crate tree_magic;  // mime types

use std::io;
use std::env;     // args
use std::fs::{self, DirEntry};  // directory
use std::path::Path;  // path, clear
use std::iter::*;

use id3::Tag;

/// generell info
struct InfoAlbum <'b> {
    album_name : &'b str,
    reference_path : Vec<&'b Path>,
}

struct Collection<'b> { collection : Vec<&'b InfoAlbum<'b> > }

impl <'b> Collection <'b> {

    pub fn new() -> Collection<'b>  {
        Collection {
            collection : Vec::new()
        }
    }

    fn is_already_in_collection(&self, piece: &str) -> bool {
        //self.collection.iter().position(|&&album_name| album_name == piece) //find(album_name == piece)
        true
    }

    /// The function that runs from the starting point
    fn visit_dirs(&self, dir: &Path, cb: &Fn(&DirEntry) -> io::Result<()> ) -> io::Result<()> {
        if dir.is_dir() {
            for entry in fs::read_dir(dir)? {
                let entry = entry?;
                let path = entry.path();
                if path.is_dir() {
                    self.visit_dirs(&path, cb)?;
                } else {
                    cb(&entry)?;
                }
            }
        }
        Ok(())
    }

    /// the function to check all files separately
    fn visit_files(cb: &DirEntry) -> io::Result<()> {
        let filetype = tree_magic::from_filepath(&cb.path());
        match filetype.as_ref() {
            "text/plain" => {},
            "audio/mpeg" => Collection::visit_audio_files(&cb.path()),
            _ => println!("[{:?}]{:?}",filetype, cb.path()),
        }
    	Ok(())
    }

    fn visit_audio_files(cb: &Path) {
        let tag : Tag = Tag::read_from_path(cb).unwrap();

        println!("{:?}",tag.artist().unwrap())
    }
}

fn main() {
    let args: Vec<_> = env::args().collect();

    let collection : Collection<'static> = Collection::new();

    let mut path : &str = ".";
    if args.len() > 1 {
        path = &args[1];
    }
    let real_path = Path::new(path);
    match collection.visit_dirs(real_path, &Collection::visit_files) {
        _ => println!("Finished!")
    }
}
<commit_msg>Trying container<commit_after>//#![feature(alloc_system)]
//extern crate alloc_system;   // strip down size of binary executable

extern crate id3;
extern crate tree_magic;  // mime types

use std::io;
use std::env;     // args
use std::fs::{self, DirEntry};  // directory
use std::path::Path;  // path, clear
use std::collections::HashMap;

use id3::Tag;

/// generell info
struct InfoAlbum <'b> {
    reference_path : Vec<&'b Path>,
}

struct Collection<'b> {
    collection : HashMap<&'b str, &'b InfoAlbum<'b> >
}

type FileFn<'a,'b: 'a> = &'a Fn(&'a mut Collection, &'b DirEntry) -> io::Result<()>;

impl <'a,'b: 'a> Collection <'a> {

    pub fn new() -> Collection<'a>  {
        Collection {
            collection : HashMap::new()
        }
    }

    fn is_already_in_collection(&self, piece: &str) -> bool {
        self.collection.contains_key(piece)
    }

    /// The function that runs from the starting point
    fn visit_dirs(&mut self, dir: &'b Path, cb: FileFn<'a,'b>) -> io::Result<()> {
        if dir.is_dir() {
            let &mut test : &mut Collection<'a> = self;
            for entry in fs::read_dir(dir)? {
                let entry = entry?;
                let path = entry.path();
                if path.is_dir() {
                    self.visit_dirs(&path, cb)?;
                } else {
                    cb(test, &entry)?;
                }
            }
        }
        Ok(())
    }

    /// the function to check all files separately
    fn visit_files(col: &mut Collection, cb: &'b DirEntry) -> io::Result<()> {
        let filetype = tree_magic::from_filepath(&cb.path());
        match filetype.as_ref() {
            "text/plain" => {},
            "audio/mpeg" => col.visit_audio_files(&cb.path()),
            _ => println!("[{:?}]{:?}",filetype, cb.path()),
        }
    	Ok(())
    }

    fn visit_audio_files(&mut self, cb: &'b Path) {
        let tag : Tag = Tag::read_from_path(cb).unwrap();
        println!("{:?}",tag.artist().unwrap())
    }
}

fn main() {
    let args: Vec<_> = env::args().collect();

    let mut collection : Collection<'static> = Collection::new();

    let mut path : &str = ".";
    if args.len() > 1 {
        path = &args[1];
    }
    let real_path = Path::new(path);
    match collection.visit_dirs(real_path, &Collection::visit_files) {
        _ => println!("Finished!")
    }
}
<|endoftext|>


<commit_before>#![warn(bad_style)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
// #![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]
#![cfg_attr(feature = "nightly", feature(plugin))]
#![cfg_attr(feature = "nightly", plugin(clippy))]
#![cfg_attr(feature = "nightly", warn(mut_mut))]
#![cfg_attr(feature = "nightly", warn(string_add))]
#![cfg_attr(feature = "nightly", warn(string_add_assign))]
#![cfg_attr(feature = "nightly", feature(windows_subsystem))]
#![cfg_attr(feature = "nightly", windows_subsystem = "windows")]

#[macro_use]
extern crate conrod;
#[macro_use]
extern crate conrod_derive;
extern crate rand;
extern crate ttf_noto_sans;
extern crate vecmath;

use conrod::UiBuilder;
use conrod::backend::glium::glium;
use conrod::backend::glium::glium::Surface;
use conrod::image::Map as ImageMap;
use conrod::text::FontCollection;
use view::Ids;
use view_model::App;

mod model;
mod view;
mod view_model;

fn main() {
    const WIDTH: u32 = 1024;
    const HEIGHT: u32 = 768;

    let mut events_loop = glium::glutin::EventsLoop::new();
    let window = glium::glutin::WindowBuilder::new()
        .with_title("Othello")
        .with_dimensions(WIDTH, HEIGHT);
    let context = glium::glutin::ContextBuilder::new()
        .with_vsync(true)
        .with_multisampling(4);
    let display =
        glium::Display::new(window, context, &events_loop).expect("failed to create Display");
    let mut ui = UiBuilder::new([WIDTH as f64, HEIGHT as f64]).build();

    let font_collection = FontCollection::from_bytes(ttf_noto_sans::REGULAR);
    let _ = ui.fonts
        .insert(font_collection.into_font().expect("failed to into_font"));

    let mut renderer =
        conrod::backend::glium::Renderer::new(&display).expect("failed to create Renderer");

    let image_map = ImageMap::<glium::texture::Texture2d>::new();

    let mut app = App::default();
    let mut ids = Ids::new(ui.widget_id_generator());

    let mut event_loop = EventLoop::new();
    'main: loop {
        for event in event_loop.next(&mut events_loop) {
            // Use the `winit` backend feature to convert the winit event to a conrod one.
            if let Some(event) = conrod::backend::winit::convert_event(event.clone(), &display) {
                ui.handle_event(event);
                event_loop.needs_update();
            }

            match event {
                glium::glutin::Event::WindowEvent { event, .. } => match event {
                    // Break from the loop upon `Escape`.
                    glium::glutin::WindowEvent::Closed |
                    glium::glutin::WindowEvent::KeyboardInput {
                        input:
                            glium::glutin::KeyboardInput {
                                virtual_keycode: Some(glium::glutin::VirtualKeyCode::Escape),
                                ..
                            },
                        ..
                    } => break 'main,
                    _ => (),
                },
                _ => (),
            }
        }

        {
            let ui = &mut ui.set_widgets();
            view::set_widgets(ui, &mut ids, &mut app);
        }

        if let Some(primitives) = ui.draw_if_changed() {
            renderer.fill(&display, primitives, &image_map);
            let mut target = display.draw();

            target.clear_color(0.0, 0.0, 0.0, 1.0);
            renderer.draw(&display, &mut target, &image_map).unwrap();
            target.finish().unwrap();
        }
    }
}

/// In most of the examples the `glutin` crate is used for providing the window context and
/// events while the `glium` crate is used for displaying `conrod::render::Primitives` to the
/// screen.
///
/// This `Iterator`-like type simplifies some of the boilerplate involved in setting up a
/// glutin+glium event loop that works efficiently with conrod.
#[derive(Debug, Copy, Clone)]
pub struct EventLoop {
    ui_needs_update: bool,
    last_update: std::time::Instant,
}

impl EventLoop {
    pub fn new() -> Self {
        EventLoop {
            last_update: std::time::Instant::now(),
            ui_needs_update: true,
        }
    }

    /// Produce an iterator yielding all available events.
    pub fn next(
        &mut self,
        events_loop: &mut glium::glutin::EventsLoop,
    ) -> Vec<glium::glutin::Event> {
        // We don't want to loop any faster than 60 FPS, so wait until it has been at least 16ms
        // since the last yield.
        let last_update = self.last_update;
        let sixteen_ms = std::time::Duration::from_millis(16);
        let duration_since_last_update = std::time::Instant::now().duration_since(last_update);
        if duration_since_last_update < sixteen_ms {
            std::thread::sleep(sixteen_ms - duration_since_last_update);
        }

        // Collect all pending events.
        let mut events = Vec::new();
        events_loop.poll_events(|event| events.push(event));

        // If there are no events and the `Ui` does not need updating, wait for the next event.
        if events.is_empty() && !self.ui_needs_update {
            events_loop.run_forever(|event| {
                events.push(event);
                glium::glutin::ControlFlow::Break
            });
        }

        self.ui_needs_update = false;
        self.last_update = std::time::Instant::now();

        events
    }

    /// Notifies the event loop that the `Ui` requires another update whether or not there are any
    /// pending events.
    ///
    /// This is primarily used on the occasion that some part of the `Ui` is still animating and
    /// requires further updates to do so.
    pub fn needs_update(&mut self) {
        self.ui_needs_update = true;
    }
}
<commit_msg>Small refactoring<commit_after>#![warn(bad_style)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
// #![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]
#![cfg_attr(feature = "nightly", feature(plugin))]
#![cfg_attr(feature = "nightly", plugin(clippy))]
#![cfg_attr(feature = "nightly", warn(mut_mut))]
#![cfg_attr(feature = "nightly", warn(string_add))]
#![cfg_attr(feature = "nightly", warn(string_add_assign))]
#![cfg_attr(feature = "nightly", feature(windows_subsystem))]
#![cfg_attr(feature = "nightly", windows_subsystem = "windows")]

#[macro_use]
extern crate conrod;
#[macro_use]
extern crate conrod_derive;
extern crate rand;
extern crate ttf_noto_sans;
extern crate vecmath;

use conrod::UiBuilder;
use conrod::backend::glium::Renderer;
use conrod::backend::glium::glium::{self, Display, Surface};
use conrod::backend::glium::glium::glutin::{ContextBuilder, Event, KeyboardInput, VirtualKeyCode,
                                            WindowBuilder, WindowEvent};
use conrod::backend::glium::glium::texture::Texture2d;
use conrod::image::Map as ImageMap;
use conrod::text::FontCollection;
use std::fmt;
use view::Ids;
use view_model::App;

mod model;
mod view;
mod view_model;

fn main() {
    const WIDTH: u32 = 1024;
    const HEIGHT: u32 = 768;

    let mut event_loop = EventLoop::new();
    let window = WindowBuilder::new()
        .with_title("Othello")
        .with_dimensions(WIDTH, HEIGHT);
    let context = ContextBuilder::new().with_vsync(true).with_multisampling(4);
    let display = Display::new(window, context, &event_loop.raw).expect("failed to create Display");
    let mut ui = UiBuilder::new([WIDTH as f64, HEIGHT as f64]).build();

    let font_collection = FontCollection::from_bytes(ttf_noto_sans::REGULAR);
    let _ = ui.fonts
        .insert(font_collection.into_font().expect("failed to into_font"));

    let mut renderer = Renderer::new(&display).expect("failed to create Renderer");
    let image_map = ImageMap::<Texture2d>::new();

    let mut app = App::default();
    let mut ids = Ids::new(ui.widget_id_generator());
    'main: loop {
        for event in event_loop.next() {
            // Use the `winit` backend feature to convert the winit event to a conrod one.
            if let Some(event) = conrod::backend::winit::convert_event(event.clone(), &display) {
                ui.handle_event(event);
                event_loop.needs_update();
            }

            match event {
                Event::WindowEvent { event, .. } => match event {
                    // Break from the loop upon `Escape`.
                    WindowEvent::Closed
                    | WindowEvent::KeyboardInput {
                        input:
                            KeyboardInput {
                                virtual_keycode: Some(VirtualKeyCode::Escape),
                                ..
                            },
                        ..
                    } => break 'main,
                    _ => (),
                },
                _ => (),
            }
        }

        {
            let ui = &mut ui.set_widgets();
            view::set_widgets(ui, &mut ids, &mut app);
        }

        if let Some(primitives) = ui.draw_if_changed() {
            renderer.fill(&display, primitives, &image_map);
            let mut target = display.draw();

            target.clear_color(0.0, 0.0, 0.0, 1.0);
            renderer.draw(&display, &mut target, &image_map).unwrap();
            target.finish().unwrap();
        }
    }
}

/// In most of the examples the `glutin` crate is used for providing the window context and
/// events while the `glium` crate is used for displaying `conrod::render::Primitives` to the
/// screen.
///
/// This `Iterator`-like type simplifies some of the boilerplate involved in setting up a
/// glutin+glium event loop that works efficiently with conrod.
pub struct EventLoop {
    raw: glium::glutin::EventsLoop,
    ui_needs_update: bool,
    last_update: std::time::Instant,
}

impl fmt::Debug for EventLoop {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "EventLoop {{ raw: ..., ui_needs_update: {:?}, last_update: {:?} }}",
            self.ui_needs_update,
            self.last_update
        )
    }
}

impl EventLoop {
    pub fn new() -> Self {
        EventLoop {
            raw: glium::glutin::EventsLoop::new(),
            last_update: std::time::Instant::now(),
            ui_needs_update: true,
        }
    }

    /// Produce an iterator yielding all available events.
    pub fn next(&mut self) -> Vec<glium::glutin::Event> {
        // We don't want to loop any faster than 60 FPS, so wait until it has been at least 16ms
        // since the last yield.
        let last_update = self.last_update;
        let sixteen_ms = std::time::Duration::from_millis(16);
        let duration_since_last_update = std::time::Instant::now().duration_since(last_update);
        if duration_since_last_update < sixteen_ms {
            std::thread::sleep(sixteen_ms - duration_since_last_update);
        }

        // Collect all pending events.
        let mut events = Vec::new();
        self.raw.poll_events(|event| events.push(event));

        // If there are no events and the `Ui` does not need updating, wait for the next event.
        if events.is_empty() && !self.ui_needs_update {
            self.raw.run_forever(|event| {
                events.push(event);
                glium::glutin::ControlFlow::Break
            });
        }

        self.ui_needs_update = false;
        self.last_update = std::time::Instant::now();

        events
    }

    /// Notifies the event loop that the `Ui` requires another update whether or not there are any
    /// pending events.
    ///
    /// This is primarily used on the occasion that some part of the `Ui` is still animating and
    /// requires further updates to do so.
    pub fn needs_update(&mut self) {
        self.ui_needs_update = true;
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Jonathan Anderson
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
 * http://opensource.org/licenses/MIT>, at your option. This file may not be
 * copied, modified, or distributed except according to those terms.
 */

extern crate docopt;
extern crate rshark;
extern crate rustc_serialize;
extern crate pcap;

use docopt::Docopt;
use rshark::Protocol;

// TODO: use docopt_macros once rust-lang/rust#28089 is resolved
const USAGE: &'static str = "
Usage: rshark [options] <source>
       rshark (--help | --version)

Options:
    -f, --filter         BFP filter (see http://biot.com/capstats/bpf.html)
    -h, --help           Show this message
    -p, --promiscuous    Listen to all packets
    -s, --snaplen=<len>  Bytes to capture from each packet [default: 5000]
    -t, --timeout=<ms>   Packet read timeout, in ms [default: 10]
    -v, --version        Show the version of rshark
";

const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");

#[derive(RustcDecodable)]
struct Args {
    arg_source: String,
    flag_filter: String,
    flag_snaplen: i32,
    flag_timeout: i32,
    flag_promiscuous: bool,
    flag_version: bool,
}

type PcapResult = Result<pcap::Capture<pcap::Activated>, pcap::Error>;

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

    println!["rshark v{}", VERSION.unwrap_or("<unknown>")];

    if args.flag_version {
        return;
    }

    let protocol = rshark::ethernet::Ethernet;

    let result = open_capture(&args)
        .map(|mut c| {
            let mut count = 0;

            while let Ok(packet) = c.next() {
                println!("\n\n{}-B packet:", packet.data.len());

                match protocol.dissect(packet.data) {
                    Ok(dissected) => print!["{}", dissected.pretty_print(1)],
                    Err(e) => println!["Error: {}", e],
                }

                count += 1;
            }

            count
        })
        ;

    match result {
        Ok(packet_count) => println!["Processed {} packets", packet_count],
        Err(e) => {
            println!["{}", e];
            std::process::exit(1);
        },
    }
}

fn open_capture(args: &Args) -> PcapResult {
    let device = try![open_device(args)];

    let capture = match device {
        Some(d) => Ok(d),
        None => open_file(&args.arg_source),
    };

    capture.and_then(|mut c| {
        try![c.filter(&args.flag_filter)];
        Ok(c)
    })
}

fn open_device(args: &Args)
        -> Result<Option<pcap::Capture<pcap::Activated>>, pcap::Error> {

    match pcap::Device::list() {
        Ok(devices) => {
            for d in devices {
                if d.name == args.arg_source {
                    return pcap::Capture::from_device(d)
                        .map(|d| d.promisc(args.flag_promiscuous)
                                  .rfmon(args.flag_promiscuous)
                                  .snaplen(args.flag_snaplen)
                                  .timeout(args.flag_timeout))
                        .and_then(|d| d.open())
                        .map(|c| c.into())
                        .map(Some)
                        ;
                }
            };

            Ok(None)
        },
        Err(e) => Err(e),
    }
}

fn open_file(filename: &str) -> PcapResult {
    std::fs::metadata(filename)
        .map_err(|e| pcap::Error::PcapError(format!["{}", e]))
        .and_then(|f|
            if f.is_file() {
                pcap::Capture::from_file(filename)
                    .map(|c| c.into())
            } else {
                Err(pcap::Error::PcapError(
                        format!["{} is not a file or interface", filename]))
            }
        )
}
<commit_msg>Output the packet source.<commit_after>/*
 * Copyright 2015 Jonathan Anderson
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
 * http://opensource.org/licenses/MIT>, at your option. This file may not be
 * copied, modified, or distributed except according to those terms.
 */

extern crate docopt;
extern crate rshark;
extern crate rustc_serialize;
extern crate pcap;

use docopt::Docopt;
use rshark::Protocol;

// TODO: use docopt_macros once rust-lang/rust#28089 is resolved
const USAGE: &'static str = "
Usage: rshark [options] <source>
       rshark (--help | --version)

Options:
    -f, --filter         BFP filter (see http://biot.com/capstats/bpf.html)
    -h, --help           Show this message
    -p, --promiscuous    Listen to all packets
    -s, --snaplen=<len>  Bytes to capture from each packet [default: 5000]
    -t, --timeout=<ms>   Packet read timeout, in ms [default: 10]
    -v, --version        Show the version of rshark
";

const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");

#[derive(RustcDecodable)]
struct Args {
    arg_source: String,
    flag_filter: String,
    flag_snaplen: i32,
    flag_timeout: i32,
    flag_promiscuous: bool,
    flag_version: bool,
}

type PcapResult = Result<pcap::Capture<pcap::Activated>, pcap::Error>;

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

    println!["rshark v{}", VERSION.unwrap_or("<unknown>")];

    if args.flag_version {
        return;
    }

    let protocol = rshark::ethernet::Ethernet;

    let result = open_capture(&args)
        .map(|mut c| {
            let mut count = 0;

            while let Ok(packet) = c.next() {
                println!("\n\n{}-B packet:", packet.data.len());

                match protocol.dissect(packet.data) {
                    Ok(dissected) => print!["{}", dissected.pretty_print(1)],
                    Err(e) => println!["Error: {}", e],
                }

                count += 1;
            }

            count
        })
        ;

    match result {
        Ok(packet_count) => println!["Processed {} packets", packet_count],
        Err(e) => {
            println!["{}", e];
            std::process::exit(1);
        },
    }
}

fn open_capture(args: &Args) -> PcapResult {
    let device = try![open_device(args)];

    let capture = match device {
        Some(d) => Ok(d),
        None => open_file(&args.arg_source),
    };

    capture.and_then(|mut c| {
        try![c.filter(&args.flag_filter)];
        println!["Opened packet source: {}", args.arg_source];
        Ok(c)
    })
}

fn open_device(args: &Args)
        -> Result<Option<pcap::Capture<pcap::Activated>>, pcap::Error> {

    match pcap::Device::list() {
        Ok(devices) => {
            for d in devices {
                if d.name == args.arg_source {
                    return pcap::Capture::from_device(d)
                        .map(|d| d.promisc(args.flag_promiscuous)
                                  .rfmon(args.flag_promiscuous)
                                  .snaplen(args.flag_snaplen)
                                  .timeout(args.flag_timeout))
                        .and_then(|d| d.open())
                        .map(|c| c.into())
                        .map(Some)
                        ;
                }
            };

            Ok(None)
        },
        Err(e) => Err(e),
    }
}

fn open_file(filename: &str) -> PcapResult {
    std::fs::metadata(filename)
        .map_err(|e| pcap::Error::PcapError(format!["{}", e]))
        .and_then(|f|
            if f.is_file() {
                pcap::Capture::from_file(filename)
                    .map(|c| c.into())
            } else {
                Err(pcap::Error::PcapError(
                        format!["{} is not a file or interface", filename]))
            }
        )
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::env;
use std::fs::File;
use std::io::{self, Read};
use handlebars::{Handlebars, to_json};

extern crate handlebars;

struct Col {
    pub buffers: Vec<String>
}
impl Col {
    fn new() -> Col {
        Col { buffers: Vec::new() }
    }
    fn add_buf(&mut self) {
        self.buffers.push(String::new());
    }
    fn append(&mut self, chr: char) {
        let mut len = self.buffers.len();

        if len == 0 {
            self.add_buf();
            len = 1;
        }

        let ref mut buffer = self.buffers[len-1];
        buffer.push(chr);
    }
    fn append_str(&mut self, str: &str) {
        for chr in str.chars() {
            self.append(chr);
        }
    }
    fn out(&self, template: &Template) -> String {
        let mut out: String = String::new();

        out.push_str(template.col_start.as_str());
        for ref buf in self.buffers.iter() {
            out.push_str(format!("{}{}{}",
                    template.segment_start.as_str(),
                    buf,
                    template.segment_end.as_str()
                ).as_str());
        }
        out.push_str(template.col_end.as_str());

        out
    }
}

struct Row {
    pub cols: Vec<Col>
}
impl Row {
    fn add_col(&mut self, col: Col) {
        self.cols.push(col);
    }
    fn get_col(&mut self, index: u8) -> &mut Col {
        self.cols.get_mut(index as usize).unwrap()
    }
    fn col_count(&self) -> usize {
        self.cols.len()
    }
    fn new() -> Row {
        let mut row: Row = Row { cols: Vec::new() };
        row.add_col(Col::new());
        row
    }
    fn out(&self, template: &Template) -> String {
        let mut out: String = String::new();

        out.push_str(template.row_start.as_str());
        for ref col in self.cols.iter() {
            let formatted = format!("{}", col.out(template));
            out.push_str(formatted.as_str());
        }
        out.push_str(template.row_end.as_str());

        out
    }
}

struct Template {
    container_start: String,
    container_end: String,
    row_start: String,
    row_end: String,
    col_start: String,
    col_end: String,
    segment_start: String,
    segment_end: String,
    label: String,
    text: String,
    checkbox: String,
    radio: String,
    textarea: String,
    hr: String,
    button: String,
    select: String
}

#[derive(PartialEq)]
enum InputType {
    Text,
    Radio,
    Checkbox,
    Textarea
}

#[derive(PartialEq)]
enum Type {
    Unknown,
    Input(InputType),
    Button,
    Label,
    Hr,
    Select
}

struct Working {
    str: String,
    until: char,
    work_type: Type
}
impl Working {
    fn new(until: char, work_type: Type) -> Working {
        Working {
            str: String::new(),
            until: until,
            work_type: work_type
        }
    }
    fn is_working(&self) -> bool {
        self.until != '\0'
    }
    fn append(&mut self, chr: char) {
        self.str.push(chr);
    }
    fn compile(&mut self, template: &Template) -> String {
        // Convert type to template
        let ref template = match self.work_type {
            Type::Button => template.button.as_str(),
            Type::Label => template.label.as_str(),
            Type::Hr => template.hr.as_str(),
            Type::Select => template.select.as_str(),
            Type::Input(ref t) => match t {
                &InputType::Text => template.text.as_str(),
                &InputType::Radio => template.radio.as_str(),
                &InputType::Checkbox => template.checkbox.as_str(),
                &InputType::Textarea => template.textarea.as_str()
            },
            _ => ""
        };

        // No actual template available
        if template.is_empty() {
            return String::new();
        }

        // Compile template
        let mut handlebars = Handlebars::new();
        assert!(handlebars.register_template_string("tmpl", template)
            .is_ok());

        // Bind data to template
        let mut data = BTreeMap::new();
        let val = match self.work_type {
            Type::Select => {
                let options: Vec<&str> = self.str.split(",").collect();
                to_json(&options)
            },
            _ => to_json(&self.str)
        };
        data.insert("value".to_string(), val);
        handlebars.render("tmpl", &data).unwrap()
    }
}

/**
 * An empty line implies a new "row"
 * A line starting with a | implies a columnar form section
 * [value] is an input text field
 * {value} is an input textarea field
 * @ is a radio
 * * is a checkbox
 * --- is an hr
 *
 */
fn main() {
    // Read in standard input
    let mut buffer = String::new();
    io::stdin().read_to_string(&mut buffer)
        .expect("Error reading from stdin");

    // Split input by line
    let v: Vec<&str> = buffer.split("\n").collect();

    // Keep track of rows in output
    let mut rows: Vec<Row> = Vec::new();
    let mut row: Row = Row::new();

    // Check arg for template
    let template = match env::args().nth(1) {
        Some(file) => {
            let dir = env::current_dir().unwrap();
            let template_file = format!("{}/{}", dir.display(), file);

            let mut in_file = match File::open(&template_file) {
                Err(_) => panic!("Unable to open template file"),
                Ok(file) => file,
            };

            let mut content = String::new();
            in_file.read_to_string(&mut content)
                .expect("Unable to process template file");

            let sp: Vec<&str> = content.split("\n").collect();

            Template {
                container_start: sp[0].to_string().trim().to_string(),
                row_start: sp[1].to_string().trim().to_string(),
                col_start: sp[2].to_string().trim().to_string(),
                segment_start: sp[3].to_string().trim().to_string(),
                segment_end: sp[4].to_string().trim().to_string(),
                col_end: sp[5].to_string().trim().to_string(),
                row_end: sp[6].to_string().trim().to_string(),
                container_end: sp[7].to_string().trim().to_string(),
                label: sp[8].to_string().trim().to_string(),
                text: sp[9].to_string().trim().to_string(),
                checkbox: sp[10].to_string().trim().to_string(),
                radio: sp[11].to_string().trim().to_string(),
                textarea: sp[12].to_string().trim().to_string(),
                button: sp[13].to_string().trim().to_string(),
                select: sp[14].to_string().trim().to_string(),
                hr: sp[15].to_string().trim().to_string()
            }

        },
        _ => Template {
            container_start: "".to_string(),
            container_end: "".to_string(),
            row_start: "
".to_string(),
            row_end: "
".to_string(),
            col_start: "".to_string(),
            col_end: "".to_string(),
            segment_start: "".to_string(),
            segment_end: "
".to_string(),
            label: "{[value}}".to_string(),
            text: "<input type=\"text\" value=\"{{value}}\"/>".to_string(),
            checkbox: "<input type=\"checkbox\"/>".to_string(),
            radio: "<input type=\"radio\"/>".to_string(),
            textarea: "<textarea>{{value}}</textarea>".to_string(),
            hr: "
".to_string(),
            button: "<button>{{value}}</button>".to_string(),
            select: "<select>{{#each value}}<option>{{this}}</option>{{/each}}</select>".to_string()
        }
    };

    // Iterate over lines in input
    for line in &v {
        // New row by way of empty line
        if line.chars().count() == 0 {
            rows.push(row);
            row = Row::new();
            continue;
        }

        let mut form_mode = false; // If user toggled form mode
        let mut col_index: u8 = 1; // Keeping tracking of column index
        let mut dashes: u8 = 0; // Keep track of dash count
        let mut working = Working::new('\0', Type::Unknown);

        // Iterate over characters in string
        for (i, c) in line.chars().enumerate() {
            // Match c against known tokens
            match c {
                '-' => {
                    dashes += 1;
                    if dashes == 3 {
                        row.get_col(col_index-1).append_str(
                            Working::new('\0', Type::Hr)
                                .compile(&template).as_str()
                            );
                        break;
                    }
                },

                // Controlling form modes
                '|' => {
                    if i == 0 {
                        form_mode = true;
                        row.get_col(col_index-1).add_buf()
                    } else if form_mode {
                        // Check if we have enough columns in row
                        // if not add a new column
                        if (row.col_count() as u8) < col_index + 1 {
                            row.add_col(Col::new());
                        }

                        // Increment index
                        col_index += 1;

                        row.get_col(col_index-1).add_buf();
                    } else {
                        row.get_col(col_index-1).append(c);
                    }
                },

                // Handle items that have a counterpart
                c if c == '[' && form_mode
                    => working = Working::new(']', Type::Unknown),
                c if c == '{' && form_mode
                    => working = Working::new('}', Type::Label),
                c if c == '(' && form_mode
                    => working = Working::new(')', Type::Button),
                c if c == '<' && form_mode
                    => working = Working::new('>', Type::Select),

                // Handle input type and we are waiting for mode qualifier
                c if c != working.until
                    && working.until != '\0'
                    && working.work_type == Type::Unknown =>
                        match c {
                            'o' => working.work_type = Type::Input(
                                InputType::Radio),
                            '/' => working.work_type = Type::Input(
                                InputType::Checkbox),
                            '+' => working.work_type = Type::Input(
                                InputType::Textarea),
                            c => {
                                working.work_type = Type::Input(
                                    InputType::Text);
                                working.append(c);
                            },
                        },

                // Handle the case we are working towards the end goal of an
                // incoming char
                c if c == working.until => {
                    row.get_col(col_index-1)
                        .append_str(working.compile(&template).as_str());
                    working = Working::new('\0', Type::Unknown);
                },

                // In any other scenario we are building strings
                _ => {
                    if working.is_working() {
                        working.append(c);
                    } else {
                        row.get_col(col_index-1).append(c)
                    }
                }
            }
        }
    }

    println!("{}", template.container_start);
    for row in rows {
        println!("{}", row.out(&template));
    }
    println!("{}", template.container_end);
}
<commit_msg>Moving template to absolute path<commit_after>use std::collections::BTreeMap;
use std::env;
use std::fs::File;
use std::io::{self, Read};
use handlebars::{Handlebars, to_json};

extern crate handlebars;

struct Col {
    pub buffers: Vec<String>
}
impl Col {
    fn new() -> Col {
        Col { buffers: Vec::new() }
    }
    fn add_buf(&mut self) {
        self.buffers.push(String::new());
    }
    fn append(&mut self, chr: char) {
        let mut len = self.buffers.len();

        if len == 0 {
            self.add_buf();
            len = 1;
        }

        let ref mut buffer = self.buffers[len-1];
        buffer.push(chr);
    }
    fn append_str(&mut self, str: &str) {
        for chr in str.chars() {
            self.append(chr);
        }
    }
    fn out(&self, template: &Template) -> String {
        let mut out: String = String::new();

        out.push_str(template.col_start.as_str());
        for ref buf in self.buffers.iter() {
            out.push_str(format!("{}{}{}",
                    template.segment_start.as_str(),
                    buf,
                    template.segment_end.as_str()
                ).as_str());
        }
        out.push_str(template.col_end.as_str());

        out
    }
}

struct Row {
    pub cols: Vec<Col>
}
impl Row {
    fn add_col(&mut self, col: Col) {
        self.cols.push(col);
    }
    fn get_col(&mut self, index: u8) -> &mut Col {
        self.cols.get_mut(index as usize).unwrap()
    }
    fn col_count(&self) -> usize {
        self.cols.len()
    }
    fn new() -> Row {
        let mut row: Row = Row { cols: Vec::new() };
        row.add_col(Col::new());
        row
    }
    fn out(&self, template: &Template) -> String {
        let mut out: String = String::new();

        out.push_str(template.row_start.as_str());
        for ref col in self.cols.iter() {
            let formatted = format!("{}", col.out(template));
            out.push_str(formatted.as_str());
        }
        out.push_str(template.row_end.as_str());

        out
    }
}

struct Template {
    container_start: String,
    container_end: String,
    row_start: String,
    row_end: String,
    col_start: String,
    col_end: String,
    segment_start: String,
    segment_end: String,
    label: String,
    text: String,
    checkbox: String,
    radio: String,
    textarea: String,
    hr: String,
    button: String,
    select: String
}

#[derive(PartialEq)]
enum InputType {
    Text,
    Radio,
    Checkbox,
    Textarea
}

#[derive(PartialEq)]
enum Type {
    Unknown,
    Input(InputType),
    Button,
    Label,
    Hr,
    Select
}

struct Working {
    str: String,
    until: char,
    work_type: Type
}
impl Working {
    fn new(until: char, work_type: Type) -> Working {
        Working {
            str: String::new(),
            until: until,
            work_type: work_type
        }
    }
    fn is_working(&self) -> bool {
        self.until != '\0'
    }
    fn append(&mut self, chr: char) {
        self.str.push(chr);
    }
    fn compile(&mut self, template: &Template) -> String {
        // Convert type to template
        let ref template = match self.work_type {
            Type::Button => template.button.as_str(),
            Type::Label => template.label.as_str(),
            Type::Hr => template.hr.as_str(),
            Type::Select => template.select.as_str(),
            Type::Input(ref t) => match t {
                &InputType::Text => template.text.as_str(),
                &InputType::Radio => template.radio.as_str(),
                &InputType::Checkbox => template.checkbox.as_str(),
                &InputType::Textarea => template.textarea.as_str()
            },
            _ => ""
        };

        // No actual template available
        if template.is_empty() {
            return String::new();
        }

        // Compile template
        let mut handlebars = Handlebars::new();
        assert!(handlebars.register_template_string("tmpl", template)
            .is_ok());

        // Bind data to template
        let mut data = BTreeMap::new();
        let val = match self.work_type {
            Type::Select => {
                let options: Vec<&str> = self.str.split(",").collect();
                to_json(&options)
            },
            _ => to_json(&self.str)
        };
        data.insert("value".to_string(), val);
        handlebars.render("tmpl", &data).unwrap()
    }
}

/**
 * An empty line implies a new "row"
 * A line starting with a | implies a columnar form section
 * [value] is an input text field
 * {value} is an input textarea field
 * @ is a radio
 * * is a checkbox
 * --- is an hr
 *
 */
fn main() {
    // Read in standard input
    let mut buffer = String::new();
    io::stdin().read_to_string(&mut buffer)
        .expect("Error reading from stdin");

    // Split input by line
    let v: Vec<&str> = buffer.split("\n").collect();

    // Keep track of rows in output
    let mut rows: Vec<Row> = Vec::new();
    let mut row: Row = Row::new();

    // Check arg for template
    let template = match env::args().nth(1) {
        Some(file) => {
            let mut in_file = match File::open(&file) {
                Err(_) => panic!("Unable to open template file"),
                Ok(file) => file,
            };

            let mut content = String::new();
            in_file.read_to_string(&mut content)
                .expect("Unable to process template file");

            let sp: Vec<&str> = content.split("\n").collect();

            Template {
                container_start: sp[0].to_string().trim().to_string(),
                row_start: sp[1].to_string().trim().to_string(),
                col_start: sp[2].to_string().trim().to_string(),
                segment_start: sp[3].to_string().trim().to_string(),
                segment_end: sp[4].to_string().trim().to_string(),
                col_end: sp[5].to_string().trim().to_string(),
                row_end: sp[6].to_string().trim().to_string(),
                container_end: sp[7].to_string().trim().to_string(),
                label: sp[8].to_string().trim().to_string(),
                text: sp[9].to_string().trim().to_string(),
                checkbox: sp[10].to_string().trim().to_string(),
                radio: sp[11].to_string().trim().to_string(),
                textarea: sp[12].to_string().trim().to_string(),
                button: sp[13].to_string().trim().to_string(),
                select: sp[14].to_string().trim().to_string(),
                hr: sp[15].to_string().trim().to_string()
            }

        },
        _ => Template {
            container_start: "".to_string(),
            container_end: "".to_string(),
            row_start: "
".to_string(),
            row_end: "
".to_string(),
            col_start: "".to_string(),
            col_end: "".to_string(),
            segment_start: "".to_string(),
            segment_end: "
".to_string(),
            label: "{[value}}".to_string(),
            text: "<input type=\"text\" value=\"{{value}}\"/>".to_string(),
            checkbox: "<input type=\"checkbox\"/>".to_string(),
            radio: "<input type=\"radio\"/>".to_string(),
            textarea: "<textarea>{{value}}</textarea>".to_string(),
            hr: "
".to_string(),
            button: "<button>{{value}}</button>".to_string(),
            select: "<select>{{#each value}}<option>{{this}}</option>{{/each}}</select>".to_string()
        }
    };

    // Iterate over lines in input
    for line in &v {
        // New row by way of empty line
        if line.chars().count() == 0 {
            rows.push(row);
            row = Row::new();
            continue;
        }

        let mut form_mode = false; // If user toggled form mode
        let mut col_index: u8 = 1; // Keeping tracking of column index
        let mut dashes: u8 = 0; // Keep track of dash count
        let mut working = Working::new('\0', Type::Unknown);

        // Iterate over characters in string
        for (i, c) in line.chars().enumerate() {
            // Match c against known tokens
            match c {
                '-' => {
                    dashes += 1;
                    if dashes == 3 {
                        row.get_col(col_index-1).append_str(
                            Working::new('\0', Type::Hr)
                                .compile(&template).as_str()
                            );
                        break;
                    }
                },

                // Controlling form modes
                '|' => {
                    if i == 0 {
                        form_mode = true;
                        row.get_col(col_index-1).add_buf()
                    } else if form_mode {
                        // Check if we have enough columns in row
                        // if not add a new column
                        if (row.col_count() as u8) < col_index + 1 {
                            row.add_col(Col::new());
                        }

                        // Increment index
                        col_index += 1;

                        row.get_col(col_index-1).add_buf();
                    } else {
                        row.get_col(col_index-1).append(c);
                    }
                },

                // Handle items that have a counterpart
                c if c == '[' && form_mode
                    => working = Working::new(']', Type::Unknown),
                c if c == '{' && form_mode
                    => working = Working::new('}', Type::Label),
                c if c == '(' && form_mode
                    => working = Working::new(')', Type::Button),
                c if c == '<' && form_mode
                    => working = Working::new('>', Type::Select),

                // Handle input type and we are waiting for mode qualifier
                c if c != working.until
                    && working.until != '\0'
                    && working.work_type == Type::Unknown =>
                        match c {
                            'o' => working.work_type = Type::Input(
                                InputType::Radio),
                            '/' => working.work_type = Type::Input(
                                InputType::Checkbox),
                            '+' => working.work_type = Type::Input(
                                InputType::Textarea),
                            c => {
                                working.work_type = Type::Input(
                                    InputType::Text);
                                working.append(c);
                            },
                        },

                // Handle the case we are working towards the end goal of an
                // incoming char
                c if c == working.until => {
                    row.get_col(col_index-1)
                        .append_str(working.compile(&template).as_str());
                    working = Working::new('\0', Type::Unknown);
                },

                // In any other scenario we are building strings
                _ => {
                    if working.is_working() {
                        working.append(c);
                    } else {
                        row.get_col(col_index-1).append(c)
                    }
                }
            }
        }
    }

    println!("{}", template.container_start);
    for row in rows {
        println!("{}", row.out(&template));
    }
    println!("{}", template.container_end);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;

use chrono::offset::local::Local;
use docopt::Docopt;
use env_logger;
use failure::Error;
use human_panic;
use wsf;

static USAGE: &'static str = "
Washing State Ferry Schedules

Usage:
  wsf [options] <from> <to>
  wsf (-h | --help)

  <from> and <to> are a prefix of the departing terminal and arriving
  terminal, respectively. For example 'wsf sea ba' is equivalent to
  'wsf Seattle \"Bainbridge Island\"'.

Options:
  -a --all      Show all times for today, not just remaining
  -h --help     Show this screen.
";

#[derive(Debug, Deserialize)]
struct Args {
    arg_from: String,
    arg_to: String,
    flag_all: bool,
}

fn run() -> Result<(), Error> {
    let env = env_logger::Env::default().filter_or("WSF_LOG", "info");

    env_logger::init_from_env(env);

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.deserialize())
        .unwrap_or_else(|e| e.exit());

    let from_in: &str = &args.arg_from.to_ascii_lowercase();
    let to_in: &str = &args.arg_to.to_ascii_lowercase();

    let mut s = wsf::Session::new("afddf683-37c5-4d1a-8486-f7004a16d86d");

    let from = s.find_terminal(&from_in)?.TerminalID;
    let to = s.find_terminal(&to_in)?.TerminalID;

    let tc = s.schedule(from, to)?;

    let now = Local::now();
    for time in tc.Times.iter() {
        if args.flag_all || time.depart_time() > now {
            println!(
                "{}\t{}\t{}\t{}",
                time.depart_time().time(),
                tc.DepartingTerminalName,
                tc.ArrivingTerminalName,
                time.VesselName
            );
        };
    }
    s.save_cache()?;
    Ok(())
}

fn main() {
    human_panic::setup_panic!();

    match run() {
        Ok(_) => {}
        Err(e) => {
            eprintln!("{}", e);
            std::process::exit(1);
        }
    }
}
<commit_msg>put logging setup in main<commit_after>#[macro_use]
extern crate serde_derive;

use chrono::offset::local::Local;
use docopt::Docopt;
use env_logger;
use failure::Error;
use human_panic;
use wsf;

static USAGE: &'static str = "
Washing State Ferry Schedules

Usage:
  wsf [options] <from> <to>
  wsf (-h | --help)

  <from> and <to> are a prefix of the departing terminal and arriving
  terminal, respectively. For example 'wsf sea ba' is equivalent to
  'wsf Seattle \"Bainbridge Island\"'.

Options:
  -a --all      Show all times for today, not just remaining
  -h --help     Show this screen.
";

#[derive(Debug, Deserialize)]
struct Args {
    arg_from: String,
    arg_to: String,
    flag_all: bool,
}

fn run() -> Result<(), Error> {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.deserialize())
        .unwrap_or_else(|e| e.exit());

    let from_in: &str = &args.arg_from.to_ascii_lowercase();
    let to_in: &str = &args.arg_to.to_ascii_lowercase();

    let mut s = wsf::Session::new("afddf683-37c5-4d1a-8486-f7004a16d86d");

    let from = s.find_terminal(&from_in)?.TerminalID;
    let to = s.find_terminal(&to_in)?.TerminalID;

    let tc = s.schedule(from, to)?;

    let now = Local::now();
    for time in tc.Times.iter() {
        if args.flag_all || time.depart_time() > now {
            println!(
                "{}\t{}\t{}\t{}",
                time.depart_time().time(),
                tc.DepartingTerminalName,
                tc.ArrivingTerminalName,
                time.VesselName
            );
        };
    }
    s.save_cache()?;
    Ok(())
}

fn main() {
    human_panic::setup_panic!();

    let env = env_logger::Env::default().filter_or("WSF_LOG", "info");
    env_logger::init_from_env(env);

    match run() {
        Ok(_) => {}
        Err(e) => {
            eprintln!("{}", e);
            std::process::exit(1);
        }
    }
}
<|endoftext|>


<commit_before>extern crate fuse;
extern crate libc;
extern crate time;
extern crate hyper;
extern crate rustc_serialize;
extern crate clap;

use std::collections::BTreeMap;
use std::path::Path;
use std::env;
use std::io::prelude::Read;
use libc::{ENOENT, ENOSYS};
use time::Timespec;
use fuse::{FileAttr, FileType, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory, ReplyOpen};
use hyper::client::{Client, Response};
use rustc_serialize::json::Json;
use clap::{App, Arg};

struct TwitchFileSystem {
    attrs: BTreeMap<u64, FileAttr>,
    inodes: BTreeMap<String, u64>
}

impl TwitchFileSystem {
    fn new() -> TwitchFileSystem {
        let mut attrs = BTreeMap::new();
        let mut inodes = BTreeMap::new();
        let ts = time::now().to_timespec();
        let attr = FileAttr {
            ino: 1,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: 0o755,
            nlink: 0,
            uid: 0,
            gid: 0,
            rdev: 0,
            flags: 0
        };
        attrs.insert(1, attr);
        inodes.insert("/".to_owned(), 1);
        let mut body = String::new();
        Client::new()
            .get("https://api.twitch.tv/kraken/streams/featured")
            .send()
            .expect("Couldn't load twitch")
            .read_to_string(&mut body);

        match Json::from_str(&body) {
            Ok(data) => {
                let streams = data.find("featured").unwrap().as_array().unwrap();
                for (i, stream) in streams.iter().enumerate() {
                    let attr = FileAttr {
                        ino: i as u64 + 2,
                        size: 0,
                        blocks: 0,
                        atime: ts,
                        mtime: ts,
                        ctime: ts,
                        crtime: ts,
                        kind: FileType::RegularFile,
                        perm: 0o644,
                        nlink: 0,
                        uid: 0,
                        gid: 0,
                        rdev: 0,
                        flags: 0
                    };

                    let game = stream
                        .find_path(&["stream", "game"])
                        .unwrap()
                        .as_string()
                        .unwrap();

                    let name = stream
                        .find_path(&["stream", "channel", "display_name"])
                        .unwrap()
                        .as_string()
                        .unwrap();

                    attrs.insert(attr.ino, attr);
                    inodes.insert(format!("{} - {}", name, game), attr.ino);
                }
            },
            Err(_) => println!("Twitch returned invalid json")
        }
        TwitchFileSystem {attrs: attrs, inodes: inodes}
    }
}

impl Filesystem for TwitchFileSystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        match self.attrs.get(&ino) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.attr(&ttl, attr);
            },
            None => reply.error(ENOENT)
        }
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        let inode = match self.inodes.get(name.to_str().unwrap()) {
            Some(inode) => inode,
            None => {
                reply.error(ENOENT);
                return;
            }
        };
        match self.attrs.get(inode) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.entry(&ttl, attr, 0);
            },
            None => reply.error(ENOENT),
        };
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        if offset == 0 {
            if ino == 1 {
                for (stream, &inode) in &self.inodes {
                    if inode == 1 { continue; }
                    let offset = inode;
                    reply.add(inode, offset, FileType::RegularFile, &Path::new(stream));
                }
                reply.add(1, 0, FileType::Directory, &Path::new("."));
                reply.add(1, 1, FileType::Directory, &Path::new(".."));
            }
        }

        reply.ok();
    }
    fn read(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, size: u32, reply: ReplyData) {
        reply.data("test".as_bytes());
    }
}

fn is_valid_dir(mountpoint: String) -> Result<(), String> {
    match Path::new(&mountpoint).is_dir() {
        true => Ok(()),
        false => Err("Mountpoint must be a directory".to_string()),
    }
}

fn main() {
    let matches = App::new("twitch-fs")
        .version(option_env!("CARGO_PKG_VERSION").unwrap_or("unknown version"))
        .arg(Arg::with_name("mountpoint")
             .validator(is_valid_dir)
             .index(1)
             .required(true))
        .get_matches();

    // unwrap() is safe here because the argument is set as required
    let mountpoint = matches.value_of_os("mountpoint").unwrap();
    let fs = TwitchFileSystem::new();

    fuse::mount(fs , &mountpoint, &[])
}
<commit_msg>Add reading urls from files<commit_after>extern crate fuse;
extern crate libc;
extern crate time;
extern crate hyper;
extern crate rustc_serialize;
extern crate clap;

use std::collections::BTreeMap;
use std::path::Path;
use std::env;
use std::io::prelude::Read;
use libc::{ENOENT, ENOSYS};
use time::Timespec;
use fuse::{FileAttr, FileType, Filesystem, Request, ReplyAttr, ReplyData, ReplyEntry, ReplyDirectory, ReplyOpen};
use hyper::client::{Client, Response};
use rustc_serialize::json::Json;
use clap::{App, Arg};

struct TwitchFileSystem {
    attrs: BTreeMap<u64, FileAttr>,
    inodes: BTreeMap<String, u64>,
    urls: BTreeMap<u64, String>
}

impl TwitchFileSystem {
    fn new() -> TwitchFileSystem {
        let mut attrs = BTreeMap::new();
        let mut inodes = BTreeMap::new();
        let mut urls = BTreeMap::new();

        let ts = time::now().to_timespec();
        let attr = FileAttr {
            ino: 1,
            size: 0,
            blocks: 0,
            atime: ts,
            mtime: ts,
            ctime: ts,
            crtime: ts,
            kind: FileType::Directory,
            perm: 0o755,
            nlink: 0,
            uid: 0,
            gid: 0,
            rdev: 0,
            flags: 0
        };
        attrs.insert(1, attr);
        inodes.insert("/".to_owned(), 1);
        let mut body = String::new();
        Client::new()
            .get("https://api.twitch.tv/kraken/streams/featured")
            .send()
            .expect("Couldn't load twitch")
            .read_to_string(&mut body);

        match Json::from_str(&body) {
            Ok(data) => {
                let streams = data.find("featured").unwrap().as_array().unwrap();
                for (i, stream) in streams.iter().enumerate() {
                    let game = stream
                        .find_path(&["stream", "game"])
                        .unwrap()
                        .as_string()
                        .unwrap();

                    let name = stream
                        .find_path(&["stream", "channel", "display_name"])
                        .unwrap()
                        .as_string()
                        .unwrap();

                    let url = stream
                        .find_path(&["stream", "channel", "url"])
                        .unwrap()
                        .as_string()
                        .unwrap()
                        .to_owned();

                    let attr = FileAttr {
                        ino: i as u64 + 2,
                        size: url.len() as u64,
                        blocks: 1,
                        atime: ts,
                        mtime: ts,
                        ctime: ts,
                        crtime: ts,
                        kind: FileType::RegularFile,
                        perm: 0o644,
                        nlink: 0,
                        uid: 0,
                        gid: 0,
                        rdev: 0,
                        flags: 0
                    };

                    attrs.insert(attr.ino, attr);
                    inodes.insert(format!("{} - {}", name, game), attr.ino);
                    urls.insert(attr.ino, url);
                }
            },
            Err(_) => println!("Twitch returned invalid json")
        }
        TwitchFileSystem {attrs: attrs, inodes: inodes, urls: urls}
    }
}

impl Filesystem for TwitchFileSystem {
    fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
        match self.attrs.get(&ino) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.attr(&ttl, attr);
            },
            None => reply.error(ENOENT)
        }
    }

    fn lookup(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        let inode = match self.inodes.get(name.to_str().unwrap()) {
            Some(inode) => inode,
            None => {
                reply.error(ENOENT);
                return;
            }
        };
        match self.attrs.get(inode) {
            Some(attr) => {
                let ttl = Timespec::new(1, 0);
                reply.entry(&ttl, attr, 0);
            },
            None => reply.error(ENOENT),
        };
    }

    fn readdir(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, mut reply: ReplyDirectory) {
        if offset == 0 {
            if ino == 1 {
                for (stream, &inode) in &self.inodes {
                    if inode == 1 { continue; }
                    let offset = inode;
                    reply.add(inode, offset, FileType::RegularFile, &Path::new(stream));
                }
                reply.add(1, 0, FileType::Directory, &Path::new("."));
                reply.add(1, 1, FileType::Directory, &Path::new(".."));
            }
        }

        reply.ok();
    }
    fn read(&mut self, _req: &Request, ino: u64, fh: u64, offset: u64, size: u32, reply: ReplyData) {
        if self.urls.contains_key(&ino) {
            reply.data(self.urls.get(&ino).unwrap().as_bytes());
            return;
        }
        reply.error(ENOSYS);
    }
}

fn is_valid_dir(mountpoint: String) -> Result<(), String> {
    match Path::new(&mountpoint).is_dir() {
        true => Ok(()),
        false => Err("Mountpoint must be a directory".to_string()),
    }
}

fn main() {
    let matches = App::new("twitch-fs")
        .version(option_env!("CARGO_PKG_VERSION").unwrap_or("unknown version"))
        .arg(Arg::with_name("mountpoint")
             .validator(is_valid_dir)
             .index(1)
             .required(true))
        .get_matches();

    // unwrap() is safe here because the argument is set as required
    let mountpoint = matches.value_of_os("mountpoint").unwrap();
    let fs = TwitchFileSystem::new();

    fuse::mount(fs , &mountpoint, &[])
}
<|endoftext|>


<commit_before>//! A simple program that recursively changes the mode of all directories or
//! files to the given mode under the given directory. The following child
//! process will be executed and waited on, and it's exit code returned
//! `sh -c "find PATH -type TYPE -exec chmod MODE {} \;"`.
use std::env;
use std::fmt::Write as FmtWrite;
use std::io;
use std::io::Write as IoWrite;
use std::path::Path;
use std::process;
use std::process::Command;

// Successful execution
const ESUCCESS: i32 = 0x00;
// No exit code found
const ENOEXIT: i32 = 0x01;
// Invalid usage
const EUSAGE: i32 = 0x02;

// Shell arguments (compatibility wrapper)
const SHELL_ARGS: &[&str] = &[
    "sh", "-c"
];
// Chmod arguments (recursive typed chmod)
const CHMOD_ARGS: &[&str] = &[
    "find", "-type", "-exec", "chmod", "{}", "\\;"
];

// The program name
const NAME: &str = "chmodrt";
// The program usage
const USAGE: &str = "Usage: chmodrt TYPE MODE PATH";
// The program options
const TYPES: &[&[&str]] = &[
    &["-d", "Change the mode of directories"],
    &["-f", "Change the mode of files"],
];

// Prepends the program name to the given message
macro_rules! format_sys {
    ($fmt:expr) => (format!(concat!("{}: ", $fmt), NAME));
    ($fmt:expr, $($arg:tt)*) => (format!(concat!("{}: ", $fmt), NAME, $($arg)*));
}

// Writes a formatted system message to the standard error
macro_rules! sys {
    ($fmt:expr) => (write!(&mut ::std::io::stderr(), "{}", format_sys!($fmt)));
    ($fmt:expr, $($arg:tt)*) => (write!(&mut ::std::io::stderr(), "{}", format_sys!($fmt, $($arg)*)));
}

// Writes a formatted system message to the standard error with a new line
macro_rules! sysln {
    ($fmt:expr) => (sys!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (sys!(concat!($fmt, "\n"), $($arg)*));
}

fn main() {
    process::exit(chmodrt(env::args().collect()));
}

fn chmodrt(args: Vec<String>) -> i32 {

    // Enforce correct usage
    if args.len() != 4 {
        print!("{}\n\n{}", USAGE, options());
        return EUSAGE;
    }

    // Check if the type is not a directory or a file
    if args[1] == TYPES[0][0] || args[1] == TYPES[1][0] {} else {
        sysln!("unknown type: '{}'", args[1]).unwrap();
        return EUSAGE;
    }

    // Authorize absolute paths
    if Path::new(&args[3]).has_root() {
        let stdin_err = format_sys!("cannot read from stdin");
        loop {
            // Reset the input buffer with every pass
            let mut input = String::new();

            // Print a confirmation prompt and wait for input
            sys!("path is absolute - continue? [y/n] ").unwrap();
            io::stdin().read_line(&mut input).expect(&stdin_err);

            // Normalize the input for comparison
            input = input.trim().to_lowercase();

            // The response must be 'y' or 'n'
            match input.as_str() {
                "y" => break,
                "n" => {
                    sysln!("abort").unwrap();
                    return ESUCCESS;
                },
                _ => continue,
            }
        }
    }

    // Construct the child process and error messages
    let find_command = format!("{} {} {} {} {} {} {} {} {}",
                               CHMOD_ARGS[0], args[3], CHMOD_ARGS[1], args[1].trim_left_matches("-"),
                               CHMOD_ARGS[2], CHMOD_ARGS[3], args[2], CHMOD_ARGS[4], CHMOD_ARGS[5]);
    let child_exec_err = format_sys!("failed to execute the child process: `{}`", SHELL_ARGS[0]);
    let child_wait_err = format_sys!("failed to wait on the child process: `{}`", SHELL_ARGS[0]);

    // Execute and wait on the child process
    let child = Command::new(SHELL_ARGS[0])
        .arg(SHELL_ARGS[1])
        .arg(find_command)
        .spawn().expect(&child_exec_err)
        .wait().expect(&child_wait_err);

    // Return the child exit code if it exists
    match child.code() {
        None => return ENOEXIT,
        Some(code) => return code,
    }
}

fn options() -> String {

    // Initialize the buffer and write the options header
    let mut buffer = String::with_capacity(128);
    writeln!(&mut buffer, "Types:").unwrap();

    // Enumerate the options and return the buffer
    for outer in TYPES.iter() {
        for inner in outer.iter() {
            write!(&mut buffer, "{:2}{}", "", inner).unwrap();
        }
        writeln!(&mut buffer, "").unwrap();
    }
    return buffer;
}
<commit_msg>Forward compatible update (stderr macros)<commit_after>//! A simple program that recursively changes the mode of all directories or
//! files to the given mode under the given directory. The following child
//! process will be executed and waited on, and it's exit code returned
//! `sh -c "find PATH -type TYPE -exec chmod MODE {} \;"`.
use std::env;
use std::fmt::Write as FmtWrite;
use std::io;
use std::path::Path;
use std::process;
use std::process::Command;

// Successful execution
const ESUCCESS: i32 = 0x00;
// No exit code found
const ENOEXIT: i32 = 0x01;
// Invalid usage
const EUSAGE: i32 = 0x02;

// Shell arguments (compatibility wrapper)
const SHELL_ARGS: &[&str] = &[
    "sh", "-c"
];
// Chmod arguments (recursive typed chmod)
const CHMOD_ARGS: &[&str] = &[
    "find", "-type", "-exec", "chmod", "{}", "\\;"
];

// The program name
const NAME: &str = "chmodrt";
// The program usage
const USAGE: &str = "Usage: chmodrt TYPE MODE PATH";
// The program options
const TYPES: &[&[&str]] = &[
    &["-d", "Change the mode of directories"],
    &["-f", "Change the mode of files"],
];

macro_rules! eprint {
    ($fmt:expr) => {{
        use std::io::{self, Write};
        write!(&mut io::stderr(), $fmt).unwrap();
    }};
    ($fmt:expr, $($arg:tt)*) => {{
        use std::io::{self, Write};
        write!(&mut io::stderr(), $fmt, $($arg)*).unwrap();
    }};
}

macro_rules! eprintln {
    () => (eprint!("\n"));
    ($fmt:expr) => (eprint!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
}

// Prepends the program name to the given message
macro_rules! sformat {
    ($fmt:expr) => (format!(concat!("{}: ", $fmt), NAME));
    ($fmt:expr, $($arg:tt)*) => (format!(concat!("{}: ", $fmt), NAME, $($arg)*));
}

// Writes a formatted system message to the standard error
macro_rules! sprint {
    ($fmt:expr) => (eprint!("{}", sformat!($fmt)));
    ($fmt:expr, $($arg:tt)*) => (eprint!("{}", sformat!($fmt, $($arg)*)));
}

// Writes a formatted system message to the standard error with a new line
macro_rules! sprintln {
    () => (sprint!("\n"));
    ($fmt:expr) => (sprint!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (sprint!(concat!($fmt, "\n"), $($arg)*));
}

fn main() {
    process::exit(chmodrt(env::args().collect()));
}

fn chmodrt(args: Vec<String>) -> i32 {

    // Enforce correct usage
    if args.len() != 4 {
        print!("{}\n\n{}", USAGE, options());
        return EUSAGE;
    }

    // Check if the type is not a directory or a file
    if args[1] == TYPES[0][0] || args[1] == TYPES[1][0] {} else {
        sprintln!("unknown type: '{}'", args[1]);
        return EUSAGE;
    }

    // Authorize absolute paths
    if Path::new(&args[3]).has_root() {
        let stdin_err = sformat!("cannot read from stdin");
        loop {
            // Reset the input buffer with every pass
            let mut input = String::new();

            // Print a confirmation prompt and wait for input
            sprint!("path is absolute - continue? [y/n] ");
            io::stdin().read_line(&mut input).expect(&stdin_err);

            // Normalize the input for comparison
            input = input.trim().to_lowercase();

            // The response must be 'y' or 'n'
            match input.as_str() {
                "y" => break,
                "n" => {
                    sprintln!("abort");
                    return ESUCCESS;
                },
                _ => continue,
            }
        }
    }

    // Construct the child process and error messages
    let find_command = format!("{} {} {} {} {} {} {} {} {}",
                               CHMOD_ARGS[0], args[3], CHMOD_ARGS[1], args[1].trim_left_matches("-"),
                               CHMOD_ARGS[2], CHMOD_ARGS[3], args[2], CHMOD_ARGS[4], CHMOD_ARGS[5]);
    let child_exec_err = sformat!("failed to execute the child process: `{}`", SHELL_ARGS[0]);
    let child_wait_err = sformat!("failed to wait on the child process: `{}`", SHELL_ARGS[0]);

    // Execute and wait on the child process
    let child = Command::new(SHELL_ARGS[0])
        .arg(SHELL_ARGS[1])
        .arg(find_command)
        .spawn().expect(&child_exec_err)
        .wait().expect(&child_wait_err);

    // Return the child exit code if it exists
    match child.code() {
        None => return ENOEXIT,
        Some(code) => return code,
    }
}

fn options() -> String {

    // Initialize the buffer and write the options header
    let mut buffer = String::with_capacity(128);
    writeln!(&mut buffer, "Types:").unwrap();

    // Enumerate the options and return the buffer
    for outer in TYPES.iter() {
        for inner in outer.iter() {
            write!(&mut buffer, "{:2}{}", "", inner).unwrap();
        }
        writeln!(&mut buffer, "").unwrap();
    }
    return buffer;
}
<|endoftext|>