<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

This modules provides bindings to the local event loop's TTY interface, using it
to have synchronous, but non-blocking versions of stdio. These handles can be
inspected for information about terminal dimensions or related information
about the stream or terminal that it is attached to.

# Example

```rust
use std::rt::io;

let mut out = io::stdout();
out.write(bytes!("Hello, world!"));
```

*/

use fmt;
use libc;
use option::{Option, Some, None};
use result::{Ok, Err};
use rt::io::buffered::{LineBufferedWriter, BufferedWriter};
use rt::rtio::{IoFactory, RtioTTY, RtioFileStream, with_local_io,
               CloseAsynchronously};
use super::{Reader, Writer, io_error, IoError, OtherIoError};

// And so begins the tale of acquiring a uv handle to a stdio stream on all
// platforms in all situations. Our story begins by splitting the world into two
// categories, windows and unix. Then one day the creators of unix said let
// there be redirection! And henceforth there was redirection away from the
// console for standard I/O streams.
//
// After this day, the world split into four factions:
//
// 1. Unix with stdout on a terminal.
// 2. Unix with stdout redirected.
// 3. Windows with stdout on a terminal.
// 4. Windows with stdout redirected.
//
// Many years passed, and then one day the nation of libuv decided to unify this
// world. After months of toiling, uv created three ideas: TTY, Pipe, File.
// These three ideas propagated throughout the lands and the four great factions
// decided to settle among them.
//
// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
// doing so, they even enhanced themselves further then their Pipe/File
// brethren, becoming the dominant powers.
//
// The group of 4, however, decided to work independently. They abandoned the
// common TTY belief throughout, and even abandoned the fledgling Pipe belief.
// The members of the 4th faction decided to only align themselves with File.
//
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
//        case pipe also doesn't work, but magically file does!
enum StdSource {
    TTY(~RtioTTY),
    File(~RtioFileStream),
}

#[fixed_stack_segment] #[inline(never)]
fn src<T>(fd: libc::c_int, readable: bool, f: &fn(StdSource) -> T) -> T {
    do with_local_io |io| {
        let fd = unsafe { libc::dup(fd) };
        match io.tty_open(fd, readable) {
            Ok(tty) => Some(f(TTY(tty))),
            Err(_) => {
                // It's not really that desirable if these handles are closed
                // synchronously, and because they're squirreled away in a task
                // structure the destructors will be run when the task is
                // attempted to get destroyed. This means that if we run a
                // synchronous destructor we'll attempt to do some scheduling
                // operations which will just result in sadness.
                Some(f(File(io.fs_from_raw_fd(fd, CloseAsynchronously))))
            }
        }
    }.unwrap()
}

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// See `stdout()` for notes about this function.
#[fixed_stack_segment] #[inline(never)]
pub fn stdin() -> StdReader {
    do src(libc::STDIN_FILENO, true) |src| { StdReader { inner: src } }
}

/// Creates a new non-blocking handle to the stdout of the current process.
///
/// Note that this is a fairly expensive operation in that at least one memory
/// allocation is performed. Additionally, this must be called from a runtime
/// task context because the stream returned will be a non-blocking object using
/// the local scheduler to perform the I/O.
pub fn stdout() -> StdWriter {
    do src(libc::STDOUT_FILENO, false) |src| { StdWriter { inner: src } }
}

/// Creates a new non-blocking handle to the stderr of the current process.
///
/// See `stdout()` for notes about this function.
pub fn stderr() -> StdWriter {
    do src(libc::STDERR_FILENO, false) |src| { StdWriter { inner: src } }
}

/// Executes a closure with the local task's handle on stdout. By default, this
/// stream is a buffering stream, so the handled yielded to the given closure
/// can be used to flush the stdout stream (if necessary). The buffering used is
/// line-buffering when stdout is attached to a terminal, and a fixed sized
/// buffer if it is not attached to a terminal.
///
/// Note that handles generated via the `stdout()` function all output to the
/// same stream, and output among all task may be interleaved as a result of
/// this. This is provided to have access to the default stream for `print` and
/// `println` (and the related macros) for this task.
///
/// Also note that logging macros do not use this stream. Using the logging
/// macros will emit output to stderr.
pub fn with_task_stdout(f: &fn(&mut Writer)) {
    use rt::local::Local;
    use rt::task::Task;

    unsafe {
        // Logging may require scheduling operations, so we can't remove the
        // task from TLS right now, hence the unsafe borrow. Sad.
        let task: *mut Task = Local::unsafe_borrow();

        match (*task).stdout_handle {
            Some(ref mut handle) => f(*handle),
            None => {
                let handle = stdout();
                let mut handle = if handle.isatty() {
                    ~LineBufferedWriter::new(handle) as ~Writer
                } else {
                    // The default capacity is very large, 64k, but this is just
                    // a stdout stream, and possibly per task, so let's not make
                    // this too expensive.
                    ~BufferedWriter::with_capacity(4096, handle) as ~Writer
                };
                f(handle);
                (*task).stdout_handle = Some(handle);
            }
        }
    }
}

/// Prints a string to the stdout of the current process. No newline is emitted
/// after the string is printed.
pub fn print(s: &str) {
    do with_task_stdout |io| {
        io.write(s.as_bytes());
    }
}

/// Prints a string as a line. to the stdout of the current process. A literal
/// `\n` character is printed to the console after the string.
pub fn println(s: &str) {
    do with_task_stdout |io| {
        io.write(s.as_bytes());
        io.write(['\n' as u8]);
    }
}

/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible
/// with the `format_args!` macro.
pub fn print_args(fmt: &fmt::Arguments) {
    do with_task_stdout |io| {
        fmt::write(io, fmt);
    }
}

/// Similar to `println`, but takes a `fmt::Arguments` structure to be
/// compatible with the `format_args!` macro.
pub fn println_args(fmt: &fmt::Arguments) {
    do with_task_stdout |io| {
        fmt::writeln(io, fmt);
    }
}

/// Representation of a reader of a standard input stream
pub struct StdReader {
    priv inner: StdSource
}

impl Reader for StdReader {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        let ret = match self.inner {
            TTY(ref mut tty) => tty.read(buf),
            File(ref mut file) => file.read(buf).map_move(|i| i as uint),
        };
        match ret {
            Ok(amt) => Some(amt as uint),
            Err(e) => {
                io_error::cond.raise(e);
                None
            }
        }
    }

    fn eof(&mut self) -> bool { false }
}

/// Representation of a writer to a standard output stream
pub struct StdWriter {
    priv inner: StdSource
}

impl StdWriter {
    /// Gets the size of this output window, if possible. This is typically used
    /// when the writer is attached to something like a terminal, this is used
    /// to fetch the dimensions of the terminal.
    ///
    /// If successful, returns Some((width, height)).
    ///
    /// # Failure
    ///
    /// This function will raise on the `io_error` condition if an error
    /// happens.
    pub fn winsize(&mut self) -> Option<(int, int)> {
        match self.inner {
            TTY(ref mut tty) => {
                match tty.get_winsize() {
                    Ok(p) => Some(p),
                    Err(e) => {
                        io_error::cond.raise(e);
                        None
                    }
                }
            }
            File(*) => {
                io_error::cond.raise(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                });
                None
            }
        }
    }

    /// Controls whether this output stream is a "raw stream" or simply a normal
    /// stream.
    ///
    /// # Failure
    ///
    /// This function will raise on the `io_error` condition if an error
    /// happens.
    pub fn set_raw(&mut self, raw: bool) {
        match self.inner {
            TTY(ref mut tty) => {
                match tty.set_raw(raw) {
                    Ok(()) => {},
                    Err(e) => io_error::cond.raise(e),
                }
            }
            File(*) => {
                io_error::cond.raise(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                });
            }
        }
    }

    /// Returns whether this tream is attached to a TTY instance or not.
    ///
    /// This is similar to libc's isatty() function
    pub fn isatty(&self) -> bool {
        match self.inner {
            TTY(ref tty) => tty.isatty(),
            File(*) => false,
        }
    }
}

impl Writer for StdWriter {
    fn write(&mut self, buf: &[u8]) {
        let ret = match self.inner {
            TTY(ref mut tty) => tty.write(buf),
            File(ref mut file) => file.write(buf),
        };
        match ret {
            Ok(()) => {}
            Err(e) => io_error::cond.raise(e)
        }
    }
}

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

    #[test]
    fn smoke() {
        // Just make sure we can acquire handles
        stdin();
        stdout();
        stderr();
    }
}
<commit_msg>Provide a sound method of flushing stdout<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

This modules provides bindings to the local event loop's TTY interface, using it
to have synchronous, but non-blocking versions of stdio. These handles can be
inspected for information about terminal dimensions or related information
about the stream or terminal that it is attached to.

# Example

```rust
use std::rt::io;

let mut out = io::stdout();
out.write(bytes!("Hello, world!"));
```

*/

use fmt;
use libc;
use option::{Option, Some, None};
use result::{Ok, Err};
use rt::io::buffered::{LineBufferedWriter, BufferedWriter};
use rt::rtio::{IoFactory, RtioTTY, RtioFileStream, with_local_io,
               CloseAsynchronously};
use super::{Reader, Writer, io_error, IoError, OtherIoError};

// And so begins the tale of acquiring a uv handle to a stdio stream on all
// platforms in all situations. Our story begins by splitting the world into two
// categories, windows and unix. Then one day the creators of unix said let
// there be redirection! And henceforth there was redirection away from the
// console for standard I/O streams.
//
// After this day, the world split into four factions:
//
// 1. Unix with stdout on a terminal.
// 2. Unix with stdout redirected.
// 3. Windows with stdout on a terminal.
// 4. Windows with stdout redirected.
//
// Many years passed, and then one day the nation of libuv decided to unify this
// world. After months of toiling, uv created three ideas: TTY, Pipe, File.
// These three ideas propagated throughout the lands and the four great factions
// decided to settle among them.
//
// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
// doing so, they even enhanced themselves further then their Pipe/File
// brethren, becoming the dominant powers.
//
// The group of 4, however, decided to work independently. They abandoned the
// common TTY belief throughout, and even abandoned the fledgling Pipe belief.
// The members of the 4th faction decided to only align themselves with File.
//
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
//        case pipe also doesn't work, but magically file does!
enum StdSource {
    TTY(~RtioTTY),
    File(~RtioFileStream),
}

#[fixed_stack_segment] #[inline(never)]
fn src<T>(fd: libc::c_int, readable: bool, f: &fn(StdSource) -> T) -> T {
    do with_local_io |io| {
        let fd = unsafe { libc::dup(fd) };
        match io.tty_open(fd, readable) {
            Ok(tty) => Some(f(TTY(tty))),
            Err(_) => {
                // It's not really that desirable if these handles are closed
                // synchronously, and because they're squirreled away in a task
                // structure the destructors will be run when the task is
                // attempted to get destroyed. This means that if we run a
                // synchronous destructor we'll attempt to do some scheduling
                // operations which will just result in sadness.
                Some(f(File(io.fs_from_raw_fd(fd, CloseAsynchronously))))
            }
        }
    }.unwrap()
}

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// See `stdout()` for notes about this function.
#[fixed_stack_segment] #[inline(never)]
pub fn stdin() -> StdReader {
    do src(libc::STDIN_FILENO, true) |src| { StdReader { inner: src } }
}

/// Creates a new non-blocking handle to the stdout of the current process.
///
/// Note that this is a fairly expensive operation in that at least one memory
/// allocation is performed. Additionally, this must be called from a runtime
/// task context because the stream returned will be a non-blocking object using
/// the local scheduler to perform the I/O.
pub fn stdout() -> StdWriter {
    do src(libc::STDOUT_FILENO, false) |src| { StdWriter { inner: src } }
}

/// Creates a new non-blocking handle to the stderr of the current process.
///
/// See `stdout()` for notes about this function.
pub fn stderr() -> StdWriter {
    do src(libc::STDERR_FILENO, false) |src| { StdWriter { inner: src } }
}

// Helper to access the local task's stdout handle
//
// Note that this is not a safe function to expose because you can create an
// aliased pointer very easily:
//
//  do with_task_stdout |io1| {
//      do with_task_stdout |io2| {
//          // io1 aliases io2
//      }
//  }
fn with_task_stdout(f: &fn(&mut Writer)) {
    use rt::local::Local;
    use rt::task::Task;

    unsafe {
        // Logging may require scheduling operations, so we can't remove the
        // task from TLS right now, hence the unsafe borrow. Sad.
        let task: *mut Task = Local::unsafe_borrow();

        match (*task).stdout_handle {
            Some(ref mut handle) => f(*handle),
            None => {
                let handle = stdout();
                let mut handle = if handle.isatty() {
                    ~LineBufferedWriter::new(handle) as ~Writer
                } else {
                    // The default capacity is very large, 64k, but this is just
                    // a stdout stream, and possibly per task, so let's not make
                    // this too expensive.
                    ~BufferedWriter::with_capacity(4096, handle) as ~Writer
                };
                f(handle);
                (*task).stdout_handle = Some(handle);
            }
        }
    }
}

/// Flushes the local task's stdout handle.
///
/// By default, this stream is a buffering stream, flushing may be necessary to
/// ensure output is on the terminal screen. The buffering used is
/// line-buffering when stdout is attached to a terminal, and a fixed sized
/// buffer if it is not attached to a terminal.
///
/// Note that logging macros do not use this stream. Using the logging macros
/// will emit output to stderr, and while they are line buffered the log
/// messages are always terminated in a newline (no need to flush).
pub fn flush() {
    do with_task_stdout |io| {
        io.flush();
    }
}

/// Prints a string to the stdout of the current process. No newline is emitted
/// after the string is printed.
pub fn print(s: &str) {
    do with_task_stdout |io| {
        io.write(s.as_bytes());
    }
}

/// Prints a string as a line. to the stdout of the current process. A literal
/// `\n` character is printed to the console after the string.
pub fn println(s: &str) {
    do with_task_stdout |io| {
        io.write(s.as_bytes());
        io.write(['\n' as u8]);
    }
}

/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible
/// with the `format_args!` macro.
pub fn print_args(fmt: &fmt::Arguments) {
    do with_task_stdout |io| {
        fmt::write(io, fmt);
    }
}

/// Similar to `println`, but takes a `fmt::Arguments` structure to be
/// compatible with the `format_args!` macro.
pub fn println_args(fmt: &fmt::Arguments) {
    do with_task_stdout |io| {
        fmt::writeln(io, fmt);
    }
}

/// Representation of a reader of a standard input stream
pub struct StdReader {
    priv inner: StdSource
}

impl Reader for StdReader {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        let ret = match self.inner {
            TTY(ref mut tty) => tty.read(buf),
            File(ref mut file) => file.read(buf).map_move(|i| i as uint),
        };
        match ret {
            Ok(amt) => Some(amt as uint),
            Err(e) => {
                io_error::cond.raise(e);
                None
            }
        }
    }

    fn eof(&mut self) -> bool { false }
}

/// Representation of a writer to a standard output stream
pub struct StdWriter {
    priv inner: StdSource
}

impl StdWriter {
    /// Gets the size of this output window, if possible. This is typically used
    /// when the writer is attached to something like a terminal, this is used
    /// to fetch the dimensions of the terminal.
    ///
    /// If successful, returns Some((width, height)).
    ///
    /// # Failure
    ///
    /// This function will raise on the `io_error` condition if an error
    /// happens.
    pub fn winsize(&mut self) -> Option<(int, int)> {
        match self.inner {
            TTY(ref mut tty) => {
                match tty.get_winsize() {
                    Ok(p) => Some(p),
                    Err(e) => {
                        io_error::cond.raise(e);
                        None
                    }
                }
            }
            File(*) => {
                io_error::cond.raise(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                });
                None
            }
        }
    }

    /// Controls whether this output stream is a "raw stream" or simply a normal
    /// stream.
    ///
    /// # Failure
    ///
    /// This function will raise on the `io_error` condition if an error
    /// happens.
    pub fn set_raw(&mut self, raw: bool) {
        match self.inner {
            TTY(ref mut tty) => {
                match tty.set_raw(raw) {
                    Ok(()) => {},
                    Err(e) => io_error::cond.raise(e),
                }
            }
            File(*) => {
                io_error::cond.raise(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                });
            }
        }
    }

    /// Returns whether this tream is attached to a TTY instance or not.
    ///
    /// This is similar to libc's isatty() function
    pub fn isatty(&self) -> bool {
        match self.inner {
            TTY(ref tty) => tty.isatty(),
            File(*) => false,
        }
    }
}

impl Writer for StdWriter {
    fn write(&mut self, buf: &[u8]) {
        let ret = match self.inner {
            TTY(ref mut tty) => tty.write(buf),
            File(ref mut file) => file.write(buf),
        };
        match ret {
            Ok(()) => {}
            Err(e) => io_error::cond.raise(e)
        }
    }
}

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

    #[test]
    fn smoke() {
        // Just make sure we can acquire handles
        stdin();
        stdout();
        stderr();
    }
}
<|endoftext|>


<commit_before>pub fn median_filter(data: &Vec<f64>, window: usize) -> Vec<f64> {
    groups(data, window)
        .iter()
        .map(median_of)
        .collect()
}

fn median_of(data: &Vec<f64>) -> f64 {
    let n = data.len();
    let mut copy = vec!(0f64; n);
    copy.copy_from_slice(&data);
    copy.sort_by(|a,b| a.partial_cmp(b).unwrap());
    let middle: usize = n / 2;

    let result = if n % 2 == 1 {
        copy[middle]
    } else {
        (copy[middle] + copy[middle - 1])/2.0
    };

    result.clone()
}

fn groups(data: &Vec<f64>, group_size: usize) -> Vec<Vec<f64>> {
    let mut groups: Vec<Vec<f64>> = vec!();

    for end_index in group_size .. data.len() + 1 {
        let mut group: Vec<f64> = vec!();
        for index in (end_index - group_size) .. end_index {
            group.push(data[index])
        }
        groups.push(group)
    }

    groups
}

#[cfg(test)]
pub mod tests {
    const EPSILON: f64 = 0.00001;
    use super::*;

    #[test]
    fn median_of_odd_length_vector() {
        let data: Vec<f64> = vec!(1.0, 2.0, 3.0);

        let median = median_of(&data);

        assert!((median - 2.0).abs() < EPSILON);
    }

    #[test]
    fn median_of_even_length_vector() {
        let data: Vec<f64> = vec!(1.0, 2.0, 3.0, 4.0);

        let median = median_of(&data);

        assert_eq!(median, 2.5);
        assert!((median - 2.5).abs() < EPSILON);
    }

    #[test]
    fn median_of_unsorted_vector() {
        let data: Vec<f64> = vec!(2.0, 4.0, 3.0, 1.0);

        let median = median_of(&data);

        assert_eq!(median, 2.5);
        assert!((median - 2.5).abs() < EPSILON);
    }

    #[test]
    fn groups_of_2_for_a_vector() {
        let data: Vec<f64> = vec!(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);

        let gs = groups(&data, 2);

        assert_eq!(vec![
            vec!(1.0, 2.0),
            vec!(2.0, 3.0),
            vec!(3.0, 4.0),
            vec!(4.0, 5.0),
            vec!(5.0, 6.0)], gs);
    }

    #[test]
    fn groups_of_3_for_a_vector() {
        let data: Vec<f64> = vec!(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);

        let gs = groups(&data, 3);

        assert_eq!(vec![
            vec!(1.0, 2.0, 3.0),
            vec!(2.0, 3.0, 4.0),
            vec!(3.0, 4.0, 5.0),
            vec!(4.0, 5.0, 6.0)], gs);
    }

    #[test]
    fn mad_of_2_for_a_vector() {
        let data: Vec<f64> = vec!(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);

        let mad = median_filter(&data, 2);

        assert_eq!(vec![
            1.5,
            2.5,
            3.5,
            4.5,
            5.5], mad);
    }

    #[test]
    fn mad_of_3_for_a_vector() {
        let data: Vec<f64> = vec!(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);

        let mad = median_filter(&data, 3);

        assert_eq!(vec![
            2.0,
            3.0,
            4.0,
            5.0], mad);
    }
}
<commit_msg>Forgo superfluous clone<commit_after>pub fn median_filter(data: &Vec<f64>, window: usize) -> Vec<f64> {
    groups(data, window)
        .iter()
        .map(median_of)
        .collect()
}

fn median_of(data: &Vec<f64>) -> f64 {
    let n = data.len();
    let mut copy = vec!(0f64; n);
    copy.copy_from_slice(&data);
    copy.sort_by(|a,b| a.partial_cmp(b).unwrap());
    let middle: usize = n / 2;

    let result = if n % 2 == 1 {
        copy[middle]
    } else {
        (copy[middle] + copy[middle - 1])/2.0
    };

    result
}

fn groups(data: &Vec<f64>, group_size: usize) -> Vec<Vec<f64>> {
    let mut groups: Vec<Vec<f64>> = vec!();

    for end_index in group_size .. data.len() + 1 {
        let mut group: Vec<f64> = vec!();
        for index in (end_index - group_size) .. end_index {
            group.push(data[index])
        }
        groups.push(group)
    }

    groups
}

#[cfg(test)]
pub mod tests {
    const EPSILON: f64 = 0.00001;
    use super::*;

    #[test]
    fn median_of_odd_length_vector() {
        let data: Vec<f64> = vec!(1.0, 2.0, 3.0);

        let median = median_of(&data);

        assert!((median - 2.0).abs() < EPSILON);
    }

    #[test]
    fn median_of_even_length_vector() {
        let data: Vec<f64> = vec!(1.0, 2.0, 3.0, 4.0);

        let median = median_of(&data);

        assert_eq!(median, 2.5);
        assert!((median - 2.5).abs() < EPSILON);
    }

    #[test]
    fn median_of_unsorted_vector() {
        let data: Vec<f64> = vec!(2.0, 4.0, 3.0, 1.0);

        let median = median_of(&data);

        assert_eq!(median, 2.5);
        assert!((median - 2.5).abs() < EPSILON);
    }

    #[test]
    fn groups_of_2_for_a_vector() {
        let data: Vec<f64> = vec!(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);

        let gs = groups(&data, 2);

        assert_eq!(vec![
            vec!(1.0, 2.0),
            vec!(2.0, 3.0),
            vec!(3.0, 4.0),
            vec!(4.0, 5.0),
            vec!(5.0, 6.0)], gs);
    }

    #[test]
    fn groups_of_3_for_a_vector() {
        let data: Vec<f64> = vec!(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);

        let gs = groups(&data, 3);

        assert_eq!(vec![
            vec!(1.0, 2.0, 3.0),
            vec!(2.0, 3.0, 4.0),
            vec!(3.0, 4.0, 5.0),
            vec!(4.0, 5.0, 6.0)], gs);
    }

    #[test]
    fn mad_of_2_for_a_vector() {
        let data: Vec<f64> = vec!(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);

        let mad = median_filter(&data, 2);

        assert_eq!(vec![
            1.5,
            2.5,
            3.5,
            4.5,
            5.5], mad);
    }

    #[test]
    fn mad_of_3_for_a_vector() {
        let data: Vec<f64> = vec!(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);

        let mad = median_filter(&data, 3);

        assert_eq!(vec![
            2.0,
            3.0,
            4.0,
            5.0], mad);
    }
}
<|endoftext|>


<commit_before>extern crate bindgen;

use std::env;
use std::io::Write;
use std::path::PathBuf;

#[cfg(not(target_os="windows"))]
fn default_include_dir(_: env::VarError) -> String {
    "/usr/include".to_owned()
}

#[cfg(target_os="windows")]
fn default_include_dir(_: env::VarError) -> String {
    panic!("No default directory for includes in windows")
}

fn main() {
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    let in_path = PathBuf::from(env::var("CAPSTONE_INCLUDE_DIR")
        .unwrap_or_else(default_include_dir));

    let wrapper = out_path.join("wrapper.h");
    {
        let mut file = std::fs::File::create(&wrapper).unwrap();
        file.write_all(b"#include <capstone/capstone.h>").unwrap();
    }

    println!("cargo:rerun-if-changed={}",
             in_path.join("capstone").join("capstone.h").display());

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header(wrapper.to_str().unwrap())
        .clang_arg(format!("-I{}", in_path.display()))
        .link("capstone")
        .generate_comments(true)
        .constified_enum("cs_.*")
        .constified_enum("x86_.*")
        .constified_enum("arm_.*")
        .constified_enum("arm64_.*")
        .constified_enum("mips_.*")
        .constified_enum("ppc_.*")
        .constified_enum("sparc_.*")
        .constified_enum("sysz_.*")
        .constified_enum("xcore_.*")
        // Only generate bindings for all types that start with cs_ and types included by them.
        // This avoids generating bindings for standard c functions.
        .whitelisted_type("cs_.*")
        .whitelisted_function("cs_.*")
        .prepend_enum_name(false)
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    bindings.write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");

    // TODO: For some reason .link("capstone") won't work.
    // Remove this once it does again.
    // TODO: Add support for library search paths.
    println!("cargo:rustc-link-lib=dylib=capstone");
}<commit_msg>Add support for library search paths<commit_after>extern crate bindgen;

use std::env;
use std::io::Write;
use std::path::PathBuf;

#[cfg(not(target_os="windows"))]
fn default_include_dir(_: env::VarError) -> String {
    "/usr/include".to_owned()
}

#[cfg(not(target_os="windows"))]
fn default_library_dir(_: env::VarError) -> String {
    "/usr/lib".to_owned()
}

#[cfg(target_os="windows")]
fn default_include_dir(_: env::VarError) -> String {
    panic!("No default directory for includes in windows")
}

#[cfg(target_os="windows")]
fn default_library_dir(_: env::VarError) -> String {
    panic!("No default directory for libraries in windows")
}

fn main() {
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    let in_path = PathBuf::from(env::var("CAPSTONE_INCLUDE_DIR")
                                    .unwrap_or_else(default_include_dir));
    let lib_path = PathBuf::from(env::var("CAPSTONE_LIBRARY_DIR")
                                     .unwrap_or_else(default_library_dir));

    let wrapper = out_path.join("wrapper.h");
    {
        let mut file = std::fs::File::create(&wrapper).unwrap();
        file.write_all(b"#include <capstone/capstone.h>").unwrap();
    }

    println!("cargo:rerun-if-changed={}",
             in_path.join("capstone").join("capstone.h").display());

    let bindings = bindgen::Builder::default()
        .header(wrapper.to_str().unwrap())
        .clang_arg(format!("-I{}", in_path.display()))
        .link("capstone")
        .generate_comments(true)
        .constified_enum("cs_.*")
        .constified_enum("x86_.*")
        .constified_enum("arm_.*")
        .constified_enum("arm64_.*")
        .constified_enum("mips_.*")
        .constified_enum("ppc_.*")
        .constified_enum("sparc_.*")
        .constified_enum("sysz_.*")
        .constified_enum("xcore_.*")
        .whitelisted_type("cs_.*")
        .whitelisted_function("cs_.*")
        .prepend_enum_name(false)
        .generate()
        .expect("Unable to generate bindings");

    bindings.write_to_file(out_path.join("bindings.rs")).expect("Couldn't write bindings!");

    println!("cargo:rustc-link-lib=dylib=capstone");
    println!("cargo:rustc-link-search={}", lib_path.display());
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::path::Path;
use std::process::Command;

const LINUX_CLANG_DIRS: &'static [&'static str] = &[
    "/usr/lib",
    "/usr/lib/llvm",
    "/usr/lib/llvm-3.4/lib",
    "/usr/lib/llvm-3.5/lib",
    "/usr/lib/llvm-3.6/lib",
    "/usr/lib64/llvm",
    "/usr/lib/x86_64-linux-gnu",
];
const MAC_CLANG_DIR: &'static str = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib";
const WIN_CLANG_DIRS: &'static [&'static str] = &["C:\\Program Files\\LLVM\\bin", "C:\\Program Files\\LLVM\\lib"];

fn path_exists(path: &Path) -> bool {
    match fs::metadata(path) {
        Ok(_) => true,
        Err(_) => false
    }
}

fn main() {
    let use_static_lib = env::var_os("LIBCLANG_STATIC").is_some() || cfg!(feature = "static");

    let possible_clang_dirs = if let Ok(dir) = env::var("LIBCLANG_PATH") {
        vec![dir]
    } else if cfg!(any(target_os = "linux", target_os = "freebsd")) {
        LINUX_CLANG_DIRS.iter().map(ToString::to_string).collect()
    } else if cfg!(target_os = "macos") {
        vec![MAC_CLANG_DIR.to_string()]
    } else if cfg!(target_os = "windows") {
		WIN_CLANG_DIRS.iter().map(ToString::to_string).collect()
    } else {
        panic!("Platform not supported");
    };

    let clang_lib = if cfg!(target_os = "windows") {
			format!("libclang{}", env::consts::DLL_SUFFIX)
		} else {
			format!("{}clang{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX)
		};

    //may contain path to libclang detected via ldconfig
    let mut libclang_path_string = String::new();

    let mut maybe_clang_dir = possible_clang_dirs.iter().filter_map(|candidate_dir| {
        let clang_dir = Path::new(candidate_dir);
        let clang_path = clang_dir.join(clang_lib.clone());
        if path_exists(&*clang_path) {
            Some(clang_dir)
        } else {
            None
        }
    }).next();

    if maybe_clang_dir == None && cfg!(target_os = "linux") {
        //try to find via lddconfig
        //may return line, like
        //libclang.so.3.7 (libc6,x86-64) => /usr/lib64/libclang.so.3.7
        let lddresult = Command::new("/sbin/ldconfig")
            .arg("-p")
            .output();
        if lddresult.is_ok() {
            let lddresult = lddresult.unwrap();
            let ldd_config_output = String::from_utf8_lossy(&lddresult.stdout).to_string();
            for line in ldd_config_output.lines() {
                let line_trim = line.trim();
                if line_trim.starts_with(&*clang_lib) {
                    let last_word = line_trim.rsplit(" ").next();
                    if let Some(last_word) = last_word {
                        let libclang_path = Path::new(last_word);
                        if path_exists(&libclang_path) {
                            libclang_path_string = last_word.to_owned();
                            maybe_clang_dir = Path::new(&libclang_path_string).parent();
                        }
                    }
                    break;
                }
            }
        }
    }

    macro_rules! qw {
        ($($i:ident)*) => (vec!($(stringify!($i)),*));
    }

    if let Some(clang_dir) = maybe_clang_dir {
        if use_static_lib {
            let libs = qw![
                LLVMAnalysis
                LLVMBitReader
                LLVMCore
                LLVMLTO
                LLVMLinker
                LLVMMC
                LLVMMCParser
                LLVMObjCARCOpts
                LLVMObject
                LLVMOption
                LLVMScalarOpts
                LLVMSupport
                LLVMTarget
                LLVMTransformUtils
                LLVMVectorize
                LLVMipa
                LLVMipo
                clang
                clangARCMigrate
                clangAST
                clangASTMatchers
                clangAnalysis
                clangBasic
                clangDriver
                clangEdit
                clangFormat
                clangFrontend
                clangIndex
                clangLex
                clangParse
                clangRewrite
                clangRewriteFrontend
                clangSema
                clangSerialization
                clangStaticAnalyzerCheckers
                clangStaticAnalyzerCore
                clangStaticAnalyzerFrontend
                clangTooling
            ];

            print!("cargo:rustc-flags=");
            for lib in libs {
                print!("-l static={} ", lib);
            }
            println!("-L {} -l ncursesw -l z -l stdc++", clang_dir.to_str().unwrap());
        } else{
            println!("cargo:rustc-link-search=native={}", clang_dir.to_str().unwrap());
            if !libclang_path_string.is_empty() {
                let libclang_path = Path::new(&libclang_path_string);
                println!("cargo:rustc-link-lib=dylib=:{}", libclang_path.file_name().unwrap().to_str().unwrap());
            } else {
                println!("cargo:rustc-link-lib=dylib=clang");
            }
        }
    } else {
        panic!("Unable to find {}", clang_lib);
    }
}
<commit_msg>Fix OS X build<commit_after>use std::env;
use std::fs;
use std::path::Path;
use std::process::Command;

const LINUX_CLANG_DIRS: &'static [&'static str] = &[
    "/usr/lib",
    "/usr/lib/llvm",
    "/usr/lib/llvm-3.4/lib",
    "/usr/lib/llvm-3.5/lib",
    "/usr/lib/llvm-3.6/lib",
    "/usr/lib64/llvm",
    "/usr/lib/x86_64-linux-gnu",
];
const MAC_CLANG_DIR: &'static [&'static str] = &[
    "/usr/local/opt/llvm/lib",
    "/Library/Developer/CommandLineTools/usr/lib",
    "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib",
];
const WIN_CLANG_DIRS: &'static [&'static str] = &["C:\\Program Files\\LLVM\\bin", "C:\\Program Files\\LLVM\\lib"];

fn path_exists(path: &Path) -> bool {
    match fs::metadata(path) {
        Ok(_) => true,
        Err(_) => false
    }
}

fn main() {
    let use_static_lib = env::var_os("LIBCLANG_STATIC").is_some() || cfg!(feature = "static");

    let possible_clang_dirs = if let Ok(dir) = env::var("LIBCLANG_PATH") {
        vec![dir]
    } else if cfg!(any(target_os = "linux", target_os = "freebsd")) {
        LINUX_CLANG_DIRS.iter().map(ToString::to_string).collect()
    } else if cfg!(target_os = "macos") {
        MAC_CLANG_DIR.iter().map(ToString::to_string).collect()
    } else if cfg!(target_os = "windows") {
		WIN_CLANG_DIRS.iter().map(ToString::to_string).collect()
    } else {
        panic!("Platform not supported");
    };

    let clang_lib = if cfg!(target_os = "windows") {
			format!("libclang{}", env::consts::DLL_SUFFIX)
		} else {
			format!("{}clang{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX)
		};

    //may contain path to libclang detected via ldconfig
    let mut libclang_path_string = String::new();

    let mut maybe_clang_dir = possible_clang_dirs.iter().filter_map(|candidate_dir| {
        let clang_dir = Path::new(candidate_dir);
        let clang_path = clang_dir.join(clang_lib.clone());
        if path_exists(&*clang_path) {
            Some(clang_dir)
        } else {
            None
        }
    }).next();
    if maybe_clang_dir == None && cfg!(target_os = "linux") {
        //try to find via lddconfig
        //may return line, like
        //libclang.so.3.7 (libc6,x86-64) => /usr/lib64/libclang.so.3.7
        let lddresult = Command::new("/sbin/ldconfig")
            .arg("-p")
            .output();
        if lddresult.is_ok() {
            let lddresult = lddresult.unwrap();
            let ldd_config_output = String::from_utf8_lossy(&lddresult.stdout).to_string();
            for line in ldd_config_output.lines() {
                let line_trim = line.trim();
                if line_trim.starts_with(&*clang_lib) {
                    let last_word = line_trim.rsplit(" ").next();
                    if let Some(last_word) = last_word {
                        let libclang_path = Path::new(last_word);
                        if path_exists(&libclang_path) {
                            libclang_path_string = last_word.to_owned();
                            maybe_clang_dir = Path::new(&libclang_path_string).parent();
                        }
                    }
                    break;
                }
            }
        }
    }

    macro_rules! qw {
        ($($i:ident)*) => (vec!($(stringify!($i)),*));
    }

    if let Some(clang_dir) = maybe_clang_dir {
        if use_static_lib {
            let libs = qw![
                LLVMAnalysis
                LLVMBitReader
                LLVMCore
                LLVMLTO
                LLVMLinker
                LLVMMC
                LLVMMCParser
                LLVMObjCARCOpts
                LLVMObject
                LLVMOption
                LLVMScalarOpts
                LLVMSupport
                LLVMTarget
                LLVMTransformUtils
                LLVMVectorize
                LLVMipa
                LLVMipo
                clang
                clangARCMigrate
                clangAST
                clangASTMatchers
                clangAnalysis
                clangBasic
                clangDriver
                clangEdit
                clangFormat
                clangFrontend
                clangIndex
                clangLex
                clangParse
                clangRewrite
                clangRewriteFrontend
                clangSema
                clangSerialization
                clangStaticAnalyzerCheckers
                clangStaticAnalyzerCore
                clangStaticAnalyzerFrontend
                clangTooling
            ];

            print!("cargo:rustc-flags=");
            for lib in libs {
                print!("-l static={} ", lib);
            }
            println!("-L {} -l ncursesw -l z -l stdc++", clang_dir.to_str().unwrap());
        } else{
            println!("cargo:rustc-link-search={}", clang_dir.to_str().unwrap());
            if !libclang_path_string.is_empty() {
                let libclang_path = Path::new(&libclang_path_string);
                println!("cargo:rustc-link-lib=dylib=:{}", libclang_path.file_name().unwrap().to_str().unwrap());
            } else {
                println!("cargo:rustc-link-lib=dylib=clang");
            }
        }
    } else {
        panic!("Unable to find {}", clang_lib);
    }
}
<|endoftext|>


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

//! Finds and links to the required `libclang` libraries.

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", warn(clippy))]

extern crate glob;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command};

use glob::{MatchOptions};

// Environment variables:
//
// * LLVM_CONFIG_PATH - provides a path to an `llvm-config` executable
// * LIBCLANG_PATH - provides a path to a directory containing a `libclang` shared library
// * LIBCLANG_STATIC_PATH - provides a path to a directory containing LLVM and Clang static libraries

/// Returns a path to one of the supplied files if such a file can be found in the supplied directory.
fn contains<D: AsRef<Path>>(directory: D, files: &[String]) -> Option<PathBuf> {
    files.iter().map(|file| directory.as_ref().join(file)).find(|file| file.exists())
}

/// Runs a console command, returning the output if the command was successfully executed.
fn run(command: &str, arguments: &[&str]) -> Option<String> {
    Command::new(command).args(arguments).output().map(|o| {
        String::from_utf8_lossy(&o.stdout).into_owned()
    }).ok()
}

/// Runs `llvm-config`, returning the output if the command was successfully executed.
fn run_llvm_config(arguments: &[&str]) -> Option<String> {
    run(&env::var("LLVM_CONFIG_PATH").unwrap_or("llvm-config".into()), arguments)
}

/// Backup search directory globs for FreeBSD and Linux.
const SEARCH_LINUX: &'static [&'static str] = &[
    "/usr/lib*",
    "/usr/lib*/*",
    "/usr/lib*/*/*",
    "/usr/local/lib*",
    "/usr/local/lib*/*",
    "/usr/local/lib*/*/*",
    "/usr/local/llvm*/lib",
];

/// Backup search directory globs for OS X.
const SEARCH_OSX: &'static [&'static str] = &[
    "/usr/local/opt/llvm*/lib",
    "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib",
    "/Library/Developer/CommandLineTools/usr/lib",
    "/usr/local/opt/llvm*/lib/llvm*/lib",
];

/// Backup search directory globs for Windows.
const SEARCH_WINDOWS: &'static [&'static str] = &[
    "C:\\LLVM\\lib",
    "C:\\Program Files*\\LLVM\\lib",
    "C:\\MSYS*\\MinGW*\\lib",
];

/// Searches for a library, returning the directory it can be found in if the search was successful.
fn find(files: &[String], env: &str) -> Result<PathBuf, String> {
    /// Searches the supplied directory and, on Windows, any relevant sibling directories.
    macro_rules! search_directory {
        ($directory:ident) => {
            if let Some(file) = contains(&$directory, files) {
                return Ok(file);
            }

            // On Windows, `libclang.dll` is usually found in the LLVM `bin` directory while
            // `libclang.lib` is usually found in the LLVM `lib` directory. To keep things
            // consistent with other platforms, only LLVM `lib` directories are included in the
            // backup search directory globs so we need to search the LLVM `bin` directory here.
            if cfg!(target_os="windows") && $directory.ends_with("lib") {
                let sibling = $directory.parent().unwrap().join("bin");
                if let Some(file) = contains(&sibling, files) {
                    return Ok(file);
                }
            }
        }
    }

    // Search the directory provided by the relevant environment variable if it is set.
    if let Ok(directory) = env::var(env).map(|d| Path::new(&d).to_path_buf()) {
        search_directory!(directory);
    }

    // Search the `bin` and `lib` subdirectories in the directory returned by
    // `llvm-config --prefix` if `llvm-config` is available.
    if let Some(output) = run_llvm_config(&["--prefix"]) {
        let directory = Path::new(output.lines().next().unwrap()).to_path_buf();
        let bin = directory.join("bin");
        if let Some(file) = contains(&bin, files) {
            return Ok(file);
        }
        let lib = directory.join("lib");
        if let Some(file) = contains(&lib, files) {
            return Ok(file);
        }
    }

    // Search the backup directories.
    let search = if cfg!(any(target_os="freebsd", target_os="linux")) {
        SEARCH_LINUX
    } else if cfg!(target_os="macos") {
        SEARCH_OSX
    } else if cfg!(target_os="windows") {
        SEARCH_WINDOWS
    } else {
        &[]
    };
    for pattern in search {
        let mut options = MatchOptions::new();
        options.case_sensitive = false;
        options.require_literal_separator = true;
        if let Ok(paths) = glob::glob_with(pattern, &options) {
            for path in paths.filter_map(Result::ok).filter(|p| p.is_dir()) {
                search_directory!(path);
            }
        }
    }

    let message = format!(
        "couldn't find any of {}, set the {} environment variable to a path where one of these \
         files can be found",
        files.iter().map(|f| format!("'{}'", f)).collect::<Vec<_>>().join(", "),
        env,
    );
    Err(message)
}

/// Searches for a `libclang` shared library, returning the path to such a shared library if the
/// search was successful.
pub fn find_shared_library() -> Result<PathBuf, String> {
    let mut files = vec![];
    if cfg!(target_os="windows") {
        // The official LLVM build uses `libclang.dll` on Windows instead of `clang.dll`. However,
        // unofficial builds such as MinGW use `clang.dll`.
        files.push("libclang.dll".into());
    }
    files.push(format!("{}clang{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX));
    find(&files, "LIBCLANG_PATH")
}

/// Returns the name of an LLVM or Clang library from a path to such a library.
fn get_library_name(path: &Path) -> Option<String> {
    path.file_stem().map(|l| l.to_string_lossy()[3..].into())
}

/// Returns the LLVM libraries required to link to `libclang` statically.
fn get_llvm_libraries() -> Vec<String> {
    run_llvm_config(&["--libs"]).expect(
        "couldn't execute `llvm-config --libs`, set the LLVM_CONFIG_PATH environment variable to a \
         path to an `llvm-config` executable"
    ).split_whitespace().filter_map(|p| {
        // Depending on the version of `llvm-config` in use, listed libraries may be in one of two
        // forms, a full path to the library or simply prefixed with `-l`.
        if p.starts_with("-l") {
            Some(p[2..].into())
        } else {
            get_library_name(Path::new(p))
        }
    }).collect()
}

/// Clang libraries required to link to `libclang` 3.5 and later statically.
const CLANG_LIBRARIES: &'static [&'static str] = &[
    "clang",
    "clangAST",
    "clangAnalysis",
    "clangBasic",
    "clangDriver",
    "clangEdit",
    "clangFrontend",
    "clangIndex",
    "clangLex",
    "clangParse",
    "clangRewrite",
    "clangSema",
    "clangSerialization",
];

/// Returns the Clang libraries required to link to `libclang` statically.
fn get_clang_libraries<P: AsRef<Path>>(directory: P) -> Vec<String> {
    let pattern = directory.as_ref().join("libclang*.a").to_string_lossy().to_string();
    if let Ok(libraries) = glob::glob(&pattern) {
        libraries.filter_map(|l| l.ok().and_then(|l| get_library_name(&l))).collect()
    } else {
        CLANG_LIBRARIES.iter().map(|l| l.to_string()).collect()
    }
}

/// Find and link to `libclang` statically.
fn link_static() {
    let file = find(&["libclang.a".into()], "LIBCLANG_STATIC_PATH").unwrap();
    let directory = file.parent().unwrap();
    print!("cargo:rustc-flags=");

    // Specify required LLVM and Clang static libraries.
    print!("-L {} ", directory.display());
    for library in get_llvm_libraries() {
        print!("-l static={} ", library);
    }
    for library in get_clang_libraries(&directory) {
        print!("-l static={} ", library);
    }

    // Specify required system libraries.
    if cfg!(target_os="freebsd") {
        println!("-l ffi -l ncursesw -l c++ -l z");
    } else if cfg!(target_os="linux") {
        println!("-l ffi -l ncursesw -l stdc++ -l z");
    } else if cfg!(target_os="macos") {
        println!("-l ffi -l ncurses -l c++ -l z");
    } else {
        panic!("unsupported operating system for static linking");
    }
}

/// Find and link to `libclang` dynamically.
fn link_dynamic() {
    let file = find_shared_library().unwrap();
    let directory = file.parent().unwrap();
    println!("cargo:rustc-link-search={}", directory.display());

    if cfg!(all(target_os="windows", target_env="msvc")) {
        // Find the `libclang` stub static library required for the MSVC toolchain.
        let libdir = if !directory.ends_with("bin") {
            directory.to_owned()
        } else {
            directory.parent().unwrap().join("lib")
        };
        if libdir.join("libclang.lib").exists() {
            println!("cargo:rustc-link-search={}", libdir.display());
        } else if libdir.join("libclang.dll.a").exists() {
            // MSYS and MinGW use `libclang.dll.a` instead of `libclang.lib`. It is linkable with
            // the MSVC linker, but Rust doesn't recognize the `.a` suffix, so we need to copy it
            // with a different name.
            //
            // FIXME: Maybe we can just hardlink or symlink it?
            let out = env::var("OUT_DIR").unwrap();
            fs::copy(libdir.join("libclang.dll.a"), Path::new(&out).join("libclang.lib")).unwrap();
            println!("cargo:rustc-link-search=native={}", out);
        } else {
            panic!(
                "using '{}', so 'libclang.lib' or 'libclang.dll.a' must be available in {}",
                file.display(),
                libdir.display(),
            );
        }
        println!("cargo:rustc-link-lib=dylib=libclang");
    } else {
        println!("cargo:rustc-link-lib=dylib=clang");
    }
}

fn main() {
    if cfg!(feature="runtime") {
        if cfg!(feature="static") {
            panic!("`runtime` and `static` features can't be combined");
        }
    } else if cfg!(feature="static") {
        link_static();
    } else {
        link_dynamic();
    }
}
<commit_msg>Fix warnings<commit_after>// Copyright 2016 Kyle Mayes
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Finds and links to the required `libclang` libraries.

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![cfg_attr(feature="clippy", warn(clippy))]

extern crate glob;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command};

use glob::{MatchOptions};

// Environment variables:
//
// * LLVM_CONFIG_PATH - provides a path to an `llvm-config` executable
// * LIBCLANG_PATH - provides a path to a directory containing a `libclang` shared library
// * LIBCLANG_STATIC_PATH - provides a path to a directory containing LLVM and Clang static libraries

/// Returns a path to one of the supplied files if such a file can be found in the supplied directory.
fn contains<D: AsRef<Path>>(directory: D, files: &[String]) -> Option<PathBuf> {
    files.iter().map(|file| directory.as_ref().join(file)).find(|file| file.exists())
}

/// Runs a console command, returning the output if the command was successfully executed.
fn run(command: &str, arguments: &[&str]) -> Option<String> {
    Command::new(command).args(arguments).output().map(|o| {
        String::from_utf8_lossy(&o.stdout).into_owned()
    }).ok()
}

/// Runs `llvm-config`, returning the output if the command was successfully executed.
fn run_llvm_config(arguments: &[&str]) -> Option<String> {
    run(&env::var("LLVM_CONFIG_PATH").unwrap_or("llvm-config".into()), arguments)
}

/// Backup search directory globs for FreeBSD and Linux.
const SEARCH_LINUX: &'static [&'static str] = &[
    "/usr/lib*",
    "/usr/lib*/*",
    "/usr/lib*/*/*",
    "/usr/local/lib*",
    "/usr/local/lib*/*",
    "/usr/local/lib*/*/*",
    "/usr/local/llvm*/lib",
];

/// Backup search directory globs for OS X.
const SEARCH_OSX: &'static [&'static str] = &[
    "/usr/local/opt/llvm*/lib",
    "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib",
    "/Library/Developer/CommandLineTools/usr/lib",
    "/usr/local/opt/llvm*/lib/llvm*/lib",
];

/// Backup search directory globs for Windows.
const SEARCH_WINDOWS: &'static [&'static str] = &[
    "C:\\LLVM\\lib",
    "C:\\Program Files*\\LLVM\\lib",
    "C:\\MSYS*\\MinGW*\\lib",
];

/// Searches for a library, returning the directory it can be found in if the search was successful.
fn find(files: &[String], env: &str) -> Result<PathBuf, String> {
    /// Searches the supplied directory and, on Windows, any relevant sibling directories.
    macro_rules! search_directory {
        ($directory:ident) => {
            if let Some(file) = contains(&$directory, files) {
                return Ok(file);
            }

            // On Windows, `libclang.dll` is usually found in the LLVM `bin` directory while
            // `libclang.lib` is usually found in the LLVM `lib` directory. To keep things
            // consistent with other platforms, only LLVM `lib` directories are included in the
            // backup search directory globs so we need to search the LLVM `bin` directory here.
            if cfg!(target_os="windows") && $directory.ends_with("lib") {
                let sibling = $directory.parent().unwrap().join("bin");
                if let Some(file) = contains(&sibling, files) {
                    return Ok(file);
                }
            }
        }
    }

    // Search the directory provided by the relevant environment variable if it is set.
    if let Ok(directory) = env::var(env).map(|d| Path::new(&d).to_path_buf()) {
        search_directory!(directory);
    }

    // Search the `bin` and `lib` subdirectories in the directory returned by
    // `llvm-config --prefix` if `llvm-config` is available.
    if let Some(output) = run_llvm_config(&["--prefix"]) {
        let directory = Path::new(output.lines().next().unwrap()).to_path_buf();
        let bin = directory.join("bin");
        if let Some(file) = contains(&bin, files) {
            return Ok(file);
        }
        let lib = directory.join("lib");
        if let Some(file) = contains(&lib, files) {
            return Ok(file);
        }
    }

    // Search the backup directories.
    let search = if cfg!(any(target_os="freebsd", target_os="linux")) {
        SEARCH_LINUX
    } else if cfg!(target_os="macos") {
        SEARCH_OSX
    } else if cfg!(target_os="windows") {
        SEARCH_WINDOWS
    } else {
        &[]
    };
    for pattern in search {
        let mut options = MatchOptions::new();
        options.case_sensitive = false;
        options.require_literal_separator = true;
        if let Ok(paths) = glob::glob_with(pattern, &options) {
            for path in paths.filter_map(Result::ok).filter(|p| p.is_dir()) {
                search_directory!(path);
            }
        }
    }

    let message = format!(
        "couldn't find any of {}, set the {} environment variable to a path where one of these \
         files can be found",
        files.iter().map(|f| format!("'{}'", f)).collect::<Vec<_>>().join(", "),
        env,
    );
    Err(message)
}

/// Searches for a `libclang` shared library, returning the path to such a shared library if the
/// search was successful.
pub fn find_shared_library() -> Result<PathBuf, String> {
    let mut files = vec![];
    if cfg!(target_os="windows") {
        // The official LLVM build uses `libclang.dll` on Windows instead of `clang.dll`. However,
        // unofficial builds such as MinGW use `clang.dll`.
        files.push("libclang.dll".into());
    }
    files.push(format!("{}clang{}", env::consts::DLL_PREFIX, env::consts::DLL_SUFFIX));
    find(&files, "LIBCLANG_PATH")
}

/// Returns the name of an LLVM or Clang library from a path to such a library.
fn get_library_name(path: &Path) -> Option<String> {
    path.file_stem().map(|l| l.to_string_lossy()[3..].into())
}

/// Returns the LLVM libraries required to link to `libclang` statically.
fn get_llvm_libraries() -> Vec<String> {
    run_llvm_config(&["--libs"]).expect(
        "couldn't execute `llvm-config --libs`, set the LLVM_CONFIG_PATH environment variable to a \
         path to an `llvm-config` executable"
    ).split_whitespace().filter_map(|p| {
        // Depending on the version of `llvm-config` in use, listed libraries may be in one of two
        // forms, a full path to the library or simply prefixed with `-l`.
        if p.starts_with("-l") {
            Some(p[2..].into())
        } else {
            get_library_name(Path::new(p))
        }
    }).collect()
}

/// Clang libraries required to link to `libclang` 3.5 and later statically.
const CLANG_LIBRARIES: &'static [&'static str] = &[
    "clang",
    "clangAST",
    "clangAnalysis",
    "clangBasic",
    "clangDriver",
    "clangEdit",
    "clangFrontend",
    "clangIndex",
    "clangLex",
    "clangParse",
    "clangRewrite",
    "clangSema",
    "clangSerialization",
];

/// Returns the Clang libraries required to link to `libclang` statically.
fn get_clang_libraries<P: AsRef<Path>>(directory: P) -> Vec<String> {
    let pattern = directory.as_ref().join("libclang*.a").to_string_lossy().to_string();
    if let Ok(libraries) = glob::glob(&pattern) {
        libraries.filter_map(|l| l.ok().and_then(|l| get_library_name(&l))).collect()
    } else {
        CLANG_LIBRARIES.iter().map(|l| l.to_string()).collect()
    }
}

/// Find and link to `libclang` statically.
#[cfg_attr(feature="runtime", allow(dead_code))]
fn link_static() {
    let file = find(&["libclang.a".into()], "LIBCLANG_STATIC_PATH").unwrap();
    let directory = file.parent().unwrap();
    print!("cargo:rustc-flags=");

    // Specify required LLVM and Clang static libraries.
    print!("-L {} ", directory.display());
    for library in get_llvm_libraries() {
        print!("-l static={} ", library);
    }
    for library in get_clang_libraries(&directory) {
        print!("-l static={} ", library);
    }

    // Specify required system libraries.
    if cfg!(target_os="freebsd") {
        println!("-l ffi -l ncursesw -l c++ -l z");
    } else if cfg!(target_os="linux") {
        println!("-l ffi -l ncursesw -l stdc++ -l z");
    } else if cfg!(target_os="macos") {
        println!("-l ffi -l ncurses -l c++ -l z");
    } else {
        panic!("unsupported operating system for static linking");
    }
}

/// Find and link to `libclang` dynamically.
#[cfg_attr(feature="runtime", allow(dead_code))]
fn link_dynamic() {
    let file = find_shared_library().unwrap();
    let directory = file.parent().unwrap();
    println!("cargo:rustc-link-search={}", directory.display());

    if cfg!(all(target_os="windows", target_env="msvc")) {
        // Find the `libclang` stub static library required for the MSVC toolchain.
        let libdir = if !directory.ends_with("bin") {
            directory.to_owned()
        } else {
            directory.parent().unwrap().join("lib")
        };
        if libdir.join("libclang.lib").exists() {
            println!("cargo:rustc-link-search={}", libdir.display());
        } else if libdir.join("libclang.dll.a").exists() {
            // MSYS and MinGW use `libclang.dll.a` instead of `libclang.lib`. It is linkable with
            // the MSVC linker, but Rust doesn't recognize the `.a` suffix, so we need to copy it
            // with a different name.
            //
            // FIXME: Maybe we can just hardlink or symlink it?
            let out = env::var("OUT_DIR").unwrap();
            fs::copy(libdir.join("libclang.dll.a"), Path::new(&out).join("libclang.lib")).unwrap();
            println!("cargo:rustc-link-search=native={}", out);
        } else {
            panic!(
                "using '{}', so 'libclang.lib' or 'libclang.dll.a' must be available in {}",
                file.display(),
                libdir.display(),
            );
        }
        println!("cargo:rustc-link-lib=dylib=libclang");
    } else {
        println!("cargo:rustc-link-lib=dylib=clang");
    }
}

#[cfg_attr(feature="runtime", allow(dead_code))]
fn main() {
    if cfg!(feature="runtime") {
        if cfg!(feature="static") {
            panic!("`runtime` and `static` features can't be combined");
        }
    } else if cfg!(feature="static") {
        link_static();
    } else {
        link_dynamic();
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

use man::prelude::*;
use regex::Regex;
use yaml_rust::yaml::Hash;
use yaml_rust::{Yaml, YamlLoader};

fn s2y<T: ToString>(s: T) -> Yaml {
    Yaml::String(s.to_string())
}

fn parse_str<T: ToString>(a: &Hash, k: T) -> String {
    let s = a.get(&s2y(k));
    if s.is_none() {
        "".to_string()
    } else {
        s.unwrap().as_str().unwrap().to_string()
    }
}

fn set_authors(p: Manual) -> Manual {
    let authors = env::var("CARGO_PKG_AUTHORS").unwrap();
    let re = Regex::new(r"([\w|\s]+)\s+<([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9]+)>").unwrap();
    re.captures_iter(&authors)
        .map(|x| {
            (
                x.get(1).map_or("", |m| m.as_str()),
                x.get(2).map_or("", |m| m.as_str()),
            )
        })
        .fold(p, |p, c| p.author(Author::new(c.0).email(c.1)))
}

fn set_args(mut p: Manual, y: &Yaml) -> Manual {
    let args = y["args"].as_vec().unwrap();
    for karg in args {
        let (key, val) = karg.as_hash().unwrap().iter().next().unwrap();
        let key = key.as_str().unwrap();
        let arg = val.as_hash().unwrap();
        if arg.get(&s2y("index")).is_none() {
            let takes_value = arg.get(&s2y("takes_value"));
            if takes_value.is_none() || takes_value.unwrap().as_bool().unwrap() == false {
                let mut f = Flag::new()
                    .long(parse_str(&arg, "long").as_str())
                    .help(parse_str(&arg, "help").as_str());
                let short = parse_str(&arg, "short");
                if short != "" {
                    f = f.short(short.as_str());
                }
                p = p.flag(f);
            } else {
                let o_val = parse_str(&arg, "value_name");
                let key = if o_val != "" { o_val.as_str() } else { key };
                let mut o = Opt::new(key)
                    .long(parse_str(&arg, "long").as_str())
                    .help(parse_str(&arg, "help").as_str());
                let short = parse_str(&arg, "short");
                let default_value = parse_str(&arg, "default_value");
                if short != "" {
                    o = o.short(short.as_str());
                }
                if default_value != "" {
                    o = o.default_value(default_value.as_str());
                }
                p = p.option(o);
            }
        } else {
            p = p.arg(Arg::new(key));
        }
    }
    p
}

fn generate_manpage(yml: &Yaml, trg_dir: &Path) -> std::io::Result<()> {
    let out_location = trg_dir.join("git-req.man");

    let page = Manual::new("git-req").about(yml["about"].as_str().unwrap());
    let page = set_authors(page);
    let page = set_args(page, yml);

    let mut output = File::create(out_location)?;
    write!(output, "{}", page.render())?;

    Ok(())
}

fn main() -> std::io::Result<()> {
    let trg_dir = match env::var("CARGO_TARGET_DIR") {
        Ok(s) => s,
        Err(_) => String::from("target"),
    };
    let trg_dir = Path::new(&trg_dir).join(&env::var("PROFILE").unwrap());

    let yml = YamlLoader::load_from_str(include_str!("cli-flags.yml")).unwrap();
    let yml = yml.get(0).unwrap();

    generate_manpage(yml, &trg_dir)?;

    Ok(())
}
<commit_msg>Address new Clippy warnings on the build script.<commit_after>use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

use man::prelude::*;
use regex::Regex;
use yaml_rust::yaml::Hash;
use yaml_rust::{Yaml, YamlLoader};

fn s2y<T: ToString>(s: T) -> Yaml {
    Yaml::String(s.to_string())
}

fn parse_str<T: ToString>(a: &Hash, k: T) -> String {
    let s = a.get(&s2y(k));
    match s {
        Some(ele) => ele.as_str().unwrap().to_string(),
        None => "".to_string(),
    }
}

fn set_authors(p: Manual) -> Manual {
    let authors = env::var("CARGO_PKG_AUTHORS").unwrap();
    let re = Regex::new(r"([\w|\s]+)\s+<([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9]+)>").unwrap();
    re.captures_iter(&authors)
        .map(|x| {
            (
                x.get(1).map_or("", |m| m.as_str()),
                x.get(2).map_or("", |m| m.as_str()),
            )
        })
        .fold(p, |p, c| p.author(Author::new(c.0).email(c.1)))
}

fn set_args(mut p: Manual, y: &Yaml) -> Manual {
    let args = y["args"].as_vec().unwrap();
    for karg in args {
        let (key, val) = karg.as_hash().unwrap().iter().next().unwrap();
        let key = key.as_str().unwrap();
        let arg = val.as_hash().unwrap();
        if arg.get(&s2y("index")).is_none() {
            let takes_value = arg.get(&s2y("takes_value"));
            if takes_value.is_none() || !takes_value.unwrap().as_bool().unwrap() {
                let mut f = Flag::new()
                    .long(parse_str(&arg, "long").as_str())
                    .help(parse_str(&arg, "help").as_str());
                let short = parse_str(&arg, "short");
                if short != "" {
                    f = f.short(short.as_str());
                }
                p = p.flag(f);
            } else {
                let o_val = parse_str(&arg, "value_name");
                let key = if o_val != "" { o_val.as_str() } else { key };
                let mut o = Opt::new(key)
                    .long(parse_str(&arg, "long").as_str())
                    .help(parse_str(&arg, "help").as_str());
                let short = parse_str(&arg, "short");
                let default_value = parse_str(&arg, "default_value");
                if short != "" {
                    o = o.short(short.as_str());
                }
                if default_value != "" {
                    o = o.default_value(default_value.as_str());
                }
                p = p.option(o);
            }
        } else {
            p = p.arg(Arg::new(key));
        }
    }
    p
}

fn generate_manpage(yml: &Yaml, trg_dir: &Path) -> std::io::Result<()> {
    let out_location = trg_dir.join("git-req.man");

    let page = Manual::new("git-req").about(yml["about"].as_str().unwrap());
    let page = set_authors(page);
    let page = set_args(page, yml);

    let mut output = File::create(out_location)?;
    write!(output, "{}", page.render())?;

    Ok(())
}

fn main() -> std::io::Result<()> {
    let trg_dir = match env::var("CARGO_TARGET_DIR") {
        Ok(s) => s,
        Err(_) => String::from("target"),
    };
    let trg_dir = Path::new(&trg_dir).join(&env::var("PROFILE").unwrap());

    let yml = YamlLoader::load_from_str(include_str!("cli-flags.yml")).unwrap();
    let yml = yml.get(0).unwrap();

    generate_manpage(yml, &trg_dir)?;

    Ok(())
}
<|endoftext|>


<commit_before>// spell-checker:ignore (vars) krate

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

pub fn main() {
    // println!("cargo:warning=Running build.rs");

    if let Ok(profile) = env::var("PROFILE") {
        println!("cargo:rustc-cfg=build={:?}", profile);
    }

    const ENV_FEATURE_PREFIX: &str = "CARGO_FEATURE_";
    const FEATURE_PREFIX: &str = "feat_";
    const OVERRIDE_PREFIX: &str = "uu_";

    let out_dir = env::var("OUT_DIR").unwrap();
    // println!("cargo:warning=out_dir={}", out_dir);
    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap().replace('\\', "/");
    // println!("cargo:warning=manifest_dir={}", manifest_dir);
    let util_tests_dir = format!("{}/tests/by-util", manifest_dir);
    // println!("cargo:warning=util_tests_dir={}", util_tests_dir);

    let mut crates = Vec::new();
    for (key, val) in env::vars() {
        if val == "1" && key.starts_with(ENV_FEATURE_PREFIX) {
            let krate = key[ENV_FEATURE_PREFIX.len()..].to_lowercase();
            match krate.as_ref() {
                "default" | "macos" | "unix" | "windows" | "selinux" => continue, // common/standard feature names
                "nightly" | "test_unimplemented" => continue, // crate-local custom features
                "test" => continue, // over-ridden with 'uu_test' to avoid collision with rust core crate 'test'
                s if s.starts_with(FEATURE_PREFIX) => continue, // crate feature sets
                _ => {}             // util feature name
            }
            crates.push(krate);
        }
    }
    crates.sort();

    let mut mf = File::create(Path::new(&out_dir).join("uutils_map.rs")).unwrap();
    let mut tf = File::create(Path::new(&out_dir).join("test_modules.rs")).unwrap();

    mf.write_all(
        "type UtilityMap<T> = phf::Map<&'static str, (fn(T) -> i32, fn() -> App<'static>)>;\n\
         \n\
         fn util_map<T: uucore::Args>() -> UtilityMap<T> {\n"
            .as_bytes(),
    )
    .unwrap();

    let mut phf_map = phf_codegen::Map::<String>::new();
    for krate in crates {
        let map_value = format!("({krate}::uumain, {krate}::uu_app)", krate = krate);
        match krate.as_ref() {
            // 'test' is named uu_test to avoid collision with rust core crate 'test'.
            // It can also be invoked by name '[' for the '[ expr ] syntax'.
            "uu_test" => {
                phf_map.entry(String::from("test"), &map_value);
                phf_map.entry(String::from("["), &map_value);

                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_test.rs\"]\nmod test_test;\n",
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap()
            }
            k if k.starts_with(OVERRIDE_PREFIX) => {
                phf_map.entry(String::from(&krate[OVERRIDE_PREFIX.len()..]), &map_value);
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{k}.rs\"]\nmod test_{k};\n",
                        k = &krate[OVERRIDE_PREFIX.len()..],
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap()
            }
            "false" | "true" => {
                phf_map.entry(
                    String::from(&krate),
                    &format!("(r#{krate}::uumain, r#{krate}::uu_app)", krate = krate),
                );
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n",
                        krate = krate,
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap()
            }
            "hashsum" => {
                phf_map.entry(
                    String::from(&krate),
                    &format!("({krate}::uumain, {krate}::uu_app_custom)", krate = krate),
                );

                let map_value = format!("({krate}::uumain, {krate}::uu_app_common)", krate = krate);
                phf_map.entry(String::from("md5sum"), &map_value);
                phf_map.entry(String::from("sha1sum"), &map_value);
                phf_map.entry(String::from("sha224sum"), &map_value);
                phf_map.entry(String::from("sha256sum"), &map_value);
                phf_map.entry(String::from("sha384sum"), &map_value);
                phf_map.entry(String::from("sha512sum"), &map_value);
                phf_map.entry(String::from("sha3sum"), &map_value);
                phf_map.entry(String::from("sha3-224sum"), &map_value);
                phf_map.entry(String::from("sha3-256sum"), &map_value);
                phf_map.entry(String::from("sha3-384sum"), &map_value);
                phf_map.entry(String::from("sha3-512sum"), &map_value);
                phf_map.entry(String::from("shake128sum"), &map_value);
                phf_map.entry(String::from("shake256sum"), &map_value);
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n",
                        krate = krate,
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap()
            }
            _ => {
                phf_map.entry(String::from(&krate), &map_value);
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n",
                        krate = krate,
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap()
            }
        }
    }
    write!(mf, "{}", phf_map.build()).unwrap();
    mf.write_all(b"\n}\n").unwrap();

    mf.flush().unwrap();
    tf.flush().unwrap();
}
<commit_msg>Avoid unneeded Strings in building phf map<commit_after>// spell-checker:ignore (vars) krate

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

pub fn main() {
    // println!("cargo:warning=Running build.rs");

    if let Ok(profile) = env::var("PROFILE") {
        println!("cargo:rustc-cfg=build={:?}", profile);
    }

    const ENV_FEATURE_PREFIX: &str = "CARGO_FEATURE_";
    const FEATURE_PREFIX: &str = "feat_";
    const OVERRIDE_PREFIX: &str = "uu_";

    let out_dir = env::var("OUT_DIR").unwrap();
    // println!("cargo:warning=out_dir={}", out_dir);
    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap().replace('\\', "/");
    // println!("cargo:warning=manifest_dir={}", manifest_dir);
    let util_tests_dir = format!("{}/tests/by-util", manifest_dir);
    // println!("cargo:warning=util_tests_dir={}", util_tests_dir);

    let mut crates = Vec::new();
    for (key, val) in env::vars() {
        if val == "1" && key.starts_with(ENV_FEATURE_PREFIX) {
            let krate = key[ENV_FEATURE_PREFIX.len()..].to_lowercase();
            match krate.as_ref() {
                "default" | "macos" | "unix" | "windows" | "selinux" => continue, // common/standard feature names
                "nightly" | "test_unimplemented" => continue, // crate-local custom features
                "test" => continue, // over-ridden with 'uu_test' to avoid collision with rust core crate 'test'
                s if s.starts_with(FEATURE_PREFIX) => continue, // crate feature sets
                _ => {}             // util feature name
            }
            crates.push(krate);
        }
    }
    crates.sort();

    let mut mf = File::create(Path::new(&out_dir).join("uutils_map.rs")).unwrap();
    let mut tf = File::create(Path::new(&out_dir).join("test_modules.rs")).unwrap();

    mf.write_all(
        "type UtilityMap<T> = phf::Map<&'static str, (fn(T) -> i32, fn() -> App<'static>)>;\n\
         \n\
         fn util_map<T: uucore::Args>() -> UtilityMap<T> {\n"
            .as_bytes(),
    )
    .unwrap();

    let mut phf_map = phf_codegen::Map::<&str>::new();
    for krate in &crates {
        let map_value = format!("({krate}::uumain, {krate}::uu_app)", krate = krate);
        match krate.as_ref() {
            // 'test' is named uu_test to avoid collision with rust core crate 'test'.
            // It can also be invoked by name '[' for the '[ expr ] syntax'.
            "uu_test" => {
                phf_map.entry("test", &map_value);
                phf_map.entry("[", &map_value);

                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_test.rs\"]\nmod test_test;\n",
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap()
            }
            k if k.starts_with(OVERRIDE_PREFIX) => {
                phf_map.entry(&k[OVERRIDE_PREFIX.len()..], &map_value);
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{k}.rs\"]\nmod test_{k};\n",
                        k = &krate[OVERRIDE_PREFIX.len()..],
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap()
            }
            "false" | "true" => {
                phf_map.entry(
                    krate,
                    &format!("(r#{krate}::uumain, r#{krate}::uu_app)", krate = krate),
                );
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n",
                        krate = krate,
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap()
            }
            "hashsum" => {
                phf_map.entry(
                    krate,
                    &format!("({krate}::uumain, {krate}::uu_app_custom)", krate = krate),
                );

                let map_value = format!("({krate}::uumain, {krate}::uu_app_common)", krate = krate);
                phf_map.entry("md5sum", &map_value);
                phf_map.entry("sha1sum", &map_value);
                phf_map.entry("sha224sum", &map_value);
                phf_map.entry("sha256sum", &map_value);
                phf_map.entry("sha384sum", &map_value);
                phf_map.entry("sha512sum", &map_value);
                phf_map.entry("sha3sum", &map_value);
                phf_map.entry("sha3-224sum", &map_value);
                phf_map.entry("sha3-256sum", &map_value);
                phf_map.entry("sha3-384sum", &map_value);
                phf_map.entry("sha3-512sum", &map_value);
                phf_map.entry("shake128sum", &map_value);
                phf_map.entry("shake256sum", &map_value);
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n",
                        krate = krate,
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap()
            }
            _ => {
                phf_map.entry(krate, &map_value);
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n",
                        krate = krate,
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap()
            }
        }
    }
    write!(mf, "{}", phf_map.build()).unwrap();
    mf.write_all(b"\n}\n").unwrap();

    mf.flush().unwrap();
    tf.flush().unwrap();
}
<|endoftext|>


<commit_before>

extern crate git2;
extern crate bindgen;

use std::path::{Path, PathBuf};
use git2::Repository;
use std::env;
use std::process::Command;

const REPO_URL: &str = "https://github.com/iris-edu/libmseed";
const BUILD_DIR: &str = "src/libmseed";
const GIT_REF: &str = "refs/remotes/origin/2.x"; // libmseed v3 broke the ABI

fn fetch_libmseed(dir: &str) {
    println!("fetching libmseed");
    let repo = match Repository::clone(REPO_URL, dir) {
        Ok( creepo ) => { creepo },
        Err(e) => panic!("Failed to update/clone repo: {}", e),
    };

    let branch = repo.revparse_single(GIT_REF).unwrap();
    repo.reset(&branch, git2::ResetType::Hard, None).unwrap();
}

fn make_libmseed(dir: &str) {
    let path = std::fs::canonicalize(dir).unwrap();
    let _ok = env::set_current_dir(&path).is_ok();

    let _output = Command::new("make").output().expect("make failed");
    let path = std::fs::canonicalize("../..").unwrap();
    let _ok = env::set_current_dir(&path).is_ok();
}

fn main() {

    if !Path::new(BUILD_DIR).is_dir() {
        fetch_libmseed(BUILD_DIR);
    }

    make_libmseed(BUILD_DIR);

    println!("cargo:rustc-link-lib=static=mseed");
    println!("cargo:rustc-link-search=native=../libmseed/");
    println!("Generate");

    let bindings = bindgen::Builder::default()
        .header("wrapper.h")
        .clang_arg("-I../libmseed")
        .allowlist_type("MS.*")
        .allowlist_var("MS_.*")
        .allowlist_var("HPT.*")
        .allowlist_function("ms_.*")
        .allowlist_function("msr_.*")
        .allowlist_function("mst_.*")
        .generate()
        .expect("Unable to generate bindings");
    println!("version: {:?}", bindgen::clang_version());
    println!("Path");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("couldn't write bindings");
}

<commit_msg>Update bindgen to hopefully find libmseed.h in src/libmseed<commit_after>

extern crate git2;
extern crate bindgen;

use std::path::{Path, PathBuf};
use git2::Repository;
use std::env;
use std::process::Command;

const REPO_URL: &str = "https://github.com/iris-edu/libmseed";
const BUILD_DIR: &str = "src/libmseed";
const GIT_REF: &str = "refs/remotes/origin/2.x"; // libmseed v3 broke the ABI

fn fetch_libmseed(dir: &str) {
    println!("fetching libmseed");
    let repo = match Repository::clone(REPO_URL, dir) {
        Ok( creepo ) => { creepo },
        Err(e) => panic!("Failed to update/clone repo: {}", e),
    };

    let branch = repo.revparse_single(GIT_REF).unwrap();
    repo.reset(&branch, git2::ResetType::Hard, None).unwrap();
}

fn make_libmseed(dir: &str) {
    let path = std::fs::canonicalize(dir).unwrap();
    let _ok = env::set_current_dir(&path).is_ok();

    let _output = Command::new("make").output().expect("make failed");
    let path = std::fs::canonicalize("../..").unwrap();
    let _ok = env::set_current_dir(&path).is_ok();
}

fn main() {

    if !Path::new(BUILD_DIR).is_dir() {
        fetch_libmseed(BUILD_DIR);
    }

    make_libmseed(BUILD_DIR);

    println!("cargo:rustc-link-lib=static=mseed");
    println!("cargo:rustc-link-search=native=../libmseed/");
    println!("Generate");

    let path = env::current_dir().unwrap();
    println!("The current directory is {}", path.display());

    let path : PathBuf = [BUILD_DIR, "libmseed.h"].iter().collect();
    if !path.exists() {
        panic!("libmseed header file: libmseed.h does not exist");
    }

    let bindings = bindgen::Builder::default()
        .header("wrapper.h")
        .clang_arg("-I./src/libmseed")
        .clang_arg("-I../libmseed")
        .allowlist_type("MS.*")
        .allowlist_var("MS_.*")
        .allowlist_var("HPT.*")
        .allowlist_function("ms_.*")
        .allowlist_function("msr_.*")
        .allowlist_function("mst_.*")
        .generate()
        .expect("Unable to generate bindings");
    println!("version: {:?}", bindgen::clang_version());
    println!("Path");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("couldn't write bindings");
}

<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! A handler and associated types for the interfaces action.
//!
//! The interfaces action lists all network interfaces available on the client,
//! collecting their names, MAC and IP addresses.

use rrg_macro::warn;

use crate::session::{self, Session};

/// A response type for the interfaces action.
#[derive(Debug)]
pub struct Response {
    /// Information about an interface.
    interface: crate::net::Interface,
}

/// Handles requests for the interfaces action.
pub fn handle<S: Session>(session: &mut S, _: ()) -> session::Result<()> {
    // TODO(panhania@): Fix error handling.
    for interface in crate::net::interfaces().unwrap() {
        session.reply(Response {
            interface: interface,
        })?;
    }

    Ok(())
}

impl super::Item for Response {

    const RDF_NAME: &'static str = "Interface";

    type Proto = rrg_proto::jobs::Interface;

    fn into_proto(self) -> rrg_proto::jobs::Interface {
        let mut proto = rrg_proto::jobs::Interface::new();

        let name = self.interface.name().to_string_lossy();
        if let std::borrow::Cow::Owned(_) = &name {
            warn!("network interface name with invalid bytes: {:?}", name);
        }
        proto.set_ifname(name.to_string());

        if let Some(mac_addr) = self.interface.mac_addr() {
            proto.set_mac_address(mac_addr.octets().into());
        } else {
            warn!("network interface '{}' without MAC address", name);
        }

        for ip_addr in self.interface.ip_addrs() {
            use rrg_proto::jobs::NetworkAddress_Family::{INET, INET6};

            let mut ip_addr_proto = rrg_proto::jobs::NetworkAddress::new();
            match ip_addr {
                std::net::IpAddr::V4(ip_addr) => {
                    ip_addr_proto.set_address_type(INET);
                    ip_addr_proto.set_packed_bytes(ip_addr.octets().into());
                },
                std::net::IpAddr::V6(ip_addr) => {
                    ip_addr_proto.set_address_type(INET6);
                    ip_addr_proto.set_packed_bytes(ip_addr.octets().into());
                },
            };
            proto.mut_addresses().push(ip_addr_proto);
        }

        proto
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn loopback_exists() {
        let mut session = session::FakeSession::new();
        assert!(handle(&mut session, ()).is_ok());

        // We have a choice: either require any of the addresses to be the loop-
        // back address or require all of them for it to be considered loopback.
        // Both of these options feel equally wrong and equally right but the
        // former one will return `true` for interfaces with no known addresses.
        // Since this feels awkward, we lean towards the "all" option.
        fn is_loopback(iface: &crate::net::Interface) -> bool {
            iface.ip_addrs().iter().all(std::net::IpAddr::is_loopback)
        }

        assert! {
            session.replies().any(|reply: &Response| {
                is_loopback(&reply.interface)
            })
        }
    }
}
<commit_msg>Refactor errors in the net interfaces action.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! A handler and associated types for the interfaces action.
//!
//! The interfaces action lists all network interfaces available on the client,
//! collecting their names, MAC and IP addresses.

use rrg_macro::warn;

use crate::session::{self, Session};

/// A response type for the interfaces action.
#[derive(Debug)]
pub struct Response {
    /// Information about an interface.
    interface: crate::net::Interface,
}

/// Handles requests for the interfaces action.
pub fn handle<S: Session>(session: &mut S, _: ()) -> session::Result<()> {
    let interfaces = crate::net::interfaces()
        .map_err(crate::session::Error::action)?;

    for interface in interfaces {
        session.reply(Response {
            interface: interface,
        })?;
    }

    Ok(())
}

impl super::Item for Response {

    const RDF_NAME: &'static str = "Interface";

    type Proto = rrg_proto::jobs::Interface;

    fn into_proto(self) -> rrg_proto::jobs::Interface {
        let mut proto = rrg_proto::jobs::Interface::new();

        let name = self.interface.name().to_string_lossy();
        if let std::borrow::Cow::Owned(_) = &name {
            warn!("network interface name with invalid bytes: {:?}", name);
        }
        proto.set_ifname(name.to_string());

        if let Some(mac_addr) = self.interface.mac_addr() {
            proto.set_mac_address(mac_addr.octets().into());
        } else {
            warn!("network interface '{}' without MAC address", name);
        }

        for ip_addr in self.interface.ip_addrs() {
            use rrg_proto::jobs::NetworkAddress_Family::{INET, INET6};

            let mut ip_addr_proto = rrg_proto::jobs::NetworkAddress::new();
            match ip_addr {
                std::net::IpAddr::V4(ip_addr) => {
                    ip_addr_proto.set_address_type(INET);
                    ip_addr_proto.set_packed_bytes(ip_addr.octets().into());
                },
                std::net::IpAddr::V6(ip_addr) => {
                    ip_addr_proto.set_address_type(INET6);
                    ip_addr_proto.set_packed_bytes(ip_addr.octets().into());
                },
            };
            proto.mut_addresses().push(ip_addr_proto);
        }

        proto
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn loopback_exists() {
        let mut session = session::FakeSession::new();
        assert!(handle(&mut session, ()).is_ok());

        // We have a choice: either require any of the addresses to be the loop-
        // back address or require all of them for it to be considered loopback.
        // Both of these options feel equally wrong and equally right but the
        // former one will return `true` for interfaces with no known addresses.
        // Since this feels awkward, we lean towards the "all" option.
        fn is_loopback(iface: &crate::net::Interface) -> bool {
            iface.ip_addrs().iter().all(std::net::IpAddr::is_loopback)
        }

        assert! {
            session.replies().any(|reply: &Response| {
                is_loopback(&reply.interface)
            })
        }
    }
}
<|endoftext|>