<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, 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()
    }
}
<commit_msg>sys_util: use sigaction() instead of signal() when installing handler<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, sigaction, timespec,
           sigset_t, siginfo_t,
           sigaddset, sigemptyset, sigismember, sigpending, sigtimedwait,
           pthread_t, pthread_kill, pthread_sigmask,
           SIG_BLOCK, SIG_UNBLOCK, 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 mut sigact: sigaction = mem::zeroed();
    sigact.sa_sigaction = handler as *const () as usize;

    let ret = sigaction(num, &sigact, null_mut());
    if ret < 0 {
        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 consume 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>use crate::common::util::*;

#[test]
fn basic_literal() {
    new_ucmd!()
        .args(&["hello world"])
        .succeeds()
        .stdout_only("hello world");
}

#[test]
fn escaped_tab() {
    new_ucmd!()
        .args(&["hello\\t world"])
        .succeeds()
        .stdout_only("hello\t world");
}

#[test]
fn escaped_newline() {
    new_ucmd!()
        .args(&["hello\\n world"])
        .succeeds()
        .stdout_only("hello\n world");
}

#[test]
fn escaped_slash() {
    new_ucmd!()
        .args(&["hello\\\\ world"])
        .succeeds()
        .stdout_only("hello\\ world");
}

#[test]
fn escaped_hex() {
    new_ucmd!().args(&["\\x41"]).succeeds().stdout_only("A");
}

#[test]
fn escaped_octal() {
    new_ucmd!().args(&["\\101"]).succeeds().stdout_only("A");
}

#[test]
fn escaped_unicode_four_digit() {
    new_ucmd!().args(&["\\u0125"]).succeeds().stdout_only("ĥ");
}

#[test]
fn escaped_unicode_eight_digit() {
    new_ucmd!()
        .args(&["\\U00000125"])
        .succeeds()
        .stdout_only("ĥ");
}

#[test]
fn escaped_percent_sign() {
    new_ucmd!()
        .args(&["hello%% world"])
        .succeeds()
        .stdout_only("hello% world");
}

#[test]
fn escaped_unrecognized() {
    new_ucmd!().args(&["c\\d"]).succeeds().stdout_only("c\\d");
}

#[test]
fn sub_string() {
    new_ucmd!()
        .args(&["hello %s", "world"])
        .succeeds()
        .stdout_only("hello world");
}

#[test]
fn sub_multi_field() {
    new_ucmd!()
        .args(&["%s %s", "hello", "world"])
        .succeeds()
        .stdout_only("hello world");
}

#[test]
fn sub_repeat_format_str() {
    new_ucmd!()
        .args(&["%s.", "hello", "world"])
        .succeeds()
        .stdout_only("hello.world.");
}

#[test]
fn sub_string_ignore_escapes() {
    new_ucmd!()
        .args(&["hello %s", "\\tworld"])
        .succeeds()
        .stdout_only("hello \\tworld");
}

#[test]
fn sub_b_string_handle_escapes() {
    new_ucmd!()
        .args(&["hello %b", "\\tworld"])
        .succeeds()
        .stdout_only("hello \tworld");
}

#[test]
fn sub_b_string_ignore_subs() {
    new_ucmd!()
        .args(&["hello %b", "world %% %i"])
        .succeeds()
        .stdout_only("hello world %% %i");
}

#[test]
fn sub_char() {
    new_ucmd!()
        .args(&["the letter %c", "A"])
        .succeeds()
        .stdout_only("the letter A");
}

#[test]
fn sub_num_int() {
    new_ucmd!()
        .args(&["twenty is %i", "20"])
        .succeeds()
        .stdout_only("twenty is 20");
}

#[test]
fn sub_num_int_min_width() {
    new_ucmd!()
        .args(&["twenty is %1i", "20"])
        .succeeds()
        .stdout_only("twenty is 20");
}

#[test]
fn sub_num_int_neg() {
    new_ucmd!()
        .args(&["neg. twenty is %i", "-20"])
        .succeeds()
        .stdout_only("neg. twenty is -20");
}

#[test]
fn sub_num_int_oct_in() {
    new_ucmd!()
        .args(&["twenty is %i", "024"])
        .succeeds()
        .stdout_only("twenty is 20");
}

#[test]
fn sub_num_int_oct_in_neg() {
    new_ucmd!()
        .args(&["neg. twenty is %i", "-024"])
        .succeeds()
        .stdout_only("neg. twenty is -20");
}

#[test]
fn sub_num_int_hex_in() {
    new_ucmd!()
        .args(&["twenty is %i", "0x14"])
        .succeeds()
        .stdout_only("twenty is 20");
}

#[test]
fn sub_num_int_hex_in_neg() {
    new_ucmd!()
        .args(&["neg. twenty is %i", "-0x14"])
        .succeeds()
        .stdout_only("neg. twenty is -20");
}

#[test]
fn sub_num_int_char_const_in() {
    new_ucmd!()
        .args(&["ninety seven is %i", "'a"])
        .succeeds()
        .stdout_only("ninety seven is 97");
}

#[test]
fn sub_num_uint() {
    new_ucmd!()
        .args(&["twenty is %u", "20"])
        .succeeds()
        .stdout_only("twenty is 20");
}

#[test]
fn sub_num_octal() {
    new_ucmd!()
        .args(&["twenty in octal is %o", "20"])
        .succeeds()
        .stdout_only("twenty in octal is 24");
}

#[test]
fn sub_num_hex_lower() {
    new_ucmd!()
        .args(&["thirty in hex is %x", "30"])
        .succeeds()
        .stdout_only("thirty in hex is 1e");
}

#[test]
fn sub_num_hex_upper() {
    new_ucmd!()
        .args(&["thirty in hex is %X", "30"])
        .succeeds()
        .stdout_only("thirty in hex is 1E");
}

#[test]
fn sub_num_float() {
    new_ucmd!()
        .args(&["twenty is %f", "20"])
        .succeeds()
        .stdout_only("twenty is 20.000000");
}

#[test]
fn sub_num_float_e_round() {
    new_ucmd!()
        .args(&["%e", "99999999"])
        .succeeds()
        .stdout_only("1.000000e+08");
}

#[test]
fn sub_num_float_e_no_round() {
    new_ucmd!()
        .args(&["%e", "99999994"])
        .succeeds()
        .stdout_only("9.999999e+07");
}

#[test]
fn sub_num_float_round() {
    new_ucmd!()
        .args(&["two is %f", "1.9999995"])
        .succeeds()
        .stdout_only("two is 2.000000");
}

#[test]
fn sub_num_float_round_nines_dec() {
    new_ucmd!()
        .args(&["%f", "0.99999999"])
        .succeeds()
        .stdout_only("1.000000");
}

#[test]
fn sub_num_sci_lower() {
    new_ucmd!()
        .args(&["twenty is %e", "20"])
        .succeeds()
        .stdout_only("twenty is 2.000000e+01");
}

#[test]
fn sub_num_sci_upper() {
    new_ucmd!()
        .args(&["twenty is %E", "20"])
        .succeeds()
        .stdout_only("twenty is 2.000000E+01");
}

#[test]
fn sub_num_sci_trunc() {
    new_ucmd!()
        .args(&["pi is ~ %e", "3.1415926535"])
        .succeeds()
        .stdout_only("pi is ~ 3.141593e+00");
}

#[test]
fn sub_num_dec_trunc() {
    new_ucmd!()
        .args(&["pi is ~ %g", "3.1415926535"])
        .succeeds()
        .stdout_only("pi is ~ 3.14159");
}

#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn sub_num_hex_float_lower() {
    new_ucmd!()
        .args(&["%a", ".875"])
        .succeeds()
        .stdout_only("0xep-4");
}

#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn sub_num_hex_float_upper() {
    new_ucmd!()
        .args(&["%A", ".875"])
        .succeeds()
        .stdout_only("0XEP-4");
}

#[test]
fn sub_min_width() {
    new_ucmd!()
        .args(&["hello %7s", "world"])
        .succeeds()
        .stdout_only("hello   world");
}

#[test]
fn sub_min_width_negative() {
    new_ucmd!()
        .args(&["hello %-7s", "world"])
        .succeeds()
        .stdout_only("hello world  ");
}

#[test]
fn sub_str_max_chars_input() {
    new_ucmd!()
        .args(&["hello %7.2s", "world"])
        .succeeds()
        .stdout_only("hello      wo");
}

#[test]
fn sub_int_decimal() {
    new_ucmd!()
        .args(&["%0.i", "11"])
        .succeeds()
        .stdout_only("11");
}

#[test]
fn sub_int_leading_zeroes() {
    new_ucmd!()
        .args(&["%.4i", "11"])
        .succeeds()
        .stdout_only("0011");
}

#[test]
fn sub_int_leading_zeroes_padded() {
    new_ucmd!()
        .args(&["%5.4i", "11"])
        .succeeds()
        .stdout_only(" 0011");
}

#[test]
fn sub_float_dec_places() {
    new_ucmd!()
        .args(&["pi is ~ %.11f", "3.1415926535"])
        .succeeds()
        .stdout_only("pi is ~ 3.14159265350");
}

#[test]
fn sub_float_hex_in() {
    new_ucmd!()
        .args(&["%f", "0xF1.1F"])
        .succeeds()
        .stdout_only("241.121094");
}

#[test]
fn sub_float_no_octal_in() {
    new_ucmd!()
        .args(&["%f", "077"])
        .succeeds()
        .stdout_only("77.000000");
}

#[test]
fn sub_any_asterisk_first_param() {
    new_ucmd!()
        .args(&["%*i", "3", "11", "4", "12"])
        .succeeds()
        .stdout_only(" 11  12");
}

#[test]
fn sub_any_asterisk_second_param() {
    new_ucmd!()
        .args(&["%.*i", "3", "11", "4", "12"])
        .succeeds()
        .stdout_only("0110012");
}

#[test]
fn sub_any_asterisk_both_params() {
    new_ucmd!()
        .args(&["%*.*i", "4", "3", "11", "5", "4", "12"])
        .succeeds()
        .stdout_only(" 011 0012");
}

#[test]
fn sub_any_asterisk_octal_arg() {
    new_ucmd!()
        .args(&["%.*i", "011", "12345678"])
        .succeeds()
        .stdout_only("012345678");
}

#[test]
fn sub_any_asterisk_hex_arg() {
    new_ucmd!()
        .args(&["%.*i", "0xA", "123456789"])
        .succeeds()
        .stdout_only("0123456789");
}

#[test]
fn sub_any_specifiers_no_params() {
    new_ucmd!()
        .args(&["%ztlhLji", "3"]) //spell-checker:disable-line
        .succeeds()
        .stdout_only("3");
}

#[test]
fn sub_any_specifiers_after_first_param() {
    new_ucmd!()
        .args(&["%0ztlhLji", "3"]) //spell-checker:disable-line
        .succeeds()
        .stdout_only("3");
}

#[test]
fn sub_any_specifiers_after_period() {
    new_ucmd!()
        .args(&["%0.ztlhLji", "3"]) //spell-checker:disable-line
        .succeeds()
        .stdout_only("3");
}

#[test]
fn sub_any_specifiers_after_second_param() {
    new_ucmd!()
        .args(&["%0.0ztlhLji", "3"]) //spell-checker:disable-line
        .succeeds()
        .stdout_only("3");
}

#[test]
fn stop_after_additional_escape() {
    new_ucmd!()
        .args(&["A%sC\\cD%sF", "B", "E"]) //spell-checker:disable-line
        .succeeds()
        .stdout_only("ABC");
}

#[test]
fn sub_float_leading_zeroes() {
    new_ucmd!()
        .args(&["%010f", "1"])
        .succeeds()
        .stdout_only("001.000000");
}

#[test]
fn sub_general_float() {
    new_ucmd!()
        .args(&["%g", "1.1"])
        .succeeds()
        .stdout_only("1.1");
}

#[test]
fn sub_general_truncate_to_integer() {
    new_ucmd!()
        .args(&["%g", "1.0"])
        .succeeds()
        .stdout_only("1");
}

#[test]
fn sub_general_scientific_notation() {
    new_ucmd!()
        .args(&["%g", "1000010"])
        .succeeds()
        .stdout_only("1.00001e+06");
}

#[test]
fn sub_general_round_scientific_notation() {
    new_ucmd!()
        .args(&["%g", "123456789"])
        .succeeds()
        .stdout_only("1.23457e+08");
}

#[test]
fn sub_general_round_float() {
    new_ucmd!()
        .args(&["%g", "12345.6789"])
        .succeeds()
        .stdout_only("12345.7");
}

#[test]
fn sub_general_round_float_to_integer() {
    new_ucmd!()
        .args(&["%g", "123456.7"])
        .succeeds()
        .stdout_only("123457");
}
<commit_msg>Fix formatting<commit_after>use crate::common::util::*;

#[test]
fn basic_literal() {
    new_ucmd!()
        .args(&["hello world"])
        .succeeds()
        .stdout_only("hello world");
}

#[test]
fn escaped_tab() {
    new_ucmd!()
        .args(&["hello\\t world"])
        .succeeds()
        .stdout_only("hello\t world");
}

#[test]
fn escaped_newline() {
    new_ucmd!()
        .args(&["hello\\n world"])
        .succeeds()
        .stdout_only("hello\n world");
}

#[test]
fn escaped_slash() {
    new_ucmd!()
        .args(&["hello\\\\ world"])
        .succeeds()
        .stdout_only("hello\\ world");
}

#[test]
fn escaped_hex() {
    new_ucmd!().args(&["\\x41"]).succeeds().stdout_only("A");
}

#[test]
fn escaped_octal() {
    new_ucmd!().args(&["\\101"]).succeeds().stdout_only("A");
}

#[test]
fn escaped_unicode_four_digit() {
    new_ucmd!().args(&["\\u0125"]).succeeds().stdout_only("ĥ");
}

#[test]
fn escaped_unicode_eight_digit() {
    new_ucmd!()
        .args(&["\\U00000125"])
        .succeeds()
        .stdout_only("ĥ");
}

#[test]
fn escaped_percent_sign() {
    new_ucmd!()
        .args(&["hello%% world"])
        .succeeds()
        .stdout_only("hello% world");
}

#[test]
fn escaped_unrecognized() {
    new_ucmd!().args(&["c\\d"]).succeeds().stdout_only("c\\d");
}

#[test]
fn sub_string() {
    new_ucmd!()
        .args(&["hello %s", "world"])
        .succeeds()
        .stdout_only("hello world");
}

#[test]
fn sub_multi_field() {
    new_ucmd!()
        .args(&["%s %s", "hello", "world"])
        .succeeds()
        .stdout_only("hello world");
}

#[test]
fn sub_repeat_format_str() {
    new_ucmd!()
        .args(&["%s.", "hello", "world"])
        .succeeds()
        .stdout_only("hello.world.");
}

#[test]
fn sub_string_ignore_escapes() {
    new_ucmd!()
        .args(&["hello %s", "\\tworld"])
        .succeeds()
        .stdout_only("hello \\tworld");
}

#[test]
fn sub_b_string_handle_escapes() {
    new_ucmd!()
        .args(&["hello %b", "\\tworld"])
        .succeeds()
        .stdout_only("hello \tworld");
}

#[test]
fn sub_b_string_ignore_subs() {
    new_ucmd!()
        .args(&["hello %b", "world %% %i"])
        .succeeds()
        .stdout_only("hello world %% %i");
}

#[test]
fn sub_char() {
    new_ucmd!()
        .args(&["the letter %c", "A"])
        .succeeds()
        .stdout_only("the letter A");
}

#[test]
fn sub_num_int() {
    new_ucmd!()
        .args(&["twenty is %i", "20"])
        .succeeds()
        .stdout_only("twenty is 20");
}

#[test]
fn sub_num_int_min_width() {
    new_ucmd!()
        .args(&["twenty is %1i", "20"])
        .succeeds()
        .stdout_only("twenty is 20");
}

#[test]
fn sub_num_int_neg() {
    new_ucmd!()
        .args(&["neg. twenty is %i", "-20"])
        .succeeds()
        .stdout_only("neg. twenty is -20");
}

#[test]
fn sub_num_int_oct_in() {
    new_ucmd!()
        .args(&["twenty is %i", "024"])
        .succeeds()
        .stdout_only("twenty is 20");
}

#[test]
fn sub_num_int_oct_in_neg() {
    new_ucmd!()
        .args(&["neg. twenty is %i", "-024"])
        .succeeds()
        .stdout_only("neg. twenty is -20");
}

#[test]
fn sub_num_int_hex_in() {
    new_ucmd!()
        .args(&["twenty is %i", "0x14"])
        .succeeds()
        .stdout_only("twenty is 20");
}

#[test]
fn sub_num_int_hex_in_neg() {
    new_ucmd!()
        .args(&["neg. twenty is %i", "-0x14"])
        .succeeds()
        .stdout_only("neg. twenty is -20");
}

#[test]
fn sub_num_int_char_const_in() {
    new_ucmd!()
        .args(&["ninety seven is %i", "'a"])
        .succeeds()
        .stdout_only("ninety seven is 97");
}

#[test]
fn sub_num_uint() {
    new_ucmd!()
        .args(&["twenty is %u", "20"])
        .succeeds()
        .stdout_only("twenty is 20");
}

#[test]
fn sub_num_octal() {
    new_ucmd!()
        .args(&["twenty in octal is %o", "20"])
        .succeeds()
        .stdout_only("twenty in octal is 24");
}

#[test]
fn sub_num_hex_lower() {
    new_ucmd!()
        .args(&["thirty in hex is %x", "30"])
        .succeeds()
        .stdout_only("thirty in hex is 1e");
}

#[test]
fn sub_num_hex_upper() {
    new_ucmd!()
        .args(&["thirty in hex is %X", "30"])
        .succeeds()
        .stdout_only("thirty in hex is 1E");
}

#[test]
fn sub_num_float() {
    new_ucmd!()
        .args(&["twenty is %f", "20"])
        .succeeds()
        .stdout_only("twenty is 20.000000");
}

#[test]
fn sub_num_float_e_round() {
    new_ucmd!()
        .args(&["%e", "99999999"])
        .succeeds()
        .stdout_only("1.000000e+08");
}

#[test]
fn sub_num_float_e_no_round() {
    new_ucmd!()
        .args(&["%e", "99999994"])
        .succeeds()
        .stdout_only("9.999999e+07");
}

#[test]
fn sub_num_float_round() {
    new_ucmd!()
        .args(&["two is %f", "1.9999995"])
        .succeeds()
        .stdout_only("two is 2.000000");
}

#[test]
fn sub_num_float_round_nines_dec() {
    new_ucmd!()
        .args(&["%f", "0.99999999"])
        .succeeds()
        .stdout_only("1.000000");
}

#[test]
fn sub_num_sci_lower() {
    new_ucmd!()
        .args(&["twenty is %e", "20"])
        .succeeds()
        .stdout_only("twenty is 2.000000e+01");
}

#[test]
fn sub_num_sci_upper() {
    new_ucmd!()
        .args(&["twenty is %E", "20"])
        .succeeds()
        .stdout_only("twenty is 2.000000E+01");
}

#[test]
fn sub_num_sci_trunc() {
    new_ucmd!()
        .args(&["pi is ~ %e", "3.1415926535"])
        .succeeds()
        .stdout_only("pi is ~ 3.141593e+00");
}

#[test]
fn sub_num_dec_trunc() {
    new_ucmd!()
        .args(&["pi is ~ %g", "3.1415926535"])
        .succeeds()
        .stdout_only("pi is ~ 3.14159");
}

#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn sub_num_hex_float_lower() {
    new_ucmd!()
        .args(&["%a", ".875"])
        .succeeds()
        .stdout_only("0xep-4");
}

#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
#[test]
fn sub_num_hex_float_upper() {
    new_ucmd!()
        .args(&["%A", ".875"])
        .succeeds()
        .stdout_only("0XEP-4");
}

#[test]
fn sub_min_width() {
    new_ucmd!()
        .args(&["hello %7s", "world"])
        .succeeds()
        .stdout_only("hello   world");
}

#[test]
fn sub_min_width_negative() {
    new_ucmd!()
        .args(&["hello %-7s", "world"])
        .succeeds()
        .stdout_only("hello world  ");
}

#[test]
fn sub_str_max_chars_input() {
    new_ucmd!()
        .args(&["hello %7.2s", "world"])
        .succeeds()
        .stdout_only("hello      wo");
}

#[test]
fn sub_int_decimal() {
    new_ucmd!()
        .args(&["%0.i", "11"])
        .succeeds()
        .stdout_only("11");
}

#[test]
fn sub_int_leading_zeroes() {
    new_ucmd!()
        .args(&["%.4i", "11"])
        .succeeds()
        .stdout_only("0011");
}

#[test]
fn sub_int_leading_zeroes_padded() {
    new_ucmd!()
        .args(&["%5.4i", "11"])
        .succeeds()
        .stdout_only(" 0011");
}

#[test]
fn sub_float_dec_places() {
    new_ucmd!()
        .args(&["pi is ~ %.11f", "3.1415926535"])
        .succeeds()
        .stdout_only("pi is ~ 3.14159265350");
}

#[test]
fn sub_float_hex_in() {
    new_ucmd!()
        .args(&["%f", "0xF1.1F"])
        .succeeds()
        .stdout_only("241.121094");
}

#[test]
fn sub_float_no_octal_in() {
    new_ucmd!()
        .args(&["%f", "077"])
        .succeeds()
        .stdout_only("77.000000");
}

#[test]
fn sub_any_asterisk_first_param() {
    new_ucmd!()
        .args(&["%*i", "3", "11", "4", "12"])
        .succeeds()
        .stdout_only(" 11  12");
}

#[test]
fn sub_any_asterisk_second_param() {
    new_ucmd!()
        .args(&["%.*i", "3", "11", "4", "12"])
        .succeeds()
        .stdout_only("0110012");
}

#[test]
fn sub_any_asterisk_both_params() {
    new_ucmd!()
        .args(&["%*.*i", "4", "3", "11", "5", "4", "12"])
        .succeeds()
        .stdout_only(" 011 0012");
}

#[test]
fn sub_any_asterisk_octal_arg() {
    new_ucmd!()
        .args(&["%.*i", "011", "12345678"])
        .succeeds()
        .stdout_only("012345678");
}

#[test]
fn sub_any_asterisk_hex_arg() {
    new_ucmd!()
        .args(&["%.*i", "0xA", "123456789"])
        .succeeds()
        .stdout_only("0123456789");
}

#[test]
fn sub_any_specifiers_no_params() {
    new_ucmd!()
        .args(&["%ztlhLji", "3"]) //spell-checker:disable-line
        .succeeds()
        .stdout_only("3");
}

#[test]
fn sub_any_specifiers_after_first_param() {
    new_ucmd!()
        .args(&["%0ztlhLji", "3"]) //spell-checker:disable-line
        .succeeds()
        .stdout_only("3");
}

#[test]
fn sub_any_specifiers_after_period() {
    new_ucmd!()
        .args(&["%0.ztlhLji", "3"]) //spell-checker:disable-line
        .succeeds()
        .stdout_only("3");
}

#[test]
fn sub_any_specifiers_after_second_param() {
    new_ucmd!()
        .args(&["%0.0ztlhLji", "3"]) //spell-checker:disable-line
        .succeeds()
        .stdout_only("3");
}

#[test]
fn stop_after_additional_escape() {
    new_ucmd!()
        .args(&["A%sC\\cD%sF", "B", "E"]) //spell-checker:disable-line
        .succeeds()
        .stdout_only("ABC");
}

#[test]
fn sub_float_leading_zeroes() {
    new_ucmd!()
        .args(&["%010f", "1"])
        .succeeds()
        .stdout_only("001.000000");
}

#[test]
fn sub_general_float() {
    new_ucmd!()
        .args(&["%g", "1.1"])
        .succeeds()
        .stdout_only("1.1");
}

#[test]
fn sub_general_truncate_to_integer() {
    new_ucmd!().args(&["%g", "1.0"]).succeeds().stdout_only("1");
}

#[test]
fn sub_general_scientific_notation() {
    new_ucmd!()
        .args(&["%g", "1000010"])
        .succeeds()
        .stdout_only("1.00001e+06");
}

#[test]
fn sub_general_round_scientific_notation() {
    new_ucmd!()
        .args(&["%g", "123456789"])
        .succeeds()
        .stdout_only("1.23457e+08");
}

#[test]
fn sub_general_round_float() {
    new_ucmd!()
        .args(&["%g", "12345.6789"])
        .succeeds()
        .stdout_only("12345.7");
}

#[test]
fn sub_general_round_float_to_integer() {
    new_ucmd!()
        .args(&["%g", "123456.7"])
        .succeeds()
        .stdout_only("123457");
}
<|endoftext|>


<commit_before>use std::net::IpAddr;

use hyper::header;
use hyper::method::Method;

use url::Position;

use urlencoded;

use unicase::UniCase;

use iron;
use iron::prelude::*;

use models;

header! { (XForwardedHost, "X-Forwarded-Host") => [String] }
header! { (XForwardedPort, "X-Forwarded-Port") => [u16] }
header! { (XForwardedProto, "X-Forwarded-Proto") => [String] }
header! { (XForwardedFor, "X-Forwarded-For") => (IpAddr)+ }

pub struct XForwardedMiddleware;

impl iron::middleware::BeforeMiddleware for XForwardedMiddleware {
    fn before(&self, request: &mut Request) -> IronResult<()> {
        macro_rules! h {
            ($x:path, $n:expr) => {{
                // FIXME: https://github.com/hyperium/hyper/issues/891
                let rv = match request.headers.get::<$x>() {
                    Some(x) => x.0.clone(),
                    None => {
                        panic!("Missing header: {:?}. Turn off use_proxy_headers or set proxy headers.", $n);
                    }
                };
                assert!(request.headers.remove::<$x>());
                rv
            }}
        }
        let host = h!(XForwardedHost, "X-Forwarded-Host");
        let port = h!(XForwardedPort, "X-Forwarded-Port");
        let scheme = h!(XForwardedProto, "X-Forwarded-Proto");
        let remote_addr = h!(XForwardedFor, "X-Forwarded-For")[0];

        // FIXME: https://github.com/iron/iron/pull/475
        let mut url = request.url.clone().into_generic_url();
        url.set_host(Some(&host)).unwrap();
        url.set_port(Some(port)).unwrap();
        url.set_scheme(&scheme).unwrap();

        request.url = iron::Url::from_generic_url(url).unwrap();
        request.remote_addr.set_ip(remote_addr);
        Ok(())
    }
}

pub struct SecurityHeaderMiddleware;

impl iron::middleware::AfterMiddleware for SecurityHeaderMiddleware {
    fn after(&self, request: &mut Request, mut response: Response) -> IronResult<Response> {
        Self::set_security_headers(request, &mut response);
        Ok(response)
    }

    fn catch(&self, request: &mut Request, mut error: IronError) -> IronResult<Response> {
        Self::set_security_headers(request, &mut error.response);
        Err(error)
    }
}

impl SecurityHeaderMiddleware {
    fn set_security_headers(rq: &Request, r: &mut Response) {
        Self::set_cors_headers(rq, r);
        r.headers.set_raw("X-Content-Type-Options", vec![b"nosniff".to_vec()]);
        r.headers.set_raw("X-XSS-Protection", vec![b"1; mode=block".to_vec()]);

        let mut csp = vec!["default-src 'self'"];

        if rq.url.path()[0] != "storage" {
            // It's probably fine to embed user storage data into other documents

            // Prevent clickjacking attacks like described in OAuth RFC
            // https://tools.ietf.org/html/rfc6749#section-10.13
            r.headers.set_raw("X-Frame-Options", vec![b"DENY".to_vec()]);

            // This is a newer way to do what X-Frame-Options does
            // http://www.w3.org/TR/CSP11/#frame-ancestors-and-frame-options
            csp.push("frame-ancestors 'none'");
        };
        r.headers.set_raw("Content-Security-Policy", vec![csp.join(";").as_bytes().to_vec()]);
    }

    /// Required by remoteStorage spec
    fn set_cors_headers(rq: &Request, r: &mut Response) {
        match &rq.url.path()[0][..] {
            ".well-known" | "storage" => (),
            _ => return
        };

        let origin = match rq.headers.get_raw("Origin") {
            Some(x) => if x.len() == 1 {
                match String::from_utf8(x.to_owned().into_iter().next().unwrap()) {
                    Ok(x) => x,
                    Err(_) => return
                }
            } else {
                return;
            },
            None => return
        };

        r.headers.set(header::AccessControlAllowOrigin::Value(origin));
        r.headers.set(header::AccessControlExposeHeaders(vec![
            UniCase("ETag".to_owned()),
            UniCase("Content-Length".to_owned())
        ]));
        r.headers.set(header::AccessControlAllowMethods(vec![Method::Get, Method::Put, Method::Delete]));
        r.headers.set(header::AccessControlAllowHeaders(vec![
            UniCase("Authorization".to_owned()),
            UniCase("Content-Type".to_owned()),
            UniCase("Origin".to_owned()),
            UniCase("If-Match".to_owned()),
            UniCase("If-None-Match".to_owned()),
        ]));
    }
}

pub trait EtagMatcher {
    fn matches_etag(&self, given: Option<&str>) -> bool;
}

impl EtagMatcher for header::IfNoneMatch {
    fn matches_etag(&self, given: Option<&str>) -> bool {
        match *self {
            header::IfNoneMatch::Any => given.is_some(),
            header::IfNoneMatch::Items(ref values) => {
                match given {
                    Some(given_value) => values.iter().any(|val| val.tag() == &given_value[..]),
                    None => false
                }
            }
        }
    }
}

impl EtagMatcher for header::IfMatch {
    fn matches_etag(&self, given: Option<&str>) -> bool {
        match *self {
            header::IfMatch::Any => given.is_some(),
            header::IfMatch::Items(ref values) => {
                match given {
                    Some(given_value) => values.iter().any(|val| val.tag() == &given_value[..]),
                    None => false
                }
            }
        }
    }
}

pub fn preconditions_ok(request: &Request, etag: Option<&str>) -> bool {
    if let Some(header) = request.headers.get::<header::IfNoneMatch>() {
        if header.matches_etag(etag) {
            return false
        }
    };

    if let Some(header) = request.headers.get::<header::IfMatch>() {
        if !header.matches_etag(etag) {
            return false
        }
    };
    true
}

pub trait FormDataHelper<K: ?Sized, V> {
    fn get_only<Q: AsRef<K>>(&self, k: Q) -> Option<&String>;
}

impl FormDataHelper<str, String> for urlencoded::QueryMap {
    fn get_only<Q: AsRef<str>>(&self, k: Q) -> Option<&String> {
        match self.get(&k.as_ref().to_owned()) {
            Some(x) if x.len() == 1 => Some(&x[0]),
            _ => None
        }
    }
}

pub fn get_account_id(user: &models::User, request: &Request) -> String {
    // FIXME: https://github.com/iron/iron/pull/475
    let url = request.url.clone().into_generic_url();
    let netloc = &url[Position::BeforeHost..Position::AfterPort];
    format!("{}@{}", user.userid, netloc)
}
<commit_msg>Debugging proxy headers<commit_after>use std::net::IpAddr;

use hyper::header;
use hyper::method::Method;

use url::Position;

use urlencoded;

use unicase::UniCase;

use iron;
use iron::prelude::*;

use models;

header! { (XForwardedHost, "X-Forwarded-Host") => [String] }
header! { (XForwardedPort, "X-Forwarded-Port") => [u16] }
header! { (XForwardedProto, "X-Forwarded-Proto") => [String] }
header! { (XForwardedFor, "X-Forwarded-For") => (IpAddr)+ }

pub struct XForwardedMiddleware;

impl iron::middleware::BeforeMiddleware for XForwardedMiddleware {
    fn before(&self, request: &mut Request) -> IronResult<()> {
        macro_rules! h {
            ($x:path, $n:expr) => {{
                // FIXME: https://github.com/hyperium/hyper/issues/891
                let rv = match request.headers.get::<$x>() {
                    Some(x) => x.0.clone(),
                    None => match request.headers.get_raw($n) {
                        Some(raw_val) => panic!("Malformed header: {}: {:?}", $n, raw_val),
                        None => panic!("Missing header: {:?}. Turn off use_proxy_headers or set proxy headers.", $n)
                    }
                };
                assert!(request.headers.remove::<$x>());
                rv
            }}
        }
        let host = h!(XForwardedHost, "X-Forwarded-Host");
        let port = h!(XForwardedPort, "X-Forwarded-Port");
        let scheme = h!(XForwardedProto, "X-Forwarded-Proto");
        let remote_addr = h!(XForwardedFor, "X-Forwarded-For")[0];

        // FIXME: https://github.com/iron/iron/pull/475
        let mut url = request.url.clone().into_generic_url();
        url.set_host(Some(&host)).unwrap();
        url.set_port(Some(port)).unwrap();
        url.set_scheme(&scheme).unwrap();

        request.url = iron::Url::from_generic_url(url).unwrap();
        request.remote_addr.set_ip(remote_addr);
        Ok(())
    }
}

pub struct SecurityHeaderMiddleware;

impl iron::middleware::AfterMiddleware for SecurityHeaderMiddleware {
    fn after(&self, request: &mut Request, mut response: Response) -> IronResult<Response> {
        Self::set_security_headers(request, &mut response);
        Ok(response)
    }

    fn catch(&self, request: &mut Request, mut error: IronError) -> IronResult<Response> {
        Self::set_security_headers(request, &mut error.response);
        Err(error)
    }
}

impl SecurityHeaderMiddleware {
    fn set_security_headers(rq: &Request, r: &mut Response) {
        Self::set_cors_headers(rq, r);
        r.headers.set_raw("X-Content-Type-Options", vec![b"nosniff".to_vec()]);
        r.headers.set_raw("X-XSS-Protection", vec![b"1; mode=block".to_vec()]);

        let mut csp = vec!["default-src 'self'"];

        if rq.url.path()[0] != "storage" {
            // It's probably fine to embed user storage data into other documents

            // Prevent clickjacking attacks like described in OAuth RFC
            // https://tools.ietf.org/html/rfc6749#section-10.13
            r.headers.set_raw("X-Frame-Options", vec![b"DENY".to_vec()]);

            // This is a newer way to do what X-Frame-Options does
            // http://www.w3.org/TR/CSP11/#frame-ancestors-and-frame-options
            csp.push("frame-ancestors 'none'");
        };
        r.headers.set_raw("Content-Security-Policy", vec![csp.join(";").as_bytes().to_vec()]);
    }

    /// Required by remoteStorage spec
    fn set_cors_headers(rq: &Request, r: &mut Response) {
        match &rq.url.path()[0][..] {
            ".well-known" | "storage" => (),
            _ => return
        };

        let origin = match rq.headers.get_raw("Origin") {
            Some(x) => if x.len() == 1 {
                match String::from_utf8(x.to_owned().into_iter().next().unwrap()) {
                    Ok(x) => x,
                    Err(_) => return
                }
            } else {
                return;
            },
            None => return
        };

        r.headers.set(header::AccessControlAllowOrigin::Value(origin));
        r.headers.set(header::AccessControlExposeHeaders(vec![
            UniCase("ETag".to_owned()),
            UniCase("Content-Length".to_owned())
        ]));
        r.headers.set(header::AccessControlAllowMethods(vec![Method::Get, Method::Put, Method::Delete]));
        r.headers.set(header::AccessControlAllowHeaders(vec![
            UniCase("Authorization".to_owned()),
            UniCase("Content-Type".to_owned()),
            UniCase("Origin".to_owned()),
            UniCase("If-Match".to_owned()),
            UniCase("If-None-Match".to_owned()),
        ]));
    }
}

pub trait EtagMatcher {
    fn matches_etag(&self, given: Option<&str>) -> bool;
}

impl EtagMatcher for header::IfNoneMatch {
    fn matches_etag(&self, given: Option<&str>) -> bool {
        match *self {
            header::IfNoneMatch::Any => given.is_some(),
            header::IfNoneMatch::Items(ref values) => {
                match given {
                    Some(given_value) => values.iter().any(|val| val.tag() == &given_value[..]),
                    None => false
                }
            }
        }
    }
}

impl EtagMatcher for header::IfMatch {
    fn matches_etag(&self, given: Option<&str>) -> bool {
        match *self {
            header::IfMatch::Any => given.is_some(),
            header::IfMatch::Items(ref values) => {
                match given {
                    Some(given_value) => values.iter().any(|val| val.tag() == &given_value[..]),
                    None => false
                }
            }
        }
    }
}

pub fn preconditions_ok(request: &Request, etag: Option<&str>) -> bool {
    if let Some(header) = request.headers.get::<header::IfNoneMatch>() {
        if header.matches_etag(etag) {
            return false
        }
    };

    if let Some(header) = request.headers.get::<header::IfMatch>() {
        if !header.matches_etag(etag) {
            return false
        }
    };
    true
}

pub trait FormDataHelper<K: ?Sized, V> {
    fn get_only<Q: AsRef<K>>(&self, k: Q) -> Option<&String>;
}

impl FormDataHelper<str, String> for urlencoded::QueryMap {
    fn get_only<Q: AsRef<str>>(&self, k: Q) -> Option<&String> {
        match self.get(&k.as_ref().to_owned()) {
            Some(x) if x.len() == 1 => Some(&x[0]),
            _ => None
        }
    }
}

pub fn get_account_id(user: &models::User, request: &Request) -> String {
    // FIXME: https://github.com/iron/iron/pull/475
    let url = request.url.clone().into_generic_url();
    let netloc = &url[Position::BeforeHost..Position::AfterPort];
    format!("{}@{}", user.userid, netloc)
}
<|endoftext|>


<commit_before>use analysis::conversion_type::ConversionType;
use analysis::parameter::Parameter as AnalysisParameter;
use analysis::out_parameters::Mode;
use analysis::return_value;
use analysis::rust_type::rust_type;
use analysis::safety_assertion_mode::SafetyAssertionMode;
use chunk::{chunks, Chunk, TupleMode};
use chunk::parameter_ffi_call_in;
use chunk::parameter_ffi_call_out;
use env::Env;

#[derive(Clone)]
enum Parameter {
    In {
        parameter: parameter_ffi_call_in::Parameter,
    },
    Out {
        parameter: parameter_ffi_call_out::Parameter,
        mem_mode: OutMemMode,
    },
}

#[derive(Clone, Eq, PartialEq)]
enum OutMemMode {
    Uninitialized,
    UninitializedNamed(String),
    NullPtr,
}

use self::Parameter::*;

#[derive(Default)]
pub struct Builder {
    glib_name: String,
    parameters: Vec<Parameter>,
    ret: return_value::Info,
    outs_as_return: bool,
    outs_mode: Mode,
    assertion: SafetyAssertionMode,
}

impl Builder {
    pub fn new() -> Builder {
        Default::default()
    }
    pub fn glib_name(&mut self, name: &str) -> &mut Builder {
        self.glib_name = name.into();
        self
    }
    pub fn assertion(&mut self, assertion: SafetyAssertionMode) -> &mut Builder {
        self.assertion = assertion;
        self
    }
    pub fn ret(&mut self, ret: &return_value::Info) -> &mut Builder {
        self.ret = ret.clone();
        self
    }
    pub fn parameter(&mut self, parameter: &AnalysisParameter) -> &mut Builder {
        self.parameters.push(Parameter::In {
            parameter: parameter.into(),
        });
        self
    }
    pub fn out_parameter(&mut self, env: &Env, parameter: &AnalysisParameter) -> &mut Builder {
        use self::OutMemMode::*;
        let mem_mode = match ConversionType::of(&env.library, parameter.typ) {
            ConversionType::Pointer => {
                if parameter.caller_allocates {
                    UninitializedNamed(rust_type(env, parameter.typ).unwrap())
                } else {
                    NullPtr
                }
            }
            _ => Uninitialized,
        };
        self.parameters.push(Parameter::Out {
            parameter: parameter.into(),
            mem_mode: mem_mode,
        });
        self.outs_as_return = true;
        self
    }
    pub fn outs_mode(&mut self, mode: Mode) -> &mut Builder {
        self.outs_mode = mode;
        self
    }
    pub fn generate(&self) -> Chunk {
        let mut body = Vec::new();

        if self.outs_as_return {
            self.write_out_variables(&mut body);
        }

        let call = self.generate_call();
        let call = self.generate_call_conversion(call);
        let ret = self.generate_out_return();
        let (call, ret) = self.apply_outs_mode(call, ret);

        body.push(call);
        if let Some(chunk) = ret {
            body.push(chunk);
        }

        let unsafe_ = Chunk::Unsafe(body);

        let mut chunks = Vec::new();
        self.add_assertion(&mut chunks);
        chunks.push(unsafe_);
        Chunk::BlockHalf(chunks)
    }
    fn add_assertion(&self, chunks: &mut Vec<Chunk>) {
        match self.assertion {
            SafetyAssertionMode::None => (),
            SafetyAssertionMode::Skip =>
                chunks.push(Chunk::AssertSkipInitialized),
            SafetyAssertionMode::InMainThread =>
                chunks.push(Chunk::AssertInitializedAndInMainThread),
        }
    }
    fn generate_call(&self) -> Chunk {
        let params = self.generate_func_parameters();
        let func = Chunk::FfiCall {
            name: self.glib_name.clone(),
            params: params,
        };
        func
    }
    fn generate_call_conversion(&self, call: Chunk) -> Chunk {
        let conv = Chunk::FfiCallConversion {
            ret: self.ret.clone(),
            call: Box::new(call),
        };
        conv
    }
    fn generate_func_parameters(&self) -> Vec<Chunk> {
        let mut params = Vec::new();
        for par in &self.parameters {
            let chunk = match *par {
                In { ref parameter } => Chunk::FfiCallParameter{
                    par: parameter.clone(),
                },
                Out { ref parameter, .. } => Chunk::FfiCallOutParameter{
                    par: parameter.clone(),
                },
            };
            params.push(chunk);
        }
        params
    }
    fn get_outs(&self) -> Vec<&Parameter> {
        self.parameters.iter()
            .filter_map(|par| if let Out{ .. } = *par { Some(par) } else { None })
            .collect()
    }
    fn get_outs_without_error(&self) -> Vec<&Parameter> {
        self.parameters.iter()
            .filter_map(|par| if let Out{ ref parameter, .. } = *par {
                if parameter.is_error {
                    None
                } else {
                    Some(par)
                }
            } else {
                None
            })
            .collect()
    }
    fn write_out_variables(&self, v: &mut Vec<Chunk>) {
        let outs = self.get_outs();
        for par in outs {
            if let Out{ ref parameter, ref mem_mode } = *par {
                let val = self.get_uninitialized(mem_mode);
                let chunk = Chunk::Let{
                    name: parameter.name.clone(),
                    is_mut: true,
                    value: Box::new(val),
                    type_: None,
                };
                v.push(chunk);
            }
        }
    }
    fn get_uninitialized(&self, mem_mode: &OutMemMode) -> Chunk {
        use self::OutMemMode::*;
        match *mem_mode {
            Uninitialized => Chunk::Uninitialized,
            UninitializedNamed(ref name) => Chunk::UninitializedNamed{ name: name.clone() },
            NullPtr => Chunk::NullMutPtr,
        }
    }
    fn generate_out_return(&self) -> Option<Chunk> {
        if !self.outs_as_return {
            return None;
        }
        let outs = self.get_outs_without_error();
        let mut chs: Vec<Chunk> = Vec::with_capacity(outs.len());
        for par in outs {
            if let Out{ ref parameter, ref mem_mode } = *par {
                chs.push(self.out_parameter_to_return(parameter, mem_mode));
            }
        }
        let chunk = Chunk::Tuple(chs, TupleMode::Auto);
        Some(chunk)
    }
    fn out_parameter_to_return(&self, parameter: &parameter_ffi_call_out::Parameter, mem_mode: &OutMemMode) -> Chunk {
        let value = Chunk::Custom(parameter.name.clone());
        if let OutMemMode::UninitializedNamed(_) = *mem_mode {
            value
        } else {
            Chunk::FromGlibConversion{
                mode: parameter.into(),
                value: Box::new(value),
            }
        }
    }
    fn apply_outs_mode(&self, call: Chunk, ret: Option<Chunk>) -> (Chunk, Option<Chunk>) {
        use analysis::out_parameters::Mode::*;
        match self.outs_mode {
            None => (call, ret),
            Normal => (call, ret),
            Optional => {
                let call = Chunk::Let{
                    name: "ret".into(),
                    is_mut: false,
                    value: Box::new(call),
                    type_: Option::None,
                };
                let ret = ret.expect("No return in optional outs mode");
                let ret = Chunk::OptionalReturn{
                    condition: "ret".into(),
                    value: Box::new(ret),
                };
                (call, Some(ret))
            }
            Combined => {
                let call = Chunk::Let{
                    name: "ret".into(),
                    is_mut: false,
                    value: Box::new(call),
                    type_: Option::None,
                };
                let mut ret = ret.expect("No return in combined outs mode");
                if let Chunk::Tuple(ref mut vec, _) = ret {
                    vec.insert(0, Chunk::Custom("ret".into()));
                }
                (call, Some(ret))
            }
            Throws(use_ret) => {
                //extracting original FFI function call
                let (boxed_call, ret_info) = if let Chunk::FfiCallConversion{call: inner, ret: ret_info} = call {
                    (inner, ret_info)
                } else {
                    panic!("Call without Chunk::FfiCallConversion")
                };
                let call = if use_ret {
                    Chunk::Let{
                        name: "ret".into(),
                        is_mut: false,
                        value: boxed_call,
                        type_: Option::None,
                    }
                } else {
                    Chunk::Let{
                        name: "_".into(),
                        is_mut: false,
                        value: boxed_call,
                        type_: Option::None,
                    }
                };
                let mut ret = ret.expect("No return in throws outs mode");
                if let Chunk::Tuple(ref mut vec, ref mut mode ) = ret {
                    *mode = TupleMode::WithUnit;
                    if use_ret {
                        let val = Chunk::Custom("ret".into());
                        let conv = Chunk::FfiCallConversion{
                            call: Box::new(val),
                            ret: ret_info,
                        };
                        vec.insert(0, conv);
                    }
                } else {
                    panic!("Return is not Tuple")
                }
                ret = Chunk::ErrorResultReturn{
                    value: Box::new(ret),
                };
                (call, Some(ret))
            }
        }
    }
}
<commit_msg>Fix unused import<commit_after>use analysis::conversion_type::ConversionType;
use analysis::parameter::Parameter as AnalysisParameter;
use analysis::out_parameters::Mode;
use analysis::return_value;
use analysis::rust_type::rust_type;
use analysis::safety_assertion_mode::SafetyAssertionMode;
use chunk::{Chunk, TupleMode};
use chunk::parameter_ffi_call_in;
use chunk::parameter_ffi_call_out;
use env::Env;

#[derive(Clone)]
enum Parameter {
    In {
        parameter: parameter_ffi_call_in::Parameter,
    },
    Out {
        parameter: parameter_ffi_call_out::Parameter,
        mem_mode: OutMemMode,
    },
}

#[derive(Clone, Eq, PartialEq)]
enum OutMemMode {
    Uninitialized,
    UninitializedNamed(String),
    NullPtr,
}

use self::Parameter::*;

#[derive(Default)]
pub struct Builder {
    glib_name: String,
    parameters: Vec<Parameter>,
    ret: return_value::Info,
    outs_as_return: bool,
    outs_mode: Mode,
    assertion: SafetyAssertionMode,
}

impl Builder {
    pub fn new() -> Builder {
        Default::default()
    }
    pub fn glib_name(&mut self, name: &str) -> &mut Builder {
        self.glib_name = name.into();
        self
    }
    pub fn assertion(&mut self, assertion: SafetyAssertionMode) -> &mut Builder {
        self.assertion = assertion;
        self
    }
    pub fn ret(&mut self, ret: &return_value::Info) -> &mut Builder {
        self.ret = ret.clone();
        self
    }
    pub fn parameter(&mut self, parameter: &AnalysisParameter) -> &mut Builder {
        self.parameters.push(Parameter::In {
            parameter: parameter.into(),
        });
        self
    }
    pub fn out_parameter(&mut self, env: &Env, parameter: &AnalysisParameter) -> &mut Builder {
        use self::OutMemMode::*;
        let mem_mode = match ConversionType::of(&env.library, parameter.typ) {
            ConversionType::Pointer => {
                if parameter.caller_allocates {
                    UninitializedNamed(rust_type(env, parameter.typ).unwrap())
                } else {
                    NullPtr
                }
            }
            _ => Uninitialized,
        };
        self.parameters.push(Parameter::Out {
            parameter: parameter.into(),
            mem_mode: mem_mode,
        });
        self.outs_as_return = true;
        self
    }
    pub fn outs_mode(&mut self, mode: Mode) -> &mut Builder {
        self.outs_mode = mode;
        self
    }
    pub fn generate(&self) -> Chunk {
        let mut body = Vec::new();

        if self.outs_as_return {
            self.write_out_variables(&mut body);
        }

        let call = self.generate_call();
        let call = self.generate_call_conversion(call);
        let ret = self.generate_out_return();
        let (call, ret) = self.apply_outs_mode(call, ret);

        body.push(call);
        if let Some(chunk) = ret {
            body.push(chunk);
        }

        let unsafe_ = Chunk::Unsafe(body);

        let mut chunks = Vec::new();
        self.add_assertion(&mut chunks);
        chunks.push(unsafe_);
        Chunk::BlockHalf(chunks)
    }
    fn add_assertion(&self, chunks: &mut Vec<Chunk>) {
        match self.assertion {
            SafetyAssertionMode::None => (),
            SafetyAssertionMode::Skip =>
                chunks.push(Chunk::AssertSkipInitialized),
            SafetyAssertionMode::InMainThread =>
                chunks.push(Chunk::AssertInitializedAndInMainThread),
        }
    }
    fn generate_call(&self) -> Chunk {
        let params = self.generate_func_parameters();
        let func = Chunk::FfiCall {
            name: self.glib_name.clone(),
            params: params,
        };
        func
    }
    fn generate_call_conversion(&self, call: Chunk) -> Chunk {
        let conv = Chunk::FfiCallConversion {
            ret: self.ret.clone(),
            call: Box::new(call),
        };
        conv
    }
    fn generate_func_parameters(&self) -> Vec<Chunk> {
        let mut params = Vec::new();
        for par in &self.parameters {
            let chunk = match *par {
                In { ref parameter } => Chunk::FfiCallParameter{
                    par: parameter.clone(),
                },
                Out { ref parameter, .. } => Chunk::FfiCallOutParameter{
                    par: parameter.clone(),
                },
            };
            params.push(chunk);
        }
        params
    }
    fn get_outs(&self) -> Vec<&Parameter> {
        self.parameters.iter()
            .filter_map(|par| if let Out{ .. } = *par { Some(par) } else { None })
            .collect()
    }
    fn get_outs_without_error(&self) -> Vec<&Parameter> {
        self.parameters.iter()
            .filter_map(|par| if let Out{ ref parameter, .. } = *par {
                if parameter.is_error {
                    None
                } else {
                    Some(par)
                }
            } else {
                None
            })
            .collect()
    }
    fn write_out_variables(&self, v: &mut Vec<Chunk>) {
        let outs = self.get_outs();
        for par in outs {
            if let Out{ ref parameter, ref mem_mode } = *par {
                let val = self.get_uninitialized(mem_mode);
                let chunk = Chunk::Let{
                    name: parameter.name.clone(),
                    is_mut: true,
                    value: Box::new(val),
                    type_: None,
                };
                v.push(chunk);
            }
        }
    }
    fn get_uninitialized(&self, mem_mode: &OutMemMode) -> Chunk {
        use self::OutMemMode::*;
        match *mem_mode {
            Uninitialized => Chunk::Uninitialized,
            UninitializedNamed(ref name) => Chunk::UninitializedNamed{ name: name.clone() },
            NullPtr => Chunk::NullMutPtr,
        }
    }
    fn generate_out_return(&self) -> Option<Chunk> {
        if !self.outs_as_return {
            return None;
        }
        let outs = self.get_outs_without_error();
        let mut chs: Vec<Chunk> = Vec::with_capacity(outs.len());
        for par in outs {
            if let Out{ ref parameter, ref mem_mode } = *par {
                chs.push(self.out_parameter_to_return(parameter, mem_mode));
            }
        }
        let chunk = Chunk::Tuple(chs, TupleMode::Auto);
        Some(chunk)
    }
    fn out_parameter_to_return(&self, parameter: &parameter_ffi_call_out::Parameter, mem_mode: &OutMemMode) -> Chunk {
        let value = Chunk::Custom(parameter.name.clone());
        if let OutMemMode::UninitializedNamed(_) = *mem_mode {
            value
        } else {
            Chunk::FromGlibConversion{
                mode: parameter.into(),
                value: Box::new(value),
            }
        }
    }
    fn apply_outs_mode(&self, call: Chunk, ret: Option<Chunk>) -> (Chunk, Option<Chunk>) {
        use analysis::out_parameters::Mode::*;
        match self.outs_mode {
            None => (call, ret),
            Normal => (call, ret),
            Optional => {
                let call = Chunk::Let{
                    name: "ret".into(),
                    is_mut: false,
                    value: Box::new(call),
                    type_: Option::None,
                };
                let ret = ret.expect("No return in optional outs mode");
                let ret = Chunk::OptionalReturn{
                    condition: "ret".into(),
                    value: Box::new(ret),
                };
                (call, Some(ret))
            }
            Combined => {
                let call = Chunk::Let{
                    name: "ret".into(),
                    is_mut: false,
                    value: Box::new(call),
                    type_: Option::None,
                };
                let mut ret = ret.expect("No return in combined outs mode");
                if let Chunk::Tuple(ref mut vec, _) = ret {
                    vec.insert(0, Chunk::Custom("ret".into()));
                }
                (call, Some(ret))
            }
            Throws(use_ret) => {
                //extracting original FFI function call
                let (boxed_call, ret_info) = if let Chunk::FfiCallConversion{call: inner, ret: ret_info} = call {
                    (inner, ret_info)
                } else {
                    panic!("Call without Chunk::FfiCallConversion")
                };
                let call = if use_ret {
                    Chunk::Let{
                        name: "ret".into(),
                        is_mut: false,
                        value: boxed_call,
                        type_: Option::None,
                    }
                } else {
                    Chunk::Let{
                        name: "_".into(),
                        is_mut: false,
                        value: boxed_call,
                        type_: Option::None,
                    }
                };
                let mut ret = ret.expect("No return in throws outs mode");
                if let Chunk::Tuple(ref mut vec, ref mut mode ) = ret {
                    *mode = TupleMode::WithUnit;
                    if use_ret {
                        let val = Chunk::Custom("ret".into());
                        let conv = Chunk::FfiCallConversion{
                            call: Box::new(val),
                            ret: ret_info,
                        };
                        vec.insert(0, conv);
                    }
                } else {
                    panic!("Return is not Tuple")
                }
                ret = Chunk::ErrorResultReturn{
                    value: Box::new(ret),
                };
                (call, Some(ret))
            }
        }
    }
}
<|endoftext|>


<commit_before>import std::vec;
import std::option;
import std::option::some;
import std::option::none;

import front::ast;
import front::ast::ident;
import front::ast::def_id;
import front::ast::ann;
import front::ast::item;
import front::ast::_fn;
import front::ast::_mod;
import front::ast::crate;
import front::ast::_obj;
import front::ast::ty_param;
import front::ast::item_fn;
import front::ast::item_obj;
import front::ast::item_ty;
import front::ast::item_tag;
import front::ast::item_const;
import front::ast::item_mod;
import front::ast::item_native_mod;
import front::ast::expr;
import front::ast::elt;
import front::ast::field;
import front::ast::decl;
import front::ast::decl_local;
import front::ast::decl_item;
import front::ast::initializer;
import front::ast::local;
import front::ast::arm;
import front::ast::expr_call;
import front::ast::expr_vec;
import front::ast::expr_tup;
import front::ast::expr_path;
import front::ast::expr_field;
import front::ast::expr_index;
import front::ast::expr_log;
import front::ast::expr_block;
import front::ast::expr_rec;
import front::ast::expr_if;
import front::ast::expr_binary;
import front::ast::expr_unary;
import front::ast::expr_assign;
import front::ast::expr_assign_op;
import front::ast::expr_while;
import front::ast::expr_do_while;
import front::ast::expr_alt;
import front::ast::expr_lit;
import front::ast::expr_ret;
import front::ast::expr_self_method;
import front::ast::expr_bind;
import front::ast::expr_spawn;
import front::ast::expr_ext;
import front::ast::expr_fail;
import front::ast::expr_break;
import front::ast::expr_cont;
import front::ast::expr_send;
import front::ast::expr_recv;
import front::ast::expr_put;
import front::ast::expr_port;
import front::ast::expr_chan;
import front::ast::expr_be;
import front::ast::expr_check;
import front::ast::expr_assert;
import front::ast::expr_cast;
import front::ast::expr_for;
import front::ast::expr_for_each;
import front::ast::stmt;
import front::ast::stmt_decl;
import front::ast::stmt_expr;
import front::ast::block;
import front::ast::block_;
import front::ast::method;

import middle::ty::expr_ann;

import util::common::uistr;
import util::common::span;
import util::common::new_str_hash;
import util::common::log_expr_err;
import util::common::log_block_err;
import util::common::log_item_err;
import util::common::log_stmt_err;
import util::common::log_expr;
import util::common::log_block;
import util::common::log_stmt;

import aux::fn_info;
import aux::fn_info_map;
import aux::num_locals;
import aux::get_fn_info;
import aux::crate_ctxt;
import aux::add_node;
import middle::tstate::ann::empty_ann;

fn collect_ids_expr(&@expr e, @vec[uint] res) -> () {
    vec::push(*res, (expr_ann(e)).id);
}
fn collect_ids_block(&block b, @vec[uint] res) -> () {
    vec::push(*res, b.node.a.id);
}

fn collect_ids_stmt(&@stmt s, @vec[uint] res) -> () {
    alt (s.node) {
        case (stmt_decl(_,?a)) {
            log("node_id " + uistr(a.id));
            log_stmt(*s);

            vec::push(*res, a.id);
        }
        case (stmt_expr(_,?a)) {
            log("node_id " + uistr(a.id));
            log_stmt(*s);

            vec::push(*res, a.id);
        }
        case (_) {}
    }
}

fn collect_ids_decl(&@decl d, @vec[uint] res) -> () {
    alt (d.node) {
        case (decl_local(?l)) {
            vec::push(*res, l.ann.id);
        }
        case (_) {}
    }
}

fn node_ids_in_fn(&_fn f, &ident i, &def_id d, &ann a, @vec[uint] res) -> () {
    auto collect_ids = walk::default_visitor();
    collect_ids = rec(visit_expr_pre  = bind collect_ids_expr(_,res),
                      visit_block_pre = bind collect_ids_block(_,res),
                      visit_stmt_pre  = bind collect_ids_stmt(_,res),
                      visit_decl_pre  = bind collect_ids_decl(_,res)
                      with collect_ids);
    walk::walk_fn(collect_ids, f, i, d, a);
}

fn init_vecs(&crate_ctxt ccx, @vec[uint] node_ids, uint len) -> () {
    for (uint i in *node_ids) {
        log(uistr(i) + " |-> " + uistr(len));
        add_node(ccx, i, empty_ann(len));
    }
}

fn visit_fn(&crate_ctxt ccx, uint num_locals, &_fn f, &ident i,
            &def_id d, &ann a) -> () {
    let vec[uint] node_ids_ = [];
    let @vec[uint] node_ids = @node_ids_;
    node_ids_in_fn(f, i, d, a, node_ids);
    init_vecs(ccx, node_ids, num_locals);
}

fn annotate_in_fn(&crate_ctxt ccx, &_fn f, &ident i, &def_id f_id, &ann a)
    -> () {
    auto f_info = get_fn_info(ccx, f_id);
    visit_fn(ccx, num_locals(f_info), f, i, f_id, a);
}

fn annotate_crate(&crate_ctxt ccx, &crate crate) -> () {
    auto do_ann = walk::default_visitor();
    do_ann = rec(visit_fn_pre = bind annotate_in_fn(ccx,_,_,_,_)
                 with do_ann);
    walk::walk_crate(do_ann, crate);
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>Just removing some unnecessary imports.<commit_after>import std::vec;
import std::option;
import std::option::some;
import std::option::none;

import front::ast;
import front::ast::ident;
import front::ast::def_id;
import front::ast::ann;
import front::ast::item;
import front::ast::_fn;
import front::ast::_mod;
import front::ast::crate;
import front::ast::_obj;
import front::ast::ty_param;
import front::ast::item_fn;
import front::ast::item_obj;
import front::ast::item_ty;
import front::ast::item_tag;
import front::ast::item_const;
import front::ast::item_mod;
import front::ast::item_native_mod;
import front::ast::expr;
import front::ast::elt;
import front::ast::field;
import front::ast::decl;
import front::ast::decl_local;
import front::ast::decl_item;
import front::ast::initializer;
import front::ast::local;
import front::ast::arm;
import front::ast::stmt;
import front::ast::stmt_decl;
import front::ast::stmt_expr;
import front::ast::block;
import front::ast::block_;
import front::ast::method;

import middle::ty::expr_ann;

import util::common::uistr;
import util::common::span;
import util::common::new_str_hash;
import util::common::log_expr_err;
import util::common::log_block_err;
import util::common::log_item_err;
import util::common::log_stmt_err;
import util::common::log_expr;
import util::common::log_block;
import util::common::log_stmt;

import aux::fn_info;
import aux::fn_info_map;
import aux::num_locals;
import aux::get_fn_info;
import aux::crate_ctxt;
import aux::add_node;
import middle::tstate::ann::empty_ann;

fn collect_ids_expr(&@expr e, @vec[uint] res) -> () {
    vec::push(*res, (expr_ann(e)).id);
}
fn collect_ids_block(&block b, @vec[uint] res) -> () {
    vec::push(*res, b.node.a.id);
}

fn collect_ids_stmt(&@stmt s, @vec[uint] res) -> () {
    alt (s.node) {
        case (stmt_decl(_,?a)) {
            log("node_id " + uistr(a.id));
            log_stmt(*s);

            vec::push(*res, a.id);
        }
        case (stmt_expr(_,?a)) {
            log("node_id " + uistr(a.id));
            log_stmt(*s);

            vec::push(*res, a.id);
        }
        case (_) {}
    }
}

fn collect_ids_decl(&@decl d, @vec[uint] res) -> () {
    alt (d.node) {
        case (decl_local(?l)) {
            vec::push(*res, l.ann.id);
        }
        case (_) {}
    }
}

fn node_ids_in_fn(&_fn f, &ident i, &def_id d, &ann a, @vec[uint] res) -> () {
    auto collect_ids = walk::default_visitor();
    collect_ids = rec(visit_expr_pre  = bind collect_ids_expr(_,res),
                      visit_block_pre = bind collect_ids_block(_,res),
                      visit_stmt_pre  = bind collect_ids_stmt(_,res),
                      visit_decl_pre  = bind collect_ids_decl(_,res)
                      with collect_ids);
    walk::walk_fn(collect_ids, f, i, d, a);
}

fn init_vecs(&crate_ctxt ccx, @vec[uint] node_ids, uint len) -> () {
    for (uint i in *node_ids) {
        log(uistr(i) + " |-> " + uistr(len));
        add_node(ccx, i, empty_ann(len));
    }
}

fn visit_fn(&crate_ctxt ccx, uint num_locals, &_fn f, &ident i,
            &def_id d, &ann a) -> () {
    let vec[uint] node_ids_ = [];
    let @vec[uint] node_ids = @node_ids_;
    node_ids_in_fn(f, i, d, a, node_ids);
    init_vecs(ccx, node_ids, num_locals);
}

fn annotate_in_fn(&crate_ctxt ccx, &_fn f, &ident i, &def_id f_id, &ann a)
    -> () {
    auto f_info = get_fn_info(ccx, f_id);
    visit_fn(ccx, num_locals(f_info), f, i, f_id, a);
}

fn annotate_crate(&crate_ctxt ccx, &crate crate) -> () {
    auto do_ann = walk::default_visitor();
    do_ann = rec(visit_fn_pre = bind annotate_in_fn(ccx,_,_,_,_)
                 with do_ann);
    walk::walk_crate(do_ann, crate);
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>extern crate quick_xml;

use std::io::{BufRead};

use quick_xml::{XmlReader, Event, AsStr, Element};
use quick_xml::error::ResultPos;
use std::fmt;

#[test]
fn sample_1_short() {
    test(
        include_bytes!("documents/sample_1.xml"),
        include_bytes!("documents/sample_1_short.txt"),
        true
    );
}

// #[test]
// fn sample_1_full() {
//     test(
//         include_bytes!("documents/sample_1.xml"),
//         include_bytes!("documents/sample_1_full.txt"),
//         false
//     );
// }

#[test]
fn sample_2_short() {
    test(
        include_bytes!("documents/sample_2.xml"),
        include_bytes!("documents/sample_2_short.txt"),
        true
    );
}

// #[test]
// fn sample_2_full() {
//     test(
//         include_bytes!("documents/sample_2.xml"),
//         include_bytes!("documents/sample_2_full.txt"),
//         false
//     );
// }

// #[test]
// fn sample_3_short() {
//     test(
//         include_bytes!("documents/sample_3.xml"),
//         include_bytes!("documents/sample_3_short.txt"),
//         true
//     );
// }

// #[test]
// fn sample_3_full() {
//     test(
//         include_bytes!("documents/sample_3.xml"),
//         include_bytes!("documents/sample_3_full.txt"),
//         false
//     );
// }

// #[test]
// fn sample_4_short() {
//     test(
//         include_bytes!("documents/sample_4.xml"),
//         include_bytes!("documents/sample_4_short.txt"),
//         true
//     );
// }

// #[test]
// fn sample_4_full() {
//     test(
//         include_bytes!("documents/sample_4.xml"),
//         include_bytes!("documents/sample_4_full.txt"),
//         false
//     );
//
// }
//

#[test]
fn eof_1() {
    test(
        br#"<?xml"#,
        br#"Malformed xml: Unescaped XmlDecl event"#,
        true
    );
}

#[test]
fn bad_1() {
    test(
        br#"<?xml&.,"#,
        br#"1:6 Malformed xml: Unescaped XmlDecl event"#,
        true
    );
}

// #[test]
// fn dashes_in_comments() {
//     test(
//         br#"<hello/>"#,
//         br#"
//             |1:14 Unexpected token '--' before ' '
//         "#,
//         false
//     );
//
//     test(
//         br#"<hello/>"#,
//         br#"
//             |1:14 Unexpected token '--' before '-'
//         "#,
//         true
//     );
// }

#[test]
fn tabs_1() {
    test(
        b"\t\t",
        br#"
            StartElement(a)
            StartElement(b)
            EndElement(b)
            EndElement(a)
            EndDocument
        "#,
        true
    );
}
//
// #[test]
// fn issue_83_duplicate_attributes() {
//     test(
//         br#"<hello><some-tag a='10' a="20"></hello>"#,
//         br#"
//             |StartElement(hello)
//             |1:30 Attribute 'a' is redefined
//         "#,
//         true
//     );
// }

#[test]
fn issue_93_large_characters_in_entity_references() {
    test(
        r#"<hello>&𤶼;</hello>"#.as_bytes(),
        r#"
            |StartElement(hello)
            |1:10 Malformed xml: Unexpected entity: 𤶼
            |EndElement(hello)
        "#.as_bytes(),
        true
    )
}

#[test]
fn issue_98_cdata_ending_with_right_bracket() {
    test(
        br#"<hello><![CDATA[Foo [Bar]]]></hello>"#,
        br#"
            |StartElement(hello)
            |Characters()
            |CData("Foo [Bar]")
            |Characters()
            |EndElement(hello)
            |EndDocument
        "#,
        false
    )
}

#[test]
fn issue_105_unexpected_double_dash() {
    test(
        br#"<hello>-- </hello>"#,
        br#"
            |StartElement(hello)
            |Characters("-- ")
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );

    test(
        br#"<hello>--</hello>"#,
        br#"
            |StartElement(hello)
            |Characters("--")
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );

    test(
        br#"<hello>--></hello>"#,
        br#"
            |StartElement(hello)
            |Characters("-->")
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );

    test(
        br#"<hello><![CDATA[--]]></hello>"#,
        br#"
            |StartElement(hello)
            |Characters()
            |CData("--")
            |Characters()
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );
}

// #[test]
// fn issue_attribues_have_no_default_namespace () {
//     test(
//         br#"<hello xmlns="urn:foo" x="y"/>"#,
//         br#"
//             |StartElement({urn:foo}hello [x="y"])
//             |EndElement({urn:foo}hello)
//             |EndDocument
//         "#,
//         true
//     );
// }

// clones a lot but that's fine
fn convert_to_quick_xml(s: &str) -> String {

    let mut s = match s.trim() {
        ts if ts.starts_with('|') => &ts[1..],
        s => s
    };

    if !s.is_empty() && s.as_bytes()[0] >= b'0' && s.as_bytes()[0] <= b'9' {
        let p = s.chars().position(|c| c == ' ').unwrap();
        s = &s[(p + 1) ..];
    }

    if s.starts_with("Whitespace") {
        format!("Character{}", s)
    } else {
        s.to_owned()
    }
}

fn test(input: &[u8], output: &[u8], is_short: bool) {

    let mut reader = XmlReader::from_reader(input).trim_text(is_short)
        .namespaced();

    let mut spec_lines = output.lines()
        .map(|line| line.unwrap())
        .enumerate()
        .map(|(i, line)| (i, convert_to_quick_xml(&line)))
        .filter(|&(_, ref line)| !line.trim().is_empty());

    if !is_short {
        reader.next();
    }

    loop {
        let e = reader.next();

        let line = format!("{}", OptEvent(e));

        if let Some((n, spec)) = spec_lines.next() {
            if line != spec {
                const SPLITTER: &'static str = "-------------------";
                panic!("\n{}\nUnexpected event at line {}:\nExpected: {}\nFound:    {}\n{}\n",
                       SPLITTER, n + 1, spec, line, SPLITTER);
            }
        } else {
            if line == "EndDocument" {
                break;
            }
            panic!("Unexpected event: {}", line);
        }
    }
}

fn namespace_name(n: &Option<Vec<u8>>, e: &Element) -> String {
    match n {
        &Some(ref n) =>
            format!("{{{}}}{}", n.as_str().unwrap(), e.name().as_str().unwrap()),
        &None => e.name().as_str().unwrap().to_owned(),
    }
}

struct OptEvent(Option<ResultPos<(Option<Vec<u8>>, Event)>>);

impl fmt::Display for OptEvent {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            Some(Ok((ref n, Event::Start(ref e)))) => {
                let atts: String = e.attributes().unescaped().map(|a| a.unwrap())
                    .filter(|&(k, _)| k.len() < 5 || &k[..5] != b"xmlns")
                    .map(|(k, v)| format!("{}={:?}", k.as_str().unwrap(), v.as_str().unwrap()))
                    .collect::<Vec<_>>().join(", ");

                let name = namespace_name(n, e);

                if atts.is_empty() {
                    write!(f, "StartElement({})", &name)
                } else {
                    write!(f, "StartElement({} [{}])", &name, &atts)
                }
            },
            Some(Ok((ref n, Event::End(ref e)))) =>
                write!(f, "EndElement({})", namespace_name(n, e)),
            Some(Ok((_, Event::Comment(ref e)))) =>
                write!(f, "Comment({:?})", e.content().as_str().unwrap()),
            Some(Ok((_, Event::CData(ref e)))) =>
                write!(f, "CData({:?})", e.content().as_str().unwrap()),
            Some(Ok((_, Event::Text(ref e)))) => {
                match e.unescaped_content() {
                    Ok(c) => {
                        if c.is_empty() {
                            write!(f, "Characters()")
                        } else {
                            write!(f, "Characters({:?})", c.as_str().unwrap())
                        }
                    },
                    Err((ref e, _)) => write!(f, "{}", e),
                }
            },
            Some(Ok((_, Event::Decl(ref e)))) => {
                let version = e.version().unwrap().as_str().unwrap();
                let encoding = e.encoding().unwrap().unwrap().as_str().unwrap();
                write!(f, "StartDocument({}, {})", version, encoding)
            },
            None => write!(f, "EndDocument"),
            Some(Ok((_, Event::PI(ref e)))) =>
                write!(f, "ProcessingInstruction({}={:?})",
                    e.name().as_str().unwrap(), e.content().as_str().unwrap()),
            Some(Err((ref e, _))) => write!(f, "{}", e),
            Some(Ok((_, Event::DocType(ref e)))) =>
                write!(f, "DocType({})", e.content().as_str().unwrap()),
        }
    }
}
<commit_msg>make double_dash_in_comment work<commit_after>extern crate quick_xml;

use std::io::{BufRead};

use quick_xml::{XmlReader, Event, AsStr, Element};
use quick_xml::error::ResultPos;
use std::fmt;

#[test]
fn sample_1_short() {
    test(
        include_bytes!("documents/sample_1.xml"),
        include_bytes!("documents/sample_1_short.txt"),
        true
    );
}

// #[test]
// fn sample_1_full() {
//     test(
//         include_bytes!("documents/sample_1.xml"),
//         include_bytes!("documents/sample_1_full.txt"),
//         false
//     );
// }

#[test]
fn sample_2_short() {
    test(
        include_bytes!("documents/sample_2.xml"),
        include_bytes!("documents/sample_2_short.txt"),
        true
    );
}

// #[test]
// fn sample_2_full() {
//     test(
//         include_bytes!("documents/sample_2.xml"),
//         include_bytes!("documents/sample_2_full.txt"),
//         false
//     );
// }

// #[test]
// fn sample_3_short() {
//     test(
//         include_bytes!("documents/sample_3.xml"),
//         include_bytes!("documents/sample_3_short.txt"),
//         true
//     );
// }

// #[test]
// fn sample_3_full() {
//     test(
//         include_bytes!("documents/sample_3.xml"),
//         include_bytes!("documents/sample_3_full.txt"),
//         false
//     );
// }

// #[test]
// fn sample_4_short() {
//     test(
//         include_bytes!("documents/sample_4.xml"),
//         include_bytes!("documents/sample_4_short.txt"),
//         true
//     );
// }

// #[test]
// fn sample_4_full() {
//     test(
//         include_bytes!("documents/sample_4.xml"),
//         include_bytes!("documents/sample_4_full.txt"),
//         false
//     );
//
// }
//

#[test]
fn eof_1() {
    test(
        br#"<?xml"#,
        br#"Malformed xml: Unescaped XmlDecl event"#,
        true
    );
}

#[test]
fn bad_1() {
    test(
        br#"<?xml&.,"#,
        br#"1:6 Malformed xml: Unescaped XmlDecl event"#,
        true
    );
}

#[test]
fn dashes_in_comments() {
    test(
        br#"<hello/>"#,
        br#"
            |1:14 Malformed xml: Unexpected token '--'
        "#,
        false
    );

    test(
        br#"<hello/>"#,
        br#"
            |1:14 Malformed xml: Unexpected token '--'
        "#,
        true
    );
}

#[test]
fn tabs_1() {
    test(
        b"\t\t",
        br#"
            StartElement(a)
            StartElement(b)
            EndElement(b)
            EndElement(a)
            EndDocument
        "#,
        true
    );
}
//
// #[test]
// fn issue_83_duplicate_attributes() {
//     test(
//         br#"<hello><some-tag a='10' a="20"></hello>"#,
//         br#"
//             |StartElement(hello)
//             |1:30 Attribute 'a' is redefined
//         "#,
//         true
//     );
// }

#[test]
fn issue_93_large_characters_in_entity_references() {
    test(
        r#"<hello>&𤶼;</hello>"#.as_bytes(),
        r#"
            |StartElement(hello)
            |1:10 Malformed xml: Unexpected entity: 𤶼
            |EndElement(hello)
        "#.as_bytes(),
        true
    )
}

#[test]
fn issue_98_cdata_ending_with_right_bracket() {
    test(
        br#"<hello><![CDATA[Foo [Bar]]]></hello>"#,
        br#"
            |StartElement(hello)
            |Characters()
            |CData("Foo [Bar]")
            |Characters()
            |EndElement(hello)
            |EndDocument
        "#,
        false
    )
}

#[test]
fn issue_105_unexpected_double_dash() {
    test(
        br#"<hello>-- </hello>"#,
        br#"
            |StartElement(hello)
            |Characters("-- ")
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );

    test(
        br#"<hello>--</hello>"#,
        br#"
            |StartElement(hello)
            |Characters("--")
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );

    test(
        br#"<hello>--></hello>"#,
        br#"
            |StartElement(hello)
            |Characters("-->")
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );

    test(
        br#"<hello><![CDATA[--]]></hello>"#,
        br#"
            |StartElement(hello)
            |Characters()
            |CData("--")
            |Characters()
            |EndElement(hello)
            |EndDocument
        "#,
        false
    );
}

// #[test]
// fn issue_attribues_have_no_default_namespace () {
//     test(
//         br#"<hello xmlns="urn:foo" x="y"/>"#,
//         br#"
//             |StartElement({urn:foo}hello [x="y"])
//             |EndElement({urn:foo}hello)
//             |EndDocument
//         "#,
//         true
//     );
// }

// clones a lot but that's fine
fn convert_to_quick_xml(s: &str) -> String {

    let mut s = match s.trim() {
        ts if ts.starts_with('|') => &ts[1..],
        s => s
    };

    if !s.is_empty() && s.as_bytes()[0] >= b'0' && s.as_bytes()[0] <= b'9' {
        let p = s.chars().position(|c| c == ' ').unwrap();
        s = &s[(p + 1) ..];
    }

    if s.starts_with("Whitespace") {
        format!("Character{}", s)
    } else {
        s.to_owned()
    }
}

fn test(input: &[u8], output: &[u8], is_short: bool) {

    let mut reader = XmlReader::from_reader(input)
        .trim_text(is_short)
        .check_comments(true)
        .namespaced();

    let mut spec_lines = output.lines()
        .map(|line| line.unwrap())
        .enumerate()
        .map(|(i, line)| (i, convert_to_quick_xml(&line)))
        .filter(|&(_, ref line)| !line.trim().is_empty());

    if !is_short {
        reader.next();
    }

    loop {
        let e = reader.next();

        let line = format!("{}", OptEvent(e));

        if let Some((n, spec)) = spec_lines.next() {
            if line != spec {
                const SPLITTER: &'static str = "-------------------";
                panic!("\n{}\nUnexpected event at line {}:\nExpected: {}\nFound:    {}\n{}\n",
                       SPLITTER, n + 1, spec, line, SPLITTER);
            }
        } else {
            if line == "EndDocument" {
                break;
            }
            panic!("Unexpected event: {}", line);
        }
    }
}

fn namespace_name(n: &Option<Vec<u8>>, e: &Element) -> String {
    match n {
        &Some(ref n) =>
            format!("{{{}}}{}", n.as_str().unwrap(), e.name().as_str().unwrap()),
        &None => e.name().as_str().unwrap().to_owned(),
    }
}

struct OptEvent(Option<ResultPos<(Option<Vec<u8>>, Event)>>);

impl fmt::Display for OptEvent {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            Some(Ok((ref n, Event::Start(ref e)))) => {
                let atts: String = e.attributes().unescaped().map(|a| a.unwrap())
                    .filter(|&(k, _)| k.len() < 5 || &k[..5] != b"xmlns")
                    .map(|(k, v)| format!("{}={:?}", k.as_str().unwrap(), v.as_str().unwrap()))
                    .collect::<Vec<_>>().join(", ");

                let name = namespace_name(n, e);

                if atts.is_empty() {
                    write!(f, "StartElement({})", &name)
                } else {
                    write!(f, "StartElement({} [{}])", &name, &atts)
                }
            },
            Some(Ok((ref n, Event::End(ref e)))) =>
                write!(f, "EndElement({})", namespace_name(n, e)),
            Some(Ok((_, Event::Comment(ref e)))) =>
                write!(f, "Comment({:?})", e.content().as_str().unwrap()),
            Some(Ok((_, Event::CData(ref e)))) =>
                write!(f, "CData({:?})", e.content().as_str().unwrap()),
            Some(Ok((_, Event::Text(ref e)))) => {
                match e.unescaped_content() {
                    Ok(c) => {
                        if c.is_empty() {
                            write!(f, "Characters()")
                        } else {
                            write!(f, "Characters({:?})", c.as_str().unwrap())
                        }
                    },
                    Err((ref e, _)) => write!(f, "{}", e),
                }
            },
            Some(Ok((_, Event::Decl(ref e)))) => {
                let version = e.version().unwrap().as_str().unwrap();
                let encoding = e.encoding().unwrap().unwrap().as_str().unwrap();
                write!(f, "StartDocument({}, {})", version, encoding)
            },
            None => write!(f, "EndDocument"),
            Some(Ok((_, Event::PI(ref e)))) =>
                write!(f, "ProcessingInstruction({}={:?})",
                    e.name().as_str().unwrap(), e.content().as_str().unwrap()),
            Some(Err((ref e, _))) => write!(f, "{}", e),
            Some(Ok((_, Event::DocType(ref e)))) =>
                write!(f, "DocType({})", e.content().as_str().unwrap()),
        }
    }
}
<|endoftext|>