<commit_before>extern mod core_foundation;
extern mod io_surface;
extern mod opengles;

use mod opengles::cgl;
use mod opengles::gl2;

use core_foundation::base::CFTypeOps;
use core::cast::transmute;
use core::ptr::{null, to_unsafe_ptr};
use geom::size::Size2D;
use io_surface::{IOSurface, kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow, kIOSurfaceHeight};
use io_surface::{kIOSurfaceIsGlobal, kIOSurfaceWidth};
use opengles::cgl::{CGLChoosePixelFormat, CGLContextObj, CGLCreateContext, CGLLockContext};
use opengles::cgl::{CGLSetCurrentContext, CGLTexImageIOSurface2D, kCGLNoError, kCGLPFACompliant};
use opengles::cgl::{kCGLPFADoubleBuffer};
use opengles::gl2::{BGRA, CLAMP_TO_EDGE, COLOR_ATTACHMENT0, FRAMEBUFFER, FRAMEBUFFER_COMPLETE};
use opengles::gl2::{GLenum, GLint, GLsizei, GLuint, LINEAR, NEAREST, RGBA, TEXTURE_MAG_FILTER};
use opengles::gl2::{TEXTURE_MIN_FILTER, TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, TEXTURE_WRAP_T};
use opengles::gl2::{UNSIGNED_INT_8_8_8_8_REV};

use base::ShareContext;

// FIXME: This is not good.
#[link_args="-framework IOSurface -framework CoreFoundation"]
#[nolink]
extern {}

pub type Context = MacContext;

pub struct MacContext {
    surface: IOSurface,
    framebuffer: GLuint,
    texture: GLuint

    // FIXME: Needs drop.
}

pub fn init_cgl() -> CGLContextObj {
    // FIXME: We should expose some higher-level, safe abstractions inside the CGL module.
    unsafe {
        // Choose a pixel format.
        let attributes = [ kCGLPFADoubleBuffer, kCGLPFACompliant, 0 ];
        let pixel_format = null();
        let pixel_format_count = 1;
        let gl_error = CGLChoosePixelFormat(transmute(&attributes[0]),
                                            to_unsafe_ptr(&pixel_format),
                                            to_unsafe_ptr(&pixel_format_count));
        assert gl_error == kCGLNoError;

        // Create the context.
        let cgl_context = null();
        let gl_error = CGLCreateContext(pixel_format, null(), to_unsafe_ptr(&cgl_context));
        assert gl_error == kCGLNoError;

        // Set the context.
        let gl_error = CGLSetCurrentContext(cgl_context);
        assert gl_error == kCGLNoError;

        // Lock the context.
        let gl_error = CGLLockContext(cgl_context);
        assert gl_error == kCGLNoError;

        return cgl_context;
    }
}

pub fn init_surface(+size: Size2D<int>) -> IOSurface {
    use cf = core_foundation;
    use number = cf::number::CFNumber::new;
    use string = cf::string::CFString::wrap;
    use true_value = cf::boolean::CFBoolean::true_value;

    IOSurface::new_io_surface(&cf::dictionary::CFDictionary::new([
        (string(kIOSurfaceWidth),           number(size.width as i32).as_type()),
        (string(kIOSurfaceHeight),          number(size.height as i32).as_type()),
        (string(kIOSurfaceBytesPerRow),     number(size.width as i32 * 4).as_type()),
        (string(kIOSurfaceBytesPerElement), number(4i32).as_type()),
        (string(kIOSurfaceIsGlobal),        true_value().as_type())
    ]))
}

pub fn init_texture() -> GLuint {
    gl2::enable(TEXTURE_RECTANGLE_ARB);

    let texture = gl2::gen_textures(1)[0];
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, texture);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_T, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MAG_FILTER, LINEAR as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MIN_FILTER, NEAREST as GLint);
    return texture;
}

// Assumes the texture is already bound via gl2::bind_texture().
pub fn bind_surface_to_texture(context: &CGLContextObj, surface: &IOSurface, +size: Size2D<int>) {
    // FIXME: There should be safe wrappers for this.
    unsafe {
        let gl_error = CGLTexImageIOSurface2D(*context,
                                              TEXTURE_RECTANGLE_ARB,
                                              RGBA as GLenum,
                                              size.width as GLsizei,
                                              size.height as GLsizei,
                                              BGRA as GLenum,
                                              UNSIGNED_INT_8_8_8_8_REV,
                                              transmute(copy surface.obj),
                                              0);
        assert gl_error == kCGLNoError;
    }
}

pub fn bind_texture_to_framebuffer(texture: GLuint) {
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, 0);
    gl2::framebuffer_texture_2d(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_RECTANGLE_ARB, texture, 0);
    assert gl2::check_framebuffer_status(FRAMEBUFFER) == FRAMEBUFFER_COMPLETE;
}

impl MacContext : ShareContext {
    static fn new(size: Size2D<int>) -> MacContext {
        // Initialize CGL.
        let context = init_cgl();

        // Create the surface.
        let surface = init_surface(copy size);

        // Create a framebuffer.
        let framebuffer = gl2::gen_framebuffers(1)[0];
        gl2::bind_framebuffer(FRAMEBUFFER, framebuffer);

        // Create and bind to the texture.
        let texture = init_texture();
        bind_surface_to_texture(&context, &surface, size);

        // Bind the texture to the framebuffer.
        bind_texture_to_framebuffer(texture);

        MacContext {
            surface: move surface,
            framebuffer: framebuffer,
            texture: texture
        }
    }

    fn flush(&self) {
        gl2::finish();
    }

    fn id() -> int {
        self.surface.get_id() as int
    }
}

<commit_msg>Update for CF bindings changes.<commit_after>extern mod core_foundation;
extern mod io_surface;
extern mod opengles;

use mod opengles::cgl;
use mod opengles::gl2;

use core_foundation::base::CFTypeOps;
use core::cast::transmute;
use core::ptr::{null, to_unsafe_ptr};
use geom::size::Size2D;
use io_surface::{IOSurface, kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow, kIOSurfaceHeight};
use io_surface::{kIOSurfaceIsGlobal, kIOSurfaceWidth};
use opengles::cgl::{CGLChoosePixelFormat, CGLContextObj, CGLCreateContext, CGLLockContext};
use opengles::cgl::{CGLSetCurrentContext, CGLTexImageIOSurface2D, kCGLNoError, kCGLPFACompliant};
use opengles::cgl::{kCGLPFADoubleBuffer};
use opengles::gl2::{BGRA, CLAMP_TO_EDGE, COLOR_ATTACHMENT0, FRAMEBUFFER, FRAMEBUFFER_COMPLETE};
use opengles::gl2::{GLenum, GLint, GLsizei, GLuint, LINEAR, NEAREST, RGBA, TEXTURE_MAG_FILTER};
use opengles::gl2::{TEXTURE_MIN_FILTER, TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, TEXTURE_WRAP_T};
use opengles::gl2::{UNSIGNED_INT_8_8_8_8_REV};

use base::ShareContext;

// FIXME: This is not good.
#[link_args="-framework IOSurface -framework CoreFoundation"]
#[nolink]
extern {}

pub type Context = MacContext;

pub struct MacContext {
    surface: IOSurface,
    framebuffer: GLuint,
    texture: GLuint

    // FIXME: Needs drop.
}

pub fn init_cgl() -> CGLContextObj {
    // FIXME: We should expose some higher-level, safe abstractions inside the CGL module.
    unsafe {
        // Choose a pixel format.
        let attributes = [ kCGLPFADoubleBuffer, kCGLPFACompliant, 0 ];
        let pixel_format = null();
        let pixel_format_count = 1;
        let gl_error = CGLChoosePixelFormat(transmute(&attributes[0]),
                                            to_unsafe_ptr(&pixel_format),
                                            to_unsafe_ptr(&pixel_format_count));
        assert gl_error == kCGLNoError;

        // Create the context.
        let cgl_context = null();
        let gl_error = CGLCreateContext(pixel_format, null(), to_unsafe_ptr(&cgl_context));
        assert gl_error == kCGLNoError;

        // Set the context.
        let gl_error = CGLSetCurrentContext(cgl_context);
        assert gl_error == kCGLNoError;

        // Lock the context.
        let gl_error = CGLLockContext(cgl_context);
        assert gl_error == kCGLNoError;

        return cgl_context;
    }
}

pub fn init_surface(+size: Size2D<int>) -> IOSurface {
    use cf = core_foundation;
    use cf::boolean::{CFBooleanRef, CFBoolean};
    use cf::number::{CFNumberRef, CFNumber};
    use number = cf::number::CFNumber::new;
    use string = cf::string::CFString::wrap_extern;
    use true_value = cf::boolean::CFBoolean::true_value;

    IOSurface::new_io_surface(&cf::dictionary::CFDictionary::new([
        (string(kIOSurfaceWidth),           cf::base::as_CFType::<CFNumberRef, CFNumber>(number(size.width as i32))),
        (string(kIOSurfaceHeight),          cf::base::as_CFType::<CFNumberRef, CFNumber>(number(size.height as i32))),
        (string(kIOSurfaceBytesPerRow),     cf::base::as_CFType::<CFNumberRef, CFNumber>(number(size.width as i32 * 4))),
        (string(kIOSurfaceBytesPerElement), cf::base::as_CFType::<CFNumberRef, CFNumber>(number(4i32))),
        (string(kIOSurfaceIsGlobal),        cf::base::as_CFType::<CFBooleanRef, CFBoolean>(true_value()))
    ]))
}

pub fn init_texture() -> GLuint {
    gl2::enable(TEXTURE_RECTANGLE_ARB);

    let texture = gl2::gen_textures(1)[0];
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, texture);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_T, CLAMP_TO_EDGE as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MAG_FILTER, LINEAR as GLint);
    gl2::tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MIN_FILTER, NEAREST as GLint);
    return texture;
}

// Assumes the texture is already bound via gl2::bind_texture().
pub fn bind_surface_to_texture(context: &CGLContextObj, surface: &IOSurface, +size: Size2D<int>) {
    // FIXME: There should be safe wrappers for this.
    unsafe {
        let gl_error = CGLTexImageIOSurface2D(*context,
                                              TEXTURE_RECTANGLE_ARB,
                                              RGBA as GLenum,
                                              size.width as GLsizei,
                                              size.height as GLsizei,
                                              BGRA as GLenum,
                                              UNSIGNED_INT_8_8_8_8_REV,
                                              transmute(copy surface.obj),
                                              0);
        assert gl_error == kCGLNoError;
    }
}

pub fn bind_texture_to_framebuffer(texture: GLuint) {
    gl2::bind_texture(TEXTURE_RECTANGLE_ARB, 0);
    gl2::framebuffer_texture_2d(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_RECTANGLE_ARB, texture, 0);
    assert gl2::check_framebuffer_status(FRAMEBUFFER) == FRAMEBUFFER_COMPLETE;
}

impl MacContext : ShareContext {
    static fn new(size: Size2D<int>) -> MacContext {
        // Initialize CGL.
        let context = init_cgl();

        // Create the surface.
        let surface = init_surface(copy size);

        // Create a framebuffer.
        let framebuffer = gl2::gen_framebuffers(1)[0];
        gl2::bind_framebuffer(FRAMEBUFFER, framebuffer);

        // Create and bind to the texture.
        let texture = init_texture();
        bind_surface_to_texture(&context, &surface, size);

        // Bind the texture to the framebuffer.
        bind_texture_to_framebuffer(texture);

        MacContext {
            surface: move surface,
            framebuffer: framebuffer,
            texture: texture
        }
    }

    fn flush(&self) {
        gl2::finish();
    }

    fn id() -> int {
        self.surface.get_id() as int
    }
}

<|endoftext|>


<commit_before>mod utils;
use clap::{App, Arg};

const USE_FLAG_AS_ARGUMENT: &str =
    "error: Found argument '--another-flag' which wasn't expected, or isn't valid in this context

\tIf you tried to supply `--another-flag` as a value rather than a flag, use `-- --another-flag`

USAGE:
    mycat [FLAGS] [filename]

For more information try --help";

#[test]
fn flag_using_short() {
    let m = App::new("flag")
        .args(&[
            Arg::from("-f, --flag 'some flag'"),
            Arg::from("-c, --color 'some other flag'"),
        ])
        .get_matches_from(vec!["", "-f", "-c"]);
    assert!(m.is_present("flag"));
    assert!(m.is_present("color"));
}

#[test]
fn lots_o_flags_sep() {
    let r = App::new("opts")
        .arg(Arg::from("-o... 'some flag'"))
        .try_get_matches_from(vec![
            "", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o",
        ]);
    assert!(r.is_ok(), "{:?}", r.unwrap_err().kind);
    let m = r.unwrap();
    assert!(m.is_present("o"));
    assert_eq!(m.occurrences_of("o"), 297); // i.e. more than u8
}

#[test]
fn lots_o_flags_combined() {
    let r = App::new("opts")
        .arg(Arg::from("-o... 'some flag'"))
        .try_get_matches_from(vec![
            "",
            "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
            "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
            "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
            "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
            "-ooooooooooooooooooooooooooooooooooooooooo",
        ]);
    assert!(r.is_ok(), "{:?}", r.unwrap_err().kind);
    let m = r.unwrap();
    assert!(m.is_present("o"));
    assert_eq!(m.occurrences_of("o"), 297); // i.e. more than u8
}

#[test]
fn flag_using_long() {
    let m = App::new("flag")
        .args(&[
            Arg::from("--flag 'some flag'"),
            Arg::from("--color 'some other flag'"),
        ])
        .get_matches_from(vec!["", "--flag", "--color"]);
    assert!(m.is_present("flag"));
    assert!(m.is_present("color"));
}

#[cfg(feature = "suggestions")]
#[test]
fn flag_using_long_with_literals() {
    use clap::ErrorKind;

    let m = App::new("flag")
        .args(&[Arg::from("--rainbow 'yet another flag'").multiple_occurrences(true)])
        .try_get_matches_from(vec![
            "",
            "--rainbow",
            "--rainbow",
            "--rainbow=false",
            "--rainbow=true",
        ]);
    assert!(m.is_err(), "{:#?}", m.unwrap());
    assert_eq!(m.unwrap_err().kind, ErrorKind::TooManyValues);
}

#[test]
fn flag_using_mixed() {
    let m = App::new("flag")
        .args(&[
            Arg::from("-f, --flag 'some flag'"),
            Arg::from("-c, --color 'some other flag'"),
        ])
        .get_matches_from(vec!["", "-f", "--color"]);
    assert!(m.is_present("flag"));
    assert!(m.is_present("color"));

    let m = App::new("flag")
        .args(&[
            Arg::from("-f, --flag 'some flag'"),
            Arg::from("-c, --color 'some other flag'"),
        ])
        .get_matches_from(vec!["", "--flag", "-c"]);
    assert!(m.is_present("flag"));
    assert!(m.is_present("color"));
}

#[test]
fn multiple_flags_in_single() {
    let m = App::new("multe_flags")
        .args(&[
            Arg::from("-f, --flag 'some flag'"),
            Arg::from("-c, --color 'some other flag'"),
            Arg::from("-d, --debug 'another other flag'"),
        ])
        .get_matches_from(vec!["", "-fcd"]);
    assert!(m.is_present("flag"));
    assert!(m.is_present("color"));
    assert!(m.is_present("debug"));
}

#[test]
fn issue_1284_argument_in_flag_style() {
    let app = App::new("mycat")
        .arg(Arg::new("filename"))
        .arg(Arg::new("a-flag").long("a-flag"));

    let m = app
        .clone()
        .get_matches_from(vec!["", "--", "--another-flag"]);
    assert_eq!(m.value_of("filename"), Some("--another-flag"));

    let m = app.clone().get_matches_from(vec!["", "--a-flag"]);
    assert!(m.is_present("a-flag"));

    let m = app.clone().get_matches_from(vec!["", "--", "--a-flag"]);
    assert_eq!(m.value_of("filename"), Some("--a-flag"));

    assert!(utils::compare_output(
        app,
        "mycat --another-flag",
        USE_FLAG_AS_ARGUMENT,
        true
    ));
}

#[test]
fn issue_2308_multiple_dashes() {
    static MULTIPLE_DASHES: &str =
        "error: Found argument '-----' which wasn't expected, or isn't valid in this context

	If you tried to supply `-----` as a value rather than a flag, use `-- -----`

USAGE:
    test <arg>

For more information try --help";
    let app = App::new("test").arg(Arg::new("arg").takes_value(true).required(true));

    assert!(utils::compare_output(
        app,
        "test -----",
        MULTIPLE_DASHES,
        true
    ));
}
<commit_msg>test: simplify `flag_using_long_with_literals`<commit_after>mod utils;
use clap::{App, Arg};

const USE_FLAG_AS_ARGUMENT: &str =
    "error: Found argument '--another-flag' which wasn't expected, or isn't valid in this context

\tIf you tried to supply `--another-flag` as a value rather than a flag, use `-- --another-flag`

USAGE:
    mycat [FLAGS] [filename]

For more information try --help";

#[test]
fn flag_using_short() {
    let m = App::new("flag")
        .args(&[
            Arg::from("-f, --flag 'some flag'"),
            Arg::from("-c, --color 'some other flag'"),
        ])
        .get_matches_from(vec!["", "-f", "-c"]);
    assert!(m.is_present("flag"));
    assert!(m.is_present("color"));
}

#[test]
fn lots_o_flags_sep() {
    let r = App::new("opts")
        .arg(Arg::from("-o... 'some flag'"))
        .try_get_matches_from(vec![
            "", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o", "-o",
            "-o", "-o", "-o",
        ]);
    assert!(r.is_ok(), "{:?}", r.unwrap_err().kind);
    let m = r.unwrap();
    assert!(m.is_present("o"));
    assert_eq!(m.occurrences_of("o"), 297); // i.e. more than u8
}

#[test]
fn lots_o_flags_combined() {
    let r = App::new("opts")
        .arg(Arg::from("-o... 'some flag'"))
        .try_get_matches_from(vec![
            "",
            "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
            "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
            "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
            "-oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo",
            "-ooooooooooooooooooooooooooooooooooooooooo",
        ]);
    assert!(r.is_ok(), "{:?}", r.unwrap_err().kind);
    let m = r.unwrap();
    assert!(m.is_present("o"));
    assert_eq!(m.occurrences_of("o"), 297); // i.e. more than u8
}

#[test]
fn flag_using_long() {
    let m = App::new("flag")
        .args(&[
            Arg::from("--flag 'some flag'"),
            Arg::from("--color 'some other flag'"),
        ])
        .get_matches_from(vec!["", "--flag", "--color"]);
    assert!(m.is_present("flag"));
    assert!(m.is_present("color"));
}

#[test]
fn flag_using_long_with_literals() {
    use clap::ErrorKind;

    let m = App::new("flag")
        .arg(Arg::new("rainbow"))
        .try_get_matches_from(vec!["", "--rainbow=false"]);
    assert!(m.is_err(), "{:#?}", m.unwrap());
    assert_eq!(m.unwrap_err().kind, ErrorKind::TooManyValues);
}

#[test]
fn flag_using_mixed() {
    let m = App::new("flag")
        .args(&[
            Arg::from("-f, --flag 'some flag'"),
            Arg::from("-c, --color 'some other flag'"),
        ])
        .get_matches_from(vec!["", "-f", "--color"]);
    assert!(m.is_present("flag"));
    assert!(m.is_present("color"));

    let m = App::new("flag")
        .args(&[
            Arg::from("-f, --flag 'some flag'"),
            Arg::from("-c, --color 'some other flag'"),
        ])
        .get_matches_from(vec!["", "--flag", "-c"]);
    assert!(m.is_present("flag"));
    assert!(m.is_present("color"));
}

#[test]
fn multiple_flags_in_single() {
    let m = App::new("multe_flags")
        .args(&[
            Arg::from("-f, --flag 'some flag'"),
            Arg::from("-c, --color 'some other flag'"),
            Arg::from("-d, --debug 'another other flag'"),
        ])
        .get_matches_from(vec!["", "-fcd"]);
    assert!(m.is_present("flag"));
    assert!(m.is_present("color"));
    assert!(m.is_present("debug"));
}

#[test]
fn issue_1284_argument_in_flag_style() {
    let app = App::new("mycat")
        .arg(Arg::new("filename"))
        .arg(Arg::new("a-flag").long("a-flag"));

    let m = app
        .clone()
        .get_matches_from(vec!["", "--", "--another-flag"]);
    assert_eq!(m.value_of("filename"), Some("--another-flag"));

    let m = app.clone().get_matches_from(vec!["", "--a-flag"]);
    assert!(m.is_present("a-flag"));

    let m = app.clone().get_matches_from(vec!["", "--", "--a-flag"]);
    assert_eq!(m.value_of("filename"), Some("--a-flag"));

    assert!(utils::compare_output(
        app,
        "mycat --another-flag",
        USE_FLAG_AS_ARGUMENT,
        true
    ));
}

#[test]
fn issue_2308_multiple_dashes() {
    static MULTIPLE_DASHES: &str =
        "error: Found argument '-----' which wasn't expected, or isn't valid in this context

	If you tried to supply `-----` as a value rather than a flag, use `-- -----`

USAGE:
    test <arg>

For more information try --help";
    let app = App::new("test").arg(Arg::new("arg").takes_value(true).required(true));

    assert!(utils::compare_output(
        app,
        "test -----",
        MULTIPLE_DASHES,
        true
    ));
}
<|endoftext|>


<commit_before>extern crate lichen;

use lichen::parse::Parser;
use lichen::var::Var;
use lichen::eval::Evaluator;
use lichen::fun::MutFn;

// Test for mutable state
#[derive(Debug)]
struct Player {
    coins: f32,
    name: String
}

#[test]
fn state_mut() {
    let src = "\n
def global\n
;\n
\n
root\n
    @global.coins 1\n
    emit \"step\"\n
    @global.coins + 5\n
    emit global.coins\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();
    assert_eq!(vars[0], 6.0 .into());
}

#[test]
fn parse_cust_fn() {
    let src = "root\n
    @root.five (inc) 1 2 3\n
    emit root.five\n
;\n
def root\n
    five 5\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let inc = MutFn::new(move |args, def| {
        let mut r = 0.;
        for n in args.iter() {
            if let Ok(v) = n.get_num(def) {
                r += v;
            }
        }

        return Some(Var::Num(r))
    });
    env.fun.insert("inc".to_owned(), inc);

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], 6.0 .into());
}

#[test]
fn parse_def_block() {
    let src = "root\n
    emit global.name global.size\n
;\n
\n
def global\n
    name \"my-game\"\n
    size 1.5\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);
    let (vars,_) = ev.next().unwrap();

    assert_eq!(vars[0], Var::String("my-game".to_owned()));
    assert_eq!(vars[1], Var::Num(1.5 .to_owned()));
}

#[test]
fn validate_def_block() {
    let src = "root\n
    @global.size + 0.5\n
    @global.name \"other-game\"\n
    emit global.name global.size\n\n
;\n
\n
def global\n
    name \"my-game\"\n
    size 1.5\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], Var::String("other-game".to_owned()));
    assert_eq!(vars[1], Var::Num(2.0 .to_owned()));
}

#[test]
fn validate_when_block() {
    let src = "root\n
    needs_coins global.coins < 1\n
    when {needs_coins @global.coins + 2, \n
         !global.name @global.name \"new-name\"}\n
    emit global.name global.coins\n
;\n
def global\n
    coins 0\n
;\n";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[1], 2.0 .into());
    assert_eq!(vars[0], "new-name".into());
}

#[test]
fn save_state() {
    let src = "root\n
    @ (inc) \"coins\" 1 2 3\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let data = Player { coins: 0.0, name: "Pan".to_owned() };
    let data = Arc::new(Mutex::new(data));

    let dc = data.clone();
    let inc = MutFn::new(move |args, def| {
        let mut r = dc.lock().unwrap().coins;
        for n in args.iter() {
            if let Ok(v) = n.get_num(def) {
                *r += v;
            }
        }

        None
    });
    env.fun.insert("inc".to_owned(), inc);

    let state = {
        let mut ev = Evaluator::new(&mut env);
        let (_,_) = ev.next().unwrap();
        ev.save()
    };

    assert_eq!(data.coins, 0.0);

    let state = {
        let mut ev = state.to_eval(&mut env);
        let (_,_) = ev.next().unwrap();
        ev.save()
    };

    assert_eq!(data.coins, 1.0);

    //check if we held our place within node after await
    let ev = state.to_eval(&mut env);
    let (vars,_) = ev.last().unwrap();
    assert_eq!(vars[0],"bye".into());
}

#[test]
fn validate_or_block() {
    let src = "root\n
    if !global.drunk \"not drunk\"\n
    or \"is drunk\"\n
\n
    @global.drunk true\n
\n
    if !global.drunk \"not drunk\"\n
    or \"is drunk\"\n
;\n
\n
def global\n
    drunk false
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);
    let (vars,_) = ev.next().unwrap();

    assert_eq!(vars[0], "not drunk".into());

    let (vars,_) = ev.next().unwrap();
    assert_eq!(vars[0], "is drunk".into());
}
<commit_msg>fix test cust save<commit_after>extern crate lichen;

use lichen::parse::Parser;
use lichen::var::Var;
use lichen::eval::Evaluator;
use lichen::fun::MutFn;

use std::sync::{Arc,Mutex};

// Test for mutable state
#[derive(Debug)]
struct Player {
    coins: f32,
    name: String
}

#[test]
fn state_mut() {
    let src = "\n
def global\n
;\n
\n
root\n
    @global.coins 1\n
    emit \"step\"\n
    @global.coins + 5\n
    emit global.coins\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();
    assert_eq!(vars[0], 6.0 .into());
}

#[test]
fn parse_cust_fn() {
    let src = "root\n
    @root.five (inc) 1 2 3\n
    emit root.five\n
;\n
def root\n
    five 5\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let inc = MutFn::new(move |args, def| {
        let mut r = 0.;
        for n in args.iter() {
            if let Ok(v) = n.get_num(def) {
                r += v;
            }
        }

        return Some(Var::Num(r))
    });
    env.fun.insert("inc".to_owned(), inc);

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], 6.0 .into());
}

#[test]
fn parse_def_block() {
    let src = "root\n
    emit global.name global.size\n
;\n
\n
def global\n
    name \"my-game\"\n
    size 1.5\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);
    let (vars,_) = ev.next().unwrap();

    assert_eq!(vars[0], Var::String("my-game".to_owned()));
    assert_eq!(vars[1], Var::Num(1.5 .to_owned()));
}

#[test]
fn validate_def_block() {
    let src = "root\n
    @global.size + 0.5\n
    @global.name \"other-game\"\n
    emit global.name global.size\n\n
;\n
\n
def global\n
    name \"my-game\"\n
    size 1.5\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[0], Var::String("other-game".to_owned()));
    assert_eq!(vars[1], Var::Num(2.0 .to_owned()));
}

#[test]
fn validate_when_block() {
    let src = "root\n
    needs_coins global.coins < 1\n
    when {needs_coins @global.coins + 2, \n
         !global.name @global.name \"new-name\"}\n
    emit global.name global.coins\n
;\n
def global\n
    coins 0\n
;\n";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let ev = Evaluator::new(&mut env);
    let (vars,_) = ev.last().unwrap();

    assert_eq!(vars[1], 2.0 .into());
    assert_eq!(vars[0], "new-name".into());
}

#[test]
fn save_state() {
    let src = "root\n
    emit root.coins\n
    @root.coins (inc) \"coins\" 1 2 3\n
    next:await no-where\n
    emit root.coins\n
;\n
def root\n
coins 0\n
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();
    let data = Player { coins: 0.0, name: "Pan".to_owned() };
    let data = Arc::new(Mutex::new(data));

    let dc = data.clone();
    let inc = MutFn::new(move |args, def| {
        let mut r = dc.lock().unwrap();
        for n in args.iter() {
            if let Ok(v) = n.get_num(def) {
                r.coins += v;
            }
        }

        Some(r.coins.into())
    });
    env.fun.insert("inc".to_owned(), inc);

    let state = {
        let mut ev = Evaluator::new(&mut env);
        let (vars,_) = ev.next().unwrap();
        assert_eq!(vars[0], 0.0 .into());

        ev.save()
    };

    let state = { //save await state
        let mut ev = state.to_eval(&mut env);
        let (_,_) = ev.next().unwrap();
        ev.save()
    };

    let mut ev = state.to_eval(&mut env);
    let (vars,_) = ev.next().unwrap();
    assert_eq!(vars[0], 6.0 .into());

    let player = data.lock().unwrap();
    assert_eq!(player.coins, 6.0);
}

#[test]
fn validate_or_block() {
    let src = "root\n
    if !global.drunk \"not drunk\"\n
    or \"is drunk\"\n
\n
    @global.drunk true\n
\n
    if !global.drunk \"not drunk\"\n
    or \"is drunk\"\n
;\n
\n
def global\n
    drunk false
;";

    let mut env = Parser::parse_blocks(src).expect("ERROR: Unable to parse source").into_env();

    let mut ev = Evaluator::new(&mut env);
    let (vars,_) = ev.next().unwrap();

    assert_eq!(vars[0], "not drunk".into());

    let (vars,_) = ev.next().unwrap();
    assert_eq!(vars[0], "is drunk".into());
}
<|endoftext|>


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

#![allow(unstable_features)]

#![feature(collections)]
#![feature(core)]
#![feature(io)]
#![feature(libc)]
#![feature(test)]

#[macro_use]
extern crate c_string;

extern crate test;
extern crate libc;

use std::error::FromError;
use std::ffi::CStr;
use std::io::Error as IoError;
use std::io::ErrorKind::InvalidInput;
use std::iter::Iterator;
use std::ptr;

use c_string::{CStrBuf, OwnedCString, CChars};
use c_string::{libc_free, parse_c_multistring};

pub fn check_c_str(c_str: &CStr, expected: &[u8]) {
    let buf = c_str.as_ptr();
    let len = expected.len();
    for i in (0 .. len) {
        let byte = unsafe { *buf.offset(i as isize) as u8 };
        assert_eq!(byte, expected[i]);
    }
    let term = unsafe { *buf.offset(len as isize) as u8 };
    assert_eq!(term, 0);
}

unsafe fn bytes_dup_raw(s: &[u8]) -> *const libc::c_char {
    let len = s.len();
    let dup = libc::malloc((len + 1) as libc::size_t) as *mut u8;
    ptr::copy_nonoverlapping(dup, s.as_ptr(), len);
    *dup.offset(len as isize) = 0;
    dup as *const libc::c_char
}

fn bytes_dup(s: &[u8]) -> OwnedCString {
    unsafe {
        OwnedCString::new(bytes_dup_raw(s), libc_free)
    }
}

fn str_dup(s: &str) -> OwnedCString {
    bytes_dup(s.as_bytes())
}

#[test]
fn test_parse_c_multistring() {
    unsafe {
        let input = b"zero\0one\0\0";
        let ptr = input.as_ptr();
        let expected = ["zero", "one"];
        let mut it = expected.iter();
        let result = parse_c_multistring(ptr as *const libc::c_char, None,
            |cbytes| {
                assert_eq!(cbytes, it.next().unwrap().as_bytes());
            });
        assert_eq!(result, 2);
        assert!(it.next().is_none());
    }
}

#[test]
fn test_c_str_macro() {
    let c_str = c_str!("hello");
    check_c_str(c_str, b"hello");
}

#[test]
fn test_owned_c_string_deref() {
    let c_str = str_dup("hello");
    check_c_str(&c_str, b"hello");
}

#[test]
fn test_owned_c_string_as_ptr() {
    let c_str = str_dup("hello");
    let len = unsafe { libc::strlen(c_str.as_ptr()) };
    assert_eq!(len, 5);
}

#[test]
fn test_iterator() {
    let c_string = str_dup("");
    let mut iter = CChars::from_c_str(&c_string);
    assert_eq!(iter.next(), None);

    let c_string = str_dup("hello");
    let mut iter = CChars::from_c_str(&c_string);
    assert_eq!(iter.next(), Some('h' as libc::c_char));
    assert_eq!(iter.next(), Some('e' as libc::c_char));
    assert_eq!(iter.next(), Some('l' as libc::c_char));
    assert_eq!(iter.next(), Some('l' as libc::c_char));
    assert_eq!(iter.next(), Some('o' as libc::c_char));
    assert_eq!(iter.next(), None);
}

#[test]
fn test_c_str_buf_from_iter() {
    let test_strings = [
        b"",
        b"foo\xFF",
        b"Mary had a little \xD0\x0D, Little \xD0\x0D"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let c_str = CStrBuf::from_iter(bytes.iter().cloned()).unwrap();
        check_c_str(&c_str, bytes);
    }

    let test_strings = [
        b"got\0nul",
        b"Mary had a little lamb, Little \0"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let res = CStrBuf::from_iter(bytes.iter().cloned());
        let err = res.err().unwrap();
        assert_eq!(err.nul_position(), bytes.position_elem(&0u8).unwrap());
        let vec = err.into_bytes();
        assert_eq!(&vec, bytes);
    }
}

#[test]
fn test_c_str_buf_from_str() {
    let c_str = CStrBuf::from_str("").unwrap();
    check_c_str(&c_str, b"");

    let c_str = CStrBuf::from_str("hello").unwrap();
    check_c_str(&c_str, b"hello");

    // Owned variant
    let c_str = CStrBuf::from_str("Mary had a little lamb, Little lamb").unwrap();
    check_c_str(&c_str, b"Mary had a little lamb, Little lamb");

    let res = CStrBuf::from_str("got\0nul");
    let err = res.err().unwrap();
    assert_eq!(err.nul_position(), 3);
    let bytes = err.into_bytes();
    assert_eq!(bytes, b"got\0nul");
}

#[test]
fn test_io_error_from_nul_error() {
    let res = CStrBuf::from_str("got\0nul");
    let err = res.err().unwrap();
    let io_err: IoError = FromError::from_error(err);
    assert_eq!(io_err.kind(), InvalidInput);
    assert!(io_err.detail().is_some());
}

#[test]
fn test_c_str_buf_from_vec() {
    let test_strings = [
        b"",
        b"foo\xFF",
        b"Mary had a little \xD0\x0D, Little \xD0\x0D"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let c_str = CStrBuf::from_vec(bytes.to_vec()).unwrap();
        check_c_str(&c_str, bytes);
    }

    let test_strings = [
        b"got\0nul",
        b"Mary had a little lamb, Little \0"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let res = CStrBuf::from_vec(bytes.to_vec());
        let err = res.err().unwrap();
        assert_eq!(err.nul_position(), bytes.position_elem(&0u8).unwrap());
        let vec = err.into_bytes();
        assert_eq!(&vec, bytes);
    }
}

#[test]
fn test_io_error_from_into_c_str_error() {
    let res = CStrBuf::from_vec(b"got\0nul".to_vec());
    let err = res.err().unwrap();
    let io_err: IoError = FromError::from_error(err);
    assert_eq!(io_err.kind(), InvalidInput);
    assert!(io_err.detail().is_some());
}

#[test]
fn test_c_str_buf_into_vec() {
    let c_str = CStrBuf::from_str("").unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], b"");
    let c_str = CStrBuf::from_str("hello").unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], b"hello");
    let bytes = b"foo\xFF";
    let c_str = CStrBuf::from_iter(bytes.iter().cloned()).unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], bytes);

    // Owned variant
    let c_str = CStrBuf::from_str("Mary had a little lamb, Little lamb").unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], b"Mary had a little lamb, Little lamb");
    let bytes = b"Mary had a little \xD0\x0D, Little \xD0\x0D";
    let c_str = CStrBuf::from_iter(bytes.iter().cloned()).unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], bytes);
}

#[test]
fn test_owned_c_string_to_bytes() {
    let c_str = str_dup("hello");
    assert_eq!(c_str.to_bytes(), b"hello");
    let c_str = str_dup("");
    assert_eq!(c_str.to_bytes(), b"");
    let c_str = bytes_dup(b"foo\xFF");
    assert_eq!(c_str.to_bytes(), b"foo\xFF");
}

#[test]
fn test_owned_c_string_debug() {
    let c_str = str_dup("hello");
    let msg = format!("{:?}", c_str);
    assert_eq!(msg, "\"hello\"");
    let c_str = str_dup("");
    let msg = format!("{:?}", c_str);
    assert_eq!(msg, "\"\"");
    let c_str = bytes_dup(b"foo\xFF");
    let msg = format!("{:?}", c_str);
    assert_eq!(msg, r#""foo\xff""#);
}

#[test]
#[should_fail]
fn test_c_string_new_fail() {
    let _c_str: OwnedCString = unsafe {
        OwnedCString::new(ptr::null(), libc_free)
    };
}
<commit_msg>Updated to rustc 1.0.0-nightly (3e4be02b8 2015-03-13)<commit_after>// Copyright 2014, 2015 Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
// Copyright 2012 The Rust Project Developers
// See the COPYRIGHT file at the top-level directory of this distribution
// and at http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(unstable_features)]

#![feature(collections)]
#![feature(core)]
#![feature(io)]
#![feature(libc)]
#![feature(test)]

#[macro_use]
extern crate c_string;

extern crate test;
extern crate libc;

use std::error::FromError;
use std::ffi::CStr;
use std::io::Error as IoError;
use std::io::ErrorKind::InvalidInput;
use std::iter::Iterator;
use std::ptr;

use c_string::{CStrBuf, OwnedCString, CChars};
use c_string::{libc_free, parse_c_multistring};

pub fn check_c_str(c_str: &CStr, expected: &[u8]) {
    let buf = c_str.as_ptr();
    let len = expected.len();
    for i in (0 .. len) {
        let byte = unsafe { *buf.offset(i as isize) as u8 };
        assert_eq!(byte, expected[i]);
    }
    let term = unsafe { *buf.offset(len as isize) as u8 };
    assert_eq!(term, 0);
}

unsafe fn bytes_dup_raw(s: &[u8]) -> *const libc::c_char {
    let len = s.len();
    let dup = libc::malloc((len + 1) as libc::size_t) as *mut u8;
    ptr::copy_nonoverlapping(dup, s.as_ptr(), len);
    *dup.offset(len as isize) = 0;
    dup as *const libc::c_char
}

fn bytes_dup(s: &[u8]) -> OwnedCString {
    unsafe {
        OwnedCString::new(bytes_dup_raw(s), libc_free)
    }
}

fn str_dup(s: &str) -> OwnedCString {
    bytes_dup(s.as_bytes())
}

#[test]
fn test_parse_c_multistring() {
    unsafe {
        let input = b"zero\0one\0\0";
        let ptr = input.as_ptr();
        let expected = ["zero", "one"];
        let mut it = expected.iter();
        let result = parse_c_multistring(ptr as *const libc::c_char, None,
            |cbytes| {
                assert_eq!(cbytes, it.next().unwrap().as_bytes());
            });
        assert_eq!(result, 2);
        assert!(it.next().is_none());
    }
}

#[test]
fn test_c_str_macro() {
    let c_str = c_str!("hello");
    check_c_str(c_str, b"hello");
}

#[test]
fn test_owned_c_string_deref() {
    let c_str = str_dup("hello");
    check_c_str(&c_str, b"hello");
}

#[test]
fn test_owned_c_string_as_ptr() {
    let c_str = str_dup("hello");
    let len = unsafe { libc::strlen(c_str.as_ptr()) };
    assert_eq!(len, 5);
}

#[test]
fn test_iterator() {
    let c_string = str_dup("");
    let mut iter = CChars::from_c_str(&c_string);
    assert_eq!(iter.next(), None);

    let c_string = str_dup("hello");
    let mut iter = CChars::from_c_str(&c_string);
    assert_eq!(iter.next(), Some('h' as libc::c_char));
    assert_eq!(iter.next(), Some('e' as libc::c_char));
    assert_eq!(iter.next(), Some('l' as libc::c_char));
    assert_eq!(iter.next(), Some('l' as libc::c_char));
    assert_eq!(iter.next(), Some('o' as libc::c_char));
    assert_eq!(iter.next(), None);
}

#[test]
fn test_c_str_buf_from_iter() {
    let test_strings = [
        b"",
        b"foo\xFF",
        b"Mary had a little \xD0\x0D, Little \xD0\x0D"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let c_str = CStrBuf::from_iter(bytes.iter().cloned()).unwrap();
        check_c_str(&c_str, bytes);
    }

    let test_strings = [
        b"got\0nul",
        b"Mary had a little lamb, Little \0"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let res = CStrBuf::from_iter(bytes.iter().cloned());
        let err = res.err().unwrap();
        assert_eq!(err.nul_position(), bytes.position_elem(&0u8).unwrap());
        let vec = err.into_bytes();
        assert_eq!(&vec, bytes);
    }
}

#[test]
fn test_c_str_buf_from_str() {
    let c_str = CStrBuf::from_str("").unwrap();
    check_c_str(&c_str, b"");

    let c_str = CStrBuf::from_str("hello").unwrap();
    check_c_str(&c_str, b"hello");

    // Owned variant
    let c_str = CStrBuf::from_str("Mary had a little lamb, Little lamb").unwrap();
    check_c_str(&c_str, b"Mary had a little lamb, Little lamb");

    let res = CStrBuf::from_str("got\0nul");
    let err = res.err().unwrap();
    assert_eq!(err.nul_position(), 3);
    let bytes = err.into_bytes();
    assert_eq!(bytes, b"got\0nul");
}

#[test]
fn test_io_error_from_nul_error() {
    let res = CStrBuf::from_str("got\0nul");
    let err = res.err().unwrap();
    let io_err: IoError = FromError::from_error(err);
    assert_eq!(io_err.kind(), InvalidInput);
}

#[test]
fn test_c_str_buf_from_vec() {
    let test_strings = [
        b"",
        b"foo\xFF",
        b"Mary had a little \xD0\x0D, Little \xD0\x0D"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let c_str = CStrBuf::from_vec(bytes.to_vec()).unwrap();
        check_c_str(&c_str, bytes);
    }

    let test_strings = [
        b"got\0nul",
        b"Mary had a little lamb, Little \0"  // Exercises the owned variant
    ];
    for bytes in test_strings.iter() {
        let res = CStrBuf::from_vec(bytes.to_vec());
        let err = res.err().unwrap();
        assert_eq!(err.nul_position(), bytes.position_elem(&0u8).unwrap());
        let vec = err.into_bytes();
        assert_eq!(&vec, bytes);
    }
}

#[test]
fn test_io_error_from_into_c_str_error() {
    let res = CStrBuf::from_vec(b"got\0nul".to_vec());
    let err = res.err().unwrap();
    let io_err: IoError = FromError::from_error(err);
    assert_eq!(io_err.kind(), InvalidInput);
}

#[test]
fn test_c_str_buf_into_vec() {
    let c_str = CStrBuf::from_str("").unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], b"");
    let c_str = CStrBuf::from_str("hello").unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], b"hello");
    let bytes = b"foo\xFF";
    let c_str = CStrBuf::from_iter(bytes.iter().cloned()).unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], bytes);

    // Owned variant
    let c_str = CStrBuf::from_str("Mary had a little lamb, Little lamb").unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], b"Mary had a little lamb, Little lamb");
    let bytes = b"Mary had a little \xD0\x0D, Little \xD0\x0D";
    let c_str = CStrBuf::from_iter(bytes.iter().cloned()).unwrap();
    let vec = c_str.into_vec();
    assert_eq!(&vec[..], bytes);
}

#[test]
fn test_owned_c_string_to_bytes() {
    let c_str = str_dup("hello");
    assert_eq!(c_str.to_bytes(), b"hello");
    let c_str = str_dup("");
    assert_eq!(c_str.to_bytes(), b"");
    let c_str = bytes_dup(b"foo\xFF");
    assert_eq!(c_str.to_bytes(), b"foo\xFF");
}

#[test]
fn test_owned_c_string_debug() {
    let c_str = str_dup("hello");
    let msg = format!("{:?}", c_str);
    assert_eq!(msg, "\"hello\"");
    let c_str = str_dup("");
    let msg = format!("{:?}", c_str);
    assert_eq!(msg, "\"\"");
    let c_str = bytes_dup(b"foo\xFF");
    let msg = format!("{:?}", c_str);
    assert_eq!(msg, r#""foo\xff""#);
}

#[test]
#[should_panic]
fn test_c_string_new_fail() {
    let _c_str: OwnedCString = unsafe {
        OwnedCString::new(ptr::null(), libc_free)
    };
}
<|endoftext|>


<commit_before>use autocfg::AutoCfg;

const CONST_THREAD_LOCAL_PROBE: &str = r#"
{
    thread_local! {
        static MY_PROBE: usize = const { 10 };
    }

    MY_PROBE.with(|val| *val)
}
"#;

fn main() {
    let mut enable_const_thread_local = false;

    match AutoCfg::new() {
        Ok(ac) => {
            // These checks prefer to call only `probe_rustc_version` if that is
            // enough to determine whether the feature is supported. This is
            // because the `probe_expression` call involves a call to rustc,
            // which the `probe_rustc_version` call avoids.

            // Const-initialized thread locals were stabilized in 1.59.
            if ac.probe_rustc_version(1, 60) {
                enable_const_thread_local = true;
            } else if ac.probe_rustc_version(1, 59) {
                // This compiler claims to be 1.59, but there are some nightly
                // compilers that claim to be 1.59 without supporting the
                // feature. Explicitly probe to check if code using them
                // compiles.
                //
                // The oldest nightly that supports the feature is 2021-12-06.
                if ac.probe_expression(CONST_THREAD_LOCAL_PROBE) {
                    enable_const_thread_local = true;
                }
            }

            if !ac.probe_rustc_version(1, 51) {
                autocfg::emit("tokio_no_addr_of")
            }
        }

        Err(e) => {
            // If we couldn't detect the compiler version and features, just
            // print a warning. This isn't a fatal error: we can still build
            // Tokio, we just can't enable cfgs automatically.
            println!(
                "cargo:warning=tokio: failed to detect compiler features: {}",
                e
            );
        }
    }

    if !enable_const_thread_local {
        // To disable this feature on compilers that support it, you can
        // explicitly pass this flag with the following environment variable:
        //
        // RUSTFLAGS="--cfg tokio_no_const_thread_local"
        autocfg::emit("tokio_no_const_thread_local")
    }
}
<commit_msg>chore: fix version detection for `addr_of!` (#4863)<commit_after>use autocfg::AutoCfg;

const CONST_THREAD_LOCAL_PROBE: &str = r#"
{
    thread_local! {
        static MY_PROBE: usize = const { 10 };
    }

    MY_PROBE.with(|val| *val)
}
"#;

const ADDR_OF_PROBE: &str = r#"
{
    let my_var = 10;
    ::std::ptr::addr_of!(my_var)
}
"#;

fn main() {
    let mut enable_const_thread_local = false;
    let mut enable_addr_of = false;

    match AutoCfg::new() {
        Ok(ac) => {
            // These checks prefer to call only `probe_rustc_version` if that is
            // enough to determine whether the feature is supported. This is
            // because the `probe_expression` call involves a call to rustc,
            // which the `probe_rustc_version` call avoids.

            // Const-initialized thread locals were stabilized in 1.59.
            if ac.probe_rustc_version(1, 60) {
                enable_const_thread_local = true;
            } else if ac.probe_rustc_version(1, 59) {
                // This compiler claims to be 1.59, but there are some nightly
                // compilers that claim to be 1.59 without supporting the
                // feature. Explicitly probe to check if code using them
                // compiles.
                //
                // The oldest nightly that supports the feature is 2021-12-06.
                if ac.probe_expression(CONST_THREAD_LOCAL_PROBE) {
                    enable_const_thread_local = true;
                }
            }

            // The `addr_of` and `addr_of_mut` macros were stabilized in 1.51.
            if ac.probe_rustc_version(1, 52) {
                enable_addr_of = true;
            } else if ac.probe_rustc_version(1, 51) {
                // This compiler claims to be 1.51, but there are some nightly
                // compilers that claim to be 1.51 without supporting the
                // feature. Explicitly probe to check if code using them
                // compiles.
                //
                // The oldest nightly that supports the feature is 2021-01-31.
                if ac.probe_expression(ADDR_OF_PROBE) {
                    enable_addr_of = true;
                }
            }
        }

        Err(e) => {
            // If we couldn't detect the compiler version and features, just
            // print a warning. This isn't a fatal error: we can still build
            // Tokio, we just can't enable cfgs automatically.
            println!(
                "cargo:warning=tokio: failed to detect compiler features: {}",
                e
            );
        }
    }

    if !enable_const_thread_local {
        // To disable this feature on compilers that support it, you can
        // explicitly pass this flag with the following environment variable:
        //
        // RUSTFLAGS="--cfg tokio_no_const_thread_local"
        autocfg::emit("tokio_no_const_thread_local")
    }

    if !enable_addr_of {
        // To disable this feature on compilers that support it, you can
        // explicitly pass this flag with the following environment variable:
        //
        // RUSTFLAGS="--cfg tokio_no_addr_of"
        autocfg::emit("tokio_no_addr_of")
    }
}
<|endoftext|>


<commit_before>#![feature(box_patterns)]
#[cfg(feature = "trace_log")]
extern crate env_logger;

extern crate base64;
extern crate r2api;
extern crate r2pipe;
extern crate radeco_lib;
extern crate rustyline;

#[macro_use]
extern crate lazy_static;
extern crate clap;
extern crate syntect;

mod cli;
mod core;
mod highlighting;

use rustyline::completion::{Completer, FilenameCompleter};
use rustyline::error::ReadlineError;
use rustyline::highlight::Highlighter;
use rustyline::hint::Hinter;
use rustyline::{CompletionType, Config, EditMode, Editor, Helper};
use std::fs;
use std::process;

mod scheme {
    pub const HTTP: &'static str = "http://";
    pub const TCP: &'static str = "tcp://";

    pub fn is_http(url: &str) -> bool {
        url.starts_with(HTTP)
    }

    pub fn is_tcp(url: &str) -> bool {
        url.starts_with(TCP)
    }
}

// On unix platforms you can use ANSI escape sequences
#[cfg(unix)]
const PROMPT: &'static str = "\x1b[1;32m>>\x1b[0m ";
// File seperator for *nix based platforms
#[cfg(unix)]
const FILE_SP: char = '/';

// Windows consoles typically don't support ANSI escape sequences out
// of the box
#[cfg(windows)]
const PROMPT: &'static str = ">> ";
#[cfg(windows)]
// File seperator for Windows
const FILE_SP: char = '\\';

#[derive(Default)]
struct Completes {
    file_completer: FilenameCompleter,
}

impl Helper for Completes {}

impl Hinter for Completes {
    fn hint(&self, _line: &str, _pos: usize) -> Option<String> {
        None
    }
}

impl Highlighter for Completes {}

impl Completer for Completes {
    type Candidate = String;
    fn complete(&self, line: &str, _pos: usize) -> rustyline::Result<(usize, Vec<String>)> {
        // TODO Completion for function names
        let cmds = vec![
            command::HELP,
            command::LOAD,
            command::CONNECT,
            command::FNLIST,
            command::ANALYZE,
            command::DOT,
            command::IR,
            command::DECOMPILE,
            command::QUIT,
        ];
        let mut ret: Vec<String> = cmds
            .into_iter()
            .filter(|s| s.starts_with(line))
            .map(|s| s.to_string())
            .collect();
        match self.file_completer.complete(line, _pos) {
            Ok((n, ss)) => {
                let mut completed_lines = ss
                    .into_iter()
                    .map(|s| {
                        if let Some(sep_loc) = line.rfind(FILE_SP) {
                            format!("{}{}", &line[..sep_loc + 1], s.display)
                        } else {
                            format!("{}{}", &line[..n], s.display)
                        }
                    })
                    .collect();
                ret.append(&mut completed_lines);
            }
            Err(_) => {}
        }

        Ok((0, ret))
    }
}

const SEP: &'static str = "END";

fn main() {
    let (arg, cmd_opt, is_append_mode, is_batch_mode, no_highlight) = cli::parse_args();
    let config = Config::builder()
        .auto_add_history(true)
        .history_ignore_space(true)
        .completion_type(CompletionType::List)
        .edit_mode(EditMode::Emacs)
        .build();
    let mut rl = Editor::with_config(config);
    rl.set_helper(Some(Completes::default()));
    core::PROJ.with(move |proj| {
        let proj_result = arg.map(|ref s| {
            if scheme::is_http(s) {
                core::load_proj_http(&s[scheme::HTTP.len()..]).map_err(|e| e.to_string())
            } else if scheme::is_tcp(s) {
                core::load_proj_tcp(&s[scheme::TCP.len()..]).map_err(|e| e.to_string())
            } else if is_file(s) {
                Ok(core::load_proj_by_path(s))
            } else {
                Err(format!("Invalid argument {}", s))
            }
        });
        match proj_result {
            Some(Ok(p)) => *proj.borrow_mut() = Some(p),
            Some(Err(ref err)) => println!("{}", err),
            None => {}
        }
    });

    if is_batch_mode {
        core::PROJ.with(|proj_opt| {
            if proj_opt.borrow().is_none() {
                eprintln!("Project was not loaded!");
                return;
            }
            // If a command is specified by the user run it,
            // otherwise decompile all functions.
            if let Some(command) = cmd_opt {
               cmd(command, no_highlight);
            } else {
                let mut proj_ = proj_opt.borrow_mut();
                let proj = proj_.as_mut().unwrap();

                core::analyze_all_functions(proj);
                let decompiled = core::decompile_all_functions(proj);
                if no_highlight {
                    println!("{}", decompiled);
                } else {
                    highlighting::print_highlighted(&decompiled);
                }
            }

            process::exit(0);
        });
    }

    loop {
        let readline = rl.readline(PROMPT);
        match readline {
            Ok(line) => {
                cmd(line, !no_highlight);
                if is_append_mode {
                    println!("{}", SEP);
                }
            }
            Err(ReadlineError::Interrupted) => {}
            Err(ReadlineError::Eof) => break,
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
    }
}

mod command {
    pub const HELP: &'static str = "help";
    pub const LOAD: &'static str = "load";
    pub const CONNECT: &'static str = "connect";
    pub const FNLIST: &'static str = "fn_list";
    pub const ANALYZE: &'static str = "analyze";
    pub const DOT: &'static str = "dot";
    pub const IR: &'static str = "ir";
    pub const DECOMPILE: &'static str = "decompile";
    pub const QUIT: &'static str = "quit";

    pub fn help() {
        let width = 30;
        println!("{:width$}    Show this help", HELP, width = width);
        println!(
            "{:width$}    Load binary",
            format!("{} path", LOAD),
            width = width
        );
        println!(
            "{:width$}    Connect to radare2 server",
            format!("{} (http|tcp)://<url>", CONNECT),
            width = width
        );
        println!("{:width$}    Show function list", FNLIST, width = width);
        println!(
            "{:width$}    Analyze <func>",
            format!("{} <func>", ANALYZE),
            width = width
        );
        println!(
            "{:width$}    Emit IR of <func>",
            format!("{} <func>", IR),
            width = width
        );
        println!(
            "{:width$}    Emit graph of the IR in Graphviz dot",
            format!("{} <func>", DOT),
            width = width
        );
        println!(
            "{:width$}    Decompile <func>",
            format!("{} <func>", DECOMPILE),
            width = width
        );
        println!("{:width$}    Quit interactive prompt", QUIT, width = width);
    }
}

fn cmd(line: String, highlight: bool) {
    if line.is_empty() {
       return;
    }

    let mut terms = line.split_whitespace();
    let op1 = terms.next();
    let op2 = terms.next();

    core::PROJ.with(|proj_opt| {
        match (op1, op2) {
            (Some(command::HELP), _) => {
                command::help();
                return;
            }
            (Some(command::LOAD), Some(path)) => {
                if is_file(path) {
                    *proj_opt.borrow_mut() = Some(core::load_proj_by_path(path));
                    return;
                } else {
                    println!("{} is not found.", path);
                    return;
                }
            }
            (Some(command::CONNECT), Some(url)) => {
                let p_opt = if scheme::is_http(&url) {
                    core::load_proj_http(&url[scheme::HTTP.len()..])
                } else if scheme::is_tcp(&url) {
                    core::load_proj_tcp(&url[scheme::TCP.len()..])
                } else {
                    Err("Invalid url")
                };
                match p_opt {
                    Ok(p) => *proj_opt.borrow_mut() = Some(p),
                    Err(msg) => println!("{}", msg),
                }
                return;
            }
            (Some(command::QUIT), _) => {
                process::exit(0);
            }
            _ => {}
        };
        if proj_opt.borrow().is_none() {
            println!("Load a project first");
            return;
        }
        let mut proj_ = proj_opt.borrow_mut();
        let proj = proj_.as_mut().unwrap();
        match (op1, op2) {
            (Some(command::ANALYZE), Some("*")) => {
                core::analyze_all_functions(proj);
            }
            (Some(command::FNLIST), _) => {
                let funcs = core::fn_list(&proj);
                println!("{}", funcs.join("\n"));
            }
            // TODO Show list of dependency information of analyses
            // TODO Add command for individual analyses
            (Some(command::ANALYZE), Some(f)) => {
                if let Some(rfn) = core::get_function_mut(f, proj) {
                    core::analyze(rfn);
                } else {
                    println!("{} is not found", f);
                }
            }
            (Some(command::DOT), Some(f)) => {
                if let Some(rfn) = core::get_function(f, &proj) {
                    println!("{}", core::emit_dot(rfn.ssa()));
                } else {
                    println!("{} is not found", f);
                }
            }
            (Some(command::IR), Some(f)) => {
                if let Some(rfn) = core::get_function(f, &proj) {
                    println!("{}", core::emit_ir(rfn));
                } else {
                    println!("{} is not found", f);
                }
            }
            (Some(command::DECOMPILE), Some("*")) => {
                let decompiled = core::decompile_all_functions(&proj);
                if highlight {
                    highlighting::print_highlighted(&decompiled);
                } else {
                    println!("{}", decompiled);
                }
            }
            (Some(command::DECOMPILE), Some(f)) => match core::decompile(f, &proj) {
                Ok(res) => {
                    if highlight {
                        highlighting::print_highlighted(&res);
                    } else {
                        println!("{}", res);
                    }
                }
                Err(err) => println!("{}", err),
            },
            _ => {
                println!(
                    "Invalid command {} {}",
                    op1.unwrap_or(""),
                    op2.unwrap_or("")
                );
            }
        }
    });
}

fn is_file(path: &str) -> bool {
    fs::metadata(path).map(|f| f.is_file()).unwrap_or(false)
}
<commit_msg>Add function completion<commit_after>#![feature(box_patterns)]
#[cfg(feature = "trace_log")]
extern crate env_logger;

extern crate base64;
extern crate r2api;
extern crate r2pipe;
extern crate radeco_lib;
extern crate rustyline;

#[macro_use]
extern crate lazy_static;
extern crate clap;
extern crate syntect;

mod cli;
mod core;
mod highlighting;

use rustyline::completion::{Completer, FilenameCompleter};
use rustyline::error::ReadlineError;
use rustyline::highlight::Highlighter;
use rustyline::hint::Hinter;
use rustyline::{CompletionType, Config, EditMode, Editor, Helper};
use std::fs;
use std::process;

mod scheme {
    pub const HTTP: &'static str = "http://";
    pub const TCP: &'static str = "tcp://";

    pub fn is_http(url: &str) -> bool {
        url.starts_with(HTTP)
    }

    pub fn is_tcp(url: &str) -> bool {
        url.starts_with(TCP)
    }
}

// On unix platforms you can use ANSI escape sequences
#[cfg(unix)]
const PROMPT: &'static str = "\x1b[1;32m>>\x1b[0m ";
// File seperator for *nix based platforms
#[cfg(unix)]
const FILE_SP: char = '/';

// Windows consoles typically don't support ANSI escape sequences out
// of the box
#[cfg(windows)]
const PROMPT: &'static str = ">> ";
#[cfg(windows)]
// File seperator for Windows
const FILE_SP: char = '\\';

#[derive(Default)]
struct Completes {
    file_completer: FilenameCompleter,
}

impl Helper for Completes {}

impl Hinter for Completes {
    fn hint(&self, _line: &str, _pos: usize) -> Option<String> {
        None
    }
}

impl Highlighter for Completes {}

impl Completer for Completes {
    type Candidate = String;
    fn complete(&self, line: &str, _pos: usize) -> rustyline::Result<(usize, Vec<String>)> {
        let cmds = vec![
            command::HELP,
            command::LOAD,
            command::CONNECT,
            command::FNLIST,
            command::ANALYZE,
            command::DOT,
            command::IR,
            command::DECOMPILE,
            command::QUIT,
        ];

        // Check if `line` contains a cmd that requires a function
        // as parameter.
        let complete_func: bool = cmds
            .iter()
            .filter(|s| line.len() >= s.len())
            .any(|s| &&line[..s.len()] == s &&
                 command::requires_func(&line[..s.len()]));

        // Complete commands.
        let mut ret: Vec<String> = cmds
            .into_iter()
            .filter(|s| line.len() < s.len())
            .filter(|s| s.starts_with(line))
            .map(|s| s.to_string())
            .collect();

        if complete_func {
            core::PROJ.with(|proj_opt| {
                if let Some(ref proj) = *proj_opt.borrow() {
                    let mut line_tokens = line.split(' ');
                    line_tokens.next(); // drop the command.

                    let to_compl = line_tokens.last().unwrap_or("");

                    let mut funcs: Vec<String> = core::fn_list(&proj)
                        .iter()
                        .filter(|f| f.len() > to_compl.len())
                        .filter(|f| &f[0..to_compl.len()] == to_compl)
                        .map(|f|
                             format!("{}{}{}", line,
                                if to_compl.len() == 0 {" "} else {""},
                                &f[to_compl.len()..f.len()]))
                        .collect();
                    ret.append(&mut funcs);
                }
            });
        }
        if line.starts_with("load") {
            match self.file_completer.complete(line, _pos) {
                Ok((n, ss)) => {
                    let mut completed_lines = ss
                        .into_iter()
                        .map(|s| {
                            if let Some(sep_loc) = line.rfind(FILE_SP) {
                                format!("{}{}", &line[..sep_loc + 1], s.display)
                            } else {
                                format!("{}{}", &line[..n], s.display)
                            }
                        })
                        .collect();
                    ret.append(&mut completed_lines);
                }
                Err(_) => {}
            }
        }

        Ok((0, ret))
    }
}

const SEP: &'static str = "END";

fn main() {
    let (arg, cmd_opt, is_append_mode, is_batch_mode, no_highlight) = cli::parse_args();
    let config = Config::builder()
        .auto_add_history(true)
        .history_ignore_space(true)
        .completion_type(CompletionType::List)
        .edit_mode(EditMode::Emacs)
        .build();
    let mut rl = Editor::with_config(config);
    rl.set_helper(Some(Completes::default()));
    core::PROJ.with(move |proj| {
        let proj_result = arg.map(|ref s| {
            if scheme::is_http(s) {
                core::load_proj_http(&s[scheme::HTTP.len()..]).map_err(|e| e.to_string())
            } else if scheme::is_tcp(s) {
                core::load_proj_tcp(&s[scheme::TCP.len()..]).map_err(|e| e.to_string())
            } else if is_file(s) {
                Ok(core::load_proj_by_path(s))
            } else {
                Err(format!("Invalid argument {}", s))
            }
        });
        match proj_result {
            Some(Ok(p)) => *proj.borrow_mut() = Some(p),
            Some(Err(ref err)) => println!("{}", err),
            None => {}
        }
    });

    if is_batch_mode {
        core::PROJ.with(|proj_opt| {
            if proj_opt.borrow().is_none() {
                eprintln!("Project was not loaded!");
                return;
            }
            // If a command is specified by the user run it,
            // otherwise decompile all functions.
            if let Some(command) = cmd_opt {
               cmd(command, no_highlight);
            } else {
                let mut proj_ = proj_opt.borrow_mut();
                let proj = proj_.as_mut().unwrap();

                core::analyze_all_functions(proj);
                let decompiled = core::decompile_all_functions(proj);
                if no_highlight {
                    println!("{}", decompiled);
                } else {
                    highlighting::print_highlighted(&decompiled);
                }
            }

            process::exit(0);
        });
    }

    loop {
        let readline = rl.readline(PROMPT);
        match readline {
            Ok(line) => {
                cmd(line, !no_highlight);
                if is_append_mode {
                    println!("{}", SEP);
                }
            }
            Err(ReadlineError::Interrupted) => {}
            Err(ReadlineError::Eof) => break,
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
    }
}

mod command {
    pub const HELP: &'static str = "help";
    pub const LOAD: &'static str = "load";
    pub const CONNECT: &'static str = "connect";
    pub const FNLIST: &'static str = "fn_list";
    pub const ANALYZE: &'static str = "analyze";
    pub const DOT: &'static str = "dot";
    pub const IR: &'static str = "ir";
    pub const DECOMPILE: &'static str = "decompile";
    pub const QUIT: &'static str = "quit";

    pub fn help() {
        let width = 30;
        println!("{:width$}    Show this help", HELP, width = width);
        println!(
            "{:width$}    Load binary",
            format!("{} path", LOAD),
            width = width
        );
        println!(
            "{:width$}    Connect to radare2 server",
            format!("{} (http|tcp)://<url>", CONNECT),
            width = width
        );
        println!("{:width$}    Show function list", FNLIST, width = width);
        println!(
            "{:width$}    Analyze <func>",
            format!("{} <func>", ANALYZE),
            width = width
        );
        println!(
            "{:width$}    Emit IR of <func>",
            format!("{} <func>", IR),
            width = width
        );
        println!(
            "{:width$}    Emit graph of the IR in Graphviz dot",
            format!("{} <func>", DOT),
            width = width
        );
        println!(
            "{:width$}    Decompile <func>",
            format!("{} <func>", DECOMPILE),
            width = width
        );
        println!("{:width$}    Quit interactive prompt", QUIT, width = width);
    }

    /// Returns true if `cmd` requires a function as parameter.
    pub fn requires_func(cmd: &str) -> bool {
        match cmd {
            ANALYZE | DOT | IR | DECOMPILE => true,
            _ => false,
        }
    }
}

fn cmd(line: String, highlight: bool) {
    if line.is_empty() {
       return;
    }

    let mut terms = line.split_whitespace();
    let op1 = terms.next();
    let op2 = terms.next();

    core::PROJ.with(|proj_opt| {
        match (op1, op2) {
            (Some(command::HELP), _) => {
                command::help();
                return;
            }
            (Some(command::LOAD), Some(path)) => {
                if is_file(path) {
                    *proj_opt.borrow_mut() = Some(core::load_proj_by_path(path));
                    return;
                } else {
                    println!("{} is not found.", path);
                    return;
                }
            }
            (Some(command::CONNECT), Some(url)) => {
                let p_opt = if scheme::is_http(&url) {
                    core::load_proj_http(&url[scheme::HTTP.len()..])
                } else if scheme::is_tcp(&url) {
                    core::load_proj_tcp(&url[scheme::TCP.len()..])
                } else {
                    Err("Invalid url")
                };
                match p_opt {
                    Ok(p) => *proj_opt.borrow_mut() = Some(p),
                    Err(msg) => println!("{}", msg),
                }
                return;
            }
            (Some(command::QUIT), _) => {
                process::exit(0);
            }
            _ => {}
        };
        if proj_opt.borrow().is_none() {
            println!("Load a project first");
            return;
        }
        let mut proj_ = proj_opt.borrow_mut();
        let proj = proj_.as_mut().unwrap();
        match (op1, op2) {
            (Some(command::ANALYZE), Some("*")) => {
                core::analyze_all_functions(proj);
            }
            (Some(command::FNLIST), _) => {
                let funcs = core::fn_list(&proj);
                println!("{}", funcs.join("\n"));
            }
            // TODO Show list of dependency information of analyses
            // TODO Add command for individual analyses
            (Some(command::ANALYZE), Some(f)) => {
                if let Some(rfn) = core::get_function_mut(f, proj) {
                    core::analyze(rfn);
                } else {
                    println!("{} is not found", f);
                }
            }
            (Some(command::DOT), Some(f)) => {
                if let Some(rfn) = core::get_function(f, &proj) {
                    println!("{}", core::emit_dot(rfn.ssa()));
                } else {
                    println!("{} is not found", f);
                }
            }
            (Some(command::IR), Some(f)) => {
                if let Some(rfn) = core::get_function(f, &proj) {
                    println!("{}", core::emit_ir(rfn));
                } else {
                    println!("{} is not found", f);
                }
            }
            (Some(command::DECOMPILE), Some("*")) => {
                let decompiled = core::decompile_all_functions(&proj);
                if highlight {
                    highlighting::print_highlighted(&decompiled);
                } else {
                    println!("{}", decompiled);
                }
            }
            (Some(command::DECOMPILE), Some(f)) => match core::decompile(f, &proj) {
                Ok(res) => {
                    if highlight {
                        highlighting::print_highlighted(&res);
                    } else {
                        println!("{}", res);
                    }
                }
                Err(err) => println!("{}", err),
            },
            _ => {
                println!(
                    "Invalid command {} {}",
                    op1.unwrap_or(""),
                    op2.unwrap_or("")
                );
            }
        }
    });
}

fn is_file(path: &str) -> bool {
    fs::metadata(path).map(|f| f.is_file()).unwrap_or(false)
}
<|endoftext|>