<commit_before>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Implements a stub PCI device. This can be used to put a device on the PCI bus that will
//! show up in PCI device enumeration with the configured parameters. The device will otherwise be
//! non-functional, in particular it doesn't have any BARs, IRQs etc. and neither will it handle
//! config register interactions.
//!
//! The motivation for stub PCI devices is the case of multifunction PCI devices getting passed
//! through via VFIO to the guest. Per PCI device enumeration, functions other than 0 will only be
//! scanned if function 0 is present. A stub PCI device is useful in that situation to present
//! something to the guest on function 0.

use base::RawDescriptor;
use resources::{Alloc, SystemAllocator};

use crate::pci::pci_configuration::{
    PciBarConfiguration, PciClassCode, PciConfiguration, PciHeaderType, PciProgrammingInterface,
    PciSubclass,
};
use crate::pci::pci_device::{PciDevice, Result};
use crate::pci::{PciAddress, PciDeviceError};

pub struct StubPciParameters {
    pub address: PciAddress,
    pub vendor_id: u16,
    pub device_id: u16,
    pub class: PciClassCode,
    pub subclass: u8,
    pub programming_interface: u8,
    pub multifunction: bool,
    pub subsystem_device_id: u16,
    pub subsystem_vendor_id: u16,
    pub revision_id: u8,
}

pub struct StubPciDevice {
    requested_address: PciAddress,
    assigned_address: Option<PciAddress>,
    config_regs: PciConfiguration,
}

struct NumericPciSubClass(u8);

impl PciSubclass for NumericPciSubClass {
    fn get_register_value(&self) -> u8 {
        self.0
    }
}

struct NumericPciProgrammingInterface(u8);

impl PciProgrammingInterface for NumericPciProgrammingInterface {
    fn get_register_value(&self) -> u8 {
        self.0
    }
}

impl StubPciDevice {
    pub fn new(config: &StubPciParameters) -> StubPciDevice {
        let config_regs = PciConfiguration::new(
            config.vendor_id,
            config.device_id,
            config.class,
            &NumericPciSubClass(config.subclass),
            Some(&NumericPciProgrammingInterface(
                config.programming_interface,
            )),
            PciHeaderType::Device,
            config.multifunction,
            config.subsystem_device_id,
            config.subsystem_vendor_id,
            config.revision_id,
        );

        Self {
            requested_address: config.address,
            assigned_address: None,
            config_regs,
        }
    }
}

impl PciDevice for StubPciDevice {
    fn debug_label(&self) -> String {
        "Stub".to_owned()
    }

    fn allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress> {
        if self.assigned_address.is_none() {
            if resources.reserve_pci(
                Alloc::PciBar {
                    bus: self.requested_address.bus,
                    dev: self.requested_address.dev,
                    func: self.requested_address.func,
                    bar: 0,
                },
                self.debug_label(),
            ) {
                self.assigned_address = Some(self.requested_address);
            }
        }
        self.assigned_address
            .ok_or(PciDeviceError::PciAllocationFailed)
    }

    fn keep_rds(&self) -> Vec<RawDescriptor> {
        Vec::new()
    }

    fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
        self.config_regs.get_bar_configuration(bar_num)
    }

    fn read_config_register(&self, reg_idx: usize) -> u32 {
        self.config_regs.read_reg(reg_idx)
    }

    fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
        (&mut self.config_regs).write_reg(reg_idx, offset, data)
    }

    fn read_bar(&mut self, _addr: u64, _data: &mut [u8]) {}

    fn write_bar(&mut self, _addr: u64, _data: &[u8]) {}
}
<commit_msg>Correct subsystem_{vendor,id} mixup in StubPciDevice<commit_after>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Implements a stub PCI device. This can be used to put a device on the PCI bus that will
//! show up in PCI device enumeration with the configured parameters. The device will otherwise be
//! non-functional, in particular it doesn't have any BARs, IRQs etc. and neither will it handle
//! config register interactions.
//!
//! The motivation for stub PCI devices is the case of multifunction PCI devices getting passed
//! through via VFIO to the guest. Per PCI device enumeration, functions other than 0 will only be
//! scanned if function 0 is present. A stub PCI device is useful in that situation to present
//! something to the guest on function 0.

use base::RawDescriptor;
use resources::{Alloc, SystemAllocator};

use crate::pci::pci_configuration::{
    PciBarConfiguration, PciClassCode, PciConfiguration, PciHeaderType, PciProgrammingInterface,
    PciSubclass,
};
use crate::pci::pci_device::{PciDevice, Result};
use crate::pci::{PciAddress, PciDeviceError};

pub struct StubPciParameters {
    pub address: PciAddress,
    pub vendor_id: u16,
    pub device_id: u16,
    pub class: PciClassCode,
    pub subclass: u8,
    pub programming_interface: u8,
    pub multifunction: bool,
    pub subsystem_vendor_id: u16,
    pub subsystem_device_id: u16,
    pub revision_id: u8,
}

pub struct StubPciDevice {
    requested_address: PciAddress,
    assigned_address: Option<PciAddress>,
    config_regs: PciConfiguration,
}

struct NumericPciSubClass(u8);

impl PciSubclass for NumericPciSubClass {
    fn get_register_value(&self) -> u8 {
        self.0
    }
}

struct NumericPciProgrammingInterface(u8);

impl PciProgrammingInterface for NumericPciProgrammingInterface {
    fn get_register_value(&self) -> u8 {
        self.0
    }
}

impl StubPciDevice {
    pub fn new(config: &StubPciParameters) -> StubPciDevice {
        let config_regs = PciConfiguration::new(
            config.vendor_id,
            config.device_id,
            config.class,
            &NumericPciSubClass(config.subclass),
            Some(&NumericPciProgrammingInterface(
                config.programming_interface,
            )),
            PciHeaderType::Device,
            config.multifunction,
            config.subsystem_vendor_id,
            config.subsystem_device_id,
            config.revision_id,
        );

        Self {
            requested_address: config.address,
            assigned_address: None,
            config_regs,
        }
    }
}

impl PciDevice for StubPciDevice {
    fn debug_label(&self) -> String {
        "Stub".to_owned()
    }

    fn allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress> {
        if self.assigned_address.is_none() {
            if resources.reserve_pci(
                Alloc::PciBar {
                    bus: self.requested_address.bus,
                    dev: self.requested_address.dev,
                    func: self.requested_address.func,
                    bar: 0,
                },
                self.debug_label(),
            ) {
                self.assigned_address = Some(self.requested_address);
            }
        }
        self.assigned_address
            .ok_or(PciDeviceError::PciAllocationFailed)
    }

    fn keep_rds(&self) -> Vec<RawDescriptor> {
        Vec::new()
    }

    fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
        self.config_regs.get_bar_configuration(bar_num)
    }

    fn read_config_register(&self, reg_idx: usize) -> u32 {
        self.config_regs.read_reg(reg_idx)
    }

    fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
        (&mut self.config_regs).write_reg(reg_idx, offset, data)
    }

    fn read_bar(&mut self, _addr: u64, _data: &mut [u8]) {}

    fn write_bar(&mut self, _addr: u64, _data: &[u8]) {}
}

#[cfg(test)]
mod test {
    use super::*;

    const CONFIG: StubPciParameters = StubPciParameters {
        address: PciAddress {
            bus: 0x0a,
            dev: 0x0b,
            func: 0x1,
        },
        vendor_id: 2,
        device_id: 3,
        class: PciClassCode::MultimediaController,
        subclass: 5,
        programming_interface: 6,
        multifunction: true,
        subsystem_vendor_id: 7,
        subsystem_device_id: 8,
        revision_id: 9,
    };

    #[test]
    fn configuration() {
        let device = StubPciDevice::new(&CONFIG);

        assert_eq!(device.read_config_register(0), 0x0003_0002);
        assert_eq!(device.read_config_register(2), 0x04_05_06_09);
        assert!((device.read_config_register(3) & 0x0080_0000) != 0);
        assert_eq!(device.read_config_register(11), 0x0008_0007);
    }

    #[test]
    fn address_allocation() {
        let mut allocator = SystemAllocator::builder()
            .add_io_addresses(0x1000_0000, 0x1000_0000)
            .add_low_mmio_addresses(0x2000_0000, 0x1000_0000)
            .add_high_mmio_addresses(0x3000_0000, 0x1000_0000)
            .create_allocator(5)
            .unwrap();
        let mut device = StubPciDevice::new(&CONFIG);

        assert!(device.allocate_address(&mut allocator).is_ok());
        assert!(allocator.release_pci(0xa, 0xb, 1));
    }
}
<|endoftext|>


<commit_before>#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
use crate::INVALID_UTF8;
use std::ffi::OsStr;
#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
use std::os::unix::ffi::OsStrExt;

#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
pub(crate) trait OsStrExt3 {
    fn from_bytes(b: &[u8]) -> &Self;
    fn as_bytes(&self) -> &[u8];
}

pub(crate) trait OsStrExt2 {
    fn starts_with(&self, s: &[u8]) -> bool;
    fn split_at_byte(&self, b: u8) -> (&OsStr, &OsStr);
    fn split_at(&self, i: usize) -> (&OsStr, &OsStr);
    fn trim_start_matches(&self, b: u8) -> &OsStr;
    fn trim_start_n_matches(&self, n: usize, ch: u8) -> &OsStr;
    fn contains_byte(&self, b: u8) -> bool;
    fn split(&self, b: u8) -> OsSplit;
}

#[cfg(target_os = "windows")]
impl OsStrExt3 for OsStr {
    #[allow(clippy::transmute_ptr_to_ptr)]
    fn from_bytes(b: &[u8]) -> &Self {
        use std::mem;
        unsafe { mem::transmute(b) }
    }
    fn as_bytes(&self) -> &[u8] {
        self.to_str().map(|s| s.as_bytes()).expect(INVALID_UTF8)
    }
}

impl OsStrExt2 for OsStr {
    fn starts_with(&self, s: &[u8]) -> bool {
        self.as_bytes().starts_with(s)
    }

    fn contains_byte(&self, byte: u8) -> bool {
        for b in self.as_bytes() {
            if b == &byte {
                return true;
            }
        }
        false
    }

    fn split_at_byte(&self, byte: u8) -> (&OsStr, &OsStr) {
        for (i, b) in self.as_bytes().iter().enumerate() {
            if b == &byte {
                return (
                    OsStr::from_bytes(&self.as_bytes()[..i]),
                    OsStr::from_bytes(&self.as_bytes()[i..]),
                );
            }
        }
        (&*self, OsStr::from_bytes(&[]))
    }

    fn trim_start_matches(&self, byte: u8) -> &OsStr {
        let mut found = false;
        for (i, b) in self.as_bytes().iter().enumerate() {
            if b != &byte {
                return OsStr::from_bytes(&self.as_bytes()[i..]);
            } else {
                found = true;
            }
        }
        if found {
            return OsStr::from_bytes(&self.as_bytes()[self.len()..]);
        }
        &*self
    }

    // Like `trim_start_matches`, but trims no more than `n` matches
    #[inline]
    fn trim_start_n_matches(&self, n: usize, ch: u8) -> &OsStr {
        let i = self
            .as_bytes()
            .into_iter()
            .take(n)
            .take_while(|c| **c == ch)
            .enumerate()
            .last()
            .map(|(i, _)| i + 1)
            .unwrap_or(0);

        self.split_at(i).1
    }

    fn split_at(&self, i: usize) -> (&OsStr, &OsStr) {
        (
            OsStr::from_bytes(&self.as_bytes()[..i]),
            OsStr::from_bytes(&self.as_bytes()[i..]),
        )
    }

    fn split(&self, b: u8) -> OsSplit {
        OsSplit {
            sep: b,
            val: self.as_bytes(),
            pos: 0,
        }
    }
}

#[derive(Clone, Debug)]
pub(crate) struct OsSplit<'a> {
    sep: u8,
    val: &'a [u8],
    pos: usize,
}

impl<'a> Iterator for OsSplit<'a> {
    type Item = &'a OsStr;

    fn next(&mut self) -> Option<&'a OsStr> {
        debugln!("OsSplit::next: self={:?}", self);
        if self.pos == self.val.len() {
            return None;
        }
        let start = self.pos;
        for b in &self.val[start..] {
            self.pos += 1;
            if *b == self.sep {
                return Some(OsStr::from_bytes(&self.val[start..self.pos - 1]));
            }
        }
        Some(OsStr::from_bytes(&self.val[start..]))
    }
}
<commit_msg>cargo clippy<commit_after>#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
use crate::INVALID_UTF8;
use std::ffi::OsStr;
#[cfg(not(any(target_os = "windows", target_arch = "wasm32")))]
use std::os::unix::ffi::OsStrExt;

#[cfg(any(target_os = "windows", target_arch = "wasm32"))]
pub(crate) trait OsStrExt3 {
    fn from_bytes(b: &[u8]) -> &Self;
    fn as_bytes(&self) -> &[u8];
}

pub(crate) trait OsStrExt2 {
    fn starts_with(&self, s: &[u8]) -> bool;
    fn split_at_byte(&self, b: u8) -> (&OsStr, &OsStr);
    fn split_at(&self, i: usize) -> (&OsStr, &OsStr);
    fn trim_start_matches(&self, b: u8) -> &OsStr;
    fn trim_start_n_matches(&self, n: usize, ch: u8) -> &OsStr;
    fn contains_byte(&self, b: u8) -> bool;
    fn split(&self, b: u8) -> OsSplit;
}

#[cfg(target_os = "windows")]
impl OsStrExt3 for OsStr {
    #[allow(clippy::transmute_ptr_to_ptr)]
    fn from_bytes(b: &[u8]) -> &Self {
        use std::mem;
        unsafe { mem::transmute(b) }
    }
    fn as_bytes(&self) -> &[u8] {
        self.to_str().map(|s| s.as_bytes()).expect(INVALID_UTF8)
    }
}

impl OsStrExt2 for OsStr {
    fn starts_with(&self, s: &[u8]) -> bool {
        self.as_bytes().starts_with(s)
    }

    fn contains_byte(&self, byte: u8) -> bool {
        for b in self.as_bytes() {
            if b == &byte {
                return true;
            }
        }
        false
    }

    fn split_at_byte(&self, byte: u8) -> (&OsStr, &OsStr) {
        for (i, b) in self.as_bytes().iter().enumerate() {
            if b == &byte {
                return (
                    OsStr::from_bytes(&self.as_bytes()[..i]),
                    OsStr::from_bytes(&self.as_bytes()[i..]),
                );
            }
        }
        (&*self, OsStr::from_bytes(&[]))
    }

    fn trim_start_matches(&self, byte: u8) -> &OsStr {
        let mut found = false;
        for (i, b) in self.as_bytes().iter().enumerate() {
            if b != &byte {
                return OsStr::from_bytes(&self.as_bytes()[i..]);
            } else {
                found = true;
            }
        }
        if found {
            return OsStr::from_bytes(&self.as_bytes()[self.len()..]);
        }
        &*self
    }

    // Like `trim_start_matches`, but trims no more than `n` matches
    #[inline]
    fn trim_start_n_matches(&self, n: usize, ch: u8) -> &OsStr {
        let i = self
            .as_bytes()
            .iter()
            .take(n)
            .take_while(|c| **c == ch)
            .enumerate()
            .last()
            .map(|(i, _)| i + 1)
            .unwrap_or(0);

        self.split_at(i).1
    }

    fn split_at(&self, i: usize) -> (&OsStr, &OsStr) {
        (
            OsStr::from_bytes(&self.as_bytes()[..i]),
            OsStr::from_bytes(&self.as_bytes()[i..]),
        )
    }

    fn split(&self, b: u8) -> OsSplit {
        OsSplit {
            sep: b,
            val: self.as_bytes(),
            pos: 0,
        }
    }
}

#[derive(Clone, Debug)]
pub(crate) struct OsSplit<'a> {
    sep: u8,
    val: &'a [u8],
    pos: usize,
}

impl<'a> Iterator for OsSplit<'a> {
    type Item = &'a OsStr;

    fn next(&mut self) -> Option<&'a OsStr> {
        debugln!("OsSplit::next: self={:?}", self);
        if self.pos == self.val.len() {
            return None;
        }
        let start = self.pos;
        for b in &self.val[start..] {
            self.pos += 1;
            if *b == self.sep {
                return Some(OsStr::from_bytes(&self.val[start..self.pos - 1]));
            }
        }
        Some(OsStr::from_bytes(&self.val[start..]))
    }
}
<|endoftext|>


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

// spell-checker:ignore (ToDO) lflag ICANON tcgetattr tcsetattr TCSADRAIN

#[macro_use]
extern crate uucore;

use std::{
    convert::TryInto,
    fs::File,
    io::{stdin, stdout, BufReader, Read, Stdout, Write},
    path::Path,
    time::Duration,
};

#[cfg(all(unix, not(target_os = "fuchsia")))]
extern crate nix;

use clap::{App, Arg};
use crossterm::{
    event::{self, Event, KeyCode, KeyEvent, KeyModifiers},
    execute, queue,
    style::Attribute,
    terminal,
};

pub mod options {
    pub const SILENT: &str = "silent";
    pub const LOGICAL: &str = "logical";
    pub const NO_PAUSE: &str = "no-pause";
    pub const PRINT_OVER: &str = "print-over";
    pub const CLEAN_PRINT: &str = "clean-print";
    pub const SQUEEZE: &str = "squeeze";
    pub const PLAIN: &str = "plain";
    pub const LINES: &str = "lines";
    pub const NUMBER: &str = "number";
    pub const PATTERN: &str = "pattern";
    pub const FROM_LINE: &str = "from-line";
    pub const FILES: &str = "files";
}

const MULTI_FILE_TOP_PROMPT: &str = "::::::::::::::\n{}\n::::::::::::::\n";

pub fn uumain(args: impl uucore::Args) -> i32 {
    let matches = App::new(executable!())
        .about("A file perusal filter for CRT viewing.")
        .version(env!("CARGO_PKG_VERSION"))
        .arg(
            Arg::with_name(options::SILENT)
                .short("d")
                .long(options::SILENT)
                .help("Display help instead of ringing bell"),
        )
        .arg(
            Arg::with_name(options::LOGICAL)
                .short("f")
                .long(options::LOGICAL)
                .help("Count logical rather than screen lines"),
        )
        .arg(
            Arg::with_name(options::NO_PAUSE)
                .short("l")
                .long(options::NO_PAUSE)
                .help("Suppress pause after form feed"),
        )
        .arg(
            Arg::with_name(options::PRINT_OVER)
                .short("c")
                .long(options::PRINT_OVER)
                .help("Do not scroll, display text and clean line ends"),
        )
        .arg(
            Arg::with_name(options::CLEAN_PRINT)
                .short("p")
                .long(options::CLEAN_PRINT)
                .help("Do not scroll, clean screen and display text"),
        )
        .arg(
            Arg::with_name(options::SQUEEZE)
                .short("s")
                .long(options::SQUEEZE)
                .help("Squeeze multiple blank lines into one"),
        )
        .arg(
            Arg::with_name(options::PLAIN)
                .short("u")
                .long(options::PLAIN)
                .help("Suppress underlining and bold"),
        )
        .arg(
            Arg::with_name(options::LINES)
                .short("n")
                .long(options::LINES)
                .value_name("number")
                .takes_value(true)
                .help("The number of lines per screenful"),
        )
        .arg(
            Arg::with_name(options::NUMBER)
                .allow_hyphen_values(true)
                .long(options::NUMBER)
                .required(false)
                .takes_value(true)
                .help("Same as --lines"),
        )
        .arg(
            Arg::with_name(options::FROM_LINE)
                .short("F")
                .allow_hyphen_values(true)
                .required(false)
                .takes_value(true)
                .value_name("number")
                .help("Display file beginning from line number"),
        )
        .arg(
            Arg::with_name(options::PATTERN)
                .short("P")
                .allow_hyphen_values(true)
                .required(false)
                .takes_value(true)
                .help("Display file beginning from pattern match"),
        )
        .arg(
            Arg::with_name(options::FILES)
                .required(false)
                .multiple(true)
                .help("Path to the files to be read"),
        )
        .get_matches_from(args);
    let mut buff = String::new();
    let mut stdout = setup_term();
    if let Some(filenames) = matches.values_of(options::FILES) {
        let length = filenames.len();
        for (idx, fname) in filenames.clone().enumerate() {
            let fname = Path::new(fname);
            if fname.is_dir() {
                terminal::disable_raw_mode().unwrap();
                show_usage_error!("'{}' is a directory.", fname.display());
                return 1;
            }
            if !fname.exists() {
                terminal::disable_raw_mode().unwrap();
                eprintln!(
                    "{}: cannot open {}: No such file or directory",
                    executable!(),
                    fname.display()
                );
                return 1;
            }
            if filenames.len() > 1 {
                buff.push_str(&MULTI_FILE_TOP_PROMPT.replace("{}", fname.to_str().unwrap()));
            }
            let mut reader = BufReader::new(File::open(fname).unwrap());
            reader.read_to_string(&mut buff).unwrap();
            let last = idx + 1 == length;
            more(&buff, &mut stdout, last);
            buff.clear();
        }
        reset_term(&mut stdout);
    } else {
        if atty::isnt(atty::Stream::Stdin) {
            let mut stdout = setup_term();
            stdin().read_to_string(&mut buff).unwrap();
            more(&buff, &mut stdout, true);
        } else {
            terminal::disable_raw_mode().unwrap();
            show_usage_error!("bad usage");
        }
    }
    0
}

#[cfg(not(target_os = "fuchsia"))]
fn setup_term() -> std::io::Stdout {
    let stdout = stdout();
    terminal::enable_raw_mode().unwrap();
    stdout
}

#[cfg(target_os = "fuchsia")]
#[inline(always)]
fn setup_term() -> usize {
    0
}

#[cfg(not(target_os = "fuchsia"))]
fn reset_term(stdout: &mut std::io::Stdout) {
    terminal::disable_raw_mode().unwrap();
    // Clear the prompt
    queue!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
    // Move cursor to the beginning without printing new line
    print!("\r");
    stdout.flush().unwrap();
}

#[cfg(target_os = "fuchsia")]
#[inline(always)]
fn reset_term(_: &mut usize) {}

fn more(buff: &str, mut stdout: &mut Stdout, is_last: bool) {
    let (cols, rows) = terminal::size().unwrap();
    let lines = break_buff(buff, usize::from(cols));
    let line_count: u16 = lines.len().try_into().unwrap();

    // Print everything and quit if line count is less than the availale rows
    if line_count < rows {
        println!("{}", buff);
        return;
    }

    let mut upper_mark = 0;
    // Number of lines left
    let mut lines_left = line_count - (upper_mark + rows);
    // Are we on the very last page and the next down arrow will return this function
    let mut to_be_done = false;
    draw(
        &mut upper_mark,
        rows,
        &mut stdout,
        lines.clone(),
        line_count,
    );

    loop {
        if event::poll(Duration::from_millis(10)).unwrap() {
            match event::read().unwrap() {
                Event::Key(KeyEvent {
                    code: KeyCode::Char('q'),
                    modifiers: KeyModifiers::NONE,
                })
                | Event::Key(KeyEvent {
                    code: KeyCode::Char('c'),
                    modifiers: KeyModifiers::CONTROL,
                }) => {
                    reset_term(&mut stdout);
                    std::process::exit(0);
                }
                Event::Key(KeyEvent {
                    code: KeyCode::Down,
                    modifiers: KeyModifiers::NONE,
                })
                | Event::Key(KeyEvent {
                    code: KeyCode::Char(' '),
                    modifiers: KeyModifiers::NONE,
                }) => {
                    // If this is the last page but some text
                    // is still left that does not require a page of its own
                    // then this event will print the left lines
                    if lines_left < rows && !to_be_done {
                        for l in lines.iter().skip((line_count - upper_mark - rows).into()) {
                            stdout.write_all(format!("\r{}\n", l).as_bytes()).unwrap();
                        }
                        make_prompt_and_flush(&mut stdout, line_count, line_count);
                        // If this is not the last input file
                        // do not return, but the next down arrow must return
                        // because we have printed everyhing
                        if !is_last {
                            to_be_done = true;
                        } else {
                            // Else quit
                            reset_term(&mut stdout);
                            return;
                        }
                        // This handles the next arrow key to quit
                    } else if lines_left < rows && to_be_done {
                        return;
                    } else {
                        // Print a normal page
                        upper_mark = upper_mark.saturating_add(rows.saturating_sub(1));
                        lines_left = line_count.saturating_sub(upper_mark + rows);
                        draw(
                            &mut upper_mark,
                            rows,
                            &mut stdout,
                            lines.clone(),
                            line_count,
                        );
                    }
                }
                Event::Key(KeyEvent {
                    code: KeyCode::Up,
                    modifiers: KeyModifiers::NONE,
                }) => {
                    upper_mark = upper_mark.saturating_sub(rows.saturating_sub(1));
                    draw(
                        &mut upper_mark,
                        rows,
                        &mut stdout,
                        lines.clone(),
                        line_count,
                    );
                }
                _ => continue,
            }
        }
    }
}

fn draw(
    upper_mark: &mut u16,
    rows: u16,
    mut stdout: &mut std::io::Stdout,
    lines: Vec<String>,
    lc: u16,
) {
    execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
    let (up_mark, lower_mark) = calc_range(*upper_mark, rows, lc);
    // Reduce the row by 1 for the prompt
    let displayed_lines = lines
        .iter()
        .skip(up_mark.into())
        .take(usize::from(rows.saturating_sub(1)));

    for line in displayed_lines {
        stdout
            .write_all(format!("\r{}\n", line).as_bytes())
            .unwrap();
    }
    make_prompt_and_flush(&mut stdout, lower_mark, lc);
    *upper_mark = up_mark;
}

// Break the lines on the cols of the terminal
fn break_buff(buff: &str, cols: usize) -> Vec<String> {
    let mut lines = Vec::new();

    for l in buff.lines() {
        lines.append(&mut break_line(l, cols));
    }
    lines
}

fn break_line(mut line: &str, cols: usize) -> Vec<String> {
    let breaks = (line.len() / cols).saturating_add(1);
    let mut lines = Vec::with_capacity(breaks);
    if line.len() < cols {
        lines.push(line.to_string());
        return lines;
    }

    for _ in 1..=breaks {
        let (line1, line2) = line.split_at(cols);
        lines.push(line1.to_string());
        if line2.len() < cols {
            lines.push(line2.to_string());
            break;
        }
        line = line2;
    }
    lines
}

// Calculate upper_mark based on certain parameters
fn calc_range(mut upper_mark: u16, rows: u16, line_count: u16) -> (u16, u16) {
    let mut lower_mark = upper_mark.saturating_add(rows);

    if lower_mark >= line_count {
        upper_mark = line_count.saturating_sub(rows);
        lower_mark = line_count;
    } else {
        lower_mark = lower_mark.saturating_sub(1)
    }
    (upper_mark, lower_mark)
}

// Make a prompt similar to original more
fn make_prompt_and_flush(stdout: &mut Stdout, lower_mark: u16, lc: u16) {
    write!(
        stdout,
        "\r{}--More--({}%){}",
        Attribute::Reverse,
        ((lower_mark as f64 / lc as f64) * 100.0).round() as u16,
        Attribute::Reset
    )
    .unwrap();
    stdout.flush().unwrap();
}

#[cfg(test)]
mod tests {
    use super::{break_line, calc_range};

    // It is good to test the above functions
    #[test]
    fn test_calc_range() {
        assert_eq!((0, 24), calc_range(0, 25, 100));
        assert_eq!((50, 74), calc_range(50, 25, 100));
        assert_eq!((75, 100), calc_range(85, 25, 100));
    }
    #[test]
    fn test_break_lines_long() {
        let mut test_string = String::with_capacity(100);
        for _ in 0..200 {
            test_string.push('#');
        }

        let lines = break_line(&test_string, 80);

        assert_eq!(
            (80, 80, 40),
            (lines[0].len(), lines[1].len(), lines[2].len())
        );
    }

    #[test]
    fn test_break_lines_short() {
        let mut test_string = String::with_capacity(100);
        for _ in 0..20 {
            test_string.push('#');
        }

        let lines = break_line(&test_string, 80);

        assert_eq!(20, lines[0].len());
    }
}
<commit_msg>Fix clippy warning<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Martin Kysel <code@martinkysel.com>
//  *
//  * For the full copyright and license information, please view the LICENSE file
//  * that was distributed with this source code.

// spell-checker:ignore (ToDO) lflag ICANON tcgetattr tcsetattr TCSADRAIN

#[macro_use]
extern crate uucore;

use std::{
    convert::TryInto,
    fs::File,
    io::{stdin, stdout, BufReader, Read, Stdout, Write},
    path::Path,
    time::Duration,
};

#[cfg(all(unix, not(target_os = "fuchsia")))]
extern crate nix;

use clap::{App, Arg};
use crossterm::{
    event::{self, Event, KeyCode, KeyEvent, KeyModifiers},
    execute, queue,
    style::Attribute,
    terminal,
};

pub mod options {
    pub const SILENT: &str = "silent";
    pub const LOGICAL: &str = "logical";
    pub const NO_PAUSE: &str = "no-pause";
    pub const PRINT_OVER: &str = "print-over";
    pub const CLEAN_PRINT: &str = "clean-print";
    pub const SQUEEZE: &str = "squeeze";
    pub const PLAIN: &str = "plain";
    pub const LINES: &str = "lines";
    pub const NUMBER: &str = "number";
    pub const PATTERN: &str = "pattern";
    pub const FROM_LINE: &str = "from-line";
    pub const FILES: &str = "files";
}

const MULTI_FILE_TOP_PROMPT: &str = "::::::::::::::\n{}\n::::::::::::::\n";

pub fn uumain(args: impl uucore::Args) -> i32 {
    let matches = App::new(executable!())
        .about("A file perusal filter for CRT viewing.")
        .version(env!("CARGO_PKG_VERSION"))
        .arg(
            Arg::with_name(options::SILENT)
                .short("d")
                .long(options::SILENT)
                .help("Display help instead of ringing bell"),
        )
        .arg(
            Arg::with_name(options::LOGICAL)
                .short("f")
                .long(options::LOGICAL)
                .help("Count logical rather than screen lines"),
        )
        .arg(
            Arg::with_name(options::NO_PAUSE)
                .short("l")
                .long(options::NO_PAUSE)
                .help("Suppress pause after form feed"),
        )
        .arg(
            Arg::with_name(options::PRINT_OVER)
                .short("c")
                .long(options::PRINT_OVER)
                .help("Do not scroll, display text and clean line ends"),
        )
        .arg(
            Arg::with_name(options::CLEAN_PRINT)
                .short("p")
                .long(options::CLEAN_PRINT)
                .help("Do not scroll, clean screen and display text"),
        )
        .arg(
            Arg::with_name(options::SQUEEZE)
                .short("s")
                .long(options::SQUEEZE)
                .help("Squeeze multiple blank lines into one"),
        )
        .arg(
            Arg::with_name(options::PLAIN)
                .short("u")
                .long(options::PLAIN)
                .help("Suppress underlining and bold"),
        )
        .arg(
            Arg::with_name(options::LINES)
                .short("n")
                .long(options::LINES)
                .value_name("number")
                .takes_value(true)
                .help("The number of lines per screenful"),
        )
        .arg(
            Arg::with_name(options::NUMBER)
                .allow_hyphen_values(true)
                .long(options::NUMBER)
                .required(false)
                .takes_value(true)
                .help("Same as --lines"),
        )
        .arg(
            Arg::with_name(options::FROM_LINE)
                .short("F")
                .allow_hyphen_values(true)
                .required(false)
                .takes_value(true)
                .value_name("number")
                .help("Display file beginning from line number"),
        )
        .arg(
            Arg::with_name(options::PATTERN)
                .short("P")
                .allow_hyphen_values(true)
                .required(false)
                .takes_value(true)
                .help("Display file beginning from pattern match"),
        )
        .arg(
            Arg::with_name(options::FILES)
                .required(false)
                .multiple(true)
                .help("Path to the files to be read"),
        )
        .get_matches_from(args);
    let mut buff = String::new();
    let mut stdout = setup_term();
    if let Some(filenames) = matches.values_of(options::FILES) {
        let length = filenames.len();
        for (idx, fname) in filenames.clone().enumerate() {
            let fname = Path::new(fname);
            if fname.is_dir() {
                terminal::disable_raw_mode().unwrap();
                show_usage_error!("'{}' is a directory.", fname.display());
                return 1;
            }
            if !fname.exists() {
                terminal::disable_raw_mode().unwrap();
                eprintln!(
                    "{}: cannot open {}: No such file or directory",
                    executable!(),
                    fname.display()
                );
                return 1;
            }
            if filenames.len() > 1 {
                buff.push_str(&MULTI_FILE_TOP_PROMPT.replace("{}", fname.to_str().unwrap()));
            }
            let mut reader = BufReader::new(File::open(fname).unwrap());
            reader.read_to_string(&mut buff).unwrap();
            let last = idx + 1 == length;
            more(&buff, &mut stdout, last);
            buff.clear();
        }
        reset_term(&mut stdout);
    } else if atty::isnt(atty::Stream::Stdin) {
        let mut stdout = setup_term();
        stdin().read_to_string(&mut buff).unwrap();
        more(&buff, &mut stdout, true);
    } else {
        terminal::disable_raw_mode().unwrap();
        show_usage_error!("bad usage");
    }
    0
}

#[cfg(not(target_os = "fuchsia"))]
fn setup_term() -> std::io::Stdout {
    let stdout = stdout();
    terminal::enable_raw_mode().unwrap();
    stdout
}

#[cfg(target_os = "fuchsia")]
#[inline(always)]
fn setup_term() -> usize {
    0
}

#[cfg(not(target_os = "fuchsia"))]
fn reset_term(stdout: &mut std::io::Stdout) {
    terminal::disable_raw_mode().unwrap();
    // Clear the prompt
    queue!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
    // Move cursor to the beginning without printing new line
    print!("\r");
    stdout.flush().unwrap();
}

#[cfg(target_os = "fuchsia")]
#[inline(always)]
fn reset_term(_: &mut usize) {}

fn more(buff: &str, mut stdout: &mut Stdout, is_last: bool) {
    let (cols, rows) = terminal::size().unwrap();
    let lines = break_buff(buff, usize::from(cols));
    let line_count: u16 = lines.len().try_into().unwrap();

    // Print everything and quit if line count is less than the availale rows
    if line_count < rows {
        println!("{}", buff);
        return;
    }

    let mut upper_mark = 0;
    // Number of lines left
    let mut lines_left = line_count - (upper_mark + rows);
    // Are we on the very last page and the next down arrow will return this function
    let mut to_be_done = false;
    draw(
        &mut upper_mark,
        rows,
        &mut stdout,
        lines.clone(),
        line_count,
    );

    loop {
        if event::poll(Duration::from_millis(10)).unwrap() {
            match event::read().unwrap() {
                Event::Key(KeyEvent {
                    code: KeyCode::Char('q'),
                    modifiers: KeyModifiers::NONE,
                })
                | Event::Key(KeyEvent {
                    code: KeyCode::Char('c'),
                    modifiers: KeyModifiers::CONTROL,
                }) => {
                    reset_term(&mut stdout);
                    std::process::exit(0);
                }
                Event::Key(KeyEvent {
                    code: KeyCode::Down,
                    modifiers: KeyModifiers::NONE,
                })
                | Event::Key(KeyEvent {
                    code: KeyCode::Char(' '),
                    modifiers: KeyModifiers::NONE,
                }) => {
                    // If this is the last page but some text
                    // is still left that does not require a page of its own
                    // then this event will print the left lines
                    if lines_left < rows && !to_be_done {
                        for l in lines.iter().skip((line_count - upper_mark - rows).into()) {
                            stdout.write_all(format!("\r{}\n", l).as_bytes()).unwrap();
                        }
                        make_prompt_and_flush(&mut stdout, line_count, line_count);
                        // If this is not the last input file
                        // do not return, but the next down arrow must return
                        // because we have printed everyhing
                        if !is_last {
                            to_be_done = true;
                        } else {
                            // Else quit
                            reset_term(&mut stdout);
                            return;
                        }
                        // This handles the next arrow key to quit
                    } else if lines_left < rows && to_be_done {
                        return;
                    } else {
                        // Print a normal page
                        upper_mark = upper_mark.saturating_add(rows.saturating_sub(1));
                        lines_left = line_count.saturating_sub(upper_mark + rows);
                        draw(
                            &mut upper_mark,
                            rows,
                            &mut stdout,
                            lines.clone(),
                            line_count,
                        );
                    }
                }
                Event::Key(KeyEvent {
                    code: KeyCode::Up,
                    modifiers: KeyModifiers::NONE,
                }) => {
                    upper_mark = upper_mark.saturating_sub(rows.saturating_sub(1));
                    draw(
                        &mut upper_mark,
                        rows,
                        &mut stdout,
                        lines.clone(),
                        line_count,
                    );
                }
                _ => continue,
            }
        }
    }
}

fn draw(
    upper_mark: &mut u16,
    rows: u16,
    mut stdout: &mut std::io::Stdout,
    lines: Vec<String>,
    lc: u16,
) {
    execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
    let (up_mark, lower_mark) = calc_range(*upper_mark, rows, lc);
    // Reduce the row by 1 for the prompt
    let displayed_lines = lines
        .iter()
        .skip(up_mark.into())
        .take(usize::from(rows.saturating_sub(1)));

    for line in displayed_lines {
        stdout
            .write_all(format!("\r{}\n", line).as_bytes())
            .unwrap();
    }
    make_prompt_and_flush(&mut stdout, lower_mark, lc);
    *upper_mark = up_mark;
}

// Break the lines on the cols of the terminal
fn break_buff(buff: &str, cols: usize) -> Vec<String> {
    let mut lines = Vec::new();

    for l in buff.lines() {
        lines.append(&mut break_line(l, cols));
    }
    lines
}

fn break_line(mut line: &str, cols: usize) -> Vec<String> {
    let breaks = (line.len() / cols).saturating_add(1);
    let mut lines = Vec::with_capacity(breaks);
    if line.len() < cols {
        lines.push(line.to_string());
        return lines;
    }

    for _ in 1..=breaks {
        let (line1, line2) = line.split_at(cols);
        lines.push(line1.to_string());
        if line2.len() < cols {
            lines.push(line2.to_string());
            break;
        }
        line = line2;
    }
    lines
}

// Calculate upper_mark based on certain parameters
fn calc_range(mut upper_mark: u16, rows: u16, line_count: u16) -> (u16, u16) {
    let mut lower_mark = upper_mark.saturating_add(rows);

    if lower_mark >= line_count {
        upper_mark = line_count.saturating_sub(rows);
        lower_mark = line_count;
    } else {
        lower_mark = lower_mark.saturating_sub(1)
    }
    (upper_mark, lower_mark)
}

// Make a prompt similar to original more
fn make_prompt_and_flush(stdout: &mut Stdout, lower_mark: u16, lc: u16) {
    write!(
        stdout,
        "\r{}--More--({}%){}",
        Attribute::Reverse,
        ((lower_mark as f64 / lc as f64) * 100.0).round() as u16,
        Attribute::Reset
    )
    .unwrap();
    stdout.flush().unwrap();
}

#[cfg(test)]
mod tests {
    use super::{break_line, calc_range};

    // It is good to test the above functions
    #[test]
    fn test_calc_range() {
        assert_eq!((0, 24), calc_range(0, 25, 100));
        assert_eq!((50, 74), calc_range(50, 25, 100));
        assert_eq!((75, 100), calc_range(85, 25, 100));
    }
    #[test]
    fn test_break_lines_long() {
        let mut test_string = String::with_capacity(100);
        for _ in 0..200 {
            test_string.push('#');
        }

        let lines = break_line(&test_string, 80);

        assert_eq!(
            (80, 80, 40),
            (lines[0].len(), lines[1].len(), lines[2].len())
        );
    }

    #[test]
    fn test_break_lines_short() {
        let mut test_string = String::with_capacity(100);
        for _ in 0..20 {
            test_string.push('#');
        }

        let lines = break_line(&test_string, 80);

        assert_eq!(20, lines[0].len());
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::path::PathBuf;
use std::process::{Command, Stdio};

fn main() {
    let wasi_sdk = env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned());

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

    let core_h_path = out_path.join("core.h");
    let core_h = File::create(&core_h_path).unwrap();

    // `bindgen` doesn't understand typed constant macros like `UINT8_C(123)`, so this fun regex
    // strips them off to yield a copy of `wasi/core.h` with bare constants.
    Command::new("sed")
        .arg("-E")
        .arg(r#"s/U?INT[0-9]+_C\(((0x)?[0-9]+)\)/\1/g"#)
        .arg("/opt/wasi-sdk/share/sysroot/include/wasi/core.h")
        .stdout(Stdio::from(core_h))
        .status()
        .unwrap();

    let host_builder = bindgen::Builder::default()
        .clang_arg("-nostdinc")
        .clang_arg("-D__wasi__")
        .clang_arg(format!("-isystem={}/share/sysroot/include/", wasi_sdk))
        .clang_arg(format!("-I{}/lib/clang/8.0.0/include/", wasi_sdk))
        .header(core_h_path.to_str().unwrap())
        .whitelist_type("__wasi_.*")
        .whitelist_var("__WASI_.*");

    host_builder
        .generate()
        .expect("can generate host bindings")
        .write_to_file(out_path.join("wasi_host.rs"))
        .expect("can write host bindings");
}
<commit_msg>[lucet-wasi] properly mark <wasi/core.h> for rebuilds<commit_after>use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

fn main() {
    let wasi_sdk =
        Path::new(&env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned())).to_path_buf();
    let wasi_sdk_core_h = wasi_sdk.join("share/sysroot/include/wasi/core.h");

    println!("cargo:rerun-if-changed={}", wasi_sdk_core_h.display());

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

    let core_h_path = out_path.join("core.h");
    let core_h = File::create(&core_h_path).unwrap();

    // `bindgen` doesn't understand typed constant macros like `UINT8_C(123)`, so this fun regex
    // strips them off to yield a copy of `wasi/core.h` with bare constants.
    Command::new("sed")
        .arg("-E")
        .arg(r#"s/U?INT[0-9]+_C\(((0x)?[0-9]+)\)/\1/g"#)
        .arg(wasi_sdk_core_h)
        .stdout(Stdio::from(core_h))
        .status()
        .unwrap();

    let host_builder = bindgen::Builder::default()
        .clang_arg("-nostdinc")
        .clang_arg("-D__wasi__")
        .clang_arg(format!(
            "-isystem={}/share/sysroot/include/",
            wasi_sdk.display()
        ))
        .clang_arg(format!("-I{}/lib/clang/8.0.0/include/", wasi_sdk.display()))
        .header(core_h_path.to_str().unwrap())
        .whitelist_type("__wasi_.*")
        .whitelist_var("__WASI_.*");

    host_builder
        .generate()
        .expect("can generate host bindings")
        .write_to_file(out_path.join("wasi_host.rs"))
        .expect("can write host bindings");
}
<|endoftext|>


<commit_before>extern crate sdl2;

use self::sdl2::event::Event;
use self::sdl2::keyboard::Keycode;

const KEY_COUNT: usize = 16;

pub struct Keyboard {
	events: sdl2::EventPump,
	key_states: [bool; KEY_COUNT]
}

impl Keyboard {
	pub fn new(sdl_context: &sdl2::Sdl) -> Keyboard {
		Keyboard {
			events: sdl_context.event_pump().unwrap(),
			key_states: [false; KEY_COUNT]
		}
	}

	pub fn update_key_states(&mut self) {
		for event in self.events.poll_iter() {
			match event {
				Event::KeyDown { keycode: Some(Keycode::Num0), ..} => self.key_states[0x0] = true,
				Event::KeyDown { keycode: Some(Keycode::Num1), ..} => self.key_states[0x1] = true,
				Event::KeyDown { keycode: Some(Keycode::Num2), ..} => self.key_states[0x2] = true,
				Event::KeyDown { keycode: Some(Keycode::Num3), ..} => self.key_states[0x3] = true,
				Event::KeyDown { keycode: Some(Keycode::Num4), ..} => self.key_states[0x4] = true,
				Event::KeyDown { keycode: Some(Keycode::Num5), ..} => self.key_states[0x5] = true,
				Event::KeyDown { keycode: Some(Keycode::Num6), ..} => self.key_states[0x6] = true,
				Event::KeyDown { keycode: Some(Keycode::Num7), ..} => self.key_states[0x7] = true,
				Event::KeyDown { keycode: Some(Keycode::Num8), ..} => self.key_states[0x8] = true,
				Event::KeyDown { keycode: Some(Keycode::Num9), ..} => self.key_states[0x9] = true,
				Event::KeyDown { keycode: Some(Keycode::A), ..} => self.key_states[0xA] = true,
				Event::KeyDown { keycode: Some(Keycode::B), ..} => self.key_states[0xB] = true,
				Event::KeyDown { keycode: Some(Keycode::C), ..} => self.key_states[0xC] = true,
				Event::KeyDown { keycode: Some(Keycode::D), ..} => self.key_states[0xD] = true,
				Event::KeyDown { keycode: Some(Keycode::E), ..} => self.key_states[0xE] = true,
				Event::KeyDown { keycode: Some(Keycode::F), ..} => self.key_states[0xF] = true,
				Event::KeyUp { keycode: Some(Keycode::Num0), ..} => self.key_states[0x0] = false,
				Event::KeyUp { keycode: Some(Keycode::Num1), ..} => self.key_states[0x1] = false,
				Event::KeyUp { keycode: Some(Keycode::Num2), ..} => self.key_states[0x2] = false,
				Event::KeyUp { keycode: Some(Keycode::Num3), ..} => self.key_states[0x3] = false,
				Event::KeyUp { keycode: Some(Keycode::Num4), ..} => self.key_states[0x4] = false,
				Event::KeyUp { keycode: Some(Keycode::Num5), ..} => self.key_states[0x5] = false,
				Event::KeyUp { keycode: Some(Keycode::Num6), ..} => self.key_states[0x6] = false,
				Event::KeyUp { keycode: Some(Keycode::Num7), ..} => self.key_states[0x7] = false,
				Event::KeyUp { keycode: Some(Keycode::Num8), ..} => self.key_states[0x8] = false,
				Event::KeyUp { keycode: Some(Keycode::Num9), ..} => self.key_states[0x9] = false,
				Event::KeyUp { keycode: Some(Keycode::A), ..} => self.key_states[0xA] = false,
				Event::KeyUp { keycode: Some(Keycode::B), ..} => self.key_states[0xB] = false,
				Event::KeyUp { keycode: Some(Keycode::C), ..} => self.key_states[0xC] = false,
				Event::KeyUp { keycode: Some(Keycode::D), ..} => self.key_states[0xD] = false,
				Event::KeyUp { keycode: Some(Keycode::E), ..} => self.key_states[0xE] = false,
				Event::KeyUp { keycode: Some(Keycode::F), ..} => self.key_states[0xF] = false,
				_ => {}
			}
		}
	}

	pub fn is_pressed(&mut self, key: u8) -> bool {
		self.key_states[key as usize]
	}

	pub fn wait_key_press(&mut self) -> u8 {
		loop {
			for event in self.events.wait_iter() {
				match event {
					Event::KeyDown { keycode: Some(Keycode::Num0), ..} => {
						self.key_states[0x0] = true;
						return 0x0
					},
					Event::KeyDown { keycode: Some(Keycode::Num1), ..} => {
						self.key_states[0x1] = true;
						return 0x1
					},
					Event::KeyDown { keycode: Some(Keycode::Num2), ..} => {
						self.key_states[0x2] = true;
						return 0x2
					},
					Event::KeyDown { keycode: Some(Keycode::Num3), ..} => {
						self.key_states[0x3] = true;
						return 0x3
					},
					Event::KeyDown { keycode: Some(Keycode::Num4), ..} => {
						self.key_states[0x4] = true;
						return 0x4
					},
					Event::KeyDown { keycode: Some(Keycode::Num5), ..} => {
						self.key_states[0x5] = true;
						return 0x5
					},
					Event::KeyDown { keycode: Some(Keycode::Num6), ..} => {
						self.key_states[0x6] = true;
						return 0x6
					},
					Event::KeyDown { keycode: Some(Keycode::Num7), ..} => {
						self.key_states[0x7] = true;
						return 0x7
					},
					Event::KeyDown { keycode: Some(Keycode::Num8), ..} => {
						self.key_states[0x8] = true;
						return 0x8
					},
					Event::KeyDown { keycode: Some(Keycode::Num9), ..} => {
						self.key_states[0x9] = true;
						return 0x9
					},
					Event::KeyDown { keycode: Some(Keycode::A), ..} => {
						self.key_states[0xA] = true;
						return 0xA
					},
					Event::KeyDown { keycode: Some(Keycode::B), ..} => {
						self.key_states[0xB] = true;
						return 0xB
					},
					Event::KeyDown { keycode: Some(Keycode::C), ..} => {
						self.key_states[0xC] = true;
						return 0xC
					},
					Event::KeyDown { keycode: Some(Keycode::D), ..} => {
						self.key_states[0xD] = true;
						return 0xD
					},
					Event::KeyDown { keycode: Some(Keycode::E), ..} => {
						self.key_states[0xE] = true;
						return 0xE
					},
					Event::KeyDown { keycode: Some(Keycode::F), ..} => {
						self.key_states[0xF] = true;
						return 0xF
					},
					Event::KeyUp { keycode: Some(Keycode::Num0), ..} => self.key_states[0x0] = false,
					Event::KeyUp { keycode: Some(Keycode::Num1), ..} => self.key_states[0x1] = false,
					Event::KeyUp { keycode: Some(Keycode::Num2), ..} => self.key_states[0x2] = false,
					Event::KeyUp { keycode: Some(Keycode::Num3), ..} => self.key_states[0x3] = false,
					Event::KeyUp { keycode: Some(Keycode::Num4), ..} => self.key_states[0x4] = false,
					Event::KeyUp { keycode: Some(Keycode::Num5), ..} => self.key_states[0x5] = false,
					Event::KeyUp { keycode: Some(Keycode::Num6), ..} => self.key_states[0x6] = false,
					Event::KeyUp { keycode: Some(Keycode::Num7), ..} => self.key_states[0x7] = false,
					Event::KeyUp { keycode: Some(Keycode::Num8), ..} => self.key_states[0x8] = false,
					Event::KeyUp { keycode: Some(Keycode::Num9), ..} => self.key_states[0x9] = false,
					Event::KeyUp { keycode: Some(Keycode::A), ..} => self.key_states[0xA] = false,
					Event::KeyUp { keycode: Some(Keycode::B), ..} => self.key_states[0xB] = false,
					Event::KeyUp { keycode: Some(Keycode::C), ..} => self.key_states[0xC] = false,
					Event::KeyUp { keycode: Some(Keycode::D), ..} => self.key_states[0xD] = false,
					Event::KeyUp { keycode: Some(Keycode::E), ..} => self.key_states[0xE] = false,
					Event::KeyUp { keycode: Some(Keycode::F), ..} => self.key_states[0xF] = false,
					_ => {}
				}
			}
		}
	}
}
<commit_msg>Change keys<commit_after>extern crate sdl2;

use self::sdl2::event::Event;
use self::sdl2::keyboard::Keycode;

const KEY_COUNT: usize = 16;

pub struct Keyboard {
	events: sdl2::EventPump,
	key_states: [bool; KEY_COUNT]
}

impl Keyboard {
	pub fn new(sdl_context: &sdl2::Sdl) -> Keyboard {
		Keyboard {
			events: sdl_context.event_pump().unwrap(),
			key_states: [false; KEY_COUNT]
		}
	}

	pub fn update_key_states(&mut self) {
		for event in self.events.poll_iter() {
			match event {
				Event::KeyDown { keycode: Some(Keycode::Kp0), ..} => self.key_states[0x0] = true,
				Event::KeyDown { keycode: Some(Keycode::Kp1), ..} => self.key_states[0x1] = true,
				Event::KeyDown { keycode: Some(Keycode::Kp2), ..} => self.key_states[0x2] = true,
				Event::KeyDown { keycode: Some(Keycode::Kp3), ..} => self.key_states[0x3] = true,
				Event::KeyDown { keycode: Some(Keycode::Kp4), ..} => self.key_states[0x4] = true,
				Event::KeyDown { keycode: Some(Keycode::Kp5), ..} => self.key_states[0x5] = true,
				Event::KeyDown { keycode: Some(Keycode::Kp6), ..} => self.key_states[0x6] = true,
				Event::KeyDown { keycode: Some(Keycode::Kp7), ..} => self.key_states[0x7] = true,
				Event::KeyDown { keycode: Some(Keycode::Kp8), ..} => self.key_states[0x8] = true,
				Event::KeyDown { keycode: Some(Keycode::Kp9), ..} => self.key_states[0x9] = true,
				Event::KeyDown { keycode: Some(Keycode::A), ..} => self.key_states[0xA] = true,
				Event::KeyDown { keycode: Some(Keycode::B), ..} => self.key_states[0xB] = true,
				Event::KeyDown { keycode: Some(Keycode::C), ..} => self.key_states[0xC] = true,
				Event::KeyDown { keycode: Some(Keycode::D), ..} => self.key_states[0xD] = true,
				Event::KeyDown { keycode: Some(Keycode::E), ..} => self.key_states[0xE] = true,
				Event::KeyDown { keycode: Some(Keycode::F), ..} => self.key_states[0xF] = true,
				Event::KeyUp { keycode: Some(Keycode::Kp0), ..} => self.key_states[0x0] = false,
				Event::KeyUp { keycode: Some(Keycode::Kp1), ..} => self.key_states[0x1] = false,
				Event::KeyUp { keycode: Some(Keycode::Kp2), ..} => self.key_states[0x2] = false,
				Event::KeyUp { keycode: Some(Keycode::Kp3), ..} => self.key_states[0x3] = false,
				Event::KeyUp { keycode: Some(Keycode::Kp4), ..} => self.key_states[0x4] = false,
				Event::KeyUp { keycode: Some(Keycode::Kp5), ..} => self.key_states[0x5] = false,
				Event::KeyUp { keycode: Some(Keycode::Kp6), ..} => self.key_states[0x6] = false,
				Event::KeyUp { keycode: Some(Keycode::Kp7), ..} => self.key_states[0x7] = false,
				Event::KeyUp { keycode: Some(Keycode::Kp8), ..} => self.key_states[0x8] = false,
				Event::KeyUp { keycode: Some(Keycode::Kp9), ..} => self.key_states[0x9] = false,
				Event::KeyUp { keycode: Some(Keycode::A), ..} => self.key_states[0xA] = false,
				Event::KeyUp { keycode: Some(Keycode::B), ..} => self.key_states[0xB] = false,
				Event::KeyUp { keycode: Some(Keycode::C), ..} => self.key_states[0xC] = false,
				Event::KeyUp { keycode: Some(Keycode::D), ..} => self.key_states[0xD] = false,
				Event::KeyUp { keycode: Some(Keycode::E), ..} => self.key_states[0xE] = false,
				Event::KeyUp { keycode: Some(Keycode::F), ..} => self.key_states[0xF] = false,
				_ => {}
			}
		}
	}

	pub fn is_pressed(&mut self, key: u8) -> bool {
		self.key_states[key as usize]
	}

	pub fn wait_key_press(&mut self) -> u8 {
		loop {
			for event in self.events.wait_iter() {
				match event {
					Event::KeyDown { keycode: Some(Keycode::Kp0), ..} => {
						self.key_states[0x0] = true;
						return 0x0
					},
					Event::KeyDown { keycode: Some(Keycode::Kp1), ..} => {
						self.key_states[0x1] = true;
						return 0x1
					},
					Event::KeyDown { keycode: Some(Keycode::Kp2), ..} => {
						self.key_states[0x2] = true;
						return 0x2
					},
					Event::KeyDown { keycode: Some(Keycode::Kp3), ..} => {
						self.key_states[0x3] = true;
						return 0x3
					},
					Event::KeyDown { keycode: Some(Keycode::Kp4), ..} => {
						self.key_states[0x4] = true;
						return 0x4
					},
					Event::KeyDown { keycode: Some(Keycode::Kp5), ..} => {
						self.key_states[0x5] = true;
						return 0x5
					},
					Event::KeyDown { keycode: Some(Keycode::Kp6), ..} => {
						self.key_states[0x6] = true;
						return 0x6
					},
					Event::KeyDown { keycode: Some(Keycode::Kp7), ..} => {
						self.key_states[0x7] = true;
						return 0x7
					},
					Event::KeyDown { keycode: Some(Keycode::Kp8), ..} => {
						self.key_states[0x8] = true;
						return 0x8
					},
					Event::KeyDown { keycode: Some(Keycode::Kp9), ..} => {
						self.key_states[0x9] = true;
						return 0x9
					},
					Event::KeyDown { keycode: Some(Keycode::A), ..} => {
						self.key_states[0xA] = true;
						return 0xA
					},
					Event::KeyDown { keycode: Some(Keycode::B), ..} => {
						self.key_states[0xB] = true;
						return 0xB
					},
					Event::KeyDown { keycode: Some(Keycode::C), ..} => {
						self.key_states[0xC] = true;
						return 0xC
					},
					Event::KeyDown { keycode: Some(Keycode::D), ..} => {
						self.key_states[0xD] = true;
						return 0xD
					},
					Event::KeyDown { keycode: Some(Keycode::E), ..} => {
						self.key_states[0xE] = true;
						return 0xE
					},
					Event::KeyDown { keycode: Some(Keycode::F), ..} => {
						self.key_states[0xF] = true;
						return 0xF
					},
					Event::KeyUp { keycode: Some(Keycode::Kp0), ..} => self.key_states[0x0] = false,
					Event::KeyUp { keycode: Some(Keycode::Kp1), ..} => self.key_states[0x1] = false,
					Event::KeyUp { keycode: Some(Keycode::Kp2), ..} => self.key_states[0x2] = false,
					Event::KeyUp { keycode: Some(Keycode::Kp3), ..} => self.key_states[0x3] = false,
					Event::KeyUp { keycode: Some(Keycode::Kp4), ..} => self.key_states[0x4] = false,
					Event::KeyUp { keycode: Some(Keycode::Kp5), ..} => self.key_states[0x5] = false,
					Event::KeyUp { keycode: Some(Keycode::Kp6), ..} => self.key_states[0x6] = false,
					Event::KeyUp { keycode: Some(Keycode::Kp7), ..} => self.key_states[0x7] = false,
					Event::KeyUp { keycode: Some(Keycode::Kp8), ..} => self.key_states[0x8] = false,
					Event::KeyUp { keycode: Some(Keycode::Kp9), ..} => self.key_states[0x9] = false,
					Event::KeyUp { keycode: Some(Keycode::A), ..} => self.key_states[0xA] = false,
					Event::KeyUp { keycode: Some(Keycode::B), ..} => self.key_states[0xB] = false,
					Event::KeyUp { keycode: Some(Keycode::C), ..} => self.key_states[0xC] = false,
					Event::KeyUp { keycode: Some(Keycode::D), ..} => self.key_states[0xD] = false,
					Event::KeyUp { keycode: Some(Keycode::E), ..} => self.key_states[0xE] = false,
					Event::KeyUp { keycode: Some(Keycode::F), ..} => self.key_states[0xF] = false,
					_ => {}
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>use std::cell::{RefCell, Ref};
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::iter::{FromIterator, IntoIterator};
use std::ops::Index;

//NOTE: transmute is used to circumvent the borrow checker in this module
//This is safe since the containers hold boxed values meaning allocating larger
//storage does not invalidate the references that are handed out and because values
//can only be inserted, never modified (this could be done with a Rc pointer as well but
//is not done for efficiency since it is not needed)

unsafe fn forget_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
    ::std::mem::transmute(x)
}

//A mapping between K and V where once a value has been inserted it cannot be changed
//Through this and the fact the all values are stored as pointers it is possible to safely
//insert new values without invalidating pointers retrieved from it
pub struct FixedMap<K, V> {
    map: RefCell<HashMap<K, Box<V>>>
}

impl <K: Eq + Hash + fmt::Debug, V: fmt::Debug> fmt::Debug for FixedMap<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.map.borrow().fmt(f)
    }
}

impl <K: Eq + Hash, V> FixedMap<K, V> {

    pub fn new() -> FixedMap<K, V> {
        FixedMap { map: RefCell::new(HashMap::new()) }
    }

    pub fn clear(&mut self) {
        self.map.borrow_mut().clear();
    }

    pub fn try_insert(&self, key: K, value: V) -> Result<(), (K, V)> {
        if self.get(&key).is_some() {
            Err((key, value))
        }
        else {
            self.map.borrow_mut().insert(key, Box::new(value));
            Ok(())
        }
    }

    #[allow(dead_code)]
    pub fn len(&self) -> usize {
        self.map.borrow().len()
    }

    pub fn get(&self, k: &K) -> Option<&V> {
        self.map.borrow()
            .get(k)
            .map(|x| unsafe { forget_lifetime(&**x) })
    }
}

#[derive(Debug)]
pub struct FixedVec<T> {
    vec: RefCell<Vec<Box<T>>>
}

impl <T> FixedVec<T> {
    pub fn new() -> FixedVec<T> {
        FixedVec { vec: RefCell::new(Vec::new()) }
    }

    pub fn push(&self, value: T) {
        self.vec.borrow_mut().push(Box::new(value))
    }

    #[allow(dead_code)]
    pub fn extend<I: Iterator<Item=T>>(&self, iter: I) {
        self.vec.borrow_mut().extend(iter.map(|v| Box::new(v)))
    }

    pub fn borrow(&self) -> Ref<Vec<Box<T>>> {
        self.vec.borrow()
    }

    pub fn find<F>(&self, mut test: F) -> Option<(usize, &T)>
        where F: FnMut(&T) -> bool {
        self.vec.borrow().iter()
            .enumerate()
            .find(|&(_, boxed)| test(&**boxed))
            .map(|(i, boxed)| (i, unsafe { forget_lifetime(&**boxed) }))
    }

    pub fn len(&self) -> usize {
        self.vec.borrow().len()
    }
}

impl <T> Index<usize> for FixedVec<T> {
    type Output = T;
    fn index(&self, index: usize) -> &T {
        let vec = self.vec.borrow();
        let result = &*(*vec)[index];
        unsafe { forget_lifetime(result) }
    }
}

impl <A> FromIterator<A> for FixedVec<A> {
    fn from_iter<T: IntoIterator<Item=A>>(iterator: T) -> FixedVec<A> {
        let vec: Vec<_> = iterator.into_iter().map(|x| Box::new(x)).collect();
        FixedVec { vec: RefCell::new(vec) }
    }
}
<commit_msg>Implement IndexMut on FixedVec<commit_after>use std::cell::{RefCell, Ref};
use std::collections::HashMap;
use std::fmt;
use std::hash::Hash;
use std::iter::{FromIterator, IntoIterator};
use std::ops::{Index, IndexMut};

//NOTE: transmute is used to circumvent the borrow checker in this module
//This is safe since the containers hold boxed values meaning allocating larger
//storage does not invalidate the references that are handed out and because values
//can only be inserted, never modified (this could be done with a Rc pointer as well but
//is not done for efficiency since it is not needed)

unsafe fn forget_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
    ::std::mem::transmute(x)
}

unsafe fn forget_lifetime_mut<'a, 'b, T: ?Sized>(x: &'a mut T) -> &'b mut T {
    ::std::mem::transmute(x)
}

//A mapping between K and V where once a value has been inserted it cannot be changed
//Through this and the fact the all values are stored as pointers it is possible to safely
//insert new values without invalidating pointers retrieved from it
pub struct FixedMap<K, V> {
    map: RefCell<HashMap<K, Box<V>>>
}

impl <K: Eq + Hash + fmt::Debug, V: fmt::Debug> fmt::Debug for FixedMap<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.map.borrow().fmt(f)
    }
}

impl <K: Eq + Hash, V> FixedMap<K, V> {

    pub fn new() -> FixedMap<K, V> {
        FixedMap { map: RefCell::new(HashMap::new()) }
    }

    pub fn clear(&mut self) {
        self.map.borrow_mut().clear();
    }

    pub fn try_insert(&self, key: K, value: V) -> Result<(), (K, V)> {
        if self.get(&key).is_some() {
            Err((key, value))
        }
        else {
            self.map.borrow_mut().insert(key, Box::new(value));
            Ok(())
        }
    }

    #[allow(dead_code)]
    pub fn len(&self) -> usize {
        self.map.borrow().len()
    }

    pub fn get(&self, k: &K) -> Option<&V> {
        self.map.borrow()
            .get(k)
            .map(|x| unsafe { forget_lifetime(&**x) })
    }
}

#[derive(Debug)]
pub struct FixedVec<T> {
    vec: RefCell<Vec<Box<T>>>
}

impl <T> FixedVec<T> {
    pub fn new() -> FixedVec<T> {
        FixedVec { vec: RefCell::new(Vec::new()) }
    }

    pub fn clear(&mut self) {
        self.vec.borrow_mut().clear();
    }

    pub fn push(&self, value: T) {
        self.vec.borrow_mut().push(Box::new(value))
    }

    #[allow(dead_code)]
    pub fn extend<I: Iterator<Item=T>>(&self, iter: I) {
        self.vec.borrow_mut().extend(iter.map(|v| Box::new(v)))
    }

    pub fn borrow(&self) -> Ref<Vec<Box<T>>> {
        self.vec.borrow()
    }

    pub fn find<F>(&self, mut test: F) -> Option<(usize, &T)>
        where F: FnMut(&T) -> bool {
        self.vec.borrow().iter()
            .enumerate()
            .find(|&(_, boxed)| test(&**boxed))
            .map(|(i, boxed)| (i, unsafe { forget_lifetime(&**boxed) }))
    }

    pub fn len(&self) -> usize {
        self.vec.borrow().len()
    }
}

impl <T> Index<usize> for FixedVec<T> {
    type Output = T;
    fn index(&self, index: usize) -> &T {
        let vec = self.vec.borrow();
        let result = &*vec[index];
        unsafe { forget_lifetime(result) }
    }
}

impl <T> IndexMut<usize> for FixedVec<T> {
    fn index_mut(&mut self, index: usize) -> &mut T {
        let mut vec = self.vec.borrow_mut();
        let result = &mut *vec[index];
        unsafe { forget_lifetime_mut(result) }
    }
}

impl <A> FromIterator<A> for FixedVec<A> {
    fn from_iter<T: IntoIterator<Item=A>>(iterator: T) -> FixedVec<A> {
        let vec: Vec<_> = iterator.into_iter().map(|x| Box::new(x)).collect();
        FixedVec { vec: RefCell::new(vec) }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use libc::{c_int, signal,
           sigset_t, sigaddset, sigemptyset, sigismember,
           pthread_t, pthread_kill, pthread_sigmask,
           SIG_BLOCK, SIG_UNBLOCK, SIG_ERR, EINVAL};

use std::mem;
use std::ptr::null_mut;
use std::result;
use std::thread::JoinHandle;
use std::os::unix::thread::JoinHandleExt;

use {errno, errno_result};

#[derive(Debug)]
pub enum Error {
    /// Couldn't create a sigset.
    CreateSigset(errno::Error),
    /// The wrapped signal has already been blocked.
    SignalAlreadyBlocked(c_int),
    /// Failed to check if the requested signal is in the blocked set already.
    CompareBlockedSignals(errno::Error),
    /// The signal could not be blocked.
    BlockSignal(errno::Error),
    /// The signal could not be unblocked.
    UnblockSignal(errno::Error),
}

pub type SignalResult<T> = result::Result<T, Error>;

#[link(name = "c")]
extern "C" {
    fn __libc_current_sigrtmin() -> c_int;
    fn __libc_current_sigrtmax() -> c_int;
}

/// Returns the minimum (inclusive) real-time signal number.
#[allow(non_snake_case)]
pub fn SIGRTMIN() -> c_int {
    unsafe { __libc_current_sigrtmin() }
}

/// Returns the maximum (inclusive) real-time signal number.
#[allow(non_snake_case)]
pub fn SIGRTMAX() -> c_int {
    unsafe { __libc_current_sigrtmax() }
}

fn valid_signal_num(num: c_int) -> bool {
    num >= SIGRTMIN() && num <= SIGRTMAX()
}

/// Registers `handler` as the signal handler of signum `num`.
///
/// The value of `num` must be within [`SIGRTMIN`, `SIGRTMAX`] range.
///
/// This is considered unsafe because the given handler will be called asynchronously, interrupting
/// whatever the thread was doing and therefore must only do async-signal-safe operations.
pub unsafe fn register_signal_handler(
    num: c_int,
    handler: extern "C" fn() -> (),
) -> errno::Result<()> {
    if !valid_signal_num(num) {
        return Err(errno::Error::new(EINVAL));
    }
    let ret = signal(num, handler as *const () as usize);
    if ret == SIG_ERR {
        return errno_result();
    }

    Ok(())
}

/// Creates `sigset` from an array of signal numbers.
///
/// This is a helper function used when we want to manipulate signals.
pub fn create_sigset(signals: &[c_int]) -> errno::Result<sigset_t> {
    // sigset will actually be initialized by sigemptyset below.
    let mut sigset: sigset_t = unsafe { mem::zeroed() };

    // Safe - return value is checked.
    let ret = unsafe { sigemptyset(&mut sigset) };
    if ret < 0 {
        return errno_result();
    }

    for signal in signals {
        // Safe - return value is checked.
        let ret = unsafe { sigaddset(&mut sigset, *signal) };
        if ret < 0 {
            return errno_result();
        }
    }

    Ok(sigset)
}

/// Masks given signal.
///
/// If signal is already blocked the call will fail with Error::SignalAlreadyBlocked
/// result.
pub fn block_signal(num: c_int) -> SignalResult<()> {
    let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;

    // Safe - return values are checked.
    unsafe {
        let mut old_sigset: sigset_t = mem::zeroed();
        let ret = pthread_sigmask(SIG_BLOCK, &sigset, &mut old_sigset as *mut sigset_t);
        if ret < 0 {
            return Err(Error::BlockSignal(errno::Error::last()));
        }
        let ret = sigismember(&old_sigset, num);
        if ret < 0 {
            return Err(Error::CompareBlockedSignals(errno::Error::last()));
        } else if ret > 0 {
            return Err(Error::SignalAlreadyBlocked(num));
        }
    }
    Ok(())
}

/// Unmasks given signal.
pub fn unblock_signal(num: c_int) -> SignalResult<()> {
    let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;

    // Safe - return value is checked.
    let ret = unsafe { pthread_sigmask(SIG_UNBLOCK, &sigset, null_mut()) };
    if ret < 0 {
        return Err(Error::UnblockSignal(errno::Error::last()));
    }
    Ok(())
}

/// Trait for threads that can be signalled via `pthread_kill`.
///
/// Note that this is only useful for signals between SIGRTMIN and SIGRTMAX because these are
/// guaranteed to not be used by the C runtime.
///
/// This is marked unsafe because the implementation of this trait must guarantee that the returned
/// pthread_t is valid and has a lifetime at least that of the trait object.
pub unsafe trait Killable {
    fn pthread_handle(&self) -> pthread_t;

    /// Sends the signal `num` to this killable thread.
    ///
    /// The value of `num` must be within [`SIGRTMIN`, `SIGRTMAX`] range.
    fn kill(&self, num: c_int) -> errno::Result<()> {
        if !valid_signal_num(num) {
            return Err(errno::Error::new(EINVAL));
        }

        // Safe because we ensure we are using a valid pthread handle, a valid signal number, and
        // check the return result.
        let ret = unsafe { pthread_kill(self.pthread_handle(), num) };
        if ret < 0 {
            return errno_result();
        }
        Ok(())
    }
}

// Safe because we fulfill our contract of returning a genuine pthread handle.
unsafe impl<T> Killable for JoinHandle<T> {
    fn pthread_handle(&self) -> pthread_t {
        self.as_pthread_t()
    }
}
<commit_msg>sys_util: allow clearing given pending signal<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use libc::{c_int, signal, timespec,
           sigset_t, siginfo_t,
           sigaddset, sigemptyset, sigismember, sigpending, sigtimedwait,
           pthread_t, pthread_kill, pthread_sigmask,
           SIG_BLOCK, SIG_UNBLOCK, SIG_ERR, EAGAIN, EINTR, EINVAL };

use std::mem;
use std::ptr::null_mut;
use std::result;
use std::thread::JoinHandle;
use std::os::unix::thread::JoinHandleExt;

use {errno, errno_result};

#[derive(Debug)]
pub enum Error {
    /// Couldn't create a sigset.
    CreateSigset(errno::Error),
    /// The wrapped signal has already been blocked.
    SignalAlreadyBlocked(c_int),
    /// Failed to check if the requested signal is in the blocked set already.
    CompareBlockedSignals(errno::Error),
    /// The signal could not be blocked.
    BlockSignal(errno::Error),
    /// The signal could not be unblocked.
    UnblockSignal(errno::Error),
    /// Failed to wait for given signal.
    ClearWaitPending(errno::Error),
    /// Failed to get pending signals.
    ClearGetPending(errno::Error),
    /// Failed to check if given signal is in the set of pending signals.
    ClearCheckPending(errno::Error),
}

pub type SignalResult<T> = result::Result<T, Error>;

#[link(name = "c")]
extern "C" {
    fn __libc_current_sigrtmin() -> c_int;
    fn __libc_current_sigrtmax() -> c_int;
}

/// Returns the minimum (inclusive) real-time signal number.
#[allow(non_snake_case)]
pub fn SIGRTMIN() -> c_int {
    unsafe { __libc_current_sigrtmin() }
}

/// Returns the maximum (inclusive) real-time signal number.
#[allow(non_snake_case)]
pub fn SIGRTMAX() -> c_int {
    unsafe { __libc_current_sigrtmax() }
}

fn valid_signal_num(num: c_int) -> bool {
    num >= SIGRTMIN() && num <= SIGRTMAX()
}

/// Registers `handler` as the signal handler of signum `num`.
///
/// The value of `num` must be within [`SIGRTMIN`, `SIGRTMAX`] range.
///
/// This is considered unsafe because the given handler will be called asynchronously, interrupting
/// whatever the thread was doing and therefore must only do async-signal-safe operations.
pub unsafe fn register_signal_handler(
    num: c_int,
    handler: extern "C" fn() -> (),
) -> errno::Result<()> {
    if !valid_signal_num(num) {
        return Err(errno::Error::new(EINVAL));
    }
    let ret = signal(num, handler as *const () as usize);
    if ret == SIG_ERR {
        return errno_result();
    }

    Ok(())
}

/// Creates `sigset` from an array of signal numbers.
///
/// This is a helper function used when we want to manipulate signals.
pub fn create_sigset(signals: &[c_int]) -> errno::Result<sigset_t> {
    // sigset will actually be initialized by sigemptyset below.
    let mut sigset: sigset_t = unsafe { mem::zeroed() };

    // Safe - return value is checked.
    let ret = unsafe { sigemptyset(&mut sigset) };
    if ret < 0 {
        return errno_result();
    }

    for signal in signals {
        // Safe - return value is checked.
        let ret = unsafe { sigaddset(&mut sigset, *signal) };
        if ret < 0 {
            return errno_result();
        }
    }

    Ok(sigset)
}

/// Masks given signal.
///
/// If signal is already blocked the call will fail with Error::SignalAlreadyBlocked
/// result.
pub fn block_signal(num: c_int) -> SignalResult<()> {
    let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;

    // Safe - return values are checked.
    unsafe {
        let mut old_sigset: sigset_t = mem::zeroed();
        let ret = pthread_sigmask(SIG_BLOCK, &sigset, &mut old_sigset as *mut sigset_t);
        if ret < 0 {
            return Err(Error::BlockSignal(errno::Error::last()));
        }
        let ret = sigismember(&old_sigset, num);
        if ret < 0 {
            return Err(Error::CompareBlockedSignals(errno::Error::last()));
        } else if ret > 0 {
            return Err(Error::SignalAlreadyBlocked(num));
        }
    }
    Ok(())
}

/// Unmasks given signal.
pub fn unblock_signal(num: c_int) -> SignalResult<()> {
    let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;

    // Safe - return value is checked.
    let ret = unsafe { pthread_sigmask(SIG_UNBLOCK, &sigset, null_mut()) };
    if ret < 0 {
        return Err(Error::UnblockSignal(errno::Error::last()));
    }
    Ok(())
}

/// Clears pending signal.
pub fn clear_signal(num: c_int) -> SignalResult<()> {
    let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;

    while {
        // This is safe as we are rigorously checking return values
        // of libc calls.
        unsafe {
            let mut siginfo: siginfo_t = mem::zeroed();
            let ts = timespec { tv_sec: 0, tv_nsec: 0 };
            // Attempt to clear one instance of pending signal. If signal
            // is not pending, the call will fail with EAGAIN or EINTR.
            let ret = sigtimedwait(&sigset, &mut siginfo, &ts);
            if ret < 0 {
                let e = errno::Error::last();
                match e.errno() {
                    EAGAIN | EINTR => {}
                    _ => {
                        return Err(Error::ClearWaitPending(errno::Error::last()));
                    }
                }
            }

            // This sigset will be actually filled with `sigpending` call.
            let mut chkset: sigset_t = mem::zeroed();
            // See if more instances of the signal are pending.
            let ret = sigpending(&mut chkset);
            if ret < 0 {
                return Err(Error::ClearGetPending(errno::Error::last()));
            }

            let ret = sigismember(&chkset, num);
            if ret < 0 {
                return Err(Error::ClearCheckPending(errno::Error::last()));
            }

            // This is do-while loop condition.
            ret != 0
        }
    }
    {}

    Ok(())
}

/// Trait for threads that can be signalled via `pthread_kill`.
///
/// Note that this is only useful for signals between SIGRTMIN and SIGRTMAX because these are
/// guaranteed to not be used by the C runtime.
///
/// This is marked unsafe because the implementation of this trait must guarantee that the returned
/// pthread_t is valid and has a lifetime at least that of the trait object.
pub unsafe trait Killable {
    fn pthread_handle(&self) -> pthread_t;

    /// Sends the signal `num` to this killable thread.
    ///
    /// The value of `num` must be within [`SIGRTMIN`, `SIGRTMAX`] range.
    fn kill(&self, num: c_int) -> errno::Result<()> {
        if !valid_signal_num(num) {
            return Err(errno::Error::new(EINVAL));
        }

        // Safe because we ensure we are using a valid pthread handle, a valid signal number, and
        // check the return result.
        let ret = unsafe { pthread_kill(self.pthread_handle(), num) };
        if ret < 0 {
            return errno_result();
        }
        Ok(())
    }
}

// Safe because we fulfill our contract of returning a genuine pthread handle.
unsafe impl<T> Killable for JoinHandle<T> {
    fn pthread_handle(&self) -> pthread_t {
        self.as_pthread_t()
    }
}
<|endoftext|>


<commit_before>#[cfg(unix)]
extern crate nix;
#[cfg(windows)]
extern crate libc;

use std::io::Result;
use std::net::{UdpSocket, SocketAddr};

/// A trait to make time-limited reads from socket-like objects.
pub trait WithReadTimeout {
    /// Receives data from the object, blocking for at most the specified number of milliseconds.
    /// On success, returns the number of bytes read and the address from whence the data came.  If
    /// the timeout expires, it returns `ErrorKind::WouldBlock`.
    fn recv_timeout(&mut self, &mut [u8], i64) -> Result<(usize, SocketAddr)>;
}

impl WithReadTimeout for UdpSocket {
    #[cfg(unix)]
    fn recv_timeout(&mut self, buf: &mut [u8], timeout: i64) -> Result<(usize, SocketAddr)> {
        use nix::sys::socket::{SockLevel, sockopt, setsockopt};
        use nix::sys::time::TimeVal;
        use std::os::unix::io::AsRawFd;

        setsockopt(self.as_raw_fd(),
                   SockLevel::Socket,
                   sockopt::ReceiveTimeout,
                   &TimeVal::milliseconds(timeout)).unwrap();
        self.recv_from(buf)
    }

    #[cfg(windows)]
    fn recv_timeout(&mut self, buf: &mut [u8], timeout: i64) -> Result<(usize, SocketAddr)> {
        use select::fd_set;
        use std::os::windows::io::AsRawSocket;
        use std::io::{Error, ErrorKind};
        use libc;

        // Initialize relevant data structures
        let mut readfds = fd_set::new();

        // TODO: Properly create C NULL pointers
        let mut null: &mut fd_set = unsafe { std::mem::transmute(0usize) };

        fd_set(&mut readfds, self.as_raw_socket());

        // Set timeout
        let mut tv = libc::timeval {
            tv_sec: timeout as i32 / 1000,
            tv_usec: (timeout as i32 % 1000) * 1000,
        };

        // In Windows, the first argument to `select` is ignored.
        let retval = unsafe { select::select(0, &mut readfds, null, null, &mut tv) };
        if retval == 0 {
            return Err(Error::new(ErrorKind::TimedOut, "Time limit expired"));
        } else if retval < 0 {
            return Err(Error::last_os_error());
        }

        self.recv_from(buf)
    }
}

// Most of the following was copied from 'rust/src/libstd/sys/windows/net.rs'
#[cfg(windows)]
mod select {
    use libc;

    pub const FD_SETSIZE: usize = 64;

    #[repr(C)]
    pub struct fd_set {
        fd_count: libc::c_uint,
        fd_array: [libc::SOCKET; FD_SETSIZE],
    }

    pub fn fd_set(set: &mut fd_set, s: libc::SOCKET) {
        set.fd_array[set.fd_count as usize] = s;
        set.fd_count += 1;
    }

    impl fd_set {
        pub fn new() -> fd_set {
            fd_set {
                fd_count: 0,
                fd_array: [0; FD_SETSIZE],
            }
        }
    }

    #[link(name = "ws2_32")]
    extern "system" {
        pub fn select(nfds: libc::c_int,
                      readfds: *mut fd_set,
                      writefds: *mut fd_set,
                      exceptfds: *mut fd_set,
                      timeout: *mut libc::timeval) -> libc::c_int;
    }
}

#[test]
fn test_socket_timeout() {
    let mut socket = UdpSocket::bind("0.0.0.0:0").unwrap();
    let mut buf = [0; 10];
    assert!(socket.recv_timeout(&mut buf, 100).is_err());
}
<commit_msg>Use proper null pointers.<commit_after>#[cfg(unix)]
extern crate nix;
#[cfg(windows)]
extern crate libc;

use std::io::Result;
use std::net::{UdpSocket, SocketAddr};

/// A trait to make time-limited reads from socket-like objects.
pub trait WithReadTimeout {
    /// Receives data from the object, blocking for at most the specified number of milliseconds.
    /// On success, returns the number of bytes read and the address from whence the data came.  If
    /// the timeout expires, it returns `ErrorKind::WouldBlock`.
    fn recv_timeout(&mut self, &mut [u8], i64) -> Result<(usize, SocketAddr)>;
}

impl WithReadTimeout for UdpSocket {
    #[cfg(unix)]
    fn recv_timeout(&mut self, buf: &mut [u8], timeout: i64) -> Result<(usize, SocketAddr)> {
        use nix::sys::socket::{SockLevel, sockopt, setsockopt};
        use nix::sys::time::TimeVal;
        use std::os::unix::io::AsRawFd;

        setsockopt(self.as_raw_fd(),
                   SockLevel::Socket,
                   sockopt::ReceiveTimeout,
                   &TimeVal::milliseconds(timeout)).unwrap();
        self.recv_from(buf)
    }

    #[cfg(windows)]
    fn recv_timeout(&mut self, buf: &mut [u8], timeout: i64) -> Result<(usize, SocketAddr)> {
        use select::fd_set;
        use std::os::windows::io::AsRawSocket;
        use std::io::{Error, ErrorKind};
        use libc;

        // Initialize relevant data structures
        let mut readfds = fd_set::new();
        let null = std::ptr::null_mut();

        fd_set(&mut readfds, self.as_raw_socket());

        // Set timeout
        let mut tv = libc::timeval {
            tv_sec: timeout as i32 / 1000,
            tv_usec: (timeout as i32 % 1000) * 1000,
        };

        // In Windows, the first argument to `select` is ignored.
        let retval = unsafe { select::select(0, &mut readfds, null, null, &mut tv) };
        if retval == 0 {
            return Err(Error::new(ErrorKind::TimedOut, "Time limit expired"));
        } else if retval < 0 {
            return Err(Error::last_os_error());
        }

        self.recv_from(buf)
    }
}

// Most of the following was copied from 'rust/src/libstd/sys/windows/net.rs'
#[cfg(windows)]
mod select {
    use libc;

    pub const FD_SETSIZE: usize = 64;

    #[repr(C)]
    pub struct fd_set {
        fd_count: libc::c_uint,
        fd_array: [libc::SOCKET; FD_SETSIZE],
    }

    pub fn fd_set(set: &mut fd_set, s: libc::SOCKET) {
        set.fd_array[set.fd_count as usize] = s;
        set.fd_count += 1;
    }

    impl fd_set {
        pub fn new() -> fd_set {
            fd_set {
                fd_count: 0,
                fd_array: [0; FD_SETSIZE],
            }
        }
    }

    #[link(name = "ws2_32")]
    extern "system" {
        pub fn select(nfds: libc::c_int,
                      readfds: *mut fd_set,
                      writefds: *mut fd_set,
                      exceptfds: *mut fd_set,
                      timeout: *mut libc::timeval) -> libc::c_int;
    }
}

#[test]
fn test_socket_timeout() {
    let mut socket = UdpSocket::bind("0.0.0.0:0").unwrap();
    let mut buf = [0; 10];
    assert!(socket.recv_timeout(&mut buf, 100).is_err());
}
<|endoftext|>