<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) BUFSIZE gecos fullname, mesg iobuf

#[macro_use]
extern crate uucore;
use uucore::entries::{Locate, Passwd};
use uucore::libc::S_IWGRP;
use uucore::utmpx::{self, time, Utmpx};

use std::io::prelude::*;
use std::io::BufReader;

use std::fs::File;
use std::os::unix::fs::MetadataExt;

use clap::{crate_version, App, Arg};
use std::path::PathBuf;
use uucore::InvalidEncodingHandling;

const BUFSIZE: usize = 1024;

static ABOUT: &str = "pinky - lightweight finger";

mod options {
    pub const LONG_FORMAT: &str = "long_format";
    pub const OMIT_HOME_DIR: &str = "omit_home_dir";
    pub const OMIT_PROJECT_FILE: &str = "omit_project_file";
    pub const OMIT_PLAN_FILE: &str = "omit_plan_file";
    pub const SHORT_FORMAT: &str = "short_format";
    pub const OMIT_HEADINGS: &str = "omit_headings";
    pub const OMIT_NAME: &str = "omit_name";
    pub const OMIT_NAME_HOST: &str = "omit_name_host";
    pub const OMIT_NAME_HOST_TIME: &str = "omit_name_host_time";
    pub const USER: &str = "user";
}

fn usage() -> String {
    format!("{0} [OPTION]... [USER]...", uucore::execution_phrase())
}

fn get_long_usage() -> String {
    format!(
        "A lightweight 'finger' program;  print user information.\n\
         The utmp file will be {}.",
        utmpx::DEFAULT_FILE
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();

    let usage = usage();
    let after_help = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&after_help[..])
        .get_matches_from(args);

    let users: Vec<String> = matches
        .values_of(options::USER)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    // If true, display the hours:minutes since each user has touched
    // the keyboard, or blank if within the last minute, or days followed
    // by a 'd' if not within the last day.
    let mut include_idle = true;

    // If true, display a line at the top describing each field.
    let include_heading = !matches.is_present(options::OMIT_HEADINGS);

    // if true, display the user's full name from pw_gecos.
    let mut include_fullname = true;

    // if true, display the user's ~/.project file when doing long format.
    let include_project = !matches.is_present(options::OMIT_PROJECT_FILE);

    // if true, display the user's ~/.plan file when doing long format.
    let include_plan = !matches.is_present(options::OMIT_PLAN_FILE);

    // if true, display the user's home directory and shell
    // when doing long format.
    let include_home_and_shell = !matches.is_present(options::OMIT_HOME_DIR);

    // if true, use the "short" output format.
    let do_short_format = !matches.is_present(options::LONG_FORMAT);

    /* if true, display the ut_host field. */
    let mut include_where = true;

    if matches.is_present(options::OMIT_NAME) {
        include_fullname = false;
    }
    if matches.is_present(options::OMIT_NAME_HOST) {
        include_fullname = false;
        include_where = false;
    }
    if matches.is_present(options::OMIT_NAME_HOST_TIME) {
        include_fullname = false;
        include_idle = false;
        include_where = false;
    }

    let pk = Pinky {
        include_idle,
        include_heading,
        include_fullname,
        include_project,
        include_plan,
        include_home_and_shell,
        include_where,
        names: users,
    };

    if do_short_format {
        pk.short_pinky();
        0
    } else {
        pk.long_pinky()
    }
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(options::LONG_FORMAT)
                .short("l")
                .requires(options::USER)
                .help("produce long format output for the specified USERs"),
        )
        .arg(
            Arg::with_name(options::OMIT_HOME_DIR)
                .short("b")
                .help("omit the user's home directory and shell in long format"),
        )
        .arg(
            Arg::with_name(options::OMIT_PROJECT_FILE)
                .short("h")
                .help("omit the user's project file in long format"),
        )
        .arg(
            Arg::with_name(options::OMIT_PLAN_FILE)
                .short("p")
                .help("omit the user's plan file in long format"),
        )
        .arg(
            Arg::with_name(options::SHORT_FORMAT)
                .short("s")
                .help("do short format output, this is the default"),
        )
        .arg(
            Arg::with_name(options::OMIT_HEADINGS)
                .short("f")
                .help("omit the line of column headings in short format"),
        )
        .arg(
            Arg::with_name(options::OMIT_NAME)
                .short("w")
                .help("omit the user's full name in short format"),
        )
        .arg(
            Arg::with_name(options::OMIT_NAME_HOST)
                .short("i")
                .help("omit the user's full name and remote host in short format"),
        )
        .arg(
            Arg::with_name(options::OMIT_NAME_HOST_TIME)
                .short("q")
                .help("omit the user's full name, remote host and idle time in short format"),
        )
        .arg(
            Arg::with_name(options::USER)
                .takes_value(true)
                .multiple(true),
        )
}

struct Pinky {
    include_idle: bool,
    include_heading: bool,
    include_fullname: bool,
    include_project: bool,
    include_plan: bool,
    include_where: bool,
    include_home_and_shell: bool,
    names: Vec<String>,
}

pub trait Capitalize {
    fn capitalize(&self) -> String;
}

impl Capitalize for str {
    fn capitalize(&self) -> String {
        self.char_indices()
            .fold(String::with_capacity(self.len()), |mut acc, x| {
                if x.0 != 0 {
                    acc.push(x.1)
                } else {
                    acc.push(x.1.to_ascii_uppercase())
                }
                acc
            })
    }
}

fn idle_string(when: i64) -> String {
    thread_local! {
        static NOW: time::Tm = time::now()
    }
    NOW.with(|n| {
        let duration = n.to_timespec().sec - when;
        if duration < 60 {
            // less than 1min
            "     ".to_owned()
        } else if duration < 24 * 3600 {
            // less than 1day
            let hours = duration / (60 * 60);
            let minutes = (duration % (60 * 60)) / 60;
            format!("{:02}:{:02}", hours, minutes)
        } else {
            // more than 1day
            let days = duration / (24 * 3600);
            format!("{}d", days)
        }
    })
}

fn time_string(ut: &Utmpx) -> String {
    time::strftime("%b %e %H:%M", &ut.login_time()).unwrap() // LC_ALL=C
}

impl Pinky {
    fn print_entry(&self, ut: &Utmpx) {
        let mut pts_path = PathBuf::from("/dev");
        pts_path.push(ut.tty_device().as_str());

        let mesg;
        let last_change;
        match pts_path.metadata() {
            Ok(meta) => {
                mesg = if meta.mode() & (S_IWGRP as u32) != 0 {
                    ' '
                } else {
                    '*'
                };
                last_change = meta.atime();
            }
            _ => {
                mesg = '?';
                last_change = 0;
            }
        }

        print!("{1:<8.0$}", utmpx::UT_NAMESIZE, ut.user());

        if self.include_fullname {
            if let Ok(pw) = Passwd::locate(ut.user().as_ref()) {
                let mut gecos = pw.user_info;
                if let Some(n) = gecos.find(',') {
                    gecos.truncate(n + 1);
                }
                print!(" {:<19.19}", gecos.replace("&", &pw.name.capitalize()));
            } else {
                print!(" {:19}", "        ???");
            }
        }

        print!(" {}{:<8.*}", mesg, utmpx::UT_LINESIZE, ut.tty_device());

        if self.include_idle {
            if last_change != 0 {
                print!(" {:<6}", idle_string(last_change));
            } else {
                print!(" {:<6}", "?????");
            }
        }

        print!(" {}", time_string(ut));

        let mut s = ut.host();
        if self.include_where && !s.is_empty() {
            s = crash_if_err!(1, ut.canon_host());
            print!(" {}", s);
        }

        println!();
    }

    fn print_heading(&self) {
        print!("{:<8}", "Login");
        if self.include_fullname {
            print!(" {:<19}", "Name");
        }
        print!(" {:<9}", " TTY");
        if self.include_idle {
            print!(" {:<6}", "Idle");
        }
        print!(" {:<16}", "When");
        if self.include_where {
            print!(" Where");
        }
        println!();
    }

    fn short_pinky(&self) {
        if self.include_heading {
            self.print_heading();
        }
        for ut in Utmpx::iter_all_records() {
            if ut.is_user_process() {
                if self.names.is_empty() {
                    self.print_entry(&ut)
                } else if self.names.iter().any(|n| n.as_str() == ut.user()) {
                    self.print_entry(&ut);
                }
            }
        }
    }

    fn long_pinky(&self) -> i32 {
        for u in &self.names {
            print!("Login name: {:<28}In real life: ", u);
            if let Ok(pw) = Passwd::locate(u.as_str()) {
                println!(" {}", pw.user_info.replace("&", &pw.name.capitalize()));
                if self.include_home_and_shell {
                    print!("Directory: {:<29}", pw.user_dir);
                    println!("Shell:  {}", pw.user_shell);
                }
                if self.include_project {
                    let mut p = PathBuf::from(&pw.user_dir);
                    p.push(".project");
                    if let Ok(f) = File::open(p) {
                        print!("Project: ");
                        read_to_console(f);
                    }
                }
                if self.include_plan {
                    let mut p = PathBuf::from(&pw.user_dir);
                    p.push(".plan");
                    if let Ok(f) = File::open(p) {
                        println!("Plan:");
                        read_to_console(f);
                    }
                }
                println!();
            } else {
                println!(" ???");
            }
        }
        0
    }
}

fn read_to_console<F: Read>(f: F) {
    let mut reader = BufReader::new(f);
    let mut iobuf = [0_u8; BUFSIZE];
    while let Ok(n) = reader.read(&mut iobuf) {
        if n == 0 {
            break;
        }
        let s = String::from_utf8_lossy(&iobuf);
        print!("{}", s);
    }
}
<commit_msg>pinky: return UResult from uumain() function<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) BUFSIZE gecos fullname, mesg iobuf

use uucore::entries::{Locate, Passwd};
use uucore::error::{FromIo, UResult};
use uucore::libc::S_IWGRP;
use uucore::utmpx::{self, time, Utmpx};

use std::io::prelude::*;
use std::io::BufReader;

use std::fs::File;
use std::os::unix::fs::MetadataExt;

use clap::{crate_version, App, Arg};
use std::path::PathBuf;
use uucore::InvalidEncodingHandling;

const BUFSIZE: usize = 1024;

static ABOUT: &str = "pinky - lightweight finger";

mod options {
    pub const LONG_FORMAT: &str = "long_format";
    pub const OMIT_HOME_DIR: &str = "omit_home_dir";
    pub const OMIT_PROJECT_FILE: &str = "omit_project_file";
    pub const OMIT_PLAN_FILE: &str = "omit_plan_file";
    pub const SHORT_FORMAT: &str = "short_format";
    pub const OMIT_HEADINGS: &str = "omit_headings";
    pub const OMIT_NAME: &str = "omit_name";
    pub const OMIT_NAME_HOST: &str = "omit_name_host";
    pub const OMIT_NAME_HOST_TIME: &str = "omit_name_host_time";
    pub const USER: &str = "user";
}

fn usage() -> String {
    format!("{0} [OPTION]... [USER]...", uucore::execution_phrase())
}

fn get_long_usage() -> String {
    format!(
        "A lightweight 'finger' program;  print user information.\n\
         The utmp file will be {}.",
        utmpx::DEFAULT_FILE
    )
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();

    let usage = usage();
    let after_help = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&after_help[..])
        .get_matches_from(args);

    let users: Vec<String> = matches
        .values_of(options::USER)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    // If true, display the hours:minutes since each user has touched
    // the keyboard, or blank if within the last minute, or days followed
    // by a 'd' if not within the last day.
    let mut include_idle = true;

    // If true, display a line at the top describing each field.
    let include_heading = !matches.is_present(options::OMIT_HEADINGS);

    // if true, display the user's full name from pw_gecos.
    let mut include_fullname = true;

    // if true, display the user's ~/.project file when doing long format.
    let include_project = !matches.is_present(options::OMIT_PROJECT_FILE);

    // if true, display the user's ~/.plan file when doing long format.
    let include_plan = !matches.is_present(options::OMIT_PLAN_FILE);

    // if true, display the user's home directory and shell
    // when doing long format.
    let include_home_and_shell = !matches.is_present(options::OMIT_HOME_DIR);

    // if true, use the "short" output format.
    let do_short_format = !matches.is_present(options::LONG_FORMAT);

    /* if true, display the ut_host field. */
    let mut include_where = true;

    if matches.is_present(options::OMIT_NAME) {
        include_fullname = false;
    }
    if matches.is_present(options::OMIT_NAME_HOST) {
        include_fullname = false;
        include_where = false;
    }
    if matches.is_present(options::OMIT_NAME_HOST_TIME) {
        include_fullname = false;
        include_idle = false;
        include_where = false;
    }

    let pk = Pinky {
        include_idle,
        include_heading,
        include_fullname,
        include_project,
        include_plan,
        include_home_and_shell,
        include_where,
        names: users,
    };

    if do_short_format {
        match pk.short_pinky() {
            Ok(_) => Ok(()),
            Err(e) => Err(e.map_err_context(String::new)),
        }
    } else {
        pk.long_pinky();
        Ok(())
    }
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(options::LONG_FORMAT)
                .short("l")
                .requires(options::USER)
                .help("produce long format output for the specified USERs"),
        )
        .arg(
            Arg::with_name(options::OMIT_HOME_DIR)
                .short("b")
                .help("omit the user's home directory and shell in long format"),
        )
        .arg(
            Arg::with_name(options::OMIT_PROJECT_FILE)
                .short("h")
                .help("omit the user's project file in long format"),
        )
        .arg(
            Arg::with_name(options::OMIT_PLAN_FILE)
                .short("p")
                .help("omit the user's plan file in long format"),
        )
        .arg(
            Arg::with_name(options::SHORT_FORMAT)
                .short("s")
                .help("do short format output, this is the default"),
        )
        .arg(
            Arg::with_name(options::OMIT_HEADINGS)
                .short("f")
                .help("omit the line of column headings in short format"),
        )
        .arg(
            Arg::with_name(options::OMIT_NAME)
                .short("w")
                .help("omit the user's full name in short format"),
        )
        .arg(
            Arg::with_name(options::OMIT_NAME_HOST)
                .short("i")
                .help("omit the user's full name and remote host in short format"),
        )
        .arg(
            Arg::with_name(options::OMIT_NAME_HOST_TIME)
                .short("q")
                .help("omit the user's full name, remote host and idle time in short format"),
        )
        .arg(
            Arg::with_name(options::USER)
                .takes_value(true)
                .multiple(true),
        )
}

struct Pinky {
    include_idle: bool,
    include_heading: bool,
    include_fullname: bool,
    include_project: bool,
    include_plan: bool,
    include_where: bool,
    include_home_and_shell: bool,
    names: Vec<String>,
}

pub trait Capitalize {
    fn capitalize(&self) -> String;
}

impl Capitalize for str {
    fn capitalize(&self) -> String {
        self.char_indices()
            .fold(String::with_capacity(self.len()), |mut acc, x| {
                if x.0 != 0 {
                    acc.push(x.1)
                } else {
                    acc.push(x.1.to_ascii_uppercase())
                }
                acc
            })
    }
}

fn idle_string(when: i64) -> String {
    thread_local! {
        static NOW: time::Tm = time::now()
    }
    NOW.with(|n| {
        let duration = n.to_timespec().sec - when;
        if duration < 60 {
            // less than 1min
            "     ".to_owned()
        } else if duration < 24 * 3600 {
            // less than 1day
            let hours = duration / (60 * 60);
            let minutes = (duration % (60 * 60)) / 60;
            format!("{:02}:{:02}", hours, minutes)
        } else {
            // more than 1day
            let days = duration / (24 * 3600);
            format!("{}d", days)
        }
    })
}

fn time_string(ut: &Utmpx) -> String {
    time::strftime("%b %e %H:%M", &ut.login_time()).unwrap() // LC_ALL=C
}

impl Pinky {
    fn print_entry(&self, ut: &Utmpx) -> std::io::Result<()> {
        let mut pts_path = PathBuf::from("/dev");
        pts_path.push(ut.tty_device().as_str());

        let mesg;
        let last_change;
        match pts_path.metadata() {
            Ok(meta) => {
                mesg = if meta.mode() & (S_IWGRP as u32) != 0 {
                    ' '
                } else {
                    '*'
                };
                last_change = meta.atime();
            }
            _ => {
                mesg = '?';
                last_change = 0;
            }
        }

        print!("{1:<8.0$}", utmpx::UT_NAMESIZE, ut.user());

        if self.include_fullname {
            if let Ok(pw) = Passwd::locate(ut.user().as_ref()) {
                let mut gecos = pw.user_info;
                if let Some(n) = gecos.find(',') {
                    gecos.truncate(n + 1);
                }
                print!(" {:<19.19}", gecos.replace("&", &pw.name.capitalize()));
            } else {
                print!(" {:19}", "        ???");
            }
        }

        print!(" {}{:<8.*}", mesg, utmpx::UT_LINESIZE, ut.tty_device());

        if self.include_idle {
            if last_change != 0 {
                print!(" {:<6}", idle_string(last_change));
            } else {
                print!(" {:<6}", "?????");
            }
        }

        print!(" {}", time_string(ut));

        let mut s = ut.host();
        if self.include_where && !s.is_empty() {
            s = ut.canon_host()?;
            print!(" {}", s);
        }

        println!();
        Ok(())
    }

    fn print_heading(&self) {
        print!("{:<8}", "Login");
        if self.include_fullname {
            print!(" {:<19}", "Name");
        }
        print!(" {:<9}", " TTY");
        if self.include_idle {
            print!(" {:<6}", "Idle");
        }
        print!(" {:<16}", "When");
        if self.include_where {
            print!(" Where");
        }
        println!();
    }

    fn short_pinky(&self) -> std::io::Result<()> {
        if self.include_heading {
            self.print_heading();
        }
        for ut in Utmpx::iter_all_records() {
            if ut.is_user_process() {
                if self.names.is_empty() {
                    self.print_entry(&ut)?
                } else if self.names.iter().any(|n| n.as_str() == ut.user()) {
                    self.print_entry(&ut)?;
                }
            }
        }
        Ok(())
    }

    fn long_pinky(&self) {
        for u in &self.names {
            print!("Login name: {:<28}In real life: ", u);
            if let Ok(pw) = Passwd::locate(u.as_str()) {
                println!(" {}", pw.user_info.replace("&", &pw.name.capitalize()));
                if self.include_home_and_shell {
                    print!("Directory: {:<29}", pw.user_dir);
                    println!("Shell:  {}", pw.user_shell);
                }
                if self.include_project {
                    let mut p = PathBuf::from(&pw.user_dir);
                    p.push(".project");
                    if let Ok(f) = File::open(p) {
                        print!("Project: ");
                        read_to_console(f);
                    }
                }
                if self.include_plan {
                    let mut p = PathBuf::from(&pw.user_dir);
                    p.push(".plan");
                    if let Ok(f) = File::open(p) {
                        println!("Plan:");
                        read_to_console(f);
                    }
                }
                println!();
            } else {
                println!(" ???");
            }
        }
    }
}

fn read_to_console<F: Read>(f: F) {
    let mut reader = BufReader::new(f);
    let mut iobuf = [0_u8; BUFSIZE];
    while let Ok(n) = reader.read(&mut iobuf) {
        if n == 0 {
            break;
        }
        let s = String::from_utf8_lossy(&iobuf);
        print!("{}", s);
    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Nick Platt <platt.nicholas@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.

// spell-checker:ignore (ToDO) filetime strptime utcoff strs datetime MMDDhhmm

pub extern crate filetime;

#[macro_use]
extern crate uucore;

use clap::{App, Arg, ArgGroup};
use filetime::*;
use std::fs::{self, File};
use std::io::Error;
use std::path::Path;

static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
pub mod options {
    pub mod sources {
        pub static DATE: &str = "date";
        pub static REFERENCE: &str = "reference";
        pub static CURRENT: &str = "current";
    }
    pub static ACCESS: &str = "access";
    pub static MODIFICATION: &str = "modification";
    pub static NO_CREATE: &str = "no-create";
    pub static NO_DEREF: &str = "no-dereference";
    pub static TIME: &str = "time";
}

static ARG_FILES: &str = "files";

fn to_local(mut tm: time::Tm) -> time::Tm {
    tm.tm_utcoff = time::now().tm_utcoff;
    tm
}

fn local_tm_to_filetime(tm: time::Tm) -> FileTime {
    let ts = tm.to_timespec();
    FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32)
}

fn get_usage() -> String {
    format!("{0} [OPTION]... [USER]", executable!())
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .arg(
            Arg::with_name(options::ACCESS)
                .short("a")
                .help("change only the access time"),
        )
        .arg(
            Arg::with_name(options::sources::CURRENT)
                .short("t")
                .help("use [[CC]YY]MMDDhhmm[.ss] instead of the current time")
                .value_name("STAMP")
                .takes_value(true),
        )
        .arg(
            Arg::with_name(options::sources::DATE)
                .short("d")
                .long(options::sources::DATE)
                .help("parse argument and use it instead of current time")
                .value_name("STRING"),
        )
        .arg(
            Arg::with_name(options::MODIFICATION)
                .short("m")
                .help("change only the modification time"),
        )
        .arg(
            Arg::with_name(options::NO_CREATE)
                .short("c")
                .long(options::NO_CREATE)
                .help("do not create any files"),
        )
        .arg(
            Arg::with_name(options::NO_DEREF)
                .short("h")
                .long(options::NO_DEREF)
                .help(
                    "affect each symbolic link instead of any referenced file \
                     (only for systems that can change the timestamps of a symlink)",
                ),
        )
        .arg(
            Arg::with_name(options::sources::REFERENCE)
                .short("r")
                .long(options::sources::REFERENCE)
                .help("use this file's times instead of the current time")
                .value_name("FILE"),
        )
        .arg(
            Arg::with_name(options::TIME)
                .long(options::TIME)
                .help(
                    "change only the specified time: \"access\", \"atime\", or \
                     \"use\" are equivalent to -a; \"modify\" or \"mtime\" are \
                     equivalent to -m",
                )
                .value_name("WORD")
                .possible_values(&["access", "atime", "use"])
                .takes_value(true),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .min_values(1),
        )
        .group(ArgGroup::with_name("sources").args(&[
            options::sources::CURRENT,
            options::sources::DATE,
            options::sources::REFERENCE,
        ]))
        .get_matches_from(args);

    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    let (mut atime, mut mtime) = if matches.is_present(options::sources::REFERENCE) {
        stat(
            &matches.value_of(options::sources::REFERENCE).unwrap()[..],
            !matches.is_present(options::NO_DEREF),
        )
    } else if matches.is_present(options::sources::DATE)
        || matches.is_present(options::sources::CURRENT)
    {
        let timestamp = if matches.is_present(options::sources::DATE) {
            parse_date(matches.value_of(options::sources::DATE).unwrap().as_ref())
        } else {
            parse_timestamp(
                matches
                    .value_of(options::sources::CURRENT)
                    .unwrap()
                    .as_ref(),
            )
        };
        (timestamp, timestamp)
    } else {
        let now = local_tm_to_filetime(time::now());
        (now, now)
    };

    for filename in &files {
        let path = &filename[..];

        if !Path::new(path).exists() {
            // no-dereference included here for compatibility
            if matches.is_present(options::NO_CREATE) || matches.is_present(options::NO_DEREF) {
                continue;
            }

            if let Err(e) = File::create(path) {
                show_warning!("cannot touch '{}': {}", path, e);
                continue;
            };

            // Minor optimization: if no reference time was specified, we're done.
            if !matches.is_present("sources") {
                continue;
            }
        }

        // If changing "only" atime or mtime, grab the existing value of the other.
        // Note that "-a" and "-m" may be passed together; this is not an xor.
        if matches.is_present(options::ACCESS)
            || matches.is_present(options::MODIFICATION)
            || matches.is_present(options::TIME)
        {
            let st = stat(path, !matches.is_present(options::NO_DEREF));
            let time = matches.value_of(options::TIME).unwrap_or("");

            if !(matches.is_present(options::ACCESS)
                || time.contains(&"access".to_owned())
                || time.contains(&"atime".to_owned())
                || time.contains(&"use".to_owned()))
            {
                atime = st.0;
            }

            if !(matches.is_present(options::MODIFICATION)
                || time.contains(&"modify".to_owned())
                || time.contains(&"mtime".to_owned()))
            {
                mtime = st.1;
            }
        }

        if matches.is_present(options::NO_DEREF) {
            if let Err(e) = set_symlink_file_times(path, atime, mtime) {
                show_warning!("cannot touch '{}': {}", path, e);
            }
        } else if let Err(e) = filetime::set_file_times(path, atime, mtime) {
            show_warning!("cannot touch '{}': {}", path, e);
        }
    }

    0
}

fn stat(path: &str, follow: bool) -> (FileTime, FileTime) {
    let metadata = if follow {
        fs::symlink_metadata(path)
    } else {
        fs::metadata(path)
    };

    match metadata {
        Ok(m) => (
            FileTime::from_last_access_time(&m),
            FileTime::from_last_modification_time(&m),
        ),
        Err(_) => crash!(
            1,
            "failed to get attributes of '{}': {}",
            path,
            Error::last_os_error()
        ),
    }
}

fn parse_date(str: &str) -> FileTime {
    // This isn't actually compatible with GNU touch, but there doesn't seem to
    // be any simple specification for what format this parameter allows and I'm
    // not about to implement GNU parse_datetime.
    // http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/parse-datetime.y
    match time::strptime(str, "%c") {
        Ok(tm) => local_tm_to_filetime(to_local(tm)),
        Err(e) => panic!("Unable to parse date\n{}", e),
    }
}

fn parse_timestamp(s: &str) -> FileTime {
    let now = time::now();
    let (format, ts) = match s.chars().count() {
        15 => ("%Y%m%d%H%M.%S", s.to_owned()),
        12 => ("%Y%m%d%H%M", s.to_owned()),
        13 => ("%y%m%d%H%M.%S", s.to_owned()),
        10 => ("%y%m%d%H%M", s.to_owned()),
        11 => ("%Y%m%d%H%M.%S", format!("{}{}", now.tm_year + 1900, s)),
        8 => ("%Y%m%d%H%M", format!("{}{}", now.tm_year + 1900, s)),
        _ => panic!("Unknown timestamp format"),
    };

    match time::strptime(&ts, format) {
        Ok(tm) => local_tm_to_filetime(to_local(tm)),
        Err(e) => panic!("Unable to parse timestamp\n{}", e),
    }
}
<commit_msg>touch: constant for the sources ArgGroup<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Nick Platt <platt.nicholas@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.

// spell-checker:ignore (ToDO) filetime strptime utcoff strs datetime MMDDhhmm

pub extern crate filetime;

#[macro_use]
extern crate uucore;

use clap::{App, Arg, ArgGroup};
use filetime::*;
use std::fs::{self, File};
use std::io::Error;
use std::path::Path;

static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
pub mod options {
    // Both SOURCES and sources are needed as we need to be able to refer to the ArgGroup.
    pub static SOURCES: &str = "sources";
    pub mod sources {
        pub static DATE: &str = "date";
        pub static REFERENCE: &str = "reference";
        pub static CURRENT: &str = "current";
    }
    pub static ACCESS: &str = "access";
    pub static MODIFICATION: &str = "modification";
    pub static NO_CREATE: &str = "no-create";
    pub static NO_DEREF: &str = "no-dereference";
    pub static TIME: &str = "time";
}

static ARG_FILES: &str = "files";

fn to_local(mut tm: time::Tm) -> time::Tm {
    tm.tm_utcoff = time::now().tm_utcoff;
    tm
}

fn local_tm_to_filetime(tm: time::Tm) -> FileTime {
    let ts = tm.to_timespec();
    FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32)
}

fn get_usage() -> String {
    format!("{0} [OPTION]... [USER]", executable!())
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .arg(
            Arg::with_name(options::ACCESS)
                .short("a")
                .help("change only the access time"),
        )
        .arg(
            Arg::with_name(options::sources::CURRENT)
                .short("t")
                .help("use [[CC]YY]MMDDhhmm[.ss] instead of the current time")
                .value_name("STAMP")
                .takes_value(true),
        )
        .arg(
            Arg::with_name(options::sources::DATE)
                .short("d")
                .long(options::sources::DATE)
                .help("parse argument and use it instead of current time")
                .value_name("STRING"),
        )
        .arg(
            Arg::with_name(options::MODIFICATION)
                .short("m")
                .help("change only the modification time"),
        )
        .arg(
            Arg::with_name(options::NO_CREATE)
                .short("c")
                .long(options::NO_CREATE)
                .help("do not create any files"),
        )
        .arg(
            Arg::with_name(options::NO_DEREF)
                .short("h")
                .long(options::NO_DEREF)
                .help(
                    "affect each symbolic link instead of any referenced file \
                     (only for systems that can change the timestamps of a symlink)",
                ),
        )
        .arg(
            Arg::with_name(options::sources::REFERENCE)
                .short("r")
                .long(options::sources::REFERENCE)
                .help("use this file's times instead of the current time")
                .value_name("FILE"),
        )
        .arg(
            Arg::with_name(options::TIME)
                .long(options::TIME)
                .help(
                    "change only the specified time: \"access\", \"atime\", or \
                     \"use\" are equivalent to -a; \"modify\" or \"mtime\" are \
                     equivalent to -m",
                )
                .value_name("WORD")
                .possible_values(&["access", "atime", "use"])
                .takes_value(true),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .min_values(1),
        )
        .group(ArgGroup::with_name(options::SOURCES).args(&[
            options::sources::CURRENT,
            options::sources::DATE,
            options::sources::REFERENCE,
        ]))
        .get_matches_from(args);

    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    let (mut atime, mut mtime) = if matches.is_present(options::sources::REFERENCE) {
        stat(
            &matches.value_of(options::sources::REFERENCE).unwrap()[..],
            !matches.is_present(options::NO_DEREF),
        )
    } else if matches.is_present(options::sources::DATE)
        || matches.is_present(options::sources::CURRENT)
    {
        let timestamp = if matches.is_present(options::sources::DATE) {
            parse_date(matches.value_of(options::sources::DATE).unwrap().as_ref())
        } else {
            parse_timestamp(
                matches
                    .value_of(options::sources::CURRENT)
                    .unwrap()
                    .as_ref(),
            )
        };
        (timestamp, timestamp)
    } else {
        let now = local_tm_to_filetime(time::now());
        (now, now)
    };

    for filename in &files {
        let path = &filename[..];

        if !Path::new(path).exists() {
            // no-dereference included here for compatibility
            if matches.is_present(options::NO_CREATE) || matches.is_present(options::NO_DEREF) {
                continue;
            }

            if let Err(e) = File::create(path) {
                show_warning!("cannot touch '{}': {}", path, e);
                continue;
            };

            // Minor optimization: if no reference time was specified, we're done.
            if !matches.is_present(options::SOURCES) {
                continue;
            }
        }

        // If changing "only" atime or mtime, grab the existing value of the other.
        // Note that "-a" and "-m" may be passed together; this is not an xor.
        if matches.is_present(options::ACCESS)
            || matches.is_present(options::MODIFICATION)
            || matches.is_present(options::TIME)
        {
            let st = stat(path, !matches.is_present(options::NO_DEREF));
            let time = matches.value_of(options::TIME).unwrap_or("");

            if !(matches.is_present(options::ACCESS)
                || time.contains(&"access".to_owned())
                || time.contains(&"atime".to_owned())
                || time.contains(&"use".to_owned()))
            {
                atime = st.0;
            }

            if !(matches.is_present(options::MODIFICATION)
                || time.contains(&"modify".to_owned())
                || time.contains(&"mtime".to_owned()))
            {
                mtime = st.1;
            }
        }

        if matches.is_present(options::NO_DEREF) {
            if let Err(e) = set_symlink_file_times(path, atime, mtime) {
                show_warning!("cannot touch '{}': {}", path, e);
            }
        } else if let Err(e) = filetime::set_file_times(path, atime, mtime) {
            show_warning!("cannot touch '{}': {}", path, e);
        }
    }

    0
}

fn stat(path: &str, follow: bool) -> (FileTime, FileTime) {
    let metadata = if follow {
        fs::symlink_metadata(path)
    } else {
        fs::metadata(path)
    };

    match metadata {
        Ok(m) => (
            FileTime::from_last_access_time(&m),
            FileTime::from_last_modification_time(&m),
        ),
        Err(_) => crash!(
            1,
            "failed to get attributes of '{}': {}",
            path,
            Error::last_os_error()
        ),
    }
}

fn parse_date(str: &str) -> FileTime {
    // This isn't actually compatible with GNU touch, but there doesn't seem to
    // be any simple specification for what format this parameter allows and I'm
    // not about to implement GNU parse_datetime.
    // http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/parse-datetime.y
    match time::strptime(str, "%c") {
        Ok(tm) => local_tm_to_filetime(to_local(tm)),
        Err(e) => panic!("Unable to parse date\n{}", e),
    }
}

fn parse_timestamp(s: &str) -> FileTime {
    let now = time::now();
    let (format, ts) = match s.chars().count() {
        15 => ("%Y%m%d%H%M.%S", s.to_owned()),
        12 => ("%Y%m%d%H%M", s.to_owned()),
        13 => ("%y%m%d%H%M.%S", s.to_owned()),
        10 => ("%y%m%d%H%M", s.to_owned()),
        11 => ("%Y%m%d%H%M.%S", format!("{}{}", now.tm_year + 1900, s)),
        8 => ("%Y%m%d%H%M", format!("{}{}", now.tm_year + 1900, s)),
        _ => panic!("Unknown timestamp format"),
    };

    match time::strptime(&ts, format) {
        Ok(tm) => local_tm_to_filetime(to_local(tm)),
        Err(e) => panic!("Unable to parse timestamp\n{}", e),
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::Arc;

use uuid::Uuid;
use futures::{stream, Future, Stream};
use tempdir::TempDir;

use kvproto::importpb::*;
use kvproto::importpb_grpc::*;
use grpc::{ChannelBuilder, Environment, Result, WriteFlags};

use tikv::config::TiKvConfig;
use tikv::import::ImportKVServer;

fn new_kv_server() -> (ImportKVServer, ImportKvClient) {
    let temp_dir = TempDir::new("test_import_kv_server").unwrap();

    let mut cfg = TiKvConfig::default();
    cfg.server.addr = "127.0.0.1:0".to_owned();
    cfg.import.import_dir = temp_dir.path().to_str().unwrap().to_owned();
    let server = ImportKVServer::new(&cfg);

    let ch = {
        let env = Arc::new(Environment::new(1));
        let addr = server.bind_addrs().first().unwrap();
        ChannelBuilder::new(env).connect(&format!("{}:{}", addr.0, addr.1))
    };
    let client = ImportKvClient::new(ch);

    (server, client)
}

#[test]
fn test_kv_service() {
    let (mut server, client) = new_kv_server();
    server.start();

    let uuid = Uuid::new_v4().as_bytes().to_vec();
    let mut head = WriteHead::new();
    head.set_uuid(uuid.clone());

    let mut m = Mutation::new();
    m.op = Mutation_OP::Put;
    m.set_key(vec![1]);
    m.set_value(vec![1]);
    let mut batch = WriteBatch::new();
    batch.set_commit_ts(123);
    batch.mut_mutations().push(m);

    let mut open = OpenRequest::new();
    open.set_uuid(uuid.clone());

    let mut close = CloseRequest::new();
    close.set_uuid(uuid.clone());

    // Write an engine before it is opened.
    let resp = send_write(&client, &head, &batch).unwrap();
    assert!(resp.get_error().has_engine_not_found());

    // Close an engine before it it opened.
    let resp = client.close(&close).unwrap();
    assert!(resp.get_error().has_engine_not_found());

    client.open(&open).unwrap();
    let resp = send_write(&client, &head, &batch).unwrap();
    assert!(!resp.has_error());
    let resp = send_write(&client, &head, &batch).unwrap();
    assert!(!resp.has_error());
    let resp = client.close(&close).unwrap();
    assert!(!resp.has_error());

    server.shutdown();
}

fn send_write(
    client: &ImportKvClient,
    head: &WriteHead,
    batch: &WriteBatch,
) -> Result<WriteResponse> {
    let mut r1 = WriteRequest::new();
    r1.set_head(head.clone());
    let mut r2 = WriteRequest::new();
    r2.set_batch(batch.clone());
    let mut r3 = WriteRequest::new();
    r3.set_batch(batch.clone());
    let reqs: Vec<_> = vec![r1, r2, r3]
        .into_iter()
        .map(|r| (r, WriteFlags::default()))
        .collect();
    let (tx, rx) = client.write().unwrap();
    let stream = stream::iter_ok(reqs);
    stream.forward(tx).and_then(|_| rx).wait()
}
<commit_msg>Fix test_kv_service (#2944)<commit_after>// Copyright 2018 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::Arc;

use uuid::Uuid;
use futures::{stream, Future, Stream};
use tempdir::TempDir;

use kvproto::importpb::*;
use kvproto::importpb_grpc::*;
use grpc::{ChannelBuilder, Environment, Result, WriteFlags};

use tikv::config::TiKvConfig;
use tikv::import::ImportKVServer;

fn new_kv_server() -> (ImportKVServer, ImportKvClient) {
    let temp_dir = TempDir::new("test_import_kv_server").unwrap();

    let mut cfg = TiKvConfig::default();
    cfg.server.addr = "127.0.0.1:0".to_owned();
    cfg.import.import_dir = temp_dir.path().to_str().unwrap().to_owned();
    let server = ImportKVServer::new(&cfg);

    let ch = {
        let env = Arc::new(Environment::new(1));
        let addr = server.bind_addrs().first().unwrap();
        ChannelBuilder::new(env).connect(&format!("{}:{}", addr.0, addr.1))
    };
    let client = ImportKvClient::new(ch);

    (server, client)
}

#[test]
fn test_kv_service() {
    let (mut server, client) = new_kv_server();
    server.start();

    let uuid = Uuid::new_v4().as_bytes().to_vec();
    let mut head = WriteHead::new();
    head.set_uuid(uuid.clone());

    let mut m = Mutation::new();
    m.op = Mutation_OP::Put;
    m.set_key(vec![1]);
    m.set_value(vec![1]);
    let mut batch = WriteBatch::new();
    batch.set_commit_ts(123);
    batch.mut_mutations().push(m);

    let mut open = OpenRequest::new();
    open.set_uuid(uuid.clone());

    let mut close = CloseRequest::new();
    close.set_uuid(uuid.clone());

    // Write an engine before it is opened.
    // Only send the write head here to avoid other gRPC errors.
    let resp = send_write_head(&client, &head).unwrap();
    assert!(resp.get_error().has_engine_not_found());

    // Close an engine before it it opened.
    let resp = client.close(&close).unwrap();
    assert!(resp.get_error().has_engine_not_found());

    client.open(&open).unwrap();
    let resp = send_write(&client, &head, &batch).unwrap();
    assert!(!resp.has_error());
    let resp = send_write(&client, &head, &batch).unwrap();
    assert!(!resp.has_error());
    let resp = client.close(&close).unwrap();
    assert!(!resp.has_error());

    server.shutdown();
}

fn send_write(
    client: &ImportKvClient,
    head: &WriteHead,
    batch: &WriteBatch,
) -> Result<WriteResponse> {
    let mut r1 = WriteRequest::new();
    r1.set_head(head.clone());
    let mut r2 = WriteRequest::new();
    r2.set_batch(batch.clone());
    let mut r3 = WriteRequest::new();
    r3.set_batch(batch.clone());
    let reqs: Vec<_> = vec![r1, r2, r3]
        .into_iter()
        .map(|r| (r, WriteFlags::default()))
        .collect();
    let (tx, rx) = client.write().unwrap();
    let stream = stream::iter_ok(reqs);
    stream.forward(tx).and_then(|_| rx).wait()
}

fn send_write_head(client: &ImportKvClient, head: &WriteHead) -> Result<WriteResponse> {
    let mut req = WriteRequest::new();
    req.set_head(head.clone());
    let (tx, rx) = client.write().unwrap();
    let stream = stream::once(Ok((req, WriteFlags::default())));
    stream.forward(tx).and_then(|_| rx).wait()
}
<|endoftext|>


<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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. This file may not be copied, modified, or distributed
// except according to those terms.

//! Test casts for alignment issues

#![feature(libc)]

extern crate libc;

#[warn(clippy::cast_ptr_alignment)]
#[allow(clippy::no_effect, clippy::unnecessary_operation, clippy::cast_lossless)]
fn main() {
    /* These should be warned against */

    // cast to more-strictly-aligned type
    (&1u8 as *const u8) as *const u16;
    (&mut 1u8 as *mut u8) as *mut u16;

    /* These should be okay */

    // not a pointer type
    1u8 as u16;
    // cast to less-strictly-aligned type
    (&1u16 as *const u16) as *const u8;
    (&mut 1u16 as *mut u16) as *mut u8;
    // For c_void, we should trust the user. See #2677
    (&1u32 as *const u32 as *const std::os::raw::c_void) as *const u32;
    (&1u32 as *const u32 as *const libc::c_void) as *const u32;
}
<commit_msg>Rollup merge of #3540 - matthiaskrgr:rustup, r=flip1995<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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. This file may not be copied, modified, or distributed
// except according to those terms.

//! Test casts for alignment issues

#![feature(rustc_private)]
extern crate libc;

#[warn(clippy::cast_ptr_alignment)]
#[allow(clippy::no_effect, clippy::unnecessary_operation, clippy::cast_lossless)]
fn main() {
    /* These should be warned against */

    // cast to more-strictly-aligned type
    (&1u8 as *const u8) as *const u16;
    (&mut 1u8 as *mut u8) as *mut u16;

    /* These should be okay */

    // not a pointer type
    1u8 as u16;
    // cast to less-strictly-aligned type
    (&1u16 as *const u16) as *const u8;
    (&mut 1u16 as *mut u16) as *mut u8;
    // For c_void, we should trust the user. See #2677
    (&1u32 as *const u32 as *const std::os::raw::c_void) as *const u32;
    (&1u32 as *const u32 as *const libc::c_void) as *const u32;
}
<|endoftext|>


<commit_before>use arc::Arc;
use circle::Circle;
use fx32::Fx32;
use fx32::Fx32Small;
use ray2::Ray2;
use vec2::Vec2;
use wide_line::WideLine;

use std::cmp;

use std::io::Error;
use std::io::prelude::*;
use std::io::BufWriter;
use std::fs::File;

#[derive (Clone, Copy)]
pub enum Ray2TraceResult {
	Hit (Fx32, Vec2 <Fx32>, Vec2 <Fx32Small>),
	Pop (Vec2 <Fx32>, Vec2 <Fx32Small>),
	Miss,
}

pub fn fold_closer_result (a: Ray2TraceResult, b: Ray2TraceResult) -> Ray2TraceResult {
	match a {
		Ray2TraceResult::Miss => {
			return b;
		},
		Ray2TraceResult::Hit (a_t, ..) => {
			match b {
				Ray2TraceResult::Miss => {
					return a;
				},
				Ray2TraceResult::Hit (b_t, ..) => {
					if a_t < b_t {
						return a;
					}
					else {
						return b;
					}
				},
				Ray2TraceResult::Pop (..) => {
					return b;
				}
			}
		},
		Ray2TraceResult::Pop (..) => {
			return a;
		},
	}
}

pub fn write_vec2 <T> (writer: &mut T, v: &Vec2 <Fx32>) where T: Write {
	write! (writer, "v {} 0 {}\n", v.x.to_f64 () / 256.0, v.y.to_f64 () / 256.0).unwrap ();
}

pub fn apply_dt (ray: &Ray2, dt: Fx32Small) -> Ray2 {
	Ray2 {
		start: ray.start,
		dir: ray.dir * dt,
	}
}

pub fn test_ray_trace (filename: &str, offset: Fx32) -> Result <(), Error> {
	let scale = 1;
	//let scale_fx = Fx32::from_int (scale);

	let points = vec! [
		Vec2 {x: Fx32::from_q (40, scale), y: Fx32::from_q (470 - 34, scale)},
		Vec2 {x: Fx32::from_q (256, scale), y: Fx32::from_q (512, scale)},
		Vec2 {x: Fx32::from_q (480, scale), y: Fx32::from_q (460, scale)},
	];

	let obstacle = vec! [
	Arc::new1 (&Circle {
		center: points [0],
		radius: Fx32::from_q (20, scale),
	}, points [1]),
	Arc::new2 (&Circle {
		center: points [1],
		radius: Fx32::from_q (20, scale),
	}, points [0], points [2]),
	Arc::new1 (&Circle {
		center: points [2],
		radius: Fx32::from_q (20, scale),
	}, points [1]),
	];

	let lines = vec! [
	WideLine {
		start: points [0],
		end: points [1],
		radius: Fx32::from_q (20, scale),
	},
	WideLine {
		start: points [2],
		end: points [1],
		radius: Fx32::from_q (20, scale),
	},
	];

	let mut num_bounces = 0;
	let mut num_pops = 0;
	let mut num_ticks = 0;

	let inv_dt = 1;
	let gravity = Vec2::<Fx32> {
		x: Fx32::from_q (0, 1),
		y: Fx32::from_q (2, 1),
	};

	let obj_file = try!(File::create(filename));
	let mut writer = BufWriter::new (obj_file);

	let mut vertex_i = 1;
	let mut polyline_start = vertex_i;

	for x in 0..128 {
		let x = x * 4;
		let mut particle = Ray2 {
			start: Vec2 {
				x: Fx32::from_q (x * 2, scale * 2) + offset,
				y: Fx32::from_q (0, scale)
			},
			dir: Vec2 {
				x: Fx32::from_q (0, scale),
				y: Fx32::from_q (1, scale),
			},
		};

		write_vec2 (&mut writer, &particle.start);
		vertex_i += 1;

		let dt = Fx32::from_q (1, inv_dt).to_small ();

		for tick in 0..500 {
			let trace_result = {
				let dt_particle = apply_dt (&particle, dt);

				let point_results = obstacle.iter ().map (|obstacle| ray_trace_arc (&dt_particle, obstacle));

				let line_results = lines.iter ().map (|line| ray_trace_line_2 (&dt_particle, line));

				point_results.chain (line_results).fold ( Ray2TraceResult::Miss, fold_closer_result)
			};

			match trace_result {
				Ray2TraceResult::Miss => {
					//let air_drag = Fx32 { x: particle.dir.length_sq ().x / -16384 };
					//let air_force = particle.dir * air_drag;
					let new_dir = particle.dir + gravity * dt;// + Vec2::<Fx32>::from (air_force * dt);
					/*
					let sum_dir = particle.dir + new_dir;
					let average_dir = Vec2::<Fx32> {
						x: Fx32 { x: sum_dir.x.x / 2 },
						y: Fx32 { x: sum_dir.y.x / 2 },
					};
					*/
					particle.start = particle.start + (particle.dir * dt);
					particle.dir = new_dir;
				},
				Ray2TraceResult::Pop (ccd_pos, normal) => {
					println! ("{}: Pop from {:?} to {:?}", tick, particle.start, ccd_pos);

					let reflected_dir = particle.dir.reflect_res (normal, Fx32::from_q (0, 1024).to_small ());

					let new_dir = reflected_dir;// + gravity * dt;
					/*
					let sum_dir = reflected_dir + new_dir;
					let average_dir = Vec2::<Fx32> {
						x: Fx32 { x: sum_dir.x.x / 2 },
						y: Fx32 { x: sum_dir.y.x / 2 },
					};
					*/
					particle.start = ccd_pos;// + (average_dir * dt);
					if particle.dir * normal < 0 {
						particle.dir = new_dir;
					}

					num_pops += 1;
				},
				Ray2TraceResult::Hit (_, ccd_pos, normal) => {
					println! ("{}: Hit from {:?} to {:?}", tick, particle.start, ccd_pos);

					println! ("Incoming vel {:?}", particle.dir);

					particle.start = ccd_pos;
					if particle.dir * normal < 0 {
						particle.dir = particle.dir.reflect_res (normal, Fx32::from_q (0, 1024).to_small ());
					}

					println! ("Outgoing vel {:?}", particle.dir);

					//particle.dir = normal;
					num_bounces += 1;
				},
			};

			write_vec2 (&mut writer, &particle.start);
			vertex_i += 1;

			num_ticks += 1;

			if particle.start.y > 768 {
				break;
			}
		}

		for i in polyline_start..vertex_i - 1 {
			try! (write! (writer, "f {} {}\n", i, i + 1));
		}
		polyline_start = vertex_i
	}

	println! ("num_bounces: {}", num_bounces);
	println! ("num_pops: {}", num_pops);
	println! ("num_ticks: {}", num_ticks);

	Ok (())
}

pub struct Basis2 {
	pub x: Vec2 <Fx32Small>,
	pub y: Vec2 <Fx32Small>,
}

// Constructs a basis to ray space
// Such that the ray is the X axis
pub fn get_ray_basis (ray: &Ray2, ray_length: Fx32) -> Basis2 {
	let basis_x_big = if ray_length == 0 {
		ray.dir
	}
	else {
		ray.dir / ray_length
	};

	Basis2 {
		x: basis_x_big.to_small (),
		y: basis_x_big.cross ().to_small (),
	}
}

impl Basis2 {
	pub fn to_space (&self, v: &Vec2 <Fx32>) -> Vec2 <Fx32> {
		Vec2::<Fx32> {
			x: *v * self.x,
			y: *v * self.y,
		}
	}

	pub fn from_space (&self, v: &Vec2 <Fx32>) -> Vec2 <Fx32> {
		Vec2::<Fx32> {
			x: (v.x * self.x.x) + (v.y * self.y.x),
			y: (v.x * self.x.y) + (v.y * self.y.y),
		}
	}
}

pub fn ray_trace_line_2 (ray: &Ray2, line: &WideLine) -> Ray2TraceResult {
	let line_tangent: Vec2 <Fx32> = line.end - line.start;
	let huge_normal = line_tangent.cross ();
	let line_tangent = Vec2::<Fx32> {
		x: line_tangent.x * Fx32::from_q (1, 256),
		y: line_tangent.y * Fx32::from_q (1, 256),
	}.normalized ();
	let line_normal = Vec2::<Fx32Small> {
		x: (-Fx32::from (line_tangent.y)).to_small (),
		y: line_tangent.x,
	};

	let ray_end = ray.start + ray.dir;

	let start_along = (ray.start - line.start) * line_tangent;
	let end_along = (ray_end - line.start) * line_tangent;

	// TODO: Probably a way to optimize this into a series of inequalities
	let line_length = (line.end - line.start) * line_tangent;

	if start_along < 0 && end_along < 0 {
		return Ray2TraceResult::Miss;
	}
	if start_along > line_length && end_along > line_length {
		return Ray2TraceResult::Miss;
	}

	let sdf: Fx32 = (ray.start - line.start) * line_normal;

	// Flip the normal so it's towards the ray
	// This will allow us to extrude the correct side
	let line_normal = if sdf > 0 {
		line_normal
	}
	else {
		-line_normal
	};
	let big_normal: Vec2 <Fx32> = line_normal.into ();

	if ray.dir * big_normal > 0 {
		// Ray is leaving the half-plane, leave it be
		return Ray2TraceResult::Miss;
	}

	let start_distance = sdf.abs () - line.radius;
	let end_distance = (ray_end - line.start) * big_normal - line.radius;

	if start_distance < 0 {
		// Ray was already inside the plane, pop it out
		return Ray2TraceResult::Pop (
			ray.start + big_normal * (line.radius - sdf.abs ()),
			line_normal
		);
	}

	if end_distance > 0 {
		// Ray will not reach the plane in this timestep, leave it be
		return Ray2TraceResult::Miss;
	}

	let t = (-start_distance) / (end_distance - start_distance);
	let ccd_pos = ray.start + ray.dir * t;

	let ccd_along = start_along * (Fx32::from_int (1) - t) + end_along * t;

	if ccd_along < 0 {
		return Ray2TraceResult::Miss;
	}
	if ccd_along > line_length {
		return Ray2TraceResult::Miss;
	}

	return Ray2TraceResult::Hit (t, ccd_pos, line_normal);
}

pub fn ray_trace_circle_2 (ray: &Ray2, circle: &Circle) -> Ray2TraceResult {
	let ray_length = ray.dir.length ();
	let basis = get_ray_basis (ray, ray_length);

	let center_in_ray_space = basis.to_space (&(circle.center - ray.start));

	if center_in_ray_space.x < 0 {
		return Ray2TraceResult::Miss;
	}

	if center_in_ray_space.x > ray_length + circle.radius {
		return Ray2TraceResult::Miss;
	}

	if center_in_ray_space.y.abs () >= circle.radius {
		// Prevents a negative root later on
		return Ray2TraceResult::Miss;
	}

	let ray_space_x = center_in_ray_space.x - (circle.radius.square () - center_in_ray_space.y.square ()).sqrt ();

	if ray_space_x > ray_length || ray_length == 0 {
		return Ray2TraceResult::Miss;
	}

	let t = ray_space_x / ray_length;
	let t = Fx32 { x: cmp::max (t.x, Fx32::from_int (0).x) };

	if t <= 1 {
		let ccd_pos = ray.start + ray.dir * t;
		let disp = ccd_pos - circle.center;
		let dist_sq = disp.length_sq ();
		let ccd_pos = if dist_sq < circle.radius.square ()
		{
			circle.center + disp * (circle.radius / dist_sq.sqrt ())
		}
		else {
			ccd_pos
		};

		return Ray2TraceResult::Hit (
			t,
			ccd_pos,
			((ccd_pos - circle.center) / circle.radius).to_small (),
		);
	}
	else {
		return Ray2TraceResult::Miss;
	}
}

pub fn ray_trace_arc (ray: &Ray2, arc: &Arc) -> Ray2TraceResult {
	let circle_result = ray_trace_circle_2 (ray, &arc.circle);
	arc.filter_collision (circle_result)
}
<commit_msg>Adding restitution back in<commit_after>use arc::Arc;
use circle::Circle;
use fx32::Fx32;
use fx32::Fx32Small;
use ray2::Ray2;
use vec2::Vec2;
use wide_line::WideLine;

use std::cmp;

use std::io::Error;
use std::io::prelude::*;
use std::io::BufWriter;
use std::fs::File;

#[derive (Clone, Copy)]
pub enum Ray2TraceResult {
	Hit (Fx32, Vec2 <Fx32>, Vec2 <Fx32Small>),
	Pop (Vec2 <Fx32>, Vec2 <Fx32Small>),
	Miss,
}

pub fn fold_closer_result (a: Ray2TraceResult, b: Ray2TraceResult) -> Ray2TraceResult {
	match a {
		Ray2TraceResult::Miss => {
			return b;
		},
		Ray2TraceResult::Hit (a_t, ..) => {
			match b {
				Ray2TraceResult::Miss => {
					return a;
				},
				Ray2TraceResult::Hit (b_t, ..) => {
					if a_t < b_t {
						return a;
					}
					else {
						return b;
					}
				},
				Ray2TraceResult::Pop (..) => {
					return b;
				}
			}
		},
		Ray2TraceResult::Pop (..) => {
			return a;
		},
	}
}

pub fn write_vec2 <T> (writer: &mut T, v: &Vec2 <Fx32>) where T: Write {
	write! (writer, "v {} 0 {}\n", v.x.to_f64 () / 256.0, v.y.to_f64 () / 256.0).unwrap ();
}

pub fn apply_dt (ray: &Ray2, dt: Fx32Small) -> Ray2 {
	Ray2 {
		start: ray.start,
		dir: ray.dir * dt,
	}
}

pub fn test_ray_trace (filename: &str, offset: Fx32) -> Result <(), Error> {
	let scale = 1;
	//let scale_fx = Fx32::from_int (scale);

	let points = vec! [
		Vec2 {x: Fx32::from_q (40, scale), y: Fx32::from_q (470 - 34, scale)},
		Vec2 {x: Fx32::from_q (256, scale), y: Fx32::from_q (512, scale)},
		Vec2 {x: Fx32::from_q (480, scale), y: Fx32::from_q (460, scale)},
	];

	let obstacle = vec! [
	Arc::new1 (&Circle {
		center: points [0],
		radius: Fx32::from_q (20, scale),
	}, points [1]),
	Arc::new2 (&Circle {
		center: points [1],
		radius: Fx32::from_q (20, scale),
	}, points [0], points [2]),
	Arc::new1 (&Circle {
		center: points [2],
		radius: Fx32::from_q (20, scale),
	}, points [1]),
	];

	let lines = vec! [
	WideLine {
		start: points [0],
		end: points [1],
		radius: Fx32::from_q (20, scale),
	},
	WideLine {
		start: points [2],
		end: points [1],
		radius: Fx32::from_q (20, scale),
	},
	];

	let mut num_bounces = 0;
	let mut num_pops = 0;
	let mut num_ticks = 0;

	let inv_dt = 1;
	let gravity = Vec2::<Fx32> {
		x: Fx32::from_q (0, 1),
		y: Fx32::from_q (2, 1),
	};

	let obj_file = try!(File::create(filename));
	let mut writer = BufWriter::new (obj_file);

	let mut vertex_i = 1;
	let mut polyline_start = vertex_i;

	for x in 0..128 {
		let x = x * 4;
		let mut particle = Ray2 {
			start: Vec2 {
				x: Fx32::from_q (x * 2, scale * 2) + offset,
				y: Fx32::from_q (0, scale)
			},
			dir: Vec2 {
				x: Fx32::from_q (0, scale),
				y: Fx32::from_q (1, scale),
			},
		};

		write_vec2 (&mut writer, &particle.start);
		vertex_i += 1;

		let dt = Fx32::from_q (1, inv_dt).to_small ();

		for tick in 0..500 {
			let trace_result = {
				let dt_particle = apply_dt (&particle, dt);

				let point_results = obstacle.iter ().map (|obstacle| ray_trace_arc (&dt_particle, obstacle));

				let line_results = lines.iter ().map (|line| ray_trace_line_2 (&dt_particle, line));

				point_results.chain (line_results).fold ( Ray2TraceResult::Miss, fold_closer_result)
			};

			match trace_result {
				Ray2TraceResult::Miss => {
					//let air_drag = Fx32 { x: particle.dir.length_sq ().x / -16384 };
					//let air_force = particle.dir * air_drag;
					let new_dir = particle.dir + gravity * dt;// + Vec2::<Fx32>::from (air_force * dt);
					/*
					let sum_dir = particle.dir + new_dir;
					let average_dir = Vec2::<Fx32> {
						x: Fx32 { x: sum_dir.x.x / 2 },
						y: Fx32 { x: sum_dir.y.x / 2 },
					};
					*/
					particle.start = particle.start + (particle.dir * dt);
					particle.dir = new_dir;
				},
				Ray2TraceResult::Pop (ccd_pos, normal) => {
					println! ("{}: Pop from {:?} to {:?}", tick, particle.start, ccd_pos);

					let reflected_dir = particle.dir.reflect_res (normal, Fx32::from_q (512, 1024).to_small ());

					let new_dir = reflected_dir;// + gravity * dt;
					/*
					let sum_dir = reflected_dir + new_dir;
					let average_dir = Vec2::<Fx32> {
						x: Fx32 { x: sum_dir.x.x / 2 },
						y: Fx32 { x: sum_dir.y.x / 2 },
					};
					*/
					particle.start = ccd_pos;// + (average_dir * dt);
					if particle.dir * normal < 0 {
						particle.dir = new_dir;
					}

					num_pops += 1;
				},
				Ray2TraceResult::Hit (_, ccd_pos, normal) => {
					println! ("{}: Hit from {:?} to {:?}", tick, particle.start, ccd_pos);

					println! ("Incoming vel {:?}", particle.dir);

					particle.start = ccd_pos;
					if particle.dir * normal < 0 {
						particle.dir = particle.dir.reflect_res (normal, Fx32::from_q (512, 1024).to_small ());
					}

					println! ("Outgoing vel {:?}", particle.dir);

					//particle.dir = normal;
					num_bounces += 1;
				},
			};

			write_vec2 (&mut writer, &particle.start);
			vertex_i += 1;

			num_ticks += 1;

			if particle.start.y > 768 {
				break;
			}
		}

		for i in polyline_start..vertex_i - 1 {
			try! (write! (writer, "f {} {}\n", i, i + 1));
		}
		polyline_start = vertex_i
	}

	println! ("num_bounces: {}", num_bounces);
	println! ("num_pops: {}", num_pops);
	println! ("num_ticks: {}", num_ticks);

	Ok (())
}

pub struct Basis2 {
	pub x: Vec2 <Fx32Small>,
	pub y: Vec2 <Fx32Small>,
}

// Constructs a basis to ray space
// Such that the ray is the X axis
pub fn get_ray_basis (ray: &Ray2, ray_length: Fx32) -> Basis2 {
	let basis_x_big = if ray_length == 0 {
		ray.dir
	}
	else {
		ray.dir / ray_length
	};

	Basis2 {
		x: basis_x_big.to_small (),
		y: basis_x_big.cross ().to_small (),
	}
}

impl Basis2 {
	pub fn to_space (&self, v: &Vec2 <Fx32>) -> Vec2 <Fx32> {
		Vec2::<Fx32> {
			x: *v * self.x,
			y: *v * self.y,
		}
	}

	pub fn from_space (&self, v: &Vec2 <Fx32>) -> Vec2 <Fx32> {
		Vec2::<Fx32> {
			x: (v.x * self.x.x) + (v.y * self.y.x),
			y: (v.x * self.x.y) + (v.y * self.y.y),
		}
	}
}

pub fn ray_trace_line_2 (ray: &Ray2, line: &WideLine) -> Ray2TraceResult {
	let line_tangent: Vec2 <Fx32> = line.end - line.start;
	let huge_normal = line_tangent.cross ();
	let line_tangent = Vec2::<Fx32> {
		x: line_tangent.x * Fx32::from_q (1, 256),
		y: line_tangent.y * Fx32::from_q (1, 256),
	}.normalized ();
	let line_normal = Vec2::<Fx32Small> {
		x: (-Fx32::from (line_tangent.y)).to_small (),
		y: line_tangent.x,
	};

	let ray_end = ray.start + ray.dir;

	let start_along = (ray.start - line.start) * line_tangent;
	let end_along = (ray_end - line.start) * line_tangent;

	// TODO: Probably a way to optimize this into a series of inequalities
	let line_length = (line.end - line.start) * line_tangent;

	if start_along < 0 && end_along < 0 {
		return Ray2TraceResult::Miss;
	}
	if start_along > line_length && end_along > line_length {
		return Ray2TraceResult::Miss;
	}

	let sdf: Fx32 = (ray.start - line.start) * line_normal;

	// Flip the normal so it's towards the ray
	// This will allow us to extrude the correct side
	let line_normal = if sdf > 0 {
		line_normal
	}
	else {
		-line_normal
	};
	let big_normal: Vec2 <Fx32> = line_normal.into ();

	if ray.dir * big_normal > 0 {
		// Ray is leaving the half-plane, leave it be
		return Ray2TraceResult::Miss;
	}

	let start_distance = sdf.abs () - line.radius;
	let end_distance = (ray_end - line.start) * big_normal - line.radius;

	if start_distance < 0 {
		// Ray was already inside the plane, pop it out
		return Ray2TraceResult::Pop (
			ray.start + big_normal * (line.radius - sdf.abs ()),
			line_normal
		);
	}

	if end_distance > 0 {
		// Ray will not reach the plane in this timestep, leave it be
		return Ray2TraceResult::Miss;
	}

	let t = (-start_distance) / (end_distance - start_distance);
	let ccd_pos = ray.start + ray.dir * t;

	let ccd_along = start_along * (Fx32::from_int (1) - t) + end_along * t;

	if ccd_along < 0 {
		return Ray2TraceResult::Miss;
	}
	if ccd_along > line_length {
		return Ray2TraceResult::Miss;
	}

	return Ray2TraceResult::Hit (t, ccd_pos, line_normal);
}

pub fn ray_trace_circle_2 (ray: &Ray2, circle: &Circle) -> Ray2TraceResult {
	let ray_length = ray.dir.length ();
	let basis = get_ray_basis (ray, ray_length);

	let center_in_ray_space = basis.to_space (&(circle.center - ray.start));

	if center_in_ray_space.x < 0 {
		return Ray2TraceResult::Miss;
	}

	if center_in_ray_space.x > ray_length + circle.radius {
		return Ray2TraceResult::Miss;
	}

	if center_in_ray_space.y.abs () >= circle.radius {
		// Prevents a negative root later on
		return Ray2TraceResult::Miss;
	}

	let ray_space_x = center_in_ray_space.x - (circle.radius.square () - center_in_ray_space.y.square ()).sqrt ();

	if ray_space_x > ray_length || ray_length == 0 {
		return Ray2TraceResult::Miss;
	}

	let t = ray_space_x / ray_length;
	let t = Fx32 { x: cmp::max (t.x, Fx32::from_int (0).x) };

	if t <= 1 {
		let ccd_pos = ray.start + ray.dir * t;
		let disp = ccd_pos - circle.center;
		let dist_sq = disp.length_sq ();
		let ccd_pos = if dist_sq < circle.radius.square ()
		{
			circle.center + disp * (circle.radius / dist_sq.sqrt ())
		}
		else {
			ccd_pos
		};

		return Ray2TraceResult::Hit (
			t,
			ccd_pos,
			((ccd_pos - circle.center) / circle.radius).to_small (),
		);
	}
	else {
		return Ray2TraceResult::Miss;
	}
}

pub fn ray_trace_arc (ray: &Ray2, arc: &Arc) -> Ray2TraceResult {
	let circle_result = ray_trace_circle_2 (ray, &arc.circle);
	arc.filter_collision (circle_result)
}
<|endoftext|>


<commit_before>//! Utitilty for writing nagios-style check scripts/plugins
//!
//! There are three things:
//!
//! * The `Status` enum for representing health status
//! * The `procfs` module, which contains rusty representations of some files
//!   from /proc
//! * A few scripts in the bin directory, which contain actual
//!   nagios-compatible scripts
//!
//! TODOs include
//!
//! * Nice logging, including some standard formats -- json and human would be
//!   nice
//! * Some way of easily standardizing command-line args
//! * Much of the code is hideous, and should not be

#[macro_use] extern crate scan_fmt;
#[macro_use] extern crate wrapped_enum;

extern crate regex;
extern crate rustc_serialize;

use std::process;
use std::cmp::{Ord};
use std::fmt;

pub mod procfs;
pub mod scripts;

/// All errors are TurbineErrors
#[derive(Debug)]
pub enum TurbineError {
    /// Represents an incorrect value passed in to a function
    UnknownValue(String)
}

/// All results are TurbineResults
pub type TurbineResult<T> = Result<T, TurbineError>;

/// Represent the nagios-ish error status of a script.
#[must_use]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Status {
    /// Unexpected result
    Unknown,
    /// Everything is fine
    Ok,
    /// Something is weird, but don't necessary call anybody
    Warning,
    /// OMG CALL SOMEONE I DON'T CARE WHAT TIME IT IS
    Critical,
}

impl Status {
    /// Exit with a return code that indicates the state of the system
    pub fn exit(&self) -> ! {
        use self::Status::*;
        match *self {
            Ok => process::exit(0),
            Warning => process::exit(1),
            Critical => process::exit(2),
            Unknown => process::exit(3)
        }
    }

    /// Primarily useful to construct from argv
    pub fn from_str(s: &str) -> TurbineResult<Status> {
        use Status::{Warning, Critical, Unknown};
        match s {
            "ok" => Ok(Status::Ok),
            "warning" => Ok(Warning),
            "critical" => Ok(Critical),
            "unknown" => Ok(Unknown),
            _ => Err(TurbineError::UnknownValue(format!("Unexpected exit status: {}", s)))
        }
    }

    /// The legal values for `from_str`
    pub fn str_values() -> [&'static str; 4] {
        ["ok", "warn", "critical", "unknown"]
    }
}

impl fmt::Display for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Status::*;
        let msg = match *self {
            Ok => "OK",
            Unknown => "UNKNOWN",
            Warning => "WARNING",
            Critical => "CRITICAL"
        };
        write!(f, "{}", msg)
    }
}

#[test]
fn comparison_is_as_expected() {
    use Status::*;
    assert!(Ok < Critical);
    assert!(Ok < Warning);
    assert_eq!(std::cmp::max(Warning, Critical), Critical)
}
<commit_msg>status: correct allowed values<commit_after>//! Utitilty for writing nagios-style check scripts/plugins
//!
//! There are three things:
//!
//! * The `Status` enum for representing health status
//! * The `procfs` module, which contains rusty representations of some files
//!   from /proc
//! * A few scripts in the bin directory, which contain actual
//!   nagios-compatible scripts
//!
//! TODOs include
//!
//! * Nice logging, including some standard formats -- json and human would be
//!   nice
//! * Some way of easily standardizing command-line args
//! * Much of the code is hideous, and should not be

#[macro_use] extern crate scan_fmt;
#[macro_use] extern crate wrapped_enum;

extern crate regex;
extern crate rustc_serialize;

use std::process;
use std::cmp::{Ord};
use std::fmt;

pub mod procfs;
pub mod scripts;

/// All errors are TurbineErrors
#[derive(Debug)]
pub enum TurbineError {
    /// Represents an incorrect value passed in to a function
    UnknownValue(String)
}

/// All results are TurbineResults
pub type TurbineResult<T> = Result<T, TurbineError>;

/// Represent the nagios-ish error status of a script.
#[must_use]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Status {
    /// Unexpected result
    Unknown,
    /// Everything is fine
    Ok,
    /// Something is weird, but don't necessary call anybody
    Warning,
    /// OMG CALL SOMEONE I DON'T CARE WHAT TIME IT IS
    Critical,
}

impl Status {
    /// Exit with a return code that indicates the state of the system
    pub fn exit(&self) -> ! {
        use self::Status::*;
        match *self {
            Ok => process::exit(0),
            Warning => process::exit(1),
            Critical => process::exit(2),
            Unknown => process::exit(3)
        }
    }

    /// Primarily useful to construct from argv
    pub fn from_str(s: &str) -> TurbineResult<Status> {
        use Status::{Warning, Critical, Unknown};
        match s {
            "ok" => Ok(Status::Ok),
            "warning" => Ok(Warning),
            "critical" => Ok(Critical),
            "unknown" => Ok(Unknown),
            _ => Err(TurbineError::UnknownValue(format!("Unexpected exit status: {}", s)))
        }
    }

    /// The legal values for `from_str`
    pub fn str_values() -> [&'static str; 4] {
        ["ok", "warning", "critical", "unknown"]
    }
}

impl fmt::Display for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Status::*;
        let msg = match *self {
            Ok => "OK",
            Unknown => "UNKNOWN",
            Warning => "WARNING",
            Critical => "CRITICAL"
        };
        write!(f, "{}", msg)
    }
}

#[test]
fn comparison_is_as_expected() {
    use Status::*;
    assert!(Ok < Critical);
    assert!(Ok < Warning);
    assert_eq!(std::cmp::max(Warning, Critical), Critical)
}
<|endoftext|>


<commit_before>// Regression test for Issue #53787: Fix ICE when creating a label in inline assembler with macros.

#![feature(asm)]

macro_rules! fake_jump {
    ($id:expr) => {
        unsafe {

            asm!(
            "
            jmp $0
            lea eax, [ebx]
            xor eax, 0xDEADBEEF
            retn
            $0:
            "::"0"($id)::"volatile", "intel");
        }
    };
}

fn main() {
    fake_jump!("FirstFunc"); //~ ERROR invalid value for constraint in inline assembly
    println!("Hello, world!");
}
<commit_msg>Remove trailing whitespace<commit_after>// Regression test for Issue #53787: Fix ICE when creating a label in inline assembler with macros.

#![feature(asm)]

macro_rules! fake_jump {
    ($id:expr) => {
        unsafe {
            asm!(
            "
            jmp $0
            lea eax, [ebx]
            xor eax, 0xDEADBEEF
            retn
            $0:
            "::"0"($id)::"volatile", "intel");
        }
    };
}

fn main() {
    fake_jump!("FirstFunc"); //~ ERROR invalid value for constraint in inline assembly
    println!("Hello, world!");
}
<|endoftext|>


<commit_before>// APIs in FreeBSD 13 that have changed since 11.

pub type nlink_t = u64;
pub type dev_t = u64;
pub type ino_t = ::c_ulong;
pub type shmatt_t = ::c_uint;

s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
    }

    pub struct kevent {
        pub ident: ::uintptr_t,
        pub filter: ::c_short,
        pub flags: ::c_ushort,
        pub fflags: ::c_uint,
        pub data: ::intptr_t,
        pub udata: *mut ::c_void,
        pub ext: [u64; 4],
    }
}

s_no_extra_traits! {
    pub struct dirent {
        pub d_fileno: ::ino_t,
        pub d_off: ::off_t,
        pub d_reclen: u16,
        pub d_type: u8,
        d_pad0: u8,
        pub d_namlen: u16,
        d_pad1: u16,
        pub d_name: [::c_char; 256],
    }

    pub struct statfs {
        pub f_version: u32,
        pub f_type: u32,
        pub f_flags: u64,
        pub f_bsize: u64,
        pub f_iosize: u64,
        pub f_blocks: u64,
        pub f_bfree: u64,
        pub f_bavail: i64,
        pub f_files: u64,
        pub f_ffree: i64,
        pub f_syncwrites: u64,
        pub f_asyncwrites: u64,
        pub f_syncreads: u64,
        pub f_asyncreads: u64,
        f_spare: [u64; 10],
        pub f_namemax: u32,
        pub f_owner: ::uid_t,
        pub f_fsid: ::fsid_t,
        f_charspare: [::c_char; 80],
        pub f_fstypename: [::c_char; 16],
        pub f_mntfromname: [::c_char; 1024],
        pub f_mntonname: [::c_char; 1024],
    }
}

cfg_if! {
    if #[cfg(feature = "extra_traits")] {
        impl PartialEq for statfs {
            fn eq(&self, other: &statfs) -> bool {
                self.f_version == other.f_version
                    && self.f_type == other.f_type
                    && self.f_flags == other.f_flags
                    && self.f_bsize == other.f_bsize
                    && self.f_iosize == other.f_iosize
                    && self.f_blocks == other.f_blocks
                    && self.f_bfree == other.f_bfree
                    && self.f_bavail == other.f_bavail
                    && self.f_files == other.f_files
                    && self.f_ffree == other.f_ffree
                    && self.f_syncwrites == other.f_syncwrites
                    && self.f_asyncwrites == other.f_asyncwrites
                    && self.f_syncreads == other.f_syncreads
                    && self.f_asyncreads == other.f_asyncreads
                    && self.f_namemax == other.f_namemax
                    && self.f_owner == other.f_owner
                    && self.f_fsid == other.f_fsid
                    && self.f_fstypename == other.f_fstypename
                    && self
                    .f_mntfromname
                    .iter()
                    .zip(other.f_mntfromname.iter())
                    .all(|(a,b)| a == b)
                    && self
                    .f_mntonname
                    .iter()
                    .zip(other.f_mntonname.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for statfs {}
        impl ::fmt::Debug for statfs {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("statfs")
                    .field("f_bsize", &self.f_bsize)
                    .field("f_iosize", &self.f_iosize)
                    .field("f_blocks", &self.f_blocks)
                    .field("f_bfree", &self.f_bfree)
                    .field("f_bavail", &self.f_bavail)
                    .field("f_files", &self.f_files)
                    .field("f_ffree", &self.f_ffree)
                    .field("f_syncwrites", &self.f_syncwrites)
                    .field("f_asyncwrites", &self.f_asyncwrites)
                    .field("f_syncreads", &self.f_syncreads)
                    .field("f_asyncreads", &self.f_asyncreads)
                    .field("f_namemax", &self.f_namemax)
                    .field("f_owner", &self.f_owner)
                    .field("f_fsid", &self.f_fsid)
                    .field("f_fstypename", &self.f_fstypename)
                    .field("f_mntfromname", &&self.f_mntfromname[..])
                    .field("f_mntonname", &&self.f_mntonname[..])
                    .finish()
            }
        }
        impl ::hash::Hash for statfs {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.f_version.hash(state);
                self.f_type.hash(state);
                self.f_flags.hash(state);
                self.f_bsize.hash(state);
                self.f_iosize.hash(state);
                self.f_blocks.hash(state);
                self.f_bfree.hash(state);
                self.f_bavail.hash(state);
                self.f_files.hash(state);
                self.f_ffree.hash(state);
                self.f_syncwrites.hash(state);
                self.f_asyncwrites.hash(state);
                self.f_syncreads.hash(state);
                self.f_asyncreads.hash(state);
                self.f_namemax.hash(state);
                self.f_owner.hash(state);
                self.f_fsid.hash(state);
                self.f_charspare.hash(state);
                self.f_fstypename.hash(state);
                self.f_mntfromname.hash(state);
                self.f_mntonname.hash(state);
            }
        }

        impl PartialEq for dirent {
            fn eq(&self, other: &dirent) -> bool {
                self.d_fileno == other.d_fileno
                    && self.d_off == other.d_off
                    && self.d_reclen == other.d_reclen
                    && self.d_type == other.d_type
                    && self.d_namlen == other.d_namlen
                    && self
                    .d_name[..self.d_namlen as _]
                    .iter()
                    .zip(other.d_name.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for dirent {}
        impl ::fmt::Debug for dirent {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("dirent")
                    .field("d_fileno", &self.d_fileno)
                    .field("d_off", &self.d_off)
                    .field("d_reclen", &self.d_reclen)
                    .field("d_type", &self.d_type)
                    .field("d_namlen", &self.d_namlen)
                    .field("d_name", &&self.d_name[..self.d_namlen as _])
                    .finish()
            }
        }
        impl ::hash::Hash for dirent {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.d_fileno.hash(state);
                self.d_off.hash(state);
                self.d_reclen.hash(state);
                self.d_type.hash(state);
                self.d_namlen.hash(state);
                self.d_name[..self.d_namlen as _].hash(state);
            }
        }
    }
}

pub const F_ADD_SEALS: ::c_int = 19;
pub const F_GET_SEALS: ::c_int = 20;
pub const F_SEAL_SEAL: ::c_int = 0x0001;
pub const F_SEAL_SHRINK: ::c_int = 0x0002;
pub const F_SEAL_GROW: ::c_int = 0x0004;
pub const F_SEAL_WRITE: ::c_int = 0x0008;

pub const GRND_NONBLOCK: ::c_uint = 0x1;
pub const GRND_RANDOM: ::c_uint = 0x2;

pub const RAND_MAX: ::c_int = 0x7fff_ffff;

pub const SO_DOMAIN: ::c_int = 0x1019;

pub const EINTEGRITY: ::c_int = 97;
pub const ELAST: ::c_int = 97;
pub const GRND_INSECURE: ::c_uint = 0x4;

extern "C" {
    pub fn aio_readv(aiocbp: *mut ::aiocb) -> ::c_int;
    pub fn aio_writev(aiocbp: *mut ::aiocb) -> ::c_int;
    pub fn setgrent();
    pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) -> ::c_int;
    pub fn freelocale(loc: ::locale_t);
    pub fn msgrcv(
        msqid: ::c_int,
        msgp: *mut ::c_void,
        msgsz: ::size_t,
        msgtyp: ::c_long,
        msgflg: ::c_int,
    ) -> ::ssize_t;
    pub fn clock_nanosleep(
        clk_id: ::clockid_t,
        flags: ::c_int,
        rqtp: *const ::timespec,
        rmtp: *mut ::timespec,
    ) -> ::c_int;

    pub fn fdatasync(fd: ::c_int) -> ::c_int;

    pub fn getrandom(buf: *mut ::c_void, buflen: ::size_t, flags: ::c_uint) -> ::ssize_t;
    pub fn elf_aux_info(aux: ::c_int, buf: *mut ::c_void, buflen: ::c_int) -> ::c_int;
}

cfg_if! {
    if #[cfg(any(target_arch = "x86_64",
                 target_arch = "aarch64"))] {
        mod b64;
        pub use self::b64::*;
    }
}
<commit_msg>Auto merge of #2163 - devnexen:android_upd_getentropy, r=JohnTitor<commit_after>// APIs in FreeBSD 13 that have changed since 11.

pub type nlink_t = u64;
pub type dev_t = u64;
pub type ino_t = ::c_ulong;
pub type shmatt_t = ::c_uint;

s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
    }

    pub struct kevent {
        pub ident: ::uintptr_t,
        pub filter: ::c_short,
        pub flags: ::c_ushort,
        pub fflags: ::c_uint,
        pub data: ::intptr_t,
        pub udata: *mut ::c_void,
        pub ext: [u64; 4],
    }
}

s_no_extra_traits! {
    pub struct dirent {
        pub d_fileno: ::ino_t,
        pub d_off: ::off_t,
        pub d_reclen: u16,
        pub d_type: u8,
        d_pad0: u8,
        pub d_namlen: u16,
        d_pad1: u16,
        pub d_name: [::c_char; 256],
    }

    pub struct statfs {
        pub f_version: u32,
        pub f_type: u32,
        pub f_flags: u64,
        pub f_bsize: u64,
        pub f_iosize: u64,
        pub f_blocks: u64,
        pub f_bfree: u64,
        pub f_bavail: i64,
        pub f_files: u64,
        pub f_ffree: i64,
        pub f_syncwrites: u64,
        pub f_asyncwrites: u64,
        pub f_syncreads: u64,
        pub f_asyncreads: u64,
        f_spare: [u64; 10],
        pub f_namemax: u32,
        pub f_owner: ::uid_t,
        pub f_fsid: ::fsid_t,
        f_charspare: [::c_char; 80],
        pub f_fstypename: [::c_char; 16],
        pub f_mntfromname: [::c_char; 1024],
        pub f_mntonname: [::c_char; 1024],
    }
}

cfg_if! {
    if #[cfg(feature = "extra_traits")] {
        impl PartialEq for statfs {
            fn eq(&self, other: &statfs) -> bool {
                self.f_version == other.f_version
                    && self.f_type == other.f_type
                    && self.f_flags == other.f_flags
                    && self.f_bsize == other.f_bsize
                    && self.f_iosize == other.f_iosize
                    && self.f_blocks == other.f_blocks
                    && self.f_bfree == other.f_bfree
                    && self.f_bavail == other.f_bavail
                    && self.f_files == other.f_files
                    && self.f_ffree == other.f_ffree
                    && self.f_syncwrites == other.f_syncwrites
                    && self.f_asyncwrites == other.f_asyncwrites
                    && self.f_syncreads == other.f_syncreads
                    && self.f_asyncreads == other.f_asyncreads
                    && self.f_namemax == other.f_namemax
                    && self.f_owner == other.f_owner
                    && self.f_fsid == other.f_fsid
                    && self.f_fstypename == other.f_fstypename
                    && self
                    .f_mntfromname
                    .iter()
                    .zip(other.f_mntfromname.iter())
                    .all(|(a,b)| a == b)
                    && self
                    .f_mntonname
                    .iter()
                    .zip(other.f_mntonname.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for statfs {}
        impl ::fmt::Debug for statfs {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("statfs")
                    .field("f_bsize", &self.f_bsize)
                    .field("f_iosize", &self.f_iosize)
                    .field("f_blocks", &self.f_blocks)
                    .field("f_bfree", &self.f_bfree)
                    .field("f_bavail", &self.f_bavail)
                    .field("f_files", &self.f_files)
                    .field("f_ffree", &self.f_ffree)
                    .field("f_syncwrites", &self.f_syncwrites)
                    .field("f_asyncwrites", &self.f_asyncwrites)
                    .field("f_syncreads", &self.f_syncreads)
                    .field("f_asyncreads", &self.f_asyncreads)
                    .field("f_namemax", &self.f_namemax)
                    .field("f_owner", &self.f_owner)
                    .field("f_fsid", &self.f_fsid)
                    .field("f_fstypename", &self.f_fstypename)
                    .field("f_mntfromname", &&self.f_mntfromname[..])
                    .field("f_mntonname", &&self.f_mntonname[..])
                    .finish()
            }
        }
        impl ::hash::Hash for statfs {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.f_version.hash(state);
                self.f_type.hash(state);
                self.f_flags.hash(state);
                self.f_bsize.hash(state);
                self.f_iosize.hash(state);
                self.f_blocks.hash(state);
                self.f_bfree.hash(state);
                self.f_bavail.hash(state);
                self.f_files.hash(state);
                self.f_ffree.hash(state);
                self.f_syncwrites.hash(state);
                self.f_asyncwrites.hash(state);
                self.f_syncreads.hash(state);
                self.f_asyncreads.hash(state);
                self.f_namemax.hash(state);
                self.f_owner.hash(state);
                self.f_fsid.hash(state);
                self.f_charspare.hash(state);
                self.f_fstypename.hash(state);
                self.f_mntfromname.hash(state);
                self.f_mntonname.hash(state);
            }
        }

        impl PartialEq for dirent {
            fn eq(&self, other: &dirent) -> bool {
                self.d_fileno == other.d_fileno
                    && self.d_off == other.d_off
                    && self.d_reclen == other.d_reclen
                    && self.d_type == other.d_type
                    && self.d_namlen == other.d_namlen
                    && self
                    .d_name[..self.d_namlen as _]
                    .iter()
                    .zip(other.d_name.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for dirent {}
        impl ::fmt::Debug for dirent {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("dirent")
                    .field("d_fileno", &self.d_fileno)
                    .field("d_off", &self.d_off)
                    .field("d_reclen", &self.d_reclen)
                    .field("d_type", &self.d_type)
                    .field("d_namlen", &self.d_namlen)
                    .field("d_name", &&self.d_name[..self.d_namlen as _])
                    .finish()
            }
        }
        impl ::hash::Hash for dirent {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.d_fileno.hash(state);
                self.d_off.hash(state);
                self.d_reclen.hash(state);
                self.d_type.hash(state);
                self.d_namlen.hash(state);
                self.d_name[..self.d_namlen as _].hash(state);
            }
        }
    }
}

pub const F_ADD_SEALS: ::c_int = 19;
pub const F_GET_SEALS: ::c_int = 20;
pub const F_SEAL_SEAL: ::c_int = 0x0001;
pub const F_SEAL_SHRINK: ::c_int = 0x0002;
pub const F_SEAL_GROW: ::c_int = 0x0004;
pub const F_SEAL_WRITE: ::c_int = 0x0008;

pub const GRND_NONBLOCK: ::c_uint = 0x1;
pub const GRND_RANDOM: ::c_uint = 0x2;

pub const RAND_MAX: ::c_int = 0x7fff_ffff;

pub const SO_DOMAIN: ::c_int = 0x1019;

pub const EINTEGRITY: ::c_int = 97;
pub const ELAST: ::c_int = 97;
pub const GRND_INSECURE: ::c_uint = 0x4;

extern "C" {
    pub fn aio_readv(aiocbp: *mut ::aiocb) -> ::c_int;
    pub fn aio_writev(aiocbp: *mut ::aiocb) -> ::c_int;
    pub fn setgrent();
    pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) -> ::c_int;
    pub fn freelocale(loc: ::locale_t);
    pub fn msgrcv(
        msqid: ::c_int,
        msgp: *mut ::c_void,
        msgsz: ::size_t,
        msgtyp: ::c_long,
        msgflg: ::c_int,
    ) -> ::ssize_t;
    pub fn clock_nanosleep(
        clk_id: ::clockid_t,
        flags: ::c_int,
        rqtp: *const ::timespec,
        rmtp: *mut ::timespec,
    ) -> ::c_int;

    pub fn fdatasync(fd: ::c_int) -> ::c_int;

    pub fn getrandom(buf: *mut ::c_void, buflen: ::size_t, flags: ::c_uint) -> ::ssize_t;
    pub fn getentropy(buf: *mut ::c_void, buflen: ::size_t) -> ::c_int;
    pub fn elf_aux_info(aux: ::c_int, buf: *mut ::c_void, buflen: ::c_int) -> ::c_int;
}

cfg_if! {
    if #[cfg(any(target_arch = "x86_64",
                 target_arch = "aarch64"))] {
        mod b64;
        pub use self::b64::*;
    }
}
<|endoftext|>