<commit_before>//! Chomp is a fast monadic-style parser combinator library for the Rust programming language. It was
//! written as the culmination of the experiments detailed in these blog posts:
//!
//! * [Part 1](http://m4rw3r.github.io/parser-combinator-experiments-rust/)
//! * [Part 2](http://m4rw3r.github.io/parser-combinator-experiments-errors)
//! * [Part 3](http://m4rw3r.github.io/parser-combinator-experiments-part-3)
//! * [Chomp 0.1 Announcement](http://m4rw3r.github.io/parser-combinators-road-chomp-0-1/)
//!
//! For its current capabilities, you will find that Chomp performs consistently as well, if not
//! better, than optimized C parsers, while being vastly more expressive. For an example that
//! builds a performant HTTP parser out of smaller parsers, see
//! [http_parser.rs](examples/http_parser.rs).
//!
//! # Example
//!
//! ```
//! # #[macro_use] extern crate chomp;
//! # fn main() {
//! use chomp::{Input, U8Result, parse_only};
//! use chomp::{take_while1, token};
//!
//! #[derive(Debug, Eq, PartialEq)]
//! struct Name<'a> {
//!     first: &'a [u8],
//!     last:  &'a [u8],
//! }
//!
//! fn name(i: Input<u8>) -> U8Result<Name> {
//!     parse!{i;
//!         let first = take_while1(|c| c != b' ');
//!                     token(b' ');  // skipping this char
//!         let last  = take_while1(|c| c != b'\n');
//!
//!         ret Name{
//!             first: first,
//!             last:  last,
//!         }
//!     }
//! }
//!
//! assert_eq!(parse_only(name, "Martin Wernstål\n".as_bytes()), Ok(Name{
//!     first: b"Martin",
//!     last: "Wernstål".as_bytes()
//! }));
//! # }
//! ```
//!
//! # Usage
//!
//! Chomp's functionality is split between three modules:
//!
//! * `parsers` contains the basic parsers used to parse streams of input.
//! * `combinators` contains functions which take parsers and return new ones.
//! * `primitives` contains the building blocks used to make new parsers. This is advanced usage and
//!   is far more involved than using the pre-existing parsers, but is sometimes unavoidable.
//!
//! A parser is, at its simplest, a function that takes a slice of input and returns a
//! `ParserResult<I, T, E>`, where `I`, `T`, and `E` are the input, output, and error types,
//! respectively. Parsers are usually parameterized over values or other parsers as well, so these
//! appear as extra arguments in the parsing function. As an example, here is the signature of the
//! `token` parser, which matches a particular input.
//!
//! ```ignore
//! fn token<I: Copy + Eq>(i: Input<I>, t: I) -> SimpleResult<I, I> {...}
//! ```
//!
//! Notice that the first argument is an `Input<I>`, and the second argument is some `I`.
//! `Input<I>` is just a datatype over the current state of the parser and a slice of input `I`,
//! and prevents the parser writer from accidentally mutating the state of the parser. Later, when
//! we introduce the `parse!` macro, we will see that using a parser in this macro just means
//! supplying all of the arguments but the input, as so:
//!
//! ```ignore
//! token(b'T');
//! ```
//!
//! Note that you cannot do this outside of the `parse!` macro. `SimpleResult<I, T>` is a
//! convenience type alias over `ParseResult<I, T, Error<u8>>`, and `Error<I>` is just a convenient
//! "default" error type that will be sufficient for most uses. For more sophisticated usage, one
//! can always write a custom error type.
//!
//! A very useful parser is the `satisfy` parser:
//!
//! ```ignore
//! fn satisfy<I: Copy, F>(i: Input<I>, f: F) -> SimpleResult<I, I>
//!    where F: FnOnce(I) -> bool { ... }
//! ```
//!
//! Besides the input state, satisfy's only parameter is a predicate function and will succeed only
//! if the next piece of input satisfies the supplied predicate. Here's an example that might be
//! used in the `parse!` macro:
//!
//! ```
//! # #[macro_use] extern crate chomp;
//! # fn main() {
//! # use chomp::{satisfy, parse_only};
//! # let r = parse_only(parser!{
//! satisfy(|c| {
//!     match c {
//!         b'c' | b'h' | b'a' | b'r' => true,
//!         _ => false,
//!     }
//! })
//! # }, b"h");
//! # assert_eq!(r, Ok(b'h'));
//! # }
//! ```
//!
//! This parser will only succeed if the character is one of the characters in "char".
//!
//! Lastly, here is the parser combinator `count`, which will attempt to run a parser a number of
//! times on its input.
//!
//! ```ignore
//! pub fn count<'a, I, T, E, F, U>(i: Input<'a, I>, num: usize, p: F) -> ParseResult<'a, I, T, E>
//!   where I: Copy,
//!         U: 'a,
//!         F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
//!         T: FromIterator<U> { ... }
//! ```
//!
//! Using parsers is almost entirely done using the `parse!` macro, which enables us to do three
//! distinct things:
//!
//! * Sequence parsers over the remaining input
//! * Store intermediate results into datatypes
//! * Return a datatype at the end, which may be the result of any arbitrary computation over the
//! intermediate results.
//!
//! In other words, just as a normal Rust function usually looks something like this:
//!
//! ```
//! # fn launch_missiles() {}
//! # fn read_number() -> u8 { 3 }
//! fn f() -> (u8, u8, u8) {
//!     let a = read_number();
//!     let b = read_number();
//!     launch_missiles();
//!     return (a, b, a + b);
//! }
//! ```
//!
//! A Chomp parser with a similar structure looks like this:
//!
//! ```
//! # #[macro_use] extern crate chomp;
//! # use chomp::{Input, parse_only, satisfy, string, U8Result};
//! fn f(i: Input<u8>) -> U8Result<(u8, u8, u8)> {
//!     parse!{i;
//!         let a = digit();
//!         let b = digit();
//!                 string(b"missiles");
//!         ret (a, b, a + b)
//!     }
//! }
//!
//! fn digit(i: Input<u8>) -> U8Result<u8> {
//!     satisfy(i, |c| b'0' <= c && c <= b'9').map(|c| c - b'0')
//! }
//! # fn main() {
//! #     let r = parse_only(f, b"33missiles");
//! #     assert_eq!(r, Ok((3, 3, 6)));
//! # }
//! ```
//!
//! Readers familiar with Haskell or F# will recognize this as a "monadic computation" or
//! "computation expression".
//!
//! You use the `parse!` macro as follows:
//!
//! - Write the input parameter first, with a semicolon.
//! - Write any number of valid parser actions or identifier bindings, where:
//!    - a parser action takes the form `parser(params*)`, with the input parameter omitted.
//!    - an identifier binding takes the form `let identifer = parser(params*);`, with the input
//!      parameter omitted.
//! - Write the final line of the macro, which must always be either a parser action, or a return
//!   statement which takes the form `ret expression`. The type of `expression` becomes the return
//!   type of the entire parser, should it succeed.
//!
//! The entire grammar for the macro is listed elsewhere in this documentation.
//!
//! # Features
//!
//! * `backtrace`:
#![cfg_attr(feature="backtrace", doc = " enabled.")]
#![cfg_attr(not(feature="backtrace"), doc = " disabled (default).")]
//!
//!    This feature enables backtraces for parse-errors, either by calling `Error::trace` or by
//!    printing it using `fmt::Debug`.
//!
//!    This incurs a performance-hit every time a `chomp::parsers` parser fails since a backtrace
//!    must be collected.
//!
//!    In the `dev` and `test` profiles backtraces will always be enabled. This does not incur any
//!    cost when built using the `release` profile unless the `backtrace` feature is enabled.
//!
//! * `noop_error`:
#![cfg_attr(not(feature="noop_error"), doc = " disabled (default).")]
#![cfg_attr(feature="noop_error", doc = " enabled.")]
//!
//!    The built-in `chomp::parsers::Error` type is zero-sized and carry no error-information. This
//!    increases performance somewhat.

#[macro_use]
extern crate bitflags;
extern crate conv;
extern crate debugtrace;

#[macro_use]
mod macros;
mod input;
mod parse;
mod parse_result;

pub mod ascii;
pub mod buffer;
pub mod parsers;
pub mod combinators;

pub use combinators::{
    count,
    option,
    or,
    many,
    many1,
    sep_by,
    sep_by1,
    many_till,
    skip_many,
    skip_many1,
    matched_by,
};
pub use parsers::{
    any,
    eof,
    not_token,
    peek,
    peek_next,
    satisfy,
    satisfy_with,
    scan,
    string,
    run_scanner,
    take,
    take_remainder,
    take_till,
    take_while,
    take_while1,
    token,
};
pub use parsers::Error;
pub use input::Input;
pub use parse::{
    ParseError,
    parse_only,
};
pub use parse_result::{
    ParseResult,
    SimpleResult,
    U8Result,
};

/// Module used to construct fundamental parsers and combinators.
///
/// # Primitive
///
/// Only used by fundamental parsers and combinators.
pub mod primitives {
    pub use input::{
        InputBuffer,
        InputClone,
    };
    pub use parse_result::{
        IntoInner,
        State,
    };

    /// Input utilities.
    ///
    /// # Primitive
    ///
    /// Only used by fundamental parsers and combinators.
    pub mod input {
        pub use input::{DEFAULT, END_OF_INPUT, new};
    }

    /// ParseResult utilities.
    ///
    /// # Primitive
    ///
    /// Only used by fundamental parsers and combinators.
    ///
    /// # Note
    ///
    /// Prefer to use ``Input::ret``, ``Input::err`` or ``Input::incomplete`` instead of using
    /// ``parse_result::new``.
    pub mod parse_result {
        pub use parse_result::new;
    }
}
<commit_msg>Fixed URLs in src/lib.rs<commit_after>//! Chomp is a fast monadic-style parser combinator library for the Rust programming language. It was
//! written as the culmination of the experiments detailed in these blog posts:
//!
//! * [Part 1](http://m4rw3r.github.io/parser-combinator-experiments-rust)
//! * [Part 2](http://m4rw3r.github.io/parser-combinator-experiments-errors)
//! * [Part 3](http://m4rw3r.github.io/parser-combinator-experiments-part-3)
//! * [Chomp 0.1 Announcement](http://m4rw3r.github.io/parser-combinators-road-chomp-0-1)
//!
//! For its current capabilities, you will find that Chomp performs consistently as well, if not
//! better, than optimized C parsers, while being vastly more expressive. For an example that
//! builds a performant HTTP parser out of smaller parsers, see
//! [http_parser.rs](examples/http_parser.rs).
//!
//! # Example
//!
//! ```
//! # #[macro_use] extern crate chomp;
//! # fn main() {
//! use chomp::{Input, U8Result, parse_only};
//! use chomp::{take_while1, token};
//!
//! #[derive(Debug, Eq, PartialEq)]
//! struct Name<'a> {
//!     first: &'a [u8],
//!     last:  &'a [u8],
//! }
//!
//! fn name(i: Input<u8>) -> U8Result<Name> {
//!     parse!{i;
//!         let first = take_while1(|c| c != b' ');
//!                     token(b' ');  // skipping this char
//!         let last  = take_while1(|c| c != b'\n');
//!
//!         ret Name{
//!             first: first,
//!             last:  last,
//!         }
//!     }
//! }
//!
//! assert_eq!(parse_only(name, "Martin Wernstål\n".as_bytes()), Ok(Name{
//!     first: b"Martin",
//!     last: "Wernstål".as_bytes()
//! }));
//! # }
//! ```
//!
//! # Usage
//!
//! Chomp's functionality is split between three modules:
//!
//! * `parsers` contains the basic parsers used to parse streams of input.
//! * `combinators` contains functions which take parsers and return new ones.
//! * `primitives` contains the building blocks used to make new parsers. This is advanced usage and
//!   is far more involved than using the pre-existing parsers, but is sometimes unavoidable.
//!
//! A parser is, at its simplest, a function that takes a slice of input and returns a
//! `ParserResult<I, T, E>`, where `I`, `T`, and `E` are the input, output, and error types,
//! respectively. Parsers are usually parameterized over values or other parsers as well, so these
//! appear as extra arguments in the parsing function. As an example, here is the signature of the
//! `token` parser, which matches a particular input.
//!
//! ```ignore
//! fn token<I: Copy + Eq>(i: Input<I>, t: I) -> SimpleResult<I, I> {...}
//! ```
//!
//! Notice that the first argument is an `Input<I>`, and the second argument is some `I`.
//! `Input<I>` is just a datatype over the current state of the parser and a slice of input `I`,
//! and prevents the parser writer from accidentally mutating the state of the parser. Later, when
//! we introduce the `parse!` macro, we will see that using a parser in this macro just means
//! supplying all of the arguments but the input, as so:
//!
//! ```ignore
//! token(b'T');
//! ```
//!
//! Note that you cannot do this outside of the `parse!` macro. `SimpleResult<I, T>` is a
//! convenience type alias over `ParseResult<I, T, Error<u8>>`, and `Error<I>` is just a convenient
//! "default" error type that will be sufficient for most uses. For more sophisticated usage, one
//! can always write a custom error type.
//!
//! A very useful parser is the `satisfy` parser:
//!
//! ```ignore
//! fn satisfy<I: Copy, F>(i: Input<I>, f: F) -> SimpleResult<I, I>
//!    where F: FnOnce(I) -> bool { ... }
//! ```
//!
//! Besides the input state, satisfy's only parameter is a predicate function and will succeed only
//! if the next piece of input satisfies the supplied predicate. Here's an example that might be
//! used in the `parse!` macro:
//!
//! ```
//! # #[macro_use] extern crate chomp;
//! # fn main() {
//! # use chomp::{satisfy, parse_only};
//! # let r = parse_only(parser!{
//! satisfy(|c| {
//!     match c {
//!         b'c' | b'h' | b'a' | b'r' => true,
//!         _ => false,
//!     }
//! })
//! # }, b"h");
//! # assert_eq!(r, Ok(b'h'));
//! # }
//! ```
//!
//! This parser will only succeed if the character is one of the characters in "char".
//!
//! Lastly, here is the parser combinator `count`, which will attempt to run a parser a number of
//! times on its input.
//!
//! ```ignore
//! pub fn count<'a, I, T, E, F, U>(i: Input<'a, I>, num: usize, p: F) -> ParseResult<'a, I, T, E>
//!   where I: Copy,
//!         U: 'a,
//!         F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
//!         T: FromIterator<U> { ... }
//! ```
//!
//! Using parsers is almost entirely done using the `parse!` macro, which enables us to do three
//! distinct things:
//!
//! * Sequence parsers over the remaining input
//! * Store intermediate results into datatypes
//! * Return a datatype at the end, which may be the result of any arbitrary computation over the
//! intermediate results.
//!
//! In other words, just as a normal Rust function usually looks something like this:
//!
//! ```
//! # fn launch_missiles() {}
//! # fn read_number() -> u8 { 3 }
//! fn f() -> (u8, u8, u8) {
//!     let a = read_number();
//!     let b = read_number();
//!     launch_missiles();
//!     return (a, b, a + b);
//! }
//! ```
//!
//! A Chomp parser with a similar structure looks like this:
//!
//! ```
//! # #[macro_use] extern crate chomp;
//! # use chomp::{Input, parse_only, satisfy, string, U8Result};
//! fn f(i: Input<u8>) -> U8Result<(u8, u8, u8)> {
//!     parse!{i;
//!         let a = digit();
//!         let b = digit();
//!                 string(b"missiles");
//!         ret (a, b, a + b)
//!     }
//! }
//!
//! fn digit(i: Input<u8>) -> U8Result<u8> {
//!     satisfy(i, |c| b'0' <= c && c <= b'9').map(|c| c - b'0')
//! }
//! # fn main() {
//! #     let r = parse_only(f, b"33missiles");
//! #     assert_eq!(r, Ok((3, 3, 6)));
//! # }
//! ```
//!
//! Readers familiar with Haskell or F# will recognize this as a "monadic computation" or
//! "computation expression".
//!
//! You use the `parse!` macro as follows:
//!
//! - Write the input parameter first, with a semicolon.
//! - Write any number of valid parser actions or identifier bindings, where:
//!    - a parser action takes the form `parser(params*)`, with the input parameter omitted.
//!    - an identifier binding takes the form `let identifer = parser(params*);`, with the input
//!      parameter omitted.
//! - Write the final line of the macro, which must always be either a parser action, or a return
//!   statement which takes the form `ret expression`. The type of `expression` becomes the return
//!   type of the entire parser, should it succeed.
//!
//! The entire grammar for the macro is listed elsewhere in this documentation.
//!
//! # Features
//!
//! * `backtrace`:
#![cfg_attr(feature="backtrace", doc = " enabled.")]
#![cfg_attr(not(feature="backtrace"), doc = " disabled (default).")]
//!
//!    This feature enables backtraces for parse-errors, either by calling `Error::trace` or by
//!    printing it using `fmt::Debug`.
//!
//!    This incurs a performance-hit every time a `chomp::parsers` parser fails since a backtrace
//!    must be collected.
//!
//!    In the `dev` and `test` profiles backtraces will always be enabled. This does not incur any
//!    cost when built using the `release` profile unless the `backtrace` feature is enabled.
//!
//! * `noop_error`:
#![cfg_attr(not(feature="noop_error"), doc = " disabled (default).")]
#![cfg_attr(feature="noop_error", doc = " enabled.")]
//!
//!    The built-in `chomp::parsers::Error` type is zero-sized and carry no error-information. This
//!    increases performance somewhat.

#[macro_use]
extern crate bitflags;
extern crate conv;
extern crate debugtrace;

#[macro_use]
mod macros;
mod input;
mod parse;
mod parse_result;

pub mod ascii;
pub mod buffer;
pub mod parsers;
pub mod combinators;

pub use combinators::{
    count,
    option,
    or,
    many,
    many1,
    sep_by,
    sep_by1,
    many_till,
    skip_many,
    skip_many1,
    matched_by,
};
pub use parsers::{
    any,
    eof,
    not_token,
    peek,
    peek_next,
    satisfy,
    satisfy_with,
    scan,
    string,
    run_scanner,
    take,
    take_remainder,
    take_till,
    take_while,
    take_while1,
    token,
};
pub use parsers::Error;
pub use input::Input;
pub use parse::{
    ParseError,
    parse_only,
};
pub use parse_result::{
    ParseResult,
    SimpleResult,
    U8Result,
};

/// Module used to construct fundamental parsers and combinators.
///
/// # Primitive
///
/// Only used by fundamental parsers and combinators.
pub mod primitives {
    pub use input::{
        InputBuffer,
        InputClone,
    };
    pub use parse_result::{
        IntoInner,
        State,
    };

    /// Input utilities.
    ///
    /// # Primitive
    ///
    /// Only used by fundamental parsers and combinators.
    pub mod input {
        pub use input::{DEFAULT, END_OF_INPUT, new};
    }

    /// ParseResult utilities.
    ///
    /// # Primitive
    ///
    /// Only used by fundamental parsers and combinators.
    ///
    /// # Note
    ///
    /// Prefer to use ``Input::ret``, ``Input::err`` or ``Input::incomplete`` instead of using
    /// ``parse_result::new``.
    pub mod parse_result {
        pub use parse_result::new;
    }
}
<|endoftext|>


<commit_before>#![feature(libc)]
extern crate libc;
// mod bindgen;

#[repr(C)]
pub enum CsArch {
    ARCH_ARM = 0,    // ARM architecture (including Thumb, Thumb-2)
    ARCH_ARM64,      // ARM-64, also called AArch64
    ARCH_MIPS,       // Mips architecture
    ARCH_X86,        // X86 architecture (including x86 & x86-64)
    ARCH_PPC,        // PowerPC architecture
    ARCH_SPARC,      // Sparc architecture
    ARCH_SYSZ,       // SystemZ architecture
    ARCH_XCORE,      // XCore architecture
    ARCH_MAX,
    ARCH_ALL = 0xFFFF, // All architectures - for cs_support()
}

#[repr(C)]
pub enum CsMode {
    MODE_LITTLE_ENDIAN = 0,  // little-endian mode (default mode)
    // MODE_ARM = 0,    // 32-bit ARM
    MODE_16 = 1 << 1,    // 16-bit mode (X86)
    MODE_32 = 1 << 2,    // 32-bit mode (X86)
    MODE_64 = 1 << 3,    // 64-bit mode (X86, PPC)
    MODE_THUMB = 1 << 4, // ARM's Thumb mode, including Thumb-2
    MODE_MCLASS = 1 << 5,    // ARM's Cortex-M series
    MODE_V8 = 1 << 6,    // ARMv8 A32 encodings for ARM
    // MODE_MICRO = 1 << 4, // MicroMips mode (MIPS)
    // MODE_MIPS3 = 1 << 5, // Mips III ISA
    // MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA
    // MODE_MIPSGP64 = 1 << 7, // General Purpose Registers are 64-bit wide (MIPS)
    // MODE_V9 = 1 << 4, // SparcV9 mode (Sparc)
    MODE_BIG_ENDIAN = 1 << 31,   // big-endian mode
    // MODE_MIPS32 = CsMode::MODE_32,    // Mips32 ISA (Mips)
    // MODE_MIPS64 = CsMode::MODE_64,    // Mips64 ISA (Mips)
}

#[repr(C)]
enum CsErr {
    CS_ERR_OK = 0,   // No error: everything was fine
    CS_ERR_MEM,      // Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
    CS_ERR_ARCH,     // Unsupported architecture: cs_open()
    CS_ERR_HANDLE,   // Invalid handle: cs_op_count(), cs_op_index()
    CS_ERR_CSH,      // Invalid csh argument: cs_close(), cs_errno(), cs_option()
    CS_ERR_MODE,     // Invalid/unsupported mode: cs_open()
    CS_ERR_OPTION,   // Invalid/unsupported option: cs_option()
    CS_ERR_DETAIL,   // Information is unavailable because detail option is OFF
    CS_ERR_MEMSETUP, // Dynamic memory management uninitialized (see CS_OPT_MEM)
    CS_ERR_VERSION,  // Unsupported version (bindings)
    CS_ERR_DIET,     // Access irrelevant data in "diet" engine
    CS_ERR_SKIPDATA, // Access irrelevant data for "data" instruction in SKIPDATA mode
    CS_ERR_X86_ATT,  // X86 AT&T syntax is unsupported (opt-out at compile time)
    CS_ERR_X86_INTEL, // X86 Intel syntax is unsupported (opt-out at compile time)
}

type csh = libc::size_t;
#[link(name = "capstone")]
extern "C" {
    fn cs_open(arch: CsArch, mode: CsMode, handle: *mut csh) -> CsErr;
    fn cs_close(handle: *mut csh) -> CsErr;
    fn cs_disasm(handle: csh, code: *const u8, code_size: isize,
                 address: u64, count: isize, insn: *mut *mut Insn) -> isize;
    fn cs_disasm_ex(handle: csh, code: *const u8, code_size: isize,
                    address: u64, count: isize, insn: *mut *mut Insn) -> isize;
}

pub struct Capstone {
    csh: libc::size_t, // Opaque handle to cs_engine
}

impl Capstone {
    pub fn new(arch: CsArch, mode: CsMode) -> Option<Capstone> {
        let mut handle: libc::size_t = 0;
        if let CsErr::CS_ERR_OK = unsafe { cs_open(arch, mode, &mut handle) } {
            Some(Capstone {
                csh: handle
            })
        } else {
            None
        }
    }
}

impl Drop for Capstone {
    fn drop(&mut self) {
        unsafe { cs_close(&mut self.csh) };
    }
}

#[repr(C)]
#[derive(Copy)]
pub struct Insn {
    pub id: ::libc::c_uint,
    pub address: u64,
    pub size: u16,
    pub bytes: [u8; 16usize],
    pub mnemonic: [::libc::c_char; 32usize],
    pub op_str: [::libc::c_char; 160usize],
    pub detail: *mut libc::c_void, // Opaque cs_detail
}
<commit_msg>Working code<commit_after>#![feature(libc)]
#![feature(core)]
#![feature(debug_builders)]
extern crate libc;

use std::ptr;
use std::mem;
use std::slice;
use std::ffi::CStr;
use std::fmt::{Debug, Formatter, Error};

use std::io;
use std::str;
use std::intrinsics;
use std::io::Write;

#[repr(C)]
pub enum CsArch {
    ARCH_ARM = 0,    // ARM architecture (including Thumb, Thumb-2)
    ARCH_ARM64,      // ARM-64, also called AArch64
    ARCH_MIPS,       // Mips architecture
    ARCH_X86,        // X86 architecture (including x86 & x86-64)
    ARCH_PPC,        // PowerPC architecture
    ARCH_SPARC,      // Sparc architecture
    ARCH_SYSZ,       // SystemZ architecture
    ARCH_XCORE,      // XCore architecture
    ARCH_MAX,
    ARCH_ALL = 0xFFFF, // All architectures - for cs_support()
}

#[repr(C)]
pub enum CsMode {
    MODE_LITTLE_ENDIAN = 0,  // little-endian mode (default mode)
    // MODE_ARM = 0,    // 32-bit ARM
    MODE_16 = 1 << 1,    // 16-bit mode (X86)
    MODE_32 = 1 << 2,    // 32-bit mode (X86)
    MODE_64 = 1 << 3,    // 64-bit mode (X86, PPC)
    MODE_THUMB = 1 << 4, // ARM's Thumb mode, including Thumb-2
    MODE_MCLASS = 1 << 5,    // ARM's Cortex-M series
    MODE_V8 = 1 << 6,    // ARMv8 A32 encodings for ARM
    // MODE_MICRO = 1 << 4, // MicroMips mode (MIPS)
    // MODE_MIPS3 = 1 << 5, // Mips III ISA
    // MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA
    // MODE_MIPSGP64 = 1 << 7, // General Purpose Registers are 64-bit wide (MIPS)
    // MODE_V9 = 1 << 4, // SparcV9 mode (Sparc)
    MODE_BIG_ENDIAN = 1 << 31,   // big-endian mode
    // MODE_MIPS32 = CsMode::MODE_32,    // Mips32 ISA (Mips)
    // MODE_MIPS64 = CsMode::MODE_64,    // Mips64 ISA (Mips)
}

#[repr(C)]
enum CsErr {
    CS_ERR_OK = 0,   // No error: everything was fine
    CS_ERR_MEM,      // Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
    CS_ERR_ARCH,     // Unsupported architecture: cs_open()
    CS_ERR_HANDLE,   // Invalid handle: cs_op_count(), cs_op_index()
    CS_ERR_CSH,      // Invalid csh argument: cs_close(), cs_errno(), cs_option()
    CS_ERR_MODE,     // Invalid/unsupported mode: cs_open()
    CS_ERR_OPTION,   // Invalid/unsupported option: cs_option()
    CS_ERR_DETAIL,   // Information is unavailable because detail option is OFF
    CS_ERR_MEMSETUP, // Dynamic memory management uninitialized (see CS_OPT_MEM)
    CS_ERR_VERSION,  // Unsupported version (bindings)
    CS_ERR_DIET,     // Access irrelevant data in "diet" engine
    CS_ERR_SKIPDATA, // Access irrelevant data for "data" instruction in SKIPDATA mode
    CS_ERR_X86_ATT,  // X86 AT&T syntax is unsupported (opt-out at compile time)
    CS_ERR_X86_INTEL, // X86 Intel syntax is unsupported (opt-out at compile time)
}

type csh = libc::size_t;
#[link(name = "capstone")]
extern "C" {
    fn cs_open(arch: CsArch, mode: CsMode, handle: *mut csh) -> CsErr;
    fn cs_close(handle: *mut csh) -> CsErr;
    fn cs_disasm(handle: csh, code: *const u8, code_size: isize,
                 address: u64, count: isize, insn: &mut *const Insn) -> isize;
    fn cs_disasm_ex(handle: csh, code: *const u8, code_size: isize,
                    address: u64, count: isize, insn: &mut *const Insn) -> isize;
}

pub struct Capstone {
    csh: libc::size_t, // Opaque handle to cs_engine
}

// Using an actual slice is causing issues with auto deref, instead implement a custom iterator and
// drop trait
pub struct Instructions {
    ptr: *const Insn,
    len: isize,
}

impl Instructions {
    fn from_raw_parts(ptr: *const Insn, len: isize) -> Instructions {
        Instructions {
            ptr: ptr,
            len: len,
        }
    }

    pub fn len(&self) -> isize {
        self.len
    }

    pub fn iter(&self) -> InstructionIterator {
        InstructionIterator { insns: &self, cur: 0 }
    }
}

pub struct InstructionIterator<'a> {
    insns: &'a Instructions,
    cur: isize,
}

impl<'a> Iterator for InstructionIterator<'a> {
    type Item = Insn;

    fn next(&mut self) -> Option<Insn> {
        if self.cur == self.insns.len {
            None
        } else {
            let obj = unsafe { intrinsics::offset(self.insns.ptr, self.cur) };
            self.cur += 1;
            Some(unsafe { *obj })
        }
    }
}

impl Capstone {
    pub fn new(arch: CsArch, mode: CsMode) -> Option<Capstone> {
        let mut handle: libc::size_t = 0;
        if let CsErr::CS_ERR_OK = unsafe { cs_open(arch, mode, &mut handle) } {
            Some(Capstone {
                csh: handle
            })
        } else {
            None
        }
    }

    pub fn disasm(&self, code: &[u8], addr: u64, count: isize) -> Option<Instructions> {
        let mut ptr: *const Insn = ptr::null();
        let insn_count = unsafe { cs_disasm(self.csh, code.as_ptr(), code.len() as isize, addr, count, &mut ptr) };
        if insn_count == 0 {
            // TODO  On failure, call cs_errno() for error code.
            return None
        }

        Some(Instructions::from_raw_parts(ptr, insn_count))
    }
}

impl Drop for Capstone {
    fn drop(&mut self) {
        unsafe { cs_close(&mut self.csh) };
    }
}

#[repr(C)]
#[derive(Copy)]
pub struct Insn {
    id: ::libc::c_uint,
    pub address: u64,
    pub size: u16,
    pub bytes: [u8; 16usize],
    pub mnemonic: [::libc::c_char; 32usize],
    pub op_str: [::libc::c_char; 160usize],
    detail: *mut libc::c_void, // Opaque cs_detail
}

impl Insn {
    pub fn mnemonic(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.mnemonic.as_ptr()) };
        str::from_utf8(cstr.to_bytes()).ok()
    }

    pub fn op_str(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.op_str.as_ptr()) };
        str::from_utf8(cstr.to_bytes()).ok()
    }
}

impl Debug for Insn {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        fmt.debug_struct("Insn")
            .field("address", &self.address)
            .field("size", &self.size)
            .field("mnemonic", &self.mnemonic())
            .field("op_str", &self.op_str())
            .finish()
    }
}
<|endoftext|>


<commit_before>#![deny(
    missing_docs, unused_qualifications, missing_debug_implementations,
    missing_copy_implementations, trivial_casts, trivial_numeric_casts, unsafe_code,
    unstable_features, unused_import_braces
)]

//! *merkle* implements a Merkle Tree in Rust.

extern crate ring;

#[cfg(feature = "serialization-protobuf")]
extern crate protobuf;

#[cfg(feature = "serialization-serde")]
extern crate serde;
#[cfg(feature = "serialization-serde")]
#[macro_use]
extern crate serde_derive;

mod merkletree;
pub use merkletree::MerkleTree;

mod proof;
pub use proof::Proof;

mod hashutils;
pub use hashutils::Hashable;

mod tree;
pub use tree::{LeavesIntoIterator, LeavesIterator};

#[cfg(feature = "serialization-protobuf")]
#[allow(unused_qualifications)]
mod proto;

#[cfg(test)]
mod tests;
<commit_msg>Formatting<commit_after>#![deny(
    missing_docs,
    unused_qualifications,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces
)]

//! *merkle* implements a Merkle Tree in Rust.

extern crate ring;

#[cfg(feature = "serialization-protobuf")]
extern crate protobuf;

#[cfg(feature = "serialization-serde")]
extern crate serde;
#[cfg(feature = "serialization-serde")]
#[macro_use]
extern crate serde_derive;

mod merkletree;
pub use merkletree::MerkleTree;

mod proof;
pub use proof::Proof;

mod hashutils;
pub use hashutils::Hashable;

mod tree;
pub use tree::{LeavesIntoIterator, LeavesIterator};

#[cfg(feature = "serialization-protobuf")]
#[allow(unused_qualifications)]
mod proto;

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>extern crate glob;
extern crate http;
extern crate hyper;
extern crate hyper_tls;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate nix;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;

mod buffer;
mod cstructs;
mod error;
mod ghclient;
mod runfiles;
mod statics;
mod structs;

use buffer::Buffer;
use cstructs::{Group, Passwd, Spwd};
use ghclient::GithubClient;
use nix::errno::Errno;
use statics::CONF_PATH;
use std::ffi::CStr;
use std::io::{BufRead, Write};
use structs::{Config, Member, MemberGid, SectorGroup};

#[allow(dead_code)]
enum NssStatus {
    TryAgain,
    Unavail,
    NotFound,
    Success,
}

impl From<NssStatus> for libc::c_int {
    fn from(status: NssStatus) -> libc::c_int {
        match status {
            NssStatus::TryAgain => -2,
            NssStatus::Unavail => -1,
            NssStatus::NotFound => 0,
            NssStatus::Success => 1,
        }
    }
}

fn string_from(cstrptr: *const libc::c_char) -> String {
    let cstr: &CStr = unsafe { CStr::from_ptr(cstrptr) };
    String::from(cstr.to_str().unwrap_or(""))
}

macro_rules! succeed {
    () => {{
        return libc::c_int::from(NssStatus::Success);
    }};
    ($finalize:expr) => {{
        $finalize;
        return libc::c_int::from(NssStatus::Success);
    }};
}

macro_rules! fail {
    ($err_no_p:ident, $err_no:expr, $return_val:expr) => {{
        unsafe { *$err_no_p = $err_no as libc::c_int };
        return libc::c_int::from($return_val);
    }};
}

macro_rules! get_or_again {
    ($getter:expr) => {{
        match $getter {
            Ok(ret) => ret,
            Err(_) => return libc::c_int::from(NssStatus::TryAgain),
        }
    }};
    ($getter:expr, $err_no_p:ident) => {{
        match $getter {
            Ok(ret) => ret,
            Err(_) => {
                unsafe { *$err_no_p = Errno::EAGAIN as libc::c_int };
                return libc::c_int::from(NssStatus::TryAgain);
            }
        }
    }};
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwnam_r(cnameptr: *const libc::c_char, pwptr: *mut Passwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))), errnop);
    let sectors = get_or_again!(client.get_sectors(), errnop);
    for sector in sectors {
        if let Some(member) = sector.members.get(&name) {
            match unsafe { (*pwptr).pack_args(&mut buffer, &member.login, member.id, sector.get_gid(), &client.conf) } {
                Ok(_) => succeed!(),
                Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
            }
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwuid_r(uid: libc::uid_t, pwptr: *mut Passwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))), errnop);
    let sectors = get_or_again!(client.get_sectors(), errnop);
    for sector in sectors {
        for member in sector.members.values() {
            if uid == member.id as libc::uid_t {
                match unsafe {
                          (*pwptr).pack_args(&mut buffer, &member.login, member.id, sector.get_gid(), &client.conf)
                      } {
                    Ok(_) => succeed!(),
                    Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
                }
            }
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setpwent() -> libc::c_int {
    let mut list_file = get_or_again!(runfiles::create());
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))));
    let sectors = get_or_again!(client.get_sectors());
    for sector in sectors {
        for member in sector.members.values() {
            let mg = MemberGid { member: member.clone(),
                                 gid: sector.get_gid(), };
            list_file.write_all(mg.to_string().as_bytes()).unwrap();
        }
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getpwent_r(pwptr: *mut Passwd, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = get_or_again!(runfiles::open(), errnop);
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))), errnop);
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let mg = get_or_again!(line.parse::<MemberGid>(), errnop);
        match unsafe { (*pwptr).pack_args(&mut buffer, &mg.member.login, mg.member.id, mg.gid, &client.conf) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endpwent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getspnam_r(cnameptr: *const libc::c_char, spptr: *mut Spwd, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))), errnop);
    let sectors = get_or_again!(client.get_sectors(), errnop);
    for sector in sectors {
        if let Some(member) = sector.members.get(&name) {
            match unsafe { (*spptr).pack_args(&mut buffer, &member.login, &client.conf) } {
                Ok(_) => succeed!(),
                Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
            }
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setspent() -> libc::c_int {
    let mut list_file = get_or_again!(runfiles::create());
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))));
    let sectors = get_or_again!(client.get_sectors());
    for sector in sectors {
        for member in sector.members.values() {
            list_file.write_all(member.to_string().as_bytes()).unwrap();
        }
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getspent_r(spptr: *mut Spwd, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = get_or_again!(runfiles::open(), errnop);
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))), errnop);
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let member = get_or_again!(line.parse::<Member>(), errnop);
        match unsafe { (*spptr).pack_args(&mut buffer, &member.login, &client.conf) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endspent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrgid_r(gid: libc::gid_t, grptr: *mut Group, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))), errnop);
    let sectors = get_or_again!(client.get_sectors(), errnop);
    for sector in sectors {
        let members: Vec<&str> = sector.members.values().map(|m| m.login.as_str()).collect();
        if gid as u64 == sector.get_gid() {
            match unsafe { (*grptr).pack_args(&mut buffer, &sector.get_group(), gid as u64, &members) } {
                Ok(_) => succeed!(),
                Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
            }
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrnam_r(cnameptr: *const libc::c_char, grptr: *mut Group, buf: *mut libc::c_char,
                                          buflen: libc::size_t, errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))), errnop);
    let sectors = get_or_again!(client.get_sectors(), errnop);
    for sector in sectors {
        let members: Vec<&str> = sector.members.values().map(|m| m.login.as_str()).collect();
        if name == sector.get_group() {
            match unsafe { (*grptr).pack_args(&mut buffer, &sector.get_group(), sector.get_gid(), &members) } {
                Ok(_) => succeed!(),
                Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
            }
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_setgrent() -> libc::c_int {
    let mut list_file = get_or_again!(runfiles::create());
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))));
    let sectors = get_or_again!(client.get_sectors());
    for sector in sectors {
        list_file.write_all(sector.to_string().as_bytes()).unwrap();
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_getgrent_r(grptr: *mut Group, buf: *mut libc::c_char, buflen: libc::size_t,
                                          errnop: *mut libc::c_int)
                                          -> libc::c_int {
    let (idx, idx_file, list) = get_or_again!(runfiles::open(), errnop);
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let sector = get_or_again!(line.parse::<SectorGroup>(), errnop);
        match unsafe { (*grptr).pack_args(&mut buffer, &sector.get_group(), sector.get_gid(), &members) } {
        let members: Vec<&str> = sector.members.keys().map(|k| k.as_str()).collect();
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub extern "C" fn _nss_sectora_endgrent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}
<commit_msg>Mark public functions as unsafe<commit_after>extern crate glob;
extern crate http;
extern crate hyper;
extern crate hyper_tls;
#[macro_use]
extern crate lazy_static;
extern crate libc;
extern crate nix;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;

mod buffer;
mod cstructs;
mod error;
mod ghclient;
mod runfiles;
mod statics;
mod structs;

use buffer::Buffer;
use cstructs::{Group, Passwd, Spwd};
use ghclient::GithubClient;
use nix::errno::Errno;
use statics::CONF_PATH;
use std::ffi::CStr;
use std::io::{BufRead, Write};
use structs::{Config, Member, MemberGid, SectorGroup};

#[allow(dead_code)]
enum NssStatus {
    TryAgain,
    Unavail,
    NotFound,
    Success,
}

impl From<NssStatus> for libc::c_int {
    fn from(status: NssStatus) -> libc::c_int {
        match status {
            NssStatus::TryAgain => -2,
            NssStatus::Unavail => -1,
            NssStatus::NotFound => 0,
            NssStatus::Success => 1,
        }
    }
}

fn string_from(cstrptr: *const libc::c_char) -> String {
    let cstr: &CStr = unsafe { CStr::from_ptr(cstrptr) };
    String::from(cstr.to_str().unwrap_or(""))
}

macro_rules! succeed {
    () => {{
        return libc::c_int::from(NssStatus::Success);
    }};
    ($finalize:expr) => {{
        $finalize;
        return libc::c_int::from(NssStatus::Success);
    }};
}

macro_rules! fail {
    ($err_no_p:ident, $err_no:expr, $return_val:expr) => {{
        *$err_no_p = $err_no as libc::c_int;
        return libc::c_int::from($return_val);
    }};
}

macro_rules! get_or_again {
    ($getter:expr) => {{
        match $getter {
            Ok(ret) => ret,
            Err(_) => return libc::c_int::from(NssStatus::TryAgain),
        }
    }};
    ($getter:expr, $err_no_p:ident) => {{
        match $getter {
            Ok(ret) => ret,
            Err(_) => {
                *$err_no_p = Errno::EAGAIN as libc::c_int;
                return libc::c_int::from(NssStatus::TryAgain);
            }
        }
    }};
}

#[no_mangle]
pub unsafe extern "C" fn _nss_sectora_getpwnam_r(cnameptr: *const libc::c_char, pwptr: *mut Passwd,
                                                 buf: *mut libc::c_char, buflen: libc::size_t,
                                                 errnop: *mut libc::c_int)
                                                 -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))), errnop);
    let sectors = get_or_again!(client.get_sectors(), errnop);
    for sector in sectors {
        if let Some(member) = sector.members.get(&name) {
            match { (*pwptr).pack_args(&mut buffer, &member.login, member.id, sector.get_gid(), &client.conf) } {
                Ok(_) => succeed!(),
                Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
            }
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub unsafe extern "C" fn _nss_sectora_getpwuid_r(uid: libc::uid_t, pwptr: *mut Passwd, buf: *mut libc::c_char,
                                                 buflen: libc::size_t, errnop: *mut libc::c_int)
                                                 -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))), errnop);
    let sectors = get_or_again!(client.get_sectors(), errnop);
    for sector in sectors {
        for member in sector.members.values() {
            if uid == member.id as libc::uid_t {
                match { (*pwptr).pack_args(&mut buffer, &member.login, member.id, sector.get_gid(), &client.conf) } {
                    Ok(_) => succeed!(),
                    Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
                }
            }
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub unsafe extern "C" fn _nss_sectora_setpwent() -> libc::c_int {
    let mut list_file = get_or_again!(runfiles::create());
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))));
    let sectors = get_or_again!(client.get_sectors());
    for sector in sectors {
        for member in sector.members.values() {
            let mg = MemberGid { member: member.clone(),
                                 gid: sector.get_gid() };
            list_file.write_all(mg.to_string().as_bytes()).unwrap();
        }
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub unsafe extern "C" fn _nss_sectora_getpwent_r(pwptr: *mut Passwd, buf: *mut libc::c_char, buflen: libc::size_t,
                                                 errnop: *mut libc::c_int)
                                                 -> libc::c_int {
    let (idx, idx_file, list) = get_or_again!(runfiles::open(), errnop);
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))), errnop);
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let mg = get_or_again!(line.parse::<MemberGid>(), errnop);
        match { (*pwptr).pack_args(&mut buffer, &mg.member.login, mg.member.id, mg.gid, &client.conf) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub unsafe extern "C" fn _nss_sectora_endpwent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub unsafe extern "C" fn _nss_sectora_getspnam_r(cnameptr: *const libc::c_char, spptr: *mut Spwd,
                                                 buf: *mut libc::c_char, buflen: libc::size_t,
                                                 errnop: *mut libc::c_int)
                                                 -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))), errnop);
    let sectors = get_or_again!(client.get_sectors(), errnop);
    for sector in sectors {
        if let Some(member) = sector.members.get(&name) {
            match { (*spptr).pack_args(&mut buffer, &member.login, &client.conf) } {
                Ok(_) => succeed!(),
                Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
            }
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub unsafe extern "C" fn _nss_sectora_setspent() -> libc::c_int {
    let mut list_file = get_or_again!(runfiles::create());
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))));
    let sectors = get_or_again!(client.get_sectors());
    for sector in sectors {
        for member in sector.members.values() {
            list_file.write_all(member.to_string().as_bytes()).unwrap();
        }
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub unsafe extern "C" fn _nss_sectora_getspent_r(spptr: *mut Spwd, buf: *mut libc::c_char, buflen: libc::size_t,
                                                 errnop: *mut libc::c_int)
                                                 -> libc::c_int {
    let (idx, idx_file, list) = get_or_again!(runfiles::open(), errnop);
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))), errnop);
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let member = get_or_again!(line.parse::<Member>(), errnop);
        match { (*spptr).pack_args(&mut buffer, &member.login, &client.conf) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub unsafe extern "C" fn _nss_sectora_endspent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub unsafe extern "C" fn _nss_sectora_getgrgid_r(gid: libc::gid_t, grptr: *mut Group, buf: *mut libc::c_char,
                                                 buflen: libc::size_t, errnop: *mut libc::c_int)
                                                 -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))), errnop);
    let sectors = get_or_again!(client.get_sectors(), errnop);
    for sector in sectors {
        let members: Vec<&str> = sector.members.values().map(|m| m.login.as_str()).collect();
        if gid as u64 == sector.get_gid() {
            match { (*grptr).pack_args(&mut buffer, &sector.get_group(), gid as u64, &members) } {
                Ok(_) => succeed!(),
                Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
            }
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub unsafe extern "C" fn _nss_sectora_getgrnam_r(cnameptr: *const libc::c_char, grptr: *mut Group,
                                                 buf: *mut libc::c_char, buflen: libc::size_t,
                                                 errnop: *mut libc::c_int)
                                                 -> libc::c_int {
    let mut buffer = Buffer::new(buf, buflen);
    let name = string_from(cnameptr);
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))), errnop);
    let sectors = get_or_again!(client.get_sectors(), errnop);
    for sector in sectors {
        let members: Vec<&str> = sector.members.values().map(|m| m.login.as_str()).collect();
        if name == sector.get_group() {
            match { (*grptr).pack_args(&mut buffer, &sector.get_group(), sector.get_gid(), &members) } {
                Ok(_) => succeed!(),
                Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
            }
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub unsafe extern "C" fn _nss_sectora_setgrent() -> libc::c_int {
    let mut list_file = get_or_again!(runfiles::create());
    let client = get_or_again!(Config::new(&CONF_PATH).and_then(|c| Ok(GithubClient::new(&c))));
    let sectors = get_or_again!(client.get_sectors());
    for sector in sectors {
        list_file.write_all(sector.to_string().as_bytes()).unwrap();
    }
    libc::c_int::from(NssStatus::Success)
}

#[no_mangle]
pub unsafe extern "C" fn _nss_sectora_getgrent_r(grptr: *mut Group, buf: *mut libc::c_char, buflen: libc::size_t,
                                                 errnop: *mut libc::c_int)
                                                 -> libc::c_int {
    let (idx, idx_file, list) = get_or_again!(runfiles::open(), errnop);
    if let Some(Ok(line)) = list.lines().nth(idx) {
        let mut buffer = Buffer::new(buf, buflen);
        let sector = get_or_again!(line.parse::<SectorGroup>(), errnop);
        let members: Vec<&str> = sector.members.keys().map(|k| k.as_str()).collect();
        match { (*grptr).pack_args(&mut buffer, &sector.get_group(), sector.get_gid(), &members) } {
            Ok(_) => succeed!(runfiles::increment(idx, idx_file)),
            Err(_) => fail!(errnop, Errno::ERANGE, NssStatus::TryAgain),
        }
    }
    fail!(errnop, Errno::ENOENT, NssStatus::NotFound)
}

#[no_mangle]
pub unsafe extern "C" fn _nss_sectora_endgrent() -> libc::c_int {
    runfiles::cleanup().unwrap_or(());
    libc::c_int::from(NssStatus::Success)
}
<|endoftext|>


<commit_before>/// Represents the bases used in the genome string.
/// For example the bases of the DNA are adenine (A),
/// thymine (T), guanine (G) and cytosine (C).
trait Base: Sized {
    /// Returns the "next" base, wrapping around. Used
    /// to produce the gene product.
    fn next(self) -> Self;
}

#[derive(Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum DNABase {
    A,
    T,
    G,
    C
}

impl Base for DNABase {
    fn next(self) -> Self {
        match self {
            A => T,
            T => G,
            G => C,
            C => A
        }
    }
}

#[test]
fn test_dnabase_next() {
    assert_eq!(DNABase::A, DNABase::C.next());
}
<commit_msg>Fix next()<commit_after>/// Represents the bases used in the genome string.
/// For example the bases of the DNA are adenine (A),
/// thymine (T), guanine (G) and cytosine (C).
trait Base: Sized {
    /// Returns the "next" base, wrapping around. Used
    /// to produce the gene product.
    fn next(self) -> Self;
}

#[derive(Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum DNABase {
    A,
    T,
    G,
    C
}

impl Base for DNABase {
    fn next(self) -> Self {
        match self {
            DNABase::A => DNABase::T,
            DNABase::T => DNABase::G,
            DNABase::G => DNABase::C,
            DNABase::C => DNABase::A
        }
    }
}

#[test]
fn test_dnabase_next() {
    assert_eq!(DNABase::A, DNABase::C.next());
}
<|endoftext|>


<commit_before>extern crate getopts;
use getopts::{optflag,getopts,OptGroup,usage};
use std::os;

use std::num::FromPrimitive;
use std::num::Int;
use std::char;
use std::old_io;
use std::old_io::{IoResult, IoError};
use std::old_io::BufferedReader;
use std::old_io::File;
use std::old_io::stdio;

pub fn print_usage(program: &str, opts: &[OptGroup]) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", usage(brief.as_slice(), opts));
}

pub fn cat(v: &Vec<String>, options: &getopts::Matches) {
    if options.opt_present("u") {
        let writer = Box::new(stdio::stdout_raw());
        stdio::set_stdout(writer);
    }
    if v.is_empty() {
        cat_stdin(options);
    }
    else {
        // read files
        cat_files(v, options);
    }
}

fn cat_files(v: &Vec<String>, options: &getopts::Matches) {
    let mut linenum = 1u32;
    for filename in v.iter() {
        let path = Path::new(filename);
        match File::open(&path) {
            Ok(fh) => {
                let mut file = BufferedReader::new(fh);
                linenum = cat_file(file, options, linenum);
            },
            Err(f) => {
                println!("{}", f);
            }
        }
    }
}

fn cat_stdin(options: &getopts::Matches) {
    let mut linenum = 1u32;
    let mut printempty: bool = false;
    for line in old_io::stdin().lock().lines() {
        let (a, b) = handle_line(line.unwrap(), &mut printempty, linenum, options);
        printempty = a;
        linenum = b;
    }
}

fn cat_file<'a>(
    mut file: old_io::BufferedReader<std::old_io::fs::File>,
    options: &getopts::Matches,
    mut linenum: u32,
    ) -> u32 {
    let mut printempty: bool = false;
    let mut read_buf = [0, 4096];
    let mut out_buf: Vec<u8> = vec![];
    loop {
        match file.read(&mut read_buf) {
            Ok(n) => {
                for c in read_buf[..n].iter() {
                    out_buf.push(*c);
                    if is_nl(c) {
                        let (a, b) = handle_buf(&out_buf, &mut printempty, linenum, options);
                        printempty = a;
                        linenum = b;
                        out_buf.clear();
                    }
                }
            },
            Err(f) => {
                let mut o = 0u32;
                if out_buf.len() > 0 {
                    handle_buf(&out_buf, &mut printempty, linenum, options);
                }
                break
            }
        }
    }
    linenum
}

fn handle_line<'a>(
    linestr: String,
    printempty: &'a mut bool,
    mut linenum: u32,
    options: &getopts::Matches) -> (bool, u32) {
    if options.opt_present("s") {
        if !is_empty(&linestr) {
            if *printempty == true {
                println!("");
            }
            linenum = print_string(&linestr, linenum, options);
        }
        else {
            *printempty = true;
        }
    }
    else {
        linenum = print_string(&linestr, linenum, options);
    }
    (*printempty, linenum)
}

fn handle_buf<'a>(
    out_buf: &Vec<u8>,
    printempty: &'a mut bool,
    mut linenum: u32,
    options: &getopts::Matches) -> (bool, u32) {
    if options.opt_present("s") {
        if !is_empty_out_buf(out_buf) {
            if *printempty == true {
                if options.opt_present("n") {
                    println!("     {}\t", linenum);
                    linenum = linenum + 1;
                }
                else {
                    println!("");
                }
            }
            linenum = print_buf(&out_buf, linenum, options);
        }
        else {
            *printempty = true;
        }
    }
    else {
        linenum = print_buf(&out_buf, linenum, options);
    }
    (*printempty, linenum)
}

fn print_string<'a>(s: &String, mut linenum: u32, options: &getopts::Matches) -> u32 {
    if options.opt_present("b") {
        if !is_empty(s) {
            print_numbered(s, linenum, options);
            linenum = linenum + 1;
        }
        else {
            print_unnumbered(s, options);
        }
    }
    else if options.opt_present("n") {
        print_numbered(s, linenum, options);
        linenum = linenum + 1;
    }
    else {
        print_unnumbered(s, options);
    }
    linenum
}

fn print_buf<'a>(out_buf: &Vec<u8>, mut linenum: u32, options: &getopts::Matches) -> u32 {
    if options.opt_present("b") {
        if !is_empty_out_buf(out_buf) {
            print_numbered_buf(out_buf, linenum, options);
            linenum = linenum + 1;
        }
        else {
            print_unnumbered_buf(out_buf, options);
        }
    }
    else if options.opt_present("n") {
        print_numbered_buf(out_buf, linenum, options);
        linenum = linenum + 1;
    }
    else {
        print_unnumbered_buf(out_buf, options);
    }
    linenum
}

fn print_numbered<'a>(s: &String, linenum: u32, options: &getopts::Matches) {
    if options.opt_present("v") || options.opt_present("t") {
        print!("     {}\t", linenum);
        for b in s.as_bytes().iter() {
            print_byte(b, options);
        }
    }
    else {
        print!("     {}\t{}", linenum, s);
    }
}

fn print_numbered_buf<'a>(out_buf: &Vec<u8>, linenum: u32, options: &getopts::Matches) {
    // if options.opt_present("v") || options.opt_present("t") {
        print!("     {}\t", linenum);
        let mut t = 0u32;
        for b in out_buf.iter() {
            if t > 0 {
                t = t + *b as u32;
                // print!("t: {} ", t);
                print!("{}", char::from_u32(t).unwrap());
                t = 0;
            }
            else {
                if *b > 160 {
                    t = *b as u32;
                }
                else {
                    print_byte(b, options);
                }
            }
        }
    // }
}

fn print_unnumbered(s: &String, options: &getopts::Matches) {
    if options.opt_present("v") || options.opt_present("t") {
        for b in s.as_bytes().iter() {
            print_byte(b, options);
        }
    }
    else {
        print!("{}", s);
    }
}

fn print_unnumbered_buf(out_buf: &Vec<u8>, options: &getopts::Matches) {
    // if options.opt_present("v") || options.opt_present("t") {
        let mut t = 0;
        let mut buf: Vec<u8> = vec![];
        for b in out_buf.iter() {
            if t > 0 {
                buf.push(*b);
                t = t - 1;
                if t == 0 {
                    print_u8_buf(&mut buf, options);
                    buf.clear();
                }
            }
            else {
                if *b >= 240 {
                    //4th byte
                    t = 3;
                    buf.push(*b);
                }
                else if *b >= 224 {
                    t = 2;
                    buf.push(*b);
                }
                else if *b >= 192 {
                    t = 1;
                    buf.push(*b);
                }
                else {
                    print_byte(b, options);
                }
            }
        }
    // }
    // else {
        // print!("{}", s);
    // }
}

fn print_u8_buf(buf: &mut Vec<u8>, options: &getopts::Matches) {

    let o = convert_buf_to_codepoint(buf);
    print!("{}", char::from_u32(o).unwrap());
    // for b in buf.iter() {
        // print_byte(b, options);
    // }
}

fn convert_buf_to_codepoint(buf: &mut Vec<u8>) -> u32 {
    let mut s = 0u32;
    // println!("size: {}", buf.len());
    // println!("s: {}", s);
    let mut l = buf.len();
    let orig_l = l;
    for b in buf.iter() {
        // println!("l: {}", l);
        if l == 4 {
            s = s + (*b as u32 - 240 + 2.pow(19));
        }
        else if l == 3 {
            s = s + ((*b as u32 | 224) - 224) << 12
        }
        else if l == 2 {
            // println!("2b: {}", b);
            // let newval = (*b & 15) << 6;
            // println!("newval: {}", newval);
            // s = s + FromPrimitive::from_u8(newval).unwrap();
            s = s + (((*b as u32 | 192) - 192) << 6);
            // println!("2: {}", s);
        }
        else if l == 1 {
            // println!("1b: {}", b);
            // println!("1b anded: {}", *b & 63);
            if orig_l > 1 {
                s = s + FromPrimitive::from_u8((*b | 128) - 128).unwrap();
            }
            else {
                s = s + FromPrimitive::from_u8((*b | 192) - 192).unwrap();
            }
        }
        l = l - 1;
    }
    s
}

fn is_empty(line: &String) -> bool {
    let newline_str = "\n".to_string();
    let crlf_str = "\r\n".to_string();
    if line.is_empty() {
        true
    }
    else if line.eq(&newline_str) || line.eq(&crlf_str) {
        true
    }
    else {
        false
    }
}

fn is_empty_out_buf(v: &Vec<u8>) -> bool {
    if v.len() > 1 {
        false
    }
    else if is_nl(&v[0]) {
        true
    }
    else {
        false
    }
}

fn is_nl(c: &u8) -> bool {
    *c == 10u8
}

fn print_byte(b: &u8, options: &getopts::Matches) {
    if (*b > 31 && *b < 127) || *b == 10 || *b == 9 {
        if options.opt_present("t") && *b == 9 {
            print_tab();
        }
        else {
            print!("{}", *b as char);
        }
    }
    else {
        if options.opt_present("v") || options.opt_present("t") {
            if *b < 32 {
                print!("^{}", (*b + 64) as char);
            }
            else if *b == 127 {
                // del char
                print!("^?");
            }
            else if *b > 127 {
                if *b == 255 {
                    print!("M-^?");
                }
                else {
                    let x = *b - 128;
                    if x < 32 {
                        print!("M-^{}", (x + 64) as char);
                    }
                    else {
                        print!("M-{}", (*b - 128) as char);
                    }
                }
            }
        }
    }
}

fn print_tab() {
    print!("^I");
}

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

    #[test]
    fn assert_is_empty() {
        let s = "".to_string();
        assert!(is_empty(&s));
    }
    #[test]
    fn assert_is_empty_newline() {
        let s = "\n".to_string();
        assert!(is_empty(&s));
    }

    #[test]
    fn assert_is_empty_crlf() {
        let s = "\r\n".to_string();
        assert!(is_empty(&s));
    }

    #[test]
    fn assert_is_empty_char() {
        let s = "d".to_string();
        assert!(!is_empty(&s));
    }

    #[test]
    fn assert_is_empty_ctrl_char() {
        let s = "".to_string();
        assert!(!is_empty(&s));
    }

    #[test]
    fn assert_buf_to_codepoint_24() {
        let mut b = vec![24u8];
        assert_eq!(convert_buf_to_codepoint(&mut b), 24u32);
    }

    #[test]
    fn assert_buf_to_codepoint_36() {
        let mut b = vec![164u8];
        assert_eq!(convert_buf_to_codepoint(&mut b), 36);
    }

    #[test]
    fn assert_buf_to_codepoint_162() {
        // ¢
        // C2 A2
        // 11000010 10100010
        // 00010100010
        let mut b = vec![194u8, 162];
        assert_eq!(convert_buf_to_codepoint(&mut b), 162);
    }

    #[test]
    fn assert_buf_to_codepoint_8364() {
        // €
        // E2 82 AC
        // 11100010 10000010 10101100
        // 0010000010101100
        let mut b = vec![226u8, 130, 172];
        assert_eq!(convert_buf_to_codepoint(&mut b), 8364);
    }

    #[test]
    fn assert_buf_to_codepoint_294() {
        // c4 a6
        // 11000100 10100110
        // 00100100110
        let mut b = vec![196u8, 166];
        assert_eq!(convert_buf_to_codepoint(&mut b), 294);
    }

}
<commit_msg>removing debugging pirnt statements<commit_after>extern crate getopts;
use getopts::{optflag,getopts,OptGroup,usage};
use std::os;

use std::num::FromPrimitive;
use std::num::Int;
use std::char;
use std::old_io;
use std::old_io::{IoResult, IoError};
use std::old_io::BufferedReader;
use std::old_io::File;
use std::old_io::stdio;

pub fn print_usage(program: &str, opts: &[OptGroup]) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", usage(brief.as_slice(), opts));
}

pub fn cat(v: &Vec<String>, options: &getopts::Matches) {
    if options.opt_present("u") {
        let writer = Box::new(stdio::stdout_raw());
        stdio::set_stdout(writer);
    }
    if v.is_empty() {
        cat_stdin(options);
    }
    else {
        // read files
        cat_files(v, options);
    }
}

fn cat_files(v: &Vec<String>, options: &getopts::Matches) {
    let mut linenum = 1u32;
    for filename in v.iter() {
        let path = Path::new(filename);
        match File::open(&path) {
            Ok(fh) => {
                let mut file = BufferedReader::new(fh);
                linenum = cat_file(file, options, linenum);
            },
            Err(f) => {
                println!("{}", f);
            }
        }
    }
}

fn cat_stdin(options: &getopts::Matches) {
    let mut linenum = 1u32;
    let mut printempty: bool = false;
    for line in old_io::stdin().lock().lines() {
        let (a, b) = handle_line(line.unwrap(), &mut printempty, linenum, options);
        printempty = a;
        linenum = b;
    }
}

fn cat_file<'a>(
    mut file: old_io::BufferedReader<std::old_io::fs::File>,
    options: &getopts::Matches,
    mut linenum: u32,
    ) -> u32 {
    let mut printempty: bool = false;
    let mut read_buf = [0, 4096];
    let mut out_buf: Vec<u8> = vec![];
    loop {
        match file.read(&mut read_buf) {
            Ok(n) => {
                for c in read_buf[..n].iter() {
                    out_buf.push(*c);
                    if is_nl(c) {
                        let (a, b) = handle_buf(&out_buf, &mut printempty, linenum, options);
                        printempty = a;
                        linenum = b;
                        out_buf.clear();
                    }
                }
            },
            Err(f) => {
                let mut o = 0u32;
                if out_buf.len() > 0 {
                    handle_buf(&out_buf, &mut printempty, linenum, options);
                }
                break
            }
        }
    }
    linenum
}

fn handle_line<'a>(
    linestr: String,
    printempty: &'a mut bool,
    mut linenum: u32,
    options: &getopts::Matches) -> (bool, u32) {
    if options.opt_present("s") {
        if !is_empty(&linestr) {
            if *printempty == true {
                println!("");
            }
            linenum = print_string(&linestr, linenum, options);
        }
        else {
            *printempty = true;
        }
    }
    else {
        linenum = print_string(&linestr, linenum, options);
    }
    (*printempty, linenum)
}

fn handle_buf<'a>(
    out_buf: &Vec<u8>,
    printempty: &'a mut bool,
    mut linenum: u32,
    options: &getopts::Matches) -> (bool, u32) {
    if options.opt_present("s") {
        if !is_empty_out_buf(out_buf) {
            if *printempty == true {
                if options.opt_present("n") {
                    println!("     {}\t", linenum);
                    linenum = linenum + 1;
                }
                else {
                    println!("");
                }
            }
            linenum = print_buf(&out_buf, linenum, options);
        }
        else {
            *printempty = true;
        }
    }
    else {
        linenum = print_buf(&out_buf, linenum, options);
    }
    (*printempty, linenum)
}

fn print_string<'a>(s: &String, mut linenum: u32, options: &getopts::Matches) -> u32 {
    if options.opt_present("b") {
        if !is_empty(s) {
            print_numbered(s, linenum, options);
            linenum = linenum + 1;
        }
        else {
            print_unnumbered(s, options);
        }
    }
    else if options.opt_present("n") {
        print_numbered(s, linenum, options);
        linenum = linenum + 1;
    }
    else {
        print_unnumbered(s, options);
    }
    linenum
}

fn print_buf<'a>(out_buf: &Vec<u8>, mut linenum: u32, options: &getopts::Matches) -> u32 {
    if options.opt_present("b") {
        if !is_empty_out_buf(out_buf) {
            print_numbered_buf(out_buf, linenum, options);
            linenum = linenum + 1;
        }
        else {
            print_unnumbered_buf(out_buf, options);
        }
    }
    else if options.opt_present("n") {
        print_numbered_buf(out_buf, linenum, options);
        linenum = linenum + 1;
    }
    else {
        print_unnumbered_buf(out_buf, options);
    }
    linenum
}

fn print_numbered<'a>(s: &String, linenum: u32, options: &getopts::Matches) {
    if options.opt_present("v") || options.opt_present("t") {
        print!("     {}\t", linenum);
        for b in s.as_bytes().iter() {
            print_byte(b, options);
        }
    }
    else {
        print!("     {}\t{}", linenum, s);
    }
}

fn print_numbered_buf<'a>(out_buf: &Vec<u8>, linenum: u32, options: &getopts::Matches) {
    // if options.opt_present("v") || options.opt_present("t") {
        print!("     {}\t", linenum);
        let mut t = 0u32;
        for b in out_buf.iter() {
            if t > 0 {
                t = t + *b as u32;
                // print!("t: {} ", t);
                print!("{}", char::from_u32(t).unwrap());
                t = 0;
            }
            else {
                if *b > 160 {
                    t = *b as u32;
                }
                else {
                    print_byte(b, options);
                }
            }
        }
    // }
}

fn print_unnumbered(s: &String, options: &getopts::Matches) {
    if options.opt_present("v") || options.opt_present("t") {
        for b in s.as_bytes().iter() {
            print_byte(b, options);
        }
    }
    else {
        print!("{}", s);
    }
}

fn print_unnumbered_buf(out_buf: &Vec<u8>, options: &getopts::Matches) {
    // if options.opt_present("v") || options.opt_present("t") {
        let mut t = 0;
        let mut buf: Vec<u8> = vec![];
        for b in out_buf.iter() {
            if t > 0 {
                buf.push(*b);
                t = t - 1;
                if t == 0 {
                    print_u8_buf(&mut buf, options);
                    buf.clear();
                }
            }
            else {
                if *b >= 240 {
                    //4th byte
                    t = 3;
                    buf.push(*b);
                }
                else if *b >= 224 {
                    t = 2;
                    buf.push(*b);
                }
                else if *b >= 192 {
                    t = 1;
                    buf.push(*b);
                }
                else {
                    print_byte(b, options);
                }
            }
        }
    // }
    // else {
        // print!("{}", s);
    // }
}

fn print_u8_buf(buf: &mut Vec<u8>, options: &getopts::Matches) {
    let o = convert_buf_to_codepoint(buf);
    print!("{}", char::from_u32(o).unwrap());
    // for b in buf.iter() {
        // print_byte(b, options);
    // }
}

fn convert_buf_to_codepoint(buf: &mut Vec<u8>) -> u32 {
    let mut s = 0u32;
    let mut l = buf.len();
    let orig_l = l;
    for b in buf.iter() {
        if l == 4 {
            s = s + (*b as u32 - 240 + 2.pow(19));
        }
        else if l == 3 {
            s = s + ((*b as u32 | 224) - 224) << 12
        }
        else if l == 2 {
            s = s + (((*b as u32 | 192) - 192) << 6);
        }
        else if l == 1 {
            if orig_l > 1 {
                s = s + FromPrimitive::from_u8((*b | 128) - 128).unwrap();
            }
            else {
                s = s + FromPrimitive::from_u8((*b | 192) - 192).unwrap();
            }
        }
        l = l - 1;
    }
    s
}

fn is_empty(line: &String) -> bool {
    let newline_str = "\n".to_string();
    let crlf_str = "\r\n".to_string();
    if line.is_empty() {
        true
    }
    else if line.eq(&newline_str) || line.eq(&crlf_str) {
        true
    }
    else {
        false
    }
}

fn is_empty_out_buf(v: &Vec<u8>) -> bool {
    if v.len() > 1 {
        false
    }
    else if is_nl(&v[0]) {
        true
    }
    else {
        false
    }
}

fn is_nl(c: &u8) -> bool {
    *c == 10u8
}

fn print_byte(b: &u8, options: &getopts::Matches) {
    if (*b > 31 && *b < 127) || *b == 10 || *b == 9 {
        if options.opt_present("t") && *b == 9 {
            print_tab();
        }
        else {
            print!("{}", *b as char);
        }
    }
    else {
        if options.opt_present("v") || options.opt_present("t") {
            if *b < 32 {
                print!("^{}", (*b + 64) as char);
            }
            else if *b == 127 {
                // del char
                print!("^?");
            }
            else if *b > 127 {
                if *b == 255 {
                    print!("M-^?");
                }
                else {
                    let x = *b - 128;
                    if x < 32 {
                        print!("M-^{}", (x + 64) as char);
                    }
                    else {
                        print!("M-{}", (*b - 128) as char);
                    }
                }
            }
        }
    }
}

fn print_tab() {
    print!("^I");
}

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

    #[test]
    fn assert_is_empty() {
        let s = "".to_string();
        assert!(is_empty(&s));
    }
    #[test]
    fn assert_is_empty_newline() {
        let s = "\n".to_string();
        assert!(is_empty(&s));
    }

    #[test]
    fn assert_is_empty_crlf() {
        let s = "\r\n".to_string();
        assert!(is_empty(&s));
    }

    #[test]
    fn assert_is_empty_char() {
        let s = "d".to_string();
        assert!(!is_empty(&s));
    }

    #[test]
    fn assert_is_empty_ctrl_char() {
        let s = "".to_string();
        assert!(!is_empty(&s));
    }

    #[test]
    fn assert_buf_to_codepoint_24() {
        let mut b = vec![24u8];
        assert_eq!(convert_buf_to_codepoint(&mut b), 24u32);
    }

    #[test]
    fn assert_buf_to_codepoint_36() {
        let mut b = vec![164u8];
        assert_eq!(convert_buf_to_codepoint(&mut b), 36);
    }

    #[test]
    fn assert_buf_to_codepoint_162() {
        // ¢
        // C2 A2
        // 11000010 10100010
        // 00010100010
        let mut b = vec![194u8, 162];
        assert_eq!(convert_buf_to_codepoint(&mut b), 162);
    }

    #[test]
    fn assert_buf_to_codepoint_8364() {
        // €
        // E2 82 AC
        // 11100010 10000010 10101100
        // 0010000010101100
        let mut b = vec![226u8, 130, 172];
        assert_eq!(convert_buf_to_codepoint(&mut b), 8364);
    }

    #[test]
    fn assert_buf_to_codepoint_294() {
        // c4 a6
        // 11000100 10100110
        // 00100100110
        let mut b = vec![196u8, 166];
        assert_eq!(convert_buf_to_codepoint(&mut b), 294);
    }

}
<|endoftext|>