<commit_before>use std::ffi::{OsStr, OsString};
use std::fmt::Debug;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio, Output, ExitStatus};
use std::thread::JoinHandle;

mod pipe;

pub trait Expression: Clone + Send + Debug + 'static {
    fn exec(&self, context: IoContext) -> io::Result<ExitStatus>;

    fn get_ioargs(&mut self) -> &mut IoArgs;

    fn run(&self) -> Result<Output, Error> {
        let context = IoContext {
            stdin: CloneableStdio::Inherit,
            stdout: CloneableStdio::Inherit,
            stderr: CloneableStdio::Inherit,
        };
        let status = try!(self.exec(context));
        Ok(Output{
            status: status,
            stdout: Vec::new(),
            stderr: Vec::new(),
        })
    }

    fn read(&self) -> Result<String, Error> {
        let (stdout, stdout_reader) = pipe_with_reader_thread();
        let context = IoContext {
            stdin: CloneableStdio::Inherit,
            stdout: CloneableStdio::Handle(stdout),
            stderr: CloneableStdio::Inherit,
        };
        let status = try!(self.exec(context));
        let output = Output{
            status: status,
            stdout: try!(stdout_reader.join().unwrap()),
            stderr: Vec::new(),
        };
        if output.status.success() {
            // TODO: should only trim newlines
            Ok(try!(String::from_utf8(output.stdout)).trim_right().to_string())
        } else {
            Err(Error::Status(output))
        }
    }

    fn stdin(&mut self, path: &AsRef<Path>) -> &mut Self {
        self.get_ioargs().stdin = Some(path.as_ref().to_owned());
        self
    }

    fn stdout(&mut self, path: &AsRef<Path>) -> &mut Self {
        self.get_ioargs().stdout = Some(path.as_ref().to_owned());
        self
    }

    fn stderr(&mut self, path: &AsRef<Path>) -> &mut Self {
        self.get_ioargs().stderr = Some(path.as_ref().to_owned());
        self
    }
}

#[derive(Debug, Clone)]
pub struct ArgvCommand {
    argv: Vec<OsString>,
    ioargs: IoArgs,
}

impl ArgvCommand {
    pub fn new<T: AsRef<OsStr>>(prog: T) -> ArgvCommand {
        ArgvCommand{
            argv: vec![prog.as_ref().to_owned()],
            ioargs: IoArgs::new(),
        }
    }

    pub fn arg<T: AsRef<OsStr>>(&mut self, arg: T) -> &mut Self {
        self.argv.push(arg.as_ref().to_owned());
        self
    }
}

impl Expression for ArgvCommand {
    fn exec(&self, context: IoContext) -> io::Result<ExitStatus> {
        let new_context = try!(self.ioargs.update_context(context));
        let IoContext{stdin, stdout, stderr} = new_context;
        // Create a Command and add the args.
        let mut command = Command::new(&self.argv[0]);
        command.args(&self.argv[1..]);
        command.stdin(stdin.to_stdio());
        command.stdout(stdout.to_stdio());
        command.stderr(stderr.to_stdio());
        Ok(try!(command.status()))
    }

    fn get_ioargs(&mut self) -> &mut IoArgs {
        &mut self.ioargs
    }
}

#[derive(Debug, Clone)]
pub struct Pipe<T: Expression, U: Expression> {
    left: T,
    right: U,
    ioargs: IoArgs,
}

impl<T: Expression, U: Expression> Pipe<T, U> {
    pub fn new(left: &T, right: &U) -> Pipe<T, U> {
        Pipe{left: left.clone(), right: right.clone(), ioargs: IoArgs::new()}
    }
}

impl<T: Expression, U: Expression> Expression for Pipe<T, U> {
    fn exec(&self, context: IoContext) -> io::Result<ExitStatus> {
        let new_context = try!(self.ioargs.update_context(context));
        let IoContext{stdin, stdout, stderr} = new_context;
        let (read_pipe, write_pipe) = pipe::open_pipe();
        let left_context = IoContext{
            stdin: stdin,
            stdout: CloneableStdio::Handle(write_pipe),
            stderr: stderr.clone(),
        };
        let right_context = IoContext{
            stdin: CloneableStdio::Handle(read_pipe),
            stdout: stdout,
            stderr: stderr,
        };
        let left_clone = self.left.clone();
        let left_thread = std::thread::spawn(move || {
            left_clone.exec(left_context)
        });
        let right_status = self.right.exec(right_context);
        let left_status = left_thread.join().unwrap();
        match right_status {
            Err(_) => right_status,
            _ => left_status,
        }
    }

    fn get_ioargs(&mut self) -> &mut IoArgs {
        &mut self.ioargs
    }
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Utf8(std::string::FromUtf8Error),
    Status(Output),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<std::string::FromUtf8Error> for Error {
    fn from(err: std::string::FromUtf8Error) -> Error {
        Error::Utf8(err)
    }
}

#[derive(Clone, Debug)]
pub struct IoArgs {
    stdin: Option<PathBuf>,
    stdout: Option<PathBuf>,
    stderr: Option<PathBuf>,
}

impl IoArgs {
    fn new() -> IoArgs {
        IoArgs { stdin: None, stdout: None, stderr: None }
    }

    fn update_context(&self, mut context: IoContext) -> Result<IoContext, io::Error> {
        if let Some(ref path) = self.stdin {
            context.stdin = CloneableStdio::Handle(pipe::Handle::from_file(
                try!(File::open(&path))));
        }
        if let Some(ref path) = self.stdout {
            context.stdout = CloneableStdio::Handle(pipe::Handle::from_file(
                try!(File::create(&path))));
        }
        if let Some(ref path) = self.stderr {
            context.stderr = CloneableStdio::Handle(pipe::Handle::from_file(
                try!(File::create(&path))));
        }
        Ok(context)
    }
}

#[derive(Clone, Debug)]
pub struct IoContext {
    stdin: CloneableStdio,
    stdout: CloneableStdio,
    stderr: CloneableStdio,
}

#[derive(Clone, Debug)]
enum CloneableStdio {
    Inherit,
    Handle(pipe::Handle),
}

impl CloneableStdio {
    fn to_stdio(self) -> Stdio {
        match self {
            CloneableStdio::Inherit => Stdio::inherit(),
            CloneableStdio::Handle(handle) => handle.to_stdio(),
        }
    }
}

fn pipe_with_reader_thread() -> (pipe::Handle, JoinHandle<io::Result<Vec<u8>>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut read_file = read_pipe.to_file();
        let mut output = Vec::new();
        try!(read_file.read_to_end(&mut output));
        Ok(output)
    });
    (write_pipe, thread)
}

#[cfg(test)]
mod test {
    use super::{ArgvCommand, Pipe, Expression};
    use std::fs::File;
    use std::io::prelude::*;
    use std::path::PathBuf;

    fn mktemp() -> PathBuf {
        let output = ArgvCommand::new("mktemp").read().unwrap();
        let path: PathBuf = output.trim().into();
        println!("here's the path we're using: {:?}", path);
        path
    }

    #[test]
    fn test_run() {
        let result = ArgvCommand::new("true").arg("foo").arg("bar").run();
        assert!(result.unwrap().status.success());
    }

    #[test]
    fn test_read() {
        let output = ArgvCommand::new("echo").arg("hi").read().unwrap();
        assert_eq!(output, "hi");
    }

    #[test]
    fn test_stdout() {
        let path = mktemp();
        let result = ArgvCommand::new("echo").arg("hi").stdout(&path).run();
        assert!(result.unwrap().status.success());
        let mut contents = String::new();
        File::open(&path).unwrap().read_to_string(&mut contents).unwrap();
        assert_eq!(contents, "hi\n");
    }

    #[test]
    fn test_pipe() {
        let mut left = ArgvCommand::new("echo");
        left.arg("hi");
        let mut middle = ArgvCommand::new("sed");
        middle.arg("s/i/o/");
        let mut right = ArgvCommand::new("sed");
        right.arg("s/h/j/");
        let pipe = Pipe::new(&left, &Pipe::new(&middle, &right));
        let output = pipe.read().unwrap();
        assert_eq!(output, "jo");
    }
}
<commit_msg>define input() and factor out apply_ioargs_and_exec()<commit_after>use std::ffi::{OsStr, OsString};
use std::fmt::Debug;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio, Output, ExitStatus};
use std::thread::JoinHandle;

mod pipe;

pub trait Expression: Clone + Send + Debug + 'static {
    fn exec_inner(&self, context: IoContext) -> io::Result<ExitStatus>;

    fn get_ioargs(&self) -> &IoArgs;

    fn get_ioargs_mut(&mut self) -> &mut IoArgs;

    fn run(&self) -> Result<Output, Error> {
        let status = try!(apply_ioargs_and_exec(self, IoContext::new()));
        Ok(Output{
            status: status,
            stdout: Vec::new(),
            stderr: Vec::new(),
        })
    }

    fn read(&self) -> Result<String, Error> {
        let (stdout, stdout_reader) = pipe_with_reader_thread();
        let mut context = IoContext::new();
        context.stdout = CloneableStdio::Handle(stdout);
        let status = try!(apply_ioargs_and_exec(self, context));
        let output = Output{
            status: status,
            stdout: try!(stdout_reader.join().unwrap()),
            stderr: Vec::new(),
        };
        if output.status.success() {
            // TODO: should only trim newlines
            Ok(try!(String::from_utf8(output.stdout)).trim_right().to_string())
        } else {
            Err(Error::Status(output))
        }
    }

    fn input<T: AsRef<[u8]>>(&mut self, buf: T) -> &mut Self {
        self.get_ioargs_mut().input = Some(buf.as_ref().to_owned());
        self
    }

    fn stdin<T: AsRef<Path>>(&mut self, path: T) -> &mut Self {
        self.get_ioargs_mut().stdin = Some(path.as_ref().to_owned());
        self
    }

    fn stdout<T: AsRef<Path>>(&mut self, path: T) -> &mut Self {
        self.get_ioargs_mut().stdout = Some(path.as_ref().to_owned());
        self
    }

    fn stderr<T: AsRef<Path>>(&mut self, path: T) -> &mut Self {
        self.get_ioargs_mut().stderr = Some(path.as_ref().to_owned());
        self
    }

    // How will pipe() work here? Can it use <T>?
}

#[derive(Debug, Clone)]
pub struct ArgvCommand {
    argv: Vec<OsString>,
    ioargs: IoArgs,
}

impl ArgvCommand {
    pub fn new<T: AsRef<OsStr>>(prog: T) -> ArgvCommand {
        ArgvCommand{
            argv: vec![prog.as_ref().to_owned()],
            ioargs: IoArgs::new(),
        }
    }

    pub fn arg<T: AsRef<OsStr>>(&mut self, arg: T) -> &mut Self {
        self.argv.push(arg.as_ref().to_owned());
        self
    }
}

impl Expression for ArgvCommand {
    fn exec_inner(&self, context: IoContext) -> io::Result<ExitStatus> {
        let IoContext{stdin, stdout, stderr} = context;
        let mut command = Command::new(&self.argv[0]);
        command.args(&self.argv[1..]);
        command.stdin(stdin.to_stdio());
        command.stdout(stdout.to_stdio());
        command.stderr(stderr.to_stdio());
        command.status()
    }

    fn get_ioargs(&self) -> &IoArgs {
        &self.ioargs
    }

    fn get_ioargs_mut(&mut self) -> &mut IoArgs {
        &mut self.ioargs
    }
}

#[derive(Debug, Clone)]
pub struct Pipe<T: Expression, U: Expression> {
    left: T,
    right: U,
    ioargs: IoArgs,
}

impl<T: Expression, U: Expression> Pipe<T, U> {
    pub fn new(left: &T, right: &U) -> Pipe<T, U> {
        Pipe{left: left.clone(), right: right.clone(), ioargs: IoArgs::new()}
    }
}

impl<T: Expression, U: Expression> Expression for Pipe<T, U> {
    fn exec_inner(&self, context: IoContext) -> io::Result<ExitStatus> {
        // Assemble new IoContexts for the left and the right sides.
        let IoContext{stdin, stdout, stderr} = context;
        let (read_pipe, write_pipe) = pipe::open_pipe();
        let left_context = IoContext{
            stdin: stdin,
            stdout: CloneableStdio::Handle(write_pipe),
            stderr: stderr.clone(),
        };
        let right_context = IoContext{
            stdin: CloneableStdio::Handle(read_pipe),
            stdout: stdout,
            stderr: stderr,
        };

        // Clone the left side, and pass it to a new thread to execute.
        // TODO: Probably use a scoped thread here.
        let left_clone = self.left.clone();
        let left_thread = std::thread::spawn(move || {
            apply_ioargs_and_exec(&left_clone, left_context)
        });

        // Execute the right side in parallel, on this thread.
        let right_status = try!(apply_ioargs_and_exec(&self.right, right_context));

        // Wait for the left to finish, then return the rightmost error, if any.
        let left_status = try!(left_thread.join().unwrap());
        if right_status.success() {
            Ok(left_status)
        } else {
            Ok(right_status)
        }
    }

    fn get_ioargs(&self) -> &IoArgs {
        &self.ioargs
    }

    fn get_ioargs_mut(&mut self) -> &mut IoArgs {
        &mut self.ioargs
    }
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Utf8(std::string::FromUtf8Error),
    Status(Output),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<std::string::FromUtf8Error> for Error {
    fn from(err: std::string::FromUtf8Error) -> Error {
        Error::Utf8(err)
    }
}

#[derive(Clone, Debug)]
pub struct IoArgs {
    input: Option<Vec<u8>>,
    stdin: Option<PathBuf>,
    stdout: Option<PathBuf>,
    stderr: Option<PathBuf>,
}

impl IoArgs {
    fn new() -> IoArgs {
        IoArgs { input: None, stdin: None, stdout: None, stderr: None }
    }
}

fn apply_ioargs_and_exec<T: Expression>(expr: &T, mut context: IoContext) -> io::Result<ExitStatus> {
    // Update the IoContext, if any IO arguments are defined for the current expression. This might
    // require spawning a writer thread.
    let ioargs = expr.get_ioargs();
    if let Some(ref path) = ioargs.stdin {
        context.stdin = CloneableStdio::Handle(pipe::Handle::from_file(
            try!(File::open(&path))));
    }
    if let Some(ref path) = ioargs.stdout {
        context.stdout = CloneableStdio::Handle(pipe::Handle::from_file(
            try!(File::create(&path))));
    }
    if let Some(ref path) = ioargs.stderr {
        context.stderr = CloneableStdio::Handle(pipe::Handle::from_file(
            try!(File::create(&path))));
    }
    let mut writer_thread = None;
    if let Some(ref input) = ioargs.input {
        let (pipe_handle, thread_joiner) = pipe_with_writer_thread(input.clone());
        writer_thread = Some(thread_joiner);
        context.stdin = CloneableStdio::Handle(pipe_handle);
    }

    // Execute the expression using the updated IoContext.
    let exec_result = expr.exec_inner(context);

    // If we created a writer thread above, join it, even if the result above is an error.
    // TODO: Suppress closed pipe errors, but pass along others.
    let mut writer_result = Ok(());
    if let Some(join_handle) = writer_thread {
        writer_result = join_handle.join().unwrap();
    }

    let status = try!(exec_result);
    try!(writer_result);
    Ok(status)
}

#[derive(Clone, Debug)]
pub struct IoContext {
    stdin: CloneableStdio,
    stdout: CloneableStdio,
    stderr: CloneableStdio,
}

impl IoContext {
    fn new() -> IoContext {
        IoContext {
            stdin: CloneableStdio::Inherit,
            stdout: CloneableStdio::Inherit,
            stderr: CloneableStdio::Inherit,
        }
    }
}

#[derive(Clone, Debug)]
enum CloneableStdio {
    Inherit,
    Handle(pipe::Handle),
}

impl CloneableStdio {
    fn to_stdio(self) -> Stdio {
        match self {
            CloneableStdio::Inherit => Stdio::inherit(),
            CloneableStdio::Handle(handle) => handle.to_stdio(),
        }
    }
}

fn pipe_with_reader_thread() -> (pipe::Handle, JoinHandle<io::Result<Vec<u8>>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut read_file = read_pipe.to_file();
        let mut output = Vec::new();
        try!(read_file.read_to_end(&mut output));
        Ok(output)
    });
    (write_pipe, thread)
}

fn pipe_with_writer_thread(input: Vec<u8>) -> (pipe::Handle, JoinHandle<io::Result<()>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut write_file = write_pipe.to_file();
        try!(write_file.write_all(&input));
        Ok(())
    });
    (read_pipe, thread)
}

#[cfg(test)]
mod test {
    use super::{ArgvCommand, Pipe, Expression};
    use std::fs::File;
    use std::io::prelude::*;
    use std::path::PathBuf;

    fn mktemp() -> PathBuf {
        let output = ArgvCommand::new("mktemp").read().unwrap();
        let path: PathBuf = output.trim().into();
        println!("here's the path we're using: {:?}", path);
        path
    }

    #[test]
    fn test_run() {
        let result = ArgvCommand::new("true").arg("foo").arg("bar").run();
        assert!(result.unwrap().status.success());
    }

    #[test]
    fn test_read() {
        let output = ArgvCommand::new("echo").arg("hi").read().unwrap();
        assert_eq!(output, "hi");
    }

    #[test]
    fn test_stdout() {
        let path = mktemp();
        let result = ArgvCommand::new("echo").arg("hi").stdout(&path).run();
        assert!(result.unwrap().status.success());
        let mut contents = String::new();
        File::open(&path).unwrap().read_to_string(&mut contents).unwrap();
        assert_eq!(contents, "hi\n");
    }

    #[test]
    fn test_pipe() {
        let mut left = ArgvCommand::new("echo");
        left.arg("hi");
        let mut middle = ArgvCommand::new("sed");
        middle.arg("s/i/o/");
        let mut right = ArgvCommand::new("sed");
        right.arg("s/h/j/");
        let pipe = Pipe::new(&left, &Pipe::new(&middle, &right));
        let output = pipe.read().unwrap();
        assert_eq!(output, "jo");
    }

    #[test]
    fn test_input() {
        let output = ArgvCommand::new("cat").input(&"blarg".as_bytes()).read().unwrap();
        assert_eq!(output, "blarg");
    }
}
<|endoftext|>


<commit_before>//! Edge is a Web framework that is simple to use, with the most common things
//! you need out of the box, and flexible, supporting both synchronous and asynchronous
//! request handling styles; see below for examples.
//!
//! The crate exports the things that you often need from dependencies, such as headers (from `hyper`),
//! cookies (from `cookie`) and JSON serialization (from `serde_json`).
//!
//! Please note that this is an early version, and the API is likely to evolve.
//!
//! ## Overview
//!
//! In Edge you must define an *application structure* that contains the state of your application.
//! You instantiate a container around this application, and associate GET/POST/... requests
//! with given URLs to methods of your application. The container handles the routing and
//! delegates calls to the appropriate methods.
//!
//! Note that the state cannot be mutated, as is usual in Rust (and enforced by the underlying HTTP server
//! this crate uses, a.k.a. Hyper). Use appropriate concurrent data structures if you need
//! shared mutable variables: locks, mutexes, channels, etc.
//!
//! ## Why another Web framework in Rust?
//!
//! Because I wanted a simple Web framework with:
//!
//!   1. everything I needed out of the box, like cookies and forms and templating, without having to dig up third-party crates,
//!   1. the possibility to describe my application as a struct, so that callbacks could use a state (even if just for configuration).
//!
//! We focus on integration rather than modularity.
//! I hope you like this crate, if it misses something to fit your needs just open an issue or make a pull request!
//!
//! And please keep in mind that the framework is in a (very) early stage :-)
//!
//! ## Hello World
//!
//! The most basic application: no state, a single page that prints Hello, world!
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response};
//!
//! struct Hello;
//! impl Hello {
//!     fn hello(&self, _req: &mut Request, mut res: Response) {
//!         res.content_type("text/plain");
//!         res.send("Hello, world!")
//!     }
//! }
//!
//! fn main() {
//!     let mut edge = Edge::new("0.0.0.0:3000", Hello);
//!     edge.get("/", Hello::hello);
//!     edge.start().unwrap();
//! }
//! ```
//!
//! ## Asynchronous handling
//!
//! Under the hood, Edge uses the asynchronous version of Hyper. This means that to get the maximum
//! performance, you should avoid waiting in a handler, so that other requests
//! can be served as soon as possible. In that example, the handler waits in a separate thread before sending
//! the response.
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response};
//! use std::thread;
//! use std::time::Duration;
//!
//! struct AsyncHello;
//! impl AsyncHello {
//!     fn hello(&self, _req: &mut Request, mut res: Response) {
//!         thread::spawn(move || {
//!             println!("waiting 1 second");
//!             thread::sleep(Duration::from_secs(1));
//!
//!             res.content_type("text/plain");
//!             res.send("Hello, world!")
//!         });
//!
//!         // the handler returns immediately without waiting for the thread
//!     }
//! }
//!
//! fn main() {
//!     let mut edge = Edge::new("0.0.0.0:3000", AsyncHello);
//!     edge.get("/", AsyncHello::hello);
//!     edge.start().unwrap();
//! }
//! ```
//!
//! ## Templating
//!
//! Here our application has a version, still a single handler except this time
//! it accepts any page name, and renders a Handlebars template.  We're also
//! setting a custom Server header.
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response, Status};
//! use edge::header::Server;
//! use std::collections::BTreeMap;
//!
//! struct Templating {
//!     version: &'static str
//! }
//!
//! impl Templating {
//!     fn page_handler(&self, req: &mut Request, mut res: Response) {
//!         let mut data = BTreeMap::new();
//!         data.insert("title", req.param("page").unwrap());
//!         data.insert("version", self.version);
//!
//!         res.content_type("text/html").header(Server(format!("Edge version {}", self.version)));
//!         res.render("tmpl", data)
//!     }
//! }
//!
//! fn main() {
//!     let app = Templating { version: "0.1" };
//!     let mut edge = Edge::new("0.0.0.0:3000", app);
//!     edge.get("/:page", Templating::page_handler);
//!     edge.register_template("tmpl");
//!     edge.start().unwrap();
//! }
//! ```
//!
//! ## Using a shared mutable counter
//!
//! In this example, we use an atomic integer to track a counter. This shows a very basic
//! kind of shared state for a handler. In practice, it's best to avoid using blocking
//! mechanisms (locks, mutexes) in a handler directly. Prefer non-blocking calls,
//! like channels' try_recv, or move blocking code in a separate thread,
//! see the example for asynchronous handling above.
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response, Status};
//! use std::sync::atomic::{AtomicUsize, Ordering};
//!
//! struct Counting {
//!     counter: AtomicUsize
//! }
//!
//! impl Counting {
//!     fn new() -> Counting { Counting { counter: AtomicUsize::new(0) } }
//!
//!     fn home(&self, _req: &mut Request, mut res: Response) {
//!         let visits = self.counter.load(Ordering::Relaxed);
//!         self.counter.store(visits + 1, Ordering::Relaxed);
//!
//!         res.status(Status::Ok).content_type("text/plain");
//!         res.send(format!("Hello, world! {} visits", visits))
//!     }
//! }
//!
//! fn main() {
//!     let mut cter = Edge::new("0.0.0.0:3000", Counting::new());
//!     cter.get("/", Counting::home);
//!     cter.start().unwrap();
//! }
//! ```

extern crate crossbeam;
extern crate handlebars;
extern crate hyper;
extern crate num_cpus;
extern crate pulldown_cmark;
extern crate scoped_pool;
extern crate serde;
extern crate url;

#[macro_use]
extern crate log;
pub extern crate serde_json;

pub use hyper::header as header;
pub use header::CookiePair as Cookie;
pub use hyper::status::StatusCode as Status;

/// serde_json crate
pub use serde_json as json;

use handlebars::{Context, Handlebars, Helper, RenderContext, RenderError};

use hyper::net::HttpListener;
use hyper::server::Server;

use pulldown_cmark::Parser;
use pulldown_cmark::{Options, OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};
use pulldown_cmark::html;

use scoped_pool::Pool;

use url::Url;

use std::fs::read_dir;
use std::io::Result as IoResult;
use std::net::ToSocketAddrs;
use std::path::{Path, PathBuf};
use std::result;

mod buffer;
mod client;
mod handler;
mod router;
mod request;
mod response;

pub use client::Client;
pub use request::Request;
pub use response::{Response, Result, Action, stream};
pub use router::{Router};

/// Structure for an Edge application.
pub struct Edge {
    base_url: Url,
    routers: Vec<router::RouterAny>,
    handlebars: Handlebars
}

/// ok!() means Ok(Action::End).
/// ok!(expr) returns Ok(From::from(expr))
#[macro_export]
macro_rules! ok {
    () => (
        return Ok(Action::End);
    );
    ($exp:expr) => (
        return Ok(std::convert::From::from($exp));
    );
    ($e1:expr, $e2:expr) => (
        return Ok(std::convert::From::from(($e1, $e2)));
    )
}

impl Edge {

    /// Creates an Edge application using the given address and application.
    pub fn new(addr: &str) -> Edge {
        let mut handlebars = Handlebars::new();
        init_handlebars(&mut handlebars).unwrap();

        Edge {
            base_url: Url::parse(&("http://".to_string() + addr)).unwrap(),
            routers: Vec::new(),
            handlebars: handlebars
        }
    }

    /// Mounts the given router at the given path.
    ///
    /// Use "/" to mount the router at the root.
    pub fn mount<T>(&mut self, mount: &str, router: Router<T>) {
        let mut router = router::get_inner(router);
        router.set_prefix(mount);
        self.routers.push(router)
    }

    // Registers a template with the given name.
    pub fn register_template(&mut self, name: &str) {
        let mut path = PathBuf::new();
        path.push("views");
        path.push(name);
        path.set_extension("hbs");

        self.handlebars.register_template_file(name, &path).unwrap();
    }

    /// Runs the server in one thread per cpu.
    ///
    /// Creates one instance of `T` per request by calling `Default::default`.
    /// This method blocks the current thread.
    pub fn start(&mut self) -> IoResult<()> {
        assert!(!self.routers.is_empty(), "No router registered! Please mount at least one router");

        // get address and start listening
        let addr = self.base_url.to_socket_addrs().unwrap().next().unwrap();
        let listener = HttpListener::bind(&addr).unwrap();

        // 50% threads for the pool, 50% for the listeners
        let num_threads = ::std::cmp::max(num_cpus::get() / 2, 1);
        let pool = Pool::new(num_threads);
        pool.scoped(|pool_scope| {
            crossbeam::scope(|scope| {
                for i in 0..num_threads {
                    let listener = listener.try_clone().unwrap();
                    let base_url = &self.base_url;
                    let routers = &self.routers;
                    let handlebars = &self.handlebars;
                    scope.spawn(move || {
                        info!("thread {} listening on http://{}", i, addr);
                        Server::new(listener).handle(move |control| {
                            handler::EdgeHandler::new(pool_scope, &base_url, &routers, &handlebars, control)
                        }).unwrap();
                    });
                }
            });
        });

        Ok(())
    }
}

fn render_html(text: &str) -> String {
    let mut opts = Options::empty();
    opts.insert(OPTION_ENABLE_TABLES);
    opts.insert(OPTION_ENABLE_FOOTNOTES);

    let mut s = String::with_capacity(text.len() * 3 / 2);
    let p = Parser::new_ext(text, opts);
    html::push_html(&mut s, p);
    s
}

/// this code is based on code Copyright (c) 2015 Wayne Nilsen
/// see https://github.com/waynenilsen/handlebars-markdown-helper/blob/master/src/lib.rs#L31
///
/// because the handlebars-markdown-helper crate does not allow custom options for Markdown rendering yet
fn markdown_helper(_: &Context, h: &Helper, _ : &Handlebars, rc: &mut RenderContext) -> result::Result<(), RenderError> {
    let markdown_text_var = try!(h.param(0).ok_or_else(|| RenderError::new(
        "Param not found for helper \"markdown\"")
    ));
    let markdown = try!(markdown_text_var.value().as_string().ok_or_else(||
        RenderError::new(format!("Expected a string for parameter {:?}", markdown_text_var))
    ));
    let html = render_html(markdown);
    try!(rc.writer.write_all(html.as_bytes()));
    Ok(())
}

fn init_handlebars(handlebars: &mut Handlebars) -> IoResult<()> {
    // register markdown helper
    handlebars.register_helper("markdown", Box::new(::markdown_helper));

    // register partials folder (if it exists)
    let partials = Path::new("views/partials");
    if partials.exists() {
        for it in try!(read_dir("views/partials")) {
            let entry = try!(it);
            let path = entry.path();
            if path.extension().is_some() && path.extension().unwrap() == "hbs" {
                let name = path.file_stem().unwrap().to_str().unwrap();
                handlebars.register_template_file(name, path.as_path()).unwrap();
            }
        }
    }

    Ok(())
}
<commit_msg>fix ok! macro for use outside of edge<commit_after>//! Edge is a Web framework that is simple to use, with the most common things
//! you need out of the box, and flexible, supporting both synchronous and asynchronous
//! request handling styles; see below for examples.
//!
//! The crate exports the things that you often need from dependencies, such as headers (from `hyper`),
//! cookies (from `cookie`) and JSON serialization (from `serde_json`).
//!
//! Please note that this is an early version, and the API is likely to evolve.
//!
//! ## Overview
//!
//! In Edge you must define an *application structure* that contains the state of your application.
//! You instantiate a container around this application, and associate GET/POST/... requests
//! with given URLs to methods of your application. The container handles the routing and
//! delegates calls to the appropriate methods.
//!
//! Note that the state cannot be mutated, as is usual in Rust (and enforced by the underlying HTTP server
//! this crate uses, a.k.a. Hyper). Use appropriate concurrent data structures if you need
//! shared mutable variables: locks, mutexes, channels, etc.
//!
//! ## Why another Web framework in Rust?
//!
//! Because I wanted a simple Web framework with:
//!
//!   1. everything I needed out of the box, like cookies and forms and templating, without having to dig up third-party crates,
//!   1. the possibility to describe my application as a struct, so that callbacks could use a state (even if just for configuration).
//!
//! We focus on integration rather than modularity.
//! I hope you like this crate, if it misses something to fit your needs just open an issue or make a pull request!
//!
//! And please keep in mind that the framework is in a (very) early stage :-)
//!
//! ## Hello World
//!
//! The most basic application: no state, a single page that prints Hello, world!
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response};
//!
//! struct Hello;
//! impl Hello {
//!     fn hello(&self, _req: &mut Request, mut res: Response) {
//!         res.content_type("text/plain");
//!         res.send("Hello, world!")
//!     }
//! }
//!
//! fn main() {
//!     let mut edge = Edge::new("0.0.0.0:3000", Hello);
//!     edge.get("/", Hello::hello);
//!     edge.start().unwrap();
//! }
//! ```
//!
//! ## Asynchronous handling
//!
//! Under the hood, Edge uses the asynchronous version of Hyper. This means that to get the maximum
//! performance, you should avoid waiting in a handler, so that other requests
//! can be served as soon as possible. In that example, the handler waits in a separate thread before sending
//! the response.
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response};
//! use std::thread;
//! use std::time::Duration;
//!
//! struct AsyncHello;
//! impl AsyncHello {
//!     fn hello(&self, _req: &mut Request, mut res: Response) {
//!         thread::spawn(move || {
//!             println!("waiting 1 second");
//!             thread::sleep(Duration::from_secs(1));
//!
//!             res.content_type("text/plain");
//!             res.send("Hello, world!")
//!         });
//!
//!         // the handler returns immediately without waiting for the thread
//!     }
//! }
//!
//! fn main() {
//!     let mut edge = Edge::new("0.0.0.0:3000", AsyncHello);
//!     edge.get("/", AsyncHello::hello);
//!     edge.start().unwrap();
//! }
//! ```
//!
//! ## Templating
//!
//! Here our application has a version, still a single handler except this time
//! it accepts any page name, and renders a Handlebars template.  We're also
//! setting a custom Server header.
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response, Status};
//! use edge::header::Server;
//! use std::collections::BTreeMap;
//!
//! struct Templating {
//!     version: &'static str
//! }
//!
//! impl Templating {
//!     fn page_handler(&self, req: &mut Request, mut res: Response) {
//!         let mut data = BTreeMap::new();
//!         data.insert("title", req.param("page").unwrap());
//!         data.insert("version", self.version);
//!
//!         res.content_type("text/html").header(Server(format!("Edge version {}", self.version)));
//!         res.render("tmpl", data)
//!     }
//! }
//!
//! fn main() {
//!     let app = Templating { version: "0.1" };
//!     let mut edge = Edge::new("0.0.0.0:3000", app);
//!     edge.get("/:page", Templating::page_handler);
//!     edge.register_template("tmpl");
//!     edge.start().unwrap();
//! }
//! ```
//!
//! ## Using a shared mutable counter
//!
//! In this example, we use an atomic integer to track a counter. This shows a very basic
//! kind of shared state for a handler. In practice, it's best to avoid using blocking
//! mechanisms (locks, mutexes) in a handler directly. Prefer non-blocking calls,
//! like channels' try_recv, or move blocking code in a separate thread,
//! see the example for asynchronous handling above.
//!
//! ```no_run
//! extern crate edge;
//!
//! use edge::{Edge, Request, Response, Status};
//! use std::sync::atomic::{AtomicUsize, Ordering};
//!
//! struct Counting {
//!     counter: AtomicUsize
//! }
//!
//! impl Counting {
//!     fn new() -> Counting { Counting { counter: AtomicUsize::new(0) } }
//!
//!     fn home(&self, _req: &mut Request, mut res: Response) {
//!         let visits = self.counter.load(Ordering::Relaxed);
//!         self.counter.store(visits + 1, Ordering::Relaxed);
//!
//!         res.status(Status::Ok).content_type("text/plain");
//!         res.send(format!("Hello, world! {} visits", visits))
//!     }
//! }
//!
//! fn main() {
//!     let mut cter = Edge::new("0.0.0.0:3000", Counting::new());
//!     cter.get("/", Counting::home);
//!     cter.start().unwrap();
//! }
//! ```

extern crate crossbeam;
extern crate handlebars;
extern crate hyper;
extern crate num_cpus;
extern crate pulldown_cmark;
extern crate scoped_pool;
extern crate serde;
extern crate url;

#[macro_use]
extern crate log;
pub extern crate serde_json;

pub use hyper::header as header;
pub use header::CookiePair as Cookie;
pub use hyper::status::StatusCode as Status;

/// serde_json crate
pub use serde_json as json;

use handlebars::{Context, Handlebars, Helper, RenderContext, RenderError};

use hyper::net::HttpListener;
use hyper::server::Server;

use pulldown_cmark::Parser;
use pulldown_cmark::{Options, OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};
use pulldown_cmark::html;

use scoped_pool::Pool;

use url::Url;

use std::fs::read_dir;
use std::io::Result as IoResult;
use std::net::ToSocketAddrs;
use std::path::{Path, PathBuf};
use std::result;

mod buffer;
mod client;
mod handler;
mod router;
mod request;
mod response;

pub use client::Client;
pub use request::Request;
pub use response::{Response, Result, Action, stream};
pub use router::{Router};

/// Structure for an Edge application.
pub struct Edge {
    base_url: Url,
    routers: Vec<router::RouterAny>,
    handlebars: Handlebars
}

/// ok!() means Ok(Action::End).
/// ok!(expr) returns Ok(From::from(expr))
#[macro_export]
macro_rules! ok {
    () => (
        return Ok($crate::Action::End);
    );
    ($exp:expr) => (
        return Ok(::std::convert::From::from($exp));
    );
    ($e1:expr, $e2:expr) => (
        return Ok(::std::convert::From::from(($e1, $e2)));
    )
}

impl Edge {

    /// Creates an Edge application using the given address and application.
    pub fn new(addr: &str) -> Edge {
        let mut handlebars = Handlebars::new();
        init_handlebars(&mut handlebars).unwrap();

        Edge {
            base_url: Url::parse(&("http://".to_string() + addr)).unwrap(),
            routers: Vec::new(),
            handlebars: handlebars
        }
    }

    /// Mounts the given router at the given path.
    ///
    /// Use "/" to mount the router at the root.
    pub fn mount<T>(&mut self, mount: &str, router: Router<T>) {
        let mut router = router::get_inner(router);
        router.set_prefix(mount);
        self.routers.push(router)
    }

    // Registers a template with the given name.
    pub fn register_template(&mut self, name: &str) {
        let mut path = PathBuf::new();
        path.push("views");
        path.push(name);
        path.set_extension("hbs");

        self.handlebars.register_template_file(name, &path).unwrap();
    }

    /// Runs the server in one thread per cpu.
    ///
    /// Creates one instance of `T` per request by calling `Default::default`.
    /// This method blocks the current thread.
    pub fn start(&mut self) -> IoResult<()> {
        assert!(!self.routers.is_empty(), "No router registered! Please mount at least one router");

        // get address and start listening
        let addr = self.base_url.to_socket_addrs().unwrap().next().unwrap();
        let listener = HttpListener::bind(&addr).unwrap();

        // 50% threads for the pool, 50% for the listeners
        let num_threads = ::std::cmp::max(num_cpus::get() / 2, 1);
        let pool = Pool::new(num_threads);
        pool.scoped(|pool_scope| {
            crossbeam::scope(|scope| {
                for i in 0..num_threads {
                    let listener = listener.try_clone().unwrap();
                    let base_url = &self.base_url;
                    let routers = &self.routers;
                    let handlebars = &self.handlebars;
                    scope.spawn(move || {
                        info!("thread {} listening on http://{}", i, addr);
                        Server::new(listener).handle(move |control| {
                            handler::EdgeHandler::new(pool_scope, &base_url, &routers, &handlebars, control)
                        }).unwrap();
                    });
                }
            });
        });

        Ok(())
    }
}

fn render_html(text: &str) -> String {
    let mut opts = Options::empty();
    opts.insert(OPTION_ENABLE_TABLES);
    opts.insert(OPTION_ENABLE_FOOTNOTES);

    let mut s = String::with_capacity(text.len() * 3 / 2);
    let p = Parser::new_ext(text, opts);
    html::push_html(&mut s, p);
    s
}

/// this code is based on code Copyright (c) 2015 Wayne Nilsen
/// see https://github.com/waynenilsen/handlebars-markdown-helper/blob/master/src/lib.rs#L31
///
/// because the handlebars-markdown-helper crate does not allow custom options for Markdown rendering yet
fn markdown_helper(_: &Context, h: &Helper, _ : &Handlebars, rc: &mut RenderContext) -> result::Result<(), RenderError> {
    let markdown_text_var = try!(h.param(0).ok_or_else(|| RenderError::new(
        "Param not found for helper \"markdown\"")
    ));
    let markdown = try!(markdown_text_var.value().as_string().ok_or_else(||
        RenderError::new(format!("Expected a string for parameter {:?}", markdown_text_var))
    ));
    let html = render_html(markdown);
    try!(rc.writer.write_all(html.as_bytes()));
    Ok(())
}

fn init_handlebars(handlebars: &mut Handlebars) -> IoResult<()> {
    // register markdown helper
    handlebars.register_helper("markdown", Box::new(::markdown_helper));

    // register partials folder (if it exists)
    let partials = Path::new("views/partials");
    if partials.exists() {
        for it in try!(read_dir("views/partials")) {
            let entry = try!(it);
            let path = entry.path();
            if path.extension().is_some() && path.extension().unwrap() == "hbs" {
                let name = path.file_stem().unwrap().to_str().unwrap();
                handlebars.register_template_file(name, path.as_path()).unwrap();
            }
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;
use std::ffi::CStr;
use std::os::raw::c_char;

use nom::{le_u64,le_u32,le_i32};
use nom::IResult;

pub use constants::*;

mod constants;

// These are all integer_t, aka int
#[allow(non_camel_case_types)]
pub type cpu_type_t = i32;
#[allow(non_camel_case_types)]
pub type cpu_subtype_t = u32;
#[allow(non_camel_case_types)]
pub type vm_prot_t = i32;

fn to_string(buf: &[u8]) -> String {
    let slice = unsafe { CStr::from_ptr(buf.as_ptr() as *const c_char) };
    std::str::from_utf8(slice.to_bytes()).unwrap().to_string()
}

#[derive(Debug)]
pub struct MachHeader<'a> {
    pub header: Header,
    pub segments: Vec<SegmentCommand>,
    pub commands: Vec<LoadCommand<'a>>,
}

#[derive(Debug)]
pub struct Header {
    pub magic: u32,
    pub cputype: cpu_type_t,
    pub cpusubtype: cpu_subtype_t,
    pub filetype: u32,
    pub ncmds: u32,
    pub sizeofcmds: u32,
    pub flags: u32,
    reserved: u32,
}

pub const LC_SEGMENT_64: u32 = 25;

impl<'a> MachHeader<'a> {
    pub fn parse(bytes: &'a [u8]) -> Option<MachHeader> {
        if let IResult::Done(_rest, header) = mach_header(bytes) {
            let mut rest = _rest;
            let mut commands = vec![];
            let mut segments = vec![];
            for _ in 0.. header.ncmds {
                // Thanks to nom being zero copy, we can actually parse the same memory twice.
                // We have one attempt to see what type it is, then we have another go to get that
                // object.
                if let IResult::Done(_, cmd) = load_command(rest) {
                    match cmd.cmd {
                        c if c == LcType::LC_SEGMENT_64 as u32 => {
                            if let IResult::Done(_rest, mut segment) = segment_command(rest) {
                                let sections_slice = &_rest[.. (segment.cmdsize - 72) as usize];
                                if let IResult::Done(leftover, sections) = sections(sections_slice) {
                                    assert_eq!(sections.len(), segment.nsects as usize);
                                    assert_eq!(leftover.len(), 0);
                                    segment.sections.extend(sections)
                                } else {
                                    return None
                                }
                                rest = &_rest[(segment.cmdsize - 72) as usize..];
                                segments.push(segment);
                            } else {
                                return None
                            }
                        },
                        _ => {
                            commands.push(cmd)
                        }
                    }
                }
            }

            Some(MachHeader {
                    header: header,
                    commands: commands,
                    segments: segments,
            })
        } else {
            return None
        }
    }
}

#[derive(Debug)]
pub struct SegmentCommand {
    pub cmd: u32,
    pub cmdsize: u32,
    pub segname: String,
    pub vmaddr: u64,
    pub vmsize: u64,
    pub fileoff: u64,
    pub filesize: u64,
    pub maxprot: vm_prot_t,
    pub initprot: vm_prot_t,
    pub nsects: u32,
    pub flags: u32,
    pub sections: Vec<Section>,
}

#[derive(Debug)]
pub struct LoadCommand<'a> {
    pub cmd: u32,
    pub cmdsize: u32,
    pub data: &'a [u8],
}

#[derive(Debug)]
pub struct Section {
	pub sectname: String, /* name of this section */
    pub segname: String, /* segment this section goes in */
    pub addr: u64, /* memory address of this section */
    pub size: u64, /* size in bytes of this section */
    pub offset: u32, /* file offset of this section */
    pub align: u32, /* section alignment (power of 2) */
    pub reloff: u32, /* file offset of relocation entries */
    pub nreloc: u32, /* number of relocation entries */
    pub flags: u32, /* flags (section type and attributes)*/
    reserved1: u32, /* reserved (for offset or index) */
    reserved2: u32, /* reserved (for count or sizeof) */
    reserved3: u32, /* reserved */
}

named!(sections<&[u8], Vec<Section> >,
       many0!(section));
named!(section<&[u8], Section>,
       chain!(
           sectname: take!(16) ~
           segname: take!(16) ~
           addr: le_u64 ~
           size: le_u64 ~
           offset: le_u32 ~
           align: le_u32 ~
           reloff: le_u32 ~
           nreloc: le_u32 ~
           flags: le_u32 ~
           reserved1: le_u32 ~
           reserved2: le_u32 ~
           reserved3: le_u32 ,

           || {
               // assert_eq!(size, 80);
               Section {
                   sectname: to_string(sectname),
                   segname: to_string(segname),
                   addr: addr,
                   size: size,
                   offset: offset,
                   align: align,
                   reloff: reloff,
                   nreloc: nreloc,
                   flags: flags,
                   reserved1: reserved1,
                   reserved2: reserved2,
                   reserved3: reserved3,
               }
           }
           )
       );

named!(load_command<&[u8], LoadCommand>,
       chain!(
           cmd: le_u32 ~
           cmdsize: le_u32 ~
           data: take!(cmdsize - 8),

           || {
               LoadCommand {
                   cmd: cmd,
                   cmdsize: cmdsize,
                   data: data,
               }
           }
           )
       );

named!(mach_header<&[u8], Header>,
       chain!(
           magic: le_u32 ~
           cputype: le_i32 ~
           cpusubtype: le_u32 ~
           filetype: le_u32 ~
           ncmds: le_u32 ~
           sizeofcmds: le_u32 ~
           flags: le_u32 ~
           reserved: le_u32,

           || {
               assert_eq!(MH_MAGIC_64, magic);
               Header {
                   magic: magic,
                   cputype: cputype,
                   // This value needs to be masked to match otool -h
                   cpusubtype: cpusubtype,
                   filetype: filetype,
                   ncmds: ncmds,
                   sizeofcmds: sizeofcmds,
                   flags: flags,
                   reserved: reserved,
               }
           }
           )
       );

named!(segment_command<&[u8], SegmentCommand>,
       chain!(
           cmd: le_u32 ~
           cmdsize: le_u32 ~
           segname: take!(16) ~
           vmaddr: le_u64 ~
           vmsize: le_u64 ~
           fileoff: le_u64 ~
           filesize: le_u64 ~
           maxprot: le_i32 ~
           initprot: le_i32 ~
           nsects: le_u32 ~
           flags: le_u32 ,

           || {
               SegmentCommand {
                   cmd: cmd,
                   cmdsize: cmdsize,
                   segname: to_string(segname),
                   vmaddr: vmaddr,
                   vmsize: vmsize,
                   fileoff: fileoff,
                   filesize: filesize,
                   maxprot: maxprot,
                   initprot: initprot,
                   nsects: nsects,
                   flags: flags,
                   sections: vec![],
               }
           }
        )
    );
<commit_msg>Deal gracefully with LC's that aren't LC_SEGMENTs<commit_after>#[macro_use]
extern crate nom;
use std::ffi::CStr;
use std::os::raw::c_char;

use nom::{le_u64,le_u32,le_i32};
use nom::IResult;

pub use constants::*;

mod constants;

// These are all integer_t, aka int
#[allow(non_camel_case_types)]
pub type cpu_type_t = i32;
#[allow(non_camel_case_types)]
pub type cpu_subtype_t = u32;
#[allow(non_camel_case_types)]
pub type vm_prot_t = i32;

fn to_string(buf: &[u8]) -> String {
    let slice = unsafe { CStr::from_ptr(buf.as_ptr() as *const c_char) };
    std::str::from_utf8(slice.to_bytes()).unwrap().to_string()
}

#[derive(Debug)]
pub struct MachHeader<'a> {
    pub header: Header,
    pub segments: Vec<SegmentCommand>,
    pub commands: Vec<LoadCommand<'a>>,
}

#[derive(Debug)]
pub struct Header {
    pub magic: u32,
    pub cputype: cpu_type_t,
    pub cpusubtype: cpu_subtype_t,
    pub filetype: u32,
    pub ncmds: u32,
    pub sizeofcmds: u32,
    pub flags: u32,
    reserved: u32,
}

pub const LC_SEGMENT_64: u32 = 25;

impl<'a> MachHeader<'a> {
    pub fn parse(bytes: &'a [u8]) -> Option<MachHeader> {
        if let IResult::Done(_rest, header) = mach_header(bytes) {
            let mut rest = _rest;
            let mut commands = vec![];
            let mut segments = vec![];
            for _ in 0.. header.ncmds {
                // Thanks to nom being zero copy, we can actually parse the same memory twice.
                // We have one attempt to see what type it is, then we have another go to get that
                // object.
                if let IResult::Done(_, cmd) = load_command(rest) {
                    let len = cmd.cmdsize;
                    match cmd.cmd {
                        c if c == LcType::LC_SEGMENT_64 as u32 => {
                            if let IResult::Done(_rest, mut segment) = segment_command(rest) {
                                let sections_slice = &_rest[.. (segment.cmdsize - 72) as usize];
                                if let IResult::Done(leftover, sections) = sections(sections_slice) {
                                    assert_eq!(sections.len(), segment.nsects as usize);
                                    assert_eq!(leftover.len(), 0);
                                    segment.sections.extend(sections)
                                } else {
                                    return None
                                }
                                segments.push(segment);
                            } else {
                                return None
                            }
                        },
                        _ => {
                            commands.push(cmd)
                        }
                    }
                    rest = &rest[len as usize..];
                }
            }

            Some(MachHeader {
                    header: header,
                    commands: commands,
                    segments: segments,
            })
        } else {
            return None
        }
    }
}

#[derive(Debug)]
pub struct SegmentCommand {
    pub cmd: u32,
    pub cmdsize: u32,
    pub segname: String,
    pub vmaddr: u64,
    pub vmsize: u64,
    pub fileoff: u64,
    pub filesize: u64,
    pub maxprot: vm_prot_t,
    pub initprot: vm_prot_t,
    pub nsects: u32,
    pub flags: u32,
    pub sections: Vec<Section>,
}

#[derive(Debug)]
pub struct LoadCommand<'a> {
    pub cmd: u32,
    pub cmdsize: u32,
    pub data: &'a [u8],
}

#[derive(Debug)]
pub struct Section {
	pub sectname: String, /* name of this section */
    pub segname: String, /* segment this section goes in */
    pub addr: u64, /* memory address of this section */
    pub size: u64, /* size in bytes of this section */
    pub offset: u32, /* file offset of this section */
    pub align: u32, /* section alignment (power of 2) */
    pub reloff: u32, /* file offset of relocation entries */
    pub nreloc: u32, /* number of relocation entries */
    pub flags: u32, /* flags (section type and attributes)*/
    reserved1: u32, /* reserved (for offset or index) */
    reserved2: u32, /* reserved (for count or sizeof) */
    reserved3: u32, /* reserved */
}

named!(sections<&[u8], Vec<Section> >,
       many0!(section));
named!(section<&[u8], Section>,
       chain!(
           sectname: take!(16) ~
           segname: take!(16) ~
           addr: le_u64 ~
           size: le_u64 ~
           offset: le_u32 ~
           align: le_u32 ~
           reloff: le_u32 ~
           nreloc: le_u32 ~
           flags: le_u32 ~
           reserved1: le_u32 ~
           reserved2: le_u32 ~
           reserved3: le_u32 ,

           || {
               // assert_eq!(size, 80);
               Section {
                   sectname: to_string(sectname),
                   segname: to_string(segname),
                   addr: addr,
                   size: size,
                   offset: offset,
                   align: align,
                   reloff: reloff,
                   nreloc: nreloc,
                   flags: flags,
                   reserved1: reserved1,
                   reserved2: reserved2,
                   reserved3: reserved3,
               }
           }
           )
       );

named!(load_command<&[u8], LoadCommand>,
       chain!(
           cmd: le_u32 ~
           cmdsize: le_u32 ~
           data: take!(cmdsize - 8),

           || {
               LoadCommand {
                   cmd: cmd,
                   cmdsize: cmdsize,
                   data: data,
               }
           }
           )
       );

named!(mach_header<&[u8], Header>,
       chain!(
           magic: le_u32 ~
           cputype: le_i32 ~
           cpusubtype: le_u32 ~
           filetype: le_u32 ~
           ncmds: le_u32 ~
           sizeofcmds: le_u32 ~
           flags: le_u32 ~
           reserved: le_u32,

           || {
               assert_eq!(MH_MAGIC_64, magic);
               Header {
                   magic: magic,
                   cputype: cputype,
                   // This value needs to be masked to match otool -h
                   cpusubtype: cpusubtype,
                   filetype: filetype,
                   ncmds: ncmds,
                   sizeofcmds: sizeofcmds,
                   flags: flags,
                   reserved: reserved,
               }
           }
           )
       );

named!(segment_command<&[u8], SegmentCommand>,
       chain!(
           cmd: le_u32 ~
           cmdsize: le_u32 ~
           segname: take!(16) ~
           vmaddr: le_u64 ~
           vmsize: le_u64 ~
           fileoff: le_u64 ~
           filesize: le_u64 ~
           maxprot: le_i32 ~
           initprot: le_i32 ~
           nsects: le_u32 ~
           flags: le_u32 ,

           || {
               SegmentCommand {
                   cmd: cmd,
                   cmdsize: cmdsize,
                   segname: to_string(segname),
                   vmaddr: vmaddr,
                   vmsize: vmsize,
                   fileoff: fileoff,
                   filesize: filesize,
                   maxprot: maxprot,
                   initprot: initprot,
                   nsects: nsects,
                   flags: flags,
                   sections: vec![],
               }
           }
        )
    );
<|endoftext|>


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

#![crate_name = "string_cache"]
#![crate_type = "rlib"]

#![cfg_attr(test, deny(warnings))]
#![cfg_attr(all(test, feature = "unstable"), feature(test))]

#[cfg(all(test, feature = "unstable"))] extern crate test;
#[cfg(feature = "log-events")] extern crate rustc_serialize;
#[cfg(feature = "heapsize")] #[macro_use] extern crate heapsize;
#[cfg(test)] extern crate rand;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate debug_unreachable;
extern crate serde;
extern crate phf_shared;

pub use atom::Atom;
pub use namespace::{Namespace, QualName};

#[macro_export]
macro_rules! qualname {
    ("", $local:tt) => {
        $crate::namespace::QualName {
            ns: ns!(),
            local: atom!($local),
        }
    };
    ($ns:tt, $local:tt) => {
        $crate::namespace::QualName {
            ns: ns!($ns),
            local: atom!($local),
        }
    }
}

#[macro_export]
macro_rules! ns {
    () => { $crate::Namespace(atom!("")) };
    (html) => { $crate::Namespace(atom!("http://www.w3.org/1999/xhtml")) };
    (xml) => { $crate::Namespace(atom!("http://www.w3.org/XML/1998/namespace")) };
    (xmlns) => { $crate::Namespace(atom!("http://www.w3.org/2000/xmlns/")) };
    (xlink) => { $crate::Namespace(atom!("http://www.w3.org/1999/xlink")) };
    (svg) => { $crate::Namespace(atom!("http://www.w3.org/2000/svg")) };
    (mathml) => { $crate::Namespace(atom!("http://www.w3.org/1998/Math/MathML")) };
}

include!(concat!(env!("OUT_DIR"), "/atom_macro.rs"));

#[cfg(feature = "log-events")]
#[macro_use]
pub mod event;

pub mod atom;
pub mod namespace;
pub mod shared;

// A private module so that macro-expanded idents like
// `::string_cache::atom::Atom` will also work in this crate.
//
// `libstd` uses the same trick.
#[doc(hidden)]
mod string_cache {
    pub use atom;
    pub use namespace;
}
<commit_msg>Remove macro hack rendered unneeded by `$crate`.<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![crate_name = "string_cache"]
#![crate_type = "rlib"]

#![cfg_attr(test, deny(warnings))]
#![cfg_attr(all(test, feature = "unstable"), feature(test))]

#[cfg(all(test, feature = "unstable"))] extern crate test;
#[cfg(feature = "log-events")] extern crate rustc_serialize;
#[cfg(feature = "heapsize")] #[macro_use] extern crate heapsize;
#[cfg(test)] extern crate rand;
#[macro_use] extern crate lazy_static;
#[macro_use] extern crate debug_unreachable;
extern crate serde;
extern crate phf_shared;

pub use atom::Atom;
pub use namespace::{Namespace, QualName};

#[macro_export]
macro_rules! qualname {
    ("", $local:tt) => {
        $crate::namespace::QualName {
            ns: ns!(),
            local: atom!($local),
        }
    };
    ($ns:tt, $local:tt) => {
        $crate::namespace::QualName {
            ns: ns!($ns),
            local: atom!($local),
        }
    }
}

#[macro_export]
macro_rules! ns {
    () => { $crate::Namespace(atom!("")) };
    (html) => { $crate::Namespace(atom!("http://www.w3.org/1999/xhtml")) };
    (xml) => { $crate::Namespace(atom!("http://www.w3.org/XML/1998/namespace")) };
    (xmlns) => { $crate::Namespace(atom!("http://www.w3.org/2000/xmlns/")) };
    (xlink) => { $crate::Namespace(atom!("http://www.w3.org/1999/xlink")) };
    (svg) => { $crate::Namespace(atom!("http://www.w3.org/2000/svg")) };
    (mathml) => { $crate::Namespace(atom!("http://www.w3.org/1998/Math/MathML")) };
}

include!(concat!(env!("OUT_DIR"), "/atom_macro.rs"));

#[cfg(feature = "log-events")]
#[macro_use]
pub mod event;

pub mod atom;
pub mod namespace;
pub mod shared;
<|endoftext|>


<commit_before>// Copyright ⓒ 2015-2016 Kevin B. Knapp and [`clap-rs` contributors](https://github.com/clap-rs/clap/graphs/contributors).
// Licensed under the MIT license
// (see LICENSE or <http://opensource.org/licenses/MIT>) All files in the project carrying such
// notice may not be copied, modified, or distributed except according to those terms.

//! > **Command Line Argument Parser for Rust**
//!
//! Quick Links:
//! - Derive [tutorial][_derive::_tutorial] and [reference][_derive]
//! - Builder [tutorial][_tutorial] and [reference](index.html)
//! - [Cookbook][_cookbook]
//! - [FAQ][_faq]
//! - [Discussions](https://github.com/clap-rs/clap/discussions)
//!
//! ## Aspirations
//!
//! - Out of the box, users get a polished CLI experience
//!   - Including common argument behavior, help generation, suggested fixes for users, colored output, [shell completions](https://github.com/clap-rs/clap/tree/master/clap_complete), etc
//! - Flexible enough to port your existing CLI interface
//!   - However, we won't necessarily streamline support for each use case
//! - Reasonable parse performance
//! - Resilient maintainership, including
//!   - Willing to break compatibility rather than batching up breaking changes in large releases
//!   - Leverage feature flags to keep to one active branch
//!   - Being under [WG-CLI](https://github.com/rust-cli/team/) to increase the bus factor
//! - We follow semver and will wait about 6-9 months between major breaking changes
//! - We will support the last two minor Rust releases (MSRV, currently 1.56.1)
//!
//! While these aspirations can be at odds with fast build times and low binary
//! size, we will still strive to keep these reasonable for the flexibility you
//! get.  Check out the
//! [argparse-benchmarks](https://github.com/rust-cli/argparse-benchmarks-rs) for
//! CLI parsers optimized for other use cases.
//!
//! ## Example
//!
//! Run
//! ```console
//! $ cargo add clap --features derive
//! ```
//! *(See also [feature flag reference][_features])*
//!
//! Then in `main.rs`:
#![cfg_attr(not(feature = "derive"), doc = " ```ignore")]
#![cfg_attr(feature = "derive", doc = " ```no_run")]
#![doc = include_str!("../examples/demo.rs")]
//! ```
//!
//! Then try it out:
#![doc = include_str!("../examples/demo.md")]
//!
//! See also the derive [tutorial][_derive::_tutorial] and [reference][_derive]
//!
//! ### Related Projects
//!
//! Augment clap:
//! - [wild](https://crates.io/crates/wild) for supporting wildcards (`*`) on Windows like you do Linux
//! - [argfile](https://crates.io/crates/argfile) for loading additional arguments from a file (aka response files)
//! - [shadow-rs](https://crates.io/crates/shadow-rs) for generating `Command::long_version`
//! - [clap_mangen](https://crates.io/crates/clap_mangen) for generating man page source (roff)
//! - [clap_complete](https://crates.io/crates/clap_complete) for shell completion support
//!
//! CLI Helpers
//! - [clap-verbosity-flag](https://crates.io/crates/clap-verbosity-flag)
//! - [clap-cargo](https://crates.io/crates/clap-cargo)
//! - [concolor-clap](https://crates.io/crates/concolor-clap)
//!
//! Testing
//! - [`trycmd`](https://crates.io/crates/trycmd):  Bulk snapshot testing
//! - [`snapbox`](https://crates.io/crates/snapbox):  Specialized snapshot testing
//! - [`assert_cmd`](https://crates.io/crates/assert_cmd) and [`assert_fs`](https://crates.io/crates/assert_fs): Customized testing
//!
//! Documentation:
//! - [Command-line Apps for Rust](https://rust-cli.github.io/book/index.html) book
//!

#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")]
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    unused_allocation,
    trivial_numeric_casts,
    clippy::single_char_pattern
)]
#![forbid(unsafe_code)]
// HACK https://github.com/rust-lang/rust-clippy/issues/7290
#![allow(clippy::single_component_path_imports)]
#![allow(clippy::branches_sharing_code)]
// Doesn't allow for debug statements, etc to be unique
#![allow(clippy::if_same_then_else)]

#[cfg(not(feature = "std"))]
compile_error!("`std` feature is currently required to build `clap`");

pub use crate::builder::ArgAction;
pub use crate::builder::Command;
pub use crate::builder::{Arg, ArgGroup};
pub use crate::error::Error;
pub use crate::parser::ArgMatches;
#[cfg(feature = "color")]
pub use crate::util::color::ColorChoice;
#[cfg(not(feature = "color"))]
#[allow(unused_imports)]
pub(crate) use crate::util::color::ColorChoice;

pub use crate::derive::{Args, CommandFactory, FromArgMatches, Parser, Subcommand, ValueEnum};

#[allow(deprecated)]
pub use crate::builder::App;
pub use crate::builder::{AppFlags, AppSettings, ArgFlags, ArgSettings, PossibleValue, ValueHint};
pub use crate::error::{ErrorKind, Result};
#[allow(deprecated)]
pub use crate::parser::{Indices, OsValues, ValueSource, Values};

#[cfg(feature = "yaml")]
#[doc(hidden)]
#[cfg_attr(
    feature = "deprecated",
    deprecated(
        since = "3.0.0",
        note = "Deprecated in Issue #3087, maybe clap::Parser would fit your use case?"
    )
)]
#[doc(hidden)]
pub use yaml_rust::YamlLoader;

#[cfg(feature = "derive")]
#[doc(hidden)]
pub use clap_derive::{self, *};

/// Deprecated, replaced with [`CommandFactory`]
#[cfg_attr(
    feature = "deprecated",
    deprecated(since = "3.0.0", note = "Replaced with `CommandFactory`")
)]
pub use CommandFactory as IntoApp;
/// Deprecated, replaced with [`Parser`]
#[cfg_attr(
    feature = "deprecated",
    deprecated(since = "3.0.0", note = "Replaced with `Parser`")
)]
#[doc(hidden)]
pub use Parser as StructOpt;
/// Deprecated, replaced with [`ValueEnum`]
#[cfg_attr(
    feature = "deprecated",
    deprecated(since = "3.2.0", note = "Replaced with `ValueEnum`")
)]
pub use ValueEnum as ArgEnum;

#[cfg(feature = "unstable-doc")]
pub mod _cookbook;
#[cfg(feature = "unstable-doc")]
pub mod _derive;
#[cfg(feature = "unstable-doc")]
pub mod _faq;
#[cfg(feature = "unstable-doc")]
pub mod _features;
#[cfg(feature = "unstable-doc")]
pub mod _tutorial;

#[doc(hidden)]
pub mod __macro_refs {
    #[cfg(any(feature = "derive", feature = "cargo"))]
    #[doc(hidden)]
    pub use once_cell;
}

#[macro_use]
#[allow(missing_docs)]
mod macros;

mod derive;

#[cfg(feature = "regex")]
pub use crate::builder::RegexRef;

pub mod builder;
pub mod error;
pub mod parser;

mod mkeymap;
mod output;
mod util;

const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
                                  report at https://github.com/clap-rs/clap/issues";
const INVALID_UTF8: &str = "unexpected invalid UTF-8 code point";

/// Deprecated, replaced with [`Command::new`], unless you were looking for [Subcommand]
#[cfg_attr(
    feature = "deprecated",
    deprecated(
        since = "3.0.0",
        note = "Replaced with `Command::new` unless you intended the `Subcommand` trait"
    )
)]
#[doc(hidden)]
#[derive(Debug, Copy, Clone)]
pub struct SubCommand {}

#[allow(deprecated)]
impl SubCommand {
    /// Deprecated, replaced with [`Command::new`].
    /// Did you mean Subcommand (lower-case c)?
    #[cfg_attr(
        feature = "deprecated",
        deprecated(since = "3.0.0", note = "Replaced with `Command::new`")
    )]
    #[doc(hidden)]
    pub fn with_name<'help>(name: &str) -> App<'help> {
        Command::new(name)
    }

    /// Deprecated in [Issue #3087](https://github.com/clap-rs/clap/issues/3087), maybe [`clap::Parser`][crate::Parser] would fit your use case?
    #[cfg(feature = "yaml")]
    #[cfg_attr(
        feature = "deprecated",
        deprecated(
            since = "3.0.0",
            note = "Deprecated in Issue #3087, maybe clap::Parser would fit your use case?"
        )
    )]
    #[doc(hidden)]
    pub fn from_yaml(yaml: &yaml_rust::Yaml) -> App {
        #![allow(deprecated)]
        Command::from_yaml(yaml)
    }
}
<commit_msg>docs: Small tweak to lib docs<commit_after>// Copyright ⓒ 2015-2016 Kevin B. Knapp and [`clap-rs` contributors](https://github.com/clap-rs/clap/graphs/contributors).
// Licensed under the MIT license
// (see LICENSE or <http://opensource.org/licenses/MIT>) All files in the project carrying such
// notice may not be copied, modified, or distributed except according to those terms.

//! > **Command Line Argument Parser for Rust**
//!
//! Quick Links:
//! - Derive [tutorial][_derive::_tutorial] and [reference][_derive]
//! - Builder [tutorial][_tutorial] and [reference](index.html)
//! - [Cookbook][_cookbook]
//! - [FAQ][_faq]
//! - [Discussions](https://github.com/clap-rs/clap/discussions)
//!
//! ## Aspirations
//!
//! - Out of the box, users get a polished CLI experience
//!   - Including common argument behavior, help generation, suggested fixes for users, colored output, [shell completions](https://github.com/clap-rs/clap/tree/master/clap_complete), etc
//! - Flexible enough to port your existing CLI interface
//!   - However, we won't necessarily streamline support for each use case
//! - Reasonable parse performance
//! - Resilient maintainership, including
//!   - Willing to break compatibility rather than batching up breaking changes in large releases
//!   - Leverage feature flags to keep to one active branch
//!   - Being under [WG-CLI](https://github.com/rust-cli/team/) to increase the bus factor
//! - We follow semver and will wait about 6-9 months between major breaking changes
//! - We will support the last two minor Rust releases (MSRV, currently 1.56.1)
//!
//! While these aspirations can be at odds with fast build times and low binary
//! size, we will still strive to keep these reasonable for the flexibility you
//! get.  Check out the
//! [argparse-benchmarks](https://github.com/rust-cli/argparse-benchmarks-rs) for
//! CLI parsers optimized for other use cases.
//!
//! ## Example
//!
//! Run
//! ```console
//! $ cargo add clap --features derive
//! ```
//! *(See also [feature flag reference][_features])*
//!
//! Then define your CLI in `main.rs`:
#![cfg_attr(not(feature = "derive"), doc = " ```ignore")]
#![cfg_attr(feature = "derive", doc = " ```no_run")]
#![doc = include_str!("../examples/demo.rs")]
//! ```
//!
//! And try it out:
#![doc = include_str!("../examples/demo.md")]
//!
//! See also the derive [tutorial][_derive::_tutorial] and [reference][_derive]
//!
//! ### Related Projects
//!
//! Augment clap:
//! - [wild](https://crates.io/crates/wild) for supporting wildcards (`*`) on Windows like you do Linux
//! - [argfile](https://crates.io/crates/argfile) for loading additional arguments from a file (aka response files)
//! - [shadow-rs](https://crates.io/crates/shadow-rs) for generating `Command::long_version`
//! - [clap_mangen](https://crates.io/crates/clap_mangen) for generating man page source (roff)
//! - [clap_complete](https://crates.io/crates/clap_complete) for shell completion support
//!
//! CLI Helpers
//! - [clap-verbosity-flag](https://crates.io/crates/clap-verbosity-flag)
//! - [clap-cargo](https://crates.io/crates/clap-cargo)
//! - [concolor-clap](https://crates.io/crates/concolor-clap)
//!
//! Testing
//! - [`trycmd`](https://crates.io/crates/trycmd):  Bulk snapshot testing
//! - [`snapbox`](https://crates.io/crates/snapbox):  Specialized snapshot testing
//! - [`assert_cmd`](https://crates.io/crates/assert_cmd) and [`assert_fs`](https://crates.io/crates/assert_fs): Customized testing
//!
//! Documentation:
//! - [Command-line Apps for Rust](https://rust-cli.github.io/book/index.html) book
//!

#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")]
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    unused_allocation,
    trivial_numeric_casts,
    clippy::single_char_pattern
)]
#![forbid(unsafe_code)]
// HACK https://github.com/rust-lang/rust-clippy/issues/7290
#![allow(clippy::single_component_path_imports)]
#![allow(clippy::branches_sharing_code)]
// Doesn't allow for debug statements, etc to be unique
#![allow(clippy::if_same_then_else)]

#[cfg(not(feature = "std"))]
compile_error!("`std` feature is currently required to build `clap`");

pub use crate::builder::ArgAction;
pub use crate::builder::Command;
pub use crate::builder::{Arg, ArgGroup};
pub use crate::error::Error;
pub use crate::parser::ArgMatches;
#[cfg(feature = "color")]
pub use crate::util::color::ColorChoice;
#[cfg(not(feature = "color"))]
#[allow(unused_imports)]
pub(crate) use crate::util::color::ColorChoice;

pub use crate::derive::{Args, CommandFactory, FromArgMatches, Parser, Subcommand, ValueEnum};

#[allow(deprecated)]
pub use crate::builder::App;
pub use crate::builder::{AppFlags, AppSettings, ArgFlags, ArgSettings, PossibleValue, ValueHint};
pub use crate::error::{ErrorKind, Result};
#[allow(deprecated)]
pub use crate::parser::{Indices, OsValues, ValueSource, Values};

#[cfg(feature = "yaml")]
#[doc(hidden)]
#[cfg_attr(
    feature = "deprecated",
    deprecated(
        since = "3.0.0",
        note = "Deprecated in Issue #3087, maybe clap::Parser would fit your use case?"
    )
)]
#[doc(hidden)]
pub use yaml_rust::YamlLoader;

#[cfg(feature = "derive")]
#[doc(hidden)]
pub use clap_derive::{self, *};

/// Deprecated, replaced with [`CommandFactory`]
#[cfg_attr(
    feature = "deprecated",
    deprecated(since = "3.0.0", note = "Replaced with `CommandFactory`")
)]
pub use CommandFactory as IntoApp;
/// Deprecated, replaced with [`Parser`]
#[cfg_attr(
    feature = "deprecated",
    deprecated(since = "3.0.0", note = "Replaced with `Parser`")
)]
#[doc(hidden)]
pub use Parser as StructOpt;
/// Deprecated, replaced with [`ValueEnum`]
#[cfg_attr(
    feature = "deprecated",
    deprecated(since = "3.2.0", note = "Replaced with `ValueEnum`")
)]
pub use ValueEnum as ArgEnum;

#[cfg(feature = "unstable-doc")]
pub mod _cookbook;
#[cfg(feature = "unstable-doc")]
pub mod _derive;
#[cfg(feature = "unstable-doc")]
pub mod _faq;
#[cfg(feature = "unstable-doc")]
pub mod _features;
#[cfg(feature = "unstable-doc")]
pub mod _tutorial;

#[doc(hidden)]
pub mod __macro_refs {
    #[cfg(any(feature = "derive", feature = "cargo"))]
    #[doc(hidden)]
    pub use once_cell;
}

#[macro_use]
#[allow(missing_docs)]
mod macros;

mod derive;

#[cfg(feature = "regex")]
pub use crate::builder::RegexRef;

pub mod builder;
pub mod error;
pub mod parser;

mod mkeymap;
mod output;
mod util;

const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
                                  report at https://github.com/clap-rs/clap/issues";
const INVALID_UTF8: &str = "unexpected invalid UTF-8 code point";

/// Deprecated, replaced with [`Command::new`], unless you were looking for [Subcommand]
#[cfg_attr(
    feature = "deprecated",
    deprecated(
        since = "3.0.0",
        note = "Replaced with `Command::new` unless you intended the `Subcommand` trait"
    )
)]
#[doc(hidden)]
#[derive(Debug, Copy, Clone)]
pub struct SubCommand {}

#[allow(deprecated)]
impl SubCommand {
    /// Deprecated, replaced with [`Command::new`].
    /// Did you mean Subcommand (lower-case c)?
    #[cfg_attr(
        feature = "deprecated",
        deprecated(since = "3.0.0", note = "Replaced with `Command::new`")
    )]
    #[doc(hidden)]
    pub fn with_name<'help>(name: &str) -> App<'help> {
        Command::new(name)
    }

    /// Deprecated in [Issue #3087](https://github.com/clap-rs/clap/issues/3087), maybe [`clap::Parser`][crate::Parser] would fit your use case?
    #[cfg(feature = "yaml")]
    #[cfg_attr(
        feature = "deprecated",
        deprecated(
            since = "3.0.0",
            note = "Deprecated in Issue #3087, maybe clap::Parser would fit your use case?"
        )
    )]
    #[doc(hidden)]
    pub fn from_yaml(yaml: &yaml_rust::Yaml) -> App {
        #![allow(deprecated)]
        Command::from_yaml(yaml)
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Keegan McAllister.
// Copyright 2016 Corey Farwell.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// See `LICENSE` in this repository.

use std::io::{self, Read};
use std::{panic, process};

mod common;
pub use common::*;

/// Utility that reads a `Vec` of bytes from standard input (stdin)
/// and passes it to `closure`. All panics that occur within
/// `closure` will be treated as aborts. This is done so that
/// AFL considers a panic to be a crash.
///
/// # Examples
///
/// ```no_run
/// extern crate afl;
/// # struct Image;
/// # impl Image {
/// #     fn parse(_: &[u8]) {}
/// # }
///
/// fn main() {
///     afl::read_stdio_bytes(|read| {
///         Image::parse(&read)
///     })
/// }
/// ```
#[deprecated(
    since = "0.3.3",
    note = "This function does not use the `persistent mode` and `defered forkserver mode` and is therefore very slow.
Please use fuzz() or fuzz!() instead."
)]
pub fn read_stdio_bytes<F>(closure: F)
where
    F: Fn(Vec<u8>) + panic::RefUnwindSafe,
{
    let mut input = vec![];
    let result = io::stdin().read_to_end(&mut input);
    if result.is_err() {
        return;
    }
    let was_panic = panic::catch_unwind(|| {
        closure(input);
    });
    if was_panic.is_err() {
        process::abort();
    }
}

/// Utility that reads a `String` from standard input (stdin) and
/// passes it to `closure`. If a `String` cannot be constructed from
/// the data provided by standard input, `closure` will _not_ be
/// called. All panics that occur within `closure` will be treated as
/// aborts. This is done so that AFL considers a panic to be a crash.
///
/// # Examples
///
/// ```no_run
/// extern crate afl;
/// # struct Url;
/// # impl Url {
/// #     fn parse(_: &str) {}
/// # }
///
/// fn main() {
///     afl::read_stdio_string(|string| {
///         Url::parse(&string)
///     })
/// }
/// ```
#[deprecated(
    since = "0.3.3",
    note = "This function does not use the `persistent mode` and `defered forkserver mode` and is therefore very slow.
Please use fuzz() or fuzz!() instead."
)]
pub fn read_stdio_string<F>(closure: F)
where
    F: Fn(String) + panic::RefUnwindSafe,
{
    let mut input = String::new();
    let result = io::stdin().read_to_string(&mut input);
    if result.is_err() {
        return;
    }
    let was_panic = panic::catch_unwind(|| {
        closure(input);
    });
    if was_panic.is_err() {
        process::abort();
    }
}

// those functions are provided by the afl-llvm-rt static library
extern "C" {
    fn __afl_persistent_loop(counter: usize) -> isize;
    fn __afl_manual_init();
}

/// Fuzz a closure by passing it a `&[u8]`
///
/// This slice contains a "random" quantity of "random" data.
///
/// ```rust,no_run
/// # extern crate afl;
/// # use afl::fuzz;
/// # fn main() {
/// fuzz(true, |data|{
///     if data.len() != 6 {return}
///     if data[0] != b'q' {return}
///     if data[1] != b'w' {return}
///     if data[2] != b'e' {return}
///     if data[3] != b'r' {return}
///     if data[4] != b't' {return}
///     if data[5] != b'y' {return}
///     panic!("BOOM")
/// });
/// # }
/// ```
pub fn fuzz<F>(hook: bool, closure: F)
where
    F: Fn(&[u8]) + std::panic::RefUnwindSafe,
{
    // this marker strings needs to be in the produced executable for
    // afl-fuzz to detect `persistent mode` and `defered mode`
    static PERSIST_MARKER: &'static str = "##SIG_AFL_PERSISTENT##\0";
    static DEFERED_MARKER: &'static str = "##SIG_AFL_DEFER_FORKSRV##\0";

    // we now need a fake instruction to prevent the compiler from optimizing out
    // those marker strings
    unsafe { std::ptr::read_volatile(&PERSIST_MARKER) }; // hack used in https://github.com/bluss/bencher for black_box()
    unsafe { std::ptr::read_volatile(&DEFERED_MARKER) };
    // unsafe { asm!("" : : "r"(&PERSIST_MARKER)) }; // hack used in nightly's back_box(), requires feature asm
    // unsafe { asm!("" : : "r"(&DEFERED_MARKER)) };

    if hook {
      // sets panic hook to abort
      std::panic::set_hook(Box::new(|_| {
          std::process::abort();
      }));
    }

    let mut input = vec![];

    // initialize forkserver there
    unsafe { __afl_manual_init() };

    while unsafe { __afl_persistent_loop(1000) } != 0 {
        // get buffer from AFL through stdin
        let result = io::stdin().read_to_end(&mut input);
        if result.is_err() {
            return;
        }

        // We still catch unwinding panics just in case the fuzzed code modifies
        // the panic hook.
        // If so, the fuzzer will be unable to tell different bugs appart and you will
        // only be able to find one bug at a time before fixing it to then find a new one.
        let did_panic = std::panic::catch_unwind(|| {
            closure(&input);
        })
        .is_err();

        if did_panic {
            // hopefully the custom panic hook will be called before and abort the
            // process before the stack frames are unwinded.
            std::process::abort();
        }
        input.clear();
    }
}

/// Fuzz a closure-like block of code by passing it an object of arbitrary type.
///
/// You can choose the type of the argument using the syntax as in the example below.
/// Please check out the `arbitrary` crate to see which types are available.
///
/// For performance reasons, it is recommended that you use the native type `&[u8]` when possible.
///
/// ```rust,no_run
/// # #[macro_use] extern crate afl;
/// # fn main() {
/// fuzz!(|data: &[u8]| {
///     if data.len() != 6 {return}
///     if data[0] != b'q' {return}
///     if data[1] != b'w' {return}
///     if data[2] != b'e' {return}
///     if data[3] != b'r' {return}
///     if data[4] != b't' {return}
///     if data[5] != b'y' {return}
///     panic!("BOOM")
/// });
/// # }
/// ```
#[macro_export]
macro_rules! fuzz {
    (|$buf:ident| $body:block) => {
        afl::fuzz(true, |$buf| $body);
    };
    (|$buf:ident: &[u8]| $body:block) => {
        afl::fuzz(true, |$buf| $body);
    };
    (|$buf:ident: $dty: ty| $body:block) => {
        afl::fuzz(true, |$buf| {
            let $buf: $dty = {
                use arbitrary::{Arbitrary, RingBuffer};
                if let Ok(d) = RingBuffer::new($buf, $buf.len()).and_then(|mut b|{
                        Arbitrary::arbitrary(&mut b).map_err(|_| "")
                    }) {
                    d
                } else {
                    return
                }
            };

            $body
        });
    };
}

/// Fuzz a closure-like block of code by passing it an object of arbitrary type. Panics that are
/// caught inside the fuzzed code are not turned into crashes.
///
/// You can choose the type of the argument using the syntax as in the example below.
/// Please check out the `arbitrary` crate to see which types are available.
///
/// For performance reasons, it is recommended that you use the native type `&[u8]` when possible.
///
/// ```rust,no_run
/// # #[macro_use] extern crate afl;
/// # fn main() {
/// fuzz!(|data: &[u8]| {
///     if data.len() != 6 {return}
///     if data[0] != b'q' {return}
///     if data[1] != b'w' {return}
///     if data[2] != b'e' {return}
///     if data[3] != b'r' {return}
///     if data[4] != b't' {return}
///     if data[5] != b'y' {return}
///     panic!("BOOM")
/// });
/// # }
/// ```
#[macro_export]
macro_rules! fuzz_nohook {
    (|$buf:ident| $body:block) => {
        afl::fuzz(false, |$buf| $body);
    };
    (|$buf:ident: &[u8]| $body:block) => {
        afl::fuzz(false, |$buf| $body);
    };
    (|$buf:ident: $dty: ty| $body:block) => {
        afl::fuzz(false, |$buf| {
            let $buf: $dty = {
                use arbitrary::{Arbitrary, RingBuffer};
                if let Ok(d) = RingBuffer::new($buf, $buf.len())
                    .and_then(|mut b| Arbitrary::arbitrary(&mut b).map_err(|_| ""))
                {
                    d
                } else {
                    return;
                }
            };

            $body
        });
    };
}

#[cfg(test)]
mod test {
    /*
    use std::path::PathBuf;
    use std::process::{Command, Stdio};
    use std::thread;
    use std::time;

    extern crate libc;
    extern crate tempdir;

    fn target_path() -> PathBuf {
        if PathBuf::from("../target/debug/cargo-afl-fuzz").exists() {
            PathBuf::from("../target/debug/")
        } else if PathBuf::from("target/debug/cargo-afl-fuzz").exists() {
            PathBuf::from("target/debug/")
        } else {
            panic!("Could not find cargo-afl-fuzz!");
        }
    }

    #[test]
    fn test_cargo_afl_fuzz() {
        let temp_dir = tempdir::TempDir::new("aflrs").expect("Could not create temporary directory");
        let temp_dir_path = temp_dir.path();
        let mut child = Command::new(target_path().join("cargo-afl-fuzz"))
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .arg("-i")
            .arg(".")
            .arg("-o")
            .arg(temp_dir_path)
            .arg(target_path().join("examples").join("hello"))
            .spawn()
            .expect("Could not run cargo-afl-fuzz");
        thread::sleep(time::Duration::from_secs(7));
        child.kill().unwrap();
        assert!(temp_dir_path.join("fuzzer_stats").is_file());
    }
    */
}
<commit_msg>Eliminate fuzz/fuzz_nohook redundancy (#161)<commit_after>// Copyright 2015 Keegan McAllister.
// Copyright 2016 Corey Farwell.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// See `LICENSE` in this repository.

use std::io::{self, Read};
use std::{panic, process};

mod common;
pub use common::*;

/// Utility that reads a `Vec` of bytes from standard input (stdin)
/// and passes it to `closure`. All panics that occur within
/// `closure` will be treated as aborts. This is done so that
/// AFL considers a panic to be a crash.
///
/// # Examples
///
/// ```no_run
/// extern crate afl;
/// # struct Image;
/// # impl Image {
/// #     fn parse(_: &[u8]) {}
/// # }
///
/// fn main() {
///     afl::read_stdio_bytes(|read| {
///         Image::parse(&read)
///     })
/// }
/// ```
#[deprecated(
    since = "0.3.3",
    note = "This function does not use the `persistent mode` and `defered forkserver mode` and is therefore very slow.
Please use fuzz() or fuzz!() instead."
)]
pub fn read_stdio_bytes<F>(closure: F)
where
    F: Fn(Vec<u8>) + panic::RefUnwindSafe,
{
    let mut input = vec![];
    let result = io::stdin().read_to_end(&mut input);
    if result.is_err() {
        return;
    }
    let was_panic = panic::catch_unwind(|| {
        closure(input);
    });
    if was_panic.is_err() {
        process::abort();
    }
}

/// Utility that reads a `String` from standard input (stdin) and
/// passes it to `closure`. If a `String` cannot be constructed from
/// the data provided by standard input, `closure` will _not_ be
/// called. All panics that occur within `closure` will be treated as
/// aborts. This is done so that AFL considers a panic to be a crash.
///
/// # Examples
///
/// ```no_run
/// extern crate afl;
/// # struct Url;
/// # impl Url {
/// #     fn parse(_: &str) {}
/// # }
///
/// fn main() {
///     afl::read_stdio_string(|string| {
///         Url::parse(&string)
///     })
/// }
/// ```
#[deprecated(
    since = "0.3.3",
    note = "This function does not use the `persistent mode` and `defered forkserver mode` and is therefore very slow.
Please use fuzz() or fuzz!() instead."
)]
pub fn read_stdio_string<F>(closure: F)
where
    F: Fn(String) + panic::RefUnwindSafe,
{
    let mut input = String::new();
    let result = io::stdin().read_to_string(&mut input);
    if result.is_err() {
        return;
    }
    let was_panic = panic::catch_unwind(|| {
        closure(input);
    });
    if was_panic.is_err() {
        process::abort();
    }
}

// those functions are provided by the afl-llvm-rt static library
extern "C" {
    fn __afl_persistent_loop(counter: usize) -> isize;
    fn __afl_manual_init();
}

/// Fuzz a closure by passing it a `&[u8]`
///
/// This slice contains a "random" quantity of "random" data.
///
/// ```rust,no_run
/// # extern crate afl;
/// # use afl::fuzz;
/// # fn main() {
/// fuzz(true, |data|{
///     if data.len() != 6 {return}
///     if data[0] != b'q' {return}
///     if data[1] != b'w' {return}
///     if data[2] != b'e' {return}
///     if data[3] != b'r' {return}
///     if data[4] != b't' {return}
///     if data[5] != b'y' {return}
///     panic!("BOOM")
/// });
/// # }
/// ```
pub fn fuzz<F>(hook: bool, closure: F)
where
    F: Fn(&[u8]) + std::panic::RefUnwindSafe,
{
    // this marker strings needs to be in the produced executable for
    // afl-fuzz to detect `persistent mode` and `defered mode`
    static PERSIST_MARKER: &'static str = "##SIG_AFL_PERSISTENT##\0";
    static DEFERED_MARKER: &'static str = "##SIG_AFL_DEFER_FORKSRV##\0";

    // we now need a fake instruction to prevent the compiler from optimizing out
    // those marker strings
    unsafe { std::ptr::read_volatile(&PERSIST_MARKER) }; // hack used in https://github.com/bluss/bencher for black_box()
    unsafe { std::ptr::read_volatile(&DEFERED_MARKER) };
    // unsafe { asm!("" : : "r"(&PERSIST_MARKER)) }; // hack used in nightly's back_box(), requires feature asm
    // unsafe { asm!("" : : "r"(&DEFERED_MARKER)) };

    if hook {
      // sets panic hook to abort
      std::panic::set_hook(Box::new(|_| {
          std::process::abort();
      }));
    }

    let mut input = vec![];

    // initialize forkserver there
    unsafe { __afl_manual_init() };

    while unsafe { __afl_persistent_loop(1000) } != 0 {
        // get buffer from AFL through stdin
        let result = io::stdin().read_to_end(&mut input);
        if result.is_err() {
            return;
        }

        // We still catch unwinding panics just in case the fuzzed code modifies
        // the panic hook.
        // If so, the fuzzer will be unable to tell different bugs appart and you will
        // only be able to find one bug at a time before fixing it to then find a new one.
        let did_panic = std::panic::catch_unwind(|| {
            closure(&input);
        })
        .is_err();

        if did_panic {
            // hopefully the custom panic hook will be called before and abort the
            // process before the stack frames are unwinded.
            std::process::abort();
        }
        input.clear();
    }
}

/// Fuzz a closure-like block of code by passing it an object of arbitrary type.
///
/// You can choose the type of the argument using the syntax as in the example below.
/// Please check out the `arbitrary` crate to see which types are available.
///
/// For performance reasons, it is recommended that you use the native type `&[u8]` when possible.
///
/// ```rust,no_run
/// # #[macro_use] extern crate afl;
/// # fn main() {
/// fuzz!(|data: &[u8]| {
///     if data.len() != 6 {return}
///     if data[0] != b'q' {return}
///     if data[1] != b'w' {return}
///     if data[2] != b'e' {return}
///     if data[3] != b'r' {return}
///     if data[4] != b't' {return}
///     if data[5] != b'y' {return}
///     panic!("BOOM")
/// });
/// # }
/// ```
#[macro_export]
macro_rules! fuzz {
    ( $($x:tt)* ) => { __fuzz!(true, $($x)*) }
}

/// Like `fuzz!` above, but panics that are caught inside the fuzzed code are not turned into
/// crashes.
#[macro_export]
macro_rules! fuzz_nohook {
    ( $($x:tt)* ) => { __fuzz!(false, $($x)*) }
}

#[macro_export]
macro_rules! __fuzz {
    ($hook:expr, |$buf:ident| $body:block) => {
        afl::fuzz($hook, |$buf| $body);
    };
    ($hook:expr, |$buf:ident: &[u8]| $body:block) => {
        afl::fuzz($hook, |$buf| $body);
    };
    ($hook:expr, |$buf:ident: $dty: ty| $body:block) => {
        afl::fuzz($hook, |$buf| {
            let $buf: $dty = {
                use arbitrary::{Arbitrary, RingBuffer};
                if let Ok(d) = RingBuffer::new($buf, $buf.len())
                    .and_then(|mut b| Arbitrary::arbitrary(&mut b).map_err(|_| ""))
                {
                    d
                } else {
                    return;
                }
            };

            $body
        });
    };
}

#[cfg(test)]
mod test {
    /*
    use std::path::PathBuf;
    use std::process::{Command, Stdio};
    use std::thread;
    use std::time;

    extern crate libc;
    extern crate tempdir;

    fn target_path() -> PathBuf {
        if PathBuf::from("../target/debug/cargo-afl-fuzz").exists() {
            PathBuf::from("../target/debug/")
        } else if PathBuf::from("target/debug/cargo-afl-fuzz").exists() {
            PathBuf::from("target/debug/")
        } else {
            panic!("Could not find cargo-afl-fuzz!");
        }
    }

    #[test]
    fn test_cargo_afl_fuzz() {
        let temp_dir = tempdir::TempDir::new("aflrs").expect("Could not create temporary directory");
        let temp_dir_path = temp_dir.path();
        let mut child = Command::new(target_path().join("cargo-afl-fuzz"))
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .arg("-i")
            .arg(".")
            .arg("-o")
            .arg(temp_dir_path)
            .arg(target_path().join("examples").join("hello"))
            .spawn()
            .expect("Could not run cargo-afl-fuzz");
        thread::sleep(time::Duration::from_secs(7));
        child.kill().unwrap();
        assert!(temp_dir_path.join("fuzzer_stats").is_file());
    }
    */
}
<|endoftext|>